Dropped in fixes for juju ssh.
authorPete Vander Giessen <petevg@gmail.com>
Tue, 24 Jan 2017 23:31:01 +0000 (18:31 -0500)
committerPete Vander Giessen <petevg@gmail.com>
Wed, 25 Jan 2017 19:12:37 +0000 (14:12 -0500)
Workaround for https://bugs.launchpad.net/juju/+bug/1643076

This requires dropping to the cli client, but it does give us machines
that actually have the juju admin's ssh key.

examples/add_model.py [new file with mode: 0644]
juju/controller.py
juju/utils.py [new file with mode: 0644]

diff --git a/examples/add_model.py b/examples/add_model.py
new file mode 100644 (file)
index 0000000..323b6ec
--- /dev/null
@@ -0,0 +1,56 @@
+"""
+This example:
+
+1. Creates a model on the current controller
+2. Deploys a charm to it.
+3. Attempts to ssh into the charm
+
+"""
+from juju import loop
+from juju import utils
+from juju.controller import Controller
+import asyncio
+from logging import getLogger
+
+LOG = getLogger(__name__)
+
+
+async def main():
+    controller = Controller()
+    print("Connecting to controller")
+    await controller.connect_current()
+
+    try:
+        model = await controller.add_model("quux")
+
+        print('Deploying ubuntu')
+        application = await model.deploy(
+            'ubuntu-10',
+            application_name='ubuntu',
+            series='trusty',
+            channel='stable',
+        )
+
+        print('Waiting for active')
+        await asyncio.sleep(10)
+        await model.block_until(
+            lambda: all(unit.workload_status == 'active'
+                        for unit in application.units))
+
+        print("Verifying that we can ssh into the created model")
+        ret = utils.execute_process('juju', 'ssh', 'ls /', log=LOG)
+        assert ret
+
+        print('Removing ubuntu')
+        await application.remove()
+
+        print("Destroying model")
+        await controller.destroy_model(model.info.uuid)
+
+    finally:
+        print('Disconnecting from controller')
+        await model.disconnect()
+        await controller.disconnect()
+
+
+loop.run(main())
index cf7c2ce..e3234f8 100644 (file)
@@ -2,6 +2,7 @@ import asyncio
 import logging
 
 from . import tag
+from . import utils
 from .client import client
 from .client import connection
 from .client import watcher
@@ -98,6 +99,19 @@ class Controller(object):
             region,
         )
 
+        # Add our ssh key to the model, to work around
+        # https://bugs.launchpad.net/juju/+bug/1643076
+        try:
+            ssh_key = utils.read_ssh_key()
+            await utils.execute_process(
+                'juju', 'add-ssh-key', '-m', model_name, ssh_key, log=log)
+        except Exception as e:
+            log.warning(
+                "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,
diff --git a/juju/utils.py b/juju/utils.py
new file mode 100644 (file)
index 0000000..b9a9b67
--- /dev/null
@@ -0,0 +1,39 @@
+import asyncio
+import os
+from pathlib import Path
+
+
+async def execute_process(*cmd, log=None):
+    '''
+    Wrapper around asyncio.create_subprocess_exec.
+
+    '''
+    p = await asyncio.create_subprocess_exec(
+            *cmd,
+            stdin=asyncio.subprocess.PIPE,
+            stdout=asyncio.subprocess.PIPE,
+            stderr=asyncio.subprocess.PIPE,
+            )
+    stdout, stderr = await p.communicate()
+    if log:
+        log.debug("Exec %s -> %d", cmd, p.returncode)
+        if stdout:
+            log.debug(stdout.decode('utf-8'))
+        if stderr:
+            log.debug(stderr.decode('utf-8'))
+    return p.returncode == 0
+
+
+def read_ssh_key():
+    '''
+    Attempt to read the local juju admin's public ssh key, so that it
+    can be passed on to a model.
+
+    '''
+    default_data_dir = Path(Path.home(), ".local", "share", "juju")
+    juju_data = os.environ.get("JUJU_DATA", default_data_dir)
+    ssh_key_path = Path(juju_data, 'ssh', 'juju_id_rsa.pub')
+    with ssh_key_path.open('r') as ssh_key_file:
+        ssh_key = ssh_key_file.readlines()[0].strip()
+    return ssh_key
+