Refactor JujuApi to use libjuju asyncronous API
[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 # Charm service name accepts only a to z and -.
29 def get_vnf_unique_name(nsr_name, vnfr_name, member_vnf_index):
30 name = "{}-{}-{}".format(nsr_name, vnfr_name, member_vnf_index)
31 new_name = ''
32 for c in name:
33 if c.isdigit():
34 c = chr(97 + int(c))
35 elif not c.isalpha():
36 c = "-"
37 new_name += c
38 return new_name.lower()
39
40
41 class JujuConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase):
42 """
43 Juju implementation of the riftcm_config_plugin.RiftCMConfigPluginBase
44 """
45 def __init__(self, dts, log, loop, project, account):
46 riftcm_config_plugin.RiftCMConfigPluginBase.__init__(self, dts, log, loop,
47 project, account)
48 self._name = account.name
49 self._type = 'juju'
50 self._ip_address = account.juju.ip_address
51 self._port = account.juju.port
52 self._user = account.juju.user
53 self._secret = account.juju.secret
54 self._rift_install_dir = os.environ['RIFT_INSTALL']
55 self._rift_var_root_dir = os.environ['RIFT_VAR_ROOT']
56
57 ############################################################
58 # This is wrongfully overloaded with 'juju' private data. #
59 # Really need to separate agent_vnfr from juju vnfr data. #
60 # Currently, this holds agent_vnfr, which has actual vnfr, #
61 # then this juju overloads actual vnfr with its own #
62 # dictionary elemetns (WRONG!!!) #
63 self._juju_vnfs = {}
64 ############################################################
65
66 self._tasks = {}
67 self._api = juju.JujuApi(log, loop,
68 self._ip_address, self._port,
69 self._user, self._secret)
70
71 @property
72 def name(self):
73 return self._name
74
75 @property
76 def agent_type(self):
77 return self._type
78
79 @property
80 def api(self):
81 return self._api
82
83 @property
84 def agent_data(self):
85 return dict(
86 type=self.agent_type,
87 name=self.name,
88 host=self._ip_address,
89 port=self._port,
90 user=self._user,
91 secret=self._secret
92 )
93
94 def vnfr(self, vnfr_id):
95 try:
96 vnfr = self._juju_vnfs[vnfr_id].vnfr
97 except KeyError:
98 self._log.error("jujuCA: Did not find VNFR %s in juju plugin", vnfr_id)
99 return None
100
101 return vnfr
102
103 def get_service_name(self, vnfr_id):
104 vnfr = self.vnfr(vnfr_id)
105 if vnfr and 'vnf_juju_name' in vnfr:
106 return vnfr['vnf_juju_name']
107 return None
108
109 def juju_log(self, level, name, log_str, *args):
110 if name is not None:
111 g_log_str = 'jujuCA:({}) {}'.format(name, log_str)
112 else:
113 g_log_str = 'jujuCA: {}'.format(log_str)
114 getattr(self._log, level)(g_log_str, *args)
115
116 # TBD: Do a better, similar to config manager
117 def xlate(self, tag, tags):
118 # TBD
119 if tag is None:
120 return tag
121 val = tag
122 if re.search('<.*>', tag):
123 self._log.debug("jujuCA: Xlate value %s", tag)
124 try:
125 if tag == '<rw_mgmt_ip>':
126 val = tags['rw_mgmt_ip']
127 except KeyError as e:
128 self._log.info("jujuCA: Did not get a value for tag %s, e=%s",
129 tag, e)
130 return val
131
132 @asyncio.coroutine
133 def notify_create_vlr(self, agent_nsr, agent_vnfr, vld, vlr):
134 """
135 Notification of create VL record
136 """
137 return True
138
139 @asyncio.coroutine
140 def notify_create_vnfr(self, agent_nsr, agent_vnfr):
141 """
142 Notification of create Network VNF record
143 Returns True if configured using config_agent
144 """
145 # Deploy the charm if specified for the vnf
146 self._log.debug("jujuCA: create vnfr nsr=%s vnfr=%s",
147 agent_nsr.name, agent_vnfr.name)
148 self._log.debug("jujuCA: Config = %s",
149 agent_vnfr.vnf_configuration)
150 try:
151 vnf_config = agent_vnfr.vnfr_msg.vnf_configuration
152 self._log.debug("jujuCA: vnf_configuration = %s", vnf_config)
153 if not vnf_config.has_field('juju'):
154 return False
155 charm = vnf_config.juju.charm
156 self._log.debug("jujuCA: charm = %s", charm)
157 except Exception as e:
158 self._log.Error("jujuCA: vnf_configuration error for vnfr {}: {}".
159 format(agent_vnfr.name, e))
160 return False
161
162 # Prepare unique name for this VNF
163 vnf_unique_name = get_vnf_unique_name(agent_nsr.name,
164 agent_vnfr.name,
165 agent_vnfr.member_vnf_index)
166 if vnf_unique_name in self._tasks:
167 self._log.warn("jujuCA: Service %s already deployed",
168 vnf_unique_name)
169
170 vnfr_dict = agent_vnfr.vnfr
171 vnfr_dict.update({'vnf_juju_name': vnf_unique_name,
172 'charm': charm,
173 'nsr_id': agent_nsr.id,
174 'member_vnf_index': agent_vnfr.member_vnf_index,
175 'tags': {},
176 'active': False,
177 'config': vnf_config,
178 'vnfr_name': agent_vnfr.name})
179 self._log.debug("jujuCA: Charm %s for vnf %s to be deployed as %s",
180 charm, agent_vnfr.name, vnf_unique_name)
181
182 # Find the charm directory
183 try:
184 path = os.path.join(self._rift_var_root_dir,
185 'launchpad/packages/vnfd',
186 self._project.name,
187 agent_vnfr.vnfr_msg.vnfd.id,
188 'charms/trusty',
189 charm)
190 self._log.debug("jujuCA: Charm dir is {}".format(path))
191 if not os.path.isdir(path):
192 self._log.error("jujuCA: Did not find the charm directory at {}".
193 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 except KeyError:
563 self._log.debug("Did not find VNFR %s in Juju plugin",
564 agent_vnfr.name)
565 return False
566
567 vnfr_msg = yield from self.get_vnfr(agent_vnfr.id)
568 if vnfr_msg is None:
569 msg = "Unable to get VNFR {} ({}) through DTS". \
570 format(agent_vnfr.id, agent_vnfr.name)
571 self._log.error(msg)
572 raise RuntimeError(msg)
573
574 vnf_config = vnfr_msg.vnf_configuration
575 self._log.debug("VNFR %s config: %s", vnfr_msg.name,
576 vnf_config.as_dict())
577
578 # Sort the primitive based on the sequence number
579 primitives = sorted(vnf_config.initial_config_primitive,
580 key=lambda k: k.seq)
581 if not primitives:
582 self._log.debug("VNFR {}: No initial-config-primitive specified".
583 format(vnfr_msg.name))
584 return True
585
586 rc = yield from self.api.is_application_up(application=service)
587 if not rc:
588 return False
589
590 # action_ids = []
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 rc == "pending":
623 action_ids.append(eid)
624
625 elif primitive.name:
626 config = {}
627 if primitive.name == 'config':
628 for param in primitive.parameter:
629 if vnfr['tags']:
630 val = self.xlate(param.value,
631 vnfr['tags'])
632 config.update({param.name: val})
633 except KeyError as e:
634 self._log.exception("jujuCA:(%s) Initial config error(%s): config=%s",
635 vnfr['vnf_juju_name'], str(e), config)
636 config = None
637 return False
638
639 if config:
640 self.juju_log('info', vnfr['vnf_juju_name'],
641 "Applying Initial config:%s",
642 config)
643
644 rc = yield from self.api.apply_config(
645 config,
646 application=service,
647 )
648 if rc is False:
649 self.log.error("Service {} is in error state".format(service))
650 return False
651
652 if config:
653 self.juju_log('info', vnfr['vnf_juju_name'],
654 "Applying Initial config:%s",
655 config)
656
657 # Apply any actions specified as part of initial config
658 for primitive in vnfr['config'].initial_config_primitive:
659 if primitive.name != 'config':
660 self._log.debug("jujuCA:(%s) Initial config action primitive %s",
661 vnfr['vnf_juju_name'], primitive)
662 action = primitive.name
663 params = {}
664 for param in primitive.parameter:
665 val = self.xlate(param.value, vnfr['tags'])
666 params.update({param.name: val})
667
668 self._log.info("jujuCA:(%s) Action %s with params %s",
669 vnfr['vnf_juju_name'], action, params)
670 self._log.debug("executing action")
671 resp = yield from self.api.execute_action(
672 service,
673 action,
674 **params,
675 )
676 self._log.debug("executed action")
677 if 'error' in resp:
678 self._log.error("Applying initial config on {} failed for {} with {}: {}".
679 format(vnfr['vnf_juju_name'], action, params, resp))
680 return False
681
682 # action_ids.append(resp['action']['tag'])
683 # action_ids.append(resp)
684 except KeyError as e:
685 self._log.info("Juju config agent(%s): VNFR %s not managed by Juju",
686 vnfr['vnf_juju_name'], agent_vnfr.id)
687 return False
688 except Exception as e:
689 self._log.exception("jujuCA:(%s) Exception juju "
690 "apply_initial_config for VNFR {}: {}".
691 format(vnfr['vnf_juju_name'],
692 agent_vnfr.id, e))
693 return False
694
695 return True
696
697 def add_vnfr_managed(self, agent_vnfr):
698 if agent_vnfr.id not in self._juju_vnfs.keys():
699 self._log.info("juju config agent: add vnfr={}/{}".
700 format(agent_vnfr.name, agent_vnfr.id))
701 self._juju_vnfs[agent_vnfr.id] = agent_vnfr
702
703 def is_vnfr_managed(self, vnfr_id):
704 try:
705 if vnfr_id in self._juju_vnfs:
706 return True
707 except Exception as e:
708 self._log.debug("jujuCA: Is VNFR {} managed: {}".
709 format(vnfr_id, e))
710 return False
711
712 @asyncio.coroutine
713 def is_configured(self, vnfr_id):
714 try:
715 agent_vnfr = self._juju_vnfs[vnfr_id]
716 vnfr = agent_vnfr.vnfr
717 if vnfr['active']:
718 return True
719
720 vnfr = self._juju_vnfs[vnfr_id].vnfr
721 service = vnfr['vnf_juju_name']
722 resp = self.api.is_application_active(application=service)
723 self._juju_vnfs[vnfr_id]['active'] = resp
724 self._log.debug("jujuCA: Service state for {} is {}".
725 format(service, resp))
726 return resp
727
728 except KeyError:
729 self._log.debug("jujuCA: VNFR id {} not found in config agent".
730 format(vnfr_id))
731 return False
732 except Exception as e:
733 self._log.error("jujuCA: VNFR id {} is_configured: {}".
734 format(vnfr_id, e))
735 return False
736
737 @asyncio.coroutine
738 def get_config_status(self, agent_nsr, agent_vnfr):
739 """Get the configuration status for the VNF"""
740 rc = 'unknown'
741
742 try:
743 vnfr = agent_vnfr.vnfr
744 service = vnfr['vnf_juju_name']
745 except KeyError:
746 # This VNF is not managed by Juju
747 return rc
748
749 rc = 'configuring'
750
751 if not self.check_task_status(service, 'deploy'):
752 return rc
753
754 try:
755 resp = yield from self.api.get_service_status(application=service)
756 self._log.debug("jujuCA: Get service %s status? %s", service, resp)
757
758 if resp == 'error':
759 return 'error'
760 if resp == 'active':
761 return 'configured'
762 except KeyError:
763 self._log.error("jujuCA: Check unknown service %s status", service)
764 except Exception as e:
765 self._log.error("jujuCA: Caught exception when checking for service is active: %s", e)
766 self._log.exception(e)
767
768 return rc
769
770 def get_action_status(self, execution_id):
771 ''' Get the action status for an execution ID
772 *** Make sure this is NOT a asyncio coroutine function ***
773 '''
774
775 try:
776 self._log.debug("jujuCA: Get action status for {}".format(execution_id))
777 resp = self.api._get_action_status(execution_id)
778 self._log.debug("jujuCA: Action status: {}".format(resp))
779 return resp
780 except Exception as e:
781 self._log.error("jujuCA: Error fetching execution status for %s",
782 execution_id)
783 self._log.exception(e)
784 raise e
785
786 def get_service_status(self, vnfr_id):
787 '''Get the service status, used by job status handle
788 Make sure this is NOT a coroutine
789 '''
790 service = self.get_service_name(vnfr_id)
791 if service is None:
792 self._log.error("jujuCA: VNFR {} not managed by this Juju agent".
793 format(vnfr_id))
794 return None
795
796 # Delay for 3 seconds before checking as config apply takes a
797 # few seconds to transfer to the service
798 time.sleep(3)
799 return self.api._get_service_status(service=service)