from n2vc.n2vc_conn import obj_to_dict, obj_to_yaml
from n2vc.exceptions \
import N2VCBadArgumentsException, N2VCException, N2VCConnectionException, \
- N2VCExecutionException, N2VCInvalidCertificate
+ N2VCExecutionException, N2VCInvalidCertificate, N2VCNotFound
from n2vc.juju_observer import JujuModelObserver
from juju.controller import Controller
##################################################################################################
"""
+ BUILT_IN_CLOUDS = ["localhost", "microk8s"]
+
def __init__(
self,
db: object,
self.apt_mirror = None
self.cloud = vca_config.get('cloud')
- self.log.debug('Arguments have been checked')
+ # self.log.debug('Arguments have been checked')
# juju data
self.controller = None # it will be filled when connect to juju
artifact_path: str,
db_dict: dict,
progress_timeout: float = None,
- total_timeout: float = None
+ total_timeout: float = None,
+ config: dict = None,
):
self.log.info('Installing configuration sw on ee_id: {}, artifact path: {}, db_dict: {}'
machine_id=machine_id,
db_dict=db_dict,
progress_timeout=progress_timeout,
- total_timeout=total_timeout
+ total_timeout=total_timeout,
+ config=config
)
except Exception as e:
raise N2VCException(message='Error desploying charm into ee={} : {}'.format(ee_id, e))
total_timeout=total_timeout
)
except Exception as e:
- self.log.info('Cannot execute action generate-ssh-key: {}\nContinuing...'.format(e))
+ self.log.info('Skipping exception while executing action generate-ssh-key: {}'.format(e))
# execute action: get-ssh-public-key
try:
except Exception as e:
msg = 'Cannot execute action get-ssh-public-key: {}\n'.format(e)
self.log.info(msg)
- raise e
+ raise N2VCException(msg)
# return public key if exists
return output["pubkey"] if "pubkey" in output else output
):
self.log.debug('adding new relation between {} and {}, endpoints: {}, {}'
- .format(ee_id_1, ee_id_2, endpoint_1, endpoint_2))
+ .format(ee_id_1, ee_id_2, endpoint_1, endpoint_2))
# check arguments
if not ee_id_1:
relation_2=endpoint_2
)
except Exception as e:
- message = 'Error adding relation between {} and {}'.format(ee_id_1, ee_id_2)
+ message = 'Error adding relation between {} and {}: {}'.format(ee_id_1, ee_id_2, e)
self.log.error(message)
raise N2VCException(message=message)
model_name=ns_id,
total_timeout=total_timeout
)
+ except N2VCNotFound:
+ raise
except Exception as e:
raise N2VCException(message='Error deleting namespace {} : {}'.format(namespace, e))
else:
update_dict=update_dict,
fail_on_empty=True
)
+ except asyncio.CancelledError:
+ raise
except Exception as e:
self.log.error('Error writing ee_id to database: {}'.format(e))
machine_id: str,
db_dict: dict,
progress_timeout: float = None,
- total_timeout: float = None
+ total_timeout: float = None,
+ config: dict = None
) -> (Application, int):
# get juju model and observer
channel='stable',
num_units=1,
series=series,
- to=machine_id
+ to=machine_id,
+ config=config
)
# register application with observer
)
self.log.debug('Result: {}, output: {}'.format(ok, output))
return True
+ except asyncio.CancelledError:
+ raise
except Exception as e:
self.log.debug('Error executing verify-ssh-credentials: {}. Retrying...'.format(e))
await asyncio.sleep(retry_timeout)
if not self.enable_os_upgrade:
config_dict['enable-os-refresh-update'] = False
config_dict['enable-os-upgrade'] = False
-
- model = await self.controller.add_model(
- model_name=model_name,
- config=config_dict,
- cloud_name=self.cloud,
- )
+ 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))
if machine_id in machines:
machine = model.machines[machine_id]
observer.unregister_machine(machine_id)
- await machine.destroy(force=True)
- # 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)
+ # 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()
- self.log.debug('Machine destroyed: {}'.format(machine_id))
+ 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))
if total_timeout is None:
total_timeout = 3600
+ end = time.time() + total_timeout
model = await self._juju_get_model(model_name=model_name)
+
+ if not model:
+ raise N2VCNotFound(
+ message="Model {} does not exist".format(model_name)
+ )
+
uuid = model.info.uuid
+ # destroy applications
+ for application_name in model.applications:
+ try:
+ await self._juju_destroy_application(model_name=model_name, application_name=application_name)
+ except Exception as e:
+ self.log.error(
+ "Error destroying application {} in model {}: {}".format(
+ application_name,
+ model_name,
+ e
+ )
+ )
+
# destroy machines
machines = await model.get_machines()
for machine_id in machines:
try:
await self._juju_destroy_machine(model_name=model_name, machine_id=machine_id)
+ except asyncio.CancelledError:
+ raise
except Exception as e:
# ignore exceptions destroying machine
pass
await self._juju_disconnect_model(model_name=model_name)
- self.juju_models[model_name] = None
- self.juju_observers[model_name] = None
self.log.debug('destroying model {}...'.format(model_name))
await self.controller.destroy_model(uuid)
- self.log.debug('model destroy requested {}'.format(model_name))
+ # self.log.debug('model destroy requested {}'.format(model_name))
# wait for model is completely destroyed
- end = time.time() + total_timeout
+ self.log.debug('Waiting for model {} to be destroyed...'.format(model_name))
+ last_exception = ''
while time.time() < end:
- self.log.debug('Waiting for model is destroyed...')
try:
# await self.controller.get_model(uuid)
models = await self.controller.list_models()
if model_name not in models:
self.log.debug('The model {} ({}) was destroyed'.format(model_name, uuid))
return
+ except asyncio.CancelledError:
+ raise
except Exception as e:
- pass
- await asyncio.sleep(1.0)
+ last_exception = e
+ await asyncio.sleep(5)
+ raise N2VCException("Timeout waiting for model {} to be destroyed {}".format(model_name, last_exception))
async def _juju_login(self):
"""Connect to juju controller
try:
self._connecting = True
self.log.info(
- 'connecting to juju controller: {} {}:{} ca_cert: {}'
- .format(self.url, self.username, self.secret, '\n'+self.ca_cert if self.ca_cert else 'None'))
+ 'connecting to juju controller: {} {}:{}{}'
+ .format(self.url, self.username, self.secret[:8] + '...', ' with ca_cert' if self.ca_cert else ''))
# Create controller object
self.controller = Controller(loop=self.loop)