From: Philip Joseph Date: Fri, 7 Apr 2017 09:53:26 +0000 (+0000) Subject: Merge from OSM SO master X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=a3bb91f092d378448cb870eccd45d43865de143c;p=osm%2FSO.git Merge from OSM SO master Signed-off-by: Philip Joseph --- a3bb91f092d378448cb870eccd45d43865de143c diff --cc common/plugins/yang/CMakeLists.txt index b17e218d,ed7d7b37..840997ae --- a/common/plugins/yang/CMakeLists.txt +++ b/common/plugins/yang/CMakeLists.txt @@@ -20,24 -20,26 +20,33 @@@ ## # 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 ++ ASSOCIATED_FILES ++ rw-sdn.role.xml + ) + 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 + rwprojectmano_yang_gen + mano-types_yang_gen DEPENDS rwcal_yang - rwsdn_yang - rwprojectmano_yang - mano-types_yang + rwsdnal_yang + ASSOCIATED_FILES + rw-cloud.role.xml - rw-sdn.role.xml ) rift_add_yang_target( diff --cc common/plugins/yang/rw-sdn.yang index b4e0d9e7,04414527..97b0441e --- a/common/plugins/yang/rw-sdn.yang +++ b/common/plugins/yang/rw-sdn.yang @@@ -28,40 -28,26 +28,41 @@@ module rw-sd prefix "rwpb"; } - import mano-types { - prefix "manotypes"; - } - + import rw-project { + prefix "rw-project"; + } + - import rwsdn { - prefix "rwsdn"; + import rwsdnal { + prefix "rwsdnal"; + } + ++ import mano-types { ++ prefix "manotypes"; + } + + revision 2017-02-08 { + description + "Update model to support projects."; + } + revision 2015-09-14 { description "Initial revision."; } - augment "/rw-project:project" { - container sdn { ++augment "/rw-project:project" { + container sdn { - rwpb:msg-new SDNAccountConfig; - list account { - rwpb:msg-new SDNAccount; - key "name"; - leaf name { - type string; - } ++ rwpb:msg-new SDNAccountConfig; + list account { - rwpb:msg-new SDNAccountConfig; ++ rwpb:msg-new SDNAccount; + key "name"; + leaf name { - type string; ++ type string; + } - uses rwsdn:sdn-provider-auth; - uses rwsdn:connection-status; - uses rwsdnal:sdn-provider-auth; - uses rwsdnal:connection-status; ++ uses rwsdnal:sdn-provider-auth; ++ uses rwsdnal:connection-status; + } } } diff --cc common/python/rift/mano/sdn/config.py index 00000000,a9de01b5..20b17cc4 mode 000000,100644..100644 --- a/common/python/rift/mano/sdn/config.py +++ b/common/python/rift/mano/sdn/config.py @@@ -1,0 -1,240 +1,221 @@@ + + # + # 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 rift.mano.utils.project import get_add_delete_update_cfgs ++ + 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 deregister(self): ++ if self._reg: ++ self._reg.deregister() ++ self._reg = None ++ + 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 --cc common/python/rift/mano/sdn/operdata.py index 00000000,b29f100c..094d8045 mode 000000,100644..100644 --- a/common/python/rift/mano/sdn/operdata.py +++ b/common/python/rift/mano/sdn/operdata.py @@@ -1,0 -1,128 +1,142 @@@ + + # + # 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 = {} ++ self._oper = None ++ self._rpc = None + + 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( ++ self._oper = 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 self._project and not self._project.rpc_check(msg, xact_info=xact_info): ++ return ++ + 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, - ) ++ self._rpc = 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() ++ ++ def deregister(self): ++ if self._oper: ++ self._oper.deregister() ++ self._oper = None ++ ++ if self._rpc: ++ self._rpc.deregister() ++ self._rpc = None diff --cc models/plugins/yang/CMakeLists.txt index f22613f9,2f6e9646..cc2c32e4 --- a/models/plugins/yang/CMakeLists.txt +++ b/models/plugins/yang/CMakeLists.txt @@@ -57,18 -51,9 +57,19 @@@ rift_add_yang_target rwcloud_yang_gen rwconfig_agent_yang_gen mano-types_yang_gen + rwprojectmano_yang_gen DEPENDS rwcloud_yang ++ rwsdn_yang rwconfig_agent_yang + rwprojectmano_yang + ASSOCIATED_FILES + project-vnfd.role.xml + project-nsd.role.xml + vnfr.role.xml + rw-vnfr.role.xml + vlr.role.xml + nsr.role.xml ) #rift_gen_yang_tree(mano-pyang-trees diff --cc models/plugins/yang/nsr.yang index 419b05b5,b081f6a9..50bbc0d8 --- a/models/plugins/yang/nsr.yang +++ b/models/plugins/yang/nsr.yang @@@ -101,19 -88,86 +101,77 @@@ module ns } } + grouping cloud-config { + description "List of cloud config parameters"; + + list ssh-authorized-key { + key "key-pair-ref"; + + description "List of authorized ssh keys as part of cloud-config"; + + leaf key-pair-ref { + description "A reference to the key pair entry in the global key pair table"; + type leafref { + path "/nsr:key-pair/nsr:name"; + } + } + } + list user { + key "name"; + + description "List of users to be added through cloud-config"; + leaf name { + description "Name of the user "; + type string; + } + leaf user-info { + description "The user name's real name"; + type string; + } + list ssh-authorized-key { + key "key-pair-ref"; + + description "Used to configure the list of public keys to be injected as part + of ns instantiation"; + + leaf key-pair-ref { + description "A reference to the key pair entry in the global key pair table"; + type leafref { + path "/nsr:key-pair/nsr:name"; + } + } + } + } + } + + list key-pair { + key "name"; + description "Used to configure the list of public keys to be injected as part + of ns instantiation"; + leaf name { + description "Name of this key pair"; + type string; + } + + leaf key { + description "Key associated with this key pair"; + type string; + } + } + - rpc start-network-service { - description "Start the network service"; - input { + augment "/rw-project:project" { + list key-pair { + key "name"; + description "Used to configure the list of public keys to be injected as part + of ns instantiation"; leaf name { - mandatory true; - description "Name of the Network Service"; + description "Name of this key pair"; type string; } - leaf nsd-ref { - description "Reference to NSR ID ref"; - mandatory true; - type leafref { - path "/nsd:nsd-catalog/nsd:nsd/nsd:id"; - } - } - uses ns-instance-config-params; - } - output { - leaf nsr-id { - description "Automatically generated parameter"; - type yang:uuid; + leaf key { + description "Key associated with this key pair"; + type string; } } } @@@ -237,63 -274,23 +295,24 @@@ NOTE: An issue with confd is preventing the use of xpath. Seems to be an issue with leafref to leafref, whose target is in a different module. - Once that is resovled this will switched to use + Once that is resolved this will switched to use leafref"; - type yang:uuid; - } + type yang:uuid; + } - leaf placement-group-ref { - description + leaf placement-group-ref { + description "A reference to VNFD placement group"; - type leafref { - path "/vnfd:vnfd-catalog/vnfd:vnfd[vnfd:id = current()/" + - "../nsr:vnfd-id-ref]/vnfd:placement-groups/vnfd:name"; + type leafref { + path "../../../../project-vnfd:vnfd-catalog/project-vnfd:vnfd[project-vnfd:id = " + + "current()/../vnfd-id-ref]/project-vnfd:placement-groups/project-vnfd:name"; + } } + + uses manotypes:placement-group-input; } - list ssh-authorized-key { - key "key-pair-ref"; - - description "List of authorized ssh keys as part of cloud-config"; - - leaf key-pair-ref { - description "A reference to the key pair entry in the global key pair table"; - type leafref { - path "../../../../key-pair/name"; - } - } - } - list user { - key "name"; - - description "List of users to be added through cloud-config"; - leaf name { - description "Name of the user "; - type string; - } - - leaf user-info { - description "The user name's real name"; - type string; - } - - list ssh-authorized-key { - key "key-pair-ref"; - - description "Used to configure the list of public keys to be injected as part - of ns instantiation"; - - leaf key-pair-ref { - description "A reference to the key pair entry in the global key pair table"; - type leafref { - path "../../../../../key-pair/name"; - } - } - } - } - uses manotypes:placement-group-input; - } - uses cloud-config; ++ uses cloud-config; } grouping vnffgr { @@@ -842,158 -826,156 +861,158 @@@ configuring: At least one of the VNFs in this instance is in configuring state configured: All the VNFs in this NS instance are configured or config-not-needed state "; - type config-states; - } - - list service-primitive { - description - "Network service level service primitives."; + type config-states; + } - key "name"; + list service-primitive { + description + "Network service level service primitives."; - leaf name { - description - "Name of the service primitive."; - type string; - } + key "name"; - list parameter { - description - "List of parameters for the service primitive."; + leaf name { + description + "Name of the service primitive."; + type string; + } - key "name"; - uses manotypes:primitive-parameter; - } + list parameter { + description + "List of parameters for the service primitive."; - uses manotypes:ui-primitive-group; + key "name"; + uses manotypes:primitive-parameter; + } - list vnf-primitive-group { - description - "List of service primitives grouped by VNF."; + uses manotypes:ui-primitive-group; - key "member-vnf-index-ref"; - leaf member-vnf-index-ref { + list vnf-primitive-group { description - "List of service primitives grouped by VNF."; + "Reference to member-vnf within constituent-vnfds"; - type string; - } - leaf vnfd-id-ref { - description - "A reference to a vnfd. This is a - leafref to path: - ../../../../nsd:constituent-vnfd - + [nsd:id = current()/../nsd:id-ref] - + /nsd:vnfd-id-ref - NOTE: An issue with confd is preventing the - use of xpath. Seems to be an issue with leafref - to leafref, whose target is in a different module. - Once that is resolved this will switched to use - leafref"; - - type string; - } - - leaf vnfd-name { - description - "Name of the VNFD"; - type string; - } + key "member-vnf-index-ref"; + leaf member-vnf-index-ref { + description + "Reference to member-vnf within constituent-vnfds"; + type string; + } - list primitive { - key "index"; + leaf vnfd-id-ref { + description + "A reference to a vnfd. This is a + leafref to path: + ../../../../nsd:constituent-vnfd + + [nsd:id = current()/../nsd:id-ref] + + /nsd:vnfd-id-ref + NOTE: An issue with confd is preventing the + use of xpath. Seems to be an issue with leafref + to leafref, whose target is in a different module. + Once that is resovled this will switched to use + leafref"; - leaf index { - description "Index of this primitive"; - type uint32; - } + type string; + } - leaf name { - description "Name of the primitive in the VNF primitive "; + leaf vnfd-name { + description + "Name of the VNFD"; type string; - } - } - } + } - leaf user-defined-script { - description - "A user defined script."; - type string; - } - } + list primitive { + key "index"; - list initial-config-primitive { - rwpb:msg-new NsrInitialConfigPrimitive; - description - "Initial set of configuration primitives for NSD."; - key "seq"; - leaf seq { - description - "Sequence number for the configuration primitive."; - type uint64; - } + leaf index { + description "Index of this primitive"; + type uint32; + } - leaf name { - description - "Name of the configuration primitive."; - type string; - mandatory "true"; + leaf name { + description "Name of the primitive in the VNF primitive "; + type string; + } + } + } + + leaf user-defined-script { + description - "A user defined script."; ++ "A user defined script."; + type string; + } } - leaf user-defined-script { + list initial-config-primitive { + rwpb:msg-new NsrInitialConfigPrimitive; description - "A user defined script."; - type string; - } + "Initial set of configuration primitives for NSD."; + key "seq"; + leaf seq { + description + "Sequence number for the configuration primitive."; + type uint64; + } - list parameter { - key "name"; leaf name { + description + "Name of the configuration primitive."; type string; + mandatory "true"; } - leaf value { + leaf user-defined-script { + description + "A user defined script."; type string; } + + list parameter { + key "name"; + leaf name { + type string; + } + + leaf value { + type string; + } + } } - } - list monitoring-param { - description - "List of NS level params."; - key "id"; + list monitoring-param { + description + "List of NS level params."; + key "id"; - uses manotypes:monitoring-param-value; - uses manotypes:monitoring-param-ui-data; - uses manotypes:monitoring-param-aggregation; + uses manotypes:monitoring-param-value; + uses manotypes:monitoring-param-ui-data; + uses manotypes:monitoring-param-aggregation; - leaf id { - type string; - } + leaf id { + type string; + } - leaf name { - type string; - } + leaf name { + type string; + } - leaf nsd-mon-param-ref { - description "Reference to the NSD monitoring param descriptor + leaf nsd-mon-param-ref { + description "Reference to the NSD monitoring param descriptor that produced this result"; - type leafref { - path "/nsd:nsd-catalog/nsd:nsd[nsd:id = current()/" + - "../../nsr:nsd-ref]/nsd:monitoring-param/nsd:id"; + // TODO: Fix leafref + type leafref { + path "../../../../project-nsd:nsd-catalog/project-nsd:nsd" + + "[project-nsd:id = current()/../../nsd-ref]" + + "/project-nsd:monitoring-param/project-nsd:id"; + } } - } - list vnfr-mon-param-ref { - description "A list of VNFR monitoring params associated with this monp"; - key "vnfr-id-ref vnfr-mon-param-ref"; + list vnfr-mon-param-ref { + description "A list of VNFR monitoring params associated with this monp"; + key "vnfr-id-ref vnfr-mon-param-ref"; - leaf vnfr-id-ref { - description - "A reference to a vnfr. This is a + leaf vnfr-id-ref { + description + "A reference to a vnfr. This is a leafref to path: /vnfr:vnfr-catalog/vnfr:vnfr/vnfr:id"; @@@ -1471,103 -1467,4 +1490,102 @@@ } } + rpc start-network-service { + description "Start the network service"; + input { + leaf name { + mandatory true; + description "Name of the Network Service"; + type string; + } + + uses rpc-common; + + uses ns-instance-config-params-common; + + list vnfd-placement-group-maps { + description + "Mapping from mano-placement groups construct from VNFD to cloud + platform placement group construct"; + + key "placement-group-ref vnfd-id-ref"; + + leaf vnfd-id-ref { + description + "A reference to a vnfd. This is a + leafref to path: + ../../../../project-nsd:constituent-vnfd + + [id = current()/../project-nsd:id-ref] + + /project-nsd:vnfd-id-ref + NOTE: An issue with confd is preventing the + use of xpath. Seems to be an issue with leafref + to leafref, whose target is in a different module. + Once that is resovled this will switched to use + leafref"; + type yang:uuid; + } + + leaf placement-group-ref { + description + "A reference to VNFD placement group"; + type leafref { + path "/rw-project:project[rw-project:name=current()/" + + "../../project-name]/project-vnfd:vnfd-catalog/project-vnfd:vnfd[project-vnfd:id = " + + "current()/../vnfd-id-ref]/project-vnfd:placement-groups/project-vnfd:name"; + } + } + + uses manotypes:placement-group-input; + + list ssh-authorized-key { + key "key-pair-ref"; + + description "List of authorized ssh keys as part of cloud-config"; + + leaf key-pair-ref { + description "A reference to the key pair entry in the global key pair table"; + type leafref { + path "/rw-project:project[rw-project:name=current()/../../../" + + "project-name]/key-pair/name"; + } + } + } + + list user { + key "name"; + + description "List of users to be added through cloud-config"; + leaf name { + description "Name of the user "; + type string; + } + leaf user-info { + description "The user name's real name"; + type string; + } + list ssh-authorized-key { + key "key-pair-ref"; + + description "Used to configure the list of public keys to be injected as part + of ns instantiation"; + + leaf key-pair-ref { + description "A reference to the key pair entry in the global key pair table"; + type leafref { + path "/rw-project:project[rw-project:name=current()/" + + "../../../../project-name]/key-pair/name"; + } + } + } + } + } + } + + output { + leaf nsr-id { + description "Automatically generated parameter"; + type yang:uuid; + } + } + } - } diff --cc models/plugins/yang/pnfd.yang index f48f75d4,2f9bcdf2..fffa8abb --- a/models/plugins/yang/pnfd.yang +++ b/models/plugins/yang/pnfd.yang @@@ -56,58 -47,56 +56,58 @@@ module pnf "Derived from earlier versions of base YANG files"; } - container pnfd-catalog { + augment "/rw-project:project" { + container pnfd-catalog { - list pnfd { - key "id"; + list pnfd { + key "id"; - leaf id { - description "Identifier for the PNFD."; - type yang:uuid; - } + leaf id { + description "Identifier for the PNFD."; + type yang:uuid; + } - leaf name { - description "PNFD name."; - type string; - } + leaf name { + description "PNFD name."; + type string; + } - leaf short-name { - description "Short name to appear as label in the UI"; - type string; - } + leaf short-name { - description "PNFD short name."; ++ description "Short name to appear as label in the UI"; + type string; + } - leaf vendor { - description "Vendor of the PNFD."; - type string; - } + leaf vendor { + description "Vendor of the PNFD."; + type string; + } - leaf description { - description "Description of the PNFD."; - type string; - } + leaf description { + description "Description of the PNFD."; + type string; + } - leaf version { - description "Version of the PNFD"; - type string; - } + leaf version { + description "Version of the PNFD"; + type string; + } - list connection-point { - description + list connection-point { + description "List for external connection points. Each PNF has one or more external connection points."; - key "id"; - leaf id { - description + key "id"; + leaf id { + description "Identifier for the external connection points"; - type uint64; - } + type uint64; + } - leaf cp-type { - description + leaf cp-type { + description "Type of the connection point."; - type manotypes:connection-point-type; + type manotypes:connection-point-type; + } } } } diff --cc models/plugins/yang/vlr.yang index ca986716,e30aa5b3..394f2ecd --- a/models/plugins/yang/vlr.yang +++ b/models/plugins/yang/vlr.yang @@@ -60,83 -51,81 +60,83 @@@ module vl "Derived from earlier versions of base YANG files"; } - container vlr-catalog { - config false; + augment "/rw-project:project" { + container vlr-catalog { + config false; - list vlr { - key "id"; - unique "name"; + list vlr { + key "id"; + unique "name"; - leaf id { - description "Identifier for the VLR."; - type yang:uuid; - } + leaf id { + description "Identifier for the VLR."; + type yang:uuid; + } - leaf name { - description "VLR name."; - type string; - } + leaf name { + description "VLR name."; + type string; + } - leaf nsr-id-ref { - description + leaf nsr-id-ref { + description "NS instance identifier. - This is a leafref /nsr:ns-instance-config/nsr:nsr/nsr:id"; - type yang:uuid; - } + This is a leafref /rw-project:project/nsr:ns-instance-config/nsr:nsr/nsr:id"; + type yang:uuid; + } - leaf vld-ref { - description - "Reference to VLD - /nsr:ns-instance-config/nsr:nsr[nsr:id=../nsr-id-ref]/nsd/vld:vld/vld:id"; - type string; - } + leaf vld-ref { + description + "Reference to VLD + /rw-project:project/nsr:ns-instance-config/nsr:nsr[nsr:id=../nsr-id-ref] + /nsd/vld:vld/vld:id"; + type string; + } - leaf res-id { - description "Identifier for resmgr id mapping"; - type yang:uuid; - } + leaf res-id { + description "Identifier for resmgr id mapping"; + type yang:uuid; + } - leaf short-name { - description "Short name to appear as label in the UI"; - type string; - } + leaf short-name { - description "Short name for VLR for UI"; ++ description "Short name to appear as label in the UI"; + type string; + } - leaf vendor { - description "Provider of the VLR."; - type string; - } + leaf vendor { + description "Provider of the VLR."; + type string; + } - leaf description { - description "Description of the VLR."; - type string; - } + leaf description { + description "Description of the VLR."; + type string; + } - leaf version { - description "Version of the VLR"; - type string; - } + leaf version { + description "Version of the VLR"; + type string; + } - leaf type { - type manotypes:virtual-link-type; - } + leaf type { + type manotypes:virtual-link-type; + } - leaf root-bandwidth { - description + leaf root-bandwidth { + description "For ELAN this is the aggregate bandwidth."; - type uint64; - } + type uint64; + } - leaf leaf-bandwidth { - description + leaf leaf-bandwidth { + description "For ELAN this is the bandwidth of branches."; - type uint64; - } + type uint64; + } - leaf create-time { - description - "Creation timestamp of this Virtual Link. + leaf create-time { + description + "Creation timestamp of this Virtual Link. The timestamp is expressed as seconds since unix epoch - 1970-01-01T00:00:00Z"; diff --cc rwlaunchpad/plugins/cli/cli_launchpad_schema_listing.txt index 6bebc9d8,f11616ca..fefbd3ed --- a/rwlaunchpad/plugins/cli/cli_launchpad_schema_listing.txt +++ b/rwlaunchpad/plugins/cli/cli_launchpad_schema_listing.txt @@@ -38,13 -36,9 +38,13 @@@ rw-nsd-bas rw-nsm rw-nsr rw-pb-ext +rw-project +rw-project-mano +rw-project-nsd +rw-project-vnfd rw-resource-mgr rw-restportforward - rwsdn + rwsdnal rw-sdn rwshell-mgmt rw-sorch diff --cc rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py index 4aed5274,69fac685..ea17e601 --- a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py +++ b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py @@@ -2038,10 -2008,10 +2038,10 @@@ class NetworkServiceRecord(object) for group in self.nsd_msg.placement_groups: for member_vnfd in group.member_vnfd: if (member_vnfd.vnfd_id_ref == vnfd_msg.id) and \ - (member_vnfd.member_vnf_index_ref == const_vnfd.member_vnf_index): + (member_vnfd.member_vnf_index_ref == str(const_vnfd.member_vnf_index)): group_info = self.resolve_placement_group_cloud_construct(group) if group_info is None: - self._log.error("Could not resolve cloud-construct for placement group: %s", group.name) + self._log.info("Could not resolve cloud-construct for placement group: %s", group.name) ### raise PlacementGroupError("Could not resolve cloud-construct for placement group: {}".format(group.name)) else: self._log.info("Successfully resolved cloud construct for placement group: %s for VNF: %s (Member Index: %s)", diff --cc rwlaunchpad/plugins/rwpkgmgr/rift/tasklets/rwpkgmgr/rpc.py index c207b437,a71f1085..d3606400 --- a/rwlaunchpad/plugins/rwpkgmgr/rift/tasklets/rwpkgmgr/rpc.py +++ b/rwlaunchpad/plugins/rwpkgmgr/rift/tasklets/rwpkgmgr/rpc.py @@@ -67,12 -68,12 +68,12 @@@ class EndpointDiscoveryRpcHandler(mano_ class SchemaRpcHandler(mano_dts.AbstractRpcHandler): """RPC handler to generate the schema for the packages. """ -- def __init__(self, log, dts, loop, proxy): ++ def __init__(self, log, dts, loop, project, proxy): """ Args: proxy: Any impl of .proxy.AbstractPackageManagerProxy """ -- super().__init__(log, dts, loop) ++ super().__init__(log, dts, loop, project) self.proxy = proxy @property @@@ -158,6 -145,33 +159,33 @@@ class PackageOperationsRpcHandler(mano_ return rpc_op + class PackageCopyOperationsRpcHandler(mano_dts.AbstractRpcHandler): - def __init__(self, log, dts, loop, proxy, publisher): ++ def __init__(self, log, dts, loop, project, proxy, publisher): + """ + Args: + proxy: Any impl of .proxy.AbstractPackageManagerProxy + publisher: CopyStatusPublisher object + """ - super().__init__(log, dts, loop) ++ super().__init__(log, dts, loop, project) + self.proxy = proxy + self.publisher = publisher + + @property + def xpath(self): + return "/rw-pkg-mgmt:package-copy" + + @asyncio.coroutine + def callback(self, ks_path, msg): + import uuid + copier = pkg_downloader.PackageFileCopier.from_rpc_input(msg, proxy=self.proxy, log=self.log) + + transaction_id, dest_package_id = yield from self.publisher.register_copier(copier) + rpc_op = RPC_PACKAGE_COPY_ENDPOINT.from_dict({ + "transaction_id":transaction_id, + "package_id":dest_package_id, + "package_type":msg.package_type}) + + return rpc_op class PackageDeleteOperationsRpcHandler(mano_dts.AbstractRpcHandler): def __init__(self, log, dts, loop, proxy): diff --cc rwlaunchpad/plugins/rwpkgmgr/rift/tasklets/rwpkgmgr/rwpkgmgr.py index 0a93ade8,5773b0e5..0fcabe37 --- a/rwlaunchpad/plugins/rwpkgmgr/rift/tasklets/rwpkgmgr/rwpkgmgr.py +++ b/rwlaunchpad/plugins/rwpkgmgr/rift/tasklets/rwpkgmgr/rwpkgmgr.py @@@ -42,31 -39,6 +42,40 @@@ from .proxy import filesyste from . import publisher as pkg_publisher from . import subscriber +class PackageManagerProject(ManoProject): + + def __init__(self, name, tasklet, **kw): + super(PackageManagerProject, self).__init__(tasklet.log, name) + self.update(tasklet) ++ proxy = kw["proxy"] + + args = [self.log, self.dts, self.loop, self] + self.job_handler = pkg_publisher.DownloadStatusPublisher(*args) ++ self.copy_publisher = pkg_publisher.CopyStatusPublisher(*args + [self.tasklet.tasklet_info]) ++ + # create catalog subscribers + self.vnfd_catalog_sub = subscriber.VnfdStatusSubscriber(*args) + self.nsd_catalog_sub = subscriber.NsdStatusSubscriber(*args) - ++ ++ args.append(proxy) ++ self.copy_rpc = rpc.PackageCopyOperationsRpcHandler(*(args + [self.copy_publisher])) + + @asyncio.coroutine + def register (self): + yield from self.vnfd_catalog_sub.register() + yield from self.nsd_catalog_sub.register() ++ yield from self.copy_rpc.register() ++ yield from self.copy_publisher.register() + yield from self.job_handler.register() + + def deregister (self): + yield from self.job_handler.deregister() ++ yield from self.copy_rpc.deregister() ++ yield from self.copy_publisher.deregister() + yield from self.vnfd_catalog_sub.deregister() + yield from self.nsd_catalog_sub.deregister() + + class PackageManagerTasklet(rift.tasklets.Tasklet): def __init__(self, *args, **kwargs): try: @@@ -92,17 -61,31 +102,24 @@@ self.loop, self.on_dts_state_change ) - + - proxy = filesystem.FileSystemProxy(self.loop, self.log) + proxy = filesystem.FileSystemProxy(self.loop, self.log) + args = [self.log, self.dts, self.loop] - args = [self.log, self.dts, self.loop] - args.append(proxy) - self.endpoint_rpc = rpc.EndpointDiscoveryRpcHandler(*args) - self.schema_rpc = rpc.SchemaRpcHandler(*args) - self.delete_rpc = rpc.PackageDeleteOperationsRpcHandler(*args) - # create catalog publishers - self.job_handler = pkg_publisher.DownloadStatusPublisher(*args) - self.copy_publisher = pkg_publisher.CopyStatusPublisher(*args +[self.tasklet_info]) - - # create catalog subscribers - self.vnfd_catalog_sub = subscriber.VnfdStatusSubscriber(*args) - self.nsd_catalog_sub = subscriber.NsdStatusSubscriber(*args) - + args.append(proxy) + self.endpoint_rpc = rpc.EndpointDiscoveryRpcHandler(*args) + self.schema_rpc = rpc.SchemaRpcHandler(*args) + self.delete_rpc = rpc.PackageDeleteOperationsRpcHandler(*args) - self.copy_rpc = rpc.PackageCopyOperationsRpcHandler(*(args + [self.copy_publisher])) + - args.append(self.job_handler) ++ args.append(self) + self.pkg_op = rpc.PackageOperationsRpcHandler(*args) - args.append(self) - self.pkg_op = rpc.PackageOperationsRpcHandler(*args) ++ self.project_handler = ProjectHandler(self, PackageManagerProject, ++ proxy=proxy,) + except Exception as e: - self.log.error("Exception caught rwpkgmgr start: %s", str(e)) ++ self.log.exception("Exception caught rwpkgmgr start: %s", str(e)) + else: + self.log.debug("rwpkgmgr started successfully!") def stop(self): try: diff --cc rwlaunchpad/plugins/rwvns/rift/tasklets/rwvnstasklet/rwvnstasklet.py index 1720e391,6ec2421e..ba3c5a25 --- a/rwlaunchpad/plugins/rwvns/rift/tasklets/rwvnstasklet/rwvnstasklet.py +++ b/rwlaunchpad/plugins/rwvns/rift/tasklets/rwvnstasklet/rwvnstasklet.py @@@ -31,11 -28,7 +28,11 @@@ from gi.repository import ) import rift.tasklets +from rift.mano.utils.project import ( + ManoProject, + ProjectHandler, +) + import rift.mano.sdn from rift.vlmgr import ( VlrDtsHandler, @@@ -70,219 -52,44 +56,49 @@@ 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): ++ def __init__(self, dts, log, log_hdl, acctstore, loop, project): self._log = log + self._log_hdl = log_hdl + self._dts = dts self._loop = loop - self._parent = parent - self._project = self._parent._project - self._regh = None - self._rpch = None - - def _register_show_status(self): - def get_xpath(sdn_name=None): - return self._project.add_project("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) + self._acctstore = acctstore ++ self._project = project + + self._log.debug("Creating SDN account config handler") + self.sdn_cfg_handler = rift.mano.sdn.SDNAccountConfigSubscriber( - self._dts, self._log, self._log_hdl, ++ self._dts, self._log, project, 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._regh = 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 self._project.rpc_check(msg, xact_info=xact_info): - return - - 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) - - self._rpch = yield from self._dts.register( - xpath=get_xpath(), - handler=rift.tasklets.DTS.RegistrationHandler( - on_prepare=on_prepare - ), - flags=rwdts.Flag.PUBLISHER, + + self._log.debug("Creating SDN account opdata handler") + self.sdn_operdata_handler = rift.mano.sdn.SDNAccountDtsOperdataHandler( - self._dts, self._log, self._loop, ++ self._dts, self._log, self._loop, project, ) - - @asyncio.coroutine - def register(self): - yield from self._register_show_status() - yield from self._register_validate_rpc() - - def deregister(self): - self._log.debug("De-register SDN opdata handler for project {}". - format(self._project.name)) - if self._regh: - self._regh.deregister() - self._regh = None - - if self._rpch: - self._rpch.deregister() - self._rpch = None - - - class SDNAccountDtsHandler(object): - XPATH = "C,/rw-sdn:sdn/rw-sdn:account" - - def __init__(self, dts, log, parent): - self._dts = dts - self._log = log - self._parent = parent - self._project = parent._project - - self._sdn_account = {} - self._regh = None - - @property - def _xpath(self): - return self._project.add_project(SDNAccountDtsHandler.XPATH) - - 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) - + + 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, - self._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, - self._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: {}". - format(self._xpath)) - - acg_handler = rift.tasklets.AppConfGroup.Handler( - on_apply=apply_config, - ) - - with self._dts.appconf_group_create(acg_handler) as acg: - self._regh = acg.register( - xpath=self._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() + def deregister(self): - self._log.debug("De-register VLR handler for project {}". - format(self._project.name)) - if self._regh: - self._regh.deregister() - self._regh = None ++ self.sdn_cfg_handler.deregister() ++ self.sdn_operdata_handler.deregister() + class VnsManager(object): """ The Virtual Network Service Manager """ @@@ -291,18 -98,13 +107,16 @@@ self._log = log self._log_hdl = log_hdl self._loop = loop + self._project = project - + 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._project) - self._sdn_handlers = SDNAccountHandlers(dts, log, log_hdl, self._acctstore, loop) ++ self._sdn_handlers = SDNAccountHandlers(dts, log, log_hdl, self._acctstore, loop, project) self._nwtopdata_store = NwtopDataStore(log) - self._nwtopdiscovery_handler = NwtopDiscoveryDtsHandler(dts, log, loop, self._project, - self._acctmgr, self._nwtopdata_store) - self._nwtopstatic_handler = NwtopStaticDtsHandler(dts, log, loop, self._project, - 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._nwtopdiscovery_handler = NwtopDiscoveryDtsHandler(dts, log, loop, project, ++ self._acctstore, self._nwtopdata_store) ++ self._nwtopstatic_handler = NwtopStaticDtsHandler(dts, log, loop, project, ++ self._acctstore, self._nwtopdata_store) self._vlrs = {} @asyncio.coroutine @@@ -343,17 -144,8 +156,15 @@@ 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 deregister(self): + self._nwtopdiscovery_handler.deregister() + self._nwtopstatic_handler.deregister() + self._vld_handler.deregister() + self._vlr_handler.deregister() - self._sdn_opdata_handler.deregister() - self._sdn_handler.deregister() ++ self._sdn_handlers.deregister() + def create_vlr(self, msg): """ Create VLR """ if msg.id in self._vlrs: diff --cc rwlaunchpad/plugins/rwvns/rift/topmgr/rwtopmgr.py index e1c7ea14,af4b75bd..7f6b4dd4 --- a/rwlaunchpad/plugins/rwvns/rift/topmgr/rwtopmgr.py +++ b/rwlaunchpad/plugins/rwvns/rift/topmgr/rwtopmgr.py @@@ -186,12 -40,11 +40,12 @@@ class NwtopDiscoveryDtsHandler(object) """ Handles DTS interactions for the Discovered Topology registration """ DISC_XPATH = "D,/nd:network" - def __init__(self, dts, log, loop, project, acctmgr, nwdatastore): - def __init__(self, dts, log, loop, acctstore, nwdatastore): ++ def __init__(self, dts, log, loop, project, acctstore, nwdatastore): self._dts = dts self._log = log self._loop = loop + self._project = project - self._acctmgr = acctmgr + self._acctstore = acctstore self._nwdatastore = nwdatastore self._regh = None @@@ -277,12 -119,11 +127,12 @@@ class NwtopStaticDtsHandler(object) """ Handles DTS interactions for the Static Topology registration """ STATIC_XPATH = "C,/nd:network" - def __init__(self, dts, log, loop, project, acctmgr, nwdatastore): - def __init__(self, dts, log, loop, acctstore, nwdatastore): ++ def __init__(self, dts, log, loop, project, acctstore, nwdatastore): self._dts = dts self._log = log self._loop = loop + self._project = project - self._acctmgr = acctmgr + self._acctstore = acctstore self._regh = None self.pending = {} diff --cc rwlaunchpad/plugins/rwvns/vala/CMakeLists.txt index 7e7ee2fc,8f87f666..d3aa299c --- a/rwlaunchpad/plugins/rwvns/vala/CMakeLists.txt +++ b/rwlaunchpad/plugins/rwvns/vala/CMakeLists.txt @@@ -33,10 -33,10 +33,10 @@@ 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 + rw_log-1.0 rw_project_yang-1.0 VAPI_DIRS ${RIFT_SUBMODULE_BINARY_ROOT}/models/plugins/yang ${RIFT_SUBMODULE_BINARY_ROOT}/rwcal/plugins/yang @@@ -50,7 -50,7 +50,7 @@@ 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 rwproject_yang - DEPENDS rwcal_yang rwsdnal_yang mano_yang rwlog_gi rwschema_yang ++ DEPENDS rwcal_yang rwsdnal_yang mano_yang rwlog_gi rwschema_yang rwproject_yang ) rift_install_vala_artifacts( diff --cc rwlaunchpad/plugins/rwvns/yang/rwsdnal.yang index 00000000,b24952b7..5cd15630 mode 000000,100644..100644 --- a/rwlaunchpad/plugins/rwvns/yang/rwsdnal.yang +++ b/rwlaunchpad/plugins/rwvns/yang/rwsdnal.yang @@@ -1,0 -1,462 +1,477 @@@ + + /* + * + * 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"; + } + ++ import rw-project { ++ prefix "rw-project"; ++ } ++ ++ revision 2017-02-08 { ++ description ++ "Update model to support projects."; ++ } + + 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; ++ // 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"; ++ augment "/rw-project:project" { ++ container sdn-accounts { ++ list sdn-account-list { ++ rwpb:msg-new SDNAccount; ++ key "name"; + - leaf name { - type string; - } ++ leaf name { ++ type string; ++ } + - uses sdn-provider-auth; - uses connection-status; ++ uses sdn-provider-auth; ++ uses connection-status; ++ } + } + } + - container vnffgs { - list vnffg-chain { - key "name"; - rwpb:msg-new VNFFGChain; - - leaf name { - type string; - } ++ augment "/rw-project:project" { ++ container vnffgs { ++ list vnffg-chain { ++ key "name"; ++ rwpb:msg-new VNFFGChain; + - 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 { ++ leaf name { + type string; + } - list vnfr-ids { - key "vnfr-id"; - leaf vnfr-id { - type yang:uuid; ++ ++ list vnf-chain-path { ++ key "order"; ++ leaf order { ++ type uint32; ++ description " Order of the VNF in VNFFG chain"; + } - leaf vnfr-name { ++ leaf service-function-type { + type string; + } - leaf mgmt-address { - type inet:ip-address; ++ leaf nsh-aware { ++ type boolean; + } - leaf mgmt-port { - type inet:port-number; ++ leaf transport-type { ++ type string; + } - 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; ++ list vnfr-ids { ++ key "vnfr-id"; ++ leaf vnfr-id { ++ type yang:uuid; + } - leaf name { ++ leaf vnfr-name { + type string; + } - leaf address { ++ leaf mgmt-address { + type inet:ip-address; + } - leaf port { ++ 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; ++ } + } - 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 { ++ list sff { ++ rwpb:msg-new VNFFGSff; + key "name"; + leaf name { - type string; - } - leaf address { ++ type string; ++ } ++ leaf function-type { ++ type string; ++ } ++ leaf mgmt-address { + type inet:ip-address; + } - leaf port { ++ leaf mgmt-port { + type inet:port-number; + } - } - list vnfr-list { - key "vnfr-name"; - leaf vnfr-name { - type string; ++ 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; ++ 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 { ++ augment "/rw-project:project" { ++ container vnffg-rendered-paths { ++ rwpb:msg-new VNFFGRenderedPaths; ++ list vnffg-rendered-path { ++ key "name"; ++ rwpb:msg-new VNFFGRenderedPath; ++ config false; ++ leaf name { + type string; + } - container service-function-forwarder { - leaf name { ++ 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 - "Service Function Forwarder name"; ++ "Location within the service path"; ++ type uint8; ++ } ++ leaf vnfr-name { + type string; + } - leaf ip-address { - description ++ 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 ++ type inet:ip-address; ++ } ++ leaf port { ++ description + "Service Function Forwarder Data Plane port"; - type inet:port-number; - } ++ type inet:port-number; ++ } ++ } + } + } + } + } + ++ augment "/rw-project:project" { ++ container vnffg-classifiers { ++ list vnffg-classifier { ++ key "name"; ++ rwpb:msg-new VNFFGClassifier; + - 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 { ++ leaf name { + type string; + } - leaf ctx2 { ++ leaf rsp-name { + type string; + } - leaf ctx3 { ++ leaf rsp-id { ++ type yang:uuid; ++ } ++ leaf port-id { ++ rwpb:field-inline "true"; ++ rwpb:field-string-max 64; + type string; + } - leaf ctx4 { ++ leaf vm-id { ++ rwpb:field-inline "true"; ++ rwpb:field-string-max 64; + type string; + } - } - list match-attributes { - description - "List of match attributes."; - key "name"; - leaf name { ++ 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; - } ++ type string; ++ } + - leaf ip-proto { - description ++ leaf ip-proto { ++ description + "IP Protocol."; - type uint8; - } ++ type uint8; ++ } + - leaf source-ip-address { - description ++ leaf source-ip-address { ++ description + "Source IP address."; - type inet:ip-prefix; - } ++ type inet:ip-prefix; ++ } + - leaf destination-ip-address { - description ++ leaf destination-ip-address { ++ description + "Destination IP address."; - type inet:ip-prefix; - } ++ type inet:ip-prefix; ++ } + - leaf source-port { - description ++ leaf source-port { ++ description + "Source port number."; - type inet:port-number; - } ++ type inet:port-number; ++ } + - leaf destination-port { - description ++ leaf destination-port { ++ description + "Destination port number."; - type inet:port-number; - } - } //match-attributes ++ type inet:port-number; ++ } ++ } //match-attributes ++ } + } + } + + } + + /* vim: set ts=2:sw=2: */ diff --cc rwlaunchpad/plugins/yang/rw-pkg-mgmt.yang index c5689906,5fbd621b..ee3b7d18 --- a/rwlaunchpad/plugins/yang/rw-pkg-mgmt.yang +++ b/rwlaunchpad/plugins/yang/rw-pkg-mgmt.yang @@@ -196,30 -182,54 +196,56 @@@ module rw-pkg-mgm } } + grouping copy-task-status { + leaf status { + description "The status of the copy task"; + type task-status; + default QUEUED; + } + } + - container download-jobs { - rwpb:msg-new DownloadJobs; - description "Download jobs"; - config false; + augment "/rw-project:project" { + container download-jobs { + rwpb:msg-new DownloadJobs; + description "Download jobs"; + config false; - list job { - rwpb:msg-new DownloadJob; - key "download-id"; + list job { + rwpb:msg-new DownloadJob; + key "download-id"; - leaf download-id { - description "Unique UUID"; - type string; - } + leaf download-id { + description "Unique UUID"; + type string; + } - leaf url { - description "URL of the download"; - type string; - } + leaf url { + description "URL of the download"; + type string; + } - uses package-file-identifer; - uses download-task-status; + uses package-file-identifer; + uses download-task-status; + } } - } + - container copy-jobs { - rwpb:msg-new CopyJobs; - description "Copy jobs"; - config false; ++ container copy-jobs { ++ rwpb:msg-new CopyJobs; ++ description "Copy jobs"; ++ config false; + - list job { - rwpb:msg-new CopyJob; - key "transaction-id"; ++ list job { ++ rwpb:msg-new CopyJob; ++ key "transaction-id"; + - leaf transaction-id { - description "Unique UUID"; - type string; - } ++ leaf transaction-id { ++ description "Unique UUID"; ++ type string; ++ } + - uses copy-task-status; ++ uses copy-task-status; ++ } + } } rpc get-package-endpoint { @@@ -238,6 -247,28 +264,30 @@@ } } + rpc package-copy { + description "Copies the package specified in input and returns the copied package id"; + + input { + uses package-identifer; + + leaf package-name { + description "Name of destination package"; + type string; + } ++ ++ uses manotypes:rpc-project-name; + } + + output { + leaf transaction-id { + description "Valid ID to track the status of the task"; + type string; + } + + uses package-identifer; + } + } + rpc get-package-schema { description "Retrieves the schema for the package type";