"""The Network Service being acted against does not exist."""
+class PrimitiveDoesNotExist(Exception):
+ """The Primitive being executed does not exist."""
+
# Quiet the debug logging
logging.getLogger('websockets.protocol').setLevel(logging.INFO)
logging.getLogger('juju.client.connection').setLevel(logging.WARN)
is bootstrapped to. This method will write the public key to disk in
that location: ~/.local/share/juju/ssh/juju_id_rsa.pub
"""
+ # Make sure that we have a public key before writing to disk
if public_key is None or len(public_key) == 0:
- return
-
+ if 'OSM_VCA_PUBKEY' in os.environ:
+ public_key = os.getenv('OSM_VCA_PUBKEY', '')
+ if len(public_key == 0):
+ return
+ else:
+ return
+
path = "{}/.local/share/juju/ssh".format(
os.path.expanduser('~'),
)
vdu:
...
- relation:
- - provides: dataVM:db
- requires: mgmtVM:app
+ vca-relationships:
+ relation:
+ - provides: dataVM:db
+ requires: mgmtVM:app
This tells N2VC that the charm referred to by the dataVM vdu offers a relation named 'db', and the mgmtVM vdu has an 'app' endpoint that should be connected to a database.
# Loop through relations
for cfg in configs:
if 'juju' in cfg:
- if 'relation' in juju:
- for rel in juju['relation']:
+ juju = cfg['juju']
+ if 'vca-relationships' in juju and 'relation' in juju['vca-relationships']:
+ for rel in juju['vca-relationships']['relation']:
try:
# get the application name for the provides
# Register this application with the model-level event monitor #
################################################################
if callback:
- self.monitors[model_name].AddApplication(
+ self.log.debug("JujuApi: Registering callback for {}".format(
application_name,
- callback,
- *callback_args
- )
+ ))
+ await self.Subscribe(model_name, application_name, callback, *callback_args)
########################################################
# Check for specific machine placement (native charms) #
if all(k in machine_spec for k in ['host', 'user']):
# Enlist an existing machine as a Juju unit
machine = await model.add_machine(spec='ssh:{}@{}:{}'.format(
- machine_spec['user'],
- machine_spec['host'],
+ machine_spec['username'],
+ machine_spec['hostname'],
self.GetPrivateKeyPath(),
))
to = machine.id
# Where to deploy the charm to.
to=to,
)
-
- # Map the vdu id<->app name,
- #
- await self.Relate(model_name, vnfd)
+ #############################
+ # Map the vdu id<->app name #
+ #############################
+ try:
+ await self.Relate(model_name, vnfd)
+ except KeyError as ex:
+ # We don't currently support relations between NS and VNF/VDU charms
+ self.log.warn("[N2VC] Relations not supported: {}".format(ex))
+ except Exception as ex:
+ # This may happen if not all of the charms needed by the relation
+ # are ready. We can safely ignore this, because Relate will be
+ # retried when the endpoint of the relation is deployed.
+ self.log.warn("[N2VC] Relations not ready")
# #######################################
# # Execute initial config primitive(s) #
}
for primitive in sorted(primitives):
- uuids.append(
- await self.ExecutePrimitive(
- model_name,
- application_name,
- primitives[primitive]['name'],
- callback,
- callback_args,
- **primitives[primitive]['parameters'],
+ try:
+ # self.log.debug("Queuing action {}".format(primitives[primitive]['name']))
+ uuids.append(
+ await self.ExecutePrimitive(
+ model_name,
+ application_name,
+ primitives[primitive]['name'],
+ callback,
+ callback_args,
+ **primitives[primitive]['parameters'],
+ )
)
- )
+ except PrimitiveDoesNotExist as e:
+ self.log.debug("Ignoring exception PrimitiveDoesNotExist: {}".format(e))
+ pass
+ except Exception as e:
+ self.log.debug("XXXXXXXXXXXXXXXXXXXXXXXXX Unexpected exception: {}".format(e))
+ raise e
+
except N2VCPrimitiveExecutionFailed as e:
self.log.debug(
"[N2VC] Exception executing primitive: {}".format(e)
else:
app = await self.get_application(model, application_name)
if app:
+ # Does this primitive exist?
+ actions = await app.get_actions()
+
+ if primitive not in actions.keys():
+ raise PrimitiveDoesNotExist("Primitive {} does not exist".format(primitive))
+
# Run against the first (and probably only) unit in the app
unit = app.units[0]
if unit:
action = await unit.run_action(primitive, **params)
uuid = action.id
+ except PrimitiveDoesNotExist as e:
+ # Catch and raise this exception if it's thrown from the inner block
+ raise e
except Exception as e:
+ # An unexpected exception was caught
self.log.debug(
"Caught exception while executing primitive: {}".format(e)
)
app = await self.get_application(model, application_name)
if app:
# Remove this application from event monitoring
- self.monitors[model_name].RemoveApplication(application_name)
+ await self.Unsubscribe(model_name, application_name)
# self.notify_callback(model_name, application_name, "removing", callback, *callback_args)
self.log.debug(
return True
return False
+ async def Subscribe(self, ns_name, application_name, callback, *callback_args):
+ """Subscribe to callbacks for an application.
+
+ :param ns_name str: The name of the Network Service
+ :param application_name str: The name of the application
+ :param callback obj: The callback method
+ :param callback_args list: The list of arguments to append to calls to
+ the callback method
+ """
+ self.monitors[ns_name].AddApplication(
+ application_name,
+ callback,
+ *callback_args
+ )
+
+ async def Unsubscribe(self, ns_name, application_name):
+ """Unsubscribe to callbacks for an application.
+
+ Unsubscribes the caller from notifications from a deployed application.
+
+ :param ns_name str: The name of the Network Service
+ :param application_name str: The name of the application
+ """
+ self.monitors[ns_name].RemoveApplication(
+ application_name,
+ )
+
# Non-public methods
async def add_relation(self, model_name, relation1, relation2):
"""