Added controller to ssh fix. (#100)
[osm/N2VC.git] / juju / controller.py
index 6331c12..135027a 100644 (file)
@@ -2,9 +2,9 @@ import asyncio
 import logging
 
 from . import tag
+from . import utils
 from .client import client
 from .client import connection
-from .client import watcher
 from .model import Model
 
 log = logging.getLogger(__name__)
@@ -22,6 +22,7 @@ class Controller(object):
         """
         self.loop = loop or asyncio.get_event_loop()
         self.connection = None
+        self.controller_name = None
 
     async def connect(
             self, endpoint, username, password, cacert=None, macaroons=None):
@@ -44,6 +45,7 @@ class Controller(object):
         """
         self.connection = (
             await connection.Connection.connect_controller(controller_name))
+        self.controller_name = controller_name
 
     async def disconnect(self):
         """Shut down the watcher task and close websockets.
@@ -76,10 +78,9 @@ class Controller(object):
         model_facade.connect(self.connection)
 
         owner = owner or self.connection.info['user-info']['identity']
+        cloud_name = cloud_name or await self.get_cloud()
 
-        # XXX: We should be able to accept a credential_name without
-        # a cloud_name, and just get the cloud_name from the controller.
-        if credential_name and cloud_name:
+        if credential_name:
             credential = tag.credential(
                 cloud_name,
                 tag.untag('user-', owner),
@@ -88,7 +89,6 @@ class Controller(object):
         else:
             credential = None
 
-
         log.debug('Creating model %s', model_name)
 
         model_info = await model_facade.CreateModel(
@@ -100,6 +100,24 @@ class Controller(object):
             region,
         )
 
+        # Add our ssh key to the model, to work around
+        # https://bugs.launchpad.net/juju/+bug/1643076
+        try:
+            ssh_key = await utils.read_ssh_key(loop=self.loop)
+
+            if self.controller_name:
+                model_name = "{}:{}".format(self.controller_name, model_name)
+
+            cmd = ['juju', 'add-ssh-key', '-m', model_name, ssh_key]
+
+            await utils.execute_process(*cmd, log=log, loop=self.loop)
+        except Exception:
+            log.exception(
+                "Could not add ssh key to model. You will not be able "
+                "to ssh into machines in this model. "
+                "Manually running `juju add-ssh-key <key>` in the cli "
+                "may fix this problem.")
+
         model = Model()
         await model.connect(
             self.connection.endpoint,
@@ -108,6 +126,7 @@ class Controller(object):
             self.connection.password,
             self.connection.cacert,
             self.connection.macaroons,
+            loop=self.loop,
         )
 
         return model
@@ -142,7 +161,7 @@ class Controller(object):
         :param list models: Models to which the user is granted access
 
         """
-        pass
+        raise NotImplementedError()
 
     def change_user_password(self, username, password):
         """Change the password for a user in this controller.
@@ -151,7 +170,7 @@ class Controller(object):
         :param str password: New password
 
         """
-        pass
+        raise NotImplementedError()
 
     def destroy(self, destroy_all_models=False):
         """Destroy this controller.
@@ -160,7 +179,7 @@ class Controller(object):
             controller.
 
         """
-        pass
+        raise NotImplementedError()
 
     def disable_user(self, username):
         """Disable a user.
@@ -168,20 +187,31 @@ class Controller(object):
         :param str username: Username
 
         """
-        pass
+        raise NotImplementedError()
 
     def enable_user(self):
         """Re-enable a previously disabled user.
 
         """
-        pass
+        raise NotImplementedError()
 
     def kill(self):
         """Forcibly terminate all machines and other associated resources for
         this controller.
 
         """
-        pass
+        raise NotImplementedError()
+
+    async def get_cloud(self):
+        """
+        Get the name of the cloud that this controller lives on.
+        """
+        cloud_facade = client.CloudFacade()
+        cloud_facade.connect(self.connection)
+
+        result = await cloud_facade.Clouds()
+        cloud = list(result.clouds.keys())[0]  # only lives on one cloud
+        return tag.untag('cloud-', cloud)
 
     def get_models(self, all_=False, username=None):
         """Return list of available models on this controller.
@@ -191,7 +221,7 @@ class Controller(object):
         :param str username: User for which to list models (admin use only)
 
         """
-        pass
+        raise NotImplementedError()
 
     def get_payloads(self, *patterns):
         """Return list of known payloads.
@@ -209,7 +239,7 @@ class Controller(object):
             - payload status
 
         """
-        pass
+        raise NotImplementedError()
 
     def get_users(self, all_=False):
         """Return list of users that can connect to this controller.
@@ -217,13 +247,13 @@ class Controller(object):
         :param bool all_: Include disabled users
 
         """
-        pass
+        raise NotImplementedError()
 
     def login(self):
         """Log in to this controller.
 
         """
-        pass
+        raise NotImplementedError()
 
     def logout(self, force=False):
         """Log out of this controller.
@@ -232,7 +262,7 @@ class Controller(object):
             with a password
 
         """
-        pass
+        raise NotImplementedError()
 
     def get_model(self, name):
         """Get a model by name.
@@ -240,7 +270,7 @@ class Controller(object):
         :param str name: Model name
 
         """
-        pass
+        raise NotImplementedError()
 
     def get_user(self, username):
         """Get a user by name.
@@ -248,4 +278,4 @@ class Controller(object):
         :param str username: Username
 
         """
-        pass
+        raise NotImplementedError()