Fix juju/tasklet integration
[osm/SO.git] / rwcm / plugins / rwconman / rift / tasklets / rwconmantasklet / jujuconf.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 os
19 import re
20 import tempfile
21 import time
22 import yaml
23
24 import rift.mano.utils.juju_api as juju
25 from . import riftcm_config_plugin
26
27
28 def get_vnf_unique_name(nsr_name, vnfr_name, member_vnf_index):
29 """Get the unique VNF name.
30 Charm names accepts only a to z and non-consecutive - characters."""
31 name = "{}-{}-{}".format(nsr_name, vnfr_name, member_vnf_index)
32 new_name = ''
33 for c in name:
34 if c.isdigit():
35 c = chr(97 + int(c))
36 elif not c.isalpha():
37 c = "-"
38 new_name += c
39 return re.sub('\-+', '-', new_name.lower())
40
41
42 class JujuConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase):
43 """
44 Juju implementation of the riftcm_config_plugin.RiftCMConfigPluginBase
45 """
46 def __init__(self, dts, log, loop, project, account):
47 riftcm_config_plugin.RiftCMConfigPluginBase.__init__(self, dts, log, loop,
48 project, account)
49 self._name = account.name
50 self._type = 'juju'
51 self._ip_address = account.juju.ip_address
52 self._port = account.juju.port
53 self._user = account.juju.user
54 self._secret = account.juju.secret
55 self._rift_install_dir = os.environ['RIFT_INSTALL']
56 self._rift_var_root_dir = os.environ['RIFT_VAR_ROOT']
57
58 ############################################################
59 # This is wrongfully overloaded with 'juju' private data. #
60 # Really need to separate agent_vnfr from juju vnfr data. #
61 # Currently, this holds agent_vnfr, which has actual vnfr, #
62 # then this juju overloads actual vnfr with its own #
63 # dictionary elemetns (WRONG!!!) #
64 self._juju_vnfs = {}
65 ############################################################
66
67 self._tasks = {}
68 self._api = juju.JujuApi(log, loop,
69 self._ip_address, self._port,
70 self._user, self._secret)
71
72 @property
73 def name(self):
74 return self._name
75
76 @property
77 def agent_type(self):
78 return self._type
79
80 @property
81 def api(self):
82 return self._api
83
84 @property
85 def agent_data(self):
86 return dict(
87 type=self.agent_type,
88 name=self.name,
89 host=self._ip_address,
90 port=self._port,
91 user=self._user,
92 secret=self._secret
93 )
94
95 def vnfr(self, vnfr_id):
96 try:
97 vnfr = self._juju_vnfs[vnfr_id].vnfr
98 except KeyError:
99 self._log.error("jujuCA: Did not find VNFR %s in juju plugin", vnfr_id)
100 return None
101
102 return vnfr
103
104 def get_service_name(self, vnfr_id):
105 vnfr = self.vnfr(vnfr_id)
106 if vnfr and 'vnf_juju_name' in vnfr:
107 return vnfr['vnf_juju_name']
108 return None
109
110 def juju_log(self, level, name, log_str, *args):
111 if name is not None:
112 g_log_str = 'jujuCA:({}) {}'.format(name, log_str)
113 else:
114 g_log_str = 'jujuCA: {}'.format(log_str)
115 getattr(self._log, level)(g_log_str, *args)
116
117 # TBD: Do a better, similar to config manager
118 def xlate(self, tag, tags):
119 # TBD
120 if tag is None:
121 return tag
122 val = tag
123 if re.search('<.*>', tag):
124 self._log.debug("jujuCA: Xlate value %s", tag)
125 try:
126 if tag == '<rw_mgmt_ip>':
127 val = tags['rw_mgmt_ip']
128 except KeyError as e:
129 self._log.info("jujuCA: Did not get a value for tag %s, e=%s",
130 tag, e)
131 return val
132
133 @asyncio.coroutine
134 def notify_create_vlr(self, agent_nsr, agent_vnfr, vld, vlr):
135 """
136 Notification of create VL record
137 """
138 return True
139
140 @asyncio.coroutine
141 def notify_create_vnfr(self, agent_nsr, agent_vnfr):
142 """
143 Notification of create Network VNF record
144 Returns True if configured using config_agent
145 """
146 # Deploy the charm if specified for the vnf
147 self._log.debug("jujuCA: create vnfr nsr=%s vnfr=%s",
148 agent_nsr.name, agent_vnfr.name)
149 self._log.debug("jujuCA: Config = %s",
150 agent_vnfr.vnf_configuration)
151 try:
152 vnf_config = agent_vnfr.vnfr_msg.vnf_configuration
153 self._log.debug("jujuCA: vnf_configuration = %s", vnf_config)
154 if not vnf_config.has_field('juju'):
155 return False
156 charm = vnf_config.juju.charm
157 self._log.debug("jujuCA: charm = %s", charm)
158 except Exception as e:
159 self._log.Error("jujuCA: vnf_configuration error for vnfr {}: {}".
160 format(agent_vnfr.name, e))
161 return False
162
163 # Prepare unique name for this VNF
164 vnf_unique_name = get_vnf_unique_name(agent_nsr.name,
165 agent_vnfr.name,
166 agent_vnfr.member_vnf_index)
167 if vnf_unique_name in self._tasks:
168 self._log.warn("jujuCA: Service %s already deployed",
169 vnf_unique_name)
170
171 vnfr_dict = agent_vnfr.vnfr
172 vnfr_dict.update({'vnf_juju_name': vnf_unique_name,
173 'charm': charm,
174 'nsr_id': agent_nsr.id,
175 'member_vnf_index': agent_vnfr.member_vnf_index,
176 'tags': {},
177 'active': False,
178 'config': vnf_config,
179 'vnfr_name': agent_vnfr.name})
180 self._log.debug("jujuCA: Charm %s for vnf %s to be deployed as %s",
181 charm, agent_vnfr.name, vnf_unique_name)
182
183 # Find the charm directory
184 try:
185 path = os.path.join(self._rift_var_root_dir,
186 'launchpad/packages/vnfd',
187 self._project.name,
188 agent_vnfr.vnfr_msg.vnfd.id,
189 'charms',
190 charm)
191 self._log.debug("jujuCA: Charm dir is {}".format(path))
192 if not os.path.isdir(path):
193 self._log.error("jujuCA: Did not find the charm directory at {}".format(path))
194 path = None
195 except Exception as e:
196 self.log.exception(e)
197 return False
198
199 if vnf_unique_name not in self._tasks:
200 self._tasks[vnf_unique_name] = {}
201
202 self._tasks[vnf_unique_name]['deploy'] = self.loop.create_task(
203 self.api.deploy_application(charm, vnf_unique_name, path=path))
204
205 self._log.debug("jujuCA: Deploying service %s",
206 vnf_unique_name)
207
208 return True
209
210 @asyncio.coroutine
211 def notify_instantiate_vnfr(self, agent_nsr, agent_vnfr):
212 """
213 Notification of Instantiate NSR with the passed nsr id
214 """
215 return True
216
217 @asyncio.coroutine
218 def notify_instantiate_vlr(self, agent_nsr, agent_vnfr, vlr):
219 """
220 Notification of Instantiate NSR with the passed nsr id
221 """
222 return True
223
224 @asyncio.coroutine
225 def notify_terminate_nsr(self, agent_nsr, agent_vnfr):
226 """
227 Notification of Terminate the network service
228 """
229 return True
230
231 @asyncio.coroutine
232 def notify_terminate_vnfr(self, agent_nsr, agent_vnfr):
233 """
234 Notification of Terminate the network service
235 """
236 self._log.debug("jujuCA: Terminate VNFr {}, current vnfrs={}".
237 format(agent_vnfr.name, self._juju_vnfs))
238 try:
239 vnfr = agent_vnfr.vnfr
240 service = vnfr['vnf_juju_name']
241
242 self._log.debug ("jujuCA: Terminating VNFr %s, %s",
243 agent_vnfr.name, service)
244 self._tasks[service]['destroy'] = self.loop.create_task(
245 self.api.remove_application(service)
246 )
247
248 del self._juju_vnfs[agent_vnfr.id]
249 self._log.debug ("jujuCA: current vnfrs={}".
250 format(self._juju_vnfs))
251 if service in self._tasks:
252 tasks = []
253 for action in self._tasks[service].keys():
254 #if self.check_task_status(service, action):
255 tasks.append(action)
256 del tasks
257 except KeyError as e:
258 self._log.debug ("jujuCA: Terminating charm service for VNFr {}, e={}".
259 format(agent_vnfr.name, e))
260 except Exception as e:
261 self._log.error("jujuCA: Exception terminating charm service for VNFR {}: {}".
262 format(agent_vnfr.name, e))
263
264 return True
265
266 @asyncio.coroutine
267 def notify_terminate_vlr(self, agent_nsr, agent_vnfr, vlr):
268 """
269 Notification of Terminate the virtual link
270 """
271 return True
272
273 def check_task_status(self, service, action):
274 #self.log.debug("jujuCA: check task status for %s, %s" % (service, action))
275 try:
276 task = self._tasks[service][action]
277 if task.done():
278 self.log.debug("jujuCA: Task for %s, %s done" % (service, action))
279 e = task.exception()
280 if e:
281 self.log.error("jujuCA: Error in task for {} and {} : {}".
282 format(service, action, e))
283 raise Exception(e)
284 r= task.result()
285 if r:
286 self.log.debug("jujuCA: Task for {} and {}, returned {}".
287 format(service, action,r))
288 return True
289 else:
290 self.log.debug("jujuCA: task {}, {} not done".
291 format(service, action))
292 return False
293 except KeyError as e:
294 self.log.error("jujuCA: KeyError for task for {} and {}: {}".
295 format(service, action, e))
296 except Exception as e:
297 self.log.error("jujuCA: Error for task for {} and {}: {}".
298 format(service, action, e))
299 raise
300 return True
301
302 @asyncio.coroutine
303 def _vnf_config_primitive(self, nsr_id, vnfr_id, primitive,
304 vnf_config=None, wait=False):
305 self._log.debug("jujuCA: VNF config primitive {} for nsr {}, "
306 "vnfr_id {}".
307 format(primitive, nsr_id, vnfr_id))
308
309 if vnf_config is None:
310 vnfr_msg = yield from self.get_vnfr(vnfr_id)
311 if vnfr_msg is None:
312 msg = "Unable to get VNFR {} through DTS".format(vnfr_id)
313 self._log.error(msg)
314 return 3, msg
315
316 vnf_config = vnfr_msg.vnf_configuration
317 self._log.debug("VNF config= %s", vnf_config.as_dict())
318
319 try:
320 service = vnfr['vnf_juju_name']
321 self._log.debug("VNF config %s", vnf_config)
322 configs = vnf_config.config_primitive
323 for config in configs:
324 if config.name == primitive.name:
325 self._log.debug("jujuCA: Found the config primitive %s",
326 config.name)
327 params = {}
328 for parameter in config.parameter:
329 val = None
330 for p in primitive.parameter:
331 if p.name == parameter.name:
332 if p.value:
333 val = self.xlate(p.value, vnfr['tags'])
334 break
335
336 if val is None:
337 val = parameter.default_value
338
339 if val is None:
340 # Check if mandatory parameter
341 if parameter.mandatory:
342 msg = "VNFR {}: Primitive {} called " \
343 "without mandatory parameter {}". \
344 format(vnfr_msg.name, config.name,
345 parameter.name)
346 self._log.error(msg)
347 return 'failed', '', msg
348
349 if val:
350 val = self.convert_value(val, parameter.data_type)
351 params.update({parameter.name: val})
352
353 rc = ''
354 exec_id = ''
355 details = ''
356 if config.name == 'config':
357 exec_id = 'config'
358 if len(params):
359 self._log.debug("jujuCA: applying config with "
360 "params {} for service {}".
361 format(params, service))
362
363 rc = yield from self.api.apply_config(params, application=service)
364
365 if rc:
366 rc = "completed"
367 self._log.debug("jujuCA: applied config {} "
368 "on {}".format(params, service))
369 else:
370 rc = 'failed'
371 details = \
372 'Failed to apply config: {}'.format(params)
373 self._log.error("jujuCA: Error applying "
374 "config {} on service {}".
375 format(params, service))
376 else:
377 self._log.warn("jujuCA: Did not find valid "
378 "parameters for config : {}".
379 format(primitive.parameter))
380 rc = "completed"
381 else:
382 self._log.debug("jujuCA: Execute action {} on "
383 "service {} with params {}".
384 format(config.name, service, params))
385
386 resp = yield from self.api.execute_action(
387 service,
388 config.name,
389 **params,
390 )
391
392 if resp:
393 if 'error' in resp:
394 details = resp['error']['message']
395 else:
396 exec_id = resp['action']['tag']
397 rc = resp['status']
398 if rc == 'failed':
399 details = resp['message']
400
401 self._log.debug("jujuCA: execute action {} on "
402 "service {} returned {}".
403 format(config.name, service, rc))
404 else:
405 self._log.error("jujuCA: error executing action "
406 "{} for {} with {}".
407 format(config.name, service,
408 params))
409 exec_id = ''
410 rc = 'failed'
411 details = "Failed to queue the action"
412 break
413
414 except KeyError as e:
415 msg = "VNF %s does not have config primitives, e=%s", \
416 vnfr_id, e
417 self._log.exception(msg)
418 raise ValueError(msg)
419
420 while wait and (rc in ['pending', 'running']):
421 self._log.debug("JujuCA: action {}, rc {}".
422 format(exec_id, rc))
423 yield from asyncio.sleep(0.2, loop=self._loop)
424 status = yield from self.api.get_action_status(exec_id)
425 rc = status['status']
426
427 return rc, exec_id, details
428
429 @asyncio.coroutine
430 def vnf_config_primitive(self, nsr_id, vnfr_id, primitive, output):
431 try:
432 vnfr = self._juju_vnfs[vnfr_id].vnfr
433 except KeyError:
434 msg = "Did not find VNFR {} in Juju plugin".format(vnfr_id)
435 self._log.debug(msg)
436 return
437
438 output.execution_status = "failed"
439 output.execution_id = ''
440 output.execution_error_details = ''
441
442 rc, exec_id, err = yield from self._vnf_config_primitive(
443 nsr_id,
444 vnfr_id,
445 primitive)
446
447 self._log.debug("VNFR {} primitive {} exec status: {}".
448 format(vnfr.name, primitive.name, rc))
449 output.execution_status = rc
450 output.execution_id = exec_id
451 output.execution_error_details = err
452
453 @asyncio.coroutine
454 def apply_config(self, agent_nsr, agent_vnfr, config, rpc_ip):
455 """ Notification on configuration of an NSR """
456 pass
457
458 @asyncio.coroutine
459 def apply_ns_config(self, agent_nsr, agent_vnfrs, rpc_ip):
460 """
461
462 ###### TBD - This really does not belong here. Looks more like NS level script ####
463 ###### apply_config should be called for a particular VNF only here ###############
464
465 Hook: Runs the user defined script. Feeds all the necessary data
466 for the script thro' yaml file.
467
468 Args:
469 rpc_ip (YangInput_Nsr_ExecNsConfigPrimitive): The input data.
470 nsr (NetworkServiceRecord): Description
471 vnfrs (dict): VNFR ID => VirtualNetworkFunctionRecord
472
473 """
474 def get_meta(agent_nsr):
475 unit_names, initial_params, vnfr_index_map = {}, {}, {}
476
477 for vnfr_id in agent_nsr.vnfr_ids:
478 juju_vnf = self._juju_vnfs[vnfr_id].vnfr
479
480 # Vnfr -> index ref
481 vnfr_index_map[vnfr_id] = juju_vnf['member_vnf_index']
482
483 # Unit name
484 unit_names[vnfr_id] = juju_vnf['vnf_juju_name']
485
486 # Flatten the data for simplicity
487 param_data = {}
488 self._log.debug("Juju Config:%s", juju_vnf['config'])
489 for primitive in juju_vnf['config'].initial_config_primitive:
490 for parameter in primitive.parameter:
491 value = self.xlate(parameter.value, juju_vnf['tags'])
492 param_data[parameter.name] = value
493
494 initial_params[vnfr_id] = param_data
495
496
497 return unit_names, initial_params, vnfr_index_map
498
499 unit_names, init_data, vnfr_index_map = get_meta(agent_nsr)
500
501 # The data consists of 4 sections
502 # 1. Account data
503 # 2. The input passed.
504 # 3. Juju unit names (keyed by vnfr ID).
505 # 4. Initial config data (keyed by vnfr ID).
506 data = dict()
507 data['config_agent'] = dict(
508 name=self._name,
509 host=self._ip_address,
510 port=self._port,
511 user=self._user,
512 secret=self._secret
513 )
514 data["rpc_ip"] = rpc_ip.as_dict()
515 data["unit_names"] = unit_names
516 data["init_config"] = init_data
517 data["vnfr_index_map"] = vnfr_index_map
518
519 tmp_file = None
520 with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
521 tmp_file.write(yaml.dump(data, default_flow_style=True)
522 .encode("UTF-8"))
523
524 self._log.debug("jujuCA: Creating a temp file: {} with input data".format(
525 tmp_file.name))
526
527 # Get the full path to the script
528 script = ''
529 if rpc_ip.user_defined_script[0] == '/':
530 # The script has full path, use as is
531 script = rpc_ip.user_defined_script
532 else:
533 script = os.path.join(self._rift_var_root_dir, 'launchpad/nsd',
534 self._project.name,
535 agent_nsr.id, 'scripts',
536 rpc_ip.user_defined_script)
537 self.log.debug("jujuCA: Checking for script in %s", script)
538 if not os.path.exists(script):
539 script = os.path.join(self._rift_install_dir, 'usr/bin', rpc_ip.user_defined_script)
540
541 cmd = "{} {}".format(rpc_ip.user_defined_script, tmp_file.name)
542 self._log.debug("jujuCA: Running the CMD: {}".format(cmd))
543
544 coro = asyncio.create_subprocess_shell(cmd, loop=self._loop,
545 stderr=asyncio.subprocess.PIPE)
546 process = yield from coro
547 err = yield from process.stderr.read()
548 task = self._loop.create_task(process.wait())
549
550 return task, err
551
552 @asyncio.coroutine
553 def apply_initial_config(self, agent_nsr, agent_vnfr):
554 """
555 Apply the initial configuration
556 Expect config directives mostly, not actions
557 Actions in initial config may not work based on charm design
558 """
559
560 try:
561 vnfr = self._juju_vnfs[agent_vnfr.id].vnfr
562 service = vnfr['vnf_juju_name']
563 except KeyError:
564 self._log.debug("Did not find VNFR %s in Juju plugin",
565 agent_vnfr.name)
566 return False
567
568 vnfr_msg = yield from self.get_vnfr(agent_vnfr.id)
569 if vnfr_msg is None:
570 msg = "Unable to get VNFR {} ({}) through DTS". \
571 format(agent_vnfr.id, agent_vnfr.name)
572 self._log.error(msg)
573 raise RuntimeError(msg)
574
575 vnf_config = vnfr_msg.vnf_configuration
576 self._log.debug("VNFR %s config: %s", vnfr_msg.name,
577 vnf_config.as_dict())
578
579 # Sort the primitive based on the sequence number
580 primitives = sorted(vnf_config.initial_config_primitive,
581 key=lambda k: k.seq)
582 if not primitives:
583 self._log.debug("VNFR {}: No initial-config-primitive specified".
584 format(vnfr_msg.name))
585 return True
586
587 rc = yield from self.api.is_application_up(application=service)
588 if not rc:
589 return False
590
591 try:
592 if vnfr_msg.mgmt_interface.ip_address:
593 vnfr['tags'].update({'rw_mgmt_ip': vnfr_msg.mgmt_interface.ip_address})
594 self._log.debug("jujuCA:(%s) tags: %s", vnfr['vnf_juju_name'], vnfr['tags'])
595
596 for primitive in primitives:
597 self._log.debug("(%s) Initial config primitive %s",
598 vnfr['vnf_juju_name'], primitive.as_dict())
599 if primitive.config_primitive_ref:
600 # Reference to a primitive in config primitive
601 class Primitive:
602 def __init__(self, name):
603 self.name = name
604 self.value = None
605 self.parameter = []
606
607 prim = Primitive(primitive.config_primitive_ref)
608 rc, eid, err = yield from self._vnf_config_primitive(
609 agent_nsr.id,
610 agent_vnfr.id,
611 prim,
612 vnf_config,
613 wait=True)
614
615 if rc == "failed":
616 msg = "Error executing initial config primitive" \
617 " {} in VNFR {}: rc={}, stderr={}". \
618 format(prim.name, vnfr_msg.name, rc, err)
619 self._log.error(msg)
620 return False
621
622 elif primitive.name:
623 config = {}
624 if primitive.name == 'config':
625 for param in primitive.parameter:
626 if vnfr['tags']:
627 val = self.xlate(param.value,
628 vnfr['tags'])
629 config.update({param.name: val})
630
631 if config:
632 self.juju_log('info', vnfr['vnf_juju_name'],
633 "Applying Initial config:%s",
634 config)
635
636 rc = yield from self.api.apply_config(
637 config,
638 application=service,
639 )
640 if rc is False:
641 self.log.error("Service {} is in error state".format(service))
642 return False
643 else:
644 # Apply any actions specified as part of initial config
645 for primitive in vnfr['config'].initial_config_primitive:
646 if primitive.name != 'config':
647 self._log.debug("jujuCA:(%s) Initial config action primitive %s",
648 vnfr['vnf_juju_name'], primitive)
649 action = primitive.name
650 params = {}
651 for param in primitive.parameter:
652 val = self.xlate(param.value, vnfr['tags'])
653 params.update({param.name: val})
654
655 self._log.info("jujuCA:(%s) Action %s with params %s",
656 vnfr['vnf_juju_name'], action, params)
657 self._log.debug("executing action")
658 resp = yield from self.api.execute_action(
659 service,
660 action,
661 **params,
662 )
663 self._log.debug("executed action")
664 if 'error' in resp:
665 self._log.error("Applying initial config on {} failed for {} with {}: {}".
666 format(vnfr['vnf_juju_name'], action, params, resp))
667 return False
668 except KeyError as e:
669 self._log.info("Juju config agent(%s): VNFR %s not managed by Juju",
670 vnfr['vnf_juju_name'], agent_vnfr.id)
671 return False
672 except Exception as e:
673 self._log.exception("jujuCA:(%s) Exception juju "
674 "apply_initial_config for VNFR {}: {}".
675 format(vnfr['vnf_juju_name'],
676 agent_vnfr.id, e))
677 return False
678
679 return True
680
681 def add_vnfr_managed(self, agent_vnfr):
682 if agent_vnfr.id not in self._juju_vnfs.keys():
683 self._log.info("juju config agent: add vnfr={}/{}".
684 format(agent_vnfr.name, agent_vnfr.id))
685 self._juju_vnfs[agent_vnfr.id] = agent_vnfr
686
687 def is_vnfr_managed(self, vnfr_id):
688 try:
689 if vnfr_id in self._juju_vnfs:
690 return True
691 except Exception as e:
692 self._log.debug("jujuCA: Is VNFR {} managed: {}".
693 format(vnfr_id, e))
694 return False
695
696 @asyncio.coroutine
697 def is_configured(self, vnfr_id):
698 try:
699 agent_vnfr = self._juju_vnfs[vnfr_id]
700 vnfr = agent_vnfr.vnfr
701 if vnfr['active']:
702 return True
703
704 vnfr = self._juju_vnfs[vnfr_id].vnfr
705 service = vnfr['vnf_juju_name']
706 resp = self.api.is_application_active(application=service)
707 self._juju_vnfs[vnfr_id]['active'] = resp
708 self._log.debug("jujuCA: Service state for {} is {}".
709 format(service, resp))
710 return resp
711
712 except KeyError:
713 self._log.debug("jujuCA: VNFR id {} not found in config agent".
714 format(vnfr_id))
715 return False
716 except Exception as e:
717 self._log.error("jujuCA: VNFR id {} is_configured: {}".
718 format(vnfr_id, e))
719 return False
720
721 @asyncio.coroutine
722 def get_config_status(self, agent_nsr, agent_vnfr):
723 """Get the configuration status for the VNF"""
724 rc = 'unknown'
725
726 try:
727 vnfr = agent_vnfr.vnfr
728 service = vnfr['vnf_juju_name']
729 except KeyError:
730 # This VNF is not managed by Juju
731 return rc
732
733 rc = 'configuring'
734
735 if not self.check_task_status(service, 'deploy'):
736 return rc
737
738 try:
739 resp = yield from self.api.get_service_status(application=service)
740 self._log.debug("jujuCA: Get service %s status? %s", service, resp)
741
742 if resp == 'error':
743 return 'error'
744 if resp == 'active':
745 return 'configured'
746 except KeyError:
747 self._log.error("jujuCA: Check unknown service %s status", service)
748 except Exception as e:
749 self._log.error("jujuCA: Caught exception when checking for service is active: %s", e)
750 self._log.exception(e)
751
752 return rc
753
754 def get_action_status(self, execution_id):
755 ''' Get the action status for an execution ID
756 *** Make sure this is NOT a asyncio coroutine function ***
757 '''
758
759 try:
760 self._log.debug("jujuCA: Get action status for {}".format(execution_id))
761 resp = self.api._get_action_status(execution_id)
762 self._log.debug("jujuCA: Action status: {}".format(resp))
763 return resp
764 except Exception as e:
765 self._log.error("jujuCA: Error fetching execution status for %s",
766 execution_id)
767 self._log.exception(e)
768 raise e
769
770 def get_service_status(self, vnfr_id):
771 '''Get the service status, used by job status handle
772 Make sure this is NOT a coroutine
773 '''
774 service = self.get_service_name(vnfr_id)
775 if service is None:
776 self._log.error("jujuCA: VNFR {} not managed by this Juju agent".
777 format(vnfr_id))
778 return None
779
780 # Delay for 3 seconds before checking as config apply takes a
781 # few seconds to transfer to the service
782 time.sleep(3)
783 return self.api._get_service_status(service=service)