Feature 10476: New client commands and library to manage subscriptions 67/10467/2 release-v10.0-start
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Fri, 26 Feb 2021 12:06:00 +0000 (12:06 +0000)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Fri, 21 May 2021 15:06:17 +0000 (17:06 +0200)
Change-Id: I55aa5e78375829f20fa4aa881058a6c3a0df622d
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
osmclient/scripts/osm.py
osmclient/sol005/client.py
osmclient/sol005/subscription.py [new file with mode: 0644]

index 0ce20c4..feb8c2f 100755 (executable)
@@ -4966,6 +4966,128 @@ def ns_metric_export(ctx, ns, vnf, vdu, metric, interval):
     #     exit(1)
 
 
+#################
+# Subscription operations
+#################
+
+
+@cli_osm.command(
+    name="subscription-create",
+    short_help="creates a new subscription to a specific event",
+)
+@click.option(
+    "--event_type",
+    # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
+    type=click.Choice(["ns"], case_sensitive=False),
+    help="event type to be subscribed (for the moment, only ns is supported)",
+)
+@click.option("--event", default=None, help="specific yaml configuration for the event")
+@click.option(
+    "--event_file", default=None, help="specific yaml configuration file for the event"
+)
+@click.pass_context
+def subscription_create(ctx, event_type, event, event_file):
+    """creates a new subscription to a specific event"""
+    logger.debug("")
+    check_client_version(ctx.obj, ctx.command.name)
+    if event_file:
+        if event:
+            raise ClientException(
+                '"--event" option is incompatible with "--event_file" option'
+            )
+        with open(event_file, "r") as cf:
+            event = cf.read()
+    ctx.obj.subscription.create(event_type, event)
+
+
+@cli_osm.command(name="subscription-delete", short_help="deletes a subscription")
+@click.option(
+    "--event_type",
+    # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
+    type=click.Choice(["ns"], case_sensitive=False),
+    help="event type to be subscribed (for the moment, only ns is supported)",
+)
+@click.argument("subscription_id")
+@click.option(
+    "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
+)
+@click.pass_context
+def subscription_delete(ctx, event_type, subscription_id, force):
+    """deletes a subscription
+
+    SUBSCRIPTION_ID: ID of the subscription to be deleted
+    """
+    logger.debug("")
+    check_client_version(ctx.obj, ctx.command.name)
+    ctx.obj.subscription.delete(event_type, subscription_id, force)
+
+
+@cli_osm.command(name="subscription-list", short_help="list all subscriptions")
+@click.option(
+    "--event_type",
+    # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
+    type=click.Choice(["ns"], case_sensitive=False),
+    help="event type to be subscribed (for the moment, only ns is supported)",
+)
+@click.option(
+    "--filter",
+    default=None,
+    multiple=True,
+    help="restricts the list to the subscriptions matching the filter",
+)
+@click.pass_context
+def subscription_list(ctx, event_type, filter):
+    """list all subscriptions"""
+    logger.debug("")
+    check_client_version(ctx.obj, ctx.command.name)
+    if filter:
+        filter = "&".join(filter)
+    resp = ctx.obj.subscription.list(event_type, filter)
+    table = PrettyTable(["id", "filter", "CallbackUri"])
+    for sub in resp:
+        table.add_row(
+            [
+                sub["_id"],
+                wrap_text(text=json.dumps(sub["filter"], indent=2), width=70),
+                sub["CallbackUri"],
+            ]
+        )
+    table.align = "l"
+    print(table)
+
+
+@cli_osm.command(
+    name="subscription-show", short_help="shows the details of a subscription"
+)
+@click.argument("subscription_id")
+@click.option(
+    "--event_type",
+    # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
+    type=click.Choice(["ns"], case_sensitive=False),
+    help="event type to be subscribed (for the moment, only ns is supported)",
+)
+@click.option(
+    "--filter",
+    multiple=True,
+    help="restricts the information to the fields in the filter",
+)
+@click.pass_context
+def subscription_show(ctx, event_type, subscription_id, filter):
+    """shows the details of a subscription
+
+    SUBSCRIPTION_ID: ID of the subscription
+    """
+    logger.debug("")
+    # try:
+    resp = ctx.obj.subscription.get(subscription_id)
+    table = PrettyTable(["key", "attribute"])
+    for k, v in list(resp.items()):
+        if not filter or k in filter:
+            table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
+    table.align = "l"
+    print(table)
+
+
 ####################
 # Other operations
 ####################
index 57bc2b1..c7f043b 100644 (file)
@@ -38,6 +38,7 @@ from osmclient.sol005 import k8scluster
 from osmclient.sol005 import vca
 from osmclient.sol005 import repo
 from osmclient.sol005 import osmrepo
+from osmclient.sol005 import subscription
 from osmclient.common import package_tool
 import json
 import logging
@@ -100,6 +101,7 @@ class Client(object):
         self.repo = repo.Repo(self._http_client, client=self)
         self.osmrepo = osmrepo.OSMRepo(self._http_client, client=self)
         self.package_tool = package_tool.PackageTool(client=self)
+        self.subscription = subscription.Subscription(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/subscription.py b/osmclient/sol005/subscription.py
new file mode 100644 (file)
index 0000000..d4860ac
--- /dev/null
@@ -0,0 +1,138 @@
+#
+#    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 Subscription API handling
+"""
+
+from osmclient.common.exceptions import NotFound
+from osmclient.common.exceptions import ClientException
+import yaml
+import json
+import logging
+
+
+class Subscription(object):
+    def __init__(self, http=None, client=None):
+        self._http = http
+        self._client = client
+        self._logger = logging.getLogger("osmclient")
+        self._apiName = "/nslcm"
+        self._apiVersion = "/v1"
+        self._apiResource = "/subscriptions"
+        self._apiBase = "{}{}{}".format(
+            self._apiName, self._apiVersion, self._apiResource
+        )
+
+    def _rebuild_apibase(self, event_type):
+        self._logger.debug("")
+        if event_type == "ns":
+            self._apiName = "/nslcm"
+        else:
+            raise ClientException("unsupported event_type {}".format(event_type))
+        self._apiBase = "{}{}{}".format(
+            self._apiName, self._apiVersion, self._apiResource
+        )
+
+    def create(self, event_type, event):
+        """
+        Creates a subscription
+        :param event_type: event type to be subscribed (only ns is supported)
+        :param event: yaml string defining the event to be subscribed
+        :return: None. Exception if fail
+        """
+        self._logger.debug("")
+        self._client.get_token()
+        self._rebuild_apibase(event_type)
+
+        subscription_event = yaml.safe_load(event)
+
+        http_code, resp = self._http.post_cmd(
+            endpoint=self._apiBase, postfields_dict=subscription_event
+        )
+        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"])
+
+    def delete(self, event_type, subscription_id, force=False):
+        """
+        Deletes a subscription
+        :param event_type: event type to be subscribed (only ns is supported)
+        :param subscription_id: identifier of the subscription
+        :param force: forces deletion
+        :return: None. Exception if fail
+        """
+        self._logger.debug("")
+        self._client.get_token()
+        self._rebuild_apibase(event_type)
+        querystring = ""
+        if force:
+            querystring = "?FORCE=True"
+        http_code, resp = self._http.delete_cmd(
+            "{}/{}{}".format(self._apiBase, subscription_id, querystring)
+        )
+        if http_code == 202:
+            print("Deletion in progress")
+        elif http_code == 204:
+            print("Deleted")
+        else:
+            msg = resp or ""
+            raise ClientException(
+                "failed to delete subscription {} - {}".format(subscription_id, msg)
+            )
+
+    def list(self, event_type, filter=None):
+        """
+        Returns a list of subscriptions
+        :param event_type: event type to be subscribed (only ns is supported)
+        :param filter
+        :return: list of subscriptions
+        """
+        self._logger.debug("")
+        self._client.get_token()
+        self._rebuild_apibase(event_type)
+        filter_string = ""
+        if filter:
+            filter_string = "?{}".format(filter)
+        _, resp = self._http.get2_cmd("{}{}".format(self._apiBase, filter_string))
+        if resp:
+            return json.loads(resp)
+        return list()
+
+    def get(self, event_type, subscription_id):
+        """
+        Returns a subscription from a subscription id
+        :param event_type: event type to be subscribed (only ns is supported)
+        :param subscription_id: identifier of the subscription
+        :return: dict with the subscription
+        """
+        self._logger.debug("")
+        self._client.get_token()
+        self._rebuild_apibase(event_type)
+        try:
+            _, resp = self._http.get2_cmd(
+                "{}/{}".format(self._apiBase, subscription_id)
+            )
+            self._logger.debug(yaml.safe_dump(resp))
+            if resp:
+                return json.loads(resp)
+            if not resp or "id" not in resp:
+                raise ClientException(
+                    "failed to get subscription info: {}".format(resp)
+                )
+            return resp
+        except NotFound:
+            raise NotFound("subscription '{}' not found".format(subscription_id))