update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[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_service(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.destroy_service(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: Termiating 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(
364 params,
365 service=service,
366 wait=True)
367
368 if rc:
369 rc = "completed"
370 self._log.debug("jujuCA: applied config {} "
371 "on {}".format(params, service))
372 else:
373 rc = 'failed'
374 details = \
375 'Failed to apply config: {}'.format(params)
376 self._log.error("jujuCA: Error applying "
377 "config {} on service {}".
378 format(params, service))
379 else:
380 self._log.warn("jujuCA: Did not find valid "
381 "parameters for config : {}".
382 format(primitive.parameter))
383 rc = "completed"
384 else:
385 self._log.debug("jujuCA: Execute action {} on "
386 "service {} with params {}".
387 format(config.name, service, params))
388
389 resp = yield from self.api.execute_action(
390 config.name,
391 params,
392 service=service)
393
394 if resp:
395 if 'error' in resp:
396 details = resp['error']['message']
397 else:
398 exec_id = resp['action']['tag']
399 rc = resp['status']
400 if rc == 'failed':
401 details = resp['message']
402
403 self._log.debug("jujuCA: execute action {} on "
404 "service {} returned {}".
405 format(config.name, service, rc))
406 else:
407 self._log.error("jujuCA: error executing action "
408 "{} for {} with {}".
409 format(config.name, service,
410 params))
411 exec_id = ''
412 rc = 'failed'
413 details = "Failed to queue the action"
414 break
415
416 except KeyError as e:
417 msg = "VNF %s does not have config primitives, e=%s", \
418 vnfr_id, e
419 self._log.exception(msg)
420 raise ValueError(msg)
421
422 while wait and (rc in ['pending', 'running']):
423 self._log.debug("JujuCA: action {}, rc {}".
424 format(exec_id, rc))
425 yield from asyncio.sleep(0.2, loop=self._loop)
426 status = yield from self.api.get_action_status(exec_id)
427 rc = status['status']
428
429 return rc, exec_id, details
430
431 @asyncio.coroutine
432 def vnf_config_primitive(self, nsr_id, vnfr_id, primitive, output):
433 try:
434 vnfr = self._juju_vnfs[vnfr_id].vnfr
435 except KeyError:
436 msg = "Did not find VNFR {} in Juju plugin".format(vnfr_id)
437 self._log.debug(msg)
438 return
439
440 output.execution_status = "failed"
441 output.execution_id = ''
442 output.execution_error_details = ''
443
444 rc, exec_id, err = yield from self._vnf_config_primitive(
445 nsr_id,
446 vnfr_id,
447 primitive)
448
449 self._log.debug("VNFR {} primitive {} exec status: {}".
450 format(vnfr.name, primitive.name, rc))
451 output.execution_status = rc
452 output.execution_id = exec_id
453 output.execution_error_details = err
454
455 @asyncio.coroutine
456 def apply_config(self, agent_nsr, agent_vnfr, config, rpc_ip):
457 """ Notification on configuration of an NSR """
458 pass
459
460 @asyncio.coroutine
461 def apply_ns_config(self, agent_nsr, agent_vnfrs, rpc_ip):
462 """
463
464 ###### TBD - This really does not belong here. Looks more like NS level script ####
465 ###### apply_config should be called for a particular VNF only here ###############
466
467 Hook: Runs the user defined script. Feeds all the necessary data
468 for the script thro' yaml file.
469
470 Args:
471 rpc_ip (YangInput_Nsr_ExecNsConfigPrimitive): The input data.
472 nsr (NetworkServiceRecord): Description
473 vnfrs (dict): VNFR ID => VirtualNetworkFunctionRecord
474
475 """
476 def get_meta(agent_nsr):
477 unit_names, initial_params, vnfr_index_map = {}, {}, {}
478
479 for vnfr_id in agent_nsr.vnfr_ids:
480 juju_vnf = self._juju_vnfs[vnfr_id].vnfr
481
482 # Vnfr -> index ref
483 vnfr_index_map[vnfr_id] = juju_vnf['member_vnf_index']
484
485 # Unit name
486 unit_names[vnfr_id] = juju_vnf['vnf_juju_name']
487
488 # Flatten the data for simplicity
489 param_data = {}
490 self._log.debug("Juju Config:%s", juju_vnf['config'])
491 for primitive in juju_vnf['config'].initial_config_primitive:
492 for parameter in primitive.parameter:
493 value = self.xlate(parameter.value, juju_vnf['tags'])
494 param_data[parameter.name] = value
495
496 initial_params[vnfr_id] = param_data
497
498
499 return unit_names, initial_params, vnfr_index_map
500
501 unit_names, init_data, vnfr_index_map = get_meta(agent_nsr)
502
503 # The data consists of 4 sections
504 # 1. Account data
505 # 2. The input passed.
506 # 3. Juju unit names (keyed by vnfr ID).
507 # 4. Initial config data (keyed by vnfr ID).
508 data = dict()
509 data['config_agent'] = dict(
510 name=self._name,
511 host=self._ip_address,
512 port=self._port,
513 user=self._user,
514 secret=self._secret
515 )
516 data["rpc_ip"] = rpc_ip.as_dict()
517 data["unit_names"] = unit_names
518 data["init_config"] = init_data
519 data["vnfr_index_map"] = vnfr_index_map
520
521 tmp_file = None
522 with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
523 tmp_file.write(yaml.dump(data, default_flow_style=True)
524 .encode("UTF-8"))
525
526 self._log.debug("jujuCA: Creating a temp file: {} with input data".format(
527 tmp_file.name))
528
529 # Get the full path to the script
530 script = ''
531 if rpc_ip.user_defined_script[0] == '/':
532 # The script has full path, use as is
533 script = rpc_ip.user_defined_script
534 else:
535 script = os.path.join(self._rift_var_root_dir, 'launchpad/nsd',
536 self._project.name,
537 agent_nsr.id, 'scripts',
538 rpc_ip.user_defined_script)
539 self.log.debug("jujuCA: Checking for script in %s", script)
540 if not os.path.exists(script):
541 script = os.path.join(self._rift_install_dir, 'usr/bin', rpc_ip.user_defined_script)
542
543 cmd = "{} {}".format(rpc_ip.user_defined_script, tmp_file.name)
544 self._log.debug("jujuCA: Running the CMD: {}".format(cmd))
545
546 coro = asyncio.create_subprocess_shell(cmd, loop=self._loop,
547 stderr=asyncio.subprocess.PIPE)
548 process = yield from coro
549 err = yield from process.stderr.read()
550 task = self._loop.create_task(process.wait())
551
552 return task, err
553
554 @asyncio.coroutine
555 def apply_initial_config(self, agent_nsr, agent_vnfr):
556 """
557 Apply the initial configuration
558 Expect config directives mostly, not actions
559 Actions in initial config may not work based on charm design
560 """
561
562 try:
563 vnfr = self._juju_vnfs[agent_vnfr.id].vnfr
564 except KeyError:
565 self._log.debug("Did not find VNFR %s in Juju plugin",
566 agent_vnfr.name)
567 return False
568
569 vnfr_msg = yield from self.get_vnfr(agent_vnfr.id)
570 if vnfr_msg is None:
571 msg = "Unable to get VNFR {} ({}) through DTS". \
572 format(agent_vnfr.id, agent_vnfr.name)
573 self._log.error(msg)
574 raise RuntimeError(msg)
575
576 vnf_config = vnfr_msg.vnf_configuration
577 self._log.debug("VNFR %s config: %s", vnfr_msg.name,
578 vnf_config.as_dict())
579
580 # Sort the primitive based on the sequence number
581 primitives = sorted(vnf_config.initial_config_primitive,
582 key=lambda k: k.seq)
583 if not primitives:
584 self._log.debug("VNFR {}: No initial-config-primitive specified".
585 format(vnfr_msg.name))
586 return True
587
588 service = vnfr['vnf_juju_name']
589 rc = yield from self.api.is_service_up(service=service)
590 if not rc:
591 return False
592
593 action_ids = []
594 try:
595 if vnfr_msg.mgmt_interface.ip_address:
596 vnfr['tags'].update({'rw_mgmt_ip': vnfr_msg.mgmt_interface.ip_address})
597 self._log.debug("jujuCA:(%s) tags: %s", vnfr['vnf_juju_name'], vnfr['tags'])
598
599 for primitive in primitives:
600 self._log.debug("(%s) Initial config primitive %s",
601 vnfr['vnf_juju_name'], primitive.as_dict())
602 if primitive.config_primitive_ref:
603 # Reference to a primitive in config primitive
604 class Primitive:
605 def __init__(self, name):
606 self.name = name
607 self.value = None
608 self.parameter = []
609
610 prim = Primitive(primitive.config_primitive_ref)
611 rc, eid, err = yield from self._vnf_config_primitive(
612 agent_nsr.id,
613 agent_vnfr.id,
614 prim,
615 vnf_config,
616 wait=True)
617
618 if rc == "failed":
619 msg = "Error executing initial config primitive" \
620 " {} in VNFR {}: rc={}, stderr={}". \
621 format(prim.name, vnfr_msg.name, rc, err)
622 self._log.error(msg)
623 return False
624
625 elif rc == "pending":
626 action_ids.append(eid)
627
628 elif primitive.name:
629 config = {}
630 if primitive.name == 'config':
631 for param in primitive.parameter:
632 if vnfr['tags']:
633 val = self.xlate(param.value,
634 vnfr['tags'])
635 config.update({param.name: val})
636
637 if config:
638 self.juju_log('info', vnfr['vnf_juju_name'],
639 "Applying Initial config:%s",
640 config)
641
642 rc = yield from self.api.apply_config(
643 config,
644 service=service)
645 if rc is False:
646 self.log.error("Service {} is in error state".
647 format(service))
648 return False
649
650 # Apply any actions specified as part of initial config
651 else:
652 self._log.debug("(%s) Initial config action "
653 "primitive %s",
654 vnfr['vnf_juju_name'], primitive)
655 action = primitive.name
656 params = {}
657 for param in primitive.parameter:
658 val = self.xlate(param.value, vnfr['tags'])
659 params.update({param.name: val})
660
661 self._log.info("(%s) Action %s with params %s",
662 vnfr['vnf_juju_name'], action,
663 params)
664
665 resp = yield from self.api.execute_action(
666 action,
667 params,
668 service=service)
669 if 'error' in resp:
670 self._log.error("Applying initial config on {}"
671 " failed for {} with {}: {}".
672 format(vnfr['vnf_juju_name'],
673 action, params, resp))
674 return False
675
676 action_ids.append(resp['action']['tag'])
677
678 except Exception as e:
679 self._log.exception("jujuCA:(%s) Exception juju "
680 "apply_initial_config for VNFR {}: {}".
681 format(vnfr['vnf_juju_name'],
682 agent_vnfr.id, e))
683 return False
684
685 # Check if all actions completed
686 pending = True
687 while pending:
688 pending = False
689 for act in action_ids:
690 resp = yield from self.api.get_action_status(act)
691 if 'error' in resp:
692 self._log.error("Initial config failed for action {}: {}".
693 format(act, resp))
694 return False
695
696 if resp['status'] == 'failed':
697 self._log.error("Initial config action failed for "
698 "action {}: {}".format(act, resp))
699 return False
700
701 if resp['status'] == 'pending':
702 pending = True
703
704 return True
705
706 def add_vnfr_managed(self, agent_vnfr):
707 if agent_vnfr.id not in self._juju_vnfs.keys():
708 self._log.info("juju config agent: add vnfr={}/{}".
709 format(agent_vnfr.name, agent_vnfr.id))
710 self._juju_vnfs[agent_vnfr.id] = agent_vnfr
711
712 def is_vnfr_managed(self, vnfr_id):
713 try:
714 if vnfr_id in self._juju_vnfs:
715 return True
716 except Exception as e:
717 self._log.debug("jujuCA: Is VNFR {} managed: {}".
718 format(vnfr_id, e))
719 return False
720
721 @asyncio.coroutine
722 def is_configured(self, vnfr_id):
723 try:
724 agent_vnfr = self._juju_vnfs[vnfr_id]
725 vnfr = agent_vnfr.vnfr
726 if vnfr['active']:
727 return True
728
729 vnfr = self._juju_vnfs[vnfr_id].vnfr
730 service = vnfr['vnf_juju_name']
731 resp = self.api.is_service_active(service=service)
732 self._juju_vnfs[vnfr_id]['active'] = resp
733 self._log.debug("jujuCA: Service state for {} is {}".
734 format(service, resp))
735 return resp
736
737 except KeyError:
738 self._log.debug("jujuCA: VNFR id {} not found in config agent".
739 format(vnfr_id))
740 return False
741 except Exception as e:
742 self._log.error("jujuCA: VNFR id {} is_configured: {}".
743 format(vnfr_id, e))
744 return False
745
746 @asyncio.coroutine
747 def get_config_status(self, agent_nsr, agent_vnfr):
748 """Get the configuration status for the VNF"""
749 rc = 'unknown'
750
751 try:
752 vnfr = agent_vnfr.vnfr
753 service = vnfr['vnf_juju_name']
754 except KeyError:
755 # This VNF is not managed by Juju
756 return rc
757
758 rc = 'configuring'
759
760 if not self.check_task_status(service, 'deploy'):
761 return rc
762
763 try:
764 resp = yield from self.api.get_service_status(service=service)
765 self._log.debug("jujuCA: Get service %s status? %s", service, resp)
766
767 if resp == 'error':
768 return 'error'
769 if resp == 'active':
770 return 'configured'
771 except KeyError:
772 self._log.error("jujuCA: Check unknown service %s status", service)
773 except Exception as e:
774 self._log.error("jujuCA: Caught exception when checking for service is active: %s", e)
775 self._log.exception(e)
776
777 return rc
778
779 def get_action_status(self, execution_id):
780 ''' Get the action status for an execution ID
781 *** Make sure this is NOT a asyncio coroutine function ***
782 '''
783
784 try:
785 self._log.debug("jujuCA: Get action status for {}".format(execution_id))
786 resp = self.api._get_action_status(execution_id)
787 self._log.debug("jujuCA: Action status: {}".format(resp))
788 return resp
789 except Exception as e:
790 self._log.error("jujuCA: Error fetching execution status for %s",
791 execution_id)
792 self._log.exception(e)
793 raise e
794
795 def get_service_status(self, vnfr_id):
796 '''Get the service status, used by job status handle
797 Make sure this is NOT a coroutine
798 '''
799 service = self.get_service_name(vnfr_id)
800 if service is None:
801 self._log.error("jujuCA: VNFR {} not managed by this Juju agent".
802 format(vnfr_id))
803 return None
804
805 # Delay for 3 seconds before checking as config apply takes a
806 # few seconds to transfer to the service
807 time.sleep(3)
808 return self.api._get_service_status(service=service)