New Feature : Addtional changes for VNF access point support
Signed-off-by: Philip Joseph <philip.joseph@riftio.com>
diff --git a/examples/ping_pong_ns/CMakeLists.txt b/examples/ping_pong_ns/CMakeLists.txt
index e373c2a..2dd5b28 100644
--- a/examples/ping_pong_ns/CMakeLists.txt
+++ b/examples/ping_pong_ns/CMakeLists.txt
@@ -67,12 +67,17 @@
COMPONENT ${PKG_LONG_NAME}
FILES
rift/mano/examples/ping_pong_nsd.py
+ rift/mano/examples/ping_setup.py
+ rift/mano/examples/ping_rate.py
+ rift/mano/examples/ping_start_stop.py
+ rift/mano/examples/pong_setup.py
+ rift/mano/examples/pong_start_stop.py
rift/mano/examples/start_traffic.py
)
install(
PROGRAMS
- rift/mano/examples/ping_config.py
+ rift/mano/examples/ping_scale.py
stand_up_ping_pong
DESTINATION usr/bin
COMPONENT ${PKG_LONG_NAME}
diff --git a/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py b/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py
index 919c5b7..8265f45 100755
--- a/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py
+++ b/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py
@@ -205,7 +205,7 @@
# Add vnf configuration
vnf_config = vnfd.vnf_configuration
- vnf_config.config_attributes.config_delay = 60
+ # vnf_config.config_attributes.config_delay = 10
# Select "script" configuration
vnf_config.script.script_type = 'bash'
@@ -223,7 +223,7 @@
{"name": "pong_port", "data_type": "INTEGER",
"default_value": "5555"},
],
- "user_defined_script": "ping-setup.py",
+ "user_defined_script": "ping_setup.py",
})
vnf_config.config_primitive.append(prim)
@@ -237,7 +237,7 @@
{"name": "rate", "data_type": "INTEGER",
"default_value": "5"},
],
- "user_defined_script": "ping-set-rate.py",
+ "user_defined_script": "ping_rate.py",
})
vnf_config.config_primitive.append(prim)
@@ -251,7 +251,7 @@
{"name": "start", "data_type": "BOOLEAN",
"default_value": "true"}
],
- "user_defined_script": "ping-start-stop.py",
+ "user_defined_script": "ping_start_stop.py",
})
vnf_config.config_primitive.append(prim)
@@ -302,7 +302,7 @@
{"name": "service_ip", "data_type": "STRING"},
{"name": "service_port", "data_type": "INTEGER"},
],
- "user_defined_script": "ping-setup.py",
+ "user_defined_script": "pong_setup.py",
})
vnf_config.config_primitive.append(prim)
@@ -316,7 +316,7 @@
{"name": "start", "data_type": "BOOLEAN",
"default_value": "true"}
],
- "user_defined_script": "ping-start-stop.py",
+ "user_defined_script": "pong_start_stop.py",
})
vnf_config.config_primitive.append(prim)
@@ -519,16 +519,16 @@
member_vdu.member_vdu_ref = vdu.id
- def write_to_file(self, outdir, output_format):
+ def write_to_file(self, outdir, output_format, use_vca_conf=False):
dirpath = "%s/%s" % (outdir, self.name)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
super(VirtualNetworkFunction, self).write_to_file(['vnfd', 'rw-vnfd'],
dirpath,
output_format)
- self.add_scripts(outdir)
+ self.add_scripts(outdir, use_vca_conf=use_vca_conf)
- def add_scripts(self, outdir):
+ def add_cloud_init(self, outdir):
script_dir = os.path.join(outdir, self.name, 'cloud_init')
try:
os.makedirs(script_dir)
@@ -536,7 +536,7 @@
if not os.path.isdir(script_dir):
raise
- if 'ping' in self.name:
+ if 'ping_' in self.name:
script_file = os.path.join(script_dir, 'ping_cloud_init.cfg')
cfg = PING_USERDATA_FILE
else:
@@ -546,6 +546,35 @@
with open(script_file, "w") as f:
f.write("{}".format(cfg))
+ def add_scripts(self, outdir, use_vca_conf=False):
+ self.add_cloud_init(outdir)
+ if use_vca_conf:
+ self.add_vca_scripts(outdir)
+
+ def add_vca_scripts(self, outdir):
+ dest_path = os.path.join(outdir, self.name, 'scripts')
+ try:
+ os.makedirs(dest_path)
+ except OSError:
+ if not os.path.isdir(dest_path):
+ raise
+
+ if 'pong_' in self.name:
+ scripts = ['pong_setup.py', 'pong_start_stop.py']
+ else:
+ scripts = ['ping_setup.py', 'ping_rate.py', 'ping_start_stop.py']
+
+ for script_name in scripts:
+ src_path = os.path.dirname(os.path.abspath(
+ os.path.realpath(__file__)))
+ script_src = os.path.join(src_path, script_name)
+ if not os.path.exists(script_src):
+ src_path = os.path.join(os.environ['RIFT_ROOT'],
+ 'modules/core/mano/examples/'
+ 'ping_pong_ns/rift/mano/examples')
+ script_src = os.path.join(src_path, script_name)
+
+ shutil.copy2(script_src, dest_path)
class NetworkService(ManoDescriptor):
def __init__(self, name):
@@ -781,7 +810,7 @@
if mano_ut:
nsd.service_primitive.add().from_dict(
{
- "name": "ping config",
+ "name": "ping scale",
"user_defined_script": "{}".format(os.path.join(
os.environ['RIFT_ROOT'],
'modules/core/mano',
@@ -791,8 +820,8 @@
else:
nsd.service_primitive.add().from_dict(
{
- "name": "ping config",
- "user_defined_script": "ping_config.py"
+ "name": "ping scale",
+ "user_defined_script": "ping_scale.py"
})
def ns_initial_config(self, nsd):
@@ -849,7 +878,7 @@
vnfap_map.capability.member_vnf_index = 2
vnfap_map.capability.capability_ref = 'service_port'
vnfap_map.dependency.member_vnf_index = 1
- vnfap_map.dependency.dependency_ref = 'port_port'
+ vnfap_map.dependency.dependency_ref = 'pong_port'
def compose(self, vnfd_list, cpgroup_list, mano_ut,
use_ns_init_conf=True,
@@ -1078,7 +1107,7 @@
def add_config(self):
self.config_action['post_scale_out']= {'ns-config-primitive-name-ref':
- 'ping config'}
+ 'ping scale'}
class PlacementGroup(object):
def __init__(self, name):
@@ -1292,8 +1321,10 @@
)
if write_to_file:
- ping.write_to_file(out_dir, ping_fmt if ping_fmt is not None else fmt)
- pong.write_to_file(out_dir, pong_fmt if ping_fmt is not None else fmt)
+ ping.write_to_file(out_dir, ping_fmt if ping_fmt is not None else fmt,
+ use_vca_conf=use_vca_conf)
+ pong.write_to_file(out_dir, pong_fmt if ping_fmt is not None else fmt,
+ use_vca_conf=use_vca_conf)
nsd_catalog.write_config(out_dir, vnfd_list)
nsd_catalog.write_to_file(out_dir, ping_fmt if nsd_fmt is not None else fmt)
diff --git a/examples/ping_pong_ns/rift/mano/examples/ping_rate.py b/examples/ping_pong_ns/rift/mano/examples/ping_rate.py
new file mode 100755
index 0000000..b3ab07b
--- /dev/null
+++ b/examples/ping_pong_ns/rift/mano/examples/ping_rate.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+
+############################################################################
+# Copyright 2016 RIFT.IO Inc #
+# #
+# Licensed under the Apache License, Version 2.0 (the "License"); #
+# you may not use this file except in compliance with the License. #
+# You may obtain a copy of the License at #
+# #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+# #
+# Unless required by applicable law or agreed to in writing, software #
+# distributed under the License is distributed on an "AS IS" BASIS, #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+############################################################################
+
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+import time
+
+import yaml
+
+
+def ping_rate(yaml_cfg, logger):
+ '''Use curl to configure ping and set the ping rate'''
+
+ # Get the required and optional parameters
+ params = yaml_cfg['parameters']
+ mgmt_ip = params['mgmt_ip']
+ mgmt_port = 18888
+ if 'mgmt_port' in params:
+ mgmt_port = params['mgmt_port']
+ rate = 1
+ if 'rate' in params:
+ rate = params['rate']
+
+ cmd = 'curl -D /dev/stdout -H "Accept: application/vnd.yang.data' \
+ '+xml" -H "Content-Type: application/vnd.yang.data+json" ' \
+ '-X POST -d "{{\\"rate\\":{rate}}}" ' \
+ 'http://{mgmt_ip}:{mgmt_port}/api/v1/ping/rate'. \
+ format(
+ mgmt_ip=mgmt_ip,
+ mgmt_port=mgmt_port,
+ rate=rate)
+
+ logger.debug("Executing cmd: %s", cmd)
+ proc = subprocess.run(cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ logger.debug("Process: {}".format(proc))
+
+ return proc.returncode
+
+
+def main(argv=sys.argv[1:]):
+ try:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("yaml_cfg_file", type=argparse.FileType('r'))
+ parser.add_argument("-q", "--quiet", dest="verbose", action="store_false")
+ args = parser.parse_args()
+
+ run_dir = os.path.join(os.environ['RIFT_INSTALL'], "var/run/rift")
+ if not os.path.exists(run_dir):
+ os.makedirs(run_dir)
+ log_file = "{}/ping_rate-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
+
+ # logging.basicConfig(filename=log_file, level=logging.DEBUG)
+ logger = logging.getLogger('ping-rate')
+ logger.setLevel(logging.DEBUG)
+
+ fh = logging.FileHandler(log_file)
+ fh.setLevel(logging.DEBUG)
+
+ ch = logging.StreamHandler()
+ if args.verbose:
+ ch.setLevel(logging.DEBUG)
+ else:
+ ch.setLevel(logging.INFO)
+
+ # create formatter and add it to the handlers
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ fh.setFormatter(formatter)
+ ch.setFormatter(formatter)
+ logger.addHandler(fh)
+ logger.addHandler(ch)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+ try:
+ logger.debug("Input file: {}".format(args.yaml_cfg_file.name))
+ yaml_str = args.yaml_cfg_file.read()
+ yaml_cfg = yaml.load(yaml_str)
+ logger.debug("Input YAML: {}".format(yaml_cfg))
+
+ rc = ping_rate(yaml_cfg, logger)
+ logger.info("Return code: {}".format(rc))
+ sys.exit(rc)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/ping_pong_ns/rift/mano/examples/ping_config.py b/examples/ping_pong_ns/rift/mano/examples/ping_scale.py
similarity index 100%
rename from examples/ping_pong_ns/rift/mano/examples/ping_config.py
rename to examples/ping_pong_ns/rift/mano/examples/ping_scale.py
diff --git a/examples/ping_pong_ns/rift/mano/examples/ping_setup.py b/examples/ping_pong_ns/rift/mano/examples/ping_setup.py
new file mode 100755
index 0000000..c05e669
--- /dev/null
+++ b/examples/ping_pong_ns/rift/mano/examples/ping_setup.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python3
+
+############################################################################
+# Copyright 2016 RIFT.IO Inc #
+# #
+# Licensed under the Apache License, Version 2.0 (the "License"); #
+# you may not use this file except in compliance with the License. #
+# You may obtain a copy of the License at #
+# #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+# #
+# Unless required by applicable law or agreed to in writing, software #
+# distributed under the License is distributed on an "AS IS" BASIS, #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+############################################################################
+
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+import time
+
+import yaml
+
+
+def ping_setup(yaml_cfg, logger):
+ '''Use curl to configure ping and set the ping rate'''
+
+ # Get the required and optional parameters
+ params = yaml_cfg['parameters']
+ mgmt_ip = params['mgmt_ip']
+ mgmt_port = 18888
+ if 'mgmt_port' in params:
+ mgmt_port = params['mgmt_port']
+ pong_ip = params['pong_ip']
+ pong_port = 5555
+ if 'pong_port' in params:
+ pong_port = params['pong_port']
+ rate = 1
+ if 'rate' in params:
+ rate = params['rate']
+
+ cmd = 'curl -D /dev/stdout -H "Accept: application/vnd.yang.data' \
+ '+xml" -H "Content-Type: application/vnd.yang.data+json" ' \
+ '-X POST -d "{{\\"ip\\":\\"{pong_ip}\\", \\"port\\":{pong_port}}}" ' \
+ 'http://{mgmt_ip}:{mgmt_port}/api/v1/ping/server'. \
+ format(
+ mgmt_ip=mgmt_ip,
+ mgmt_port=mgmt_port,
+ pong_ip=pong_ip,
+ pong_port=pong_port)
+
+ logger.debug("Executing cmd: %s", cmd)
+ count = 0
+ delay = 5
+ max_tries = 12
+ rc = 0
+
+ while True:
+ count += 1
+ proc = subprocess.run(cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ logger.debug("Process: {}".format(proc))
+
+ if proc.returncode == 0:
+ # Check if response is 200 OK
+ resp = proc.stdout.decode()
+ if 'HTTP/1.1 200 OK' in resp:
+ rc = 0
+ break
+ self._log.error("Got error response: {}".format(resp))
+ rc = 1
+ break
+
+ elif proc.returncode == 7:
+ # Connection timeout
+ if count >= max_tries:
+ self._log.error("Connect failed for {}. Failing".format(count))
+ rc = 7
+ break
+ # Try after delay
+ time.sleep(delay)
+
+ return rc
+
+def main(argv=sys.argv[1:]):
+ try:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("yaml_cfg_file", type=argparse.FileType('r'))
+ parser.add_argument("-q", "--quiet", dest="verbose", action="store_false")
+ args = parser.parse_args()
+
+ run_dir = os.path.join(os.environ['RIFT_INSTALL'], "var/run/rift")
+ if not os.path.exists(run_dir):
+ os.makedirs(run_dir)
+ log_file = "{}/ping_setup-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
+
+ # logging.basicConfig(filename=log_file, level=logging.DEBUG)
+ logger = logging.getLogger('ping-setup')
+ logger.setLevel(logging.DEBUG)
+
+ fh = logging.FileHandler(log_file)
+ fh.setLevel(logging.DEBUG)
+
+ ch = logging.StreamHandler()
+ if args.verbose:
+ ch.setLevel(logging.DEBUG)
+ else:
+ ch.setLevel(logging.INFO)
+
+ # create formatter and add it to the handlers
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ fh.setFormatter(formatter)
+ ch.setFormatter(formatter)
+ logger.addHandler(fh)
+ logger.addHandler(ch)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+ try:
+ logger.debug("Input file: {}".format(args.yaml_cfg_file.name))
+ yaml_str = args.yaml_cfg_file.read()
+ yaml_cfg = yaml.load(yaml_str)
+ logger.debug("Input YAML: {}".format(yaml_cfg))
+
+ rc = ping_setup(yaml_cfg, logger)
+ logger.info("Return code: {}".format(rc))
+ sys.exit(rc)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/ping_pong_ns/rift/mano/examples/ping_start_stop.py b/examples/ping_pong_ns/rift/mano/examples/ping_start_stop.py
new file mode 100755
index 0000000..76f653c
--- /dev/null
+++ b/examples/ping_pong_ns/rift/mano/examples/ping_start_stop.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python3
+
+############################################################################
+# Copyright 2016 RIFT.IO Inc #
+# #
+# Licensed under the Apache License, Version 2.0 (the "License"); #
+# you may not use this file except in compliance with the License. #
+# You may obtain a copy of the License at #
+# #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+# #
+# Unless required by applicable law or agreed to in writing, software #
+# distributed under the License is distributed on an "AS IS" BASIS, #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+############################################################################
+
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+import time
+
+import yaml
+
+
+def ping_start_stop(yaml_cfg, logger):
+ '''Use curl to configure ping and set the ping rate'''
+
+ # Get the required and optional parameters
+ params = yaml_cfg['parameters']
+ mgmt_ip = params['mgmt_ip']
+ mgmt_port = 18888
+ if 'mgmt_port' in params:
+ mgmt_port = params['mgmt_port']
+ start = 'true'
+ if 'start' in params:
+ if not params['start']:
+ start = 'false'
+
+ cmd = 'curl -D /dev/stdout -H "Accept: application/vnd.yang.data' \
+ '+xml" -H "Content-Type: application/vnd.yang.data+json" ' \
+ '-X POST -d "{{\\"enable\\":{start}}}" ' \
+ 'http://{mgmt_ip}:{mgmt_port}/api/v1/ping/adminstatus/state'. \
+ format(
+ mgmt_ip=mgmt_ip,
+ mgmt_port=mgmt_port,
+ start=start)
+
+ logger.debug("Executing cmd: %s", cmd)
+ proc = subprocess.run(cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ logger.debug("Process: {}".format(proc))
+
+ rc = proc.returncode
+
+ if rc == 0:
+ # Check if we got 200 OK
+ resp = proc.stdout.decode()
+ if 'HTTP/1.1 200 OK' not in resp:
+ self._log.error("Got error response: {}".format(resp))
+ rc = 1
+
+ return rc
+
+
+def main(argv=sys.argv[1:]):
+ try:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("yaml_cfg_file", type=argparse.FileType('r'))
+ parser.add_argument("-q", "--quiet", dest="verbose", action="store_false")
+ args = parser.parse_args()
+
+ run_dir = os.path.join(os.environ['RIFT_INSTALL'], "var/run/rift")
+ if not os.path.exists(run_dir):
+ os.makedirs(run_dir)
+ log_file = "{}/ping_start_stop-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
+
+ # logging.basicConfig(filename=log_file, level=logging.DEBUG)
+ logger = logging.getLogger('ping-start-stop')
+ logger.setLevel(logging.DEBUG)
+
+ fh = logging.FileHandler(log_file)
+ fh.setLevel(logging.DEBUG)
+
+ ch = logging.StreamHandler()
+ if args.verbose:
+ ch.setLevel(logging.DEBUG)
+ else:
+ ch.setLevel(logging.INFO)
+
+ # create formatter and add it to the handlers
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ fh.setFormatter(formatter)
+ ch.setFormatter(formatter)
+ logger.addHandler(fh)
+ logger.addHandler(ch)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+ try:
+ logger.debug("Input file: {}".format(args.yaml_cfg_file.name))
+ yaml_str = args.yaml_cfg_file.read()
+ yaml_cfg = yaml.load(yaml_str)
+ logger.debug("Input YAML: {}".format(yaml_cfg))
+
+ rc = ping_start_stop(yaml_cfg, logger)
+ logger.info("Return code: {}".format(rc))
+ sys.exit(rc)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/ping_pong_ns/rift/mano/examples/pong_setup.py b/examples/ping_pong_ns/rift/mano/examples/pong_setup.py
new file mode 100755
index 0000000..cd56eca
--- /dev/null
+++ b/examples/ping_pong_ns/rift/mano/examples/pong_setup.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python3
+
+############################################################################
+# Copyright 2016 RIFT.IO Inc #
+# #
+# Licensed under the Apache License, Version 2.0 (the "License"); #
+# you may not use this file except in compliance with the License. #
+# You may obtain a copy of the License at #
+# #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+# #
+# Unless required by applicable law or agreed to in writing, software #
+# distributed under the License is distributed on an "AS IS" BASIS, #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+############################################################################
+
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+import time
+
+import yaml
+
+
+def pong_setup(yaml_cfg, logger):
+ '''Use curl to configure ping and set the ping rate'''
+
+ # Get the required and optional parameters
+ params = yaml_cfg['parameters']
+ mgmt_ip = params['mgmt_ip']
+ mgmt_port = 18889
+ if 'mgmt_port' in params:
+ mgmt_port = params['mgmt_port']
+ service_ip = params['service_ip']
+ service_port = 5555
+ if 'service_port' in params:
+ service_port = params['service_port']
+ rate = 1
+ if 'rate' in params:
+ rate = params['rate']
+
+ config_cmd = 'curl -D /dev/stdout -H "Accept: application/vnd.yang.data' \
+ '+xml" -H "Content-Type: application/vnd.yang.data+json" ' \
+ '-X POST -d "{{\\"ip\\":\\"{service_ip}\\", \\"port\\":{service_port}}}" ' \
+ 'http://{mgmt_ip}:{mgmt_port}/api/v1/pong/server'. \
+ format(
+ mgmt_ip=mgmt_ip,
+ mgmt_port=mgmt_port,
+ service_ip=service_ip,
+ service_port=service_port)
+
+ logger.debug("Executing cmd: %s", config_cmd)
+ count = 0
+ delay = 5
+ max_tries = 12
+ rc = 0
+
+ while True:
+ count += 1
+ proc = subprocess.run(config_cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ logger.debug("Process: {}".format(proc))
+
+ if proc.returncode == 0:
+ # Check if response is 200 OK
+ resp = proc.stdout.decode()
+ if 'HTTP/1.1 200 OK' in resp:
+ rc = 0
+ break
+ self._log.error("Got error response: {}".format(resp))
+ rc = 1
+ break
+
+ elif proc.returncode == 7:
+ # Connection timeout
+ if count >= max_tries:
+ self._log.error("Connect failed for {}. Failing".format(count))
+ rc = 7
+ break
+ # Try after delay
+ time.sleep(delay)
+
+ return rc
+
+
+def main(argv=sys.argv[1:]):
+ try:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("yaml_cfg_file", type=argparse.FileType('r'))
+ parser.add_argument("-q", "--quiet", dest="verbose", action="store_false")
+ args = parser.parse_args()
+
+ run_dir = os.path.join(os.environ['RIFT_INSTALL'], "var/run/rift")
+ if not os.path.exists(run_dir):
+ os.makedirs(run_dir)
+ log_file = "{}/pong_setup-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
+
+ # logging.basicConfig(filename=log_file, level=logging.DEBUG)
+ logger = logging.getLogger('pong-setup')
+ logger.setLevel(logging.DEBUG)
+
+ fh = logging.FileHandler(log_file)
+ fh.setLevel(logging.DEBUG)
+
+ ch = logging.StreamHandler()
+ if args.verbose:
+ ch.setLevel(logging.DEBUG)
+ else:
+ ch.setLevel(logging.INFO)
+
+ # create formatter and add it to the handlers
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ fh.setFormatter(formatter)
+ ch.setFormatter(formatter)
+ logger.addHandler(fh)
+ logger.addHandler(ch)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+ try:
+ logger.debug("Input file: {}".format(args.yaml_cfg_file.name))
+ yaml_str = args.yaml_cfg_file.read()
+ yaml_cfg = yaml.load(yaml_str)
+ logger.debug("Input YAML: {}".format(yaml_cfg))
+
+ rc = pong_setup(yaml_cfg, logger)
+ logger.info("Return code: {}".format(rc))
+ sys.exit(rc)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/ping_pong_ns/rift/mano/examples/pong_start_stop.py b/examples/ping_pong_ns/rift/mano/examples/pong_start_stop.py
new file mode 100755
index 0000000..b5195dd
--- /dev/null
+++ b/examples/ping_pong_ns/rift/mano/examples/pong_start_stop.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python3
+
+############################################################################
+# Copyright 2016 RIFT.IO Inc #
+# #
+# Licensed under the Apache License, Version 2.0 (the "License"); #
+# you may not use this file except in compliance with the License. #
+# You may obtain a copy of the License at #
+# #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+# #
+# Unless required by applicable law or agreed to in writing, software #
+# distributed under the License is distributed on an "AS IS" BASIS, #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+############################################################################
+
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+import time
+
+import yaml
+
+
+def pong_start_stop(yaml_cfg, logger):
+ '''Use curl to configure ping and set the ping rate'''
+
+ # Get the required and optional parameters
+ params = yaml_cfg['parameters']
+ mgmt_ip = params['mgmt_ip']
+ mgmt_port = 18889
+ if 'mgmt_port' in params:
+ mgmt_port = params['mgmt_port']
+ start = 'true'
+ if 'start' in params:
+ if not params['start']:
+ start = 'false'
+
+ cmd = 'curl -D /dev/stdout -H "Accept: application/vnd.yang.data' \
+ '+xml" -H "Content-Type: application/vnd.yang.data+json" ' \
+ '-X POST -d "{{\\"enable\\":{start}}}" ' \
+ 'http://{mgmt_ip}:{mgmt_port}/api/v1/pong/adminstatus/state'. \
+ format(
+ mgmt_ip=mgmt_ip,
+ mgmt_port=mgmt_port,
+ start=start)
+
+ logger.debug("Executing cmd: %s", cmd)
+ proc = subprocess.run(cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ logger.debug("Process: {}".format(proc))
+
+ rc = proc.returncode
+
+ if rc == 0:
+ # Check if we got 200 OK
+ resp = proc.stdout.decode()
+ if 'HTTP/1.1 200 OK' not in resp:
+ self._log.error("Got error response: {}".format(resp))
+ rc = 1
+
+ return rc
+
+
+def main(argv=sys.argv[1:]):
+ try:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("yaml_cfg_file", type=argparse.FileType('r'))
+ parser.add_argument("-q", "--quiet", dest="verbose", action="store_false")
+ args = parser.parse_args()
+
+ run_dir = os.path.join(os.environ['RIFT_INSTALL'], "var/run/rift")
+ if not os.path.exists(run_dir):
+ os.makedirs(run_dir)
+ log_file = "{}/pong_start_stop-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
+
+ # logging.basicConfig(filename=log_file, level=logging.DEBUG)
+ logger = logging.getLogger('pong-start-stop')
+ logger.setLevel(logging.DEBUG)
+
+ fh = logging.FileHandler(log_file)
+ fh.setLevel(logging.DEBUG)
+
+ ch = logging.StreamHandler()
+ if args.verbose:
+ ch.setLevel(logging.DEBUG)
+ else:
+ ch.setLevel(logging.INFO)
+
+ # create formatter and add it to the handlers
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ fh.setFormatter(formatter)
+ ch.setFormatter(formatter)
+ logger.addHandler(fh)
+ logger.addHandler(ch)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+ try:
+ logger.debug("Input file: {}".format(args.yaml_cfg_file.name))
+ yaml_str = args.yaml_cfg_file.read()
+ yaml_cfg = yaml.load(yaml_str)
+ logger.debug("Input YAML: {}".format(yaml_cfg))
+
+ rc = pong_start_stop(yaml_cfg, logger)
+ logger.info("Return code: {}".format(rc))
+ sys.exit(rc)
+
+ except Exception as e:
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/ping_pong_ns/rift/mano/examples/start_traffic.py b/examples/ping_pong_ns/rift/mano/examples/start_traffic.py
index af6f62f..3093792 100755
--- a/examples/ping_pong_ns/rift/mano/examples/start_traffic.py
+++ b/examples/ping_pong_ns/rift/mano/examples/start_traffic.py
@@ -41,7 +41,13 @@
vnf_type=vnf_type)
logger.debug("Executing cmd: %s", curl_cmd)
- subprocess.check_call(curl_cmd, shell=True)
+ proc = subprocess.run(curl_cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ logger.debug("Process: {}".format(proc))
+
+ return proc.returncode
# Enable pong service first
for index, vnfr in yaml_cfg['vnfr'].items():
@@ -51,11 +57,15 @@
if 'pong_vnfd' in vnfr['name']:
vnf_type = 'pong'
port = 18889
- enable_service(vnfr['mgmt_ip_address'], port, vnf_type)
+ rc = enable_service(vnfr['mgmt_ip_address'], port, vnf_type)
+ if rc != 0:
+ logger.error("Enable service for pong failed: {}".
+ format(rc))
+ return rc
break
# Add a delay to provide pong port to come up
- time.sleep(0.1)
+ time.sleep(1)
# Enable ping service next
for index, vnfr in yaml_cfg['vnfr'].items():
@@ -65,9 +75,12 @@
if 'ping_vnfd' in vnfr['name']:
vnf_type = 'ping'
port = 18888
- enable_service(vnfr['mgmt_ip_address'], port, vnf_type)
+ rc = enable_service(vnfr['mgmt_ip_address'], port, vnf_type)
break
+ return rc
+
+
def main(argv=sys.argv[1:]):
try:
parser = argparse.ArgumentParser()
@@ -79,14 +92,14 @@
if not os.path.exists(run_dir):
os.makedirs(run_dir)
log_file = "{}/ping_pong_start_traffic-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
- logging.basicConfig(filename=log_file, level=logging.DEBUG)
- logger = logging.getLogger()
- except Exception as e:
- print("Exception in {}: {}".format(__file__, e))
- sys.exit(1)
+ # logging.basicConfig(filename=log_file, level=logging.DEBUG)
+ logger = logging.getLogger('ping-pong-start-traffic')
+ logger.setLevel(logging.DEBUG)
- try:
+ fh = logging.FileHandler(log_file)
+ fh.setLevel(logging.DEBUG)
+
ch = logging.StreamHandler()
if args.verbose:
ch.setLevel(logging.DEBUG)
@@ -95,24 +108,28 @@
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ fh.setFormatter(formatter)
ch.setFormatter(formatter)
+ logger.addHandler(fh)
logger.addHandler(ch)
except Exception as e:
- logger.exception(e)
- raise e
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
try:
+ logger.debug("Input file: {}".format(args.yaml_cfg_file.name))
yaml_str = args.yaml_cfg_file.read()
- # logger.debug("Input YAML file:\n{}".format(yaml_str))
yaml_cfg = yaml.load(yaml_str)
logger.debug("Input YAML: {}".format(yaml_cfg))
- start_traffic(yaml_cfg, logger)
+ rc = start_traffic(yaml_cfg, logger)
+ logger.info("Return code: {}".format(rc))
+ sys.exit(rc)
except Exception as e:
- logger.exception(e)
- raise e
+ logger.exception("Exception in {}: {}".format(__file__, e))
+ sys.exit(1)
if __name__ == "__main__":
main()
diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py
index 0400a54..1d70b23 100644
--- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py
+++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py
@@ -16,10 +16,11 @@
import asyncio
import concurrent.futures
+import os
import re
+import shlex
import tempfile
import yaml
-import os
from gi.repository import (
RwDts as rwdts,
@@ -94,7 +95,7 @@
def riftca_log(self, name, level, log_str, *args):
getattr(self._log, level)('RiftCA:({}) {}'.format(name, log_str), *args)
-
+
@asyncio.coroutine
def notify_create_vnfr(self, agent_nsr, agent_vnfr):
"""
@@ -140,12 +141,122 @@
pass
@asyncio.coroutine
- def vnf_config_primitive(self, agent_nsr, agent_vnfr, primitive, output):
+ def _vnf_config_primitive(self, nsr_id, vnfr_id, primitive,
+ vnf_config=None):
+ '''
+ Pass vnf_config to avoid querying DTS each time
+ '''
+ self._log.debug("VNF config primitive {} for nsr {}, vnfr {}".
+ format(primitive.name, nsr_id, vnfr_id))
+
+ if vnf_config is None:
+ vnfr = yield from self.get_vnfr(vnfr_id)
+ if vnfr is None:
+ self._log.error("Unable to get VNFR {} through DTS".
+ format(vnfr_id))
+ return 1, "Unable to get VNFR {} through DTS".format(vnfr_id)
+
+ vnf_config = vnfr.vnf_configuration
+ self._log.debug("VNF config= %s", vnf_config.as_dict())
+
+ data = {}
+ script = None
+ found = False
+
+ configs = vnf_config.config_primitive
+ for config in configs:
+ if config.name == primitive.name:
+ found = True
+ self._log.debug("RiftCA: Found the config primitive %s",
+ config.name)
+
+ spt = config.user_defined_script
+ if spt is None:
+ self._log.error("RiftCA: VNFR {}, Did not find "
+ "script defined in config {}".
+ format(vnfr['name'], config.as_dict()))
+ return 1, "Did not find user defined script for " \
+ "config primitive {}".format(primitive.name)
+
+ spt = shlex.quote(spt.strip())
+ if spt[0] == '/':
+ script = spt
+ else:
+ script = os.path.join(self._rift_artif_dir,
+ 'launchpad/libs',
+ nsr_id,
+ 'scripts',
+ spt)
+ self._log.debug("Rift config agent: Checking for script "
+ "in %s", script)
+ if not os.path.exists(script):
+ self._log.debug("Rift config agent: Did not find "
+ "script %s", script)
+ script = os.path.join(self._rift_install_dir,
+ 'usr/bin', spt)
+ if not os.path.exists(script):
+ self._log.debug("Rift config agent: Did not find "
+ "script %s", script)
+ return 1, "Did not find user defined " \
+ "script {}".format(spt)
+
+ params = {}
+ for param in config.parameter:
+ val = None
+ for p in primitive.parameter:
+ if p.name == param.name:
+ val = p.value
+ break
+
+ if val is None:
+ val = param.default_value
+
+ if val:
+ val = self.convert_value(val, param.data_type)
+
+ params.update({param.name: val})
+
+ data['parameters'] = params
+ break
+
+ if not found:
+ msg = "Did not find the primitive {} in VNFR {}". \
+ format(primitive.name, vnfr.name)
+ self._log.error(msg)
+ return 1, msg
+
+ rc, script_err = yield from self.exec_script(script, data)
+ return rc, script_err
+
+ @asyncio.coroutine
+ def vnf_config_primitive(self, nsr_id, vnfr_id, primitive, output):
'''
primitives support by RiftCA
+
+ Pass vnf_config to avoid querying DTS each time
'''
- pass
-
+ output.execution_status = "failed"
+ output.execution_id = ''
+ output.execution_error_details = ''
+
+ try:
+ vnfr = self._rift_vnfs[vnfr_id].vnfr
+ except KeyError:
+ msg = "Did not find VNFR %s in RiftCA plugin", vnfr_id
+ self._log.error(msg)
+ output.execution_error_details = msg
+ return
+
+ rc, err = yield from self._vnf_config_primitive(nsr_id,
+ vnfr_id,
+ primitive)
+ if rc == 0:
+ output.execution_status = "completed"
+ else:
+ if isinstance(err, bytes):
+ err = err.decode()
+ output.execution_error_details = err
+
@asyncio.coroutine
def apply_config(self, config, nsr, vnfr, rpc_ip):
""" Notification on configuration of an NSR """
@@ -266,6 +377,67 @@
return task, err
@asyncio.coroutine
+ def apply_initial_config_new(self, agent_nsr, agent_vnfr):
+ self._log.debug("RiftCA: VNF initial config primitive for nsr {}, vnfr {}".
+ format(agent_nsr.name, agent_vnfr.name))
+
+ try:
+ vnfr = self._rift_vnfs[agent_vnfr.id].vnfr
+ except KeyError:
+ self._log.error("RiftCA: Did not find VNFR %s in RiftCA plugin",
+ agent_vnfr.name)
+ return False
+
+ class Primitive:
+ def __init__(self, name):
+ self.name = name
+ self.value = None
+ self.parameter = []
+
+ vnfr = yield from self.get_vnfr(agent_vnfr.id)
+ if vnfr is None:
+ msg = "Unable to get VNFR {} ({}) through DTS". \
+ format(agent_vnfr.id, agent_vnfr.name)
+ self._log.error(msg)
+ raise RuntimeError(msg)
+
+ vnf_config = vnfr.vnf_configuration
+ self._log.debug("VNFR %s config: %s", vnfr.name,
+ vnf_config.as_dict())
+
+ # Sort the primitive based on the sequence number
+ primitives = sorted(vnf_config.initial_config_primitive,
+ key=lambda k: k.seq)
+ if not primitives:
+ self._log.debug("VNFR {}: No initial-config-primitive specified".
+ format(vnfr.name))
+ return True
+
+ for primitive in primitives:
+ if primitive.config_primitive_ref:
+ # Reference to a primitive in config primitive
+ prim = Primitive(primitive.config_primitive_ref)
+ rc, err = yield from self._vnf_config_primitive(agent_nsr.id,
+ agent_vnfr.id,
+ prim,
+ vnf_config)
+ if rc != 0:
+ msg = "Error executing initial config primitive" \
+ " {} in VNFR {}: rc={}, stderr={}". \
+ format(prim.name, vnfr.name, rc, err)
+ self._log.error(msg)
+ return False
+
+ elif primitive.name:
+ msg = "Primitive {} definition in initial config " \
+ "primitive for VNFR {} not supported yet". \
+ format(primtive.name, vnfr.name)
+ self._log.error(msg)
+ raise NotImplementedError(msg)
+
+ return True
+
+ @asyncio.coroutine
def apply_initial_config(self, agent_nsr, agent_vnfr):
"""
Apply the initial configuration
@@ -280,16 +452,23 @@
agent_vnfr.set_to_configurable()
if agent_vnfr.is_configurable:
# apply initial config for the vnfr
+ # Keep the config-template based initial-config
rc = yield from self._events.apply_vnf_config(agent_vnfr.vnf_cfg)
+
+ # Check if the new method of initial-config-primitive is present
+ if rc:
+ rc = yield from self.apply_initial_config_new(agent_nsr, agent_vnfr)
+
else:
self._log.info("Rift config agent: VNF:%s/%s is not configurable yet!",
agent_nsr.name, agent_vnfr.name)
+
except Exception as e:
self._log.error("Rift config agent: Error on initial configuration to VNF:{}/{}, e {}"
.format(agent_nsr.name, agent_vnfr.name, str(e)))
-
+
self._log.exception(e)
- return rc
+ return False
return rc
diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/riftcm_config_plugin.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/riftcm_config_plugin.py
index b8de0d3..9312020 100644
--- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/riftcm_config_plugin.py
+++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/riftcm_config_plugin.py
@@ -16,10 +16,41 @@
import asyncio
import abc
+import os
+import tempfile
+import yaml
+
+import gi
+gi.require_version('RwDts', '1.0')
+from gi.repository import (
+ RwDts as rwdts,
+)
# Default config agent plugin type
DEFAULT_CAP_TYPE = "riftca"
+
+class XPaths(object):
+ @staticmethod
+ def nsr_opdata(k=None):
+ return ("D,/nsr:ns-instance-opdata/nsr:nsr" +
+ ("[nsr:ns-instance-config-ref='{}']".format(k) if k is not None else ""))
+
+ @staticmethod
+ def nsd_msg(k=None):
+ return ("C,/nsd:nsd-catalog/nsd:nsd" +
+ "[nsd:id = '{}']".format(k) if k is not None else "")
+
+ @staticmethod
+ def vnfr_opdata(k=None):
+ return ("D,/vnfr:vnfr-catalog/vnfr:vnfr" +
+ ("[vnfr:id='{}']".format(k) if k is not None else ""))
+
+ @staticmethod
+ def nsr_config(k=None):
+ return ("C,/nsr:ns-instance-config/nsr:nsr[nsr:id='{}']".format(k) if k is not None else "")
+
+
class RiftCMnsr(object):
'''
Agent class for NSR
@@ -89,6 +120,12 @@
def vnfr_ids(self):
return self._vnfr_ids
+ def get_member_vnfr(self, member_index):
+ for vnfr in self._vnfrs:
+ if vnfr.member_vnf_index == member_index:
+ return vnfr
+
+
class RiftCMvnfr(object):
'''
Agent base class for VNFR processing
@@ -284,6 +321,118 @@
"""Get the status of the service"""
return None
+ # Helper functions
+
+ def convert_value(self, value, type_='STRING'):
+ if type_ == 'STRING':
+ return str(value)
+
+ if type_ == 'INTEGER':
+ return int(value)
+
+ if type_ == 'BOOLEAN':
+ return (value == 1) or (value.lower() == 'true')
+
+ return value
+
+ @asyncio.coroutine
+ def _read_dts(self, xpath, do_trace=False):
+ self._log.debug("_read_dts path = %s", xpath)
+ flags = rwdts.XactFlag.MERGE
+ res_iter = yield from self._dts.query_read(
+ xpath, flags=flags
+ )
+
+ results = []
+ try:
+ for i in res_iter:
+ result = yield from i
+ if result is not None:
+ results.append(result.result)
+ except:
+ pass
+
+ return results
+
+
+ @asyncio.coroutine
+ def get_xpath(self, xpath):
+ self._log.debug("Attempting to get xpath: {}".format(xpath))
+ resp = yield from self._read_dts(xpath, False)
+ if len(resp) > 0:
+ self._log.debug("Got DTS resp: {}".format(resp[0]))
+ return resp[0]
+ return None
+
+ @asyncio.coroutine
+ def get_nsr(self, id):
+ self._log.debug("Attempting to get NSR: %s", id)
+ nsrl = yield from self._read_dts(XPaths.nsr_opdata(id), False)
+ nsr = None
+ if len(nsrl) > 0:
+ nsr = nsrl[0].as_dict()
+ return nsr
+
+ @asyncio.coroutine
+ def get_nsr_config(self, id):
+ self._log.debug("Attempting to get config NSR: %s", id)
+ nsrl = yield from self._read_dts(XPaths.nsr_config(id), False)
+ nsr = None
+ if len(nsrl) > 0:
+ nsr = nsrl[0]
+ return nsr
+
+ @asyncio.coroutine
+ def get_vnfr(self, id):
+ self._log.debug("Attempting to get VNFR: %s", id)
+ vnfrl = yield from self._read_dts(XPaths.vnfr_opdata(id), do_trace=False)
+ vnfr_msg = None
+ if len(vnfrl) > 0:
+ vnfr_msg = vnfrl[0]
+ return vnfr_msg
+
+ @asyncio.coroutine
+ def exec_script(self, script, data):
+ """Execute a shell script with the data as yaml input file"""
+ self._log.debug("Execute script {} with data {}".
+ format(script, data))
+ tmp_file = None
+ with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
+ tmp_file.write(yaml.dump(data, default_flow_style=True)
+ .encode("UTF-8"))
+
+ cmd = "{} {}".format(script, tmp_file.name)
+ self._log.debug("Running the CMD: {}".format(cmd))
+
+ try:
+ proc = yield from asyncio.create_subprocess_shell(
+ cmd,
+ stdout=asyncio.subprocess.PIPE,
+ stderr=asyncio.subprocess.PIPE)
+ rc = yield from proc.wait()
+ script_out, script_err = yield from proc.communicate()
+
+ except Exception as e:
+ msg = "Script {} caused exception: {}". \
+ format(script, e)
+ self._log.exception(msg)
+ rc = 1
+ script_err = msg
+ script_out = ''
+
+ finally:
+ # Remove the tempfile created
+ try:
+ os.remove(tmp_file.name)
+ except OSError as e:
+ self._log.info("Error removing tempfile {}: {}".
+ format(tmp_file.name, e))
+
+ self._log.debug("Script {}: rc={}\nStdOut:{}\nStdErr:{}".
+ format(script, rc, script_out, script_err))
+
+ return rc, script_err
+
@asyncio.coroutine
def invoke(self, method, *args):
try:
diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_config.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_config.py
index f71b3f1..26c595d 100644
--- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_config.py
+++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_config.py
@@ -241,7 +241,7 @@
# Initialize all handles that needs to be registered
for reg in self.reg_handles:
yield from reg.register()
-
+
@asyncio.coroutine
def register_cm_state_opdata(self):
@@ -422,8 +422,11 @@
if 'config_template' in vnf_config:
- vnf_cfg['cfg_template'] = '{}_{}_template.cfg'.format(nsr_obj.cfg_path_prefix, config_priority['configuration_type'])
- vnf_cfg['cfg_file'] = '{}.{}'.format(nsr_obj.cfg_path_prefix, get_cfg_file_extension(method, configuration_options))
+ vnf_cfg['cfg_template'] = '{}_{}_template.cfg'.format(nsr_obj.cfg_path_prefix,
+ config_priority['configuration_type'])
+ vnf_cfg['cfg_file'] = '{}.{}'.format(nsr_obj.cfg_path_prefix,
+ get_cfg_file_extension(method,
+ configuration_options))
vnf_cfg['xlate_script'] = os.path.join(self._parent.cfg_dir, 'xlate_cfg.py')
try:
# Now write this template into file
@@ -455,103 +458,294 @@
nsr_obj.populate_vm_state_from_vnf_cfg()
@asyncio.coroutine
- def resolve_xpath(self, xpath, name, vnfd):
+ def update_config_primitives(self, nsr_obj):
+
+ # Process all config-primitives in the member VNFs
+ for vnfr in nsr_obj.vnfrs:
+ vnfd = vnfr['vnf_cfg']['agent_vnfr'].vnfd
+
+ try:
+ prims = vnfd.vnf_configuration.config_primitive
+ if not prims:
+ self._log.debug("VNFR {} with VNFD {} has no config primitives defined".
+ format(vnfr.name, vnfd.name))
+ return
+ except AttributeError as e:
+ self._log.error("No config primitives found on VNFR {} ({})".
+ format(vnfr.name, vnfd.name))
+
+ cm_state = nsr_obj.find_vnfr_cm_state(vnfr['id'])
+ caps = cm_state['vnf_access_point']['capability']
+ deps = cm_state['vnf_access_point']['dependency']
+
+ vnf_configuration = vnfd.vnf_configuration.as_dict()
+ vnf_configuration['config_primitive'] = []
+ for prim in prims:
+ confp = prim.as_dict()
+ for param in confp['parameter']:
+ # First check the param in capabilities
+ found = False
+ for cap in caps:
+ if cap['name'] == param['name']:
+ param['default_value'] = cap['value']
+ param['read_only'] = True
+ break
+ if not found:
+ for dep in deps:
+ if dep['name'] == param['name']:
+ param['default_value'] = dep['value']
+ param['read_only'] = True
+ found = True
+ break
+ self._log.debug("Config primitive: {}".format(confp))
+ vnf_configuration['config_primitive'].append(confp)
+
+ cm_state['vnf_configuration'] = vnf_configuration
+
+ # Publish the updated config primitives for the VNFRs
+ yield from nsr_obj.publish_cm_state()
+
+ @asyncio.coroutine
+ def get_resolved_xpath(self, xpath, name, vnf_name, xpath_prefix):
# For now, use DTS to resolve the path
# TODO (pjoseph): Add better xpath support
-
- xpath_prefix = "C,/vnfd:vnfd-catalog/vnfd[id='{}']/vnfap/capability/capability[name='{}']/xpath". \
- format(vnfd.id, name)
-
+ dts_path = xpath
if xpath.startswith('../'):
prefix = xpath_prefix
xp = xpath
while xp.startswith('../'):
idx = prefix.rfind('/')
if idx == -1:
- raise ValueError("VNFD {}, Did not find the xpath specified: {}".
- format(vnfd.name, xpath))
+ raise ValueError("VNF {}, Did not find the xpath specified: {}".
+ format(vnf_name, xpath))
prefix = prefix[:idx]
xp = xp[3:]
- idx = xp.rfind('/')
- if idx = -1:
- raise ValueError("VNFD {}, xpath {} should point to an attribute".
- format(vnfd.name, xpath))
- attr = xp[idx+1:]
- dts_path = prefix + '/' + xp[:idx]
- self._log.error("DTS path: {}, attribute: {}".format(dts_path, attribute))
+ dts_path = prefix + '/' + xp
elif xpath.startswith('/'):
dts_path = 'C,' + xpath
elif xpath.startswith('C,/') or xpath.startswith('D,/'):
dts_path = xpath
else:
- self._log.error("Unknown xpath {} for capability {} in VNFD {}".
- format(xpath, name, vnfd.name))
- return None
+ self._log.error("Invalid xpath {} for capability {} in VNF {}".
+ format(xpath, name, vnf_name))
+ raise ValueError("XPath {} in capability {} for VNF {} is invalid".
+ format(xpath, name, vnf_name))
+ return dts_path
+
+ @asyncio.coroutine
+ def resolve_xpath(self, xpath, name, vnfd):
+ xpath_prefix = "C,/vnfd:vnfd-catalog/vnfd[id='{}']/vnfap/capability" \
+ "/capability[name='{}']/xpath". \
+ format(vnfd.id, name)
+
+ dts_path = yield from self.get_resolved_xpath(xpath, name,
+ vnfd.name, xpath_prefix)
+ idx = dts_path.rfind('/')
+ if idx == -1:
+ raise ValueError("VNFD {}, xpath {} should point to an attribute".
+ format(vnfd.name, xpath))
+ attr = dts_path[idx+1:]
+ dts_path = dts_path[:idx]
+ self._log.debug("DTS path: {}, attribute: {}".format(dts_path, attr))
resp = yield from self.cmdts_obj.get_xpath(dts_path)
- self._log.error("DTS response: {}".resp)
+ if resp is None:
+ raise ValueError("Xpath {} in capability {} for VNFD {} is not found".
+ format(xpath, name, vnfd.name))
+ self._log.debug("DTS response: {}".format(resp.as_dict()))
+
+ try:
+ val = getattr(resp, attr)
+ except AttributeError as e:
+ self._log.error("Did not find attribute : {}".format(attr))
+ try:
+ val = getattr(resp, attr.replace('-', '_'))
+ except AttributeError as e:
+ raise ValueError("Did not find attribute {} in XPath {} "
+ "for capability {} in VNF {}".
+ format(attr, dts_path, vnfd.name))
+
+ self._log.debug("XPath {}: {}".format(xpath, val))
+ return val
+
+ @asyncio.coroutine
+ def resolve_attribute(self, attribute, name, vnfd, vnfr):
+ idx = attribute.rfind(',')
+ if idx == -1:
+ raise ValueError ("Invalid attribute {} for capability {} in "
+ "VNFD specified".
+ format(attribute, name, vnfd.name))
+ xpath = attribute[:idx].strip()
+ attr = attribute[idx+1:].strip()
+ self._log.debug("Attribute {}, {}".format(xpath, attr))
+ if xpath.startswith('C,/'):
+ raise ValueError("Attribute {} for capability {} in VNFD cannot "
+ "be a config".
+ format(attribute, name, vnfd.name))
+
+ xpath_prefix = "D,/vnfr:vnfr-catalog/vnfr[id='{}']/vnfap/capability" \
+ "/capability[name='{}']/attribute". \
+ format(vnfr['id'], name)
+ dts_path = yield from self.get_resolved_xpath(xpath, name,
+ vnfr['name'],
+ xpath_prefix)
+ self._log.debug("DTS query: {}".format(dts_path))
+
+ resp = yield from self.cmdts_obj.get_xpath(dts_path)
+ if resp is None:
+ raise ValueError("Attribute {} in capability {} for VNFD {} is " \
+ "not found".
+ format(xpath, name, vnfd.name))
+ self._log.debug("DTS response: {}".format(resp.as_dict()))
+
+ try:
+ val = getattr(resp, attr)
+ except AttributeError as e:
+ self._log.debug("Did not find attribute {}".format(attr))
+ try:
+ val = getattr(resp, attr.replace('-', '_'))
+ except AttributeError as e:
+ raise ValueError("Did not find attribute {} in XPath {} "
+ "for capability {} in VNF {}".
+ format(attr, dts_path, vnfd.name))
+
+ self._log.debug("Attribute {}: {}".format(attribute, val))
+ return val
@asyncio.coroutine
def process_vnf_access_point(self, nsr_obj):
nsd = nsr_obj.agent_nsr.nsd
- vnfap_map = None
- try:
- vnfap_map = nsd.vnfap_map
- except AttributeError as e:
- self._log.error("No vnfap map specified for nsr: {}".
- format(nsr_obj.nsr_name))
- return
-
- if not len(vnfap_map):
- self._log.error("No entries in vnfap map for nsr: {}".
- format(nsr_obj.nsr_name))
- return
# Process all capabilities in all the member VNFs
for vnfr in nsr_obj.vnfrs:
vnfd = vnfr['vnf_cfg']['agent_vnfr'].vnfd
- self._log.error("VNFD: {}".format(vnfd.as_dict()))
+
try:
vnfap = vnfd.vnfap
except AttributeError as e:
- self._log.error("VNFR {} does not have VNF access point".
+ self._log.debug("VNFR {} does not have VNF access point".
format(vnfr.name))
continue
+ caps = []
try:
caps = vnfap.capability
except AttributeError as e:
- self._log.error("VNFR {} has no capabilities defined".
+ self._log.debug("VNFR {} has no capabilities defined".
format(vnfr.name))
- continue
# Get the cm state dict for this vnfr
cm_state = nsr_obj.find_vnfr_cm_state(vnfr['id'])
- cm_caps = cm_state['vnf_access_point']['capability']
+ cm_caps = []
for cap in caps:
- self._log.error("VNFR {}: capability {}".
+ self._log.debug("VNFR {}: capability {}".
format(vnfr['name'], cap.as_dict()))
- val = None
try:
val = cap.value
- self._log.error("Got value {}".format(val))
+ self._log.debug("Got value {}".format(val))
+ if val:
+ cm_caps.append({'name': cap.name, 'value': str(val)})
+ continue
except AttributeError as e:
pass
- if val is None:
- try:
- xpath = cap.xpath
- # resolve xpath
+ try:
+ xpath = cap.xpath
+ # resolve xpath
+ if xpath:
val = yield from self.resolve_xpath(xpath, cap.name, vnfd)
self._log.debug("Got xpath value: {}".format(val))
- except AttributeError as e:
- pass
+ cm_caps.append({'name': cap.name, 'value': str(val)})
+ continue
+ except AttributeError as e:
+ pass
+ try:
+ attribute = cap.attribute
+ # resolve attribute
+ if attribute:
+ val = yield from self.resolve_attribute(attribute, cap.name, vnfd, vnfr)
+ self._log.debug("Got attribute value: {}".format(val))
+ cm_caps.append({'name': cap.name, 'value': str(val)})
+ continue
+ except AttributeError as e:
+ pass
+ self._log.debug("VNF Capabilities: {}".format(cm_caps))
+ cm_state['vnf_access_point']['capability'] = cm_caps
+
+ try:
+ deps = vnfap.dependency
+ except AttributeError as e:
+ self._log.debug("VNFR {} has no dependencies defined".
+ format(vnfr.name))
+ continue
+
+ cm_deps = []
+ for dep in deps:
+ self._log.debug("VNFR{}: dependency {}".
+ format(vnfr['name'], dep.as_dict()))
+ cm_deps.append({'name': dep.name, 'mandatory': dep.mandatory})
+
+ self._log.debug("VNF Dependencies: {}".format(cm_deps))
+ cm_state['vnf_access_point']['dependency'] = cm_deps
+
+ # Publish all capabilities for the VNFRs
+ yield from nsr_obj.publish_cm_state()
+
+ vnfap_map = None
+ try:
+ vnfap_map = nsd.vnfap_map
+ except AttributeError as e:
+ self._log.debug("No vnfap map specified for nsr: {}".
+ format(nsr_obj.nsr_name))
+ return
+
+ if not len(vnfap_map):
+ self._log.info("No entries in vnfap map for nsr: {}".
+ format(nsr_obj.nsr_name))
+ return
+
+ for ap in vnfap_map:
+ cap_vnfr = nsr_obj.agent_nsr.get_member_vnfr(ap.capability.member_vnf_index)
+ cm_state = nsr_obj.find_vnfr_cm_state(cap_vnfr.id)
+ if cm_state is None:
+ raise ValueError("Capabilities are not defined for VNF member {} ({})".
+ format(ap.capability.member_vnf_index, cap_vnfr.name))
+ caps = cm_state['vnf_access_point']['capability']
+
+ cap_attr = ap.capability.capability_ref
+ val = None
+ for cap in caps:
+ if cap['name'] == cap_attr:
+ val = cap['value']
+ break
+
+ dep_vnfr = nsr_obj.agent_nsr.get_member_vnfr(ap.dependency.member_vnf_index)
+ dep_attr = ap.dependency.dependency_ref
+ cm_state = nsr_obj.find_vnfr_cm_state(dep_vnfr.id)
+ try:
+ cm_deps = cm_state['vnf_access_point']['dependency']
+ except KeyError as e:
+ raise ValueError("VNFR index {} ({}) has no dependencies defined".
+ format(ap.dependency.member_vnf_index, dep_vnfr['name']))
+
+ for i, item in enumerate(cm_deps):
+ if item['name'] == dep_attr:
+ item['value'] = str(val)
+ cm_deps[i] = item
+ self._log.debug("Dependency in VNFR {}: {}".
+ format(dep_vnfr.name, item))
+ break
+
+ # Publish resolved dependencies for the VNFRs
+ yield from nsr_obj.publish_cm_state()
+
+ yield from self.update_config_primitives(nsr_obj)
@asyncio.coroutine
def config_NSR(self, id):
@@ -704,7 +898,8 @@
# Find vnfr for this vnf_unique_name
if vnf_unique_name not in nsr_obj._vnfr_dict:
- self._log.error("NS (%s) - Can not find VNF to be configured: %s", nsr_obj.nsr_name, vnf_unique_name)
+ self._log.error("NS (%s) - Can not find VNF to be configured: %s",
+ nsr_obj.nsr_name, vnf_unique_name)
else:
# Save this unique VNF's config input parameters
nsr_obj.vnf_config_attributes_dict[vnf_unique_name] = vnf_config_attributes_dict
@@ -911,12 +1106,18 @@
self._log.debug("Running the CMD: {}".format(cmd))
process = yield from asyncio. \
- create_subprocess_shell(cmd, loop=self._loop)
+ create_subprocess_shell(
+ cmd, loop=self._loop,
+ stdout=asyncio.subprocess.PIPE,
+ stderr=asyncio.subprocess.PIPE)
yield from process.wait()
if process.returncode:
+ script_out, script_err = yield from proc.communicate()
msg = "NSR {} initial config using {} failed with {}". \
format(nsr_name, script, process.returncode)
self._log.error(msg)
+ self._log.error("Script {} stderr: {}".
+ format(script, script_err))
raise InitialConfigError(msg)
else:
os.remove(inp_file)
@@ -1073,30 +1274,30 @@
self._cp_dict['rw_mgmt_ip'] = vnf_cfg['mgmt_ip_address']
self._cp_dict['rw_username'] = vnf_cfg['username']
self._cp_dict['rw_password'] = vnf_cfg['password']
- ############################################################
- # TBD - Need to lookup above 3 for a given VNF, not global #
- # Once we do that no need to dump below file again before #
- # each VNF configuration translation. #
- # This will require all existing config templates to be #
- # changed for above three tags to include member index #
- ############################################################
- try:
- nsr_obj = vnf_cfg['nsr_obj']
- # Generate config_config_attributes.yaml (For debug reference)
- with open(nsr_obj.xlate_dict_file, "w") as yf:
- yf.write(yaml.dump(nsr_obj._cp_dict, default_flow_style=False))
- except Exception as e:
- self._log.error("NS:(%s) failed to write nsr xlate tags file as (%s)", nsr_obj.nsr_name, str(e))
if 'cfg_template' in vnf_cfg:
- script_cmd = 'python3 {} -i {} -o {} -x "{}"'.format(vnf_cfg['xlate_script'], vnf_cfg['cfg_template'], vnf_cfg['cfg_file'], self.xlate_dict_file)
- self._log.debug("xlate script command (%s)", script_cmd)
- #xlate_msg = subprocess.check_output(script_cmd).decode('utf-8')
- xlate_msg = subprocess.check_output(script_cmd, shell=True).decode('utf-8')
- self._log.info("xlate script output (%s)", xlate_msg)
+ try:
+ nsr_obj = vnf_cfg['nsr_obj']
+ # Generate config_config_attributes.yaml (For debug reference)
+ with open(nsr_obj.xlate_dict_file, "w") as yf:
+ yf.write(yaml.dump(nsr_obj._cp_dict, default_flow_style=False))
+ except Exception as e:
+ self._log.error("NS:(%s) failed to write nsr xlate tags "
+ "file as (%s)", nsr_obj.nsr_name, str(e))
+
+ script_cmd = 'python3 {} -i {} -o {} -x "{}"'. \
+ format(vnf_cfg['xlate_script'],
+ vnf_cfg['cfg_template'],
+ vnf_cfg['cfg_file'],
+ self.xlate_dict_file)
+ self._log.debug("xlate script command (%s)", script_cmd)
+ xlate_msg = subprocess.check_output(script_cmd, shell=True).decode('utf-8')
+ self._log.info("xlate script output (%s)", xlate_msg)
+
except Exception as e:
vnf_cm_state['state'] = self.state_to_string(conmanY.RecordState.CFG_PROCESS_FAILED)
- self._log.error("Failed to execute translation script for VNF: %s with (%s)", log_this_vnf(vnf_cfg), str(e))
+ self._log.error("Failed to execute translation script for VNF: %s with (%s)",
+ log_this_vnf(vnf_cfg), str(e))
return
self._log.info("Applying config to VNF: %s = %s!", log_this_vnf(vnf_cfg), vnf_cfg)
@@ -1456,9 +1657,12 @@
@asyncio.coroutine
def get_xpath(self, xpath):
- self._log.debug("Attempting to get {}".format(xpath))
+ self._log.debug("Attempting to get xpath: {}".format(xpath))
resp = yield from self._read_dts(xpath, False)
- return resp
+ if len(resp) > 0:
+ self._log.debug("Got DTS resp: {}".format(resp[0]))
+ return resp[0]
+ return None
@asyncio.coroutine
def get_nsr(self, id):
@@ -1549,7 +1753,7 @@
def register(self):
yield from self.register_to_publish()
yield from self.register_for_nsr()
-
+
@asyncio.coroutine
def register_to_publish(self):
''' Register to DTS for publishing cm-state opdata '''
diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_events.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_events.py
index f292a68..0b2e576 100644
--- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_events.py
+++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_events.py
@@ -55,9 +55,12 @@
else:
log_vnf += "{}/".format(vnf_cfg[item])
return log_vnf
-
+
+
class ConfigManagerROifConnectionError(Exception):
pass
+
+
class ScriptError(Exception):
pass
@@ -78,23 +81,23 @@
def update_vnf_state(self, vnf_cfg, state):
nsr_obj = vnf_cfg['nsr_obj']
yield from nsr_obj.update_vnf_cm_state(vnf_cfg['vnfr'], state)
-
+
@asyncio.coroutine
def apply_vnf_config(self, vnf_cfg):
self._log.debug("apply_vnf_config VNF:{}"
.format(log_this_vnf(vnf_cfg)))
-
+
if vnf_cfg['config_delay']:
yield from self.update_vnf_state(vnf_cfg, conmanY.RecordState.CFG_DELAY)
yield from asyncio.sleep(vnf_cfg['config_delay'], loop=self._loop)
-
+
# See if we are still alive!
if vnf_cfg['nsr_obj'].being_deleted:
# Don't do anything, just return
self._log.info("VNF : %s is being deleted, skipping configuration!",
log_this_vnf(vnf_cfg))
return True
-
+
yield from self.update_vnf_state(vnf_cfg, conmanY.RecordState.CFG_SEND)
try:
if vnf_cfg['config_method'] == 'netconf':
@@ -124,21 +127,20 @@
yield from self.update_vnf_state(vnf_cfg, conmanY.RecordState.CFG_FAILED)
return True
- #Update VNF state
- yield from self.update_vnf_state(vnf_cfg, conmanY.RecordState.READY)
- self._log.info("Successfully applied configuration to VNF: %s",
+ self._log.info("Successfully applied config template to VNF: %s",
log_this_vnf(vnf_cfg))
+
except Exception as e:
self._log.error("Applying configuration(%s) file(%s) to VNF: %s failed as: %s",
vnf_cfg['config_method'],
vnf_cfg['cfg_file'],
log_this_vnf(vnf_cfg),
str(e))
- #raise
+ self._log.exception(e)
return False
return True
-
+
class ConfigManagerVNFscriptconf(object):
def __init__(self, log, loop, parent, vnf_cfg):
@@ -151,7 +153,12 @@
#@asyncio.coroutine
def apply_edit_cfg(self):
vnf_cfg = self._vnf_cfg
- self._log.debug("Attempting to apply scriptconf to VNF: %s", log_this_vnf(vnf_cfg))
+ self._log.debug("Attempting to apply scriptconf to VNF %s: %s", log_this_vnf(vnf_cfg), vnf_cfg)
+
+ if vnf_cfg['cfg_file'] is None or (vnf_cfg['cfg_file'] == 'None'):
+ self._log.debug("Config file for script not provided")
+ return
+
try:
st = os.stat(vnf_cfg['cfg_file'])
os.chmod(vnf_cfg['cfg_file'], st.st_mode | stat.S_IEXEC)
@@ -297,6 +304,10 @@
vnf_cfg = self._vnf_cfg
self._log.debug("Attempting to apply netconf to VNF: %s", log_this_vnf(vnf_cfg))
+ if vnf_cfg['cfg_file'] is None or (vnf_cfg['cfg_file'] == 'None'):
+ self._log.debug("Config file for Netconf not provided")
+ return
+
if self._manager is None:
self._log.error("Netconf is not connected to VNF: %s, aborting!", log_this_vnf(vnf_cfg))
return
diff --git a/rwlaunchpad/plugins/rwmonitor/rift/tasklets/rwmonitor/tasklet.py b/rwlaunchpad/plugins/rwmonitor/rift/tasklets/rwmonitor/tasklet.py
index 4ab351e..5beafe6 100644
--- a/rwlaunchpad/plugins/rwmonitor/rift/tasklets/rwmonitor/tasklet.py
+++ b/rwlaunchpad/plugins/rwmonitor/rift/tasklets/rwmonitor/tasklet.py
@@ -628,9 +628,15 @@
self.dts.handle.set_state(next_state)
def on_vnfr_create(self, vnfr):
- if not self.monitor.nfvi_metrics_available(vnfr.cloud_account):
+ try:
+ acc = vnfr.cloud_account
+ except AttributeError as e:
+ self.log.warning("NFVI metrics not supported")
+ return
+
+ if not self.monitor.nfvi_metrics_available(acc):
msg = "NFVI metrics unavailable for {}"
- self.log.warning(msg.format(vnfr.cloud_account))
+ self.log.warning(msg.format(acc))
return
self.monitor.add_vnfr(vnfr)
@@ -642,6 +648,12 @@
self.loop.create_task(coro)
def on_vnfr_update(self, vnfr):
+ try:
+ acc = vnfr.cloud_account
+ except AttributeError as e:
+ self.log.warning("NFVI metrics not supported")
+ return
+
if not self.monitor.nfvi_metrics_available(vnfr.cloud_account):
msg = "NFVI metrics unavailable for {}"
self.log.warning(msg.format(vnfr.cloud_account))
diff --git a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsm_conman.py b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsm_conman.py
index 23ab7b6..8073c4c 100644
--- a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsm_conman.py
+++ b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsm_conman.py
@@ -83,33 +83,38 @@
return
try:
- nsrid = cm_nsr['id']
+ nsrid = cm_nsr.id
# Update the VNFRs' config status
- gen = []
- if 'cm_vnfr' in cm_nsr:
- gen = (vnfr for vnfr in cm_nsr['cm_vnfr']
- if vnfr['id'] in self.nsm._vnfrs)
+ gen = (vnfr for vnfr in cm_nsr.cm_vnfr
+ if vnfr.id in self.nsm._vnfrs)
for vnfr in gen:
- vnfrid = vnfr['id']
- new_status = ROConfigManager.map_config_status(vnfr['state'])
+ vnfrid = vnfr.id
+ new_status = ROConfigManager.map_config_status(vnfr.state)
self._log.debug("Updating config status of VNFR {} " \
"in NSR {} to {}({})".
format(vnfrid, nsrid, new_status,
- vnfr['state']))
+ vnfr.state))
yield from \
self.nsm.vnfrs[vnfrid].set_config_status(new_status)
- # Update the NSR's config status
- new_status = ROConfigManager.map_config_status(cm_nsr['state'])
- self._log.info("Updating config status of NSR {} to {}({})".
- format(nsrid, new_status, cm_nsr['state']))
+ yield from \
+ self.nsm.vnfrs[vnfrid].update_config_primitives(
+ vnfr.vnf_configuration)
- # If terminate nsr request comes when NS instantiation is in 'Configuring state'; self.nsm.nsrs dict
- # is already empty when self.nsm.nsrs[nsrid].set_config_status gets executed. So adding a check here.
+ # Update the NSR's config status
+ new_status = ROConfigManager.map_config_status(cm_nsr.state)
+ self._log.debug("Updating config status of NSR {} to {}({})".
+ format(nsrid, new_status, cm_nsr.state))
+
+ # If terminate nsr request comes when NS instantiation is in
+ # 'Configuring state'; self.nsm.nsrs dict is already empty when
+ # self.nsm.nsrs[nsrid].set_config_status gets executed. So adding a check here.
if nsrid in self.nsm.nsrs:
- yield from self.nsm.nsrs[nsrid].set_config_status(new_status, cm_nsr.get('state_details'))
+ yield from self.nsm.nsrs[nsrid].set_config_status(
+ new_status,
+ cm_nsr.state_details)
except Exception as e:
self._log.error("Failed to process cm-state for nsr {}: {}".
@@ -119,12 +124,11 @@
@asyncio.coroutine
def register(self):
""" Register for cm-state changes """
-
+
@asyncio.coroutine
def on_prepare(xact_info, query_action, ks_path, msg):
""" cm-state changed """
- #print("###>>> cm-state change ({}), msg_dict = {}".format(query_action, msg_dict))
self._log.debug("Received cm-state on_prepare (%s:%s:%s)",
query_action,
ks_path,
@@ -133,10 +137,11 @@
if (query_action == rwdts.QueryAction.UPDATE or
query_action == rwdts.QueryAction.CREATE):
# Update Each NSR/VNFR state
- msg_dict = msg.as_dict()
- yield from self.update_ns_cfg_state(msg_dict)
+ # msg_dict = msg.as_dict()
+ yield from self.update_ns_cfg_state(msg)
elif query_action == rwdts.QueryAction.DELETE:
- self._log.debug("DELETE action in on_prepare for cm-state, ignoring")
+ self._log.debug("DELETE action in on_prepare for cm-state, "
+ "ignoring")
else:
raise NotImplementedError(
"%s on cm-state is not supported",
@@ -145,10 +150,13 @@
xact_info.respond_xpath(rwdts.XactRspCode.ACK)
try:
- handler = rift.tasklets.DTS.RegistrationHandler(on_prepare=on_prepare)
- self.dts_reg_hdl = yield from self._dts.register(self.cm_state_xpath,
- flags=rwdts.Flag.SUBSCRIBER,
- handler=handler)
+ handler = rift.tasklets.DTS.RegistrationHandler(
+ on_prepare=on_prepare)
+ self.dts_reg_hdl = yield from self._dts.register(
+ self.cm_state_xpath,
+ flags=rwdts.Flag.SUBSCRIBER,
+ handler=handler)
+
except Exception as e:
- self._log.error("Failed to register for cm-state changes as %s", str(e))
-
+ self._log.error("Failed to register for cm-state changes as %s",
+ str(e))
diff --git a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py
index bbe1552..6396b95 100755
--- a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py
+++ b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py
@@ -42,6 +42,7 @@
gi.require_version('RwTypes', '1.0')
gi.require_version('RwVlrYang', '1.0')
gi.require_version('RwVnfrYang', '1.0')
+gi.require_version('VnfdYang', '1.0')
from gi.repository import (
RwYang,
RwNsrYang,
@@ -54,6 +55,7 @@
RwsdnYang,
RwDts as rwdts,
RwTypes,
+ VnfdYang,
ProtobufC,
)
@@ -829,7 +831,10 @@
@property
def const_vnfr_msg(self):
""" VNFR message """
- return RwNsrYang.YangData_Nsr_NsInstanceOpdata_Nsr_ConstituentVnfrRef(vnfr_id=self.id,cloud_account=self.cloud_account_name,om_datacenter=self._om_datacenter_name)
+ return RwNsrYang.YangData_Nsr_NsInstanceOpdata_Nsr_ConstituentVnfrRef(
+ vnfr_id=self.id,
+ cloud_account=self.cloud_account_name,
+ om_datacenter=self._om_datacenter_name)
@property
def vnfd(self):
@@ -979,7 +984,7 @@
format(self.name, self.vnfr_msg))
yield from self._dts.query_update(
self.xpath,
- rwdts.XactFlag.TRACE,
+ rwdts.XactFlag.REPLACE,
self.vnfr_msg
)
@@ -1041,6 +1046,47 @@
return False
@asyncio.coroutine
+ def update_config_primitives(self, vnf_config):
+ # Update only after we are configured
+ if self._config_status == NsrYang.ConfigStates.INIT:
+ return
+
+ if not vnf_config.as_dict():
+ return
+
+ self._log.debug("Update VNFR {} config: {}".
+ format(self.name, vnf_config.as_dict()))
+
+ # Update config primitive
+ updated = False
+ for prim in self._vnfd.vnf_configuration.config_primitive:
+ for p in vnf_config.config_primitive:
+ if prim.name == p.name:
+ for param in prim.parameter:
+ for pa in p.parameter:
+ if pa.name == param.name:
+ if not param.default_value or \
+ (pa.default_value != param.default_value):
+ param.default_value = pa.default_value
+ updated = True
+ break
+ break
+
+ if updated:
+ self._log.debug("Updated VNFD {} config: {}".
+ format(self._vnfd.name,
+ self._vnfd.vnf_configuration))
+ self._vnfr_msg = self.create_vnfr_msg()
+
+ try:
+ yield from self.update_vnfm()
+ except Exception as e:
+ self._log.error("Exception updating VNFM with new config "
+ "primitive for VNFR {}: {}".
+ format(self.name, e))
+ self._log.exception(e)
+
+ @asyncio.coroutine
def instantiate(self, nsr):
""" Instantiate this VNFR"""
diff --git a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py
index 36f0351..6f66cb5 100755
--- a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py
+++ b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py
@@ -1278,6 +1278,17 @@
return vnfr_msg
+ @asyncio.coroutine
+ def update_config(self, msg, xact):
+ self._log.debug("VNFM vnf config: {}".
+ format(msg.vnf_configuration.as_dict()))
+ self._config_status = msg.config_status
+ self._vnfr = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict(
+ msg.as_dict())
+ self._log.debug("VNFR msg config: {}".
+ format(self.msg.vnf_configuration.as_dict()))
+ yield from self.publish(xact)
+
@property
def dashboard_url(self):
ip, cfg_port = self.mgmt_intf_info()
@@ -2150,9 +2161,8 @@
self._log.debug("VNFR {} update config status {} (current {})".
format(vnfr.name, msg.config_status, vnfr.config_status))
- # Update the config status and publish
- vnfr._config_status = msg.config_status
- yield from vnfr.publish(None)
+ # Update the config and publish
+ yield from vnfr.update_config(msg, xact_info)
else:
raise NotImplementedError(
@@ -2172,7 +2182,6 @@
handler=hdl,
flags=(rwdts.Flag.PUBLISHER |
rwdts.Flag.NO_PREP_READ |
- rwdts.Flag.CACHE |
rwdts.Flag.DATASTORE),)
@asyncio.coroutine
@@ -2188,13 +2197,13 @@
xact, path, msg)
@asyncio.coroutine
- def update(self, xact, path, msg):
+ def update(self, xact, path, msg, flags=rwdts.XactFlag.REPLACE):
"""
Update a VNFR record in DTS with path and message
"""
self._log.debug("Updating VNFR xact = %s, %s:%s",
xact, path, msg)
- self.regh.update_element(path, msg)
+ self.regh.update_element(path, msg, flags)
self._log.debug("Updated VNFR xact = %s, %s:%s",
xact, path, msg)