support of PDUs 55/6855/13
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Tue, 6 Nov 2018 04:56:15 +0000 (05:56 +0100)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Sun, 2 Dec 2018 11:19:28 +0000 (12:19 +0100)
Change-Id: Ifb20578016ef7212399db6b4c12aa5a30376c67e
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
osmclient/scripts/osm.py
osmclient/sol005/client.py
osmclient/sol005/pdud.py [new file with mode: 0644]

index c2fe67f..52e3bc8 100755 (executable)
@@ -532,6 +532,44 @@ def nsi_op_list2(ctx, name):
     nsi_op_list(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
 ####################
 ####################
 # SHOW operations
 ####################
@@ -900,6 +938,38 @@ def nsi_op_show2(ctx, id, filter):
     nsi_op_show(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
 ####################
 ####################
 # 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)
 
 
     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=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>'+
+                   '[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_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
 ####################
 ####################
 # UPDATE operations
 ####################
@@ -1391,6 +1505,23 @@ def nsi_delete2(ctx, name, force):
     nsi_delete(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
 ####################
 ####################
 # VIM operations
 ####################
index 7583165..c70be23 100644 (file)
@@ -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 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
 
 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.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)
         '''
         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 (file)
index 0000000..b59b91d
--- /dev/null
@@ -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)
+