+#
+# All Rights Reserved.
+#
+# 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.
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM client entry point
+"""
+
+from osmclient.v1 import client
+
+
+def Client(version=1, host = None, *args, **kwargs):
+ if version == 1:
+ return client.Client(host, *args, **kwargs)
+ else:
+ raise Exception("Unsupported client version")
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+
+class ClientException(Exception):
+ pass
+
+class NotFound(ClientException):
+ pass
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+from io import BytesIO
+import pycurl
+import json
+
+
+class Http(object):
+
+ def __init__(self,url,user='admin',password='admin'):
+ self._url = url
+ self._user = user
+ self._password = password
+ self._http_header = None
+
+ def set_http_header(self,header):
+ self._http_header = header
+
+ def _get_curl_cmd(self,endpoint):
+ curl_cmd = pycurl.Curl()
+ curl_cmd.setopt(pycurl.URL, self._url + endpoint )
+ curl_cmd.setopt(pycurl.SSL_VERIFYPEER,0)
+ curl_cmd.setopt(pycurl.SSL_VERIFYHOST,0)
+ curl_cmd.setopt(pycurl.USERPWD, '{}:{}'.format(self._user,self._password))
+ if self._http_header:
+ curl_cmd.setopt(pycurl.HTTPHEADER, self._http_header)
+ return curl_cmd
+
+ def get_cmd( self, endpoint ):
+
+ data = BytesIO()
+ curl_cmd=self._get_curl_cmd(endpoint)
+ curl_cmd.setopt(pycurl.HTTPGET,1)
+ curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
+ curl_cmd.perform()
+ curl_cmd.close()
+ if data.getvalue():
+ return json.loads(data.getvalue().decode())
+ return None
+
+ def delete_cmd( self, endpoint ):
+ data = BytesIO()
+ curl_cmd=self._get_curl_cmd(endpoint)
+ curl_cmd.setopt(pycurl.CUSTOMREQUEST, "DELETE")
+ curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
+ curl_cmd.perform()
+ curl_cmd.close()
+ if data.getvalue():
+ return json.loads(data.getvalue().decode())
+ return None
+
+ def post_cmd( self, endpoint='', postfields_dict=None, formfile=None, ):
+ data = BytesIO()
+ curl_cmd=self._get_curl_cmd(endpoint)
+ curl_cmd.setopt(pycurl.POST,1)
+ curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
+
+ if postfields_dict is not None:
+ jsondata=json.dumps(postfields_dict)
+ curl_cmd.setopt(pycurl.POSTFIELDS,jsondata)
+
+ if formfile is not None:
+ curl_cmd.setopt(pycurl.HTTPPOST,[((formfile[0],(pycurl.FORM_FILE,formfile[1])))])
+
+ curl_cmd.perform()
+ curl_cmd.close()
+ if data.getvalue():
+ return json.loads(data.getvalue().decode())
+ return None
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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 unittest
+from osmclient.common import utils
+
+class TestUtil(unittest.TestCase):
+
+ def test_wait_for_method_basic(self):
+ def foobar():
+ return True
+ assert utils.wait_for_value(lambda: foobar())
+
+ def test_wait_for_method_timeout(self):
+ def foobar():
+ return False
+ assert not utils.wait_for_value(lambda: foobar(),wait_time=0)
+
+ def test_wait_for_method_paramter(self):
+ def foobar(input):
+ return input
+ assert not utils.wait_for_value(lambda: foobar(False),wait_time=0)
+ assert utils.wait_for_value(lambda: foobar(True),wait_time=0)
+
+ def test_wait_for_method_wait_for_change(self):
+ def foobar():
+ if foobar.counter == 0:
+ return True
+ foobar.counter -=1
+ return False
+ foobar.counter=1
+ assert utils.wait_for_value(lambda: foobar(),wait_time=1)
+
+ def test_wait_for_method_exception(self):
+ def foobar():
+ raise Exception('send exception')
+ assert not utils.wait_for_value(lambda: foobar(),wait_time=0,catch_exception=Exception)
+
+ def test_wait_for_method_first_exception(self):
+ def foobar():
+ if foobar.counter == 0:
+ return True
+ foobar.counter -=1
+ raise Exception('send exception')
+ foobar.counter=1
+ assert utils.wait_for_value(lambda: foobar(),wait_time=1,catch_exception=Exception)
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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 time
+
+
+def wait_for_value(func, result=True, wait_time=10, catch_exception = None ):
+ maxtime = time.time() + wait_time
+ while time.time() < maxtime:
+ try:
+ if func() == result:
+ return True
+ except catch_exception as inst:
+ pass
+ time.sleep(1)
+ try:
+ return func() == result
+ except catch_exception as inst:
+ return False
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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 click
-from osmclient.common import OsmAPI
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+"""
+OSM shell/cli
+"""
+
+import click
+from osmclient.client import client
+from osmclient.common.exceptions import ClientException
from prettytable import PrettyTable
-import pprint
-import textwrap
+import json
+
@click.group()
@click.option('--hostname',default=None,envvar='OSM_HOSTNAME',help='hostname of server. Also can set OSM_HOSTNAME in environment')
if hostname is None:
print("either hostname option or OSM_HOSTNAME environment variable needs to be specified")
exit(1)
- ctx.obj=OsmAPI.OsmAPI(hostname)
+ ctx.obj=client.Client(host=hostname)
@cli.command(name='ns-list')
@click.pass_context
def ns_list(ctx):
- ctx.obj.list_ns_instance()
+ resp=ctx.obj.ns.list()
+ table=PrettyTable(['ns instance name','id','operational status','config status'])
+ for ns in resp:
+ nsopdata=ctx.obj.ns.get_opdata(ns['id'])
+ nsr=nsopdata['nsr:nsr']
+ table.add_row([nsr['name-ref'],nsr['ns-instance-config-ref'],nsr['operational-status'],nsr['config-status']])
+ table.align='l'
+ print(table)
@cli.command(name='nsd-list')
@click.pass_context
def nsd_list(ctx):
- ctx.obj.list_ns_catalog()
+ resp=ctx.obj.nsd.list()
+ table=PrettyTable(['nsd name','id'])
+ for ns in resp:
+ table.add_row([ns['name'],ns['id']])
+ table.align='l'
+ print(table)
@cli.command(name='vnfd-list')
@click.pass_context
def vnfd_list(ctx):
- ctx.obj.list_vnf_catalog()
+ resp = ctx.obj.vnfd.list()
+ table=PrettyTable(['vnfd name','id'])
+ for vnfd in resp:
+ table.add_row([vnfd['name'],vnfd['id']])
+ table.align='l'
+ print(table)
@cli.command(name='vnf-list')
@click.pass_context
def vnf_list(ctx):
- resp=ctx.obj.list_vnfr()
- table=PrettyTable(['vnf name','id','operational status','config Status','mgmt interface','nsr id'])
- if resp is not None:
- for vnfr in resp['vnfr:vnfr']:
- if not 'mgmt-interface' in vnfr:
- vnfr['mgmt-interface'] = {}
- vnfr['mgmt-interface']['ip-address'] = None
- table.add_row([vnfr['name'],vnfr['id'],vnfr['operational-status'],vnfr['config-status'],vnfr['mgmt-interface']['ip-address'],vnfr['nsr-id-ref']])
- table.align='l'
+ resp=ctx.obj.vnf.list()
+ table=PrettyTable(['vnf name','id','operational status','config status'])
+ for vnfr in resp:
+ if not 'mgmt-interface' in vnfr:
+ vnfr['mgmt-interface'] = {}
+ vnfr['mgmt-interface']['ip-address'] = None
+ table.add_row([vnfr['name'],vnfr['id'],vnfr['operational-status'],vnfr['config-status']])
+ table.align='l'
+ print(table)
+
+@cli.command(name='vnf-show')
+@click.argument('vnf_name')
+@click.option('--filter',default=None)
+@click.pass_context
+def vnf_show(ctx,vnf_name,filter):
+ try:
+ resp=ctx.obj.vnf.get(vnf_name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
+ table=PrettyTable(['field','value'])
+ for k,v in resp.items():
+ if filter is None or filter in k:
+ table.add_row([k,json.dumps(v,indent=2)])
+ table.align='l'
print(table)
@cli.command(name='vnf-monitoring-show')
@click.argument('vnf_name')
@click.pass_context
def vnf_monitoring_show(ctx,vnf_name):
- resp=ctx.obj.get_vnf_monitoring(vnf_name)
+ try:
+ resp=ctx.obj.vnf.get_monitoring(vnf_name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
table=PrettyTable(['vnf name','monitoring name','value','units'])
if resp is not None:
for monitor in resp:
@click.argument('ns_name')
@click.pass_context
def ns_monitoring_show(ctx,ns_name):
- resp=ctx.obj.get_ns_monitoring(ns_name)
+ try:
+ resp=ctx.obj.ns.get_monitoring(ns_name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
table=PrettyTable(['vnf name','monitoring name','value','units'])
- if resp is not None:
- for key,val in resp.items():
- for monitor in val:
- table.add_row([key,monitor['name'],monitor['value-integer'],monitor['units']])
+ for key,val in resp.items():
+ for monitor in val:
+ table.add_row([key,monitor['name'],monitor['value-integer'],monitor['units']])
table.align='l'
print(table)
@cli.command(name='ns-create')
-@click.argument('nsd_name')
-@click.argument('ns_name')
-@click.argument('vim_account')
+@click.option('--ns_name',prompt=True)
+@click.option('--nsd_name',prompt=True)
+@click.option('--vim_account',prompt=True)
@click.option('--admin_status',default='ENABLED',help='administration status')
@click.option('--ssh_keys',default=None,help='comma separated list of keys to inject to vnfs')
@click.option('--vim_network_prefix',default=None,help='vim network name prefix')
@click.pass_context
def ns_create(ctx,nsd_name,ns_name,vim_account,admin_status,ssh_keys,vim_network_prefix):
- ctx.obj.instantiate_ns(nsd_name,ns_name,vim_network_prefix=vim_network_prefix,ssh_keys=ssh_keys,account=vim_account)
+ try:
+ ctx.obj.ns.create(nsd_name,ns_name,vim_network_prefix=vim_network_prefix,ssh_keys=ssh_keys,account=vim_account)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
@cli.command(name='ns-delete')
@click.argument('ns_name')
@click.pass_context
def ns_delete(ctx,ns_name):
- ctx.obj.terminate_ns(ns_name)
-
-'''
-@cli.command(name='keypair-list')
-@click.pass_context
-def keypair_list(ctx):
- resp=ctx.obj.list_key_pair()
- table=PrettyTable(['key Name','key'])
- for kp in resp:
- table.add_row([kp['name'],kp['key']])
- table.align='l'
- print(table)
-'''
+ try:
+ ctx.obj.ns.delete(ns_name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
@cli.command(name='upload-package')
@click.argument('filename')
@click.pass_context
def upload_package(ctx,filename):
- ctx.obj.upload_package(filename)
+ try:
+ ctx.obj.package.upload(filename)
+ ctx.obj.package.wait_for_upload(filename)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
@cli.command(name='ns-show')
@click.argument('ns_name')
+@click.option('--filter',default=None)
@click.pass_context
-def ns_show(ctx,ns_name):
- ctx.obj.show_ns(ns_name)
+def ns_show(ctx,ns_name,filter):
+ try:
+ ns = ctx.obj.ns.get(ns_name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
+ table=PrettyTable(['field','value'])
+
+ for k,v in ns.items():
+ if filter is None or filter in k:
+ table.add_row([k,json.dumps(v,indent=2)])
+
+ nsopdata=ctx.obj.ns.get_opdata(ns['id'])
+ nsr_optdata=nsopdata['nsr:nsr']
+ for k,v in nsr_optdata.items():
+ if filter is None or filter in k:
+ table.add_row([k,json.dumps(v,indent=2)])
+ table.align='l'
+ print(table)
@cli.command(name='ns-scaling-show')
@click.argument('ns_name')
@click.pass_context
def show_ns_scaling(ctx,ns_name):
- ctx.obj.show_ns_scaling(ns_name)
+ resp = ctx.obj.ns.list()
+
+ table=PrettyTable(['instance-id','operational status','create-time','vnfr ids'])
+
+ if 'nsr' in resp:
+ for ns in resp['nsr']:
+ if ns_name == ns['name']:
+ nsopdata=ctx.obj.ns.get_opdata(ns['id'])
+ scaling_records=nsopdata['nsr:nsr']['scaling-group-record']
+ for record in scaling_records:
+ if 'instance' in record:
+ instances=record['instance']
+ for inst in instances:
+ table.add_row([inst['instance-id'],inst['op-status'],time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(inst['create-time'])),inst['vnfrs']])
+ table.align='l'
+ print(table)
@cli.command(name='nsd-delete')
@click.argument('nsd_name')
@click.pass_context
def nsd_delete(ctx,nsd_name):
- ctx.obj.delete_nsd(nsd_name)
+ try:
+ ctx.obj.nsd.delete(nsd_name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
@cli.command(name='vnfd-delete')
@click.argument('vnfd_name')
@click.pass_context
-def nsd_delete(ctx,vnfd_name):
- ctx.obj.delete_vnfd(vnfd_name)
+def vnfd_delete(ctx,vnfd_name):
+ try:
+ ctx.obj.vnfd.delete(vnfd_name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
@cli.command(name='config-agent-list')
@click.pass_context
def config_agent_list(ctx):
table=PrettyTable(['name','account-type','details'])
- for account in ctx.obj.get_config_agents():
+ for account in ctx.obj.vca.list():
table.add_row([account['name'],account['account-type'],account['juju']])
table.align='l'
print(table)
@click.argument('name')
@click.pass_context
def config_agent_delete(ctx,name):
- ctx.obj.delete_config_agent(name)
+ try:
+ ctx.obj.vca.delete(name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
@cli.command(name='config-agent-add')
-@click.argument('name')
-@click.argument('account_type')
-@click.argument('server')
-@click.argument('user')
-@click.argument('secret')
+@click.option('--name',prompt=True)
+@click.option('--account_type',prompt=True)
+@click.option('--server',prompt=True)
+@click.option('--user',prompt=True)
+@click.option('--secret',prompt=True,hide_input=True,confirmation_prompt=True)
@click.pass_context
def config_agent_add(ctx,name,account_type,server,user,secret):
- ctx.obj.add_config_agent(name,account_type,server,user,secret)
+ try:
+ ctx.obj.vca.create(name,account_type,server,user,secret)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
-'''
@cli.command(name='vim-create')
-@click.argument('name')
-@click.argument('user')
-@click.argument('password')
-@click.argument('auth_url')
-@click.argument('tenant')
-@click.argument('mgmt_network')
-@click.argument('floating_ip_pool')
+@click.option('--name',prompt=True)
+@click.option('--user',prompt=True)
+@click.option('--password',prompt=True,hide_input=True,confirmation_prompt=True)
+@click.option('--auth_url',prompt=True)
+@click.option('--tenant',prompt=True)
+@click.option('--floating_ip_pool',default=None)
+@click.option('--keypair',default=None)
@click.option('--account_type',default='openstack')
+@click.option('--description',default='no description')
@click.pass_context
-def vim_create(ctx,name,user,password,auth_url,tenant,mgmt_network,floating_ip_pool,account_type):
- ctx.obj.add_vim_account(name,user,password,auth_url,tenant,mgmt_network,floating_ip_pool,account_type)
-'''
+def vim_create(ctx,name,user,password,auth_url,tenant,floating_ip_pool,keypair,account_type,description):
+ vim={}
+ vim['os-username']=user
+ vim['os-password']=password
+ vim['os-url']=auth_url
+ vim['os-project-name']=tenant
+ vim['floating_ip_pool']=floating_ip_pool
+ vim['keypair']=keypair
+ vim['vim-type']='openstack'
+ vim['description']=description
+ try:
+ ctx.obj.vim.create(name,vim)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
+@cli.command(name='vim-delete')
+@click.argument('name')
+@click.pass_context
+def vim_delete(ctx,name):
+ try:
+ ctx.obj.vim.delete(name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
@cli.command(name='vim-list')
@click.pass_context
def vim_list(ctx):
- resp=ctx.obj.list_vim_accounts()
- table=PrettyTable(['ro-account','datacenter name','uuid'])
- for roaccount in resp:
- for datacenter in roaccount['datacenters']:
- table.add_row([roaccount['name'],datacenter['name'],datacenter['uuid']])
+ resp=ctx.obj.vim.list()
+ table=PrettyTable(['vim name','uuid'])
+ for vim in resp:
+ table.add_row([vim['name'],vim['uuid']])
+ table.align='l'
+ print(table)
+
+@cli.command(name='vim-show')
+@click.argument('name')
+@click.pass_context
+def vim_show(ctx,name):
+ try:
+ resp=ctx.obj.vim.get(name)
+ except ClientException as inst:
+ print(inst.message)
+ exit(1)
+
+ table=PrettyTable(['key','attribute'])
+ for k,v in resp.items():
+ table.add_row([k,json.dumps(v,indent=2)])
+ table.align='l'
+ print(table)
+
+@cli.command(name='ro-dump')
+@click.pass_context
+def ro_dump(ctx):
+ resp=ctx.obj.vim.get_resource_orchestrator()
+ table=PrettyTable(['key','attribute'])
+ for k,v in resp.items():
+ table.add_row([k,json.dumps(v,indent=2)])
table.align='l'
print(table)
@cli.command(name='vcs-list')
@click.pass_context
def vcs_list(ctx):
- resp=ctx.obj.get_vcs_info()
+ resp=ctx.obj.utils.get_vcs_info()
table=PrettyTable(['component name','state'])
for component in resp:
table.add_row([component['component_name'],component['state']])
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM v1 client API
+"""
+
+from osmclient.v1 import vnf
+from osmclient.v1 import vnfd
+from osmclient.v1 import ns
+from osmclient.v1 import nsd
+from osmclient.v1 import vim
+from osmclient.v1 import package
+from osmclient.v1 import vca
+from osmclient.v1 import utils
+from osmclient.common import http
+import pycurl
+
+
+class Client(object):
+
+ def __init__(self, host=None,ro_port=9090,upload_port=8443,**kwargs):
+ self._user='admin'
+ self._password='admin'
+ self._host = host.split(':')[0]
+ self._so_port = host.split(':')[1]
+
+ http_client = http.Http('https://{}:{}/'.format(self._host,self._so_port))
+ http_client.set_http_header( ['Accept: application/vnd.yand.data+json','Content-Type: application/json'])
+
+ ro_http_client = http.Http('http://{}:{}/'.format(self._host,ro_port))
+ ro_http_client.set_http_header( ['Accept: application/vnd.yand.data+json','Content-Type: application/json'])
+
+ upload_client = http.Http('https://{}:{}/composer/upload?api_server=https://localhost&upload_server=https://{}'.format(self._host,upload_port,self._host))
+
+ self.vnf = vnf.Vnf(http_client,**kwargs)
+ self.vnfd = vnfd.Vnfd(http_client,**kwargs)
+ self.ns = ns.Ns(http=http_client,client=self,**kwargs)
+ self.nsd = nsd.Nsd(http_client,**kwargs)
+ self.vim = vim.Vim(http=http_client,ro_http=ro_http_client,client=self,**kwargs)
+ self.package = package.Package(http=http_client,upload_http=upload_client,client=self,**kwargs)
+ self.vca = vca.Vca(http_client,**kwargs)
+ self.utils = utils.Utils(http_client,**kwargs)
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM ssh-key API handling
+"""
+
+import json
+import pycurl
+from io import BytesIO
+
+
+class Key(object):
+
+ def __init__(self,client=None):
+ self._client=client
+
+ def list(self):
+ data = BytesIO()
+ curl_cmd=self._client.get_curl_cmd('v1/api/config/key-pair?deep')
+ curl_cmd.setopt(pycurl.HTTPGET,1)
+ curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
+ curl_cmd.perform()
+ curl_cmd.close()
+ resp = json.loads(data.getvalue().decode())
+ if 'nsr:key-pair' in resp:
+ return resp['nsr:key-pair']
+ return list()
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM ns API handling
+"""
+
+from osmclient.common import utils
+from osmclient.common.exceptions import ClientException
+from osmclient.common.exceptions import NotFound
+import uuid
+import pprint
+
+
+class Ns(object):
+ def __init__(self,http=None,client=None):
+ self._http=http
+ self._client=client
+
+ def list(self):
+ """Returns a list of ns's
+ """
+ resp = self._http.get_cmd('api/running/ns-instance-config')
+
+ if not resp or 'nsr:ns-instance-config' not in resp:
+ return list()
+
+ if 'nsr' not in resp['nsr:ns-instance-config']:
+ return list()
+
+ return resp['nsr:ns-instance-config']['nsr']
+
+ def get(self,name):
+ """Returns an ns based on name
+ """
+ for ns in self.list():
+ if name == ns['name']:
+ return ns
+ raise NotFound("ns {} not found".format(name))
+
+ def create(self,nsd_name,nsr_name,account,vim_network_prefix=None,ssh_keys=None,description='default description',admin_status='ENABLED'):
+ postdata={}
+ postdata['nsr'] = list()
+ nsr={}
+ nsr['id']=str(uuid.uuid1())
+
+ nsd=self._client.nsd.get(nsd_name)
+
+ datacenter=self._client.vim.get_datacenter(account)
+ if datacenter is None:
+ raise NotFound("cannot find datacenter account {}".format(account))
+
+ nsr['nsd']=nsd
+ nsr['name']=nsr_name
+ nsr['short-name']=nsr_name
+ nsr['description']=description
+ nsr['admin-status']=admin_status
+ nsr['om-datacenter']=datacenter['uuid']
+
+ if ssh_keys is not None:
+ # ssh_keys is comma separate list
+ ssh_keys_format=[]
+ for key in ssh_keys.split(','):
+ ssh_keys_format.append({'key-pair-ref':key})
+
+ nsr['ssh-authorized-key']=ssh_keys_format
+
+ if vim_network_prefix is not None:
+ for index,vld in enumerate(nsr['nsd']['vld']):
+ network_name = vld['name']
+ nsr['nsd']['vld'][index]['vim-network-name'] = '{}-{}'.format(vim_network_prefix,network_name)
+
+ postdata['nsr'].append(nsr)
+
+ resp = self._http.post_cmd('api/config/ns-instance-config/nsr',postdata)
+
+ if 'success' not in resp:
+ raise ClientException("failed to create ns: {} nsd: {} result: {}".format(nsr_name,nsd_name,resp))
+
+ def get_opdata(self,id):
+ return self._http.get_cmd('api/operational/ns-instance-opdata/nsr/{}?deep'.format(id))
+
+ def get_field(self,ns_name,field):
+ nsr=self.get(ns_name)
+ if nsr is None:
+ raise NotFound("failed to retrieve ns {}".format(ns_name))
+
+ if field in nsr:
+ return nsr[field]
+
+ nsopdata=self.get_opdata(nsr['id'])
+
+ if field in nsopdata['nsr:nsr']:
+ return nsopdata['nsr:nsr'][field]
+
+ raise NotFound("failed to find {} in ns {}".format(field,ns_name))
+
+ def _terminate(self,ns_name):
+ ns=self.get(ns_name)
+ if ns is None:
+ raise NotFound("cannot find ns {}".format(ns_name))
+
+ return self._http.delete_cmd('api/config/ns-instance-config/nsr/'+ns['id'])
+
+ def delete(self,ns_name,wait=True):
+ vnfs = self.get_field(ns_name,'constituent-vnfr-ref')
+
+ resp=self._terminate(ns_name)
+ if 'success' not in resp:
+ raise ClientException("failed to delete ns {}".format(name))
+
+ # helper method to check if pkg exists
+ def check_not_exists( func ):
+ try:
+ func()
+ return False
+ except NotFound:
+ return True
+
+ for vnf in vnfs:
+ if not utils.wait_for_value(lambda: check_not_exists(lambda: self._client.vnf.get(vnf['vnfr-id']))):
+ raise ClientException("vnf {} failed to delete".format(vnf['vnfr-id']))
+ if not utils.wait_for_value(lambda: check_not_exists(lambda: self.get(ns_name))):
+ raise ClientException("ns {} failed to delete".format(ns_name))
+
+ def get_monitoring(self,ns_name):
+ ns=self.get(ns_name)
+ mon_list={}
+ if ns is None:
+ return mon_list
+
+ vnfs=self._client.vnf.list()
+ for vnf in vnfs:
+ if ns['id'] == vnf['nsr-id-ref']:
+ if 'monitoring-param' in vnf:
+ mon_list[vnf['name']] = vnf['monitoring-param']
+
+ return mon_list
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM nsd API handling
+"""
+
+from osmclient.common.exceptions import NotFound
+from osmclient.common.exceptions import ClientException
+
+
+class Nsd(object):
+ def __init__(self,http=None):
+ self._http=http
+
+ def list(self):
+ resp = self._http.get_cmd('api/running/nsd-catalog/nsd')
+ if resp and 'nsd:nsd' in resp:
+ return resp['nsd:nsd']
+ return list()
+
+ def get(self,name):
+ for nsd in self.list():
+ if name == nsd['name']:
+ return nsd
+ raise NotFound("cannot find nsd {}".format(name))
+
+ def delete(self,nsd_name):
+ nsd=self.get(nsd_name)
+ if nsd is None:
+ raise NotFound("cannot find nsd {}".format(nsd_name))
+
+ resp=self._http.delete_cmd('api/running/nsd-catalog/nsd/{}'.format(nsd['id']))
+ if 'success' not in resp:
+ raise ClientException("failed to delete nsd {}".format(nsd_name))
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM package API handling
+"""
+
+import json
+import pycurl
+from io import BytesIO
+import tarfile
+import re
+import yaml
+import time
+from osmclient.common.exceptions import ClientException
+from osmclient.common.exceptions import NotFound
+from osmclient.common import utils
+
+
+class Package(object):
+ def __init__(self,http=None,upload_http=None,client=None):
+ self._client=client
+ self._http=http
+ self._upload_http=upload_http
+
+ def _wait_for_package(self,pkg_type):
+ if 'vnfd' in pkg_type['type']:
+ get_method=self._client.vnfd.get
+ elif 'nsd' in pkg_type['type']:
+ get_method=self._client.nsd.get
+ else:
+ raise ClientException("no valid package type found")
+
+ # helper method to check if pkg exists
+ def check_exists( func ):
+ try:
+ func()
+ except NotFound:
+ return False
+ return True
+
+ return utils.wait_for_value(lambda: check_exists(lambda: get_method(pkg_type['name'])))
+
+ # method opens up a package and finds the name of the resulting
+ # descriptor (vnfd or nsd name)
+ def get_descriptor_type_from_pkg(self, descriptor_file):
+ tar = tarfile.open(descriptor_file)
+ yamlfile = None
+ for member in tar.getmembers():
+ if re.match('.*.yaml',member.name) and len(member.name.split('/')) == 2:
+ yamlfile = member.name
+ break
+ if yamlfile is None:
+ return None
+
+ dict=yaml.load(tar.extractfile(yamlfile))
+ result={}
+ for k1,v1 in dict.items():
+ if not k1.endswith('-catalog'):
+ continue
+ for k2,v2 in v1.items():
+ if not k2.endswith('nsd') and not k2.endswith('vnfd'):
+ continue
+
+ if 'nsd' in k2:
+ result['type'] = 'nsd'
+ else:
+ result['type'] = 'vnfd'
+
+ for entry in v2:
+ for k3,v3 in entry.items():
+ if k3 == 'name' or k3.endswith(':name'):
+ result['name'] = v3
+ return result
+ tar.close()
+ return None
+
+ def wait_for_upload(self,filename):
+ """wait(block) for an upload to succeed.
+
+ The filename passed is assumed to be a descriptor tarball.
+ """
+ pkg_type=self.get_descriptor_type_from_pkg(filename)
+
+ if pkg_type is None:
+ raise ClientException("Cannot determine package type")
+
+ if not self._wait_for_package(pkg_type):
+ raise ClientException("package {} failed to upload".format(filename))
+
+ def upload(self,filename):
+ resp=self._upload_http.post_cmd(formfile=('package',filename))
+ if not resp or 'transaction_id' not in resp:
+ raise ClientException("failed to upload package")
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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 unittest
+from mock import Mock
+from osmclient.v1 import ns
+from osmclient.common.exceptions import NotFound
+
+
+class TestNs(unittest.TestCase):
+
+ def test_list_empty(self):
+ mock=Mock()
+ mock.get_cmd.return_value=list()
+ assert len(ns.Ns(mock).list()) == 0
+
+ def test_get_notfound(self):
+ mock=Mock()
+ mock.get_cmd.return_value='foo'
+ self.assertRaises(NotFound,ns.Ns(mock).get,'bar')
+
+ def test_get_found(self):
+ mock=Mock()
+ mock.get_cmd.return_value={'nsr:ns-instance-config': { 'nsr': [{'name': 'foo' }]}}
+ assert ns.Ns(mock).get('foo')
+
+ def test_get_monitoring_notfound(self):
+ mock=Mock()
+ mock.get_cmd.return_value='foo'
+ self.assertRaises(NotFound,ns.Ns(mock).get_monitoring,'bar')
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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 unittest
+from mock import Mock
+from osmclient.v1 import nsd
+from osmclient.common.exceptions import NotFound
+
+class TestNsd(unittest.TestCase):
+
+ def test_list_empty(self):
+ mock=Mock()
+ mock.get_cmd.return_value=list()
+ assert len(nsd.Nsd(mock).list()) == 0
+
+ def test_get_notfound(self):
+ mock=Mock()
+ mock.get_cmd.return_value='foo'
+ self.assertRaises(NotFound,nsd.Nsd(mock).get,'bar')
+
+ def test_get_found(self):
+ mock=Mock()
+ mock.get_cmd.return_value={'nsd:nsd': [{'name': 'foo' }]}
+ assert nsd.Nsd(mock).get('foo')
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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 unittest
+from mock import Mock
+from osmclient.v1 import package
+from osmclient.common.exceptions import ClientException
+
+
+class TestPackage(unittest.TestCase):
+
+ def test_upload_fail(self):
+ mock=Mock()
+ mock.post_cmd.return_value='foo'
+ self.assertRaises(ClientException,package.Package(upload_http=mock).upload,'bar')
+
+ mock.post_cmd.return_value=None
+ self.assertRaises(ClientException,package.Package(upload_http=mock).upload,'bar')
+
+ def test_wait_for_upload_bad_file(self):
+ mock=Mock()
+ mock.post_cmd.return_value='foo'
+ self.assertRaises(IOError,package.Package(upload_http=mock).wait_for_upload,'invalidfile')
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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 unittest
+from mock import Mock
+from osmclient.v1 import vnf
+from osmclient.common.exceptions import NotFound
+
+
+class TestVnf(unittest.TestCase):
+
+ def test_list_empty(self):
+ mock=Mock()
+ mock.get_cmd.return_value=list()
+ assert len(vnf.Vnf(mock).list()) == 0
+
+ def test_get_notfound(self):
+ mock=Mock()
+ mock.get_cmd.return_value='foo'
+ self.assertRaises(NotFound,vnf.Vnf(mock).get,'bar')
+
+ def test_get_found(self):
+ mock=Mock()
+ mock.get_cmd.return_value={'vnfr:vnfr': [{'name': 'foo' }]}
+ assert vnf.Vnf(mock).get('foo')
+
+ def test_get_monitoring_notfound(self):
+ mock=Mock()
+ mock.get_cmd.return_value='foo'
+ self.assertRaises(NotFound,vnf.Vnf(mock).get_monitoring,'bar')
+
+ def test_get_monitoring_found(self):
+ mock=Mock()
+ mock.get_cmd.return_value={'vnfr:vnfr': [{'name': 'foo', 'monitoring-param': True }]}
+ assert vnf.Vnf(mock).get_monitoring('foo')
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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 unittest
+from mock import Mock
+from osmclient.v1 import vnfd
+from osmclient.common.exceptions import NotFound
+
+
+class TestVnfd(unittest.TestCase):
+
+ def test_list_empty(self):
+ mock=Mock()
+ mock.get_cmd.return_value=list()
+ assert len(vnfd.Vnfd(mock).list()) == 0
+
+ def test_get_notfound(self):
+ mock=Mock()
+ mock.get_cmd.return_value='foo'
+ self.assertRaises(NotFound,vnfd.Vnfd(mock).get,'bar')
+
+ def test_get_found(self):
+ mock=Mock()
+ mock.get_cmd.return_value={'vnfd:vnfd': [{'name': 'foo' }]}
+ assert vnfd.Vnfd(mock).get('foo')
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM utils
+"""
+
+class Utils(object):
+ def __init__(self,http=None):
+ self._http=http
+
+ def get_vcs_info(self):
+ resp=self._http.get_cmd('api/operational/vcs/info')
+ if resp:
+ return resp['rw-base:info']['components']['component_info']
+ return list()
+
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM VCA API handling
+"""
+
+from osmclient.common.exceptions import ClientException
+
+class Vca(object):
+
+ def __init__(self,http=None):
+ self._http=http
+
+ def list(self):
+ resp = self._http.get_cmd('api/config/config-agent')
+ if resp and 'rw-config-agent:config-agent' in resp:
+ return resp['rw-config-agent:config-agent']['account']
+ return list()
+
+ def delete(self,name):
+ if 'success' not in self._http.delete_cmd('api/config/config-agent/account/{}'.format(name)):
+ raise ClientException("failed to delete config agent {}".format(name))
+
+ def create(self,name,account_type,server,user,secret):
+ postdata={}
+ postdata['account'] = list()
+
+ account={}
+ account['name'] = name
+ account['account-type'] = account_type
+ account['juju'] = {}
+ account['juju']['user'] = user
+ account['juju']['secret'] = secret
+ account['juju']['ip-address'] = server
+ postdata['account'].append(account)
+
+ if 'success' not in self._http.post_cmd('api/config/config-agent',postdata):
+ raise ClientException("failed to create config agent {}".format(name))
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM vim API handling
+"""
+
+from osmclient.common.exceptions import ClientException
+from osmclient.common.exceptions import NotFound
+
+
+class Vim(object):
+
+ def __init__(self,http=None,ro_http=None,client=None):
+ self._client=client
+ self._ro_http=ro_http
+ self._http=http
+
+ def _attach(self,vim_name,username,secret,vim_tenant_name):
+ tenant_name='osm'
+ tenant=self._get_ro_tenant()
+ if tenant is None:
+ raise ClientException("tenant {} not found".format(tenant_name))
+ datacenter= self._get_ro_datacenter(vim_name)
+ if datacenter is None:
+ raise Exception('datacenter {} not found'.format(vim_name))
+
+ vim_account={}
+ vim_account['datacenter']={}
+
+ vim_account['datacenter']['vim_username'] = username
+ vim_account['datacenter']['vim_password'] = secret
+ vim_account['datacenter']['vim_tenant_name'] = vim_tenant_name
+ return self._ro_http.post_cmd('openmano/{}/datacenters/{}'.format(tenant['uuid'],datacenter['uuid']),vim_account)
+
+ def _detach(self,vim_name):
+ return self._ro_http.delete_cmd('openmano/{}/datacenters/{}'.format('osm',vim_name))
+
+ def create(self, name, vim_access):
+ vim_account={}
+ vim_account['datacenter']={}
+
+ # currently assumes vim_acc
+ if 'vim-type' not in vim_access or 'openstack' not in vim_access['vim-type']:
+ raise Exception("only vim type openstack support")
+
+ vim_account['datacenter']['name'] = name
+ vim_account['datacenter']['type'] = vim_access['vim-type']
+ vim_account['datacenter']['vim_url'] = vim_access['os-url']
+ vim_account['datacenter']['vim_url_admin'] = vim_access['os-url']
+ vim_account['datacenter']['description'] = vim_access['description']
+
+ vim_config = {}
+ vim_config['use_floating_ip'] = False
+
+ if 'floating_ip_pool' in vim_access and vim_access['floating_ip_pool'] is not None:
+ vim_config['use_floating_ip'] = True
+
+ if 'keypair' in vim_access and vim_access['keypair'] is not None:
+ vim_config['keypair'] = vim_access['keypair']
+
+ vim_account['datacenter']['config'] = vim_config
+
+ resp = self._ro_http.post_cmd('openmano/datacenters',vim_account)
+ if resp and 'error' in resp:
+ raise ClientException("failed to create vim")
+ else:
+ self._attach(name,vim_access['os-username'],vim_access['os-password'],vim_access['os-project-name'])
+
+ def delete(self,vim_name):
+ # first detach
+ resp=self._detach(vim_name)
+ # detach. continue if error, it could be the datacenter is left without attachment
+
+ if 'result' not in self._ro_http.delete_cmd('openmano/datacenters/{}'.format(vim_name)):
+ raise ClientException("failed to delete vim {}".format(vim_name))
+
+ def list(self):
+ resp=self._http.get_cmd('v1/api/operational/datacenters')
+ if not resp or 'rw-launchpad:datacenters' not in resp:
+ return list()
+
+ datacenters=resp['rw-launchpad:datacenters']
+
+ vim_accounts = list()
+ if 'ro-accounts' not in datacenters:
+ return vim_accounts
+
+ tenant=self._get_ro_tenant()
+ if tenant is None:
+ return vim_accounts
+
+ for roaccount in datacenters['ro-accounts']:
+ if 'datacenters' not in roaccount:
+ continue
+ for datacenter in roaccount['datacenters']:
+ vim_accounts.append(self._get_ro_datacenter(datacenter['name'],tenant['uuid']))
+ return vim_accounts
+
+ def _get_ro_tenant(self,name='osm'):
+ resp=self._ro_http.get_cmd('openmano/tenants/{}'.format(name))
+
+ if not resp:
+ return None
+
+ if 'tenant' in resp and 'uuid' in resp['tenant']:
+ return resp['tenant']
+ else:
+ return None
+
+ def _get_ro_datacenter(self,name,tenant_uuid='any'):
+ resp=self._ro_http.get_cmd('openmano/{}/datacenters/{}'.format(tenant_uuid,name))
+ if not resp:
+ raise NotFound("datacenter {} not found".format(name))
+
+ if 'datacenter' in resp and 'uuid' in resp['datacenter']:
+ return resp['datacenter']
+ else:
+ raise NotFound("datacenter {} not found".format(name))
+
+ def get(self,name):
+ tenant=self._get_ro_tenant()
+ if tenant is None:
+ raise NotFound("no ro tenant found")
+
+ return self._get_ro_datacenter(name,tenant['uuid'])
+
+ def get_datacenter(self,name):
+ resp=self._http.get_cmd('v1/api/operational/datacenters')
+ if not resp:
+ return None
+ datacenters=resp['rw-launchpad:datacenters']
+
+ if not resp or 'rw-launchpad:datacenters' not in resp:
+ return None
+ if 'ro-accounts' not in resp['rw-launchpad:datacenters']:
+ return None
+ for roaccount in resp['rw-launchpad:datacenters']['ro-accounts']:
+ if not 'datacenters' in roaccount:
+ continue
+ for datacenter in roaccount['datacenters']:
+ if datacenter['name'] == name:
+ return datacenter
+ return None
+
+ def get_resource_orchestrator(self):
+ resp=self._http.get_cmd('v1/api/operational/resource-orchestrator')
+ if not resp or 'rw-launchpad:resource-orchestrator' not in resp:
+ return None
+ return resp['rw-launchpad:resource-orchestrator']
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM vnf API handling
+"""
+
+from osmclient.common.exceptions import NotFound
+
+
+class Vnf(object):
+ def __init__(self,http=None):
+ self._http=http
+
+ def list(self):
+ resp = self._http.get_cmd('v1/api/operational/vnfr-catalog/vnfr')
+ if resp and 'vnfr:vnfr' in resp:
+ return resp['vnfr:vnfr']
+ return list()
+
+ def get(self,vnf_name):
+ vnfs=self.list()
+ for vnf in vnfs:
+ if vnf_name == vnf['name']:
+ return vnf
+ if vnf_name == vnf['id']:
+ return vnf
+ raise NotFound("vnf {} not found".format(vnf_name))
+
+ def get_monitoring(self,vnf_name):
+ vnf=self.get(vnf_name)
+ if vnf and 'monitoring-param' in vnf:
+ return vnf['monitoring-param']
+ return None
--- /dev/null
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+# 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.
+
+"""
+OSM vnfd API handling
+"""
+
+from osmclient.common.exceptions import NotFound
+from osmclient.common.exceptions import ClientException
+
+
+class Vnfd(object):
+
+ def __init__(self,http=None):
+ self._http=http
+
+ def list(self):
+ resp = self._http.get_cmd('api/running/vnfd-catalog/vnfd')
+ if resp and 'vnfd:vnfd' in resp:
+ return resp['vnfd:vnfd']
+ return list()
+
+ def get(self,name):
+ for vnfd in self.list():
+ if name == vnfd['name']:
+ return vnfd
+ raise NotFound("vnfd {} not found".format(name))
+
+ def delete(self,vnfd_name):
+ vnfd=self.get(vnfd_name)
+ resp=self._http.delete_cmd('api/running/vnfd-catalog/vnfd/{}'.format(vnfd['id']))
+ if 'success' not in resp:
+ raise ClientException("failed to delete vnfd {}".format(vnfd_name))