From e42708b6ce89b35b88ae526065951f994128ceed Mon Sep 17 00:00:00 2001 From: Pete Vander Giessen Date: Tue, 24 Jan 2017 18:31:01 -0500 Subject: [PATCH] Dropped in fixes for juju ssh. 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 | 56 +++++++++++++++++++++++++++++++++++++++++++ juju/controller.py | 14 +++++++++++ juju/utils.py | 39 ++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 examples/add_model.py create mode 100644 juju/utils.py diff --git a/examples/add_model.py b/examples/add_model.py new file mode 100644 index 0000000..323b6ec --- /dev/null +++ b/examples/add_model.py @@ -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()) diff --git a/juju/controller.py b/juju/controller.py index cf7c2ce..e3234f8 100644 --- a/juju/controller.py +++ b/juju/controller.py @@ -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 ` 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 index 0000000..b9a9b67 --- /dev/null +++ b/juju/utils.py @@ -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 + -- 2.17.1