9a875b3caa9247fa7b3189847edd24042feb1c19
[osm/LCM.git] / osm_lcm / data_utils / wim.py
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 # find VIMs to be connected by VLD
55 vims_to_connect = get_vims_to_connect(db_nsr, db_vnfrs, target_vld)
56 # check if we need a WIM to interconnect the VNFs in different VIMs
57 if len(vims_to_connect) < 2:
58 logger.info(
59 "WIM not needed, VLD({:s}) does not involve multiple VIMs".format(
60 str(target_vld)
61 )
62 )
63 return None, None
64 # if more than one VIM needs to be connected...
65 logger.info(
66 "WIM is needed, multiple VIMs to interconnect: {:s}".format(
67 str(vims_to_connect)
68 )
69 )
70 # find a WIM having these VIMs on its wim_port_mapping setting
71 candidate_wims = get_candidate_wims(vims_to_connect)
72 logger.info("Candidate WIMs: {:s}".format(str(candidate_wims)))
73
74 # check if a desired wim_account_id is specified in vld_params
75 wim_account_id = vld_params.get("wimAccountId")
76 if wim_account_id:
77 # check if the desired WIM account is feasible
78 # implicitly checks if it exists in the DB
79 db_wim = candidate_wims.get(wim_account_id)
80 if db_wim:
81 return wim_account_id, db_wim
82 msg = (
83 "WimAccountId specified in VldParams({:s}) cannot be used "
84 "to connect the required VIMs({:s}). Candidate WIMs are: {:s}"
85 )
86 raise LcmException(
87 msg.format(str(vld_params), str(vims_to_connect), str(candidate_wims))
88 )
89
90 # TODO: sort feasible WIMs based on some meaningful criteria, and select best one
91 wim_account_id = next(iter(candidate_wims.keys()), None)
92 db_wim = candidate_wims.get(wim_account_id)
93 return wim_account_id, db_wim
94
95
96 def get_target_wim_attrs(nsr_id, target_vld, vld_params):
97 target_vims = [
98 "vim:{:s}".format(vim_id) for vim_id in vld_params["vim-network-name"]
99 ]
100 wim_vld = "nsrs:{}:vld.{}".format(nsr_id, target_vld["id"])
101 vld_type = target_vld.get("type")
102 if vld_type is None:
103 vld_type = "ELAN" if len(target_vims) > 2 else "ELINE"
104 target_wim_attrs = {
105 "sdn": True,
106 "target_vims": target_vims,
107 "vlds": [wim_vld],
108 "type": vld_type,
109 }
110 return target_wim_attrs
111
112
113 def get_sdn_ports(vld_params, db_wim):
114 if vld_params.get("provider-network"):
115 # if SDN ports are specified in VLD params, use them
116 return vld_params["provider-network"].get("sdn-ports")
117
118 # otherwise, compose SDN ports required
119 wim_port_mapping = db_wim.get("config", {}).get("wim_port_mapping", [])
120 sdn_ports = []
121 for vim_id in vld_params["vim-network-name"]:
122 db_vim = VimAccountDB.get_vim_account_with_id(vim_id)
123 vim_name = db_vim["name"]
124 mapping = next(
125 (m for m in wim_port_mapping if m["datacenter_id"] == vim_name),
126 None,
127 )
128 if mapping is None:
129 msg = "WIM({:s},{:s}) does not specify a mapping for VIM({:s},{:s})"
130 raise LcmException(
131 msg.format(
132 db_wim["name"],
133 db_wim["_id"],
134 db_vim["name"],
135 db_vim["_id"],
136 )
137 )
138 sdn_port = {
139 "device_id": vim_name,
140 "switch_id": mapping.get("device_id"),
141 "switch_port": mapping.get("device_interface_id"),
142 "service_endpoint_id": mapping.get("service_endpoint_id"),
143 }
144 service_mapping_info = mapping.get("service_mapping_info", {})
145 encapsulation = service_mapping_info.get("encapsulation", {})
146 if encapsulation.get("type"):
147 sdn_port["service_endpoint_encapsulation_type"] = encapsulation["type"]
148 if encapsulation.get("vlan"):
149 sdn_port["vlan"] = encapsulation["vlan"]
150 sdn_ports.append(sdn_port)
151 return sdn_ports