def extract_vnfd_config(self, vnfd, format="yaml"):
config_prim = None
try:
- config_prim = vnfd.vnf_configuration.service_primitive
+ config_prim = vnfd.vnf_configuration.config_primitive
except AttributeError:
pass
vnfd_init_cfg_prim_msg.append(prim)
def merge_vnfd_config(self, vnfd, input_data):
- for config_primitive in vnfd.vnf_configuration.service_primitive:
+ for config_primitive in vnfd.vnf_configuration.config_primitive:
try:
cfg = input_data[self.CONFIG_PRIMITIVE][config_primitive.name]
except KeyError:
],
})
- vnf_config.service_primitive.add().from_dict({
+ vnf_config.config_primitive.add().from_dict({
"name": "PE1",
"parameter": [
{"name": "Foo", "default_value": "Bar"}
]
})
- expected_yaml = """service_primitive:
+ expected_yaml = """config_primitive:
PE1:
parameter:
Foo: Bar
"parameter": [{"name": "cidr"}],
})
- vnf_config.service_primitive.add().from_dict({
+ vnf_config.config_primitive.add().from_dict({
"name": "PE1",
"parameter": [{"name": "Foo",}]
})
- ip_yaml = """service_primitive:
+ ip_yaml = """config_primitive:
PE1:
parameter:
Foo: Bar
],
})
- vnf_config.service_primitive.add().from_dict({
+ vnf_config.config_primitive.add().from_dict({
"name": "PE1",
"parameter": [
{"name": "Foo", "default_value": "Bar"}
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}
+++ /dev/null
-#!/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 stat
-import subprocess
-import sys
-import time
-import yaml
-
-def ping_config(run_dir, mgmt_ip, mgmt_port, pong_cp, logger, dry_run):
- sh_file = "{}/ping_config-{}.sh".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
- logger.debug("Creating script file %s" % sh_file)
- f = open(sh_file, "w")
- f.write(r'''
-#!/bin/bash
-
-# Rest API config
-ping_mgmt_ip='{}'
-ping_mgmt_port={}
-
-# VNF specific configuration
-pong_server_ip='{}'
-ping_rate=5
-server_port=5555
-'''.format(mgmt_ip, mgmt_port, pong_cp))
-
- f.write(r'''
-# Check if the port is open
-DELAY=1
-MAX_TRIES=60
-COUNT=0
-while true; do
- COUNT=$(expr $COUNT + 1)
- timeout 1 bash -c "cat < /dev/null > /dev/tcp/${ping_mgmt_ip}/${ping_mgmt_port}"
- rc=$?
- if [ $rc -ne 0 ]
- then
- echo "Failed to connect to server ${ping_mgmt_ip}:${ping_mgmt_port} for ping with $rc!"
- if [ ${COUNT} -gt ${MAX_TRIES} ]; then
- exit $rc
- fi
- sleep ${DELAY}
- else
- break
- fi
-done
-
-# Make rest API calls to configure VNF
-curl -D /dev/stdout \
- -H "Accept: application/vnd.yang.data+xml" \
- -H "Content-Type: application/vnd.yang.data+json" \
- -X POST \
- -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \
- http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/server
-rc=$?
-if [ $rc -ne 0 ]
-then
- echo "Failed to set server info for ping!"
- exit $rc
-fi
-
-curl -D /dev/stdout \
- -H "Accept: application/vnd.yang.data+xml" \
- -H "Content-Type: application/vnd.yang.data+json" \
- -X POST \
- -d "{\"rate\":$ping_rate}" \
- http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/rate
-rc=$?
-if [ $rc -ne 0 ]
-then
- echo "Failed to set ping rate!"
- exit $rc
-fi
-
-output=$(curl -D /dev/stdout \
- -H "Accept: application/vnd.yang.data+xml" \
- -H "Content-Type: application/vnd.yang.data+json" \
- -X POST \
- -d "{\"enable\":true}" \
- http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/adminstatus/state)
-if [[ $output == *"Internal Server Error"* ]]
-then
- echo $output
- exit 3
-else
- echo $output
-fi
-
-exit 0
-''')
- f.close()
- os.chmod(sh_file, stat.S_IRWXU)
- if not dry_run:
- rc = subprocess.call(sh_file, shell=True)
- if rc:
- logger.error("Config failed: {}".format(rc))
- return False
- return True
-
-
-
-def main(argv=sys.argv[1:]):
- try:
- parser = argparse.ArgumentParser()
- parser.add_argument("yaml_cfg_file", type=argparse.FileType('r'))
- parser.add_argument("--dry-run", action="store_true")
- parser.add_argument("--quiet", "-q", 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 = "{}/rift_ping_config-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
- logging.basicConfig(filename=log_file, level=logging.DEBUG)
- logger = logging.getLogger()
-
- 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')
- ch.setFormatter(formatter)
- logger.addHandler(ch)
-
- except Exception as e:
- print("Got exception:{}".format(e))
- raise e
-
- try:
- dry_run = args.dry_run
-
- yaml_str = args.yaml_cfg_file.read()
- logger.debug("Input YAML file: {}".format(yaml_str))
- yaml_cfg = yaml.load(yaml_str)
- logger.debug("Input YAML: {}".format(yaml_cfg))
-
- # Check if this is post scale out trigger
- if yaml_cfg['trigger'] != 'post_scale_out':
- logger.error("Unexpected trigger {}".
- format(yaml_cfg['trigger']))
- raise
-
- pong_cp = ""
- for vnfr in yaml_cfg['vnfrs_others']:
- # Find the pong VNFR, assuming vnfr name will
- # have pong_vnfd as a substring
- if 'pong_vnfd' in vnfr['name']:
- for cp in vnfr['connection_points']:
- logger.debug("Connection point {}".format(cp))
- if 'cp0' in cp['name']:
- pong_cp = cp['ip_address']
- break
- if not len(pong_cp):
- logger.error("Did not get Pong cp0 IP")
- raise
-
- for vnfr in yaml_cfg['vnfrs_in_group']:
- mgmt_ip = vnfr['rw_mgmt_ip']
- mgmt_port = vnfr['rw_mgmt_port']
- if ping_config(run_dir, mgmt_ip, mgmt_port, pong_cp, logger, dry_run):
- logger.info("Successfully configured Ping {} at {}".
- format(vnfr['name'], mgmt_ip))
- else:
- logger.error("Config of ping {} with {} failed".
- format(vnfr['name'], mgmt_ip))
- raise
-
- except Exception as e:
- logger.error("Got exception {}".format(e))
- logger.exception(e)
- raise e
-
-if __name__ == "__main__":
- main()
def add_placement_group(self, group):
self._placement_groups.append(group)
+ def add_vnf_access_point(self, mano_ut=False):
+ vnfd = self.descriptor.vnfd[0]
+ confparam = vnfd.config_parameter
+
+ def get_params(param):
+ # Check if pong
+ if 'pong_' in self.name:
+ params = [
+ {
+ "config_primitive_name_ref": "config",
+ "config_primitive_parameter_ref": param
+ },
+ {
+ "config_primitive_name_ref": "start-stop",
+ "config_primitive_parameter_ref": param
+ },
+ ]
+ else:
+ params = [
+ {
+ "config_primitive_name_ref": "config",
+ "config_primitive_parameter_ref": param
+ },
+ {
+ "config_primitive_name_ref": "set-rate",
+ "config_primitive_parameter_ref": param
+ },
+ {
+ "config_primitive_name_ref": "start-stop",
+ "config_primitive_parameter_ref": param
+ },
+ ]
+ return params
+
+ src = confparam.create_config_parameter_source()
+ src.from_dict({
+ "name": "mgmt_ip",
+ "description": "Management address",
+ "attribute": "../../../../mgmt-interface, ip-address",
+ "parameter" : get_params("mgmt_ip")
+ })
+ confparam.config_parameter_source.append(src)
+ src = confparam.create_config_parameter_source()
+ src.from_dict({
+ "name": "mgmt_port",
+ "description": "Management port",
+ "descriptor": "../../../../mgmt-interface/port",
+ "parameter" : get_params("mgmt_port")
+ })
+ confparam.config_parameter_source.append(src)
+ src = confparam.create_config_parameter_source()
+ src.from_dict({
+ "name": "username",
+ "description": "Management username",
+ "value": "admin",
+ "parameter" : get_params("username")
+ })
+ confparam.config_parameter_source.append(src)
+ src = confparam.create_config_parameter_source()
+ src.from_dict({
+ "name": "password",
+ "description": "Management password",
+ "value": "admin",
+ "parameter" : get_params("password")
+ })
+ confparam.config_parameter_source.append(src)
+
+ # Check if pong
+ if 'pong_' in self.name:
+ src = confparam.create_config_parameter_source()
+ src.from_dict({
+ "name": "service_ip",
+ "description": "IP on which Pong service is listening",
+ "attribute": "../../../../connection-point[name='pong_vnfd/cp0'], ip-address",
+ "parameter" : [
+ {
+ "config_primitive_name_ref": "config",
+ "config_primitive_parameter_ref": "service_ip"
+ },
+ ]
+ })
+ confparam.config_parameter_source.append(src)
+ src = confparam.create_config_parameter_source()
+ src.from_dict({
+ "name": "service_port",
+ "description": "Port on which server listens for incoming data packets",
+ "value": "5555",
+ "parameter" : [
+ {
+ "config_primitive_name_ref": "config",
+ "config_primitive_parameter_ref": "service_port"
+ },
+ ]
+ })
+ confparam.config_parameter_source.append(src)
+
+ else:
+ src = confparam.create_config_parameter_source()
+ src.from_dict({
+ "name": "rate",
+ "description": "Rate of packet generation",
+ "value": "5",
+ "parameter" : [
+ {
+ "config_primitive_name_ref": "set-rate",
+ "config_primitive_parameter_ref": "rate"
+ },
+ ]
+ })
+ confparam.config_parameter_source.append(src)
+
+ req = confparam.create_config_parameter_request()
+ req.from_dict({
+ "name": "pong_ip",
+ "description": "IP on which Pong service is listening",
+ "parameter" : [
+ {
+ "config_primitive_name_ref": "config",
+ "config_primitive_parameter_ref": "pong_ip"
+ },
+ ]
+ })
+ confparam.config_parameter_request.append(req)
+ req = confparam.create_config_parameter_request()
+ req.from_dict({
+ "name": "pong_port",
+ "description": "Port on which Pong service is listening",
+ "parameter" : [
+ {
+ "config_primitive_name_ref": "config",
+ "config_primitive_parameter_ref": "pong_port"
+ },
+ ]
+ })
+ confparam.config_parameter_request.append(req)
+
+ def add_ping_config(self, mano_ut=False, use_ns_init_conf=False):
+ vnfd = self.descriptor.vnfd[0]
+ # Add vnf configuration
+ vnf_config = vnfd.vnf_configuration
+
+ # vnf_config.config_attributes.config_delay = 10
+
+ # Select "script" configuration
+ vnf_config.script.script_type = 'bash'
+
+ # Add config primitive
+ vnf_config.create_config_primitive()
+ prim = VnfdYang.ConfigPrimitive.from_dict({
+ "name": "config",
+ "parameter": [
+ {"name": "mgmt_ip", "data_type": "STRING"},
+ {"name": "mgmt_port", "data_type": "INTEGER"},
+ {"name": "username", "data_type": "STRING"},
+ {"name": "password", "data_type": "STRING"},
+ {"name": "pong_ip", "data_type": "STRING"},
+ {"name": "pong_port", "data_type": "INTEGER",
+ "default_value": "5555"},
+ ],
+ "user_defined_script": "ping_setup.py",
+ })
+ vnf_config.config_primitive.append(prim)
+
+ prim = VnfdYang.ConfigPrimitive.from_dict({
+ "name": "set-rate",
+ "parameter": [
+ {"name": "mgmt_ip", "data_type": "STRING"},
+ {"name": "mgmt_port", "data_type": "INTEGER"},
+ {"name": "username", "data_type": "STRING"},
+ {"name": "password", "data_type": "STRING"},
+ {"name": "rate", "data_type": "INTEGER",
+ "default_value": "5"},
+ ],
+ "user_defined_script": "ping_rate.py",
+ })
+ vnf_config.config_primitive.append(prim)
+
+ prim = VnfdYang.ConfigPrimitive.from_dict({
+ "name": "start-stop",
+ "parameter": [
+ {"name": "mgmt_ip", "data_type": "STRING"},
+ {"name": "mgmt_port", "data_type": "INTEGER"},
+ {"name": "username", "data_type": "STRING"},
+ {"name": "password", "data_type": "STRING"},
+ {"name": "start", "data_type": "BOOLEAN",
+ "default_value": "true"}
+ ],
+ "user_defined_script": "ping_start_stop.py",
+ })
+ vnf_config.config_primitive.append(prim)
+
+ # Add initial config primitive
+ vnf_config.create_initial_config_primitive()
+ init_config = VnfdYang.InitialConfigPrimitive.from_dict(
+ {
+ "seq": 1,
+ "config_primitive_ref": "config",
+ }
+ )
+ vnf_config.initial_config_primitive.append(init_config)
+
+ init_config = VnfdYang.InitialConfigPrimitive.from_dict(
+ {
+ "seq": 2,
+ "config_primitive_ref": "set-rate",
+ },
+ )
+ vnf_config.initial_config_primitive.append(init_config)
+
+ if use_ns_init_conf is False:
+ init_config = VnfdYang.InitialConfigPrimitive.from_dict(
+ {
+ "seq": 3,
+ "config_primitive_ref": "start-stop",
+ },
+ )
+ vnf_config.initial_config_primitive.append(init_config)
+
+ def add_pong_config(self, mano_ut=False, use_ns_init_conf=False):
+ vnfd = self.descriptor.vnfd[0]
+ # Add vnf configuration
+ vnf_config = vnfd.vnf_configuration
+
+ # Select "script" configuration
+ vnf_config.script.script_type = 'bash'
+
+ # Add config primitive
+ vnf_config.create_config_primitive()
+ prim = VnfdYang.ConfigPrimitive.from_dict({
+ "name": "config",
+ "parameter": [
+ {"name": "mgmt_ip", "data_type": "STRING"},
+ {"name": "mgmt_port", "data_type": "INTEGER"},
+ {"name": "username", "data_type": "STRING"},
+ {"name": "password", "data_type": "STRING"},
+ {"name": "service_ip", "data_type": "STRING"},
+ {"name": "service_port", "data_type": "INTEGER"},
+ ],
+ "user_defined_script": "pong_setup.py",
+ })
+ vnf_config.config_primitive.append(prim)
+
+ prim = VnfdYang.ConfigPrimitive.from_dict({
+ "name": "start-stop",
+ "parameter": [
+ {"name": "mgmt_ip", "data_type": "STRING"},
+ {"name": "mgmt_port", "data_type": "INTEGER"},
+ {"name": "username", "data_type": "STRING"},
+ {"name": "password", "data_type": "STRING"},
+ {"name": "start", "data_type": "BOOLEAN",
+ "default_value": "true"}
+ ],
+ "user_defined_script": "pong_start_stop.py",
+ })
+ vnf_config.config_primitive.append(prim)
+
+ # Add initial config primitive
+ vnf_config.create_initial_config_primitive()
+ init_config = VnfdYang.InitialConfigPrimitive.from_dict(
+ {
+ "seq": 1,
+ "config_primitive_ref": "config",
+ }
+ )
+ vnf_config.initial_config_primitive.append(init_config)
+
+ if use_ns_init_conf is False:
+ init_config = VnfdYang.InitialConfigPrimitive.from_dict(
+ {
+ "seq": 2,
+ "config_primitive_ref": "start-stop",
+ },
+ )
+ vnf_config.initial_config_primitive.append(init_config)
+
def compose(self, image_name, cloud_init="", cloud_init_file="", endpoint=None, mon_params=[],
mon_port=8888, mgmt_port=8888, num_vlr_count=1, num_ivlr_count=1,
- num_vms=1, image_md5sum=None, mano_ut=False):
+ num_vms=1, image_md5sum=None, mano_ut=False, use_ns_init_conf=False,
+ use_vca_conf=False):
self.descriptor = RwVnfdYang.YangData_Vnfd_VnfdCatalog()
self.id = str(uuid.uuid1())
vnfd = self.descriptor.vnfd.add()
if aws:
vdu.cloud_init += " - [ systemctl, restart, --no-block, elastic-network-interfaces.service ]\n"
+ # Add VNF access point
+ if use_vca_conf:
+ self.add_vnf_access_point(mano_ut=mano_ut)
+ if 'pong_' in self.name:
+ self.add_pong_config(mano_ut=mano_ut,
+ use_ns_init_conf=use_ns_init_conf)
+ else:
+ self.add_ping_config(mano_ut=mano_ut,
+ use_ns_init_conf=use_ns_init_conf)
+
# sepcify the guest EPA
if use_epa:
vdu.guest_epa.trusted_execution = False
internal_cp.name = cp_name + "/icp{}".format(i)
internal_cp.id = cp_name + "/icp{}".format(i)
internal_cp.type_yang = 'VPORT'
- ivld_cp = internal_vlds[i].internal_connection_point_ref.add()
+ ivld_cp = internal_vlds[i].internal_connection_point.add()
ivld_cp.id_ref = internal_cp.id
internal_interface = vdu.internal_interface.add()
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)
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:
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):
# Config parameters can be taken from config.yaml and
# actions from actions.yaml in the charm
# Config to set the home domain
- vnf_config.create_service_primitive()
- config = VnfdYang.ServicePrimitive.from_dict({
+ vnf_config.create_config_primitive()
+ config = VnfdYang.ConfigPrimitive.from_dict({
"name": "config",
"parameter": [
{"name": "home_domain", "data_type": "STRING"},
{"name": "password", "data_type": "STRING"},
]
})
- vnf_config.service_primitive.append(config)
+ vnf_config.config_primitive.append(config)
- config = VnfdYang.ServicePrimitive.from_dict({
+ config = VnfdYang.ConfigPrimitive.from_dict({
"name": "create-update-user",
# "user-defined-script":"/tmp/test.py",
"parameter": [
{"name": "password", "data_type": "STRING", "mandatory": True},
]
})
- vnf_config.service_primitive.append(config)
+ vnf_config.config_primitive.append(config)
- config = VnfdYang.ServicePrimitive.from_dict({
+ config = VnfdYang.ConfigPrimitive.from_dict({
"name": "delete-user",
"parameter": [
{"name": "number", "data_type": "STRING", "mandatory": True},
]
})
- vnf_config.service_primitive.append(config)
+ vnf_config.config_primitive.append(config)
def default_config(self, const_vnfd, vnfd, mano_ut, use_ns_init_conf):
vnf_config = vnfd.vnfd.vnf_configuration
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',
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):
self.nsd.monitoring_param.append(nsd_monp)
param_id += 1
+ def add_confparam_map(self):
+ nsd = self.nsd
+ confparam_map = nsd.config_parameter_map.add()
+ confparam_map.id = '1'
+ confparam_map.config_parameter_source.member_vnf_index_ref = 2
+ confparam_map.config_parameter_source.config_parameter_source_ref = 'service_ip'
+ confparam_map.config_parameter_request.member_vnf_index_ref = 1
+ confparam_map.config_parameter_request.config_parameter_request_ref = 'pong_ip'
+ confparam_map = nsd.config_parameter_map.add()
+ confparam_map.id = '2'
+ confparam_map.config_parameter_source.member_vnf_index_ref = 2
+ confparam_map.config_parameter_source.config_parameter_source_ref = 'service_port'
+ confparam_map.config_parameter_request.member_vnf_index_ref = 1
+ confparam_map.config_parameter_request.config_parameter_request_ref = 'pong_port'
- def compose(self, vnfd_list, cpgroup_list, mano_ut, use_ns_init_conf=True):
+ def compose(self, vnfd_list, cpgroup_list, mano_ut,
+ use_ns_init_conf=True,
+ use_vca_conf=False):
if mano_ut:
# Disable NS initial config primitive
constituent_vnfd.start_by_default = False
constituent_vnfd.vnfd_id_ref = vnfd.descriptor.vnfd[0].id
- self.default_config(constituent_vnfd, vnfd, mano_ut,
- use_ns_init_conf,)
+ if use_vca_conf is False:
+ self.default_config(constituent_vnfd, vnfd, mano_ut,
+ use_ns_init_conf)
member_vnf_index += 1
# Enable config primitives if either mano_ut or
member.member_vnf_index_ref = vnfd_index_map[member_vnfd]
# self.create_mon_params(vnfd_list)
+ if use_vca_conf:
+ self.add_confparam_map()
def write_config(self, outdir, vnfds):
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):
ex_pong_userdata=None,
use_placement_group=True,
use_ns_init_conf=True,
+ use_vca_conf=True,
):
# List of connection point groups
# Each connection point group refers to a virtual link
num_vms=num_vnf_vms,
image_md5sum=ping_md5sum,
mano_ut=mano_ut,
+ use_ns_init_conf=use_ns_init_conf,
+ use_vca_conf=use_vca_conf,
)
pong = VirtualNetworkFunction("pong_vnfd%s" % (suffix))
num_vms=num_vnf_vms,
image_md5sum=pong_md5sum,
mano_ut=mano_ut,
+ use_ns_init_conf=use_ns_init_conf,
+ use_vca_conf=use_vca_conf,
)
# Initialize the member VNF index
nsd_catalog.compose(vnfd_list,
cpgroup_list,
mano_ut,
- use_ns_init_conf=use_ns_init_conf,)
+ use_ns_init_conf=use_ns_init_conf,
+ use_vca_conf=use_vca_conf,
+ )
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)
--- /dev/null
+#!/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()
--- /dev/null
+#!/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 stat
+import subprocess
+import sys
+import time
+import yaml
+
+def ping_config(run_dir, mgmt_ip, mgmt_port, pong_cp, logger, dry_run):
+ sh_file = "{}/ping_config-{}.sh".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
+ logger.debug("Creating script file %s" % sh_file)
+ f = open(sh_file, "w")
+ f.write(r'''
+#!/bin/bash
+
+# Rest API config
+ping_mgmt_ip='{}'
+ping_mgmt_port={}
+
+# VNF specific configuration
+pong_server_ip='{}'
+ping_rate=5
+server_port=5555
+'''.format(mgmt_ip, mgmt_port, pong_cp))
+
+ f.write(r'''
+# Check if the port is open
+DELAY=1
+MAX_TRIES=60
+COUNT=0
+while true; do
+ COUNT=$(expr $COUNT + 1)
+ timeout 1 bash -c "cat < /dev/null > /dev/tcp/${ping_mgmt_ip}/${ping_mgmt_port}"
+ rc=$?
+ if [ $rc -ne 0 ]
+ then
+ echo "Failed to connect to server ${ping_mgmt_ip}:${ping_mgmt_port} for ping with $rc!"
+ if [ ${COUNT} -gt ${MAX_TRIES} ]; then
+ exit $rc
+ fi
+ sleep ${DELAY}
+ else
+ break
+ fi
+done
+
+# Make rest API calls to configure VNF
+curl -D /dev/stdout \
+ -H "Accept: application/vnd.yang.data+xml" \
+ -H "Content-Type: application/vnd.yang.data+json" \
+ -X POST \
+ -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \
+ http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/server
+rc=$?
+if [ $rc -ne 0 ]
+then
+ echo "Failed to set server info for ping!"
+ exit $rc
+fi
+
+curl -D /dev/stdout \
+ -H "Accept: application/vnd.yang.data+xml" \
+ -H "Content-Type: application/vnd.yang.data+json" \
+ -X POST \
+ -d "{\"rate\":$ping_rate}" \
+ http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/rate
+rc=$?
+if [ $rc -ne 0 ]
+then
+ echo "Failed to set ping rate!"
+ exit $rc
+fi
+
+output=$(curl -D /dev/stdout \
+ -H "Accept: application/vnd.yang.data+xml" \
+ -H "Content-Type: application/vnd.yang.data+json" \
+ -X POST \
+ -d "{\"enable\":true}" \
+ http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/adminstatus/state)
+if [[ $output == *"Internal Server Error"* ]]
+then
+ echo $output
+ exit 3
+else
+ echo $output
+fi
+
+exit 0
+''')
+ f.close()
+ os.chmod(sh_file, stat.S_IRWXU)
+ if not dry_run:
+ rc = subprocess.call(sh_file, shell=True)
+ if rc:
+ logger.error("Config failed: {}".format(rc))
+ return False
+ return True
+
+
+
+def main(argv=sys.argv[1:]):
+ try:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("yaml_cfg_file", type=argparse.FileType('r'))
+ parser.add_argument("--dry-run", action="store_true")
+ parser.add_argument("--quiet", "-q", 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 = "{}/rift_ping_config-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S"))
+ logging.basicConfig(filename=log_file, level=logging.DEBUG)
+ logger = logging.getLogger()
+
+ 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')
+ ch.setFormatter(formatter)
+ logger.addHandler(ch)
+
+ except Exception as e:
+ print("Got exception:{}".format(e))
+ raise e
+
+ try:
+ dry_run = args.dry_run
+
+ yaml_str = args.yaml_cfg_file.read()
+ logger.debug("Input YAML file: {}".format(yaml_str))
+ yaml_cfg = yaml.load(yaml_str)
+ logger.debug("Input YAML: {}".format(yaml_cfg))
+
+ # Check if this is post scale out trigger
+ if yaml_cfg['trigger'] != 'post_scale_out':
+ logger.error("Unexpected trigger {}".
+ format(yaml_cfg['trigger']))
+ raise
+
+ pong_cp = ""
+ for vnfr in yaml_cfg['vnfrs_others']:
+ # Find the pong VNFR, assuming vnfr name will
+ # have pong_vnfd as a substring
+ if 'pong_vnfd' in vnfr['name']:
+ for cp in vnfr['connection_points']:
+ logger.debug("Connection point {}".format(cp))
+ if 'cp0' in cp['name']:
+ pong_cp = cp['ip_address']
+ break
+ if not len(pong_cp):
+ logger.error("Did not get Pong cp0 IP")
+ raise
+
+ for vnfr in yaml_cfg['vnfrs_in_group']:
+ mgmt_ip = vnfr['rw_mgmt_ip']
+ mgmt_port = vnfr['rw_mgmt_port']
+ if ping_config(run_dir, mgmt_ip, mgmt_port, pong_cp, logger, dry_run):
+ logger.info("Successfully configured Ping {} at {}".
+ format(vnfr['name'], mgmt_ip))
+ else:
+ logger.error("Config of ping {} with {} failed".
+ format(vnfr['name'], mgmt_ip))
+ raise
+
+ except Exception as e:
+ logger.error("Got exception {}".format(e))
+ logger.exception(e)
+ raise e
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+#!/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()
--- /dev/null
+#!/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()
--- /dev/null
+#!/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()
--- /dev/null
+#!/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()
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():
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():
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()
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)
+
+ fh = logging.FileHandler(log_file)
+ fh.setLevel(logging.DEBUG)
- try:
ch = logging.StreamHandler()
if args.verbose:
ch.setLevel(logging.DEBUG)
# 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()
"The value should be greyed out by the UI.
Only applies to parameters with default values.";
type boolean;
+ default false;
}
leaf hidden {
"The value should be hidden by the UI.
Only applies to parameters with default values.";
type boolean;
+ default false;
+ }
+
+ leaf out {
+ description "If this is an output of the primitive execution";
+ type boolean;
+ default false;
}
leaf parameter-type {
description "Type of this parameter, whether this in IN or OUT";
}
}
- list service-primitive {
- rwpb:msg-new ServicePrimitive;
+ list config-primitive {
+ rwpb:msg-new ConfigPrimitive;
description
- "List of service primitives supported by the
+ "List of config primitives supported by the
configuration agent for this VNF.";
key "name";
leaf name {
description
- "Name of the service primitive.";
+ "Name of the config primitive.";
type string;
}
list parameter {
description
- "List of parameters to the service primitive.";
+ "List of parameters to the config primitive.";
key "name";
uses primitive-parameter;
}
+
+ leaf user-defined-script {
+ description
+ "A user defined script. If user defined script is defined,
+ the script will be executed using bash";
+ type string;
+ }
}
list initial-config-primitive {
type uint64;
}
- leaf name {
- description
- "Name of the configuration primitive.";
- type string;
- }
+ choice primtive-type {
+ case primtive-definition {
+ leaf name {
+ description
+ "Name of the configuration primitive.";
+ type string;
+ }
- list parameter {
- key "name";
- leaf name {
- type string;
+ uses primitive-parameter-value;
}
- leaf value {
- type string;
+ case primitive-ref {
+ leaf config-primitive-ref {
+ description
+ "Reference to a config primitive name.
+ NOTE: The config primitive referred should have
+ all the input paramaters predefined either
+ with default values or dependency references.";
+ type leafref {
+ path "../../config-primitive/name";
+ }
+ }
}
}
}
}
}
- list vnfap-map {
- key "id";
- description "A mapping of VNF application point
- capability/dependency within this network service";
- leaf id {
- description "Identfier for VNF access point map";
- type string;
- }
- container capability {
- leaf member-vnf-index-ref {
- description "Reference to member-vnf within constituent-vnfds";
- type leafref {
- path "../../../../constituent-vnfd/member-vnf-index";
- }
- }
- leaf capability-ref {
- description "Reference to the capability with the capability of the VNF
- with the specified member-vnf-index";
- type leafref {
- path "/vnfd:vnfd-catalog/vnfd:vnfd/vnfd:vnfap/vnfd:capability/vnfd:name";
- }
- }
- }
- container dependency {
- leaf member-vnf-index-ref {
- description "Reference to member-vnf within constituent-vnfds";
- type leafref {
- path "../../../../constituent-vnfd/member-vnf-index";
- }
- }
- leaf dependency-ref {
- description "Reference to the dependency within the dependency of the VNF
- with the specified member-vnf-index";
- type leafref {
- path "/vnfd:vnfd-catalog/vnfd:vnfd/vnfd:vnfap/vnfd:dependency/vnfd:name";
- }
- }
- }
- }
-
// replicate for pnfd container here
uses manotypes:provider-network;
}
}
+ list config-parameter-map {
+ key "id";
+ description "A mapping of VNF config parameter
+ requests and sources within this network service";
+ leaf id {
+ description "Identfier for VNF map";
+ type string;
+ }
+ container config-parameter-request {
+ leaf member-vnf-index-ref {
+ description "Reference to member-vnf within constituent-vnfds";
+ type leafref {
+ path "../../../constituent-vnfd/member-vnf-index";
+ }
+ }
+ leaf config-parameter-request-ref {
+ description "Reference to the request in the VNF
+ with the specified member-vnf-index";
+ type leafref {
+ path "/vnfd:vnfd-catalog/vnfd:vnfd/vnfd:config-parameter/vnfd:config-parameter-request/vnfd:name";
+ }
+ }
+ }
+ container config-parameter-source {
+ leaf member-vnf-index-ref {
+ description "Reference to member-vnf within constituent-vnfds";
+ type leafref {
+ path "../../../constituent-vnfd/member-vnf-index";
+ }
+ }
+ leaf config-parameter-source-ref {
+ description "Reference to the source in the VNF
+ with the specified member-vnf-index";
+ type leafref {
+ path "/vnfd:vnfd-catalog/vnfd:vnfd/vnfd:config-parameter/vnfd:config-parameter-source/vnfd:name";
+ }
+ }
+ }
+ }
+
list scaling-group-descriptor {
description
"scaling group descriptor within this network service.
}
}
- grouping vnf-access-point {
- list vnfap {
- description "List of VNF access points";
- key "name";
- leaf name {
- description "Name of the vnf access point";
- type string {
- length 128;
- }
- }
- leaf description {
- description "A description of this VNF access point";
- type string;
- }
- list capability {
- description "The List of capabilities of this VNF access point";
+ grouping config-parameter {
+ container config-parameter {
+ rwpb:msg-new ConfigParams;
+ description
+ "List of VNF config parameter requests and sources";
+ list config-parameter-source {
+ description "The list of parameters exposed by this VNF";
key "name";
+
leaf name {
- description "Name of the capability";
+ description "Name of the source";
type string {
- length 128;
+ length "1..128";
}
}
+
leaf description {
- description "A description of the capability";
+ description " Description of the source";
type string;
}
- choice capability-location {
- case location-path {
- leaf xpath {
- description "Location of this capaibility as an xpath.
- This field points to an element within vnfd
- with the xpath notation and additionally
- provides the flexibility to choose attributes
- within the instantiated version of this object.
- For example,
- /vnfd-catalog/vnfd[id='xyz']/connection-point[name='cp1']/ip_address()
- refers to the ip address of the connection point with name 'cp1'
- in VNFD with id 'xyz'.";
+
+ choice source {
+ case descriptor {
+ leaf descriptor {
+ description
+ "Location of this source as an xpath.
+ For example:
+ ../../../mgmt-interface/port";
type string;
}
}
- case location-primitive-ref {
- leaf config-primitive-name-ref {
- description "A leafref to configuration primitive.
- This field contains a link to the config primitive
- the output paramaters of which will satisfy this requirement.";
- type leafref {
- path "/vnfd:vnfd-catalog/vnfd/vnf-configuration/service-primitive/name";
- }
+
+ case attirbute {
+ leaf attribute {
+ description
+ "Location of this source as runtime attribute.
+ The value is <xpath>, <attribute_name>
+ For example:
+ ../../../mgmt-interface, ip-address
+ which retruns the ip-address assigned to the
+ mgmt-interface after VNF instantiation.";
+ type string;
}
}
- case user-input {
- list user-input {
- key "name";
- description "User input for this capability";
- leaf name {
- description "Name of this input";
- type string;
+
+ case primitive-ref {
+ leaf config-primitive-name-ref {
+ description
+ "A leafref to configuration primitive.
+ This refers to a config parameter whose
+ output parameter is referred in out-parameter.";
+ type leafref {
+ path "../../../vnf-configuration/config-primitive/name";
}
- leaf value {
- description "Value of this input";
- type string;
+ }
+
+ leaf parameter-ref {
+ description
+ "Name of the output parameter in the config primitiive";
+ type leafref {
+ path
+ "../../../vnf-configuration/config-primitive[name=current()/../config-primitive-name-ref]/parameter/name";
}
}
}
+
+ case value {
+ leaf value {
+ description
+ "Pre-defined value to be used for this source";
+ type string;
+ }
+ }
+ }
+
+ list parameter {
+ key "config-primitive-name-ref";
+
+ leaf config-primitive-name-ref {
+ description
+ "Name of the configuration primitive where this
+ request will used";
+ type leafref {
+ path "../../../../vnf-configuration/config-primitive/name";
+ }
+ }
+
+ leaf config-primitive-parameter-ref {
+ description
+ "Parameter name of the config primitive";
+ type leafref {
+ path "../../../../vnf-configuration/config-primitive[name=current()/../config-primitive-name-ref]/parameter/name";
+ }
+ }
}
}
- list dependency {
- description "The List of depenencies of this VNF access point";
+
+ list config-parameter-request {
+ description "The list of requests for this VNF";
key "name";
+
leaf name {
- description "Name of this VNF access point";
+ description "Name of this parameter request";
type string {
- length 128;
+ length "1..128";
}
}
- leaf mandatory {
- description "Is this dependcy mandatory for this dependency";
- type boolean;
- }
+
leaf description {
- description "A description of the dependency";
+ description "Description of this request";
type string;
}
- leaf config-primitive-name-ref {
- description "A leafref to configuration primitive.
- This field contains a link to the config primitive
- the input paramaters of which will satisfy this requirement.";
- type leafref {
- path "/vnfd:vnfd-catalog/vnfd/vnf-configuration/service-primitive/name";
+
+ list parameter {
+ key "config-primitive-name-ref";
+
+ leaf config-primitive-name-ref {
+ description
+ "Name of the configuration primitive where this
+ request will used";
+ type leafref {
+ path "../../../../vnf-configuration/config-primitive/name";
+ }
+ }
+
+ leaf config-primitive-parameter-ref {
+ description
+ "Parameter name of the config primitive";
+ type leafref {
+ path "../../../../vnf-configuration/config-primitive[name=current()/../config-primitive-name-ref]/parameter/name";
+ }
}
}
}
uses manotypes:vnf-configuration;
+ uses config-parameter;
+
container mgmt-interface {
description
"Interface over which the VNF is managed.";
key "id";
uses vnfd-descriptor;
-
- uses vnf-access-point;
}
}
}
import rwlogger
import neutronclient.common.exceptions as NeutronException
import keystoneclient.exceptions as KeystoneExceptions
-<<<<<<< 06b6ab4edf863c75fc6e2947ad52d1c76de1a308
import tornado
import gi
gi.require_version('RwSdn', '1.0')
-=======
->>>>>>> RIFT-14308 Meaningful logs while initalizing Openstack driver
from gi.repository import (
GObject,
import asyncio
import concurrent.futures
+import os
import re
+import shlex
import tempfile
import yaml
-import os
from gi.repository import (
RwDts as rwdts,
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):
"""
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 is None:
+ # Check if mandatory parameter
+ if param.mandatory:
+ msg = "VNFR {}: Primitive {} called " \
+ "without mandatory parameter {}". \
+ format(vnfr.name, config.name,
+ param.name)
+ self._log.error(msg)
+ return 1, msg
+
+ 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)
+ self._log.debug("VNFR {} primitive {} exec status: {}".
+ format(vnfr.name, primitive.name, rc))
+
+ 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 """
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):
"""
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
if vnf:
self._log.debug("nsr/vnf {}/{}, vnf_configuration: %s",
vnf.vnf_configuration)
- for primitive in vnf.vnf_configuration.service_primitive:
+ for primitive in vnf.vnf_configuration.config_primitive:
if primitive.name == primitive_name:
return primitive
return True
@asyncio.coroutine
- def vnf_config_primitive(self, nsr_id, vnfr_id, primitive, output):
- self._log.debug("jujuCA: VNF config primititve {} for nsr {}, vnfr_id {}".
+ def _vnf_config_primitive(self, nsr_id, vnfr_id, primitive,
+ vnf_config=None):
+ self._log.debug("jujuCA: VNF config primitive {} for nsr {}, "
+ "vnfr_id {}".
format(primitive, nsr_id, vnfr_id))
+
try:
vnfr = self._juju_vnfs[vnfr_id].vnfr
except KeyError:
- self._log.error("jujuCA: Did not find VNFR %s in juju plugin",
- vnfr_id)
+ msg = "Did not find VNFR %s in Juju plugin", vnfr_id
+ self._log.error(msg)
+ output.execution_error_details = msg
return
- output.execution_status = "failed"
- output.execution_id = ''
- output.execution_error_details = ''
+ if vnf_config is None:
+ vnfr_msg = yield from self.get_vnfr(vnfr_id)
+ if vnfr is None:
+ self._log.error("Unable to get VNFR {} through DTS".
+ format(vnfr_id))
+ return 'failed', '', "Unable to get VNFR {} through DTS". \
+ format(vnfr_id)
+
+ vnf_config = vnfr_msg.vnf_configuration
+ self._log.debug("VNF config= %s", vnf_config.as_dict())
try:
service = vnfr['vnf_juju_name']
- vnf_config = vnfr['config']
self._log.debug("VNF config %s", vnf_config)
- configs = vnf_config.service_primitive
+ configs = vnf_config.config_primitive
for config in configs:
if config.name == primitive.name:
self._log.debug("jujuCA: Found the config primitive %s",
config.name)
params = {}
- for parameter in primitive.parameter:
- if parameter.value:
- val = self.xlate(parameter.value, vnfr['tags'])
- # TBD do validation of the parameters
- data_type = 'string'
- found = False
- for ca_param in config.parameter:
- if ca_param.name == parameter.name:
- data_type = ca_param.data_type
- found = True
- break
- if data_type == 'integer':
- val = int(parameter.value)
- if not found:
- self._log.warn("jujuCA: Did not find parameter {} for {}".
- format(parameter, config.name))
+ for parameter in config.parameter:
+ val = None
+ for p in primitive.parameter:
+ if p.name == parameter.name:
+ if p.value:
+ val = self.xlate(p.value, vnfr['tags'])
+ break
+
+ if val is None:
+ val = parameter.default_value
+
+ if val is None:
+ # Check if mandatory parameter
+ if parameter.mandatory:
+ msg = "VNFR {}: Primitive {} called " \
+ "without mandatory parameter {}". \
+ format(vnfr_msg.name, config.name,
+ parameter.name)
+ self._log.error(msg)
+ return 'failed', '', msg
+
+ if val:
+ val = self.convert_value(val, parameter.data_type)
params.update({parameter.name: val})
+ rc = ''
+ exec_id = ''
+ details = ''
if config.name == 'config':
- output.execution_id = 'config'
+ exec_id = 'config'
if len(params):
- self._log.debug("jujuCA: applying config with params {} for service {}".
+ self._log.debug("jujuCA: applying config with "
+ "params {} for service {}".
format(params, service))
- rc = yield from self.api.apply_config(params, service=service, wait=False)
+ rc = yield from self.api.apply_config(
+ params,
+ service=service,
+ wait=False)
if rc:
# Mark as pending and check later for the status
- output.execution_status = "pending"
- self._log.debug("jujuCA: applied config {} on {}".
- format(params, service))
+ rc = "pending"
+ self._log.debug("jujuCA: applied config {} "
+ "on {}".format(params, service))
else:
- output.execution_status = 'failed'
- output.execution_error_details = \
+ rc = 'failed'
+ details = \
'Failed to apply config: {}'.format(params)
- self._log.error("jujuCA: Error applying config {} on service {}".
+ self._log.error("jujuCA: Error applying "
+ "config {} on service {}".
format(params, service))
else:
- self._log.warn("jujuCA: Did not find valid parameters for config : {}".
+ self._log.warn("jujuCA: Did not find valid "
+ "parameters for config : {}".
format(primitive.parameter))
- output.execution_status = "completed"
+ rc = "completed"
else:
- self._log.debug("jujuCA: Execute action {} on service {} with params {}".
+ self._log.debug("jujuCA: Execute action {} on "
+ "service {} with params {}".
format(config.name, service, params))
- resp = yield from self.api.execute_action(config.name,
- params,
- service=service)
+ resp = yield from self.api.execute_action(
+ config.name,
+ params,
+ service=service)
if resp:
if 'error' in resp:
- output.execution_error_details = resp['error']['Message']
+ details = resp['error']['Message']
else:
- output.execution_id = resp['action']['tag']
- output.execution_status = resp['status']
- if output.execution_status == 'failed':
- output.execution_error_details = resp['message']
- self._log.debug("jujuCA: execute action {} on service {} returned {}".
- format(config.name, service, output.execution_status))
+ exec_id = resp['action']['tag']
+ rc = resp['status']
+ if rc == 'failed':
+ details = resp['message']
+
+ self._log.debug("jujuCA: execute action {} on "
+ "service {} returned {}".
+ format(config.name, service, rc))
else:
- self._log.error("jujuCA: error executing action {} for {} with {}".
- format(config.name, service, params))
- output.execution_id = ''
- output.execution_status = 'failed'
- output.execution_error_details = "Failed to queue the action"
+ self._log.error("jujuCA: error executing action "
+ "{} for {} with {}".
+ format(config.name, service,
+ params))
+ exec_id = ''
+ rc = 'failed'
+ details = "Failed to queue the action"
break
except KeyError as e:
- self._log.info("VNF %s does not have config primititves, e=%s", vnfr_id, e)
+ msg = "VNF %s does not have config primitives, e=%s", \
+ vnfr_msg.name, e
+ self._log.error(msg)
+ raise ValueError(msg)
+
+ return rc, exec_id, details
+
+ @asyncio.coroutine
+ def vnf_config_primitive(self, nsr_id, vnfr_id, primitive, output):
+ output.execution_status = "failed"
+ output.execution_id = ''
+ output.execution_error_details = ''
+
+ rc, exec_id, err = yield from self._vnf_config_primitive(
+ nsr_id,
+ vnfr_id,
+ primitive)
+
+ self._log.debug("VNFR {} primitive {} exec status: {}".
+ format(vnfr.name, primitive.name, rc))
+ output.execution_status = rc
+ output.execution_id = exec_id
+ output.execution_error_details = err
@asyncio.coroutine
def apply_config(self, agent_nsr, agent_vnfr, config, rpc_ip):
Actions in initial config may not work based on charm design
"""
- vnfr = agent_vnfr.vnfr
- service = vnfr['vnf_juju_name']
+ try:
+ vnfr = self._juju_vnfs[agent_vnfr.id].vnfr
+ except KeyError:
+ self._log.error("Did not find VNFR %s in Juju plugin",
+ agent_vnfr.name)
+ return False
+
+ vnfr_msg = yield from self.get_vnfr(agent_vnfr.id)
+ if vnfr_msg 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_msg.vnf_configuration
+ self._log.debug("VNFR %s config: %s", vnfr_msg.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_msg.name))
+ return True
+ service = vnfr['vnf_juju_name']
rc = yield from self.api.is_service_up(service=service)
if not rc:
return False
action_ids = []
try:
- vnf_cat = agent_vnfr.vnfr_msg
- if vnf_cat and vnf_cat.mgmt_interface.ip_address:
- vnfr['tags'].update({'rw_mgmt_ip': vnf_cat.mgmt_interface.ip_address})
+ if vnfr_msg.mgmt_interface.ip_address:
+ vnfr['tags'].update({'rw_mgmt_ip': vnfr_msg.mgmt_interface.ip_address})
self._log.debug("jujuCA:(%s) tags: %s", vnfr['vnf_juju_name'], vnfr['tags'])
- config = {}
- try:
- for primitive in vnfr['config'].initial_config_primitive:
- self._log.debug("jujuCA:(%s) Initial config primitive %s", vnfr['vnf_juju_name'], primitive)
+ for primitive in primitives:
+ self._log.debug("(%s) Initial config primitive %s",
+ vnfr['vnf_juju_name'], primitive)
+ if primitive.config_primitive_ref:
+ # Reference to a primitive in config primitive
+ class Primitive:
+ def __init__(self, name):
+ self.name = name
+ self.value = None
+ self.parameter = []
+
+ prim = Primitive(primitive.config_primitive_ref)
+ rc, eid, err = yield from self._vnf_config_primitive(
+ agent_nsr.id,
+ agent_vnfr.id,
+ prim,
+ vnf_config)
+
+ if rc == "failed":
+ msg = "Error executing initial config primitive" \
+ " {} in VNFR {}: rc={}, stderr={}". \
+ format(prim.name, vnfr_msg.name, rc, err)
+ self._log.error(msg)
+ return False
+
+ elif rc == "pending":
+ action_ids.append(eid)
+
+ elif primitive.name:
+ config = {}
if primitive.name == 'config':
for param in primitive.parameter:
if vnfr['tags']:
- val = self.xlate(param.value, vnfr['tags'])
+ val = self.xlate(param.value,
+ vnfr['tags'])
config.update({param.name: val})
- except KeyError as e:
- self._log.exception("jujuCA:(%s) Initial config error(%s): config=%s",
- vnfr['vnf_juju_name'], str(e), config)
- config = None
- return False
- if config:
- self.juju_log('info', vnfr['vnf_juju_name'],
- "Applying Initial config:%s",
- config)
+ if config:
+ self.juju_log('info', vnfr['vnf_juju_name'],
+ "Applying Initial config:%s",
+ config)
- rc = yield from self.api.apply_config(config, service=service)
- if rc is False:
- self.log.error("Service {} is in error state".format(service))
- return False
-
-
- # Apply any actions specified as part of initial config
- for primitive in vnfr['config'].initial_config_primitive:
- if primitive.name != 'config':
- self._log.debug("jujuCA:(%s) Initial config action primitive %s",
- vnfr['vnf_juju_name'], primitive)
- action = primitive.name
- params = {}
- for param in primitive.parameter:
- val = self.xlate(param.value, vnfr['tags'])
- params.update({param.name: val})
-
- self._log.info("jujuCA:(%s) Action %s with params %s",
- vnfr['vnf_juju_name'], action, params)
-
- resp = yield from self.api.execute_action(action, params,
- service=service)
- if 'error' in resp:
- self._log.error("Applying initial config on {} failed for {} with {}: {}".
- format(vnfr['vnf_juju_name'], action, params, resp))
- return False
+ rc = yield from self.api.apply_config(
+ config,
+ service=service)
+ if rc is False:
+ self.log.error("Service {} is in error state".
+ format(service))
+ return False
- action_ids.append(resp['action']['tag'])
+ # Apply any actions specified as part of initial config
+ else:
+ self._log.debug("(%s) Initial config action "
+ "primitive %s",
+ vnfr['vnf_juju_name'], primitive)
+ action = primitive.name
+ params = {}
+ for param in primitive.parameter:
+ val = self.xlate(param.value, vnfr['tags'])
+ params.update({param.name: val})
+
+ self._log.info("(%s) Action %s with params %s",
+ vnfr['vnf_juju_name'], action,
+ params)
+
+ resp = yield from self.api.execute_action(
+ action,
+ params,
+ service=service)
+ if 'error' in resp:
+ self._log.error("Applying initial config on {}"
+ " failed for {} with {}: {}".
+ format(vnfr['vnf_juju_name'],
+ action, params, resp))
+ return False
+
+ action_ids.append(resp['action']['tag'])
- except KeyError as e:
- self._log.info("Juju config agent(%s): VNFR %s not managed by Juju",
- vnfr['vnf_juju_name'], agent_vnfr.id)
- return False
except Exception as e:
- self._log.exception("jujuCA:(%s) Exception juju apply_initial_config for VNFR {}: {}".
- format(vnfr['vnf_juju_name'], agent_vnfr.id, e))
+ self._log.exception("jujuCA:(%s) Exception juju "
+ "apply_initial_config for VNFR {}: {}".
+ format(vnfr['vnf_juju_name'],
+ agent_vnfr.id, e))
return False
# Check if all actions completed
for act in action_ids:
resp = yield from self.api.get_action_status(act)
if 'error' in resp:
- self._log.error("Initial config failed: {}".format(resp))
+ self._log.error("Initial config failed for action {}: {}".
+ format(act, resp))
return False
if resp['status'] == 'failed':
- self._log.error("Initial config action failed: {}".format(resp))
+ self._log.error("Initial config action failed for "
+ "action {}: {}".format(act, resp))
return False
if resp['status'] == 'pending':
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
def nsr_cfg_msg(self):
return self._cfg
+ @property
+ def nsd(self):
+ return self._cfg.nsd
+
@property
def job_id(self):
''' Get a new job id for config primitive'''
def member_vnf_index(self):
return self._vnfr['member_vnf_index_ref']
- def add_vnfr(self, vnfr, vnfr_msg):
+ def add_vnfr(self, vnfr, vnfr_msg, vnfd):
if vnfr['id'] in self._vnfr_ids.keys():
agent_vnfr = self._vnfr_ids[vnfr['id']]
else:
- agent_vnfr = RiftCMvnfr(self.name, vnfr, vnfr_msg)
+ agent_vnfr = RiftCMvnfr(self.name, vnfr, vnfr_msg, vnfd)
self._vnfrs.append(agent_vnfr)
self._vnfrs_msg.append(vnfr_msg)
self._vnfr_ids[agent_vnfr.id] = agent_vnfr
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
'''
- def __init__(self, nsr_name, vnfr_dict, vnfr_msg):
+ def __init__(self, nsr_name, vnfr_dict, vnfr_msg, vnfd):
self._vnfr = vnfr_dict
self._vnfr_msg = vnfr_msg
+ self._vnfd_msg = vnfd
self._nsr_name = nsr_name
self._configurable = False
def vnfr_msg(self):
return self._vnfr_msg
+ @property
+ def vnfd(self):
+ return self._vnfd_msg
+
@property
def name(self):
return self._vnfr['short_name']
"""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:
+ if rc == 0:
+ 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:
self._log.error("Unknown method %s invoked on config agent plugin",
method)
except Exception as e:
- self._log.error("Caught exception while invoking method: %s, Exception: %s", method, str(e))
- raise
+ self._log.exception("Caught exception while invoking method: %s, "
+ "Exception: %s", method, str(e))
+ raise e
+
return rc
rc = yield from agent.invoke(method, nsr, vnfr, *args)
break
except Exception as e:
- self._log.error("Error invoking {} on {} : {}".
- format(method, agent.name, e))
- raise
+ self._log.exception("Error invoking {} on {} : {}".
+ format(method, agent.name, e))
+ raise e
self._log.info("vnfr({}), method={}, return rc={}"
.format(vnfr.name, method, rc))
done = False
if 'nsrid' in task:
nsrid = task['nsrid']
- self._log.debug("Will execute pending task for NSR id(%s)", nsrid)
+ self._log.debug("Will execute pending task for NSR id: %s", nsrid)
try:
# Try to configure this NSR
task['retries'] -= 1
self.pending_tasks.remove(task)
if done:
- self._log.debug("Finished pending task NSR id(%s):", nsrid)
+ self._log.debug("Finished pending task NSR id: %s", nsrid)
else:
self._log.error("Failed configuring NSR(%s), retries remained:%d!",
nsrid, task['retries'])
# 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):
except Exception as e:
self._log.error("Failed to register for opdata as (%s)", e)
+ def get_config_method(self, vnf_config):
+ cfg_types = ['netconf', 'juju', 'script']
+ for method in cfg_types:
+ if method in vnf_config:
+ return method
+ return None
+
@asyncio.coroutine
def process_nsd_vnf_configuration(self, nsr_obj, vnfr):
- def get_config_method(vnf_config):
- cfg_types = ['netconf', 'juju', 'script']
- for method in cfg_types:
- if method in vnf_config:
- return method
- return None
-
def get_cfg_file_extension(method, configuration_options):
ext_dict = {
"netconf" : "xml",
target : running
'''
+ # Get vnf_configuration from vnfr
+ vnf_config = vnfr['vnf_configuration']
+
# Save some parameters needed as short cuts in flat structure (Also generated)
vnf_cfg = vnfr['vnf_cfg']
# Prepare unique name for this VNF
nsr_vnfr = '{}/{}_{}'.format(
vnf_cfg['nsr_name'], vnfr['short_name'], vnfr['member_vnf_index_ref'])
- # Get vnf_configuration from vnfr
- vnf_config = vnfr['vnf_configuration']
-
self._log.debug("vnf_configuration = %s", vnf_config)
# Create priority dictionary
# No VNFR with this priority yet, initialize the list
nsr_obj.nsr_cfg_config_attributes_dict[cfg_priority_order] = []
- method = get_config_method(vnf_config)
+ method = self.get_config_method(vnf_config)
if method is not None:
# Create all sub dictionaries first
config_priority = {
'member_vnf_index' : vnfr['member_vnf_index_ref'],
}
- if 'config_delay' in vnf_config['config_attributes']:
- config_priority['configuration_delay'] = vnf_config['config_attributes']['config_delay']
- vnf_cfg['config_delay'] = config_priority['configuration_delay']
+ if ('config_attributes' in vnf_config) and \
+ ('config_delay' in vnf_config['config_attributes']):
+ config_priority['configuration_delay'] = vnf_config['config_attributes']['config_delay']
+ vnf_cfg['config_delay'] = config_priority['configuration_delay']
+ else:
+ vnf_cfg['config_delay'] = 0
configuration_options = {}
self._log.debug("config method=%s", method)
vnf_cp_dict['rw_mgmt_ip'] = vnf_cfg['mgmt_ip_address']
vnf_cp_dict['rw_username'] = vnf_cfg['username']
vnf_cp_dict['rw_password'] = vnf_cfg['password']
-
- # TBD - see if we can neatly include the config in "config_attributes" file, no need though
- #config_priority['config_template'] = vnf_config['config_template']
- # Create config file
- vnf_cfg['juju_script'] = os.path.join(self._parent.cfg_dir, 'juju_if.py')
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
# Update the cm-state
nsr_obj.populate_vm_state_from_vnf_cfg()
+ @asyncio.coroutine
+ 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'])
+ srcs = cm_state['config_parameter']['config_parameter_source']
+ reqs = cm_state['config_parameter']['config_parameter_request']
+
+ 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 src in srcs:
+ for p in src['parameter']:
+ if (p['config_primitive_ref'] == confp['name']) \
+ and (p['parameter_ref'] == param['name']):
+ param['default_value'] = src['value']
+ param['read_only'] = True
+ found = True
+ break
+ if found:
+ break
+
+ if not found:
+ for req in reqs:
+ for p in req['parameter']:
+ if (p['config_primitive_ref'] == confp['name']) \
+ and (p['parameter_ref'] == param['name']):
+ param['default_value'] = req['value']
+ param['read_only'] = True
+ found = True
+ break
+ if found:
+ break
+
+ self._log.debug("Config primitive: {}".format(confp))
+ vnf_configuration['config_primitive'].append(confp)
+
+ cm_state['vnf_configuration'] = vnf_configuration
+
+ @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
+
+ dts_path = xpath
+ if xpath.startswith('../'):
+ prefix = xpath_prefix
+ xp = xpath
+ while xp.startswith('../'):
+ idx = prefix.rfind('/')
+ if idx == -1:
+ raise ValueError("VNF {}, Did not find the xpath specified: {}".
+ format(vnf_name, xpath))
+ prefix = prefix[:idx]
+ xp = xp[3:]
+
+ 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("Invalid xpath {} for source {} in VNF {}".
+ format(xpath, name, vnf_name))
+ raise ValueError("Descriptor xpath {} in source {} 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='{}']/config-parameter" \
+ "/config-parameter-source/config-parameter-source[name='{}']" \
+ "/descriptor".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 {}, descriptor 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)
+ 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='{}']/config_parameter" \
+ "/config-parameter-source/config-parameter-source[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 request {} 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 source {} in VNF {}".
+ format(attr, dts_path, vnfd.name))
+
+ self._log.debug("Attribute {}: {}".format(attribute, val))
+ return val
+
+ @asyncio.coroutine
+ def process_vnf_config_parameter(self, nsr_obj):
+ nsd = nsr_obj.agent_nsr.nsd
+
+ # Process all capabilities in all the member VNFs
+ for vnfr in nsr_obj.vnfrs:
+ vnfd = vnfr['vnf_cfg']['agent_vnfr'].vnfd
+
+ try:
+ cparam = vnfd.config_parameter
+ except AttributeError as e:
+ self._log.debug("VNFR {} does not have VNF config parameter".
+ format(vnfr.name))
+ continue
+
+ srcs = []
+ try:
+ srcs = cparam.config_parameter_source
+ except AttributeError as e:
+ self._log.debug("VNFR {} has no source defined".
+ format(vnfr.name))
+
+ # Get the cm state dict for this vnfr
+ cm_state = nsr_obj.find_vnfr_cm_state(vnfr['id'])
+
+ cm_srcs = []
+ for src in srcs:
+ self._log.debug("VNFR {}: source {}".
+ format(vnfr['name'], src.as_dict()))
+
+ param_refs = []
+ for p in src.parameter:
+ param_refs.append({
+ 'config_primitive_ref': p.config_primitive_name_ref,
+ 'parameter_ref': p.config_primitive_parameter_ref
+ })
+
+ try:
+ val = src.value
+ self._log.debug("Got value {}".format(val))
+ if val:
+ cm_srcs.append({'name': src.name,
+ 'value': str(val),
+ 'parameter': param_refs})
+ continue
+ except AttributeError as e:
+ pass
+
+ try:
+ xpath = src.descriptor
+ # resolve xpath
+ if xpath:
+ val = yield from self.resolve_xpath(xpath, src.name, vnfd)
+ self._log.debug("Got xpath value: {}".format(val))
+ cm_srcs.append({'name': src.name,
+ 'value': str(val),
+ 'parameter': param_refs})
+ continue
+ except AttributeError as e:
+ pass
+
+ try:
+ attribute = src.attribute
+ # resolve attribute
+ if attribute:
+ val = yield from self.resolve_attribute(attribute,
+ src.name,
+ vnfd, vnfr)
+ self._log.debug("Got attribute value: {}".format(val))
+ cm_srcs.append({'name': src.name,
+ 'value': str(val),
+ 'parameter': param_refs})
+ continue
+ except AttributeError as e:
+ pass
+
+ try:
+ prim = src.primitive_ref
+ if prim:
+ raise NotImplementedError("{}: VNF config parameter {}"
+ "source support for config"
+ "primitive not yet supported".
+ format(vnfr.name, prim))
+ except AttributeError as e:
+ pass
+
+ self._log.debug("VNF config parameter sources: {}".format(cm_srcs))
+ cm_state['config_parameter']['config_parameter_source'] = cm_srcs
+
+ try:
+ reqs = cparam.config_parameter_request
+ except AttributeError as e:
+ self._log.debug("VNFR {} has no requests defined".
+ format(vnfr.name))
+ continue
+
+ cm_reqs = []
+ for req in reqs:
+ self._log.debug("VNFR{}: request {}".
+ format(vnfr['name'], req.as_dict()))
+ param_refs = []
+ for p in req.parameter:
+ param_refs.append({
+ 'config_primitive_ref': p.config_primitive_name_ref,
+ 'parameter_ref': p.config_primitive_parameter_ref
+ })
+ cm_reqs.append({'name': req.name,
+ 'parameter': param_refs})
+
+ self._log.debug("VNF requests: {}".format(cm_reqs))
+ cm_state['config_parameter']['config_parameter_request'] = cm_reqs
+
+ # Publish all config parameter for the VNFRs
+ # yield from nsr_obj.publish_cm_state()
+
+ cparam_map = []
+ try:
+ cparam_map = nsd.config_parameter_map
+ except AttributeError as e:
+ self._log.debug("No config parameter map specified for nsr: {}".
+ format(nsr_obj.nsr_name))
+
+ for cp in cparam_map:
+ src_vnfr = nsr_obj.agent_nsr.get_member_vnfr(
+ cp.config_parameter_source.member_vnf_index_ref)
+ cm_state = nsr_obj.find_vnfr_cm_state(src_vnfr.id)
+ if cm_state is None:
+ raise ValueError("Config parameter sources are not defined "
+ "for VNF member {} ({})".
+ format(cp.config_parameter_source.member_vnf_index_ref,
+ src_vnfr.name))
+ srcs = cm_state['config_parameter']['config_parameter_source']
+
+ src_attr = cp.config_parameter_source.config_parameter_source_ref
+ val = None
+ for src in srcs:
+ if src['name'] == src_attr:
+ val = src['value']
+ break
+
+ req_vnfr = nsr_obj.agent_nsr.get_member_vnfr(
+ cp.config_parameter_request.member_vnf_index_ref)
+ req_attr = cp.config_parameter_request.config_parameter_request_ref
+ cm_state = nsr_obj.find_vnfr_cm_state(req_vnfr.id)
+ try:
+ cm_reqs = cm_state['config_parameter']['config_parameter_request']
+ except KeyError as e:
+ raise ValueError("VNFR index {} ({}) has no requests defined".
+ format(cp.config_parameter_reequest.member_vnf_index_ref,
+ req_vnfr['name']))
+
+ for i, item in enumerate(cm_reqs):
+ if item['name'] == req_attr:
+ item['value'] = str(val)
+ cm_reqs[i] = item
+ self._log.debug("Request in VNFR {}: {}".
+ format(req_vnfr.name, item))
+ break
+
+ yield from self.update_config_primitives(nsr_obj)
+
+ # Publish resolved dependencies for the VNFRs
+ yield from nsr_obj.publish_cm_state()
+
@asyncio.coroutine
def config_NSR(self, id):
yaml_dict = dict(sorted(config_attributes_dict.items()))
yf.write(yaml.dump(yaml_dict, default_flow_style=False))
-
+
nsr_dict = self._nsr_dict
self._log.info("Configure NSR, id = %s", id)
#####################TBD###########################
# yield from self._config_agent_mgr.invoke_config_agent_plugins('notify_create_nsr', self.id, self._nsd)
# yield from self._config_agent_mgr.invoke_config_agent_plugins('notify_nsr_active', self.id, self._vnfrs)
-
+
try:
if id not in nsr_dict:
nsr_obj = ConfigManagerNSR(self._log, self._loop, self, id)
if nsr_obj.cm_nsr['state'] != nsr_obj.state_to_string(conmanY.RecordState.INIT):
self._log.debug("NSR(%s) is already processed, state=%s",
nsr_obj.nsr_name, nsr_obj.cm_nsr['state'])
- yield from nsr_obj.publish_cm_state()
+ #yield from nsr_obj.publish_cm_state()
return True
cmdts_obj = self.cmdts_obj
# return
nsr_obj.set_config_dir(self)
-
+
for const_vnfr in nsr['constituent_vnfr_ref']:
self._log.debug("Fetching VNFR (%s)", const_vnfr['vnfr_id'])
vnfr_msg = yield from cmdts_obj.get_vnfr(const_vnfr['vnfr_id'])
if vnfr_msg:
vnfr = vnfr_msg.as_dict()
+ # Get the VNFD also
+ vnfd = vnfr_msg.vnfd
+
self._log.info("create VNF:{}/{}".format(nsr_obj.nsr_name, vnfr['short_name']))
- agent_vnfr = yield from nsr_obj.add_vnfr(vnfr, vnfr_msg)
+ agent_vnfr = yield from nsr_obj.add_vnfr(vnfr, vnfr_msg, vnfd)
# Preserve order, self.process_nsd_vnf_configuration()
# sets up the config agent based on the method
yield from self.process_nsd_vnf_configuration(nsr_obj, vnfr)
- yield from self._config_agent_mgr.invoke_config_agent_plugins(
- 'notify_create_vnfr',
- nsr_obj.agent_nsr,
- agent_vnfr)
+
+ # Process VNF config parameter
+ yield from self.process_vnf_config_parameter(nsr_obj)
+
+ # Invoke the config agent plugin
+ for vnfr in nsr_obj.vnfrs:
+ yield from self._config_agent_mgr.invoke_config_agent_plugins(
+ 'notify_create_vnfr',
+ nsr_obj.agent_nsr,
+ vnfr['vnf_cfg']['agent_vnfr'])
#####################TBD###########################
# self._log.debug("VNF active. Apply initial config for vnfr {}".format(vnfr.name))
# Iterate through each priority level
for vnf_config_attributes_dict in config_attributes_dict:
# Iterate through each vnfr at this priority level
-
+
# Make up vnf_unique_name with vnfd name and member index
#vnfr_name = "{}.{}".format(nsr_obj.nsr_name, vnf_config_attributes_dict['name'])
vnf_unique_name = get_vnf_unique_name(
# 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
if nsr_obj_p == nsr_obj:
assert id == nsr_obj_p._nsr_id
#self._parent.pending_cfg.remove(nsr_obj_p)
- # Mark this as being deleted so we do not try to configure it if we are in cfg_delay (will wake up and continue to process otherwise)
+ # Mark this as being deleted so we do not try to configure it
+ # if we are in cfg_delay (will wake up and continue to process otherwise)
nsr_obj_p.being_deleted = True
self._log.info("Removed scheduled configuration for NSR(%s)", nsr_obj.nsr_name)
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)
caller._nsr['name_ref'], self.this_nsr_dir)
self.config_attributes_file = os.path.join(self.this_nsr_dir, "configuration_config_attributes.yml")
self.xlate_dict_file = os.path.join(self.this_nsr_dir, "nsr_xlate_dict.yml")
-
+
def xlate_conf(self, vnfr, vnf_cfg):
# If configuration type is not already set, try to read from attributes
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))
+
+ 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, 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)
'cfg_type' : vnf_cfg['config_method'],
'cfg_location' : vnf_cfg['cfg_file'],
'connection_point' : [],
+ 'config_parameter' :
+ {
+ 'config_parameter_source' : [],
+ 'config_parameter_request' : [],
+ },
}
self.cm_nsr['cm_vnfr'].append(vnf_cm_state)
yield from self.publish_cm_state()
@asyncio.coroutine
- def add_vnfr(self, vnfr, vnfr_msg):
+ def add_vnfr(self, vnfr, vnfr_msg, vnfd):
@asyncio.coroutine
def populate_subnets_from_vlr(id):
except Exception as e:
self._log.error("VNF:(%s) VLR Error = %s",
vnfr['short_name'], e)
-
+
if vnfr['id'] not in self._vnfr_dict:
self._log.info("NSR(%s) : Adding VNF Record for name=%s, id=%s", self._nsr_id, vnfr['short_name'], vnfr['id'])
# Add this vnfr to the list for show, or single traversal
self._vnfr_list.append(vnfr)
else:
- self._log.warning("NSR(%s) : VNF Record for name=%s, id=%s already exists, overwriting", self._nsr_id, vnfr['short_name'], vnfr['id'])
+ self._log.warning("NSR(%s) : VNF Record for name=%s, id=%s already exists, overwriting",
+ self._nsr_id, vnfr['short_name'], vnfr['id'])
# Make vnfr available by id as well as by name
unique_name = get_vnf_unique_name(self.nsr_name, vnfr['short_name'], vnfr['member_vnf_index_ref'])
vnf_cfg = {
'nsr_obj' : self,
'vnfr' : vnfr,
- 'agent_vnfr' : self.agent_nsr.add_vnfr(vnfr, vnfr_msg),
+ 'agent_vnfr' : self.agent_nsr.add_vnfr(vnfr, vnfr_msg, vnfd),
'nsr_name' : self.nsr_name,
'nsr_id' : self._nsr_id,
'vnfr_name' : vnfr['short_name'],
if 'internal_vlr' in vnfr:
for ivlr in vnfr['internal_vlr']:
yield from populate_subnets_from_vlr(ivlr['vlr_ref'])
-
+
# Update vnfr
vnf_cfg['agent_vnfr']._vnfr = vnfr
return vnf_cfg['agent_vnfr']
return ("D,/vnfr:vnfr-catalog/vnfr:vnfr" +
("[vnfr:id='{}']".format(k) if k is not None else ""))
+ @staticmethod
+ def vnfd_path(k=None):
+ return ("C,/vnfd:vnfd-catalog/vnfd:vnfd" +
+ ("[vnfd:id='{}']".format(k) if k is not None else ""))
+
@staticmethod
def config_agent(k=None):
return ("D,/rw-config-agent:config-agent/rw-config-agent:account" +
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)
vnfr_msg = vnfrl[0]
return vnfr_msg
+ @asyncio.coroutine
+ def get_vnfd(self, id):
+ self._log.debug("Attempting to get VNFD: %s", XPaths.vnfd_path(id))
+ vnfdl = yield from self._read_dts(XPaths.vnfd_path(id), do_trace=False)
+ vnfd_msg = None
+ if len(vnfdl) > 0:
+ vnfd_msg = vnfdl[0]
+ return vnfd_msg
+
@asyncio.coroutine
def get_vlr(self, id):
self._log.debug("Attempting to get VLR subnet: %s", id)
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 '''
else:
log_vnf += "{}/".format(vnf_cfg[item])
return log_vnf
-
+
+
class ConfigManagerROifConnectionError(Exception):
pass
+
+
class ScriptError(Exception):
pass
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':
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):
#@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)
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
ids.append(nsr_id)
e = task.exception()
if e:
- self._log.error("Exception in configuring nsr {}: {}".
- format(nsr_id, e))
+ self._log.exception("Exception in configuring nsr {}: {}".
+ format(nsr_id, e))
nsr_obj = self.get_nsr_obj(nsr_id)
if nsr_obj:
yield from nsr_obj.update_ns_cm_state(conmanY.RecordState.CFG_FAILED, str(e))
type inet:ip-address;
}
}
+ // Publish the resolved capabilites and dependecies here
+ container config-parameter {
+ description
+ "The resolved config parameter for a VNF";
+ list config-parameter-source {
+ description "List of resolved sources";
+ key "name";
+
+ leaf name {
+ type string {
+ length 128;
+ }
+ description
+ "Name of the source as defined in VNFD";
+ }
+ leaf value {
+ type string;
+ description
+ "Resovled value for the source";
+ }
+ list parameter {
+ key "config-primitive-ref";
+ leaf config-primitive-ref {
+ type string;
+ }
+ leaf parameter-ref {
+ type string;
+ }
+ }
+ }
+
+ list config-parameter-request {
+ description
+ "List of resolved requests for the the VNF";
+ key "name";
+
+ leaf name {
+ type string {
+ length 128;
+ }
+ description
+ "Name of the request as defined in VNFD";
+ }
+ leaf value {
+ type string;
+ description
+ "Resovled value for the request";
+ }
+ list parameter {
+ key "config-primitive-ref";
+ leaf config-primitive-ref {
+ type string;
+ }
+ leaf parameter-ref {
+ type string;
+ }
+ }
+ }
+ }
+
+ // Resolve the VNF config-primitives and publish it
+ // here. VNFR will use this and update config-primitives
+ // from here.
+ uses manotypes:vnf-configuration;
} // list VNFR
} // list NSR
} // cm-state
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)
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))
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)
+ yield from \
+ self.nsm.vnfrs[vnfrid].update_config_primitives(
+ vnfr.vnf_configuration)
+
# 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']))
+ 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 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 {}: {}".
@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,
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",
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))
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,
RwsdnYang,
RwDts as rwdts,
RwTypes,
+ VnfdYang,
ProtobufC,
)
@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):
format(self.name, self.vnfr_msg))
yield from self._dts.query_update(
self.xpath,
- rwdts.XactFlag.TRACE,
+ rwdts.XactFlag.REPLACE,
self.vnfr_msg
)
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 pa.default_value and \
+ (pa.default_value != param.default_value):
+ param.default_value = pa.default_value
+ param.read_only = pa.read_only
+ updated = True
+ break
+ self._log.debug("Prim: {}".format(prim.as_dict()))
+ 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"""
vnfr_dict.update(vnfd_copy_dict)
vnfr_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict(vnfr_dict)
+ vnfr_msg.vnfd = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vnfd.from_dict(self.vnfd.as_dict())
+
+ vnfr_msg.create_time = self._create_time
vnfr_msg.uptime = int(time.time()) - self._create_time
vnfr_msg.mgmt_interface = mgmt_intf
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()
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(
handler=hdl,
flags=(rwdts.Flag.PUBLISHER |
rwdts.Flag.NO_PREP_READ |
- rwdts.Flag.CACHE |
rwdts.Flag.DATASTORE),)
@asyncio.coroutine
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)
internal_vlr_count=num_internal_vlrs,
num_vnf_vms=2,
mano_ut=True,
- use_scale_group=True,
+ use_scale_group=False,
use_mon_params=False,
)