Revert "Remove vendored libjuju"

This reverts commit 9d18c22a0dc9e295adda50601fc5e2f45d2c9b8a.

Change-Id: I7dbf291ccd750c5f836ff80c642be492434ab3ac
Signed-off-by: Adam Israel <adam.israel@canonical.com>
diff --git a/modules/libjuju/examples/action.py b/modules/libjuju/examples/action.py
new file mode 100644
index 0000000..f839f11
--- /dev/null
+++ b/modules/libjuju/examples/action.py
@@ -0,0 +1,49 @@
+"""
+This example:
+
+1. Connects to current model and resets it.
+2. Deploys a git unit.
+3. Runs an action against the unit.
+4. Waits for the action results to come back, then exits.
+
+"""
+import logging
+
+from juju import loop
+from juju.model import Model
+
+
+async def run_action(unit):
+    logging.debug('Running action on unit %s', unit.name)
+
+    # unit.run() returns a juju.action.Action instance
+    action = await unit.run_action('add-repo', repo='myrepo')
+    # wait for the action to complete
+    action = await action.wait()
+
+    logging.debug("Action results: %s", action.results)
+
+
+async def main():
+    model = Model()
+    # connect to current model with current user, per Juju CLI
+    await model.connect()
+
+    app = await model.deploy(
+        'git',
+        application_name='git',
+        series='trusty',
+        channel='stable',
+    )
+
+    for unit in app.units:
+        await run_action(unit)
+
+    await model.disconnect()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+    ws_logger = logging.getLogger('websockets.protocol')
+    ws_logger.setLevel(logging.INFO)
+    loop.run(main())
diff --git a/modules/libjuju/examples/add_machine.py b/modules/libjuju/examples/add_machine.py
new file mode 100755
index 0000000..33d0c34
--- /dev/null
+++ b/modules/libjuju/examples/add_machine.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3.5
+
+"""
+This example:
+
+1. Connects to the current model
+2. Creates two machines and a lxd container
+3. Deploys charm to the lxd container
+
+"""
+import logging
+
+from juju import loop
+from juju.model import Model
+
+MB = 1
+GB = 1024
+
+
+async def main():
+    model = Model()
+    await model.connect()
+
+    try:
+        # add a new default machine
+        machine1 = await model.add_machine()
+        # add a machine with constraints, disks, and series
+        machine2 = await model.add_machine(
+            constraints={
+                'mem': 256 * MB,
+            },
+            disks=[{
+                'pool': 'rootfs',
+                'size': 10 * GB,
+                'count': 1,
+            }],
+            series='xenial',
+        )
+        # add a lxd container to machine2
+        machine3 = await model.add_machine(
+            'lxd:{}'.format(machine2.id))
+
+        # deploy charm to the lxd container
+        application = await model.deploy(
+            'ubuntu-10',
+            application_name='ubuntu',
+            series='xenial',
+            channel='stable',
+            to=machine3.id
+        )
+
+        await model.block_until(
+            lambda: all(unit.workload_status == 'active'
+                        for unit in application.units))
+
+        await application.remove()
+
+        await machine3.destroy(force=True)
+        await machine2.destroy(force=True)
+        await machine1.destroy(force=True)
+    finally:
+        await model.disconnect()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+    ws_logger = logging.getLogger('websockets.protocol')
+    ws_logger.setLevel(logging.INFO)
+
+    loop.run(main())
diff --git a/modules/libjuju/examples/add_model.py b/modules/libjuju/examples/add_model.py
new file mode 100644
index 0000000..88766f1
--- /dev/null
+++ b/modules/libjuju/examples/add_model.py
@@ -0,0 +1,67 @@
+"""
+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
+import uuid
+
+LOG = getLogger(__name__)
+
+
+async def main():
+    controller = Controller()
+    print("Connecting to controller")
+    # connect to current controller with current user, per Juju CLI
+    await controller.connect()
+
+    try:
+        model_name = "addmodeltest-{}".format(uuid.uuid4())
+        print("Adding model {}".format(model_name))
+        model = await controller.add_model(model_name)
+
+        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 = await utils.execute_process(
+            'juju', 'ssh', '-m', model_name, 'ubuntu/0', 'ls /', log=LOG)
+        assert ret
+
+        print('Removing ubuntu')
+        await application.remove()
+
+        print("Destroying model")
+        await controller.destroy_model(model.info.uuid)
+
+    except Exception:
+        LOG.exception(
+            "Test failed! Model {} may not be cleaned up".format(model_name))
+
+    finally:
+        print('Disconnecting from controller')
+        if model:
+            await model.disconnect()
+        await controller.disconnect()
+
+
+if __name__ == '__main__':
+    loop.run(main())
diff --git a/modules/libjuju/examples/allwatcher.py b/modules/libjuju/examples/allwatcher.py
new file mode 100644
index 0000000..884230b
--- /dev/null
+++ b/modules/libjuju/examples/allwatcher.py
@@ -0,0 +1,31 @@
+"""
+This example:
+
+1. Connects to the current model
+2. Starts an AllWatcher
+3. Prints all changes received from the AllWatcher
+4. Runs forever (kill with Ctrl-C)
+
+"""
+import asyncio
+import logging
+
+from juju.client.connection import Connection
+from juju.client import client
+from juju import loop
+
+
+async def watch():
+    conn = await Connection.connect()
+    allwatcher = client.AllWatcherFacade.from_connection(conn)
+    while True:
+        change = await allwatcher.Next()
+        for delta in change.deltas:
+            print(delta.deltas)
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+    # Run loop until the process is manually stopped (watch will loop
+    # forever).
+    loop.run(watch())
diff --git a/modules/libjuju/examples/config.py b/modules/libjuju/examples/config.py
new file mode 100644
index 0000000..c7580f6
--- /dev/null
+++ b/modules/libjuju/examples/config.py
@@ -0,0 +1,54 @@
+"""
+This example:
+
+1. Connects to the current model
+2. Resets it
+3. Deploys a charm and prints its config and constraints
+
+"""
+import logging
+
+from juju.model import Model
+from juju import loop
+
+log = logging.getLogger(__name__)
+
+MB = 1
+
+
+async def main():
+    model = Model()
+    # connect to current model with current user, per Juju CLI
+    await model.connect()
+
+    ubuntu_app = await model.deploy(
+        'mysql',
+        application_name='mysql',
+        series='trusty',
+        channel='stable',
+        config={
+            'tuning-level': 'safest',
+        },
+        constraints={
+            'mem': 256 * MB,
+        },
+    )
+
+    # update and check app config
+    await ubuntu_app.set_config({'tuning-level': 'fast'})
+    config = await ubuntu_app.get_config()
+    assert(config['tuning-level']['value'] == 'fast')
+
+    # update and check app constraints
+    await ubuntu_app.set_constraints({'mem': 512 * MB})
+    constraints = await ubuntu_app.get_constraints()
+    assert(constraints['mem'] == 512 * MB)
+
+    await model.disconnect()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+    ws_logger = logging.getLogger('websockets.protocol')
+    ws_logger.setLevel(logging.INFO)
+    loop.run(main())
diff --git a/modules/libjuju/examples/connect_current_model.py b/modules/libjuju/examples/connect_current_model.py
new file mode 100644
index 0000000..b46a09c
--- /dev/null
+++ b/modules/libjuju/examples/connect_current_model.py
@@ -0,0 +1,27 @@
+"""
+This is a very basic example that connects to the currently selected model
+and prints the number of applications deployed to it.
+"""
+import logging
+
+from juju import loop
+from juju.model import Model
+
+log = logging.getLogger(__name__)
+
+
+async def main():
+    model = Model()
+    try:
+        # connect to the current model with the current user, per the Juju CLI
+        await model.connect()
+        print('There are {} applications'.format(len(model.applications)))
+    finally:
+        if model.is_connected():
+            print('Disconnecting from model')
+            await model.disconnect()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.INFO)
+    loop.run(main())
diff --git a/modules/libjuju/examples/controller.py b/modules/libjuju/examples/controller.py
new file mode 100644
index 0000000..b61a6f6
--- /dev/null
+++ b/modules/libjuju/examples/controller.py
@@ -0,0 +1,41 @@
+"""
+This example:
+
+1. Connects to current controller.
+2. Creates a new model.
+3. Deploys an application on the new model.
+4. Disconnects from the model
+5. Destroys the model
+
+"""
+import logging
+
+from juju.controller import Controller
+from juju import loop
+
+
+async def main():
+    controller = Controller()
+    # connect to current controller with current user, per Juju CLI
+    await controller.connect()
+    model = await controller.add_model(
+        'my-test-model',
+        'aws',
+        'aws-tim',
+    )
+    await model.deploy(
+        'ubuntu-0',
+        application_name='ubuntu',
+        series='trusty',
+        channel='stable',
+    )
+    await model.disconnect()
+    await controller.destroy_model(model.info.uuid)
+    await controller.disconnect()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+    ws_logger = logging.getLogger('websockets.protocol')
+    ws_logger.setLevel(logging.INFO)
+    loop.run(main())
diff --git a/modules/libjuju/examples/credential.py b/modules/libjuju/examples/credential.py
new file mode 100644
index 0000000..e653536
--- /dev/null
+++ b/modules/libjuju/examples/credential.py
@@ -0,0 +1,47 @@
+import sys
+from juju import loop
+from juju.controller import Controller
+
+
+async def main(cloud_name, credential_name):
+    controller = Controller()
+    model = None
+    print('Connecting to controller')
+    # connect to current controller with current user, per Juju CLI
+    await controller.connect()
+    try:
+        print('Adding model')
+        model = await controller.add_model(
+            'test',
+            cloud_name=cloud_name,
+            credential_name=credential_name)
+
+        # verify credential
+        print("Verify model's credential: {}".format(
+            model.info.cloud_credential_tag))
+
+        # verify we can deploy
+        print('Deploying ubuntu')
+        app = await model.deploy('ubuntu-10')
+
+        print('Waiting for active')
+        await model.block_until(
+            lambda: app.units and all(unit.workload_status == 'active'
+                                      for unit in app.units))
+
+        print('Removing ubuntu')
+        await app.remove()
+    finally:
+        print('Cleaning up')
+        if model:
+            print('Removing model')
+            model_uuid = model.info.uuid
+            await model.disconnect()
+            await controller.destroy_model(model_uuid)
+        print('Disconnecting')
+        await controller.disconnect()
+
+
+if __name__ == '__main__':
+    assert len(sys.argv) > 2, 'Please provide a cloud and credential name'
+    loop.run(main(sys.argv[1], sys.argv[2]))
diff --git a/modules/libjuju/examples/deploy.py b/modules/libjuju/examples/deploy.py
new file mode 100644
index 0000000..43764d7
--- /dev/null
+++ b/modules/libjuju/examples/deploy.py
@@ -0,0 +1,41 @@
+"""
+This example:
+
+1. Connects to the current model
+2. Deploy a charm and waits until it reports itself active
+3. Destroys the unit and application
+
+"""
+from juju import loop
+from juju.model import Model
+
+
+async def main():
+    model = Model()
+    print('Connecting to model')
+    # connect to current model with current user, per Juju CLI
+    await model.connect()
+
+    try:
+        print('Deploying ubuntu')
+        application = await model.deploy(
+            'ubuntu-10',
+            application_name='ubuntu',
+            series='trusty',
+            channel='stable',
+        )
+
+        print('Waiting for active')
+        await model.block_until(
+            lambda: all(unit.workload_status == 'active'
+                        for unit in application.units))
+
+        print('Removing ubuntu')
+        await application.remove()
+    finally:
+        print('Disconnecting from model')
+        await model.disconnect()
+
+
+if __name__ == '__main__':
+    loop.run(main())
diff --git a/modules/libjuju/examples/fullstatus.py b/modules/libjuju/examples/fullstatus.py
new file mode 100644
index 0000000..5548423
--- /dev/null
+++ b/modules/libjuju/examples/fullstatus.py
@@ -0,0 +1,23 @@
+import asyncio
+
+from juju.client.connection import Connection
+from juju.client.client import ClientFacade
+from juju import loop
+
+async def status():
+    conn = await Connection.connect()
+    client = ClientFacade.from_connection(conn)
+
+    patterns = None
+    status = await client.FullStatus(patterns)
+    await conn.close()
+
+    print('Applications:', list(status.applications.keys()))
+    print('Machines:', list(status.machines.keys()))
+    print('Relations:', status.relations)
+
+    return status
+
+if __name__ == '__main__':
+    loop.run(status())
+
diff --git a/modules/libjuju/examples/future.py b/modules/libjuju/examples/future.py
new file mode 100644
index 0000000..5e974cf
--- /dev/null
+++ b/modules/libjuju/examples/future.py
@@ -0,0 +1,47 @@
+"""
+This example doesn't work - it demonstrates features that don't exist yet.
+
+"""
+import logging
+
+from juju.model import Model
+from juju import loop
+
+
+async def main():
+    model = Model()
+    # connect to current model with current user, per Juju CLI
+    await model.connect()
+
+    goal_state = Model.from_yaml('bundle-like-thing')
+    ubuntu_app = await model.deploy(
+        'ubuntu-0',
+        application_name='ubuntu',
+        series='trusty',
+        channel='stable',
+    )
+    ubuntu_app.on_unit_added(callback=lambda unit: True)
+
+    await model.deploy(
+        'nrpe-11',
+        application_name='nrpe',
+        series='trusty',
+        channel='stable',
+        num_units=0,
+    )
+    await model.add_relation(
+        'ubuntu',
+        'nrpe',
+    )
+
+    result, ok = await model.block_until(
+        lambda: model.matches(goal_state),
+        timeout=600
+    )
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+    ws_logger = logging.getLogger('websockets.protocol')
+    ws_logger.setLevel(logging.INFO)
+    loop.run(main())
diff --git a/modules/libjuju/examples/leadership.py b/modules/libjuju/examples/leadership.py
new file mode 100644
index 0000000..dbd1b6e
--- /dev/null
+++ b/modules/libjuju/examples/leadership.py
@@ -0,0 +1,28 @@
+"""
+This example:
+
+1. Connects to the current model.
+2. Prints out leadership status for all deployed units in the model.
+3. Cleanly disconnects.
+
+"""
+import asyncio
+
+from juju.model import Model
+from juju import loop
+
+async def report_leadership():
+    model = Model()
+    await model.connect()
+
+    print("Leadership: ")
+    for app in model.applications.values():
+        for unit in app.units:
+            print("{}: {}".format(
+                unit.name, await unit.is_leader_from_status()))
+
+    await model.disconnect()
+
+
+if __name__ == '__main__':
+    loop.run(report_leadership())
diff --git a/modules/libjuju/examples/livemodel.py b/modules/libjuju/examples/livemodel.py
new file mode 100644
index 0000000..1b10ac9
--- /dev/null
+++ b/modules/libjuju/examples/livemodel.py
@@ -0,0 +1,31 @@
+"""
+This example:
+
+1. Connects to the current model
+2. Watches the model and prints all changes
+3. Runs forever (kill with Ctrl-C)
+
+"""
+from juju.model import Model
+from juju import loop
+
+
+async def on_model_change(delta, old, new, model):
+    print(delta.entity, delta.type, delta.data)
+    print(old)
+    print(new)
+    print(model)
+
+
+async def watch_model():
+    model = Model()
+    # connect to current model with current user, per Juju CLI
+    await model.connect()
+
+    model.add_observer(on_model_change)
+
+
+if __name__ == '__main__':
+    # Run loop until the process is manually stopped (watch_model will loop
+    # forever).
+    loop.run(watch_model())
diff --git a/modules/libjuju/examples/localcharm.py b/modules/libjuju/examples/localcharm.py
new file mode 100644
index 0000000..b9481d4
--- /dev/null
+++ b/modules/libjuju/examples/localcharm.py
@@ -0,0 +1,34 @@
+"""
+This example shows how to deploy a local charm. It:
+
+1. Connects to current model.
+2. Uploads a local charm (directory on filesystem) to the model.
+3. Deploys the uploaded charm.
+
+"""
+import asyncio
+import logging
+
+from juju.model import Model
+from juju import loop
+
+
+async def main():
+    model = Model()
+    await model.connect()
+
+    # Deploy a local charm using a path to the charm directory
+    await model.deploy(
+        '/home/tvansteenburgh/src/charms/ubuntu',
+        application_name='ubuntu',
+        series='trusty',
+    )
+
+    await model.disconnect()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+    ws_logger = logging.getLogger('websockets.protocol')
+    ws_logger.setLevel(logging.INFO)
+    loop.run(main())
diff --git a/modules/libjuju/examples/relate.py b/modules/libjuju/examples/relate.py
new file mode 100644
index 0000000..347e021
--- /dev/null
+++ b/modules/libjuju/examples/relate.py
@@ -0,0 +1,102 @@
+"""
+This example:
+
+1. Connects to the current model
+2. Resets it
+3. Deploys two charms and relates them
+4. Waits for units to be idle, then exits
+
+"""
+import asyncio
+import logging
+
+from juju.model import Model, ModelObserver
+from juju import loop
+
+
+class MyRemoveObserver(ModelObserver):
+    async def on_change(self, delta, old, new, model):
+        if delta.type == 'remove':
+            assert(new.latest() == new)
+            assert(new.next() is None)
+            assert(new.dead)
+            assert(new.current)
+            assert(new.connected)
+            assert(new.previous().dead)
+            assert(not new.previous().current)
+            assert(not new.previous().connected)
+
+
+class MyModelObserver(ModelObserver):
+    _shutting_down = False
+
+    async def on_change(self, delta, old, new, model):
+        if model.units and model.all_units_idle() and not self._shutting_down:
+            self._shutting_down = True
+            logging.debug('All units idle, disconnecting')
+            await model.reset(force=True)
+            await model.disconnect()
+
+
+async def main():
+    model = Model()
+    # connect to current model with current user, per Juju CLI
+    await model.connect()
+
+    try:
+        model.add_observer(MyRemoveObserver())
+        await model.reset(force=True)
+        model.add_observer(MyModelObserver())
+
+        ubuntu_app = await model.deploy(
+            'ubuntu',
+            application_name='ubuntu',
+            series='trusty',
+            channel='stable',
+        )
+        ubuntu_app.on_change(asyncio.coroutine(
+            lambda delta, old_app, new_app, model:
+                print('App changed: {}'.format(new_app.entity_id))
+        ))
+        ubuntu_app.on_remove(asyncio.coroutine(
+            lambda delta, old_app, new_app, model:
+                print('App removed: {}'.format(old_app.entity_id))
+        ))
+        ubuntu_app.on_unit_add(asyncio.coroutine(
+            lambda delta, old_unit, new_unit, model:
+                print('Unit added: {}'.format(new_unit.entity_id))
+        ))
+        ubuntu_app.on_unit_remove(asyncio.coroutine(
+            lambda delta, old_unit, new_unit, model:
+                print('Unit removed: {}'.format(old_unit.entity_id))
+        ))
+        unit_a, unit_b = await ubuntu_app.add_units(count=2)
+        unit_a.on_change(asyncio.coroutine(
+            lambda delta, old_unit, new_unit, model:
+                print('Unit changed: {}'.format(new_unit.entity_id))
+        ))
+        await model.deploy(
+            'nrpe',
+            application_name='nrpe',
+            series='trusty',
+            channel='stable',
+            # subordinates must be deployed without units
+            num_units=0,
+        )
+        my_relation = await model.add_relation(
+            'ubuntu',
+            'nrpe',
+        )
+        my_relation.on_remove(asyncio.coroutine(
+            lambda delta, old_rel, new_rel, model:
+                print('Relation removed: {}'.format(old_rel.endpoints))
+        ))
+    finally:
+        await model.disconnect()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.INFO)
+    ws_logger = logging.getLogger('websockets.protocol')
+    ws_logger.setLevel(logging.INFO)
+    loop.run(main())
diff --git a/modules/libjuju/examples/unitrun.py b/modules/libjuju/examples/unitrun.py
new file mode 100644
index 0000000..805f0ae
--- /dev/null
+++ b/modules/libjuju/examples/unitrun.py
@@ -0,0 +1,46 @@
+"""
+This example:
+
+1. Connects to current model and resets it.
+2. Deploys one ubuntu unit.
+3. Runs an action against the unit.
+4. Waits for the action results to come back, then exits.
+
+"""
+import logging
+
+from juju.model import Model
+from juju import loop
+
+
+async def run_command(unit):
+    logging.debug('Running command on unit %s', unit.name)
+
+    # unit.run() returns a juju.action.Action instance
+    action = await unit.run('unit-get public-address')
+    logging.debug("Action results: %s", action.results)
+
+
+async def main():
+    model = Model()
+    # connect to current model with current user, per Juju CLI
+    await model.connect()
+
+    app = await model.deploy(
+        'ubuntu-0',
+        application_name='ubuntu',
+        series='trusty',
+        channel='stable',
+    )
+
+    for unit in app.units:
+        await run_command(unit)
+
+    await model.disconnect()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+    ws_logger = logging.getLogger('websockets.protocol')
+    ws_logger.setLevel(logging.INFO)
+    loop.run(main())