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