Merge from OSM SO master 35/1535/1
authorPhilip Joseph <philip.joseph@riftio.com>
Fri, 7 Apr 2017 09:53:26 +0000 (09:53 +0000)
committerPhilip Joseph <philip.joseph@riftio.com>
Fri, 7 Apr 2017 09:53:26 +0000 (09:53 +0000)
Signed-off-by: Philip Joseph <philip.joseph@riftio.com>
27 files changed:
1  2 
BUILD.sh
common/plugins/yang/CMakeLists.txt
common/plugins/yang/rw-sdn.yang
common/python/CMakeLists.txt
common/python/rift/mano/sdn/config.py
common/python/rift/mano/sdn/operdata.py
models/openmano/python/rift/openmano/rift2openmano.py
models/plugins/yang/CMakeLists.txt
models/plugins/yang/mano-types.yang
models/plugins/yang/nsr.yang
models/plugins/yang/pnfd.yang
models/plugins/yang/vlr.yang
rwcal/plugins/yang/rwcal.yang
rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_config.py
rwlaunchpad/plugins/cli/cli_launchpad_schema_listing.txt
rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/openmano_nsm.py
rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py
rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwvnffgmgr.py
rwlaunchpad/plugins/rwpkgmgr/rift/tasklets/rwpkgmgr/rpc.py
rwlaunchpad/plugins/rwpkgmgr/rift/tasklets/rwpkgmgr/rwpkgmgr.py
rwlaunchpad/plugins/rwvns/rift/tasklets/rwvnstasklet/rwvnstasklet.py
rwlaunchpad/plugins/rwvns/rift/topmgr/rwtopmgr.py
rwlaunchpad/plugins/rwvns/vala/CMakeLists.txt
rwlaunchpad/plugins/rwvns/yang/CMakeLists.txt
rwlaunchpad/plugins/rwvns/yang/rwsdnal.yang
rwlaunchpad/plugins/yang/rw-pkg-mgmt.yang
rwlaunchpad/plugins/yang/rw-vns.yang

diff --cc BUILD.sh
Simple merge
  ##
  # 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(
@@@ -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;
 +      }
      }
    }
  
Simple merge
index 0000000,a9de01b..20b17cc
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,240 +1,221 @@@
 -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
 -
 -
+ #
+ #   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
+ 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,
+                     )
index 0000000,b29f100..094d804
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,128 +1,142 @@@
 -        yield from self._dts.register(
+ #
+ #   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(
 -                xpath=get_xpath(),
 -                handler=rift.tasklets.DTS.RegistrationHandler(
 -                    on_prepare=on_prepare
 -                    ),
 -                flags=rwdts.Flag.PUBLISHER,
 -                )
++        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)
++        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
@@@ -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
Simple merge
@@@ -101,19 -88,86 +101,77 @@@ module ns
      }
    }
  
 -  rpc start-network-service {
 -    description "Start the network service";
 -    input {
+   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;
+     }
+   }
 +  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;
        }
      }
    }
            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 {
              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";
  
      }
    }
  
 +  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;
 +      }
 +    }
 +  }
  }
@@@ -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;
 +          }
          }
        }
      }
@@@ -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";
  
Simple merge
@@@ -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
@@@ -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)",
@@@ -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
  
 -    def __init__(self, log, dts, loop, proxy, publisher):
+ class PackageCopyOperationsRpcHandler(mano_dts.AbstractRpcHandler):
 -        super().__init__(log, dts, loop)
++    def __init__(self, log, dts, loop, project, proxy, publisher):
+         """
+         Args:
+             proxy: Any impl of .proxy.AbstractPackageManagerProxy
+             publisher: CopyStatusPublisher object
+         """
++        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):
@@@ -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:
                  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:
@@@ -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()
  
-         self._log.debug("De-register VLR handler for project {}".
-                         format(self._project.name))
-         if self._regh:
-             self._regh.deregister()
-             self._regh = None
 +    def deregister(self):
++        self.sdn_cfg_handler.deregister()
++        self.sdn_operdata_handler.deregister()
 +
  
  class VnsManager(object):
      """ The Virtual Network Service Manager """
          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
          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()
  
-         self._sdn_opdata_handler.deregister()
-         self._sdn_handler.deregister()
 +    def deregister(self):
 +        self._nwtopdiscovery_handler.deregister()
 +        self._nwtopstatic_handler.deregister()
 +        self._vld_handler.deregister()
 +        self._vlr_handler.deregister()
++        self._sdn_handlers.deregister()
 +
      def create_vlr(self, msg):
          """ Create VLR """
          if msg.id in self._vlrs:
@@@ -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._acctmgr = acctmgr
 +        self._project = project
+         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._acctmgr = acctmgr
 +        self._project = project
+         self._acctstore = acctstore
  
          self._regh = None
          self.pending = {}
@@@ -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(
index 0000000,b24952b..5cd1563
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,462 +1,477 @@@
 -  uses connection-status;
+ /*
+  * 
+  *   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;
+       }
+     }
+   }
 -  container sdn-accounts {
 -    list sdn-account-list {
 -      rwpb:msg-new SDNAccount;
 -      key "name";
++  // 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";
+         }
+       }
+     }
+   }
 -      leaf name {
 -        type string;
 -      }
++  augment "/rw-project:project" {
++    container sdn-accounts {
++      list sdn-account-list {
++        rwpb:msg-new SDNAccount;
++        key "name";
 -      uses sdn-provider-auth;
 -      uses connection-status;
++        leaf name {
++          type string;
++        }
 -  container vnffgs {
 -    list vnffg-chain {
 -      key "name";
 -      rwpb:msg-new VNFFGChain;
 -
 -      leaf name {
 -        type string;
 -      }
++        uses sdn-provider-auth;
++        uses connection-status;
++      }
+     }
+   }
 -      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 {
++  augment "/rw-project:project" {
++    container vnffgs {
++      list vnffg-chain {
++        key "name";
++        rwpb:msg-new VNFFGChain;
 -        list vnfr-ids {
 -          key "vnfr-id";
 -          leaf vnfr-id {
 -            type yang:uuid;
++        leaf name {
+           type string;
+         }
 -          leaf vnfr-name {
++
++        list vnf-chain-path {
++          key "order";
++          leaf order {
++            type uint32;
++            description " Order of the VNF in VNFFG chain";
+           }
 -          leaf mgmt-address {
 -            type inet:ip-address;
++          leaf service-function-type {
+             type string;
+           }
 -          leaf mgmt-port {
 -              type inet:port-number;
++          leaf nsh-aware {
++            type boolean;
+           }
 -          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 transport-type {
++            type string;
+           }
 -            leaf name {
++          list vnfr-ids {
++            key "vnfr-id";
++            leaf vnfr-id {
++              type yang:uuid;
+             }
 -            leaf address {
++            leaf vnfr-name {
+               type string;
+             }
 -            leaf port {
++            leaf mgmt-address {
+               type inet:ip-address;
+             }
 -          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;
++            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 dp-endpoints {
+         }
 -           type string;
 -          } 
 -          leaf address {
++        list sff {
++          rwpb:msg-new VNFFGSff;
+           key "name";
+           leaf name {
 -          leaf port {
++            type string;
++          }
++          leaf function-type {
++            type string;
++          }
++          leaf mgmt-address {
+             type inet:ip-address;
+           }
 -        }
 -        list vnfr-list {
 -          key "vnfr-name";
 -          leaf vnfr-name {
 -            type string;
++          leaf mgmt-port {
+             type inet:port-number;
+           }
 -      }
 -      leaf classifier-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;
++            }
+           }
+         }
 -  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 {
++        leaf classifier-name {
++          type string;
++        }
+       }
+     }
+   }
 -        container service-function-forwarder {
 -          leaf 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;
+         }
 -                "Service Function Forwarder 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
 -          leaf ip-address {
 -            description
++              "Location within the service path";
++            type uint8;
++          }
++          leaf vnfr-name {
+             type string;
+           }
 -            type inet:ip-address;
 -          }  
 -          leaf port {
 -            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:port-number;
 -          }  
++              type inet:ip-address;
++            }
++            leaf port {
++              description
+                 "Service Function Forwarder Data Plane port";
 -  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 inet:port-number;
++            }
++          }
+         }
+       }
+     }
+   }
++  augment "/rw-project:project" {
++    container vnffg-classifiers {
++      list vnffg-classifier {
++        key "name";
++        rwpb:msg-new VNFFGClassifier;
 -        leaf ctx2 {
++        leaf name {
+           type string;
+         }
 -        leaf ctx3 {
++        leaf rsp-name {
+           type string;
+         }
 -        leaf ctx4 {
++        leaf rsp-id {
++          type yang:uuid;
++        }
++        leaf port-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 vm-id {
++          rwpb:field-inline "true";
++          rwpb:field-string-max 64;
+           type string;
+         }
 -          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";
 -        leaf ip-proto {
 -          description
++            type string;
++          }
 -          type uint8;
 -        }
++          leaf ip-proto {
++            description
+               "IP Protocol.";
 -        leaf source-ip-address {
 -          description
++            type uint8;
++          }
 -          type inet:ip-prefix;
 -        }
++          leaf source-ip-address {
++            description
+               "Source IP address.";
 -        leaf destination-ip-address {
 -          description
++            type inet:ip-prefix;
++          }
 -          type inet:ip-prefix;
 -        }
++          leaf destination-ip-address {
++            description
+               "Destination IP address.";
 -        leaf source-port {
 -          description
++            type inet:ip-prefix;
++          }
 -          type inet:port-number;
 -        }
++          leaf source-port {
++            description
+               "Source port number.";
 -        leaf destination-port {
 -          description
++            type inet:port-number;
++          }
 -          type inet:port-number;
 -        }
 -      } //match-attributes
++          leaf destination-port {
++            description
+               "Destination port number.";
++            type inet:port-number;
++          }
++        } //match-attributes
++      }
+     }
+   }
+ }
+ /* vim: set ts=2:sw=2: */
@@@ -196,30 -182,54 +196,56 @@@ module rw-pkg-mgm
      }
    }
  
 -  container download-jobs {
 -    rwpb:msg-new DownloadJobs;
 -    description "Download jobs";
 -    config false;
+   grouping copy-task-status {
+     leaf status {
+       description "The status of the copy task";
+       type task-status;
+       default QUEUED;
+     }
+   }
 +  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 {
      }
    }
  
+   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";
  
Simple merge