From 2cc451122a28672aa0b928688fc76d633d5ece81 Mon Sep 17 00:00:00 2001 From: garciadeblas Date: Tue, 6 Nov 2018 05:56:15 +0100 Subject: [PATCH] support of PDUs Change-Id: Ifb20578016ef7212399db6b4c12aa5a30376c67e Signed-off-by: garciadeblas --- osmclient/scripts/osm.py | 131 +++++++++++++++++++++++++++++++++++++ osmclient/sol005/client.py | 2 + osmclient/sol005/pdud.py | 127 +++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 osmclient/sol005/pdud.py diff --git a/osmclient/scripts/osm.py b/osmclient/scripts/osm.py index c2fe67f..52e3bc8 100755 --- a/osmclient/scripts/osm.py +++ b/osmclient/scripts/osm.py @@ -532,6 +532,44 @@ def nsi_op_list2(ctx, name): nsi_op_list(ctx,name) +@cli.command(name='pdu-list') +@click.option('--filter', default=None, + help='restricts the list to the Physical Deployment Units matching the filter') +@click.pass_context +def pdu_list(ctx, filter): + '''list all Physical Deployment Units (PDU)''' + try: + check_client_version(ctx.obj, ctx.command.name) + resp = ctx.obj.pdu.list(filter) + except ClientException as inst: + print((inst.message)) + exit(1) + table = PrettyTable( + ['pdu name', + 'id', + 'type', + 'shared', + 'mgmt ip address']) + for pdu in resp: + pdu_name = pdu['name'] + pdu_id = pdu['_id'] + pdu_type = pdu['type'] + pdu_shared = pdu['shared'] + pdu_ipaddress = "None" + for iface in pdu['interfaces']: + if iface['mgmt']: + pdu_ipaddress = iface['ip-address'] + break + table.add_row( + [pdu_name, + pdu_id, + pdu_type, + pdu_shared, + pdu_ipaddress]) + table.align = 'l' + print(table) + + #################### # SHOW operations #################### @@ -900,6 +938,38 @@ def nsi_op_show2(ctx, id, filter): nsi_op_show(ctx, id, filter) +@cli.command(name='pdu-show', short_help='shows the content of a Physical Deployment Unit (PDU)') +@click.argument('name') +@click.option('--literal', is_flag=True, + help='print literally, no pretty table') +@click.option('--filter', default=None) +@click.pass_context +def pdu_show(ctx, name, literal, filter): + '''shows the content of a Physical Deployment Unit (PDU) + + NAME: name or ID of the PDU + ''' + try: + check_client_version(ctx.obj, ctx.command.name) + pdu = ctx.obj.pdu.get(name) + except ClientException as inst: + print((inst.message)) + exit(1) + + if literal: + print(yaml.safe_dump(pdu)) + return + + table = PrettyTable(['field', 'value']) + + for k, v in list(pdu.items()): + if filter is None or filter in k: + table.add_row([k, json.dumps(v, indent=2)]) + + table.align = 'l' + print(table) + + #################### # CREATE operations #################### @@ -1120,6 +1190,50 @@ def nsi_create2(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_f nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file) +@cli.command(name='pdu-create', short_help='adds a new Physical Deployment Unit to the catalog') +@click.option('--name', help='name of the Physical Deployment Unit') +@click.option('--pdu_type', help='type of PDU (e.g. router, firewall, FW001)') +@click.option('--interface', + help='interface(s) of the PDU: name=,mgmt=,ip-address='+ + '[,type=][,mac-address=][,vim-network-name=]', + multiple=True) +@click.option('--description', help='human readable description') +@click.option('--shared', is_flag=True, help='flag to indicate if the PDU is shared') +@click.option('--vimAccounts', help='list of VIM accounts where this PDU is physically connected') +@click.option('--descriptor_file', default=None, help='PDU descriptor file (as an alternative to using the other arguments') +@click.pass_context +#TODO +def pdu_create(ctx, name, pdu_type, interface, description, shared, vimAccounts, descriptor_file): + '''creates a new Physical Deployment Unit (PDU)''' + try: + check_client_version(ctx.obj, ctx.command.name) + pdu = {} + if not descriptor_file: + if not name: + raise ClientException('in absence of descriptor file, option "--name" is mandatory') + if not pdu_type: + raise ClientException('in absence of descriptor file, option "--pdu_type" is mandatory') + if not interface: + raise ClientException('in absence of descriptor file, option "--interface" is mandatory (at least once)') + else: + with open(descriptor_file, 'r') as df: + pdu = yaml.load(df.read()) + if name: pdu["name"] = name + if pdu_type: pdu["type"] = pdu_type + if description: pdu["description"] = description + if shared: pdu["shared"] = shared + if vimAccounts: pdu["vim_accounts"] = yaml.load(vimAccounts) + if interface: + ifaces_list = [] + for iface in interface: + ifaces_list.append({k:v for k,v in [i.split('=') for i in iface.split(',')]}) + pdu["interfaces"] = ifaces_list + ctx.obj.pdu.create(pdu) + except ClientException as inst: + print((inst.message)) + exit(1) + + #################### # UPDATE operations #################### @@ -1391,6 +1505,23 @@ def nsi_delete2(ctx, name, force): nsi_delete(ctx, name, force) +@cli.command(name='pdu-delete', short_help='deletes a Physical Deployment Unit (PDU)') +@click.argument('name') +@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions') +@click.pass_context +def pdu_delete(ctx, name, force): + '''deletes a Physical Deployment Unit (PDU) + + NAME: name or ID of the PDU to be deleted + ''' + try: + check_client_version(ctx.obj, ctx.command.name) + ctx.obj.pdu.delete(name, force) + except ClientException as inst: + print((inst.message)) + exit(1) + + #################### # VIM operations #################### diff --git a/osmclient/sol005/client.py b/osmclient/sol005/client.py index 7583165..c70be23 100644 --- a/osmclient/sol005/client.py +++ b/osmclient/sol005/client.py @@ -31,6 +31,7 @@ from osmclient.sol005 import http from osmclient.sol005 import sdncontroller from osmclient.sol005 import project as projectmodule from osmclient.sol005 import user as usermodule +from osmclient.sol005 import pdud from osmclient.common.exceptions import ClientException import json @@ -86,6 +87,7 @@ class Client(object): self.vnf = vnf.Vnf(self._http_client, client=self) self.project = projectmodule.Project(self._http_client, client=self) self.user = usermodule.User(self._http_client, client=self) + self.pdu = pdud.Pdu(self._http_client, client=self) ''' self.vca = vca.Vca(http_client, client=self, **kwargs) self.utils = utils.Utils(http_client, **kwargs) diff --git a/osmclient/sol005/pdud.py b/osmclient/sol005/pdud.py new file mode 100644 index 0000000..b59b91d --- /dev/null +++ b/osmclient/sol005/pdud.py @@ -0,0 +1,127 @@ +# Copyright 2018 Telefonica +# +# 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 pdud API handling +""" + +from osmclient.common.exceptions import NotFound +from osmclient.common.exceptions import ClientException +from osmclient.common import utils +import json + + +class Pdu(object): + + def __init__(self, http=None, client=None): + self._http = http + self._client = client + self._apiName = '/pdu' + self._apiVersion = '/v1' + self._apiResource = '/pdu_descriptors' + self._apiBase = '{}{}{}'.format(self._apiName, + self._apiVersion, self._apiResource) + + def list(self, filter=None): + filter_string = '' + if filter: + filter_string = '?{}'.format(filter) + resp = self._http.get_cmd('{}{}'.format(self._apiBase,filter_string)) + if resp: + return resp + return list() + + def get(self, name): + if utils.validate_uuid4(name): + for pdud in self.list(): + if name == pdud['_id']: + return pdud + else: + for pdud in self.list(): + if 'name' in pdud and name == pdud['name']: + return pdud + raise NotFound("pdud {} not found".format(name)) + + def get_individual(self, name): + pdud = self.get(name) + # It is redundant, since the previous one already gets the whole pdudInfo + # The only difference is that a different primitive is exercised + resp = self._http.get_cmd('{}/{}'.format(self._apiBase, pdud['_id'])) + #print yaml.safe_dump(resp) + if resp: + return resp + raise NotFound("pdu {} not found".format(name)) + + def delete(self, name, force=False): + pdud = self.get(name) + querystring = '' + if force: + querystring = '?FORCE=True' + http_code, resp = self._http.delete_cmd('{}/{}{}'.format(self._apiBase, + pdud['_id'], querystring)) + #print 'HTTP CODE: {}'.format(http_code) + #print 'RESP: {}'.format(resp) + if http_code == 202: + print('Deletion in progress') + elif http_code == 204: + print('Deleted') + else: + msg = "" + if resp: + try: + msg = json.loads(resp) + except ValueError: + msg = resp + raise ClientException("failed to delete pdu {} - {}".format(name, msg)) + + def create(self, pdu, update_endpoint=None): + headers= self._client._headers + headers['Content-Type'] = 'text/plain' + http_header = ['{}: {}'.format(key,val) + for (key,val) in list(headers.items())] + self._http.set_http_header(http_header) + if update_endpoint: + http_code, resp = self._http.put_cmd(endpoint=update_endpoint, postfields_dict=pdu) + else: + self._apiResource = '/pdu_descriptors_content' + self._apiBase = '{}{}{}'.format(self._apiName, + self._apiVersion, self._apiResource) + endpoint = self._apiBase + #endpoint = '{}{}'.format(self._apiBase,ow_string) + http_code, resp = self._http.post_cmd(endpoint=endpoint, postfields_dict=pdu) + #print 'HTTP CODE: {}'.format(http_code) + #print 'RESP: {}'.format(resp) + if http_code in (200, 201, 202, 204): + if resp: + resp = json.loads(resp) + if not resp or 'id' not in resp: + raise ClientException('unexpected response from server: '.format( + resp)) + print(resp['id']) + else: + msg = "Error {}".format(http_code) + if resp: + try: + msg = "{} - {}".format(msg, json.loads(resp)) + except ValueError: + msg = "{} - {}".format(msg, resp) + raise ClientException("failed to create/update pdu - {}".format(msg)) + + def update(self, name, filename): + pdud = self.get(name) + endpoint = '{}/{}'.format(self._apiBase, pdud['_id']) + self.create(filename=filename, update_endpoint=endpoint) + -- 2.25.1