Add Controller.add_model() with example
authorTim Van Steenburgh <tvansteenburgh@gmail.com>
Thu, 17 Nov 2016 21:26:45 +0000 (16:26 -0500)
committerTim Van Steenburgh <tvansteenburgh@gmail.com>
Thu, 17 Nov 2016 21:26:53 +0000 (16:26 -0500)
examples/controller.py [new file with mode: 0644]
juju/client/connection.py
juju/controller.py

diff --git a/examples/controller.py b/examples/controller.py
new file mode 100644 (file)
index 0000000..de0460c
--- /dev/null
@@ -0,0 +1,46 @@
+"""
+This example:
+
+1. Connects to current controller.
+2. Creates a new model.
+3. Deploys an application on the new 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',
+    )
+    await model.deploy(
+        'ubuntu-0',
+        service_name='ubuntu',
+        series='trusty',
+        channel='stable',
+    )
+    await model.disconnect()
+    await controller.disconnect()
+    model.loop.stop()
+
+
+logging.basicConfig(level=logging.DEBUG)
+ws_logger = logging.getLogger('websockets.protocol')
+ws_logger.setLevel(logging.INFO)
+loop = asyncio.get_event_loop()
+loop.set_debug(False)
+loop.create_task(run())
+loop.run_forever()
index 18111ce..f0737ca 100644 (file)
@@ -135,8 +135,7 @@ class Connection:
 
         redirect_info = await client.redirect_info()
         if not redirect_info:
-            server_info = await client.login(username, password, macaroons)
-            client.build_facades(server_info['facades'])
+            await client.login(username, password, macaroons)
             return client
 
         await client.close()
@@ -153,7 +152,6 @@ class Connection:
                 result = await client.login(username, password, macaroons)
                 if 'discharge-required-error' in result:
                     continue
-                client.build_facades(result['facades'])
                 return client
             except Exception as e:
                 await client.close()
@@ -175,6 +173,33 @@ class Connection:
         return await cls.connect_model(
             '{}:{}'.format(controller_name, model_name))
 
+    @classmethod
+    async def connect_current_controller(cls):
+        """Connect to the currently active controller.
+
+        """
+        jujudata = JujuData()
+        controller_name = jujudata.current_controller()
+
+        return await cls.connect_controller(controller_name)
+
+    @classmethod
+    async def connect_controller(cls, controller_name):
+        """Connect to a controller by name.
+
+        """
+        jujudata = JujuData()
+        controller = jujudata.controllers()[controller_name]
+        endpoint = controller['api-endpoints'][0]
+        cacert = controller.get('ca-cert')
+        accounts = jujudata.accounts()[controller_name]
+        username = accounts['user']
+        password = accounts.get('password')
+        macaroons = get_macaroons() if not password else None
+
+        return await cls.connect(
+            endpoint, None, username, password, cacert, macaroons)
+
     @classmethod
     async def connect_model(cls, model):
         """Connect to a model by name.
@@ -221,7 +246,10 @@ class Connection:
                 "nonce": "".join(random.sample(string.printable, 12)),
                 "macaroons": macaroons or []
             }})
-        return result['response']
+        response = result['response']
+        self.build_facades(response['facades'])
+        self.info = response.copy()
+        return response
 
     async def redirect_info(self):
         try:
index e0f8066..ca871a1 100644 (file)
@@ -1,5 +1,34 @@
+import asyncio
+import logging
+
+from .client import client
+from .client import connection
+from .client import watcher
+from .model import Model
+
+log = logging.getLogger(__name__)
+
+
 class Controller(object):
-    def add_model(self, name, config=None, credential=None, owner=None):
+    async def connect_current(self):
+        """Connect to the current Juju controller.
+
+        """
+        self.connection = (
+            await connection.Connection.connect_current_controller())
+
+    async def disconnect(self):
+        """Shut down the watcher task and close websockets.
+
+        """
+        if self.connection and self.connection.is_open:
+            log.debug('Closing controller connection')
+            await self.connection.close()
+            self.connection = None
+
+    async def add_model(
+            self, name, cloud, credential, owner=None,
+            config=None, region=None):
         """Add a model to this controller.
 
         :param str name: Name of the model
@@ -8,7 +37,31 @@ class Controller(object):
         :param str owner: Owner username
 
         """
-        pass
+        model_facade = client.ModelManagerFacade()
+        model_facade.connect(self.connection)
+
+        log.debug('Creating model %s', name)
+
+        model_info = await model_facade.CreateModel(
+            cloud,
+            config,
+            credential,
+            name,
+            owner or self.connection.info['user-info']['identity'],
+            region,
+        )
+
+        model = Model()
+        await model.connect(
+            self.connection.endpoint,
+            model_info.uuid,
+            self.connection.username,
+            self.connection.password,
+            self.connection.cacert,
+            self.connection.macaroons,
+        )
+
+        return model
 
     def add_user(self, username, display_name=None, acl=None, models=None):
         """Add a user to this controller.