| gifrerenom | 17cd492 | 2022-11-11 14:44:57 +0000 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
| 2 | |
| 3 | # This file is part of OSM Life-Cycle Management module |
| 4 | # |
| 5 | # Copyright 2022 ETSI |
| 6 | # |
| 7 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 8 | # not use this file except in compliance with the License. You may obtain |
| 9 | # a copy of the License at |
| 10 | # |
| 11 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | # |
| 13 | # Unless required by applicable law or agreed to in writing, software |
| 14 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 15 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 16 | # License for the specific language governing permissions and limitations |
| 17 | # under the License. |
| 18 | ## |
| 19 | |
| 20 | |
| 21 | from osm_lcm.data_utils.database.vim_account import VimAccountDB |
| 22 | from osm_lcm.data_utils.database.wim_account import WimAccountDB |
| 23 | from osm_lcm.data_utils.vim import get_vims_to_connect |
| 24 | from osm_lcm.lcm_utils import LcmException |
| 25 | |
| 26 | __author__ = ( |
| 27 | "Lluis Gifre <lluis.gifre@cttc.es>, Ricard Vilalta <ricard.vilalta@cttc.es>" |
| 28 | ) |
| 29 | |
| 30 | |
| 31 | def get_candidate_wims(vims_to_connect): |
| 32 | all_wim_accounts = WimAccountDB.get_all_wim_accounts() |
| 33 | candidate_wims = {} |
| 34 | for wim_id, db_wim in all_wim_accounts.items(): |
| 35 | wim_port_mapping = db_wim.get("config", {}).get("wim_port_mapping", []) |
| 36 | wim_dc_ids = { |
| 37 | m.get("datacenter_id") for m in wim_port_mapping if m.get("datacenter_id") |
| 38 | } |
| 39 | not_reachable_vims = vims_to_connect.difference(wim_dc_ids) |
| 40 | if len(not_reachable_vims) > 0: |
| 41 | continue |
| 42 | # TODO: consider adding other filtering fields such as supported layer(s) [L2, L3, ...] |
| 43 | candidate_wims[wim_id] = db_wim |
| 44 | return candidate_wims |
| 45 | |
| 46 | |
| 47 | def select_feasible_wim_account(db_nsr, db_vnfrs, target_vld, vld_params, logger): |
| 48 | logger.info("Checking if WIM is needed for VLD({:s})...".format(str(target_vld))) |
| 49 | if target_vld.get("mgmt-network", False): |
| 50 | logger.info( |
| 51 | "WIM not needed, VLD({:s}) is a management network".format(str(target_vld)) |
| 52 | ) |
| 53 | return None, None # assume mgmt networks do not use a WIM |
| 54 | |
| 55 | # check if WIM account is explicitly False |
| 56 | wim_account_id = vld_params.get("wimAccountId") |
| 57 | if wim_account_id is not None and not wim_account_id: |
| 58 | logger.info( |
| 59 | "VLD({:s}) explicitly specifies not to use a WIM".format(str(target_vld)) |
| 60 | ) |
| 61 | return None, None # WIM account explicitly set to False, do not use a WIM |
| 62 | |
| 63 | # find VIMs to be connected by VLD |
| 64 | vims_to_connect = get_vims_to_connect(db_nsr, db_vnfrs, target_vld, logger) |
| 65 | # check if we need a WIM to interconnect the VNFs in different VIMs |
| 66 | if len(vims_to_connect) < 2: |
| 67 | logger.info( |
| 68 | "WIM not needed, VLD({:s}) does not involve multiple VIMs".format( |
| 69 | str(target_vld) |
| 70 | ) |
| 71 | ) |
| 72 | return None, None |
| 73 | # if more than one VIM needs to be connected... |
| 74 | logger.info( |
| 75 | "WIM is needed, multiple VIMs to interconnect: {:s}".format( |
| 76 | str(vims_to_connect) |
| 77 | ) |
| 78 | ) |
| 79 | # find a WIM having these VIMs on its wim_port_mapping setting |
| 80 | candidate_wims = get_candidate_wims(vims_to_connect) |
| 81 | logger.info("Candidate WIMs: {:s}".format(str(candidate_wims))) |
| 82 | |
| Pedro Escaleira | 8b2a7ea | 2023-03-28 18:44:11 +0100 | [diff] [blame] | 83 | # check if there are no WIM candidates |
| 84 | if len(candidate_wims) == 0: |
| 85 | logger.info("No WIM accounts found") |
| 86 | return None, None |
| 87 | |
| gifrerenom | 17cd492 | 2022-11-11 14:44:57 +0000 | [diff] [blame] | 88 | # check if a desired wim_account_id is specified in vld_params |
| 89 | wim_account_id = vld_params.get("wimAccountId") |
| 90 | if wim_account_id: |
| 91 | # check if the desired WIM account is feasible |
| 92 | # implicitly checks if it exists in the DB |
| 93 | db_wim = candidate_wims.get(wim_account_id) |
| 94 | if db_wim: |
| 95 | return wim_account_id, db_wim |
| 96 | msg = ( |
| 97 | "WimAccountId specified in VldParams({:s}) cannot be used " |
| 98 | "to connect the required VIMs({:s}). Candidate WIMs are: {:s}" |
| 99 | ) |
| 100 | raise LcmException( |
| 101 | msg.format(str(vld_params), str(vims_to_connect), str(candidate_wims)) |
| 102 | ) |
| 103 | |
| 104 | # if multiple candidate WIMs: report error message |
| 105 | if len(candidate_wims) > 1: |
| 106 | msg = ( |
| 107 | "Multiple candidate WIMs found ({:s}) and wim_account not specified. " |
| 108 | "Please, specify the WIM account to be used." |
| 109 | ) |
| 110 | raise LcmException(msg.format(str(candidate_wims.keys()))) |
| 111 | |
| 112 | # a single candidate WIM has been found, retrieve it |
| 113 | return candidate_wims.popitem() # returns tuple (wim_account_id, db_wim) |
| 114 | |
| 115 | |
| 116 | def get_target_wim_attrs(nsr_id, target_vld, vld_params): |
| 117 | target_vims = [ |
| 118 | "vim:{:s}".format(vim_id) for vim_id in vld_params["vim-network-name"] |
| 119 | ] |
| 120 | wim_vld = "nsrs:{}:vld.{}".format(nsr_id, target_vld["id"]) |
| 121 | vld_type = target_vld.get("type") |
| 122 | if vld_type is None: |
| 123 | vld_type = "ELAN" if len(target_vims) > 2 else "ELINE" |
| 124 | target_wim_attrs = { |
| 125 | "sdn": True, |
| 126 | "target_vims": target_vims, |
| 127 | "vlds": [wim_vld], |
| 128 | "type": vld_type, |
| 129 | } |
| 130 | return target_wim_attrs |
| 131 | |
| 132 | |
| 133 | def get_sdn_ports(vld_params, db_wim): |
| 134 | if vld_params.get("provider-network"): |
| 135 | # if SDN ports are specified in VLD params, use them |
| 136 | return vld_params["provider-network"].get("sdn-ports") |
| 137 | |
| 138 | # otherwise, compose SDN ports required |
| 139 | wim_port_mapping = db_wim.get("config", {}).get("wim_port_mapping", []) |
| 140 | sdn_ports = [] |
| 141 | for vim_id in vld_params["vim-network-name"]: |
| 142 | db_vim = VimAccountDB.get_vim_account_with_id(vim_id) |
| 143 | vim_name = db_vim["name"] |
| 144 | mapping = next( |
| 145 | (m for m in wim_port_mapping if m["datacenter_id"] == vim_name), |
| 146 | None, |
| 147 | ) |
| 148 | if mapping is None: |
| 149 | msg = "WIM({:s},{:s}) does not specify a mapping for VIM({:s},{:s})" |
| 150 | raise LcmException( |
| 151 | msg.format( |
| 152 | db_wim["name"], |
| 153 | db_wim["_id"], |
| 154 | db_vim["name"], |
| 155 | db_vim["_id"], |
| 156 | ) |
| 157 | ) |
| 158 | sdn_port = { |
| 159 | "device_id": vim_name, |
| 160 | "switch_id": mapping.get("device_id"), |
| 161 | "switch_port": mapping.get("device_interface_id"), |
| 162 | "service_endpoint_id": mapping.get("service_endpoint_id"), |
| 163 | } |
| 164 | service_mapping_info = mapping.get("service_mapping_info", {}) |
| 165 | encapsulation = service_mapping_info.get("encapsulation", {}) |
| 166 | if encapsulation.get("type"): |
| 167 | sdn_port["service_endpoint_encapsulation_type"] = encapsulation["type"] |
| 168 | if encapsulation.get("vlan"): |
| 169 | sdn_port["vlan"] = encapsulation["vlan"] |
| 170 | sdn_ports.append(sdn_port) |
| 171 | return sdn_ports |