--- /dev/null
+#!/usr/bin/env python3
+
+############################################################################
+# Copyright 2016 RIFT.io Inc #
+# #
+# Licensed under the Apache License, Version 2.0 (the "License"); #
+# you may not use this file except in compliance with the License. #
+# You may obtain a copy of the License at #
+# #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+# #
+# Unless required by applicable law or agreed to in writing, software #
+# distributed under the License is distributed on an "AS IS" BASIS, #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+############################################################################
+
+import argparse
+from contextlib import closing
+import logging
+import os.path
+import socket
+import subprocess
+import sys
+import uuid
+
+import json
+
+
+class OnboardPkgError(Exception):
+ pass
+
+
+class OnboardPkgInputError(OnboardPkgError):
+ pass
+
+
+class OnboardPkgMissingPkg(OnboardPkgError):
+ pass
+
+
+class OnboardPkgFileError(OnboardPkgError):
+ pass
+
+
+class OnboardPkgMissingDescId(OnboardPkgError):
+ pass
+
+
+class OnboardPkgInvalidDescId(OnboardPkgError):
+ pass
+
+
+class OnboardPkgMissingAcct(OnboardPkgError):
+ pass
+
+
+class OnboardPkgSoConnError(OnboardPkgError):
+ pass
+
+
+class OnboardPkgCmdError(OnboardPkgError):
+ pass
+
+
+class OnboardPkgUploadError(OnboardPkgError):
+ pass
+
+
+class OnboardPkgRcConnError(OnboardPkgError):
+ pass
+
+
+class OnboardPkgAcctError(OnboardPkgError):
+ pass
+
+
+class OnboardPkgNsdError(OnboardPkgError):
+ pass
+
+
+class OnboardPkgInstError(OnboardPkgError):
+ pass
+
+
+class OnboardPkgInvalidPort(OnboardPkgError):
+ pass
+
+
+class OnboardPackage:
+
+ def __init__(self,
+ log,
+ args):
+ self._log = log
+ self._args = args
+
+ self._pkgs = None
+
+ self._service_name = None
+ self._nsd_id = None
+ self._dc = None
+ self._account = None
+
+ self._ip = args.so_ip
+
+ self._uport = args.upload_port
+ self._upload_url = "curl -k https://{ip}:{port}/api/upload". \
+ format(ip=self._ip,
+ port=self._uport)
+
+ self._rport = args.restconf_port
+ self._user = args.restconf_user
+ self._password = args.restconf_password
+ self._headers = '-H "accept: application/json"' + \
+ ' -H "content-type: application/json"'
+ self._conf_url = "curl -k {header} --user \"{user}:{passwd}\" https://{ip}:{port}/api/config". \
+ format(header=self._headers,
+ user=self._user,
+ passwd=self._password,
+ ip=self._ip,
+ port=self._rport)
+
+ @property
+ def log(self):
+ return self._log
+
+ def validate_args(self):
+ if args.upload_pkg is not None:
+ self._pkgs = args.upload_pkg
+ self.log.debug("Packages to upload: {}".format(self._pkgs))
+ if len(self._pkgs) == 0:
+ raise OnboardPkgMissingPkg('Need to specify atleast one package to upload')
+
+ for pkg in self._pkgs:
+ self.log.debug("Check pkg: {}".format(pkg))
+ if os.path.isfile(pkg) is False:
+ raise OnboardPkgFileError("Unable to access file: {}".format(pkg))
+
+ if args.instantiate:
+ if args.nsd_id is None:
+ raise OnboardPkgMissingDescId("NS Descriptor ID required for instantiation")
+
+ if args.datacenter:
+ try:
+ uuid.UUID(args.datacenter)
+ self._dc = args.datacenter
+ except ValueError as e:
+ raise OnboardPkgInvalidDescId("Invalid UUID for datacenter: {}".
+ format(args.datacenter))
+
+ elif args.vim_account:
+ self._account = args.vim_account
+
+ else:
+ raise OnboardPkgMissingAcct("Datacenter or VIM account required for instantiation")
+
+ self._service_name = args.instantiate
+ self._nsd_id = args.nsd_id
+
+ self.log.debug("Instantiate NSD {} as {} on {}".format(self._nsd_id,
+ self._service_name,
+ self._account))
+
+ if (self._pkgs is None) and (self._nsd_id is None):
+ raise OnboardPkgInputError("Need to specify either upload-pkg or instantiate options")
+
+ # Validate the port numbers are correct
+ def valid_port(port):
+ if 1 <= port <= 65535:
+ return True
+ return False
+
+ if not valid_port(self._uport):
+ raise OnboardPkgInvalidPort("Invalid upload port: {}".format(self._uport))
+
+ if not valid_port(self._rport):
+ raise OnboardPkgInvalidPort("Invalid Restconf port: {}".format(self._rport))
+
+ def _exec_cmd(self, cmd):
+ self.log.debug("Execute command: {}".format(cmd))
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
+ (output, err) = proc.communicate()
+ rc = proc.returncode
+ self.log.debug("Command exec status: {}, {}, {}".format(rc, output, err))
+ if rc != 0:
+ raise OnboardPkgCmdError("Command {} failed ({}): {}".
+ format(cmd, rc, err))
+ return output.decode("utf-8")
+
+ def validate_connectivity(self):
+ if self._pkgs:
+ self.log.debug("Check connectivity to SO at {}:{}".
+ format(self._ip, self._uport))
+
+ with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
+ if sock.connect_ex((self._ip, self._uport)) != 0:
+ raise OnboardPkgSoConnError("Connection error to SO for upload at {}:{}".
+ format(self._ip, self._uport))
+ self.log.debug("Connection to SO upload port succeeded")
+
+ if self._nsd_id:
+ self.log.debug("Check connectivity to SO at {}:{}, with credentials {}:{}".
+ format(self._ip, self._rport, self._user, self._password))
+
+ rest_url = self._conf_url+"/resource-orchestrator"
+ try:
+ output = self._exec_cmd(rest_url)
+ self.log.debug("Output of restconf validation: {}".
+ format(output))
+ if len(output) != 0:
+ js = json.loads(output)
+ if "error" in js:
+ raise OnboardPkgRcConnError("SO Restconf connect error: {}".
+ format(js["error"]))
+
+ self.log.debug("Connection to SO restconf port succeeded")
+
+ except OnboardPkgCmdError as e:
+ self.log.error("SO restconf connect failed: {}".format(e))
+ raise OnboardPkgRcConnError("SO Restconf connect error: {}".
+ format(e))
+
+
+ def _upload_package(self, pkg):
+ upload_cmd = "{url} -F \"descriptor=@{pkg}\" ". \
+ format(url=self._upload_url,
+ pkg=pkg)
+ self.log.debug("Upload pkg {} cmd: {}".format(pkg, upload_cmd))
+
+ output = self._exec_cmd(upload_cmd)
+
+ # Get the transaction id and wait for upload to complete
+ tx_id = json.loads(output)['transaction_id']
+
+ upload_status_url = "{url}/{id}/state". \
+ format(url=self._upload_url,
+ id=tx_id)
+ status = ""
+ while status not in ['success', 'failure']:
+ output = self._exec_cmd(upload_status_url)
+ js = json.loads(output)
+ self.log.debug("Upload status of pkg {}: {}".format(pkg, js))
+ status = js['status']
+
+ if status != 'success':
+ raise OnboardPkgUploadError("Package {} upload failed: {}".
+ format(pkg, js['errors']))
+
+ self.log.info("Upload of package {} succeeded".format(pkg))
+
+ def upload_packages(self):
+ if self._pkgs is None:
+ self.log.debug("Upload packages not provided")
+ return
+
+ for pkg in self._pkgs:
+ self._upload_package(pkg)
+
+ def instantiate(self):
+ if self._nsd_id is None:
+ self.log.debug("No NSD ID provided for instantiation")
+ return
+
+ # TODO: Add check to see if datacenter is valid
+
+ # Check cloud account is valid, if provided
+ if self._account:
+ acct_url = "{url}/cloud/account/{acct}". \
+ format(url=self._conf_url, acct=self._account)
+ output = self._exec_cmd(acct_url)
+ if (output is None) or (len(output) == 0):
+ # Account not found
+ raise OnboardPkgAcctError("VIM/Cloud account {} provided is not valid".
+ format(self._account))
+
+ # Check id NSD ID is valid
+ nsd_url = "{url}/nsd-catalog/nsd/{nsd_id}". \
+ format(url=self._conf_url, nsd_id=self._nsd_id)
+ output = self._exec_cmd(nsd_url)
+ if (output is None) or (len(output) == 0):
+ # NSD not found
+ raise OnboardPkgNsdError("NSD ID {} provided is not valid".
+ format(self._nsd_id))
+
+ js = json.loads(output)
+ if "error" in js:
+ raise OnboardPkgNsdError("NSD ID {} error: {}".
+ format(self._nsd_id,
+ js['error']))
+
+ nsd = js['nsd:nsd']
+ self.log.debug("NSD to instantiate: {}".format(nsd))
+
+ # Generate a UUID for NS
+ ns_id = str(uuid.uuid4())
+ self.log.debug("NS instance uuid: {}".format(ns_id))
+
+ # Build the nsr post data
+ nsr = {"id": ns_id,
+ 'name': self._service_name,
+ "nsd": nsd,}
+ if self._dc:
+ nsr['om-datacenter'] = self._dc
+ else:
+ nsr['cloud-account'] = self._account
+
+ data = {'nsr': [nsr]}
+
+ data_str = json.dumps(data)
+ self.log.debug("NSR post data: {}".format(data_str))
+
+ inst_url = "{url}/ns-instance-config -X POST -d '{data}'". \
+ format(url=self._conf_url, data=data_str)
+ output = self._exec_cmd(inst_url)
+ self.log.debug("Instantiate output: {}".format(output))
+
+ js = json.loads(output)
+
+ if "last-error" in js:
+ msg = "Error instantiating NS as {} with NSD {}: ". \
+ format(self._service_name, self._nsd_id,
+ js["last-error"])
+ self.log.error(msg)
+ raise OnboardPkgInstError(msg)
+
+ elif "rpc-reply" in js:
+ reply = js["rpc-reply"]
+ if "rpc-error" in reply:
+ msg = "Error instantiating NS as {} with NSD {}: ". \
+ format(self._service_name, self._nsd_id,
+ reply["rpc-error"])
+ self.log.error(msg)
+ raise OnboardPkgInstError(msg)
+
+ self.log.info("Successfully initiated instantiation of NS as {} ({})".
+ format(self._service_name, ns_id))
+
+ def process(self):
+ self.validate_args()
+ self.validate_connectivity()
+ self.upload_packages()
+ self.instantiate()
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Upload and instantiate NS')
+ parser.add_argument("-s", "--so-ip", default='localhost',
+ help="SO Launchpad IP")
+
+ parser.add_argument("-u", "--upload-pkg", action='append',
+ help="Descriptor packages to upload. " + \
+ "If multiple descriptors are provided, they are uploaded in the same sequence.")
+
+ parser.add_argument("-i", "--instantiate",
+ help="Instantiate a network service with the name")
+ parser.add_argument("-d", "--nsd-id",
+ help="Network descriptor ID to instantiate")
+ parser.add_argument("-D", "--datacenter",
+ help="OpenMano datacenter to instantiate on")
+ parser.add_argument("-c", "--vim-account",
+ help="Cloud/VIM account to instantiate on")
+
+ parser.add_argument("-p", "--upload-port", default=4567, type=int,
+ help="Upload port number, default 4567")
+ parser.add_argument("-P", "--restconf-port", default=8888, type=int,
+ help="RESTconf port number, default 8888")
+ parser.add_argument("--restconf-user", default='admin',
+ help="RESTconf user name, default admin")
+ parser.add_argument("--restconf-password", default='admin',
+ help="RESTconf password, default admin")
+
+ parser.add_argument("-v", "--verbose", action='store_true',
+ help="Show more logs")
+
+ args = parser.parse_args()
+
+ fmt = logging.Formatter(
+ '%(asctime)-23s %(levelname)-5s (%(name)s@%(process)d:' \
+ '%(filename)s:%(lineno)d) - %(message)s')
+ stderr_handler = logging.StreamHandler(stream=sys.stderr)
+ stderr_handler.setFormatter(fmt)
+ logging.basicConfig(level=logging.INFO)
+ log = logging.getLogger('onboard-pkg')
+ log.addHandler(stderr_handler)
+ if args.verbose:
+ log.setLevel(logging.DEBUG)
+
+ log.debug("Input arguments: {}".format(args))
+
+ ob = OnboardPackage(log, args)
+ ob.process()
+++ /dev/null
-#!/bin/bash
-
-# Script details
-SCRIPTNAME=`basename $0`
-SCRIPT=$0
-SCRIPT_ARGS=${@}
-
-# Initialize some of the variables
-if [ "$RIFT_LP_ADDR" = "" ]; then
- RIFT_LP_ADDR="localhost"
-fi
-PKGS=()
-INSTANTIATE=0
-DESC_ID=""
-NS_NAME=""
-LOGGING=0
-RIFT_LP_PKG_UPLOAD_URL="https://${RIFT_LP_ADDR}:4567/api/upload"
-
-######################################################################
-# Function:usage #
-# Prints usage #
-######################################################################
-function usage() {
- cat <<EOF
- usage $SCRIPTNAME [-h] [-r launchpad-ip][-u upload-package][-i ns-service-name [-d descriptor-id]][-l]
- -h : show this message
- -r : launchpad ip address - defaults to RIFT_LP_ADDR enviroment variable
- -u : upload package with the package name specified
- -i : Instantiate a network service with network service name
- -d : Instantiate a network service with the specified descriptor
- -l : Log to file
-EOF
-}
-
-######################################################################
-# Function:validate_args #
-# Validates the passed arguments #
-######################################################################
-function validate_args () {
- if [ "$RIFT_LP_ADDR" = "" ]; then
- echo "RIFT LP address must be specified - set RIFT_LP_ADDR or specify -l option"
- usage
- exit 1
- fi
- if [ "${#PKGS[@]}" -eq 0 -a "${INSTANTIATE}" -eq 0 ]; then
- echo "One of -u or -i option must be specified"
- usage
- exit 1
- fi
- if [ "${INSTANTIATE}" -eq 1 ]; then
- if [ "${NS_NAME}" = "" -o "${DESC_ID}" = "" ]; then
- echo "Must specify both descriptor id and ns service name when -i is specified"
- usage
- exit 1
- fi
- fi
-}
-
-######################################################################
-# Function:upload_pacakage #
-# Uploads a package with the passed argument #
-######################################################################
-function upload_package() {
- if [ -z "$1" ]; then
- echo "upload_package: package name should be passed in as an argument"
- usage
- exit 1
- fi
- PACKAGE=$1
- curl --insecure -F "descriptor=@${PACKAGE}" ${RIFT_LP_PKG_UPLOAD_URL}
-}
-
-######################################################################
-# Function:instantiate_ns #
-# Instantiates a netork service #
-######################################################################
-function instantiate_ns() {
- echo "instantiate_ns need implementation"
-}
-
-
-while getopts ":hl:r:u:i:n:" OPTION
-do
- case $OPTION in
- h)
- usage
- exit 1
- ;;
- r)
- RIFT_LP_ADDR=$OPTARG
- RIFT_LP_PKG_UPLOAD_URL="https://${RIFT_LP_ADDR}:4567/api/upload"
- ;;
- u)
- PKGS+=($OPTARG)
- ;;
- i)
- INSTANTIATE=1
- NS_NAME=$OPTARG
- ;;
- n)
- DESC_ID=$OPTARG
- ;;
- l)
- LOGGING=1
- ;;
- *)
- usage
- exit 1
- ;;
- esac
-done
-
-shift $((OPTIND-1))
-
-validate_args
-
-if [ $LOGGING -eq 1 ]; then
- LOGDIR="/tmp"
- LOGFILE="$LOGDIR/$SCRIPTNAME-$DATE.log"
- echo "Logging to file $LOGFILE"
-
- # Redirect stdout ( > ) and stderr to file
- # and store the STDOUT and STDERR for later use
- exec 3>&1
- exec 4>&2
- exec >$LOGFILE
- exec 2>&1
-fi
-
-echo "Started at $DATE"
-
-# Iterate through the packages and upload them
-for PKG in "${PKGS[@]}"
-do
- echo "Uploading package $PKG"
- upload_package $PKG
- echo ""
-done
-
-if [ "${INSTANTIATE}" -eq 1 ]; then
- instantiate_ns $DESC_ID
-fi
-
-echo "Ended at $DATE"