SDN Accounts refactoring
authorChamarty <ravi.chamarty@riftio.com>
Mon, 3 Apr 2017 21:26:43 +0000 (17:26 -0400)
committerChamarty <ravi.chamarty@riftio.com>
Mon, 3 Apr 2017 21:27:23 +0000 (17:27 -0400)
Change-Id: I1e9d8f744dab71a8b4967158f7c086e9731938ac
Signed-off-by: Chamarty <ravi.chamarty@riftio.com>
31 files changed:
BUILD.sh
common/plugins/yang/CMakeLists.txt
common/plugins/yang/rw-sdn.yang
common/python/CMakeLists.txt
common/python/rift/mano/sdn/__init__.py [new file with mode: 0644]
common/python/rift/mano/sdn/accounts.py [new file with mode: 0644]
common/python/rift/mano/sdn/config.py [new file with mode: 0644]
common/python/rift/mano/sdn/operdata.py [new file with mode: 0644]
rwcal/plugins/yang/rwcal.yang
rwlaunchpad/plugins/cli/cli_launchpad_schema_listing.txt
rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py
rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwvnffgmgr.py
rwlaunchpad/plugins/rwvns/rift/tasklets/rwvnstasklet/rwvnstasklet.py
rwlaunchpad/plugins/rwvns/rift/topmgr/__init__.py
rwlaunchpad/plugins/rwvns/rift/topmgr/rwtopmgr.py
rwlaunchpad/plugins/rwvns/test/test_sdn_mock.py
rwlaunchpad/plugins/rwvns/test/test_sdn_odl.py [new file with mode: 0644]
rwlaunchpad/plugins/rwvns/test/test_sdn_openstack.py [new file with mode: 0644]
rwlaunchpad/plugins/rwvns/test/test_sdn_sim.py
rwlaunchpad/plugins/rwvns/test/topmgr_module_test.py
rwlaunchpad/plugins/rwvns/vala/CMakeLists.txt
rwlaunchpad/plugins/rwvns/vala/rwsdn.vala
rwlaunchpad/plugins/rwvns/vala/rwsdn_mock/rwsdn_mock.py
rwlaunchpad/plugins/rwvns/vala/rwsdn_odl/rwsdn_odl.py
rwlaunchpad/plugins/rwvns/vala/rwsdn_openstack/rwsdn_openstack.py
rwlaunchpad/plugins/rwvns/vala/rwsdn_sim/rwsdn_sim.py
rwlaunchpad/plugins/rwvns/yang/CMakeLists.txt
rwlaunchpad/plugins/rwvns/yang/rwsdn.yang [deleted file]
rwlaunchpad/plugins/rwvns/yang/rwsdnal.yang [new file with mode: 0644]
rwlaunchpad/plugins/yang/rw-vns.yang
rwlaunchpad/ra/pytest/test_launchpad.py

index 0e7804c..40c5990 100755 (executable)
--- a/BUILD.sh
+++ b/BUILD.sh
@@ -210,6 +210,8 @@ if [[ $PLATFORM == ub16 ]]; then
             rw.core.mano-mano_yang_ylib-1.0 \
             rw.core.mano-common-1.0 \
             rw.core.mano-rwsdn_yang_ylib-1.0 \
+            rw.core.mano-rwsdnal_yang_ylib-1.0 \
+            rw.core.mano-rwsdn-1.0 \
             rw.core.mano-mano-types_yang_ylib-1.0 \
             rw.core.mano-rwcal-cloudsim-1.0 \
             rw.core.mano-rwcal-1.0 \
index be583ed..ed7d7b3 100644 (file)
 ##
 # Yang targets
 ##
+rift_add_yang_target(
+  TARGET rwsdn_yang
+  YANG_FILES rw-sdn.yang
+  COMPONENT ${PKG_LONG_NAME}
+  LIBRARIES
+    rwsdnal_yang_gen
+  DEPENDS
+    rwsdnal_yang
+)
+
 rift_add_yang_target(
   TARGET rwcloud_yang
-  YANG_FILES rw-cloud.yang rw-sdn.yang
+  YANG_FILES rw-cloud.yang 
   COMPONENT ${PKG_LONG_NAME}
   LIBRARIES
     rwsdn_yang_gen
     rwcal_yang_gen
   DEPENDS
     rwcal_yang
+    rwsdnal_yang
 )
 
 rift_add_yang_target(
index 6475cc5..0441452 100644 (file)
@@ -28,8 +28,8 @@ module rw-sdn
     prefix "rwpb";
   }
 
-  import rwsdn {
-    prefix "rwsdn";
+  import rwsdnal {
+    prefix "rwsdnal";
   }
 
   revision 2015-09-14 {
@@ -38,15 +38,16 @@ module rw-sdn
   }
 
   container sdn {
+    rwpb:msg-new SDNAccountConfig;
     list account {
-      rwpb:msg-new SDNAccountConfig;
+      rwpb:msg-new SDNAccount;
       key "name";
       leaf name {
        type string;
       }
 
-      uses rwsdn:sdn-provider-auth;
-      uses rwsdn:connection-status;
+      uses rwsdnal:sdn-provider-auth;
+      uses rwsdnal:connection-status;
     }
   }
 
index 50ed1de..8fba078 100644 (file)
@@ -36,6 +36,16 @@ rift_python_install_tree(
   PYTHON3_ONLY
   )
 
+rift_python_install_tree(
+  FILES
+    rift/mano/sdn/__init__.py
+    rift/mano/sdn/accounts.py
+    rift/mano/sdn/config.py
+    rift/mano/sdn/operdata.py
+  COMPONENT ${PKG_LONG_NAME}
+  PYTHON3_ONLY
+  )
+
 rift_python_install_tree(
   FILES
     rift/mano/config_agent/operdata.py
diff --git a/common/python/rift/mano/sdn/__init__.py b/common/python/rift/mano/sdn/__init__.py
new file mode 100644 (file)
index 0000000..8f85832
--- /dev/null
@@ -0,0 +1,30 @@
+
+# 
+#   Copyright 2017 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.
+#
+
+from .accounts import (
+    SDNAccount,
+    SDNAccountCalError,
+    )
+
+from .config import (
+    SDNAccountConfigSubscriber,
+    SDNAccountConfigCallbacks
+    )
+
+from .operdata import (
+     SDNAccountDtsOperdataHandler,
+)
diff --git a/common/python/rift/mano/sdn/accounts.py b/common/python/rift/mano/sdn/accounts.py
new file mode 100644 (file)
index 0000000..d539ead
--- /dev/null
@@ -0,0 +1,157 @@
+
+# 
+#   Copyright 2017 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 sys
+import asyncio
+from gi import require_version
+require_version('RwTypes', '1.0')
+require_version('RwsdnalYang', '1.0')
+require_version('RwSdnYang', '1.0')
+
+from gi.repository import (
+        RwTypes,
+        RwsdnalYang,
+        RwSdnYang,
+        )
+import rw_peas
+
+if sys.version_info < (3, 4, 4):
+    asyncio.ensure_future = asyncio.async
+
+
+class PluginLoadingError(Exception):
+    pass
+
+
+class SDNAccountCalError(Exception):
+    pass
+
+
+class SDNAccount(object):
+    def __init__(self, log, rwlog_hdl, account_msg):
+        self._log = log
+        self._account_msg = account_msg.deep_copy()
+
+        self._sdn_plugin = None
+        self._engine = None
+
+        self._sdn = self.plugin.get_interface("Topology")
+        self._sdn.init(rwlog_hdl)
+
+        self._status = RwsdnalYang.SDNAccount_ConnectionStatus(
+                status="unknown",
+                details="Connection status lookup not started"
+                )
+
+        self._validate_task = None
+
+    @property
+    def plugin(self):
+        if self._sdn_plugin is None:
+            try:
+                self._sdn_plugin = rw_peas.PeasPlugin(
+                        getattr(self._account_msg, self.account_type).plugin_name,
+                        'RwSdn-1.0',
+                        )
+
+            except AttributeError as e:
+                raise PluginLoadingError(str(e))
+
+            self._engine, _, _ = self._sdn_plugin()
+
+        return self._sdn_plugin
+
+    def _wrap_status_fn(self, fn, *args, **kwargs):
+        ret = fn(*args, **kwargs)
+        rw_status = ret[0]
+        if rw_status != RwTypes.RwStatus.SUCCESS:
+            msg = "%s returned %s" % (fn.__name__, str(rw_status))
+            self._log.error(msg)
+            raise SDNAccountCalError(msg)
+
+        # If there was only one other return value besides rw_status, then just
+        # return that element.  Otherwise return the rest of the return values
+        # as a list.
+        return ret[1] if len(ret) == 2 else ret[1:]
+
+    @property
+    def sdn(self):
+        return self._sdn
+
+    @property
+    def name(self):
+        return self._account_msg.name
+
+    @property
+    def account_msg(self):
+        return self._account_msg
+
+    @property
+    def sdnal_account_msg(self):
+        return RwsdnalYang.SDNAccount.from_dict(
+                self.account_msg.as_dict(),
+                ignore_missing_keys=True,
+                )
+
+    def sdn_account_msg(self, account_dict):
+        self._account_msg = RwSdnYang.SDNAccount.from_dict(account_dict)
+
+    @property
+    def account_type(self):
+        return self._account_msg.account_type
+
+    @property
+    def connection_status(self):
+        return self._status
+
+    def update_from_cfg(self, cfg):
+        self._log.debug("Updating parent SDN Account to %s", cfg)
+
+        raise NotImplementedError("Update SDN account not yet supported")
+
+
+    @asyncio.coroutine
+    def validate_sdn_account_credentials(self, loop):
+        self._log.debug("Validating SDN Account credentials %s", self._account_msg)
+        self._status = RwSdnYang.SDNAccount_ConnectionStatus(
+                status="validating",
+                details="SDN account connection validation in progress"
+                )
+        rwstatus, status = yield from loop.run_in_executor(
+                None,
+                self._sdn.validate_sdn_creds,
+                self.sdnal_account_msg,
+                )
+        if rwstatus == RwTypes.RwStatus.SUCCESS:
+            self._status = RwSdnYang.SDNAccount_ConnectionStatus.from_dict(status.as_dict())
+        else:
+            self._status = RwSdnYang.SDNAccount_ConnectionStatus(
+                    status="failure",
+                    details="Error when calling SDNAL validate SDN creds"
+                    )
+
+        self._log.info("Got SDN account validation response: %s", self._status)
+
+    def start_validate_credentials(self, loop):
+        if self._validate_task is not None:
+            self._validate_task.cancel()
+            self._validate_task = None
+
+        self._validate_task = asyncio.ensure_future(
+                self.validate_sdn_account_credentials(loop),
+                loop=loop
+                )
diff --git a/common/python/rift/mano/sdn/config.py b/common/python/rift/mano/sdn/config.py
new file mode 100644 (file)
index 0000000..a9de01b
--- /dev/null
@@ -0,0 +1,240 @@
+
+#
+#   Copyright 2017 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 asyncio
+
+import gi
+gi.require_version('RwDts', '1.0')
+import rift.tasklets
+
+from gi.repository import (
+    RwDts as rwdts,
+    ProtobufC,
+    )
+
+from . import accounts
+
+
+class SDNAccountNotFound(Exception):
+    pass
+
+
+class SDNAccountError(Exception):
+    pass
+
+
+def get_add_delete_update_cfgs(dts_member_reg, xact, key_name):
+    # Unforunately, it is currently difficult to figure out what has exactly
+    # changed in this xact without Pbdelta support (RIFT-4916)
+    # As a workaround, we can fetch the pre and post xact elements and
+    # perform a comparison to figure out adds/deletes/updates
+    xact_cfgs = list(dts_member_reg.get_xact_elements(xact))
+    curr_cfgs = list(dts_member_reg.elements)
+
+    xact_key_map = {getattr(cfg, key_name): cfg for cfg in xact_cfgs}
+    curr_key_map = {getattr(cfg, key_name): cfg for cfg in curr_cfgs}
+
+    # Find Adds
+    added_keys = set(xact_key_map) - set(curr_key_map)
+    added_cfgs = [xact_key_map[key] for key in added_keys]
+
+    # Find Deletes
+    deleted_keys = set(curr_key_map) - set(xact_key_map)
+    deleted_cfgs = [curr_key_map[key] for key in deleted_keys]
+
+    # Find Updates
+    updated_keys = set(curr_key_map) & set(xact_key_map)
+    updated_cfgs = [xact_key_map[key] for key in updated_keys if xact_key_map[key] != curr_key_map[key]]
+
+    return added_cfgs, deleted_cfgs, updated_cfgs
+
+
+class SDNAccountConfigCallbacks(object):
+    def __init__(self,
+                 on_add_apply=None, on_add_prepare=None,
+                 on_delete_apply=None, on_delete_prepare=None):
+
+        @asyncio.coroutine
+        def prepare_noop(*args, **kwargs):
+            pass
+
+        def apply_noop(*args, **kwargs):
+            pass
+
+        self.on_add_apply = on_add_apply
+        self.on_add_prepare = on_add_prepare
+        self.on_delete_apply = on_delete_apply
+        self.on_delete_prepare = on_delete_prepare
+
+        for f in ('on_add_apply', 'on_delete_apply'):
+            ref = getattr(self, f)
+            if ref is None:
+                setattr(self, f, apply_noop)
+                continue
+
+            if asyncio.iscoroutinefunction(ref):
+                raise ValueError('%s cannot be a coroutine' % (f,))
+
+        for f in ('on_add_prepare', 'on_delete_prepare'):
+            ref = getattr(self, f)
+            if ref is None:
+                setattr(self, f, prepare_noop)
+                continue
+
+            if not asyncio.iscoroutinefunction(ref):
+                raise ValueError("%s must be a coroutine" % f)
+
+
+class SDNAccountConfigSubscriber(object):
+    XPATH = "C,/rw-sdn:sdn/rw-sdn:account"
+
+    def __init__(self, dts, log, rwlog_hdl, sdn_callbacks, acctstore):
+        self._dts = dts
+        self._log = log
+        self._rwlog_hdl = rwlog_hdl
+        self._reg = None
+
+        self.accounts = acctstore
+
+        self._sdn_callbacks = sdn_callbacks
+
+    def add_account(self, account_msg):
+        self._log.info("adding sdn account: {}".format(account_msg))
+
+        account = accounts.SDNAccount(self._log, self._rwlog_hdl, account_msg)
+        self.accounts[account.name] = account
+
+        self._sdn_callbacks.on_add_apply(account)
+
+    def delete_account(self, account_name):
+        self._log.info("deleting sdn account: {}".format(account_name))
+        del self.accounts[account_name]
+
+        self._sdn_callbacks.on_delete_apply(account_name)
+
+    def update_account(self, account_msg):
+        """ Update an existing sdn account
+
+        In order to simplify update, turn an update into a delete followed by
+        an add.  The drawback to this approach is that we will not support
+        updates of an "in-use" sdn account, but this seems like a
+        reasonable trade-off.
+
+
+        Arguments:
+            account_msg - The sdn account config message
+        """
+        self._log.info("updating sdn account: {}".format(account_msg))
+
+        self.delete_account(account_msg.name)
+        self.add_account(account_msg)
+
+    def register(self):
+        @asyncio.coroutine
+        def apply_config(dts, acg, xact, action, _):
+            self._log.debug("Got sdn account apply config (xact: %s) (action: %s)", xact, action)
+
+            if xact.xact is None:
+                if action == rwdts.AppconfAction.INSTALL:
+                    curr_cfg = self._reg.elements
+                    for cfg in curr_cfg:
+                        self._log.debug("SDN account being re-added after restart.")
+                        if not cfg.has_field('account_type'):
+                            raise SDNAccountError("New SDN account must contain account_type field.")
+                        self.add_account(cfg)
+                else:
+                    # When RIFT first comes up, an INSTALL is called with the current config
+                    # Since confd doesn't actally persist data this never has any data so
+                    # skip this for now.
+                    self._log.debug("No xact handle.  Skipping apply config")
+
+                return
+
+            add_cfgs, delete_cfgs, update_cfgs = get_add_delete_update_cfgs(
+                    dts_member_reg=self._reg,
+                    xact=xact,
+                    key_name="name",
+                    )
+
+            # Handle Deletes
+            for cfg in delete_cfgs:
+                self.delete_account(cfg.name)
+
+            # Handle Adds
+            for cfg in add_cfgs:
+                self.add_account(cfg)
+
+            # Handle Updates
+            for cfg in update_cfgs:
+                self.update_account(cfg)
+
+        @asyncio.coroutine
+        def on_prepare(dts, acg, xact, xact_info, ks_path, msg, scratch):
+            """ Prepare callback from DTS for SDN Account """
+
+            action = xact_info.query_action
+            self._log.debug("SDN account on_prepare config received (action: %s): %s",
+                            xact_info.query_action, msg)
+
+            if action in [rwdts.QueryAction.CREATE, rwdts.QueryAction.UPDATE]:
+                if msg.name in self.accounts:
+                    self._log.debug("SDN account already exists. Invoking update request")
+
+                    # Since updates are handled by a delete followed by an add, invoke the
+                    # delete prepare callbacks to give clients an opportunity to reject.
+                    yield from self._sdn_callbacks.on_delete_prepare(msg.name)
+
+                else:
+                    self._log.debug("SDN account does not already exist. Invoking on_prepare add request")
+                    if not msg.has_field('account_type'):
+                        raise SDNAccountError("New sdn account must contain account_type field.")
+
+                    account = accounts.SDNAccount(self._log, self._rwlog_hdl, msg)
+                    yield from self._sdn_callbacks.on_add_prepare(account)
+
+            elif action == rwdts.QueryAction.DELETE:
+                # Check if the entire SDN account got deleted
+                fref = ProtobufC.FieldReference.alloc()
+                fref.goto_whole_message(msg.to_pbcm())
+                if fref.is_field_deleted():
+                    yield from self._sdn_callbacks.on_delete_prepare(msg.name)
+
+                else:
+                    self._log.error("Deleting individual fields for SDN account not supported")
+                    xact_info.respond_xpath(rwdts.XactRspCode.NACK)
+                    return
+
+            else:
+                self._log.error("Action (%s) NOT SUPPORTED", action)
+                xact_info.respond_xpath(rwdts.XactRspCode.NACK)
+
+            xact_info.respond_xpath(rwdts.XactRspCode.ACK)
+
+        self._log.debug("Registering for SDN Account config using xpath: %s",
+                        SDNAccountConfigSubscriber.XPATH,
+                        )
+
+        acg_handler = rift.tasklets.AppConfGroup.Handler(
+                        on_apply=apply_config,
+                        )
+
+        with self._dts.appconf_group_create(acg_handler) as acg:
+            self._reg = acg.register(
+                    xpath=SDNAccountConfigSubscriber.XPATH,
+                    flags=rwdts.Flag.SUBSCRIBER | rwdts.Flag.DELTA_READY | rwdts.Flag.CACHE,
+                    on_prepare=on_prepare,
+                    )
diff --git a/common/python/rift/mano/sdn/operdata.py b/common/python/rift/mano/sdn/operdata.py
new file mode 100644 (file)
index 0000000..b29f100
--- /dev/null
@@ -0,0 +1,128 @@
+
+#
+#   Copyright 2017 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 asyncio
+import rift.tasklets
+
+from gi.repository import(
+        RwSdnYang,
+        RwDts as rwdts,
+        )
+
+
+class SDNAccountNotFound(Exception):
+    pass
+
+
+class SDNAccountDtsOperdataHandler(object):
+    def __init__(self, dts, log, loop):
+        self._dts = dts
+        self._log = log
+        self._loop = loop
+
+        self.sdn_accounts = {}
+
+    def add_sdn_account(self, account):
+        self.sdn_accounts[account.name] = account
+        account.start_validate_credentials(self._loop)
+
+    def delete_sdn_account(self, account_name):
+        del self.sdn_accounts[account_name]
+
+    def get_saved_sdn_accounts(self, sdn_account_name):
+        ''' Get SDN Account corresponding to passed name, or all saved accounts if name is None'''
+        saved_sdn_accounts = []
+
+        if sdn_account_name is None or sdn_account_name == "":
+            sdn_accounts = list(self.sdn_accounts.values())
+            saved_sdn_accounts.extend(sdn_accounts)
+        elif sdn_account_name in self.sdn_accounts:
+            account = self.sdn_accounts[sdn_account_name]
+            saved_sdn_accounts.append(account)
+        else:
+            errstr = "SDN account {} does not exist".format(sdn_account_name)
+            raise KeyError(errstr)
+
+        return saved_sdn_accounts
+
+    def _register_show_status(self):
+        def get_xpath(sdn_name=None):
+            return "D,/rw-sdn:sdn/account{}/connection-status".format(
+                    "[name='%s']" % sdn_name if sdn_name is not None else ''
+                    )
+
+        @asyncio.coroutine
+        def on_prepare(xact_info, action, ks_path, msg):
+            self._log.debug("Got show SDN connection status request: %s", ks_path.create_string())
+            path_entry = RwSdnYang.SDNAccount.schema().keyspec_to_entry(ks_path)
+            sdn_account_name = path_entry.key00.name
+
+            try:
+                saved_accounts = self.get_saved_sdn_accounts(sdn_account_name)
+                for account in saved_accounts:
+                    connection_status = account.connection_status
+                    self._log.debug("Responding to SDN connection status request: %s", connection_status)
+                    xact_info.respond_xpath(
+                            rwdts.XactRspCode.MORE,
+                            xpath=get_xpath(account.name),
+                            msg=account.connection_status,
+                            )
+            except KeyError as e:
+                self._log.warning(str(e))
+                xact_info.respond_xpath(rwdts.XactRspCode.NA)
+                return
+
+            xact_info.respond_xpath(rwdts.XactRspCode.ACK)
+
+        yield from self._dts.register(
+                xpath=get_xpath(),
+                handler=rift.tasklets.DTS.RegistrationHandler(
+                    on_prepare=on_prepare),
+                flags=rwdts.Flag.PUBLISHER,
+                )
+
+    def _register_validate_rpc(self):
+        def get_xpath():
+            return "/rw-sdn:update-sdn-status"
+
+        @asyncio.coroutine
+        def on_prepare(xact_info, action, ks_path, msg):
+            if not msg.has_field("sdn_account"):
+                raise SDNAccountNotFound("SDN account name not provided")
+
+            sdn_account_name = msg.sdn_account
+            try:
+                account = self.sdn_accounts[sdn_account_name]
+            except KeyError:
+                raise SDNAccountNotFound("SDN account name %s not found" % sdn_account_name)
+
+            account.start_validate_credentials(self._loop)
+
+            xact_info.respond_xpath(rwdts.XactRspCode.ACK)
+
+        yield from self._dts.register(
+                xpath=get_xpath(),
+                handler=rift.tasklets.DTS.RegistrationHandler(
+                    on_prepare=on_prepare
+                    ),
+                flags=rwdts.Flag.PUBLISHER,
+                )
+
+    @asyncio.coroutine
+    def register(self):
+        yield from self._register_show_status()
+        yield from self._register_validate_rpc()
index 9daefb1..1ed2f7b 100644 (file)
@@ -100,62 +100,6 @@ module rwcal
 
   uses connection-status;
 
-  typedef sdn-account-type {
-    description "SDN account type";
-    type enumeration {
-      enum odl;
-      enum mock;
-      enum sdnsim;
-    }
-  }
-
-  grouping sdn-provider-auth {
-    leaf account-type {
-      type sdn-account-type;
-    }
-
-    choice provider-specific-info {
-      container odl {
-        leaf username {
-          type string {
-            length "1..255";
-          }
-        }
-
-        leaf password {
-          type string {
-            length "1..32";
-          }
-        }
-
-        leaf url {
-          type string {
-            length "1..255";
-          }
-        }
-      }
-      container mock {
-        leaf username {
-          type string;
-        }
-        leaf plugin-name {
-          type string;
-          default "rwsdn_mock";
-        }
-      }
-
-      container sdnsim {
-        leaf username {
-          type string;
-        }
-        leaf plugin-name {
-          type string;
-          default "rwsdn_sim";
-        }
-      }
-    }
-  }
-
   grouping provider-auth {
     leaf account-type {
       type manotypes:cloud-account-type;
index 4a2741d..f11616c 100644 (file)
@@ -38,7 +38,7 @@ rw-nsr
 rw-pb-ext
 rw-resource-mgr
 rw-restportforward
-rwsdn
+rwsdnal
 rw-sdn
 rwshell-mgmt
 rw-sorch
index da9807a..99cb3f7 100755 (executable)
@@ -51,7 +51,7 @@ from gi.repository import (
     VnfrYang,
     RwVnfrYang,
     RwNsmYang,
-    RwsdnYang,
+    RwsdnalYang,
     RwDts as rwdts,
     RwTypes,
     ProtobufC,
@@ -383,7 +383,7 @@ class VnffgRecord(object):
                     vnfr = yield from self._nsr.fetch_vnfr(nsr_vnfr.xpath)
                     self._log.debug("Received VNFR is %s", vnfr)
 
-                sff =  RwsdnYang.VNFFGSff()
+                sff =  RwsdnalYang.VNFFGSff()
                 sff_list[nsr_vnfr.vnfd.id] = sff
                 sff.name = nsr_vnfr.name
                 sff.function_type = nsr_vnfr.vnfd.service_function_chain
index cf83612..4d6cde4 100755 (executable)
@@ -19,7 +19,7 @@ import asyncio
 
 from gi.repository import (
     RwDts as rwdts,
-    RwsdnYang,
+    RwsdnalYang,
     RwTypes,
     ProtobufC,
 )
@@ -79,7 +79,7 @@ class VnffgMgr(object):
         if (account.name in self._account):
             self._log.error("SDN Account is already set")
         else:
-            sdn_account           = RwsdnYang.SDNAccount()
+            sdn_account           = RwsdnalYang.SDNAccount()
             sdn_account.from_dict(account.as_dict())
             sdn_account.name = account.name
             self._account[account.name] = sdn_account
@@ -102,7 +102,7 @@ class VnffgMgr(object):
 
     def get_sdn_account(self, name):
         """
-        Creates an object for class RwsdnYang.SdnAccount()
+        Creates an object for class RwsdnalYang.SdnAccount()
         """
         if (name in self._account):
             return self._account[name]
@@ -172,7 +172,7 @@ class VnffgMgr(object):
         sdn_plugin = self.get_sdn_plugin(sdn_acct_name)
 
         for rsp in vnffgr.rsp:
-            vnffg = RwsdnYang.VNFFGChain()
+            vnffg = RwsdnalYang.VNFFGChain()
             vnffg.name = rsp.name
             vnffg.classifier_name = rsp.classifier_name
 
@@ -230,7 +230,7 @@ class VnffgMgr(object):
             else:
                 self._log.error("No RSP wiht name %s found; Skipping classifier %s creation",classifier.rsp_id_ref,classifier.name)
                 continue
-            vnffgcl = RwsdnYang.VNFFGClassifier()
+            vnffgcl = RwsdnalYang.VNFFGClassifier()
             vnffgcl.name = classifier.name
             vnffgcl.rsp_name = cl_rsp_name
             vnffgcl.port_id = vnffgr_cl[0].port_id
index 0ced574..6ec2421 100755 (executable)
@@ -16,8 +16,6 @@
 #
 
 import asyncio
-import logging
-import os
 import sys
 
 import gi
@@ -25,13 +23,12 @@ gi.require_version('RwVnsYang', '1.0')
 gi.require_version('RwDts', '1.0')
 from gi.repository import (
     RwVnsYang,
-    RwSdnYang,
     RwDts as rwdts,
     RwTypes,
-    ProtobufC,
 )
 
 import rift.tasklets
+import rift.mano.sdn
 
 from rift.vlmgr import (
     VlrDtsHandler,
@@ -43,20 +40,9 @@ from rift.topmgr import (
     NwtopStaticDtsHandler,
     NwtopDiscoveryDtsHandler,
     NwtopDataStore,
-    SdnAccountMgr,
 )
 
 
-class SdnInterfaceError(Exception):
-    """ SDN interface creation Error """
-    pass
-
-
-class SdnPluginError(Exception):
-    """ SDN plugin creation Error """
-    pass
-
-
 class VlRecordError(Exception):
     """ Vlr Record creation Error """
     pass
@@ -66,186 +52,43 @@ class VlRecordNotFound(Exception):
     """ Vlr Record not found"""
     pass
 
-class SdnAccountError(Exception):
-    """ Error while creating/deleting/updating SDN Account"""
-    pass
 
-class SdnAccountNotFound(Exception):
-    pass
-
-class SDNAccountDtsOperdataHandler(object):
-    def __init__(self, dts, log, loop, parent):
-        self._dts = dts
+class SDNAccountHandlers(object):
+    def __init__(self, dts, log, log_hdl, acctstore, loop):
         self._log = log
-        self._loop = loop
-        self._parent = parent
-
-    def _register_show_status(self):
-        def get_xpath(sdn_name=None):
-            return "D,/rw-sdn:sdn/rw-sdn:account{}/rw-sdn:connection-status".format(
-                    "[name='%s']" % sdn_name if sdn_name is not None else ''
-                   )
-
-        @asyncio.coroutine
-        def on_prepare(xact_info, action, ks_path, msg):
-            path_entry = RwSdnYang.SDNAccountConfig.schema().keyspec_to_entry(ks_path)
-            sdn_account_name = path_entry.key00.name
-            self._log.debug("Got show sdn connection status request: %s", ks_path.create_string())
-
-            try:
-                saved_accounts = self._parent._acctmgr.get_saved_sdn_accounts(sdn_account_name)
-                for account in saved_accounts:
-                    sdn_acct = RwSdnYang.SDNAccountConfig()
-                    sdn_acct.from_dict(account.as_dict())
-
-                    self._log.debug("Responding to sdn connection status request: %s", sdn_acct.connection_status)
-                    xact_info.respond_xpath(
-                            rwdts.XactRspCode.MORE,
-                            xpath=get_xpath(account.name),
-                            msg=sdn_acct.connection_status,
-                            )
-            except KeyError as e:
-                self._log.warning(str(e))
-                xact_info.respond_xpath(rwdts.XactRspCode.NA)
-                return
-
-            xact_info.respond_xpath(rwdts.XactRspCode.ACK)
-
-        yield from self._dts.register(
-                xpath=get_xpath(),
-                handler=rift.tasklets.DTS.RegistrationHandler(
-                    on_prepare=on_prepare),
-                flags=rwdts.Flag.PUBLISHER,
-                )
-
-    def _register_validate_rpc(self):
-        def get_xpath():
-            return "/rw-sdn:update-sdn-status"
-
-        @asyncio.coroutine
-        def on_prepare(xact_info, action, ks_path, msg):
-            if not msg.has_field("sdn_account"):
-                raise SdnAccountNotFound("SDN account name not provided")
-
-            sdn_account_name = msg.sdn_account
-            account = self._parent._acctmgr.get_sdn_account(sdn_account_name)
-            if account is None:
-                self._log.warning("SDN account %s does not exist", sdn_account_name)
-                xact_info.respond_xpath(rwdts.XactRspCode.NA)
-                return
-
-            self._parent._acctmgr.start_validate_credentials(self._loop, sdn_account_name)
-
-            xact_info.respond_xpath(rwdts.XactRspCode.ACK)
-
-        yield from self._dts.register(
-                xpath=get_xpath(),
-                handler=rift.tasklets.DTS.RegistrationHandler(
-                    on_prepare=on_prepare
-                    ),
-                flags=rwdts.Flag.PUBLISHER,
-                )
-
-    @asyncio.coroutine
-    def register(self):
-        yield from self._register_show_status()
-        yield from self._register_validate_rpc()
-
-class SDNAccountDtsHandler(object):
-    XPATH = "C,/rw-sdn:sdn/rw-sdn:account"
-
-    def __init__(self, dts, log, parent):
+        self._log_hdl = log_hdl
         self._dts = dts
-        self._log = log
-        self._parent = parent
-
-        self._sdn_account = {}
-
-    def _set_sdn_account(self, account):
-        self._log.info("Setting sdn account: {}".format(account))
-        if account.name in self._sdn_account:
-            self._log.error("SDN Account with name %s already exists. Ignoring config", account.name);
-        self._sdn_account[account.name]  = account
-        self._parent._acctmgr.set_sdn_account(account)
-
-    def _del_sdn_account(self, account_name):
-        self._log.info("Deleting sdn account: {}".format(account_name))
-        del self._sdn_account[account_name]
-
-        self._parent._acctmgr.del_sdn_account(account_name)
-
-    def _update_sdn_account(self, account):
-        self._log.info("Updating sdn account: {}".format(account))
-        # No need to update locally saved sdn_account's updated fields, as they
-        # are not used anywhere. Call the parent's update callback.
-        self._parent._acctmgr.update_sdn_account(account)
-
+        self._loop = loop
+        self._acctstore = acctstore
+  
+        self._log.debug("Creating SDN account config handler")
+        self.sdn_cfg_handler = rift.mano.sdn.SDNAccountConfigSubscriber(
+              self._dts, self._log, self._log_hdl,
+              rift.mano.sdn.SDNAccountConfigCallbacks(
+                  on_add_apply=self.on_sdn_account_added,
+                  on_delete_apply=self.on_sdn_account_deleted,
+              ),
+              self._acctstore
+
+        )
+  
+        self._log.debug("Creating SDN account opdata handler")
+        self.sdn_operdata_handler = rift.mano.sdn.SDNAccountDtsOperdataHandler(
+              self._dts, self._log, self._loop,
+        )
+  
+    def on_sdn_account_deleted(self, account_name):
+        self._log.debug("SDN account deleted")
+        self.sdn_operdata_handler.delete_sdn_account(account_name)
+  
+    def on_sdn_account_added(self, account):
+        self._log.debug("SDN account added")
+        self.sdn_operdata_handler.add_sdn_account(account)
+  
     @asyncio.coroutine
     def register(self):
-        def apply_config(dts, acg, xact, action, _):
-            self._log.debug("Got sdn account apply config (xact: %s) (action: %s)", xact, action)
-            if action == rwdts.AppconfAction.INSTALL and xact.id is None:
-                self._log.debug("No xact handle.  Skipping apply config")
-                return RwTypes.RwStatus.SUCCESS
-
-            return RwTypes.RwStatus.SUCCESS
-
-        @asyncio.coroutine
-        def on_prepare(dts, acg, xact, xact_info, ks_path, msg, scratch):
-            """ Prepare callback from DTS for SDN Account config """
-
-            self._log.info("SDN Cloud account config received: %s", msg)
-
-            fref = ProtobufC.FieldReference.alloc()
-            fref.goto_whole_message(msg.to_pbcm())
-
-            if fref.is_field_deleted():
-                # Delete the sdn account record
-                self._del_sdn_account(msg.name)
-            else:
-                # If the account already exists, then this is an update.
-                if msg.name in self._sdn_account:
-                    self._log.debug("SDN account already exists. Invoking on_prepare update request")
-                    if msg.has_field("account_type"):
-                        errmsg = "Cannot update SDN account's account-type."
-                        self._log.error(errmsg)
-                        xact_info.send_error_xpath(RwTypes.RwStatus.FAILURE,
-                                                   SDNAccountDtsHandler.XPATH,
-                                                   errmsg)
-                        raise SdnAccountError(errmsg)
-
-                    # Update the sdn account record
-                    self._update_sdn_account(msg)
-                else:
-                    self._log.debug("SDN account does not already exist. Invoking on_prepare add request")
-                    if not msg.has_field('account_type'):
-                        errmsg = "New SDN account must contain account-type field."
-                        self._log.error(errmsg)
-                        xact_info.send_error_xpath(RwTypes.RwStatus.FAILURE,
-                                                   SDNAccountDtsHandler.XPATH,
-                                                   errmsg)
-                        raise SdnAccountError(errmsg)
-
-                    # Set the sdn account record
-                    self._set_sdn_account(msg)
-
-            xact_info.respond_xpath(rwdts.XactRspCode.ACK)
-
-
-        self._log.debug("Registering for Sdn Account config using xpath: %s",
-                        SDNAccountDtsHandler.XPATH,
-                        )
-
-        acg_handler = rift.tasklets.AppConfGroup.Handler(
-                        on_apply=apply_config,
-                        )
-
-        with self._dts.appconf_group_create(acg_handler) as acg:
-            acg.register(
-                    xpath=SDNAccountDtsHandler.XPATH,
-                    flags=rwdts.Flag.SUBSCRIBER | rwdts.Flag.DELTA_READY,
-                    on_prepare=on_prepare
-                    )
+        self.sdn_cfg_handler.register()
+        yield from self.sdn_operdata_handler.register()
 
 
 class VnsManager(object):
@@ -255,14 +98,13 @@ class VnsManager(object):
         self._log = log
         self._log_hdl = log_hdl
         self._loop = loop
+        self._acctstore = {}
         self._vlr_handler = VlrDtsHandler(dts, log, loop, self)
         self._vld_handler = VldDtsHandler(dts, log, loop, self)
-        self._sdn_handler = SDNAccountDtsHandler(dts,log,self)
-        self._sdn_opdata_handler = SDNAccountDtsOperdataHandler(dts,log, loop, self)
-        self._acctmgr = SdnAccountMgr(self._log, self._log_hdl, self._loop)
+        self._sdn_handlers = SDNAccountHandlers(dts, log, log_hdl, self._acctstore, loop)
         self._nwtopdata_store = NwtopDataStore(log)
-        self._nwtopdiscovery_handler = NwtopDiscoveryDtsHandler(dts, log, loop, self._acctmgr, self._nwtopdata_store)
-        self._nwtopstatic_handler = NwtopStaticDtsHandler(dts, log, loop, self._acctmgr, self._nwtopdata_store)
+        self._nwtopdiscovery_handler = NwtopDiscoveryDtsHandler(dts, log, loop, self._acctstore, self._nwtopdata_store)
+        self._nwtopstatic_handler = NwtopStaticDtsHandler(dts, log, loop, self._acctstore, self._nwtopdata_store)
         self._vlrs = {}
 
     @asyncio.coroutine
@@ -278,11 +120,10 @@ class VnsManager(object):
         yield from self._vld_handler.register()
 
     @asyncio.coroutine
-    def register_sdn_handler(self):
-        """ Register vlr DTS handler """
-        self._log.debug("Registering  SDN Account config handler")
-        yield from self._sdn_handler.register()
-        yield from self._sdn_opdata_handler.register()
+    def register_sdn_handlers(self):
+        """ Register SDN DTS handlers """
+        self._log.debug("Registering  SDN Account handlers")
+        yield from self._sdn_handlers.register()
 
     @asyncio.coroutine
     def register_nwtopstatic_handler(self):
@@ -299,11 +140,10 @@ class VnsManager(object):
     @asyncio.coroutine
     def register(self):
         """ Register all static DTS handlers"""
-        yield from self.register_sdn_handler()
+        yield from self.register_sdn_handlers()
         yield from self.register_vlr_handler()
         yield from self.register_vld_handler()
         yield from self.register_nwtopstatic_handler()
-        # Not used for now
         yield from self.register_nwtopdiscovery_handler()
 
     def create_vlr(self, msg):
index f570abc..1f750bd 100644 (file)
@@ -20,7 +20,6 @@
 from .rwtopmgr import (
     NwtopDiscoveryDtsHandler,
     NwtopStaticDtsHandler,
-    SdnAccountMgr,
 )
 
 from .rwtopdatastore import (
index b095fbc..af4b75b 100755 (executable)
@@ -28,168 +28,23 @@ from gi.repository import (
     IetfNetworkTopologyYang,
     IetfL2TopologyYang,
     RwTopologyYang,
-    RwsdnYang,
+    RwsdnalYang,
     RwTypes
 )
 
 from gi.repository.RwTypes import RwStatus
-import rw_peas
 import rift.tasklets
 
-class SdnGetPluginError(Exception):
-    """ Error while fetching SDN plugin """
-    pass
-  
-  
-class SdnGetInterfaceError(Exception):
-    """ Error while fetching SDN interface"""
-    pass
-
-
-class SdnAccountMgr(object):
-    """ Implements the interface to backend plugins to fetch topology """
-    def __init__(self, log, log_hdl, loop):
-        self._account = {}
-        self._log = log
-        self._log_hdl = log_hdl
-        self._loop = loop
-        self._sdn = {}
-
-        self._regh = None
-
-        self._status = RwsdnYang.SDNAccount_ConnectionStatus(
-                status='unknown',
-                details="Connection status lookup not started"
-                )
-
-        self._validate_task = None
-
-    def set_sdn_account(self,account):
-        if (account.name in self._account):
-            self._log.error("SDN Account is already set")
-        else:
-            sdn_account           = RwsdnYang.SDNAccount()
-            sdn_account.from_dict(account.as_dict())
-            sdn_account.name = account.name
-            self._account[account.name] = sdn_account
-            self._log.debug("Account set is %s , %s",type(self._account), self._account)
-            self.start_validate_credentials(self._loop, account.name)
-
-    def del_sdn_account(self, name):
-        self._log.debug("Account deleted is %s , %s", type(self._account), name)
-        del self._account[name]
-
-    def update_sdn_account(self,account):
-        self._log.debug("Account updated is %s , %s", type(self._account), account)
-        if account.name in self._account:
-            sdn_account = self._account[account.name]
-
-            sdn_account.from_dict(
-                account.as_dict(),
-                ignore_missing_keys=True,
-                )
-            self._account[account.name] = sdn_account
-            self.start_validate_credentials(self._loop, account.name)
-
-    def get_sdn_account(self, name):
-        """
-        Creates an object for class RwsdnYang.SdnAccount()
-        """
-        if (name in self._account):
-            return self._account[name]
-        else:
-            self._log.error("ERROR : SDN account is not configured") 
-
-    def get_saved_sdn_accounts(self, name):
-        ''' Get SDN Account corresponding to passed name, or all saved accounts if name is None'''
-        saved_sdn_accounts = []
-
-        if name is None or name == "":
-            sdn_accounts = list(self._account.values())
-            saved_sdn_accounts.extend(sdn_accounts)
-        elif name in self._account:
-            account = self._account[name]
-            saved_sdn_accounts.append(account)
-        else:
-            errstr = "SDN account {} does not exist".format(name)
-            raise KeyError(errstr)
-
-        return saved_sdn_accounts
-
-    def get_sdn_plugin(self,name):
-        """
-        Loads rw.sdn plugin via libpeas
-        """
-        if (name in self._sdn):
-            return self._sdn[name]
-        account = self.get_sdn_account(name)
-        plugin_name = getattr(account, account.account_type).plugin_name
-        self._log.info("SDN plugin being created")
-        plugin = rw_peas.PeasPlugin(plugin_name, 'RwSdn-1.0')
-        engine, info, extension = plugin()
-
-        self._sdn[name] = plugin.get_interface("Topology")
-        try:
-            rc = self._sdn[name].init(self._log_hdl)
-            assert rc == RwStatus.SUCCESS
-        except:
-            self._log.error("ERROR:SDN plugin instantiation failed ")
-        else:
-            self._log.info("SDN plugin successfully instantiated")
-        return self._sdn[name]
-
-    @asyncio.coroutine
-    def validate_sdn_account_credentials(self, loop, name):
-        self._log.debug("Validating SDN Account credentials %s", name)
-        self._status = RwsdnYang.SDNAccount_ConnectionStatus(
-                status="validating",
-                details="SDN account connection validation in progress"
-                )
-
-        _sdnacct = self.get_sdn_account(name)
-        if (_sdnacct is None):
-            raise SdnGetPluginError
-        _sdnplugin = self.get_sdn_plugin(name)
-        if (_sdnplugin is None):
-            raise SdnGetInterfaceError
-
-        rwstatus, status = yield from loop.run_in_executor(
-                None,
-                _sdnplugin.validate_sdn_creds,
-                _sdnacct,
-                )
-
-        if rwstatus == RwTypes.RwStatus.SUCCESS:
-            self._status = RwsdnYang.SDNAccount_ConnectionStatus.from_dict(status.as_dict())
-        else:
-            self._status = RwsdnYang.SDNAccount_ConnectionStatus(
-                    status="failure",
-                    details="Error when calling CAL validate sdn creds"
-                    )
-
-        self._log.info("Got sdn account validation response: %s", self._status)
-        _sdnacct.connection_status = self._status
-
-    def start_validate_credentials(self, loop, name):
-        if self._validate_task is not None:
-            self._validate_task.cancel()
-            self._validate_task = None
-
-        self._validate_task = asyncio.ensure_future(
-                self.validate_sdn_account_credentials(loop, name),
-                loop=loop
-                )
-
 
 class NwtopDiscoveryDtsHandler(object):
     """ Handles DTS interactions for the Discovered Topology registration """
     DISC_XPATH = "D,/nd:network"
 
-    def __init__(self, dts, log, loop, acctmgr, nwdatastore):
+    def __init__(self, dts, log, loop, acctstore, nwdatastore):
         self._dts = dts
         self._log = log
         self._loop = loop
-        self._acctmgr = acctmgr
+        self._acctstore = acctstore
         self._nwdatastore = nwdatastore
 
         self._regh = None
@@ -219,16 +74,12 @@ class NwtopDiscoveryDtsHandler(object):
 
             if action == rwdts.QueryAction.READ:
                 
-                for name in self._acctmgr._account:
-                    _sdnacct = self._acctmgr.get_sdn_account(name)
-                    if (_sdnacct is None):
-                        raise SdnGetPluginError
-
-                    _sdnplugin = self._acctmgr.get_sdn_plugin(name)
-                    if (_sdnplugin is None):
-                        raise SdnGetInterfaceError
+                for name, sdnacct in self._acctstore.items():
+                    if sdnacct.account_type != "odl":
+                        continue
+                    sdnintf = sdnacct.sdn
 
-                    rc, nwtop = _sdnplugin.get_network_list(_sdnacct)
+                    rc, nwtop = sdnintf.get_network_list(sdnacct.sdnal_account_msg)
                     #assert rc == RwStatus.SUCCESS
                     if rc != RwStatus.SUCCESS:
                         self._log.error("Fetching get network list for SDN Account %s failed", name)
@@ -268,11 +119,11 @@ class NwtopStaticDtsHandler(object):
     """ Handles DTS interactions for the Static Topology registration """
     STATIC_XPATH = "C,/nd:network"
 
-    def __init__(self, dts, log, loop, acctmgr, nwdatastore):
+    def __init__(self, dts, log, loop, acctstore, nwdatastore):
         self._dts = dts
         self._log = log
         self._loop = loop
-        self._acctmgr = acctmgr
+        self._acctstore = acctstore
 
         self._regh = None
         self.pending = {}
index 45e2e80..6121747 100644 (file)
@@ -22,10 +22,10 @@ import unittest
 import rw_peas
 import rwlogger
 
-from gi.repository import RwsdnYang
+from gi.repository import RwsdnalYang
 import gi
 gi.require_version('RwTypes', '1.0')
-gi.require_version('RwSdn', '1.0')
+gi.require_version('RwSdnal', '1.0')
 from gi.repository import RwcalYang
 from gi.repository import IetfNetworkYang
 from gi.repository.RwTypes import RwStatus
@@ -35,9 +35,9 @@ logger = logging.getLogger('mock')
 
 def get_sdn_account():
     """
-    Creates an object for class RwsdnYang.SdnAccount()
+    Creates an object for class RwsdnalYang.SdnAccount()
     """
-    account                 = RwsdnYang.SDNAccount()
+    account                 = RwsdnalYang.SDNAccount()
     account.account_type    = "mock"
     account.mock.username   = "rift"
     account.mock.plugin_name = "rwsdn_mock"
diff --git a/rwlaunchpad/plugins/rwvns/test/test_sdn_odl.py b/rwlaunchpad/plugins/rwvns/test/test_sdn_odl.py
new file mode 100644 (file)
index 0000000..b4dda0e
--- /dev/null
@@ -0,0 +1,116 @@
+
+# 
+#   Copyright 2017 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 logging
+import unittest
+
+import rw_peas
+import rwlogger
+
+import gi
+gi.require_version('RwTypes', '1.0')
+from gi.repository import RwsdnalYang
+from gi.repository.RwTypes import RwStatus
+
+
+logger = logging.getLogger('sdnodl')
+
+odl_info = {
+    'username'      : 'admin',
+    'password'      : 'admin',
+    'url'           : 'http://10.66.4.27:8181',
+}
+
+
+def get_sdn_account():
+    """
+    Creates an object for class RwsdnalYang.SdnAccount()
+    """
+    account                 = RwsdnalYang.SDNAccount()
+    account.name            = "grunt27"
+    account.account_type    = "odl"
+    account.odl.plugin_name = "rwsdn_odl"
+    account.odl.username    = odl_info['username']
+    account.odl.password    = odl_info['password']
+    account.odl.url       = odl_info['url']
+
+    return account
+
+def get_sdn_plugin():
+    """
+    Loads rw.sdn plugin via libpeas
+    """
+    plugin = rw_peas.PeasPlugin('rwsdn_odl', 'RwSdn-1.0')
+    engine, info, extension = plugin()
+
+    # Get the RwLogger context
+    rwloggerctx = rwlogger.RwLog.Ctx.new("SDN-Log")
+
+    sdn = plugin.get_interface("Topology")
+    try:
+        rc = sdn.init(rwloggerctx)
+        assert rc == RwStatus.SUCCESS
+    except:
+        logger.error("ERROR:SDN ODL plugin instantiation failed. Aborting tests")
+    else:
+        logger.info("SDN ODL plugin successfully instantiated")
+    return sdn
+
+
+
+class SdnOdlTest(unittest.TestCase):
+    def setUp(self):
+        """
+          Initialize test plugins
+        """
+        self._acct = get_sdn_account()
+        logger.info("SDN-Odl-Test: setUp")
+        self.sdn   = get_sdn_plugin()
+        logger.info("SDN-Odl-Test: setUpEND")
+
+    def tearDown(self):
+        logger.info("SDN-Odl-Test: Done with tests")
+
+    def test_validate_sdn_creds(self):
+        """
+           First test case
+        """
+        logger.debug("SDN-Odl-Test: Starting validate creds ")
+        rc, status = self.sdn.validate_sdn_creds(self._acct)
+        logger.debug("SDN-Odl-Test: SDN return code %s resp %s", rc, status)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("SDN-Odl-Test: Passed validate creds")
+
+    def test_get_network_list(self):
+        """
+           Get-network-list test case
+        """
+        logger.debug("SDN-Odl-Test: Getting network list ")
+        rc, status = self.sdn.get_network_list(self._acct)
+        logger.debug("SDN-Odl-Test: SDN return code %s resp %s", rc, status)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("SDN-Odl-Test: Passed get network list")
+
+
+
+if __name__ == "__main__":
+    logging.basicConfig(level=logging.DEBUG)
+    unittest.main()
+
+
+
+
diff --git a/rwlaunchpad/plugins/rwvns/test/test_sdn_openstack.py b/rwlaunchpad/plugins/rwvns/test/test_sdn_openstack.py
new file mode 100644 (file)
index 0000000..05fc3f7
--- /dev/null
@@ -0,0 +1,111 @@
+
+# 
+#   Copyright 2017 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 logging
+import unittest
+
+import rw_peas
+import rwlogger
+
+import gi
+gi.require_version('RwTypes', '1.0')
+from gi.repository import RwsdnalYang
+from gi.repository.RwTypes import RwStatus
+
+
+logger = logging.getLogger('sdnopenstack')
+
+openstack_info = {
+    'username'           : 'pluto',
+    'password'           : 'mypasswd',
+    'auth_url'           : 'http://10.66.4.17:5000/v2.0/',
+    'project_name'       : 'demo',
+    'user_domain_name'   : 'default',
+    'project_domain_name': 'default'
+}
+
+
+def get_sdn_account():
+    """
+    Creates an object for class RwsdnalYang.SdnAccount()
+    """
+    account                 = RwsdnalYang.SDNAccount()
+    account.name                     = "grunt17"
+    account.account_type             = "openstack"
+    account.openstack.plugin_name = "rwsdn_openstack"
+    account.openstack.key            = openstack_info['username']
+    account.openstack.secret         = openstack_info['password']
+    account.openstack.auth_url       = openstack_info['auth_url']
+    account.openstack.tenant         = openstack_info['project_name']
+    account.openstack.user_domain    = openstack_info['user_domain_name']
+    account.openstack.project_domain = openstack_info['project_domain_name']
+
+    return account
+
+def get_sdn_plugin():
+    """
+    Loads rw.sdn plugin via libpeas
+    """
+    plugin = rw_peas.PeasPlugin('rwsdn_openstack', 'RwSdn-1.0')
+    engine, info, extension = plugin()
+
+    # Get the RwLogger context
+    rwloggerctx = rwlogger.RwLog.Ctx.new("SDN-Log")
+
+    sdn = plugin.get_interface("Topology")
+    try:
+        rc = sdn.init(rwloggerctx)
+        assert rc == RwStatus.SUCCESS
+    except:
+        logger.error("ERROR:SDN openstack plugin instantiation failed. Aborting tests")
+    else:
+        logger.info("SDN openstack plugin successfully instantiated")
+    return sdn
+
+
+
+class SdnOpenstackTest(unittest.TestCase):
+    def setUp(self):
+        """
+          Initialize test plugins
+        """
+        self._acct = get_sdn_account()
+        logger.info("SDN-Openstack-Test: setUp")
+        self.sdn   = get_sdn_plugin()
+        logger.info("SDN-Openstack-Test: setUpEND")
+
+    def tearDown(self):
+        logger.info("SDN-Openstack-Test: Done with tests")
+
+    def test_validate_sdn_creds(self):
+        """
+           First test case
+        """
+        logger.debug("SDN-Openstack-Test: Starting validate creds ")
+        rc, status = self.sdn.validate_sdn_creds(self._acct)
+        logger.debug("SDN-Openstack-Test: SDN return code %s resp %s", rc, status)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("SDN-Openstack-Test: Passed validate creds")
+
+
+if __name__ == "__main__":
+    logging.basicConfig(level=logging.DEBUG)
+    unittest.main()
+
+
+
+
index d216f0d..e9cd0b3 100644 (file)
@@ -15,7 +15,6 @@
 #   limitations under the License.
 #
 
-import datetime
 import logging
 import unittest
 
@@ -24,20 +23,17 @@ import rwlogger
 
 import gi
 gi.require_version('RwTypes', '1.0')
-gi.require_version('RwSdn', '1.0')
-from gi.repository import RwsdnYang
-from gi.repository import IetfNetworkYang
+from gi.repository import RwsdnalYang
 from gi.repository.RwTypes import RwStatus
-from gi.repository import RwSdn
 
 
 logger = logging.getLogger('sdnsim')
 
 def get_sdn_account():
     """
-    Creates an object for class RwsdnYang.SdnAccount()
+    Creates an object for class RwsdnalYang.SdnAccount()
     """
-    account                 = RwsdnYang.SDNAccount()
+    account                 = RwsdnalYang.SDNAccount()
     account.account_type    = "sdnsim"
     account.sdnsim.username   = "rift"
     account.sdnsim.plugin_name = "rwsdn_sim"
index 44e2f5c..06b59c3 100755 (executable)
@@ -43,7 +43,7 @@ import gi.repository.RwManifestYang as rwmanifest
 import gi.repository.IetfL2TopologyYang as l2Tl
 import gi.repository.RwTopologyYang as RwTl
 import gi.repository.RwLaunchpadYang as launchpadyang
-from gi.repository import RwsdnYang
+from gi.repository import RwsdnalYang
 from gi.repository.RwTypes import RwStatus
 
 from create_stackedl2topology import MyL2Topology
index 4865d2e..8f87f66 100644 (file)
@@ -33,7 +33,7 @@ rift_add_vala(
   VALA_FILES ${VALA_FILES}
   VALA_PACKAGES
     rw_types-1.0 rw_yang-1.0 rw_keyspec-1.0 rw_yang_pb-1.0 rw_schema_proto-1.0
-    rw_log_yang-1.0 rw_base_yang-1.0 rwcal_yang-1.0 rwsdn_yang-1.0 rw_manifest_yang-1.0 protobuf_c-1.0 ietf_netconf_yang-1.0
+    rw_log_yang-1.0 rw_base_yang-1.0 rwcal_yang-1.0 rwsdnal_yang-1.0 rw_manifest_yang-1.0 protobuf_c-1.0 ietf_netconf_yang-1.0
     ietf_network_yang-1.0 ietf_network_topology_yang-1.0
     ietf_l2_topology_yang-1.0 rw_topology_yang-1.0
     rw_log-1.0
@@ -50,7 +50,7 @@ rift_add_vala(
   GENERATE_VAPI_FILE ${VALA_LONG_NAME}.vapi
   GENERATE_GIR_FILE ${VALA_TYPELIB_PREFIX}.gir
   GENERATE_TYPELIB_FILE ${VALA_TYPELIB_PREFIX}.typelib
-  DEPENDS rwcal_yang rwsdn_yang mano_yang rwlog_gi rwschema_yang
+  DEPENDS rwcal_yang rwsdnal_yang mano_yang rwlog_gi rwschema_yang
   )
 
 rift_install_vala_artifacts(
index ec4ab31..a4d597d 100644 (file)
@@ -10,8 +10,8 @@ namespace RwSdn {
      * Credential Validation related APIs
      */
     public abstract RwTypes.RwStatus validate_sdn_creds(
-      Rwsdn.SDNAccount account,
-      out Rwsdn.SdnConnectionStatus status);
+      Rwsdnal.SDNAccount account,
+      out Rwsdnal.SdnConnectionStatus status);
 
     /*
      * Configuring  related APIs
@@ -22,22 +22,22 @@ namespace RwSdn {
      * Network related APIs
      */
     public abstract RwTypes.RwStatus get_network_list(
-      Rwsdn.SDNAccount account,
+      Rwsdnal.SDNAccount account,
       out RwTopology.YangData_IetfNetwork network_topology);
    
     /*
      * VNFFG Chain related APIs
      */
     public abstract RwTypes.RwStatus create_vnffg_chain(
-      Rwsdn.SDNAccount account,
-      Rwsdn.VNFFGChain vnffg_chain,
+      Rwsdnal.SDNAccount account,
+      Rwsdnal.VNFFGChain vnffg_chain,
       out string vnffg_id);
 
     /*
      * VNFFG Chain Terminate related APIs
      */
     public abstract RwTypes.RwStatus terminate_vnffg_chain(
-      Rwsdn.SDNAccount account,
+      Rwsdnal.SDNAccount account,
       string vnffg_id);
 
 
@@ -45,22 +45,22 @@ namespace RwSdn {
      * Network related APIs
      */
     public abstract RwTypes.RwStatus get_vnffg_rendered_paths(
-      Rwsdn.SDNAccount account,
-      out Rwsdn.VNFFGRenderedPaths rendered_paths);
+      Rwsdnal.SDNAccount account,
+      out Rwsdnal.VNFFGRenderedPaths rendered_paths);
 
     /*
      * Classifier related APIs
      */
     public abstract RwTypes.RwStatus create_vnffg_classifier(
-      Rwsdn.SDNAccount account,
-      Rwsdn.VNFFGClassifier vnffg_classifier, 
+      Rwsdnal.SDNAccount account,
+      Rwsdnal.VNFFGClassifier vnffg_classifier, 
       out string vnffg_classifier_id);
 
     /*
      * Classifier related APIs
      */
     public abstract RwTypes.RwStatus terminate_vnffg_classifier(
-      Rwsdn.SDNAccount account,
+      Rwsdnal.SDNAccount account,
       string vnffg_classifier_id);
 
 
index 2c0ffcc..fc0d86e 100644 (file)
@@ -27,7 +27,7 @@ from gi.repository import (
     RwSdn, # Vala package
     RwTypes,
     RwTopologyYang as RwTl,
-    RwsdnYang
+    RwsdnalYang
     )
 
 import rw_status
@@ -144,7 +144,7 @@ class MockPlugin(GObject.Object, RwSdn.Topology):
                 )
             )
 
-        account = RwsdnYang.SDNAccount()
+        account = RwsdnalYang.SDNAccount()
         account.name = 'mock'
         account.account_type = 'mock'
         account.mock.username = 'rift'
index 3eb39fc..2727d8a 100644 (file)
@@ -26,7 +26,7 @@ import time
 
 import gi
 gi.require_version('RwTypes', '1.0')
-gi.require_version('RwsdnYang', '1.0')
+gi.require_version('RwsdnalYang', '1.0')
 gi.require_version('RwSdn', '1.0')
 gi.require_version('RwTopologyYang','1.0')
 
@@ -34,7 +34,7 @@ from gi.repository import (
     GObject,
     RwSdn, # Vala package
     RwTypes,
-    RwsdnYang, 
+    RwsdnalYang, 
     RwTopologyYang as RwTl,
     )
 
@@ -336,7 +336,7 @@ class SdnOdl(object):
         """
             Validate the SDN account credentials by accessing the rest API using the provided credentials
         """
-        status = RwsdnYang.SdnConnectionStatus()
+        status = RwsdnalYang.SdnConnectionStatus()
         url = '{}/{}'.format(account.odl.url,"restconf")
         try:
             r=requests.get(url,auth=(account.odl.username,account.odl.password))
@@ -354,7 +354,6 @@ class SdnOdl(object):
             status.status = "failure"
             status.details = "Connection Failed (Invlaid URL): %s" % str(e)
         else:
-            print("SDN Successfully connected")
             status.status = "success"
             status.details = "Connection was successful"
 
@@ -935,7 +934,7 @@ class SdnOdl(object):
         self.delete_all_sf(account)
 
     def _fill_rsp_list(self,sfc_rsp_list,sff_list):
-        vnffg_rsps = RwsdnYang.VNFFGRenderedPaths()
+        vnffg_rsps = RwsdnalYang.VNFFGRenderedPaths()
         for sfc_rsp in sfc_rsp_list['rendered-service-paths']['rendered-service-path']:
             rsp = vnffg_rsps.vnffg_rendered_path.add()
             rsp.name = sfc_rsp['name']
index ff5d019..6adece4 100644 (file)
@@ -41,7 +41,7 @@ from gi.repository import (
     GObject,
     RwCal,
     RwSdn, # Vala package
-    RwsdnYang,
+    RwsdnalYang,
     RwTypes,
     RwcalYang)
 
@@ -255,7 +255,7 @@ class SdnOpenstackPlugin(GObject.Object, RwSdn.Topology):
         Returns:
             Validation Code and Details String
         """
-        status = RwsdnYang.SdnConnectionStatus()
+        status = RwsdnalYang.SdnConnectionStatus()
         drv = self._use_driver(account)
         try:
             drv.validate_account_creds()
@@ -366,7 +366,7 @@ class SdnOpenstackPlugin(GObject.Object, RwSdn.Topology):
            @param account - a SDN account
         """
         self.log.debug('Received get VNFFG rendered path for account %s ', account)
-        vnffg_rsps = RwsdnYang.VNFFGRenderedPaths() 
+        vnffg_rsps = RwsdnalYang.VNFFGRenderedPaths() 
         drv = self._use_driver(account)
         port_chain_list = drv.get_port_chain_list()
         for port_chain in port_chain_list:
index 3061265..164aa03 100644 (file)
@@ -32,7 +32,7 @@ from gi.repository import (
     GObject,
     RwSdn, # Vala package
     RwTypes,
-    RwsdnYang,
+    RwsdnalYang,
     #IetfL2TopologyYang as l2Tl,
     RwTopologyYang as RwTl,
     )
@@ -91,7 +91,7 @@ class SdnSimPlugin(GObject.Object, RwSdn.Topology):
         Returns:
             Validation Code and Details String
         """
-        status = RwsdnYang.SdnConnectionStatus()
+        status = RwsdnalYang.SdnConnectionStatus()
         print("SDN Successfully connected")
         status.status = "success"
         status.details = "Connection was successful"
index 00cde0b..5e7e98a 100644 (file)
 
 include(rift_yang)
 
-set(source_yang_files rwsdn.yang)
+set(source_yang_files rwsdnal.yang)
 
 rift_add_yang_target(
-  TARGET rwsdn_yang
+  TARGET rwsdnal_yang
   YANG_FILES ${source_yang_files}
   COMPONENT ${PKG_LONG_NAME}
   LIBRARIES
diff --git a/rwlaunchpad/plugins/rwvns/yang/rwsdn.yang b/rwlaunchpad/plugins/rwvns/yang/rwsdn.yang
deleted file mode 100644 (file)
index 8371ab8..0000000
+++ /dev/null
@@ -1,462 +0,0 @@
-
-/*
- * 
- *   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.
- *
- *
- */
-
-module rwsdn
-{
-  namespace "http://riftio.com/ns/riftware-1.0/rwsdn";
-  prefix "rwsdn";
-
-  import rw-base {
-    prefix rwbase;
-  }
-
-  import rw-pb-ext {
-    prefix "rwpb";
-  }
-
-  import rw-yang-types {
-    prefix "rwt";
-  }
-
-  import rw-log {
-    prefix "rwlog";
-  }
-
-  import mano-types {
-    prefix "manotypes";
-  }
-
-  import ietf-inet-types {
-    prefix "inet";
-  }
-
-  import ietf-yang-types {
-    prefix "yang";
-  }
-
-
-  revision 2014-12-30 {
-    description
-        "Initial revision.";
-    reference
-        "RIFT RWSDN cloud data";
-  }
-
-  typedef sdn-connection-status-enum {
-    description "Connection status for the sdn account";
-    type enumeration {
-      enum unknown;
-      enum validating;
-      enum success;
-      enum failure;
-    }
-  }
-
-  grouping connection-status {
-    container connection-status {
-      config false;
-      rwpb:msg-new SdnConnectionStatus;
-      leaf status {
-        type sdn-connection-status-enum;
-      }
-      leaf details {
-        type string;
-      }
-    }
-  }
-
-  uses connection-status;
-
-  typedef sdn-account-type {
-    description "SDN account type";
-    type enumeration {
-      enum odl;
-      enum mock;
-      enum sdnsim;
-      enum openstack;
-    }
-  }
-
-  grouping sdn-provider-auth {
-    leaf account-type {
-      type sdn-account-type;
-    }
-
-    choice provider-specific-info {
-      container odl {
-        leaf username {
-          type string {
-            length "1..255";
-          }
-        }
-
-        leaf password {
-          type string {
-            length "1..32";
-          }
-        }
-
-        leaf url {
-          type string {
-            length "1..255";
-          }
-        }
-        leaf plugin-name {
-          type string;
-          default "rwsdn_odl";
-        }
-      }
-      container mock {
-        leaf username {
-          type string;
-        }
-        leaf plugin-name {
-          type string;
-          default "rwsdn_mock";
-        }
-      }
-
-      container sdnsim {
-        leaf username {
-          type string;
-        }
-        leaf topology-source {
-          type string;
-        }
-        leaf plugin-name {
-          type string;
-          default "rwsdn_sim";
-        }
-      }
-
-      container openstack {
-        leaf key {
-          type string;
-          mandatory true;
-        }
-
-        leaf secret {
-          type string;
-          mandatory true;
-        }
-
-        leaf auth_url {
-          type string;
-          mandatory true;
-        }
-
-        leaf tenant {
-          type string;
-          mandatory true;
-        }
-
-        leaf admin {
-          type boolean;
-          default false;
-        }
-
-        leaf user-domain {
-          type string;
-          default "Default";
-          description "Domain of the OpenStack user";
-        }
-
-        leaf project-domain {
-          type string;
-          default "Default";
-          description "Domain of the OpenStack project";
-        }
-
-        leaf region {
-          type string;
-          default "RegionOne";
-        }
-
-        leaf plugin-name {
-          type string;
-          default "rwsdn_openstack";
-        }
-
-        leaf cert-validate {
-          type boolean;
-          default false;
-          description "Certificate validatation policy in case of SSL/TLS connection";
-        }
-      }
-
-    }
-  }
-
-  container sdn-accounts {
-    list sdn-account-list {
-      rwpb:msg-new SDNAccount;
-      key "name";
-
-      leaf name {
-        type string;
-      }
-
-      uses sdn-provider-auth;
-      uses connection-status;
-    }
-  }
-
-  container vnffgs {
-    list vnffg-chain {
-      key "name";
-      rwpb:msg-new VNFFGChain;
-
-      leaf name {
-        type string;
-      }
-
-      list vnf-chain-path {
-        key "order";
-        leaf order {
-          type uint32;
-          description " Order of the VNF in VNFFG chain";
-        }
-        leaf service-function-type {
-          type string;
-        }
-        leaf nsh-aware {
-          type boolean;
-        }
-        leaf transport-type {
-          type string;
-        }
-        list vnfr-ids {
-          key "vnfr-id";
-          leaf vnfr-id {
-            type yang:uuid;
-          }
-          leaf vnfr-name {
-            type string;
-          }
-          leaf mgmt-address {
-            type inet:ip-address;
-          }
-          leaf mgmt-port {
-              type inet:port-number;
-          }
-          list vdu-list {
-            key "vm-id port-id";
-            leaf port-id {
-              rwpb:field-inline "true";
-              rwpb:field-string-max 64;
-              type string;
-            }
-            leaf vm-id {
-              rwpb:field-inline "true";
-              rwpb:field-string-max 64;
-              type string;
-            }
-            leaf name {
-              type string;
-            }
-            leaf address {
-              type inet:ip-address;
-            }
-            leaf port {
-              type inet:port-number;
-            }
-          }
-          leaf sff-name {
-            description "SFF name useful for non OVS based SFF";
-            type string;
-          } 
-        }
-      }
-      list sff {
-        rwpb:msg-new VNFFGSff;
-        key "name"; 
-        leaf name {
-          type string;
-        }
-        leaf function-type {
-          type string;
-        }
-        leaf mgmt-address {
-          type inet:ip-address;
-        }
-        leaf mgmt-port {
-          type inet:port-number;
-        }
-        list dp-endpoints {
-          key "name";
-          leaf name {
-           type string;
-          } 
-          leaf address {
-            type inet:ip-address;
-          }
-          leaf port {
-            type inet:port-number;
-          }
-        }
-        list vnfr-list {
-          key "vnfr-name";
-          leaf vnfr-name {
-            type string;
-          }
-        }
-      }
-      leaf classifier-name {
-        type string;
-      }
-    }
-  }
-
-  container vnffg-rendered-paths {
-    rwpb:msg-new VNFFGRenderedPaths;
-    list vnffg-rendered-path {
-      key "name";
-      rwpb:msg-new VNFFGRenderedPath;
-      config false;
-      leaf name {
-        type string;
-      }
-      leaf path-id {
-          description
-              "Unique Identifier for the service path";
-        type uint32;
-      }
-      list rendered-path-hop {
-        key "hop-number";
-        leaf hop-number {
-          type uint8;
-        }
-        leaf service-index {
-            description
-                "Location within the service path";
-          type uint8;
-        }
-        leaf vnfr-name {
-          type string;
-        }
-        container service-function-forwarder {
-          leaf name { 
-            description
-                "Service Function Forwarder name";
-            type string;
-          }
-          leaf ip-address {
-            description
-                "Service Function Forwarder Data Plane IP address";
-            type inet:ip-address;
-          }  
-          leaf port {
-            description
-                "Service Function Forwarder Data Plane port";
-            type inet:port-number;
-          }  
-        }
-      }
-    }
-  }
-
-
-  container vnffg-classifiers {
-    list vnffg-classifier {
-      key "name";
-      rwpb:msg-new VNFFGClassifier;
-
-      leaf name {
-        type string;
-      }
-      leaf rsp-name {
-        type string;
-      }
-      leaf rsp-id {
-        type yang:uuid;
-      }
-      leaf port-id {
-        rwpb:field-inline "true";
-        rwpb:field-string-max 64;
-        type string;
-      }
-      leaf vm-id {
-        rwpb:field-inline "true";
-        rwpb:field-string-max 64;
-        type string;
-      }
-      leaf sff-name {
-        type string;
-      }
-      container vnffg-metadata {
-        leaf ctx1 {
-          type string;
-        }
-        leaf ctx2 {
-          type string;
-        }
-        leaf ctx3 {
-          type string;
-        }
-        leaf ctx4 {
-          type string;
-        }
-      }
-      list match-attributes {
-        description
-            "List of match attributes.";
-        key "name";
-        leaf name {
-          description
-              "Name for the Access list";
-          type string;  
-        }
-
-        leaf ip-proto {
-          description
-              "IP Protocol.";
-          type uint8;
-        }
-
-        leaf source-ip-address {
-          description
-              "Source IP address.";
-          type inet:ip-prefix;
-        }
-
-        leaf destination-ip-address {
-          description
-              "Destination IP address.";
-          type inet:ip-prefix;
-        }
-
-        leaf source-port {
-          description
-              "Source port number.";
-          type inet:port-number;
-        }
-
-        leaf destination-port {
-          description
-              "Destination port number.";
-          type inet:port-number;
-        }
-      } //match-attributes
-    }
-  }
-
-}
-
-/* vim: set ts=2:sw=2: */
diff --git a/rwlaunchpad/plugins/rwvns/yang/rwsdnal.yang b/rwlaunchpad/plugins/rwvns/yang/rwsdnal.yang
new file mode 100644 (file)
index 0000000..b24952b
--- /dev/null
@@ -0,0 +1,462 @@
+
+/*
+ * 
+ *   Copyright 2016-2017 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.
+ *
+ *
+ */
+
+module rwsdnal
+{
+  namespace "http://riftio.com/ns/riftware-1.0/rwsdnal";
+  prefix "rwsdnal";
+
+  import rw-base {
+    prefix rwbase;
+  }
+
+  import rw-pb-ext {
+    prefix "rwpb";
+  }
+
+  import rw-yang-types {
+    prefix "rwt";
+  }
+
+  import rw-log {
+    prefix "rwlog";
+  }
+
+  import mano-types {
+    prefix "manotypes";
+  }
+
+  import ietf-inet-types {
+    prefix "inet";
+  }
+
+  import ietf-yang-types {
+    prefix "yang";
+  }
+
+
+  revision 2014-12-30 {
+    description
+        "Initial revision.";
+    reference
+        "RIFT RWSDN cloud data";
+  }
+
+  typedef sdn-connection-status-enum {
+    description "Connection status for the sdn account";
+    type enumeration {
+      enum unknown;
+      enum validating;
+      enum success;
+      enum failure;
+    }
+  }
+
+  grouping connection-status {
+    container connection-status {
+      config false;
+      rwpb:msg-new SdnConnectionStatus;
+      leaf status {
+        type sdn-connection-status-enum;
+      }
+      leaf details {
+        type string;
+      }
+    }
+  }
+
+  uses connection-status;
+
+  typedef sdn-account-type {
+    description "SDN account type";
+    type enumeration {
+      enum odl;
+      enum mock;
+      enum sdnsim;
+      enum openstack;
+    }
+  }
+
+  grouping sdn-provider-auth {
+    leaf account-type {
+      type sdn-account-type;
+    }
+
+    choice provider-specific-info {
+      container odl {
+        leaf username {
+          type string {
+            length "1..255";
+          }
+        }
+
+        leaf password {
+          type string {
+            length "1..32";
+          }
+        }
+
+        leaf url {
+          type string {
+            length "1..255";
+          }
+        }
+        leaf plugin-name {
+          type string;
+          default "rwsdn_odl";
+        }
+      }
+      container mock {
+        leaf username {
+          type string;
+        }
+        leaf plugin-name {
+          type string;
+          default "rwsdn_mock";
+        }
+      }
+
+      container sdnsim {
+        leaf username {
+          type string;
+        }
+        leaf topology-source {
+          type string;
+        }
+        leaf plugin-name {
+          type string;
+          default "rwsdn_sim";
+        }
+      }
+
+      container openstack {
+        leaf key {
+          type string;
+          mandatory true;
+        }
+
+        leaf secret {
+          type string;
+          mandatory true;
+        }
+
+        leaf auth_url {
+          type string;
+          mandatory true;
+        }
+
+        leaf tenant {
+          type string;
+          mandatory true;
+        }
+
+        leaf admin {
+          type boolean;
+          default false;
+        }
+
+        leaf user-domain {
+          type string;
+          default "Default";
+          description "Domain of the OpenStack user";
+        }
+
+        leaf project-domain {
+          type string;
+          default "Default";
+          description "Domain of the OpenStack project";
+        }
+
+        leaf region {
+          type string;
+          default "RegionOne";
+        }
+
+        leaf plugin-name {
+          type string;
+          default "rwsdn_openstack";
+        }
+
+        leaf cert-validate {
+          type boolean;
+          default false;
+          description "Certificate validatation policy in case of SSL/TLS connection";
+        }
+      }
+
+    }
+  }
+
+  container sdn-accounts {
+    list sdn-account-list {
+      rwpb:msg-new SDNAccount;
+      key "name";
+
+      leaf name {
+        type string;
+      }
+
+      uses sdn-provider-auth;
+      uses connection-status;
+    }
+  }
+
+  container vnffgs {
+    list vnffg-chain {
+      key "name";
+      rwpb:msg-new VNFFGChain;
+
+      leaf name {
+        type string;
+      }
+
+      list vnf-chain-path {
+        key "order";
+        leaf order {
+          type uint32;
+          description " Order of the VNF in VNFFG chain";
+        }
+        leaf service-function-type {
+          type string;
+        }
+        leaf nsh-aware {
+          type boolean;
+        }
+        leaf transport-type {
+          type string;
+        }
+        list vnfr-ids {
+          key "vnfr-id";
+          leaf vnfr-id {
+            type yang:uuid;
+          }
+          leaf vnfr-name {
+            type string;
+          }
+          leaf mgmt-address {
+            type inet:ip-address;
+          }
+          leaf mgmt-port {
+              type inet:port-number;
+          }
+          list vdu-list {
+            key "vm-id port-id";
+            leaf port-id {
+              rwpb:field-inline "true";
+              rwpb:field-string-max 64;
+              type string;
+            }
+            leaf vm-id {
+              rwpb:field-inline "true";
+              rwpb:field-string-max 64;
+              type string;
+            }
+            leaf name {
+              type string;
+            }
+            leaf address {
+              type inet:ip-address;
+            }
+            leaf port {
+              type inet:port-number;
+            }
+          }
+          leaf sff-name {
+            description "SFF name useful for non OVS based SFF";
+            type string;
+          } 
+        }
+      }
+      list sff {
+        rwpb:msg-new VNFFGSff;
+        key "name"; 
+        leaf name {
+          type string;
+        }
+        leaf function-type {
+          type string;
+        }
+        leaf mgmt-address {
+          type inet:ip-address;
+        }
+        leaf mgmt-port {
+          type inet:port-number;
+        }
+        list dp-endpoints {
+          key "name";
+          leaf name {
+           type string;
+          } 
+          leaf address {
+            type inet:ip-address;
+          }
+          leaf port {
+            type inet:port-number;
+          }
+        }
+        list vnfr-list {
+          key "vnfr-name";
+          leaf vnfr-name {
+            type string;
+          }
+        }
+      }
+      leaf classifier-name {
+        type string;
+      }
+    }
+  }
+
+  container vnffg-rendered-paths {
+    rwpb:msg-new VNFFGRenderedPaths;
+    list vnffg-rendered-path {
+      key "name";
+      rwpb:msg-new VNFFGRenderedPath;
+      config false;
+      leaf name {
+        type string;
+      }
+      leaf path-id {
+          description
+              "Unique Identifier for the service path";
+        type uint32;
+      }
+      list rendered-path-hop {
+        key "hop-number";
+        leaf hop-number {
+          type uint8;
+        }
+        leaf service-index {
+            description
+                "Location within the service path";
+          type uint8;
+        }
+        leaf vnfr-name {
+          type string;
+        }
+        container service-function-forwarder {
+          leaf name { 
+            description
+                "Service Function Forwarder name";
+            type string;
+          }
+          leaf ip-address {
+            description
+                "Service Function Forwarder Data Plane IP address";
+            type inet:ip-address;
+          }  
+          leaf port {
+            description
+                "Service Function Forwarder Data Plane port";
+            type inet:port-number;
+          }  
+        }
+      }
+    }
+  }
+
+
+  container vnffg-classifiers {
+    list vnffg-classifier {
+      key "name";
+      rwpb:msg-new VNFFGClassifier;
+
+      leaf name {
+        type string;
+      }
+      leaf rsp-name {
+        type string;
+      }
+      leaf rsp-id {
+        type yang:uuid;
+      }
+      leaf port-id {
+        rwpb:field-inline "true";
+        rwpb:field-string-max 64;
+        type string;
+      }
+      leaf vm-id {
+        rwpb:field-inline "true";
+        rwpb:field-string-max 64;
+        type string;
+      }
+      leaf sff-name {
+        type string;
+      }
+      container vnffg-metadata {
+        leaf ctx1 {
+          type string;
+        }
+        leaf ctx2 {
+          type string;
+        }
+        leaf ctx3 {
+          type string;
+        }
+        leaf ctx4 {
+          type string;
+        }
+      }
+      list match-attributes {
+        description
+            "List of match attributes.";
+        key "name";
+        leaf name {
+          description
+              "Name for the Access list";
+          type string;  
+        }
+
+        leaf ip-proto {
+          description
+              "IP Protocol.";
+          type uint8;
+        }
+
+        leaf source-ip-address {
+          description
+              "Source IP address.";
+          type inet:ip-prefix;
+        }
+
+        leaf destination-ip-address {
+          description
+              "Destination IP address.";
+          type inet:ip-prefix;
+        }
+
+        leaf source-port {
+          description
+              "Source port number.";
+          type inet:port-number;
+        }
+
+        leaf destination-port {
+          description
+              "Destination port number.";
+          type inet:port-number;
+        }
+      } //match-attributes
+    }
+  }
+
+}
+
+/* vim: set ts=2:sw=2: */
index 0036e16..8dc63bb 100644 (file)
@@ -48,8 +48,8 @@ module rw-vns
     prefix "rwcal";
   }
 
-  import rwsdn {
-    prefix "rwsdn";
+  import rwsdnal {
+    prefix "rwsdnal";
   }
 
 
index 81f5b54..a6f5ae7 100644 (file)
@@ -25,9 +25,9 @@
 import pytest
 
 import gi
-gi.require_version('RwsdnYang', '1.0')
+gi.require_version('RwsdnalYang', '1.0')
 
-from gi.repository import RwsdnYang
+from gi.repository import RwsdnalYang
 
 @pytest.mark.setup('sdn')
 @pytest.mark.feature('sdn')
@@ -39,8 +39,8 @@ class TestSdnSetup:
         Asserts:
             SDN name and accout type.
         '''
-        proxy = mgmt_session.proxy(RwsdnYang)
-        sdn_account = RwsdnYang.SDNAccount(
+        proxy = mgmt_session.proxy(RwsdnalYang)
+        sdn_account = RwsdnalYang.SDNAccount(
                 name=sdn_account_name,
                 account_type=sdn_account_type)
         xpath = "/sdn-accounts/sdn-account-list[name='%s']" % sdn_account_name
@@ -57,7 +57,7 @@ class TestSdn:
         Asserts:
             sdn_account.account_type is what was configured
         '''
-        proxy = mgmt_session.proxy(RwsdnYang)
+        proxy = mgmt_session.proxy(RwsdnalYang)
         xpath = "/sdn-accounts/sdn-account-list[name='%s']" % sdn_account_name
         sdn_account = proxy.get_config(xpath)
         assert sdn_account.account_type == sdn_account_type
@@ -68,7 +68,7 @@ class TestSdn:
 class TestSdnTeardown:
     def test_delete_odl_sdn_account(self, mgmt_session, sdn_account_name):
         '''Unconfigure sdn account'''
-        proxy = mgmt_session.proxy(RwsdnYang)
+        proxy = mgmt_session.proxy(RwsdnalYang)
         xpath = "/sdn-accounts/sdn-account-list[name='%s']" % sdn_account_name
         proxy.delete_config(xpath)