From 6ba2856fecf224ae3fd589331e889a6587e8153b Mon Sep 17 00:00:00 2001 From: Tim Van Steenburgh Date: Thu, 8 Dec 2016 16:01:58 -0500 Subject: [PATCH] Make add_model() more user-friendly --- docs/api/juju.rst | 8 ++++ docs/narrative/create-model.rst | 23 +++++++++++ examples/controller.py | 18 +++------ juju/client/connection.py | 2 +- juju/controller.py | 68 +++++++++++++++++++-------------- juju/tag.py | 23 +++++++++++ 6 files changed, 100 insertions(+), 42 deletions(-) create mode 100644 docs/narrative/create-model.rst create mode 100644 juju/tag.py diff --git a/docs/api/juju.rst b/docs/api/juju.rst index bf002f6..37cf094 100644 --- a/docs/api/juju.rst +++ b/docs/api/juju.rst @@ -123,6 +123,14 @@ juju.relation module :undoc-members: :show-inheritance: +juju.tag module +--------------- + +.. automodule:: juju.tag + :members: + :undoc-members: + :show-inheritance: + juju.unit module ---------------- diff --git a/docs/narrative/create-model.rst b/docs/narrative/create-model.rst new file mode 100644 index 0000000..c650f91 --- /dev/null +++ b/docs/narrative/create-model.rst @@ -0,0 +1,23 @@ +Creating and Destroying a Model +=============================== +Example of creating a new model and then destroying it. + +.. code:: python + + from juju.controller import Controller + + controller = Controller() + await controller.connect_current() + + # Create our new model + model = await controller.add_model( + 'mymodel', # name of your new model + 'aws', # name of the cloud to use + 'aws-tim', # name of the credential to use + ) + + # Do stuff with our model... + + # Destroy the model + await model.disconnect() + await controller.destroy_model(model.info.uuid) diff --git a/examples/controller.py b/examples/controller.py index 3a492c4..7bd4b03 100644 --- a/examples/controller.py +++ b/examples/controller.py @@ -4,30 +4,23 @@ This example: 1. Connects to current controller. 2. Creates a new model. 3. Deploys an application on the new model. - -Note: 'cloudcred' format to add a model should be: -cloudcred-__ +4. Disconnects from the model +5. Destroys the model """ import asyncio import logging -from juju.model import Model, ModelObserver from juju.controller import Controller -class MyModelObserver(ModelObserver): - async def on_change(self, delta, old, new, model): - pass - - async def run(): controller = Controller() await controller.connect_current() model = await controller.add_model( - 'libjuju-test', - 'cloud-aws', - 'cloudcred-aws_tvansteenburgh@external_aws-tim', + 'my-test-model', + 'aws', + 'aws-tim', ) await model.deploy( 'ubuntu-0', @@ -36,6 +29,7 @@ async def run(): channel='stable', ) await model.disconnect() + await controller.destroy_model(model.info.uuid) await controller.disconnect() model.loop.stop() diff --git a/juju/client/connection.py b/juju/client/connection.py index f0737ca..452754e 100644 --- a/juju/client/connection.py +++ b/juju/client/connection.py @@ -247,7 +247,7 @@ class Connection: "macaroons": macaroons or [] }}) response = result['response'] - self.build_facades(response['facades']) + self.build_facades(response.get('facades', {})) self.info = response.copy() return response diff --git a/juju/controller.py b/juju/controller.py index 95a4771..67409ba 100644 --- a/juju/controller.py +++ b/juju/controller.py @@ -1,6 +1,7 @@ import asyncio import logging +from . import tag from .client import client from .client import connection from .client import watcher @@ -54,27 +55,41 @@ class Controller(object): self.connection = None async def add_model( - self, name, cloud, credential, owner=None, - config=None, region=None): + self, model_name, cloud_name, credential_name, + owner=None, config=None, region=None): """Add a model to this controller. - :param str name: Name of the model - :param dict config: Model configuration - :param str credential: e.g. ':' - :param str owner: Owner username + :param str model_name: Name to give the new model. + :param str cloud_name: Name of the cloud in which to create the + model, e.g. 'aws'. + :param str credential_name: Name of the credential to use when + creating the model. + :param str owner: Username that will own the model. Defaults to + the current user. + :param dict config: Model configuration. + :param str region: Region in which to create the model. """ + # XXX: We can probably obviate the cloud_name param by getting it + # from the controller itself. + model_facade = client.ModelManagerFacade() model_facade.connect(self.connection) - log.debug('Creating model %s', name) + owner = owner or self.connection.info['user-info']['identity'] + + log.debug('Creating model %s', model_name) model_info = await model_facade.CreateModel( - cloud, + tag.cloud(cloud_name), config, - credential, - name, - owner or self.connection.info['user-info']['identity'], + tag.credential( + cloud_name, + tag.untag('user-', owner), + credential_name + ), + model_name, + owner, region, ) @@ -90,31 +105,26 @@ class Controller(object): return model - async def destroy_models(self, *args): - - """Destroy a model to this controller. - - :param str : of the Model - param accepts string of only OR `model-` + async def destroy_models(self, *uuids): + """Destroy one or more models. + :param str \*uuids: UUIDs of models to destroy """ model_facade = client.ModelManagerFacade() model_facade.connect(self.connection) - # Generate list of args, pre-pend 'model-' - prependarg = list(args) - for index, item in enumerate(prependarg): - if not item.startswith('model-'): - prependarg[index] = "model-%s" % item - - # Create list of objects to pass to DestroyModels() - arglist = [] - for arg in prependarg: - arglist.append(client.Entity(arg)) - log.debug('Destroying Model %s', arg) + log.debug( + 'Destroying model%s %s', + '' if len(uuids) == 1 else 's', + ', '.join(uuids) + ) - await model_facade.DestroyModels(arglist) + await model_facade.DestroyModels([ + client.Entity(tag.model(uuid)) + for uuid in uuids + ]) + destroy_model = destroy_models def add_user(self, username, display_name=None, acl=None, models=None): """Add a user to this controller. diff --git a/juju/tag.py b/juju/tag.py new file mode 100644 index 0000000..f10c5ef --- /dev/null +++ b/juju/tag.py @@ -0,0 +1,23 @@ +def _prefix(prefix, s): + if not s.startswith(prefix): + return '{}{}'.format(prefix, s) + return s + + +def untag(prefix, s): + if s.startswith(prefix): + return s[len(prefix):] + return s + + +def cloud(cloud_name): + return _prefix('cloud-', cloud_name) + + +def credential(cloud, user, credential_name): + credential_string = '{}_{}_{}'.format(cloud, user, credential_name) + return _prefix('cloudcred-', credential_string) + + +def model(cloud_name): + return _prefix('model-', cloud_name) -- 2.25.1