from osm_im.nst import nst as nst_im
from pyangbind.lib.serialise import pybindJSONDecoder
import pyangbind.lib.pybindJSON as pybindJSON
-from osm_nbi.utils import deep_update_dict
+from osm_nbi import utils
__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
out = pybindJSON.dumps(myvnfd, mode="ietf")
desc_out = self._remove_envelop(yaml.safe_load(out))
desc_out = self._remove_yang_prefixes_from_descriptor(desc_out)
- return deep_update_dict(data, desc_out)
+ return utils.deep_update_dict(data, desc_out)
except Exception as e:
raise EngineException("Error in pyangbind validation: {}".format(str(e)),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
for vdu in get_iterable(indata.get("vdu")):
self.validate_vdu_internal_connection_points(vdu)
- self._validate_vdu_charms_in_package(storage_params, vdu, indata)
self._validate_vdu_cloud_init_in_package(storage_params, vdu, indata)
+ self._validate_vdu_charms_in_package(storage_params, indata)
self._validate_vnf_charms_in_package(storage_params, indata)
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
# TODO: Validate k8s-cluster-net points to a valid k8s-cluster:nets ?
- def _validate_vdu_charms_in_package(self, storage_params, vdu, indata):
- if not vdu.get("vdu-configuration"):
- return
- for vdu_configuration in get_iterable(indata.get("vdu-configuration")):
- if vdu_configuration.get("juju"):
- if not self._validate_package_folders(storage_params, 'charms'):
- raise EngineException("Charm defined in vnf[id={}] but not present in "
- "package".format(indata["id"]))
+ def _validate_vdu_charms_in_package(self, storage_params, indata):
+ for df in indata["df"]:
+ if "lcm-operations-configuration" in df and "operate-vnf-op-config" in df["lcm-operations-configuration"]:
+ configs = df["lcm-operations-configuration"]["operate-vnf-op-config"].get("day1-2", [])
+ for config in configs:
+ if config.get("juju"):
+ if not self._validate_package_folders(storage_params, 'charms'):
+ raise EngineException("Charm defined in vnf[id={}] but not present in "
+ "package".format(indata["id"]))
def _validate_vdu_cloud_init_in_package(self, storage_params, vdu, indata):
if not vdu.get("cloud-init-file"):
"package".format(indata["id"], vdu["id"]))
def _validate_vnf_charms_in_package(self, storage_params, indata):
- if not indata.get("vnf-configuration"):
- return
- for vnf_configuration in get_iterable(indata.get("vnf-configuration")):
- if vnf_configuration.get("juju"):
- if not self._validate_package_folders(storage_params, 'charms'):
- raise EngineException("Charm defined in vnf[id={}] but not present in "
- "package".format(indata["id"]))
+ # Get VNF configuration through new container
+ for deployment_flavor in indata.get('df', []):
+ if "lcm-operations-configuration" not in deployment_flavor:
+ return
+ if "operate-vnf-op-config" not in deployment_flavor["lcm-operations-configuration"]:
+ return
+ for day_1_2_config in deployment_flavor["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"]:
+ if day_1_2_config["id"] == indata["id"]:
+ vnf_configuration = day_1_2_config
+ if vnf_configuration.get("juju"):
+ if not self._validate_package_folders(storage_params, 'charms'):
+ raise EngineException("Charm defined in vnf[id={}] but not present in "
+ "package".format(indata["id"]))
def _validate_package_folders(self, storage_params, folder, file=None):
if not storage_params or not storage_params.get("pkg-dir"):
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
for sca in get_iterable(sa.get("scaling-config-action")):
- if not indata.get("vnf-configuration"):
- raise EngineException("'vnf-configuration' not defined in the descriptor but it is referenced "
- "by df[id='{}']:scaling-aspect[id='{}']:scaling-config-action"
+ if "lcm-operations-configuration" not in df \
+ or "operate-vnf-op-config" not in df["lcm-operations-configuration"] \
+ or not utils.find_in_list(
+ df["lcm-operations-configuration"]["operate-vnf-op-config"].get("day1-2", []),
+ lambda config: config["id"] == indata["id"]):
+ raise EngineException("'day1-2 configuration' not defined in the descriptor but it is "
+ "referenced by df[id='{}']:scaling-aspect[id='{}']:scaling-config-action"
.format(df["id"], sa["id"]),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- for configuration in get_iterable(indata["vnf-configuration"]):
+ for configuration in get_iterable(
+ df["lcm-operations-configuration"]["operate-vnf-op-config"].get("day1-2", [])
+ ):
for primitive in get_iterable(configuration.get("config-primitive")):
if primitive["name"] == sca["vnf-config-primitive-name-ref"]:
break
else:
raise EngineException("df[id='{}']:scaling-aspect[id='{}']:scaling-config-action:vnf-"
"config-primitive-name-ref='{}' does not match any "
- "vnf-configuration:config-primitive:name"
+ "day1-2 configuration:config-primitive:name"
.format(df["id"], sa["id"], sca["vnf-config-primitive-name-ref"]),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
additional_params[k] = "!!yaml " + safe_dump(v)
if descriptor:
- # check that enough parameters are supplied for the initial-config-primitive
- # TODO: check for cloud-init
- if member_vnf_index:
- if kdu_name:
- initial_primitives = None
- elif vdu_id:
- vdud = next(x for x in descriptor["vdu"] if x["id"] == vdu_id)
- initial_primitives = deep_get(vdud, ("vdu-configuration", "initial-config-primitive"))
- else:
- vnf_configurations = get_iterable(descriptor.get("vnf-configuration"))
+ for df in descriptor.get("df", []):
+ # check that enough parameters are supplied for the initial-config-primitive
+ # TODO: check for cloud-init
+ if member_vnf_index:
initial_primitives = []
- for vnfc in vnf_configurations:
- for primitive in get_iterable(vnfc.get("initial-config-primitive")):
- initial_primitives.append(primitive)
- else:
- initial_primitives = deep_get(descriptor, ("ns-configuration", "initial-config-primitive"))
-
- for initial_primitive in get_iterable(initial_primitives):
- for param in get_iterable(initial_primitive.get("parameter")):
- if param["value"].startswith("<") and param["value"].endswith(">"):
- if param["value"] in ("<rw_mgmt_ip>", "<VDU_SCALE_INFO>", "<ns_config_info>"):
- continue
- if not additional_params or param["value"][1:-1] not in additional_params:
- raise EngineException("Parameter '{}' needed for vnfd[id={}]:vnf-configuration:"
- "initial-config-primitive[name={}] not supplied".
- format(param["value"], descriptor["id"],
- initial_primitive["name"]))
+ if "lcm-operations-configuration" in df \
+ and "operate-vnf-op-config" in df["lcm-operations-configuration"]:
+ for config in df["lcm-operations-configuration"]["operate-vnf-op-config"].get("day1-2", []):
+ for primitive in get_iterable(config.get("initial-config-primitive")):
+ initial_primitives.append(primitive)
+ else:
+ initial_primitives = deep_get(descriptor, ("ns-configuration", "initial-config-primitive"))
+
+ for initial_primitive in get_iterable(initial_primitives):
+ for param in get_iterable(initial_primitive.get("parameter")):
+ if param["value"].startswith("<") and param["value"].endswith(">"):
+ if param["value"] in ("<rw_mgmt_ip>", "<VDU_SCALE_INFO>", "<ns_config_info>"):
+ continue
+ if not additional_params or param["value"][1:-1] not in additional_params:
+ raise EngineException("Parameter '{}' needed for vnfd[id={}]:day1-2 configuration:"
+ "initial-config-primitive[name={}] not supplied".
+ format(param["value"], descriptor["id"],
+ initial_primitive["name"]))
return additional_params or None, other_params or None
vnfr_descriptor["kdur"].append(kdur)
vnfd_mgmt_cp = vnfd.get("mgmt-cp")
+
for vdu in vnfd.get("vdu", ()):
additional_params, vdu_params = self._format_additional_params(
ns_request, vnf_index, vdu_id=vdu["id"], descriptor=vnfd)
indata["member_vnf_index"] = indata.pop("vnf_member_index") # for backward compatibility
if indata.get("member_vnf_index"):
vnfd = self._get_vnfd_from_vnf_member_index(indata["member_vnf_index"], nsr["_id"])
+ try:
+ configs = vnfd.get("df")[0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"]
+ except Exception:
+ configs = []
+
if indata.get("vdu_id"):
self._check_valid_vdu(vnfd, indata["vdu_id"])
- # TODO: Change the [0] as vdu-configuration is now a list
- descriptor_configuration = vnfd.get("vdu-configuration", [{}])[0].get("config-primitive")
+ descriptor_configuration = utils.find_in_list(
+ configs,
+ lambda config: config["id"] == indata["vdu_id"]
+ ).get("config-primitive")
elif indata.get("kdu_name"):
self._check_valid_kdu(vnfd, indata["kdu_name"])
- # TODO: Change the [0] as kdu-configuration is now a list
- kdud = next((k for k in vnfd["kdu"] if k["name"] == indata["kdu_name"]), None)
- descriptor_configuration = deep_get(kdud, ("kdu-configuration", "config-primitive"))
+ descriptor_configuration = utils.find_in_list(
+ configs,
+ lambda config: config["id"] == indata.get("kdu_name")
+ ).get("config-primitive")
else:
- # TODO: Change the [0] as vnf-configuration is now a list
- descriptor_configuration = vnfd.get("vnf-configuration", [{}])[0].get("config-primitive")
+ descriptor_configuration = utils.find_in_list(
+ configs,
+ lambda config: config["id"] == vnfd["id"]
+ ).get("config-primitive")
else: # use a NSD
descriptor_configuration = nsd.get("ns-configuration", {}).get("config-primitive")
else:
for vnfr in vnfr_desc:
vnfd_desc = self.db.get_one("vnfds", {"_id": vnfr["vnfd-id"]}, fail_on_empty=True, fail_on_more=False)
- if vnfd_desc.get("vdu"):
- for vdu in vnfd_desc['vdu']:
- # Checks for vdu metric in vdu-configuration
- if 'vdu-configuration' in vdu and 'metrics' in vdu['vdu-configuration']:
- metric_list.extend([quote(metric['name'])
- for metric in vdu["vdu-configuration"]["metrics"]])
- # Checks for vnf metric in vnf-configutaion
- if 'vnf-configuration' in vnfd_desc and 'metrics' in vnfd_desc['vnf-configuration']:
- metric_list.extend([quote(metric['name']) for metric in vnfd_desc["vnf-configuration"]["metrics"]])
+ try:
+ configs = vnfd_desc.get("df")[0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"]
+ except Exception:
+ configs = []
+
+ for config in configs:
+ if "metrics" in config:
+ metric_list.extend([quote(metric['name']) for metric in config["metrics"]])
metric_list = list(set(metric_list))
return metric_list
df:
- id: hackfest_default
- vnf-configuration-id: vnf-configuration-example
vdu-profile:
- id: mgmtVM
min-number-of-instances: 1
- id: dataVM
min-number-of-instances: 1
max-number-of-instances: 10
- vdu-configuration-id: vdu-configuration-example
instantiation-level:
- id: default
vdu-level:
vnf-config-primitive-name-ref: touch
- trigger: pre-scale-in
vnf-config-primitive-name-ref: touch
-
- vnf-configuration:
- - id: vnf-configuration-example
- initial-config-primitive:
- - seq: "1"
- name: config
- parameter:
- - name: ssh-hostname
- value: <rw_mgmt_ip>
- - name: ssh-username
- value: ubuntu
- - name: ssh-password
- value: osm4u
- - seq: "2"
- name: touch
- parameter:
- - name: filename
- value: <touch_filename>
- config-primitive:
- - name: touch
- parameter:
- - data-type: STRING
- default-value: <touch_filename2>
- name: filename
- juju:
- charm: simple
+ lcm-operations-configuration:
+ operate-vnf-op-config:
+ day1-2:
+ - id: hackfest3charmed-vnf
+ initial-config-primitive:
+ - seq: "1"
+ name: config
+ parameter:
+ - name: ssh-hostname
+ value: <rw_mgmt_ip>
+ - name: ssh-username
+ value: ubuntu
+ - name: ssh-password
+ value: osm4u
+ - seq: "2"
+ name: touch
+ parameter:
+ - name: filename
+ value: <touch_filename>
+ config-primitive:
+ - name: touch
+ parameter:
+ - data-type: STRING
+ default-value: <touch_filename2>
+ name: filename
+ juju:
+ charm: simple
"""
db_nsds_text = """
self.assertEqual(db_args[1]["_admin"]["projects_read"], [test_pid], "Wrong read-only project list")
self.assertEqual(db_args[1]["_admin"]["projects_write"], [test_pid], "Wrong read-write project list")
tmp1 = test_vnfd["vdu"][0]["cloud-init-file"]
- tmp2 = test_vnfd["vnf-configuration"][0]["juju"]
+ tmp2 = test_vnfd["df"][0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"][0]["juju"]
del test_vnfd["vdu"][0]["cloud-init-file"]
- del test_vnfd["vnf-configuration"][0]["juju"]
+ del test_vnfd["df"][0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"][0]["juju"]
try:
self.db.get_one.side_effect = [{"_id": did, "_admin": deepcopy(db_vnfd_content["_admin"])}, None]
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
compare_desc(self, test_vnfd, db_args[2], "VNFD")
finally:
test_vnfd["vdu"][0]["cloud-init-file"] = tmp1
- test_vnfd["vnf-configuration"][0]["juju"] = tmp2
+ test_vnfd["df"][0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"][0]["juju"] = tmp2
self.db.get_one.side_effect = lambda table, filter, fail_on_empty=None, fail_on_more=None: \
{"_id": did, "_admin": deepcopy(db_vnfd_content["_admin"])}
with self.subTest(i=2, t='Check Pyangbind Validation: additional properties'):
self.assertIn(norm("{} defined in vnf[id={}]:vdu[id={}] but not present in package"
.format("cloud-init", test_vnfd["id"], test_vnfd["vdu"][0]["id"])),
norm(str(e.exception)), "Wrong exception text")
- with self.subTest(i=5, t='Check Input Validation: vnf-configuration[juju]'):
+ with self.subTest(i=5, t='Check Input Validation: day1-2 configuration[juju]'):
del test_vnfd["vdu"][0]["cloud-init-file"]
with self.assertRaises(EngineException, msg="Accepted non-existent charm in VNF configuration") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.BAD_REQUEST, "Wrong HTTP status code")
self.assertIn(norm("{} defined in vnf[id={}] but not present in package".format("charm", test_vnfd["id"])),
norm(str(e.exception)), "Wrong exception text")
- del test_vnfd["vnf-configuration"][0]["juju"]
+ del test_vnfd["df"][0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"][0]["juju"]
with self.subTest(i=6, t='Check Input Validation: mgmt-cp'):
tmp = test_vnfd["mgmt-cp"]
del test_vnfd["mgmt-cp"]
vdu['monitoring-parameter'] = tmp
with self.subTest(i=13, t='Check Input Validation: scaling-aspect vnf-configuration'):
df = test_vnfd['df'][0]
- tmp = test_vnfd.pop('vnf-configuration')
+ tmp = test_vnfd["df"][0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"].pop()
try:
with self.assertRaises(EngineException, msg="Accepted non-existent Scaling Group VDU ID Reference") \
as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("'vnf-configuration' not defined in the descriptor but it is referenced "
+ self.assertIn(norm("'day1-2 configuration' not defined in the descriptor but it is referenced "
"by df[id='{}']:scaling-aspect[id='{}']:scaling-config-action"
.format(df["id"], df['scaling-aspect'][0]["id"])),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_vnfd["vnf-configuration"] = tmp
+ test_vnfd["df"][0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"].append(tmp)
with self.subTest(i=14, t='Check Input Validation: scaling-config-action'):
df = test_vnfd['df'][0]
- tmp = test_vnfd['vnf-configuration'][0]['config-primitive']
- test_vnfd['vnf-configuration'][0]['config-primitive'] = [{'name': 'wrong-primitive'}]
+ tmp = test_vnfd["df"][0].get(
+ "lcm-operations-configuration"
+ ).get(
+ "operate-vnf-op-config"
+ )["day1-2"][0]['config-primitive']
+ test_vnfd["df"][0].get(
+ "lcm-operations-configuration"
+ ).get(
+ "operate-vnf-op-config"
+ )["day1-2"][0]['config-primitive'] = [{'name': 'wrong-primitive'}]
try:
with self.assertRaises(EngineException,
msg="Accepted non-existent Scaling Group VDU ID Reference") as e:
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
self.assertIn(norm("df[id='{}']:scaling-aspect[id='{}']:scaling-config-action:vnf-"
"config-primitive-name-ref='{}' does not match any "
- "vnf-configuration:config-primitive:name"
+ "day1-2 configuration:config-primitive:name"
.format(df["id"], df['scaling-aspect'][0]["id"],
sa['scaling-config-action'][0]['vnf-config-primitive-name-ref'])),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_vnfd['vnf-configuration'][0]['config-primitive'] = tmp
+ test_vnfd["df"][0].get(
+ "lcm-operations-configuration"
+ ).get(
+ "operate-vnf-op-config"
+ )["day1-2"][0]['config-primitive'] = tmp
with self.subTest(i=15, t='Check Input Validation: everything right'):
test_vnfd["id"] = "fake-vnfd-id"
+ test_vnfd["df"][0].get(
+ "lcm-operations-configuration"
+ ).get(
+ "operate-vnf-op-config"
+ )["day1-2"][0]["id"] = "fake-vnfd-id"
self.db.get_one.side_effect = [{"_id": did, "_admin": deepcopy(db_vnfd_content["_admin"])}, None]
rc = self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertTrue(rc, "Input Validation: Unexpected failure")
with self.subTest(i=1, t='Normal Edition'):
now = time()
self.db.get_one.side_effect = [deepcopy(vnfd_content), None]
- data = {"id": "new-vnfd-id", "product-name": "new-vnfd-name"}
+ data = {
+ "product-name": "new-vnfd-name"
+ }
self.topic.edit(fake_session, did, data)
db_args = self.db.replace.call_args[0]
msg_args = self.msg.write.call_args[0]
"Wrong read-only project list")
self.assertEqual(db_args[2]["_admin"]["projects_write"], vnfd_content["_admin"]["projects_write"],
"Wrong read-write project list")
- self.assertEqual(db_args[2]["id"], data["id"], "Wrong VNFD ID")
self.assertEqual(db_args[2]["product-name"], data["product-name"], "Wrong VNFD Name")
with self.subTest(i=2, t='Conflict on Edit'):
- data = {"id": "fake-vnfd-id", "product-name": "new-vnfd-name"}
+ data = {"id": "hackfest3charmed-vnf", "product-name": "new-vnfd-name"}
self.db.get_one.side_effect = [deepcopy(vnfd_content), {"_id": str(uuid4()), "id": data["id"]}]
with self.assertRaises(EngineException, msg="Accepted existing VNFD ID") as e:
self.topic.edit(fake_session, did, data)
indata = deepcopy(db_vnfd_content)
df = indata['df'][0]
affected_sa = df['scaling-aspect'][0]
- indata.pop('vnf-configuration')
+ indata["df"][0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"].pop()
with self.assertRaises(EngineException) as e:
self.topic.validate_scaling_group_descriptor(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("'vnf-configuration' not defined in the descriptor but it is referenced "
+ self.assertIn(norm("'day1-2 configuration' not defined in the descriptor but it is referenced "
"by df[id='{}']:scaling-aspect[id='{}']:scaling-config-action"
.format(df["id"], affected_sa["id"])),
norm(str(e.exception)), "Wrong exception text")
df = indata['df'][0]
affected_sa = df['scaling-aspect'][0]
affected_sca_primitive = affected_sa['scaling-config-action'][0]['vnf-config-primitive-name-ref']
- indata['vnf-configuration'][0]['config-primitive'] = []
+ df["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"][0]['config-primitive'] = []
with self.assertRaises(EngineException) as e:
self.topic.validate_scaling_group_descriptor(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
self.assertIn(norm("df[id='{}']:scaling-aspect[id='{}']:scaling-config-action:vnf-"
"config-primitive-name-ref='{}' does not match any "
- "vnf-configuration:config-primitive:name"
+ "day1-2 configuration:config-primitive:name"
.format(df["id"], affected_sa["id"], affected_sca_primitive)),
norm(str(e.exception)), "Wrong exception text")
df:
- id: hackfest_default
- vnf-configuration-id: vnf-configuration-example
vdu-profile:
- id: mgmtVM
min-number-of-instances: 1
- id: dataVM
min-number-of-instances: 1
max-number-of-instances: 10
- vdu-configuration-id: vdu-configuration-example
instantiation-level:
- id: default
vdu-level:
vnf-config-primitive-name-ref: touch
- trigger: pre-scale-in
vnf-config-primitive-name-ref: touch
-
- vnf-configuration:
- - id: vnf-configuration-example
- initial-config-primitive:
- - seq: "1"
- name: config
- parameter:
- - name: ssh-hostname
- value: <rw_mgmt_ip>
- - name: ssh-username
- value: ubuntu
- - name: ssh-password
- value: osm4u
- - seq: "2"
- name: touch
- parameter:
- - name: filename
- value: <touch_filename>
- config-primitive:
- - name: touch
- parameter:
- - data-type: STRING
- default-value: <touch_filename2>
- name: filename
- juju:
- charm: simple
+ lcm-operations-configuration:
+ operate-vnf-op-config:
+ day1-2:
+ - id: hackfest3charmed-vnf
+ initial-config-primitive:
+ - seq: "1"
+ name: config
+ parameter:
+ - name: ssh-hostname
+ value: <rw_mgmt_ip>
+ - name: ssh-username
+ value: ubuntu
+ - name: ssh-password
+ value: osm4u
+ - seq: "2"
+ name: touch
+ parameter:
+ - name: filename
+ value: <touch_filename>
+ config-primitive:
+ - name: touch
+ parameter:
+ - data-type: STRING
+ default-value: <touch_filename2>
+ name: filename
+ juju:
+ charm: simple
"""
db_nsds_text = """