- # format model name
- model_name = N2VCJujuConnector._format_model_name(model_name)
-
- if model_name in self.juju_models:
- return self.juju_models[model_name]
-
- if self._creating_model:
- self.log.debug('Another coroutine is creating a model. Wait...')
- while self._creating_model:
- # another coroutine is creating a model, wait
- await asyncio.sleep(0.1)
- # retry (perhaps another coroutine has created the model meanwhile)
- if model_name in self.juju_models:
- return self.juju_models[model_name]
-
- try:
- self._creating_model = True
-
- # get juju model names from juju
- model_list = await self.controller.list_models()
-
- if model_name not in model_list:
- self.log.info('Model {} does not exist. Creating new model...'.format(model_name))
- config_dict = {'authorized-keys': self.public_key}
- if self.apt_mirror:
- config_dict['apt-mirror'] = self.apt_mirror
- if not self.enable_os_upgrade:
- config_dict['enable-os-refresh-update'] = False
- config_dict['enable-os-upgrade'] = False
- if self.cloud in self.BUILT_IN_CLOUDS:
- model = await self.controller.add_model(
- model_name=model_name,
- config=config_dict,
- cloud_name=self.cloud,
- )
- else:
- model = await self.controller.add_model(
- model_name=model_name,
- config=config_dict,
- cloud_name=self.cloud,
- credential_name="admin"
- )
- self.log.info('New model created, name={}'.format(model_name))
- else:
- self.log.debug('Model already exists in juju. Getting model {}'.format(model_name))
- model = await self.controller.get_model(model_name)
- self.log.debug('Existing model in juju, name={}'.format(model_name))
-
- self.juju_models[model_name] = model
- self.juju_observers[model_name] = JujuModelObserver(n2vc=self, model=model)
- return model
-
- except Exception as e:
- msg = 'Cannot get model {}. Exception: {}'.format(model_name, e)
- self.log.error(msg)
- raise N2VCException(msg)
- finally:
- self._creating_model = False
-
- async def _juju_add_relation(
- self,
- model_name: str,
- application_name_1: str,
- application_name_2: str,
- relation_1: str,
- relation_2: str
- ):
-
- # get juju model and observer
- model = await self._juju_get_model(model_name=model_name)
-
- r1 = '{}:{}'.format(application_name_1, relation_1)
- r2 = '{}:{}'.format(application_name_2, relation_2)
-
- self.log.debug('adding relation: {} -> {}'.format(r1, r2))
- try:
- await model.add_relation(relation1=r1, relation2=r2)
- except JujuAPIError as e:
- # If one of the applications in the relationship doesn't exist, or the relation has already been added,
- # let the operation fail silently.
- if 'not found' in e.message:
- return
- if 'already exists' in e.message:
- return
- # another execption, raise it
- raise e
-
- async def _juju_destroy_application(
- self,
- model_name: str,
- application_name: str
- ):
-
- self.log.debug('Destroying application {} in model {}'.format(application_name, model_name))
-
- # get juju model and observer
- model = await self._juju_get_model(model_name=model_name)
- observer = self.juju_observers[model_name]
-
- application = model.applications.get(application_name)
- if application:
- observer.unregister_application(application_name)
- await application.destroy()
- else:
- self.log.debug('Application not found: {}'.format(application_name))
-
- async def _juju_destroy_machine(
- self,
- model_name: str,
- machine_id: str,
- total_timeout: float = None
- ):
-
- self.log.debug('Destroying machine {} in model {}'.format(machine_id, model_name))
-
- if total_timeout is None:
- total_timeout = 3600
-
- # get juju model and observer
- model = await self._juju_get_model(model_name=model_name)
- observer = self.juju_observers[model_name]
-
- machines = await model.get_machines()
- if machine_id in machines:
- machine = model.machines[machine_id]
- observer.unregister_machine(machine_id)
- # TODO: change this by machine.is_manual when this is upstreamed: https://github.com/juju/python-libjuju/pull/396
- if "instance-id" in machine.safe_data and machine.safe_data[
- "instance-id"
- ].startswith("manual:"):
- self.log.debug("machine.destroy(force=True) started.")
- await machine.destroy(force=True)
- self.log.debug("machine.destroy(force=True) passed.")
- # max timeout
- end = time.time() + total_timeout
- # wait for machine removal
- machines = await model.get_machines()
- while machine_id in machines and time.time() < end:
- self.log.debug("Waiting for machine {} is destroyed".format(machine_id))
- await asyncio.sleep(0.5)
- machines = await model.get_machines()
- self.log.debug("Machine destroyed: {}".format(machine_id))
- else:
- self.log.debug('Machine not found: {}'.format(machine_id))