##
import asyncio
+import shutil
from typing import Any, Dict, List
import yaml
import logging
deep_get,
get_iterable,
populate_dict,
+ check_juju_bundle_existence,
+ get_charm_artifact_path,
)
from osm_lcm.data_utils.nsd import (
get_ns_configuration_relation_list,
get_number_of_instances,
get_juju_ee_ref,
get_kdu_resource_profile,
+ find_software_version,
)
from osm_lcm.data_utils.list_utils import find_in_list
from osm_lcm.data_utils.vnfr import get_osm_params, get_vdur_index, get_kdur
timeout_ns_terminate = 1800 # default global timeout for un deployment a ns
timeout_charm_delete = 10 * 60
timeout_primitive = 30 * 60 # timeout for primitive execution
+ timeout_ns_update = 30 * 60 # timeout for ns update
timeout_progress_primitive = (
10 * 60
) # timeout for some progress in a primitive execution
self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
return nslcmop_operation_state, detailed_status
+ async def _ns_charm_upgrade(
+ self,
+ ee_id,
+ charm_id,
+ charm_type,
+ path,
+ timeout: float = None,
+ ) -> (str, str):
+ """This method upgrade charms in VNF instances
+
+ Args:
+ ee_id: Execution environment id
+ path: Local path to the charm
+ charm_id: charm-id
+ charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
+ timeout: (Float) Timeout for the ns update operation
+
+ Returns:
+ result: (str, str) COMPLETED/FAILED, details
+ """
+ try:
+ charm_type = charm_type or "lxc_proxy_charm"
+ output = await self.vca_map[charm_type].upgrade_charm(
+ ee_id=ee_id,
+ path=path,
+ charm_id=charm_id,
+ charm_type=charm_type,
+ timeout=timeout or self.timeout_ns_update,
+ )
+
+ if output:
+ return "COMPLETED", output
+
+ except (LcmException, asyncio.CancelledError):
+ raise
+
+ except Exception as e:
+
+ self.logger.debug("Error upgrading charm {}".format(path))
+
+ return "FAILED", "Error upgrading charm {}: {}".format(path, e)
+
+ async def update(self, nsr_id, nslcmop_id):
+ """Update NS according to different update types
+
+ This method performs upgrade of VNF instances then updates the revision
+ number in VNF record
+
+ Args:
+ nsr_id: Network service will be updated
+ nslcmop_id: ns lcm operation id
+
+ Returns:
+ It may raise DbException, LcmException, N2VCException, K8sException
+
+ """
+ # Try to lock HA task here
+ task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
+ if not task_is_locked_by_me:
+ return
+
+ logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
+ self.logger.debug(logging_text + "Enter")
+
+ # Set the required variables to be filled up later
+ db_nsr = None
+ db_nslcmop_update = {}
+ vnfr_update = {}
+ nslcmop_operation_state = None
+ db_nsr_update = {}
+ error_description_nslcmop = ""
+ exc = None
+ change_type = ""
+ detailed_status = ""
+
+ try:
+ # wait for any previous tasks in process
+ step = "Waiting for previous operations to terminate"
+ await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
+ self._write_ns_status(
+ nsr_id=nsr_id,
+ ns_state=None,
+ current_operation="UPDATING",
+ current_operation_id=nslcmop_id,
+ )
+
+ step = "Getting nslcmop from database"
+ db_nslcmop = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
+ )
+ update_type = db_nslcmop["operationParams"]["updateType"]
+
+ step = "Getting nsr from database"
+ db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
+ old_operational_status = db_nsr["operational-status"]
+ db_nsr_update["operational-status"] = "updating"
+ self.update_db_2("nsrs", nsr_id, db_nsr_update)
+ nsr_deployed = db_nsr["_admin"].get("deployed")
+
+ if update_type == "CHANGE_VNFPKG":
+
+ # Get the input parameters given through update request
+ vnf_instance_id = db_nslcmop["operationParams"][
+ "changeVnfPackageData"
+ ].get("vnfInstanceId")
+
+ vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
+ "vnfdId"
+ )
+ timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
+
+ step = "Getting vnfr from database"
+ db_vnfr = self.db.get_one(
+ "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
+ )
+
+ step = "Getting vnfds from database"
+ # Latest VNFD
+ latest_vnfd = self.db.get_one(
+ "vnfds", {"_id": vnfd_id}, fail_on_empty=False
+ )
+ latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
+
+ # Current VNFD
+ current_vnf_revision = db_vnfr.get("revision", 1)
+ current_vnfd = self.db.get_one(
+ "vnfds_revisions",
+ {"_id": vnfd_id + ":" + str(current_vnf_revision)},
+ fail_on_empty=False,
+ )
+ # Charm artifact paths will be filled up later
+ (
+ current_charm_artifact_path,
+ target_charm_artifact_path,
+ charm_artifact_paths,
+ ) = ([], [], [])
+
+ step = "Checking if revision has changed in VNFD"
+ if current_vnf_revision != latest_vnfd_revision:
+
+ # There is new revision of VNFD, update operation is required
+ current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
+ latest_vnfd_path = vnfd_id
+
+ step = "Removing the VNFD packages if they exist in the local path"
+ shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
+ shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
+
+ step = "Get the VNFD packages from FSMongo"
+ self.fs.sync(from_path=latest_vnfd_path)
+ self.fs.sync(from_path=current_vnfd_path)
+
+ step = (
+ "Get the charm-type, charm-id, ee-id if there is deployed VCA"
+ )
+ base_folder = latest_vnfd["_admin"]["storage"]
+
+ for charm_index, charm_deployed in enumerate(
+ get_iterable(nsr_deployed, "VCA")
+ ):
+ vnf_index = db_vnfr.get("member-vnf-index-ref")
+
+ # Getting charm-id and charm-type
+ if charm_deployed.get("member-vnf-index") == vnf_index:
+ charm_id = self.get_vca_id(db_vnfr, db_nsr)
+ charm_type = charm_deployed.get("type")
+
+ # Getting ee-id
+ ee_id = charm_deployed.get("ee_id")
+
+ step = "Getting descriptor config"
+ descriptor_config = get_configuration(
+ current_vnfd, current_vnfd["id"]
+ )
+
+ if "execution-environment-list" in descriptor_config:
+ ee_list = descriptor_config.get(
+ "execution-environment-list", []
+ )
+ else:
+ ee_list = []
+
+ # There could be several charm used in the same VNF
+ for ee_item in ee_list:
+ if ee_item.get("juju"):
+
+ step = "Getting charm name"
+ charm_name = ee_item["juju"].get("charm")
+
+ step = "Setting Charm artifact paths"
+ current_charm_artifact_path.append(
+ get_charm_artifact_path(
+ base_folder,
+ charm_name,
+ charm_type,
+ current_vnf_revision,
+ )
+ )
+ target_charm_artifact_path.append(
+ get_charm_artifact_path(
+ base_folder,
+ charm_name,
+ charm_type,
+ )
+ )
+
+ charm_artifact_paths = zip(
+ current_charm_artifact_path, target_charm_artifact_path
+ )
+
+ step = "Checking if software version has changed in VNFD"
+ if find_software_version(current_vnfd) != find_software_version(
+ latest_vnfd
+ ):
+
+ step = "Checking if existing VNF has charm"
+ for current_charm_path, target_charm_path in list(
+ charm_artifact_paths
+ ):
+ if current_charm_path:
+ raise LcmException(
+ "Software version change is not supported as VNF instance {} has charm.".format(
+ vnf_instance_id
+ )
+ )
+
+ # There is no change in the charm package, then redeploy the VNF
+ # based on new descriptor
+ step = "Redeploying VNF"
+ # This part is in https://osm.etsi.org/gerrit/11943
+
+ else:
+ step = "Checking if any charm package has changed or not"
+ for current_charm_path, target_charm_path in list(
+ charm_artifact_paths
+ ):
+ if (
+ current_charm_path
+ and target_charm_path
+ and self.check_charm_hash_changed(
+ current_charm_path, target_charm_path
+ )
+ ):
+
+ step = "Checking whether VNF uses juju bundle"
+ if check_juju_bundle_existence(current_vnfd):
+
+ raise LcmException(
+ "Charm upgrade is not supported for the instance which"
+ " uses juju-bundle: {}".format(
+ check_juju_bundle_existence(current_vnfd)
+ )
+ )
+
+ step = "Upgrading Charm"
+ (
+ result,
+ detailed_status,
+ ) = await self._ns_charm_upgrade(
+ ee_id=ee_id,
+ charm_id=charm_id,
+ charm_type=charm_type,
+ path=self.fs.path + target_charm_path,
+ timeout=timeout_seconds,
+ )
+
+ if result == "FAILED":
+ nslcmop_operation_state = result
+ error_description_nslcmop = detailed_status
+
+ db_nslcmop_update["detailed-status"] = detailed_status
+ self.logger.debug(
+ logging_text
+ + " step {} Done with result {} {}".format(
+ step, nslcmop_operation_state, detailed_status
+ )
+ )
+
+ step = "Updating policies"
+ # This part is in https://osm.etsi.org/gerrit/11943
+
+ # If nslcmop_operation_state is None, so any operation is not failed.
+ if not nslcmop_operation_state:
+ nslcmop_operation_state = "COMPLETED"
+
+ # If update CHANGE_VNFPKG nslcmop_operation is successful
+ # vnf revision need to be updated
+ vnfr_update["revision"] = latest_vnfd_revision
+ self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
+
+ self.logger.debug(
+ logging_text
+ + " task Done with result {} {}".format(
+ nslcmop_operation_state, detailed_status
+ )
+ )
+ elif update_type == "REMOVE_VNF":
+ # This part is included in https://osm.etsi.org/gerrit/11876
+ pass
+
+ # If nslcmop_operation_state is None, so any operation is not failed.
+ # All operations are executed in overall.
+ if not nslcmop_operation_state:
+ nslcmop_operation_state = "COMPLETED"
+ db_nsr_update["operational-status"] = old_operational_status
+
+ except (DbException, LcmException, N2VCException, K8sException) as e:
+ self.logger.error(logging_text + "Exit Exception {}".format(e))
+ exc = e
+ except asyncio.CancelledError:
+ self.logger.error(
+ logging_text + "Cancelled Exception while '{}'".format(step)
+ )
+ exc = "Operation was cancelled"
+ except asyncio.TimeoutError:
+ self.logger.error(logging_text + "Timeout while '{}'".format(step))
+ exc = "Timeout"
+ except Exception as e:
+ exc = traceback.format_exc()
+ self.logger.critical(
+ logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
+ exc_info=True,
+ )
+ finally:
+ if exc:
+ db_nslcmop_update[
+ "detailed-status"
+ ] = (
+ detailed_status
+ ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
+ nslcmop_operation_state = "FAILED"
+ db_nsr_update["operational-status"] = old_operational_status
+ if db_nsr:
+ self._write_ns_status(
+ nsr_id=nsr_id,
+ ns_state=db_nsr["nsState"],
+ current_operation="IDLE",
+ current_operation_id=None,
+ other_update=db_nsr_update,
+ )
+
+ self._write_op_status(
+ op_id=nslcmop_id,
+ stage="",
+ error_message=error_description_nslcmop,
+ operation_state=nslcmop_operation_state,
+ other_update=db_nslcmop_update,
+ )
+
+ if nslcmop_operation_state:
+ try:
+ await self.msg.aiowrite(
+ "ns",
+ "updated",
+ {
+ "nsr_id": nsr_id,
+ "nslcmop_id": nslcmop_id,
+ "operationState": nslcmop_operation_state,
+ },
+ loop=self.loop,
+ )
+ except Exception as e:
+ self.logger.error(
+ logging_text + "kafka_write notification Exception {}".format(e)
+ )
+ self.logger.debug(logging_text + "Exit")
+ self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
+ return nslcmop_operation_state, detailed_status
+
async def scale(self, nsr_id, nslcmop_id):
# Try to lock HA task here
task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
db_nslcmops_text = """
---
+- _admin:
+ created: 1651100375.77829
+ modified: 1651100481.36625
+ projects_read:
+ - 7f563445c74147f78e29b193a6da42bb
+ projects_write:
+ - 7f563445c74147f78e29b193a6da42bb
+ worker: a5adf5972b63
+ detailed-status: success
+ _id: 6bd4362f-da74-4bd8-a825-fd00e610c644
+ id: 6bd4362f-da74-4bd8-a825-fd00e610c644
+ operationState: COMPLETED
+ queuePosition: 0
+ stage: ''
+ errorMessage: ''
+ detailedStatus:
+ statusEnteredTime: 1651100481.36625
+ nsInstanceId: 7e3ad9ce-39b8-4636-a661-7870f25bf800
+ lcmOperationType: update
+ startTime: 1651100375.77823
+ isAutomaticInvocation: false
+ operationParams:
+ updateType: CHANGE_VNFPKG
+ changeVnfPackageData:
+ vnfInstanceId: 6421c7c9-d865-4fb4-9a13-d4275d243e01
+ vnfdId: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77
+ lcmOperationType: update
+ nsInstanceId: f48163a6-c807-47bc-9682-f72caef5af85
+ isCancelPending: false
+ links:
+ self: "/osm/nslcm/v1/ns_lcm_op_occs/6bd4362f-da74-4bd8-a825-fd00e610c644"
+ nsInstance: "/osm/nslcm/v1/ns_instances/f48163a6-c807-47bc-9682-f72caef5af85"
- _admin:
created: 1566823354.4148262
modified: 1566823354.4148262
vdu_count_index: null
vdu_id: null
vdu_name: null
+ type: lxc_proxy_charm
vnfd_id: hackfest3charmed-vnf
- application: alf-c-ab
ee_id: f48163a6-c807-47bc-9682-f72caef5af85.alf-c-ab
vdu_count_index: null
vdu_id: null
vdu_name: null
+ type: lxc_proxy_charm
vnfd_id: hackfest3charmed-vnf
VCA-model-name: f48163a6-c807-47bc-9682-f72caef5af85
modified: 1566823354.3716335
nsd-name-ref: hackfest3charmed-ns
nsd-ref: hackfest3charmed-ns
operational-events: []
- operational-status: failed
+ operational-status: running
orchestration-progress: {}
resource-orchestrator: osmopenmano
+ nsState: INSTANTIATED
short-name: ALF
ssh-authorized-key: null
flavor : [{"vcpu-count":1,"memory-mb":1024,"storage-gb":"10","vim_info":[],"name":"mgmtVM-flv","id":"0"}]
vim_account: ea958ba5-4e58-4405-bf42-6e3be15d4c3a
"""
+db_vnfds_revisions_text = """
+---
+- _admin:
+ created: 1566823352.7154346
+ modified: 1566823353.9295402
+ onboardingState: ONBOARDED
+ operationalState: ENABLED
+ projects_read:
+ - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4
+ projects_write:
+ - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4
+ storage:
+ descriptor: hackfest_3charmed_vnfd/hackfest_3charmed_vnfd.yaml
+ folder: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77
+ fs: local
+ path: /app/storage/
+ pkg-dir: hackfest_3charmed_vnfd
+ zipfile: package.tar.gz
+ type: vnfd
+ usageState: NOT_IN_USE
+ userDefinedData: {}
+ _id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1
+ id: hackfest3charmed-vnf
+ description: >-
+ A VNF consisting of 2 VDUs connected to an internal VL, and one VDU
+ with cloud-init
+ product-name: hackfest3charmed-vnf
+ version: '1.0'
+ mgmt-cp: vnf-mgmt-ext
+ virtual-compute-desc:
+ - id: mgmt-compute
+ virtual-cpu:
+ num-virtual-cpu: 1
+ virtual-memory:
+ size: 1
+ - id: data-compute
+ virtual-cpu:
+ num-virtual-cpu: 1
+ virtual-memory:
+ size: 1
+ kdu:
+ - juju-bundle: stable/native-kdu
+ name: native-kdu
+ virtual-storage-desc:
+ - id: mgmt-storage
+ block-storage-data:
+ size-of-storage: 10
+ - id: data-storage
+ block-storage-data:
+ size-of-storage: 10
+
+ sw-image-desc:
+ - id: hackfest3-mgmt
+ name: hackfest3-mgmt
+
+ vdu:
+ - id: mgmtVM
+ name: mgmtVM
+ cloud-init-file: cloud-config.txt
+ sw-image-desc: hackfest3-mgmt
+ virtual-compute-desc: mgmt-compute
+ virtual-storage-desc: mgmt-storage
+ int-cpd:
+ - id: vnf-mgmt
+ order: 1
+ virtual-network-interface-requirement:
+ - name: mgmtVM-eth0
+ virtual-interface:
+ type: VIRTIO
+ - id: mgmtVM-internal
+ int-virtual-link-desc: internal
+ order: 2
+ virtual-network-interface-requirement:
+ - name: mgmtVM-eth1
+ virtual-interface:
+ type: VIRTIO
+ - id: dataVM
+ name: dataVM
+ sw-image-desc: hackfest3-mgmt
+ virtual-compute-desc: data-compute
+ virtual-storage-desc: data-storage
+ int-cpd:
+ - id: dataVM-internal
+ int-virtual-link-desc: internal
+ order: 1
+ virtual-network-interface-requirement:
+ - name: dataVM-eth1
+ virtual-interface:
+ type: VIRTIO
+ - id: vnf-data
+ order: 2
+ virtual-network-interface-requirement:
+ - name: dataVM-eth0
+ virtual-interface:
+ type: VIRTIO
+ monitoring-parameter:
+ - id: dataVM_cpu_util
+ name: dataVM_cpu_util
+ performance-metric: cpu_utilization
+
+ int-virtual-link-desc:
+ - id: internal
+
+ ext-cpd:
+ - id: vnf-mgmt-ext
+ int-cpd: # Connection to int-cpd
+ vdu-id: mgmtVM
+ cpd: vnf-mgmt
+ - id: vnf-data-ext
+ int-cpd: # Connection to int-cpd
+ vdu-id: dataVM
+ cpd: vnf-data
+
+ df:
+ - id: hackfest_default
+ vdu-profile:
+ - id: mgmtVM
+ min-number-of-instances: 1
+ - id: dataVM
+ min-number-of-instances: 1
+ max-number-of-instances: 10
+ instantiation-level:
+ - id: default
+ vdu-level:
+ - vdu-id: mgmtVM
+ number-of-instances: 1
+ - vdu-id: dataVM
+ number-of-instances: 1
+ scaling-aspect:
+ - id: scale_dataVM
+ name: scale_dataVM
+ max-scale-level: 10
+ aspect-delta-details:
+ deltas:
+ - id: delta1
+ vdu-delta:
+ - id: vdudelta1
+ number-of-instances: 1
+ scaling-policy:
+ - name: auto_cpu_util_above_threshold
+ scaling-type: automatic
+ enabled: true
+ threshold-time: 0
+ cooldown-time: 60
+ scaling-criteria:
+ - name: cpu_util_above_threshold
+ scale-in-relational-operation: LE
+ scale-in-threshold: '15.0000000000'
+ scale-out-relational-operation: GE
+ scale-out-threshold: '60.0000000000'
+ vnf-monitoring-param-ref: dataVM_cpu_util
+ scaling-config-action:
+ - trigger: post-scale-out
+ vnf-config-primitive-name-ref: touch
+ - trigger: pre-scale-in
+ vnf-config-primitive-name-ref: touch
+ lcm-operations-configuration:
+ operate-vnf-op-config:
+ day1-2:
+ - id: hackfest3charmed-vnf
+ execution-environment-list:
+ - id: simple-ee
+ juju:
+ charm: simple
+ initial-config-primitive:
+ - seq: "1"
+ execution-environment-ref: simple-ee
+ name: config
+ parameter:
+ - name: ssh-hostname
+ value: <rw_mgmt_ip>
+ - name: ssh-username
+ value: ubuntu
+ - name: ssh-password
+ value: osm4u
+ - seq: "2"
+ execution-environment-ref: simple-ee
+ name: touch
+ parameter:
+ - name: filename
+ value: <touch_filename>
+ config-primitive:
+ - name: touch
+ execution-environment-ref: simple-ee
+ parameter:
+ - data-type: STRING
+ default-value: <touch_filename2>
+ name: filename
+"""
+
db_vnfds_text = """
---
- _admin:
vim-id: ff181e6d-2597-4244-b40b-bb0174bdfeb6
vnfd-id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77
vnfd-ref: hackfest3charmed-vnf
+- _admin:
+ created: 1566823354.3668208
+ modified: 1566823354.3668208
+ nsState: NOT_INSTANTIATED
+ projects_read:
+ - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4
+ projects_write:
+ - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4
+ _id: 6421c7c9-d865-4fb4-9a13-d4275d243e01
+ additionalParamsForVnf:
+ touch_filename: /home/ubuntu/first-touch-1
+ touch_filename2: /home/ubuntu/second-touch-1
+ connection-point:
+ - connection-point-id: vnf-mgmt
+ id: vnf-mgmt
+ name: vnf-mgmt
+ - connection-point-id: vnf-data
+ id: vnf-data
+ name: vnf-data
+ created-time: 1566823354.36234
+ id: 6421c7c9-d865-4fb4-9a13-d4275d243e01
+ ip-address: 10.205.1.46
+ member-vnf-index-ref: '1'
+ nsr-id-ref: f48163a6-c807-47bc-9682-f72caef5af85
+ vdur:
+ - _id: f0e7d7ce-2443-4dcb-ad0b-5ab9f3b13d37
+ count-index: 0
+ interfaces:
+ - ip-address: 10.205.1.46
+ mac-address: fa:16:3e:b4:3e:b1
+ mgmt-vnf: true
+ name: mgmtVM-eth0
+ ns-vld-id: mgmt
+ - ip-address: 192.168.54.2
+ mac-address: fa:16:3e:6e:7e:78
+ name: mgmtVM-eth1
+ vnf-vld-id: internal
+ internal-connection-point:
+ - connection-point-id: mgmtVM-internal
+ id: mgmtVM-internal
+ name: mgmtVM-internal
+ ip-address: 10.205.1.46
+ name: ALF-1-mgmtVM-1
+ status: ACTIVE
+ status-detailed: null
+ vdu-id-ref: mgmtVM
+ vim-id: c2538499-4c30-41c0-acd5-80cb92f48061
+ ns-image-id: 0
+ ns-flavor-id: 0
+ affinity-or-anti-affinity-group-id : []
+ - _id: ab453219-2d9a-45c2-864d-2c0788385028
+ count-index: 0
+ interfaces:
+ - ip-address: 192.168.54.3
+ mac-address: fa:16:3e:d9:7a:5d
+ name: dataVM-eth0
+ vnf-vld-id: internal
+ - ip-address: 192.168.24.3
+ mac-address: fa:16:3e:d1:6c:0d
+ name: dataVM-xe0
+ ns-vld-id: datanet
+ internal-connection-point:
+ - connection-point-id: dataVM-internal
+ id: dataVM-internal
+ name: dataVM-internal
+ ip-address: null
+ name: ALF-1-dataVM-1
+ status: ACTIVE
+ status-detailed: null
+ vdu-id-ref: dataVM
+ vim-id: 87973c3f-365d-4227-95c2-7a8abc74349c
+ ns-image-id: 0
+ ns-flavor-id: 0
+ affinity-or-anti-affinity-group-id : []
+ vim-account-id: ea958ba5-4e58-4405-bf42-6e3be15d4c3a
+ vld:
+ - id: internal
+ name: ALF-internal
+ status: ACTIVE
+ status-detailed: null
+ vim-id: ff181e6d-2597-4244-b40b-bb0174bdfeb6
+ vnfd-id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77
+ vnfd-ref: hackfest3charmed-vnf
- _admin:
created: 1566823354.3703845
modified: 1566823354.3703845
"ns": "f48163a6-c807-47bc-9682-f72caef5af85",
"instantiate": "a639fac7-e0bb-4225-8ecb-c1f8efcc125e",
"terminate": "a639fac7-e0bb-4225-ffff-c1f8efcc125e",
+ "update": "6bd4362f-da74-4bd8-a825-fd00e610c644",
},
"TEST-KDU": {
"ns": "0bcb701c-ee4d-41ab-8ee6-f4156f7f114d",
from osm_lcm.ng_ro import NgRoClient
from osm_lcm.data_utils.database.database import Database
from osm_lcm.data_utils.filesystem.filesystem import Filesystem
+from osm_lcm.data_utils.vnfd import find_software_version
+from osm_lcm.lcm_utils import check_juju_bundle_existence, get_charm_artifact_path
+from osm_lcm.lcm_utils import LcmException
from uuid import uuid4
+from unittest.mock import Mock, patch
from osm_lcm.tests import test_db_descriptors as descriptors
self.db.create_list(
"vnfds", yaml.load(descriptors.db_vnfds_text, Loader=yaml.Loader)
)
+ self.db.create_list(
+ "vnfds_revisions",
+ yaml.load(descriptors.db_vnfds_revisions_text, Loader=yaml.Loader),
+ )
self.db.create_list(
"nsds", yaml.load(descriptors.db_nsds_text, Loader=yaml.Loader)
)
# self.assertEqual(db_nsr.get("errorDescription "), None, "errorDescription different than None")
# self.assertEqual(db_nsr.get("errorDetail"), None, "errorDetail different than None")
+ # Test update method
+
+ async def test_update(self):
+
+ nsr_id = descriptors.test_ids["TEST-A"]["ns"]
+ nslcmop_id = descriptors.test_ids["TEST-A"]["update"]
+ vnfr_id = "6421c7c9-d865-4fb4-9a13-d4275d243e01"
+ vnfd_id = "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"
+
+ def mock_reset():
+ mock_charm_hash.reset_mock()
+ mock_juju_bundle.reset_mock()
+ fs.sync.reset_mock()
+ mock_charm_upgrade.reset_mock()
+ mock_software_version.reset_mock()
+
+ with self.subTest(
+ i=1,
+ t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed,"
+ "Charm package changed, sw-version is not changed.",
+ ):
+
+ self.db.set_one(
+ "vnfds",
+ q_filter={"_id": vnfd_id},
+ update_dict={"_admin.revision": 3, "kdu": []},
+ )
+
+ self.db.set_one(
+ "vnfds_revisions",
+ q_filter={"_id": vnfd_id + ":1"},
+ update_dict={"_admin.revision": 1, "kdu": []},
+ )
+
+ self.db.set_one(
+ "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
+ )
+
+ mock_charm_hash = Mock(autospec=True)
+ mock_charm_hash.return_value = True
+
+ mock_juju_bundle = Mock(return_value=None)
+
+ mock_software_version = Mock(autospec=True)
+ mock_software_version.side_effect = ["1.0", "1.0"]
+
+ mock_charm_upgrade = asynctest.Mock(autospec=True)
+ task = asyncio.Future()
+ task.set_result(("COMPLETED", "some_output"))
+ mock_charm_upgrade.return_value = task
+
+ fs = Mock(autospec=True)
+ fs.path.__add__ = Mock()
+ fs.path.side_effect = ["/", "/", "/", "/"]
+ fs.sync.side_effect = [None, None]
+
+ instance = self.my_ns
+
+ expected_operation_state = "COMPLETED"
+ expected_operation_error = ""
+ expected_vnfr_revision = 3
+ expected_ns_state = "INSTANTIATED"
+ expected_ns_operational_state = "running"
+
+ with patch.object(instance, "fs", fs), patch(
+ "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
+ ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade), patch(
+ "osm_lcm.data_utils.vnfd.find_software_version", mock_software_version
+ ), patch(
+ "osm_lcm.lcm_utils.check_juju_bundle_existence", mock_juju_bundle
+ ):
+
+ await instance.update(nsr_id, nslcmop_id)
+ return_operation_state = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("operationState")
+ return_operation_error = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("errorMessage")
+ return_ns_operational_state = self.db.get_one(
+ "nsrs", {"_id": nsr_id}
+ ).get("operational-status")
+
+ return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+ "revision"
+ )
+
+ return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+ "nsState"
+ )
+
+ mock_charm_hash.assert_called_with(
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/hackfest_3charmed_vnfd/charms/simple",
+ )
+
+ self.assertEqual(fs.sync.call_count, 2)
+ self.assertEqual(return_ns_state, expected_ns_state)
+ self.assertEqual(return_operation_state, expected_operation_state)
+ self.assertEqual(return_operation_error, expected_operation_error)
+ self.assertEqual(
+ return_ns_operational_state, expected_ns_operational_state
+ )
+ self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+ mock_reset()
+
+ with self.subTest(
+ i=2, t="Update type: CHANGE_VNFPKG, latest_vnfd revision not changed"
+ ):
+
+ self.db.set_one(
+ "vnfds", q_filter={"_id": vnfd_id}, update_dict={"_admin.revision": 1}
+ )
+
+ self.db.set_one(
+ "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
+ )
+
+ mock_charm_hash = Mock(autospec=True)
+ mock_charm_hash.return_value = True
+
+ mock_juju_bundle = Mock(return_value=None)
+ mock_software_version = Mock(autospec=True)
+
+ mock_charm_upgrade = asynctest.Mock(autospec=True)
+ task = asyncio.Future()
+ task.set_result(("COMPLETED", "some_output"))
+ mock_charm_upgrade.return_value = task
+
+ fs = Mock(autospec=True)
+ fs.path.__add__ = Mock()
+ fs.path.side_effect = ["/", "/", "/", "/"]
+ fs.sync.side_effect = [None, None]
+
+ instance = self.my_ns
+
+ expected_operation_state = "COMPLETED"
+ expected_operation_error = ""
+ expected_vnfr_revision = 1
+ expected_ns_state = "INSTANTIATED"
+ expected_ns_operational_state = "running"
+
+ with patch.object(instance, "fs", fs), patch(
+ "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
+ ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade), patch(
+ "osm_lcm.lcm_utils.check_juju_bundle_existence", mock_juju_bundle
+ ):
+
+ await instance.update(nsr_id, nslcmop_id)
+
+ return_operation_state = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("operationState")
+
+ return_operation_error = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("errorMessage")
+
+ return_ns_operational_state = self.db.get_one(
+ "nsrs", {"_id": nsr_id}
+ ).get("operational-status")
+
+ return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+ "nsState"
+ )
+
+ return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+ "revision"
+ )
+
+ mock_charm_hash.assert_not_called()
+ mock_software_version.assert_not_called()
+ mock_juju_bundle.assert_not_called()
+ mock_charm_upgrade.assert_not_called()
+ fs.sync.assert_not_called()
+
+ self.assertEqual(return_ns_state, expected_ns_state)
+ self.assertEqual(return_operation_state, expected_operation_state)
+ self.assertEqual(return_operation_error, expected_operation_error)
+ self.assertEqual(
+ return_ns_operational_state, expected_ns_operational_state
+ )
+ self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+ mock_reset()
+
+ with self.subTest(
+ i=3,
+ t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed, "
+ "Charm package is not changed, sw-version is not changed.",
+ ):
+
+ self.db.set_one(
+ "vnfds", q_filter={"_id": vnfd_id}, update_dict={"_admin.revision": 3}
+ )
+
+ self.db.set_one(
+ "vnfds_revisions",
+ q_filter={"_id": vnfd_id + ":1"},
+ update_dict={"_admin.revision": 1},
+ )
+
+ self.db.set_one(
+ "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
+ )
+
+ mock_charm_hash = Mock(autospec=True)
+ mock_charm_hash.return_value = False
+
+ mock_juju_bundle = Mock(return_value=None)
+
+ mock_software_version = Mock(autospec=True)
+
+ mock_charm_upgrade = asynctest.Mock(autospec=True)
+ task = asyncio.Future()
+ task.set_result(("COMPLETED", "some_output"))
+ mock_charm_upgrade.return_value = task
+ mock_software_version.side_effect = ["1.0", "1.0"]
+
+ fs = Mock(autospec=True)
+ fs.path.__add__ = Mock()
+ fs.path.side_effect = ["/", "/", "/", "/"]
+ fs.sync.side_effect = [None, None]
+
+ instance = self.my_ns
+
+ expected_operation_state = "COMPLETED"
+ expected_operation_error = ""
+ expected_vnfr_revision = 3
+ expected_ns_state = "INSTANTIATED"
+ expected_ns_operational_state = "running"
+
+ with patch.object(instance, "fs", fs), patch(
+ "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
+ ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade), patch(
+ "osm_lcm.lcm_utils.check_juju_bundle_existence", mock_juju_bundle
+ ):
+
+ await instance.update(nsr_id, nslcmop_id)
+
+ return_operation_state = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("operationState")
+
+ return_operation_error = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("errorMessage")
+
+ return_ns_operational_state = self.db.get_one(
+ "nsrs", {"_id": nsr_id}
+ ).get("operational-status")
+
+ return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+ "revision"
+ )
+
+ return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+ "nsState"
+ )
+
+ mock_charm_hash.assert_called_with(
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/hackfest_3charmed_vnfd/charms/simple",
+ )
+
+ self.assertEqual(fs.sync.call_count, 2)
+ self.assertEqual(mock_charm_hash.call_count, 1)
+
+ mock_juju_bundle.assert_not_called()
+ mock_charm_upgrade.assert_not_called()
+
+ self.assertEqual(return_ns_state, expected_ns_state)
+ self.assertEqual(return_operation_state, expected_operation_state)
+ self.assertEqual(return_operation_error, expected_operation_error)
+ self.assertEqual(
+ return_ns_operational_state, expected_ns_operational_state
+ )
+ self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+ mock_reset()
+
+ with self.subTest(
+ i=4,
+ t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed, "
+ "Charm package exists, sw-version changed.",
+ ):
+
+ self.db.set_one(
+ "vnfds",
+ q_filter={"_id": vnfd_id},
+ update_dict={"_admin.revision": 3, "software-version": "3.0"},
+ )
+
+ self.db.set_one(
+ "vnfds_revisions",
+ q_filter={"_id": vnfd_id + ":1"},
+ update_dict={"_admin.revision": 1},
+ )
+
+ self.db.set_one(
+ "vnfrs",
+ q_filter={"_id": vnfr_id},
+ update_dict={"revision": 1},
+ )
+
+ mock_charm_hash = Mock(autospec=True)
+ mock_charm_hash.return_value = False
+
+ mock_juju_bundle = Mock(return_value=None)
+
+ mock_charm_upgrade = asynctest.Mock(autospec=True)
+ task = asyncio.Future()
+ task.set_result(("COMPLETED", "some_output"))
+ mock_charm_upgrade.return_value = task
+
+ mock_charm_artifact = Mock(autospec=True)
+ mock_charm_artifact.side_effect = [
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/hackfest_3charmed_vnfd/charms/simple",
+ ]
+
+ fs = Mock(autospec=True)
+ fs.path.__add__ = Mock()
+ fs.path.side_effect = ["/", "/", "/", "/"]
+ fs.sync.side_effect = [None, None]
+
+ instance = self.my_ns
+
+ expected_operation_state = "FAILED"
+ expected_operation_error = "FAILED Checking if existing VNF has charm: Software version change is not supported as VNF instance 6421c7c9-d865-4fb4-9a13-d4275d243e01 has charm."
+ expected_vnfr_revision = 1
+ expected_ns_state = "INSTANTIATED"
+ expected_ns_operational_state = "running"
+
+ with patch.object(instance, "fs", fs), patch(
+ "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
+ ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade), patch(
+ "osm_lcm.lcm_utils.get_charm_artifact_path", mock_charm_artifact
+ ):
+
+ await instance.update(nsr_id, nslcmop_id)
+
+ return_operation_state = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("operationState")
+
+ return_operation_error = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("errorMessage")
+
+ return_ns_operational_state = self.db.get_one(
+ "nsrs", {"_id": nsr_id}
+ ).get("operational-status")
+
+ return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+ "revision"
+ )
+
+ return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+ "nsState"
+ )
+
+ self.assertEqual(fs.sync.call_count, 2)
+ mock_charm_hash.assert_not_called()
+
+ mock_juju_bundle.assert_not_called()
+ mock_charm_upgrade.assert_not_called()
+
+ self.assertEqual(return_ns_state, expected_ns_state)
+ self.assertEqual(return_operation_state, expected_operation_state)
+ self.assertEqual(return_operation_error, expected_operation_error)
+ self.assertEqual(
+ return_ns_operational_state, expected_ns_operational_state
+ )
+ self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+ mock_reset()
+
+ with self.subTest(
+ i=5,
+ t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed,"
+ "Charm package exists, sw-version not changed, juju-bundle exists",
+ ):
+
+ self.db.set_one(
+ "vnfds",
+ q_filter={"_id": vnfd_id},
+ update_dict={
+ "_admin.revision": 3,
+ "software-version": "1.0",
+ "kdu.0.juju-bundle": "stable/native-kdu",
+ },
+ )
+
+ self.db.set_one(
+ "vnfds_revisions",
+ q_filter={"_id": vnfd_id + ":1"},
+ update_dict={
+ "_admin.revision": 1,
+ "software-version": "1.0",
+ "kdu.0.juju-bundle": "stable/native-kdu",
+ },
+ )
+
+ self.db.set_one(
+ "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
+ )
+
+ mock_charm_hash = Mock(autospec=True)
+ mock_charm_hash.return_value = True
+
+ mock_charm_artifact = Mock(autospec=True)
+ mock_charm_artifact.side_effect = [
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/hackfest_3charmed_vnfd/charms/simple",
+ ]
+
+ fs = Mock(autospec=True)
+ fs.path.__add__ = Mock()
+ fs.path.side_effect = ["/", "/", "/", "/"]
+ fs.sync.side_effect = [None, None]
+
+ instance = self.my_ns
+
+ expected_operation_state = "FAILED"
+ expected_operation_error = "FAILED Checking whether VNF uses juju bundle: Charm upgrade is not supported for the instance which uses juju-bundle: stable/native-kdu"
+ expected_vnfr_revision = 1
+ expected_ns_state = "INSTANTIATED"
+ expected_ns_operational_state = "running"
+
+ with patch.object(instance, "fs", fs), patch(
+ "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
+ ), patch("osm_lcm.lcm_utils.get_charm_artifact_path", mock_charm_artifact):
+
+ await instance.update(nsr_id, nslcmop_id)
+
+ return_operation_state = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("operationState")
+
+ return_operation_error = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("errorMessage")
+
+ return_ns_operational_state = self.db.get_one(
+ "nsrs", {"_id": nsr_id}
+ ).get("operational-status")
+
+ return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+ "revision"
+ )
+
+ return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+ "nsState"
+ )
+
+ self.assertEqual(fs.sync.call_count, 2)
+ self.assertEqual(mock_charm_hash.call_count, 1)
+ self.assertEqual(mock_charm_hash.call_count, 1)
+
+ mock_charm_upgrade.assert_not_called()
+
+ self.assertEqual(return_ns_state, expected_ns_state)
+ self.assertEqual(return_operation_state, expected_operation_state)
+ self.assertEqual(return_operation_error, expected_operation_error)
+ self.assertEqual(
+ return_ns_operational_state, expected_ns_operational_state
+ )
+ self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+ mock_reset()
+
+ with self.subTest(
+ i=6,
+ t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed,"
+ "Charm package exists, sw-version not changed, charm-upgrade failed",
+ ):
+
+ self.db.set_one(
+ "vnfds",
+ q_filter={"_id": vnfd_id},
+ update_dict={
+ "_admin.revision": 3,
+ "software-version": "1.0",
+ "kdu": [],
+ },
+ )
+
+ self.db.set_one(
+ "vnfds_revisions",
+ q_filter={"_id": vnfd_id + ":1"},
+ update_dict={
+ "_admin.revision": 1,
+ "software-version": "1.0",
+ "kdu": [],
+ },
+ )
+
+ self.db.set_one(
+ "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
+ )
+
+ mock_charm_hash = Mock(autospec=True)
+ mock_charm_hash.return_value = True
+
+ mock_charm_upgrade = asynctest.Mock(autospec=True)
+ task = asyncio.Future()
+ task.set_result(("FAILED", "some_error"))
+ mock_charm_upgrade.return_value = task
+
+ mock_charm_artifact = Mock(autospec=True)
+ mock_charm_artifact.side_effect = [
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/hackfest_3charmed_vnfd/charms/simple",
+ ]
+
+ fs = Mock(autospec=True)
+ fs.path.__add__ = Mock()
+ fs.path.side_effect = ["/", "/", "/", "/"]
+ fs.sync.side_effect = [None, None]
+
+ instance = self.my_ns
+
+ expected_operation_state = "FAILED"
+ expected_operation_error = "some_error"
+ expected_vnfr_revision = 1
+ expected_ns_state = "INSTANTIATED"
+ expected_ns_operational_state = "running"
+
+ with patch.object(instance, "fs", fs), patch(
+ "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
+ ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade):
+
+ await instance.update(nsr_id, nslcmop_id)
+
+ return_operation_state = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("operationState")
+
+ return_operation_error = self.db.get_one(
+ "nslcmops", {"_id": nslcmop_id}
+ ).get("errorMessage")
+
+ return_ns_operational_state = self.db.get_one(
+ "nsrs", {"_id": nsr_id}
+ ).get("operational-status")
+
+ return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+ "revision"
+ )
+
+ return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+ "nsState"
+ )
+
+ self.assertEqual(fs.sync.call_count, 2)
+ self.assertEqual(mock_charm_hash.call_count, 1)
+ self.assertEqual(mock_charm_upgrade.call_count, 1)
+
+ self.assertEqual(return_ns_state, expected_ns_state)
+ self.assertEqual(return_operation_state, expected_operation_state)
+ self.assertEqual(return_operation_error, expected_operation_error)
+ self.assertEqual(
+ return_ns_operational_state, expected_ns_operational_state
+ )
+ self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+ mock_reset()
+
+ def test_ns_update_helper_methods(self):
+ def mock_reset():
+ fs.mock_reset()
+ mock_path.mock_reset()
+ mock_checksumdir.mock_reset()
+
+ with self.subTest(
+ i=1, t="Find software version, VNFD does not have have software version"
+ ):
+ # Testing method find_software_version
+
+ db_vnfd = self.db.get_one(
+ "vnfds", {"_id": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"}
+ )
+ expected_result = "1.0"
+ result = find_software_version(db_vnfd)
+ self.assertEqual(
+ result, expected_result, "Default sw version should be 1.0"
+ )
+
+ with self.subTest(
+ i=2, t="Find software version, VNFD includes software version"
+ ):
+ # Testing method find_software_version
+
+ db_vnfd = self.db.get_one(
+ "vnfds", {"_id": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"}
+ )
+ db_vnfd["software-version"] = "3.1"
+ expected_result = "3.1"
+ result = find_software_version(db_vnfd)
+ self.assertEqual(result, expected_result, "VNFD software version is wrong")
+
+ with self.subTest(i=3, t="Check charm hash, Hash has did not change"):
+ # Testing method check_charm_hash_changed
+
+ current_path, target_path = "/tmp/charm1", "/tmp/charm1"
+ fs = Mock(autospec=True)
+ fs.path.__add__ = Mock()
+ fs.path.side_effect = ["/", "/", "/", "/"]
+
+ mock_path = Mock(autospec=True)
+ mock_path.exists.side_effect = [True, True]
+
+ mock_checksumdir = Mock(autospec=True)
+ mock_checksumdir.dirhash.side_effect = ["hash_value", "hash_value"]
+
+ instance = self.my_ns
+ expected_result = False
+
+ with patch.object(instance, "fs", fs), patch(
+ "checksumdir.dirhash", mock_checksumdir.dirhash
+ ), patch("os.path.exists", mock_path.exists):
+
+ result = instance.check_charm_hash_changed(current_path, target_path)
+ self.assertEqual(
+ result, expected_result, "Wrong charm hash control value"
+ )
+ self.assertEqual(mock_path.exists.call_count, 2)
+ self.assertEqual(mock_checksumdir.dirhash.call_count, 2)
+
+ mock_reset()
+
+ with self.subTest(i=4, t="Check charm hash, Hash has changed"):
+ # Testing method check_charm_hash_changed
+
+ current_path, target_path = "/tmp/charm1", "/tmp/charm2"
+ fs = Mock(autospec=True)
+ fs.path.__add__ = Mock()
+ fs.path.side_effect = ["/", "/", "/", "/"]
+
+ mock_path = Mock(autospec=True)
+ mock_path.exists.side_effect = [True, True]
+
+ mock_checksumdir = Mock(autospec=True)
+ mock_checksumdir.dirhash.side_effect = ["hash_value", "another_hash_value"]
+
+ instance = self.my_ns
+ expected_result = True
+
+ with patch.object(instance, "fs", fs), patch(
+ "checksumdir.dirhash", mock_checksumdir.dirhash
+ ), patch("os.path.exists", mock_path.exists):
+
+ result = instance.check_charm_hash_changed(current_path, target_path)
+ self.assertEqual(
+ result, expected_result, "Wrong charm hash control value"
+ )
+ self.assertEqual(mock_path.exists.call_count, 2)
+ self.assertEqual(mock_checksumdir.dirhash.call_count, 2)
+
+ mock_reset()
+
+ with self.subTest(i=5, t="Check charm hash, Charm path does not exists"):
+ # Testing method check_charm_hash_changed
+
+ current_path, target_path = "/tmp/charm1", "/tmp/charm2"
+ fs = Mock(autospec=True)
+ fs.path.__add__ = Mock()
+ fs.path.side_effect = ["/", "/", "/", "/"]
+
+ mock_path = Mock(autospec=True)
+ mock_path.exists.side_effect = [True, False]
+
+ mock_checksumdir = Mock(autospec=True)
+ mock_checksumdir.dirhash.side_effect = ["hash_value", "hash_value"]
+
+ instance = self.my_ns
+
+ with patch.object(instance, "fs", fs), patch(
+ "checksumdir.dirhash", mock_checksumdir.dirhash
+ ), patch("os.path.exists", mock_path.exists):
+
+ with self.assertRaises(LcmException):
+
+ instance.check_charm_hash_changed(current_path, target_path)
+ self.assertEqual(mock_path.exists.call_count, 2)
+ self.assertEqual(mock_checksumdir.dirhash.call_count, 0)
+
+ mock_reset()
+
+ with self.subTest(i=6, t="Check juju bundle existence"):
+ # Testing method check_juju_bundle_existence
+
+ test_vnfd1 = self.db.get_one(
+ "vnfds", {"_id": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"}
+ )
+ test_vnfd2 = self.db.get_one(
+ "vnfds", {"_id": "d96b1cdf-5ad6-49f7-bf65-907ada989293"}
+ )
+
+ expected_result = None
+ result = check_juju_bundle_existence(test_vnfd1)
+ self.assertEqual(result, expected_result, "Wrong juju bundle name")
+
+ expected_result = "stable/native-kdu"
+ result = check_juju_bundle_existence(test_vnfd2)
+ self.assertEqual(result, expected_result, "Wrong juju bundle name")
+
+ with self.subTest(i=7, t="Check charm artifacts"):
+ # Testing method check_juju_bundle_existence
+
+ base_folder = {
+ "folder": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
+ "pkg-dir": "hackfest_3charmed_vnfd",
+ }
+ charm_name = "simple"
+ charm_type = "lxc_proxy_charm"
+ revision = 3
+
+ expected_result = "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:3/hackfest_3charmed_vnfd/charms/simple"
+ result = get_charm_artifact_path(
+ base_folder, charm_name, charm_type, revision
+ )
+ self.assertEqual(result, expected_result, "Wrong charm artifact path")
+
+ # SOL004 packages
+ base_folder = {
+ "folder": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
+ }
+ charm_name = "basic"
+ charm_type = ""
+ revision = ""
+
+ expected_result = (
+ "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/Scripts/helm-charts/basic"
+ )
+ result = get_charm_artifact_path(
+ base_folder, charm_name, charm_type, revision
+ )
+ self.assertEqual(result, expected_result, "Wrong charm artifact path")
+
if __name__ == "__main__":
asynctest.main()