RIFT-16103 : Adding VDU Name field in YAML File.
[osm/SO.git] / rwcm / plugins / rwconman / rift / tasklets / rwconmantasklet / RiftCA.py
1 #
2 # Copyright 2016 RIFT.IO Inc
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16
17 import asyncio
18 import concurrent.futures
19 import re
20 import tempfile
21 import yaml
22 import os
23
24 from gi.repository import (
25 RwDts as rwdts,
26 )
27
28 from . import riftcm_config_plugin
29 from . import rwconman_events as Events
30
31 class RiftCAConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase):
32 """
33 Implementation of the riftcm_config_plugin.RiftCMConfigPluginBase
34 """
35 def __init__(self, dts, log, loop, account):
36 riftcm_config_plugin.RiftCMConfigPluginBase.__init__(self, dts, log, loop, account)
37 self._name = account.name
38 self._type = riftcm_config_plugin.DEFAULT_CAP_TYPE
39 self._rift_install_dir = os.environ['RIFT_INSTALL']
40 self._rift_artif_dir = os.environ['RIFT_ARTIFACTS']
41 self._rift_vnfs = {}
42 self._tasks = {}
43
44 # Instantiate events that will handle RiftCA configuration requests
45 self._events = Events.ConfigManagerEvents(dts, log, loop, self)
46
47 @property
48 def name(self):
49 return self._name
50
51 @property
52 def agent_type(self):
53 return self._type
54
55 @property
56 def agent_data(self):
57 return dict(
58 type=self.agent_type,
59 name=self.name,
60 )
61
62 def vnfr(self, vnfr_id):
63 try:
64 vnfr = self._rift_vnfs[vnfr_id].vnfr
65 except KeyError:
66 self._log.debug("RiftCA: Did not find VNFR %s in Rift plugin", vnfr_id)
67 return None
68
69 return vnfr
70
71 def get_service_name(self, vnfr_id):
72 vnfr = self.vnfr(vnfr_id)
73 if vnfr:
74 return vnfr['name']
75 return None
76
77 @asyncio.coroutine
78 def notify_create_vlr(self, agent_nsr, agent_vnfr, vld, vlr):
79 """
80 Notification of create VL record
81 """
82 pass
83
84 @asyncio.coroutine
85 def is_vnf_configurable(self, agent_vnfr):
86 '''
87 This needs to be part of abstract class
88 '''
89 loop_count = 10
90 while loop_count:
91 loop_count -= 1
92 # Set this VNF's configurability status (need method to check)
93 yield from asyncio.sleep(2, loop=self._loop)
94
95 def riftca_log(self, name, level, log_str, *args):
96 getattr(self._log, level)('RiftCA:({}) {}'.format(name, log_str), *args)
97
98 @asyncio.coroutine
99 def notify_create_vnfr(self, agent_nsr, agent_vnfr):
100 """
101 Notification of create Network VNF record
102 """
103 # Deploy the charm if specified for the vnf
104 self._log.debug("Rift config agent: create vnfr nsr={} vnfr={}"
105 .format(agent_nsr.name, agent_vnfr.name))
106 try:
107 self._loop.create_task(self.is_vnf_configurable(agent_vnfr))
108 except Exception as e:
109 self._log.debug("Rift config agent: vnf_configuration error for VNF:%s/%s: %s",
110 agent_nsr.name, agent_vnfr.name, str(e))
111 return False
112
113 return True
114
115 @asyncio.coroutine
116 def notify_instantiate_vnfr(self, agent_nsr, agent_vnfr):
117 """
118 Notification of Instantiate NSR with the passed nsr id
119 """
120 pass
121
122 @asyncio.coroutine
123 def notify_instantiate_vlr(self, agent_nsr, agent_vnfr, vlr):
124 """
125 Notification of Instantiate NSR with the passed nsr id
126 """
127 pass
128
129 @asyncio.coroutine
130 def notify_terminate_vnfr(self, agent_nsr, agent_vnfr):
131 """
132 Notification of Terminate the network service
133 """
134
135 @asyncio.coroutine
136 def notify_terminate_vlr(self, agent_nsr, agent_vnfr, vlr):
137 """
138 Notification of Terminate the virtual link
139 """
140 pass
141
142 @asyncio.coroutine
143 def vnf_config_primitive(self, agent_nsr, agent_vnfr, primitive, output):
144 '''
145 primitives support by RiftCA
146 '''
147 pass
148
149 @asyncio.coroutine
150 def apply_config(self, config, nsr, vnfr, rpc_ip):
151 """ Notification on configuration of an NSR """
152 pass
153
154 @asyncio.coroutine
155 def apply_ns_config(self, agent_nsr, agent_vnfrs, rpc_ip):
156 """Hook: Runs the user defined script. Feeds all the necessary data
157 for the script thro' yaml file.
158
159 Args:
160 rpc_ip (YangInput_Nsr_ExecNsConfigPrimitive): The input data.
161 nsr (NetworkServiceRecord): Description
162 vnfrs (dict): VNFR ID => VirtualNetworkFunctionRecord
163 """
164
165 def xlate(tag, tags):
166 # TBD
167 if tag is None or tags is None:
168 return tag
169 val = tag
170 if re.search('<.*>', tag):
171 try:
172 if tag == '<rw_mgmt_ip>':
173 val = tags['rw_mgmt_ip']
174 except KeyError as e:
175 self._log.info("RiftCA: Did not get a value for tag %s, e=%s",
176 tag, e)
177 return val
178
179 def get_meta(agent_nsr, agent_vnfrs):
180 unit_names, initial_params, vnfr_index_map, vnfr_data_map = {}, {}, {}, {}
181
182 for vnfr_id in agent_nsr.vnfr_ids:
183 vnfr = agent_vnfrs[vnfr_id]
184
185 # index->vnfr ref
186 vnfr_index_map[vnfr.member_vnf_index] = vnfr_id
187 vnfr_data_dict = dict()
188 if 'mgmt_interface' in vnfr.vnfr:
189 vnfr_data_dict['mgmt_interface'] = vnfr.vnfr['mgmt_interface']
190
191 vnfr_data_dict['connection_point'] = []
192 if 'connection_point' in vnfr.vnfr:
193 for cp in vnfr.vnfr['connection_point']:
194 cp_dict = dict()
195 cp_dict['name'] = cp['name']
196 cp_dict['ip_address'] = cp['ip_address']
197 vnfr_data_dict['connection_point'].append(cp_dict)
198
199 vnfr_data_dict['vdur'] = []
200 vdu_data = [(vdu['name'], vdu['management_ip'], vdu['vm_management_ip'], vdu['id'], vdu['vdu_id_ref'])
201 for vdu in vnfr.vnfr['vdur']]
202
203 for data in vdu_data:
204 data = dict(zip(['name', 'management_ip', 'vm_management_ip', 'id', 'vdu_id_ref'] , data))
205 vnfr_data_dict['vdur'].append(data)
206
207 vnfr_data_map[vnfr.member_vnf_index] = vnfr_data_dict
208 # Unit name
209 unit_names[vnfr_id] = vnfr.name
210 # Flatten the data for simplicity
211 param_data = {}
212 if 'initial_config_primitive' in vnfr.vnf_configuration:
213 for primitive in vnfr.vnf_configuration['initial_config_primitive']:
214 for parameter in primitive.parameter:
215 value = xlate(parameter.value, vnfr.tags)
216 param_data[parameter.name] = value
217
218 initial_params[vnfr_id] = param_data
219
220
221 return unit_names, initial_params, vnfr_index_map, vnfr_data_map
222
223 unit_names, init_data, vnfr_index_map, vnfr_data_map = get_meta(agent_nsr, agent_vnfrs)
224 # The data consists of 4 sections
225 # 1. Account data
226 # 2. The input passed.
227 # 3. Unit names (keyed by vnfr ID).
228 # 4. Initial config data (keyed by vnfr ID).
229 data = dict()
230 data['config_agent'] = dict(
231 name=self._name,
232 )
233 data["rpc_ip"] = rpc_ip.as_dict()
234 data["unit_names"] = unit_names
235 data["init_config"] = init_data
236 data["vnfr_index_map"] = vnfr_index_map
237 data["vnfr_data_map"] = vnfr_data_map
238
239 tmp_file = None
240 with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
241 tmp_file.write(yaml.dump(data, default_flow_style=True)
242 .encode("UTF-8"))
243
244 # Get the full path to the script
245 script = ''
246 if rpc_ip.user_defined_script[0] == '/':
247 # The script has full path, use as is
248 script = rpc_ip.user_defined_script
249 else:
250 script = os.path.join(self._rift_artif_dir, 'launchpad/libs', agent_nsr.nsd_id, 'scripts',
251 rpc_ip.user_defined_script)
252 self._log.debug("Rift config agent: Checking for script in %s", script)
253 if not os.path.exists(script):
254 self._log.debug("Rift config agent: Did not find scipt %s", script)
255 script = os.path.join(self._rift_install_dir, 'usr/bin', rpc_ip.user_defined_script)
256
257 cmd = "{} {}".format(script, tmp_file.name)
258 self._log.debug("Rift config agent: Running the CMD: {}".format(cmd))
259
260 coro = asyncio.create_subprocess_shell(cmd, loop=self._loop,
261 stderr=asyncio.subprocess.PIPE)
262 process = yield from coro
263 err = yield from process.stderr.read()
264 task = self._loop.create_task(process.wait())
265
266 return task, err
267
268 @asyncio.coroutine
269 def apply_initial_config(self, agent_nsr, agent_vnfr):
270 """
271 Apply the initial configuration
272 """
273 rc = False
274 self._log.debug("Rift config agent: Apply initial config to VNF:%s/%s",
275 agent_nsr.name, agent_vnfr.name)
276 try:
277 if agent_vnfr.id in self._rift_vnfs.keys():
278 # Check if VNF instance is configurable (TBD - future)
279 ### Remove this once is_vnf_configurable() is implemented
280 agent_vnfr.set_to_configurable()
281 if agent_vnfr.is_configurable:
282 # apply initial config for the vnfr
283 rc = yield from self._events.apply_vnf_config(agent_vnfr.vnf_cfg)
284 else:
285 self._log.info("Rift config agent: VNF:%s/%s is not configurable yet!",
286 agent_nsr.name, agent_vnfr.name)
287 except Exception as e:
288 self._log.error("Rift config agent: Error on initial configuration to VNF:{}/{}, e {}"
289 .format(agent_nsr.name, agent_vnfr.name, str(e)))
290
291 self._log.exception(e)
292 return rc
293
294 return rc
295
296 def is_vnfr_managed(self, vnfr_id):
297 try:
298 if vnfr_id in self._rift_vnfs:
299 return True
300 except Exception as e:
301 self._log.debug("Rift config agent: Is VNFR {} managed: {}".
302 format(vnfr_id, e))
303 return False
304
305 def add_vnfr_managed(self, agent_vnfr):
306 if agent_vnfr.id not in self._rift_vnfs.keys():
307 self._log.info("Rift config agent: add vnfr={}/{}".format(agent_vnfr.name, agent_vnfr.id))
308 self._rift_vnfs[agent_vnfr.id] = agent_vnfr
309
310 @asyncio.coroutine
311 def get_config_status(self, agent_nsr, agent_vnfr):
312 if agent_vnfr.id in self._rift_vnfs.keys():
313 return 'configured'
314 return 'unknown'
315
316
317 def get_action_status(self, execution_id):
318 ''' Get the action status for an execution ID
319 *** Make sure this is NOT a asyncio coroutine function ***
320 '''
321 return None