Remove deprecated juju api interface 98/5998/1
authorAdam Israel <adam.israel@canonical.com>
Wed, 18 Apr 2018 17:14:26 +0000 (13:14 -0400)
committerAdam Israel <adam.israel@canonical.com>
Wed, 18 Apr 2018 17:14:26 +0000 (13:14 -0400)
This patch removes the deprecated juju_api interface

Change-Id: Ib21504fbb6b43502b9a39988e162355b80debe98
Signed-off-by: Adam Israel <adam.israel@canonical.com>
lcm/osm_lcm/juju_api.py [deleted file]

diff --git a/lcm/osm_lcm/juju_api.py b/lcm/osm_lcm/juju_api.py
deleted file mode 100644 (file)
index 9b8fa5a..0000000
+++ /dev/null
@@ -1,855 +0,0 @@
-############################################################################
-# Copyright 2016 RIFT.io Inc                                               #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License");          #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http://www.apache.org/licenses/LICENSE-2.0                           #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-
-import argparse
-import asyncio
-import logging
-import os
-import ssl
-
-import juju.loop
-from juju.controller import Controller
-from juju.model import Model, ModelObserver
-
-try:
-    ssl._create_default_https_context = ssl._create_unverified_context
-except AttributeError:
-    # Legacy Python doesn't verify by default (see pep-0476)
-    #   https://www.python.org/dev/peps/pep-0476/
-    pass
-
-
-class JujuVersionError(Exception):
-    pass
-
-
-class JujuApiError(Exception):
-    pass
-
-
-class JujuEnvError(JujuApiError):
-    pass
-
-
-class JujuModelError(JujuApiError):
-    pass
-
-
-class JujuStatusError(JujuApiError):
-    pass
-
-
-class JujuUnitsError(JujuApiError):
-    pass
-
-
-class JujuWaitUnitsError(JujuApiError):
-    pass
-
-
-class JujuSrvNotDeployedError(JujuApiError):
-    pass
-
-
-class JujuAddCharmError(JujuApiError):
-    pass
-
-
-class JujuDeployError(JujuApiError):
-    pass
-
-
-class JujuDestroyError(JujuApiError):
-    pass
-
-
-class JujuResolveError(JujuApiError):
-    pass
-
-
-class JujuActionError(JujuApiError):
-    pass
-
-
-class JujuActionApiError(JujuActionError):
-    pass
-
-
-class JujuActionInfoError(JujuActionError):
-    pass
-
-
-class JujuActionExecError(JujuActionError):
-    pass
-
-
-class JujuAuthenticationError(Exception):
-    pass
-
-
-class JujuMonitor(ModelObserver):
-    """Monitor state changes within the Juju Model."""
-    # async def on_change(self, delta, old, new, model):
-    #     """React to changes in the Juju model."""
-    #
-    #     # TODO: Setup the hook to update the UI if the status of a unit changes
-    #     # to be used when deploying a charm and waiting for it to be "ready"
-    #     if delta.entity in ['application', 'unit'] and delta.type == "change":
-    #         pass
-    #
-    #     # TODO: Add a hook when an action is complete
-
-    pass
-
-
-class JujuApi(object):
-    """JujuApi wrapper on jujuclient library.
-
-    There should be one instance of JujuApi for each VNF manged by Juju.
-
-    Assumption:
-        Currently we use one unit per service/VNF. So once a service
-        is deployed, we store the unit name and reuse it
-    """
-
-    log = None
-    controller = None
-    models = {}
-    model = None
-    model_name = None
-    model_uuid = None
-    authenticated = False
-
-    def __init__(self,
-                 log=None,
-                 loop=None,
-                 server='127.0.0.1',
-                 port=17070,
-                 user='admin',
-                 secret=None,
-                 version=None,
-                 model_name='default',
-                 ):
-        """Initialize with the Juju credentials."""
-
-        if log:
-            self.log = log
-        else:
-            self.log = logging.getLogger(__name__)
-
-        # Quiet websocket traffic
-        logging.getLogger('websockets.protocol').setLevel(logging.INFO)
-
-        self.log.debug('JujuApi: instantiated')
-
-        self.server = server
-        self.port = port
-
-        self.secret = secret
-        if user.startswith('user-'):
-            self.user = user
-        else:
-            self.user = 'user-{}'.format(user)
-
-        self.endpoint = '%s:%d' % (server, int(port))
-
-        self.model_name = model_name
-
-        if loop:
-            self.loop = loop
-
-    def __del__(self):
-        """Close any open connections."""
-        yield self.logout()
-
-    async def add_relation(self, a, b, via=None):
-        """
-        Add a relation between two application endpoints.
-
-        :param a An application endpoint
-        :param b An application endpoint
-        :param via The egress subnet(s) for outbound traffic, e.g., (192.168.0.0/16,10.0.0.0/8)
-        """
-        if not self.authenticated:
-            await self.login()
-
-        m = await self.get_model()
-        try:
-            m.add_relation(a, b, via)
-        finally:
-            await m.disconnect()
-
-    async def apply_config(self, config, application):
-        """Apply a configuration to the application."""
-        self.log.debug("JujuApi: Applying configuration to {}.".format(
-            application
-        ))
-        return await self.set_config(application=application, config=config)
-
-    async def deploy_application(self, charm, name="", path="", specs={}):
-        """
-        Deploy an application.
-
-        Deploy an application to a container or a machine already provisioned
-        by the OSM Resource Orchestrator (requires the Juju public ssh key
-        installed on the new machine via cloud-init).
-
-        :param str charm: The name of the charm
-        :param str name: The name of the application, if different than the charm
-        :param str path: The path to the charm
-        :param dict machine: A dictionary identifying the machine to manage via Juju
-            Examples::
-
-                deploy_application(..., specs={'host': '10.0.0.4', 'user': 'ubuntu'})
-        """
-        if not self.authenticated:
-            await self.login()
-
-        # Check that the charm is valid and exists.
-        if charm is None:
-            return None
-
-        app = await self.get_application(name)
-        if app is None:
-
-            # Check for specific machine placement
-            to = None
-            if all(k in specs for k in ['hostname', 'username']):
-                machine = await self.model.add_machine(spec='ssh:%@%'.format(
-                    specs['host'],
-                    specs['user'],
-                ))
-                to = machine.id
-
-            # TODO: Handle the error if the charm isn't found.
-            self.log.debug("JujuApi: Deploying charm {} ({}) from {}".format(
-                charm,
-                name,
-                path,
-                to=to,
-            ))
-            app = await self.model.deploy(
-                path,
-                application_name=name,
-                series='xenial',
-            )
-        return app
-    deploy_service = deploy_application
-
-    async def get_action_status(self, uuid):
-        """Get the status of an action."""
-        if not self.authenticated:
-            await self.login()
-
-        self.log.debug("JujuApi: Waiting for status of action uuid {}".format(uuid))
-        action = await self.model.wait_for_action(uuid)
-        return action.status
-
-    async def get_application(self, application):
-        """Get the deployed application."""
-        if not self.authenticated:
-            await self.login()
-
-        self.log.debug("JujuApi: Getting application {}".format(application))
-        app = None
-        if application and self.model:
-            if self.model.applications:
-                if application in self.model.applications:
-                    app = self.model.applications[application]
-        return app
-
-    async def get_application_status(self, application):
-        """Get the status of an application."""
-        if not self.authenticated:
-            await self.login()
-
-        status = None
-        app = await self.get_application(application)
-        if app:
-            status = app.status
-            self.log.debug("JujuApi: Status of application {} is {}".format(
-                application,
-                str(status),
-            ))
-        return status
-    get_service_status = get_application_status
-
-    async def get_config(self, application):
-        """Get the configuration of an application."""
-        if not self.authenticated:
-            await self.login()
-
-        config = None
-        app = await self.get_application(application)
-        if app:
-            config = await app.get_config()
-
-        self.log.debug("JujuApi: Config of application {} is {}".format(
-            application,
-            str(config),
-        ))
-
-        return config
-
-    async def get_model(self, name='default'):
-        """Get a model from the Juju Controller.
-
-        Note: Model objects returned must call disconnected() before it goes
-        out of scope."""
-        if not self.authenticated:
-            await self.login()
-
-        model = Model()
-
-        uuid = await self.get_model_uuid(name)
-
-        self.log.debug("JujuApi: Connecting to model {} ({})".format(
-            model,
-            uuid,
-        ))
-
-        await model.connect(
-            self.endpoint,
-            uuid,
-            self.user,
-            self.secret,
-            None,
-        )
-
-        return model
-
-    async def get_model_uuid(self, name='default'):
-        """Get the UUID of a model.
-
-        Iterate through all models in a controller and find the matching model.
-        """
-        if not self.authenticated:
-            await self.login()
-
-        uuid = None
-
-        models = await self.controller.get_models()
-
-        self.log.debug("JujuApi: Looking through {} models for model {}".format(
-            len(models.user_models),
-            name,
-        ))
-        for model in models.user_models:
-            if model.model.name == name:
-                uuid = model.model.uuid
-                break
-
-        return uuid
-
-    async def get_status(self):
-        """Get the model status."""
-        if not self.authenticated:
-            await self.login()
-
-        if not self.model:
-            self.model = self.get_model(self.model_name)
-
-        class model_state:
-            applications = {}
-            machines = {}
-            relations = {}
-
-        self.log.debug("JujuApi: Getting model status")
-        status = model_state()
-        status.applications = self.model.applications
-        status.machines = self.model.machines
-
-        return status
-
-    async def is_application_active(self, application):
-        """Check if the application is in an active state."""
-        if not self.authenticated:
-            await self.login()
-
-        state = False
-        status = await self.get_application_status(application)
-        if status and status in ['active']:
-            state = True
-
-        self.log.debug("JujuApi: Application {} is {} active".format(
-            application,
-            "" if status else "not",
-        ))
-
-        return state
-    is_service_active = is_application_active
-
-    async def is_application_blocked(self, application):
-        """Check if the application is in a blocked state."""
-        if not self.authenticated:
-            await self.login()
-
-        state = False
-        status = await self.get_application_status(application)
-        if status and status in ['blocked']:
-            state = True
-
-        self.log.debug("JujuApi: Application {} is {} blocked".format(
-            application,
-            "" if status else "not",
-        ))
-
-        return state
-    is_service_blocked = is_application_blocked
-
-    async def is_application_deployed(self, application):
-        """Check if the application is in a deployed state."""
-        if not self.authenticated:
-            await self.login()
-
-        state = False
-        status = await self.get_application_status(application)
-        if status and status in ['active']:
-            state = True
-        self.log.debug("JujuApi: Application {} is {} deployed".format(
-            application,
-            "" if status else "not",
-        ))
-
-        return state
-    is_service_deployed = is_application_deployed
-
-    async def is_application_error(self, application):
-        """Check if the application is in an error state."""
-        if not self.authenticated:
-            await self.login()
-
-        state = False
-        status = await self.get_application_status(application)
-        if status and status in ['error']:
-            state = True
-        self.log.debug("JujuApi: Application {} is {} errored".format(
-            application,
-            "" if status else "not",
-        ))
-
-        return state
-    is_service_error = is_application_error
-
-    async def is_application_maint(self, application):
-        """Check if the application is in a maintenance state."""
-        if not self.authenticated:
-            await self.login()
-
-        state = False
-        status = await self.get_application_status(application)
-        if status and status in ['maintenance']:
-            state = True
-        self.log.debug("JujuApi: Application {} is {} in maintenence".format(
-            application,
-            "" if status else "not",
-        ))
-
-        return state
-    is_service_maint = is_application_maint
-
-    async def is_application_up(self, application=None):
-        """Check if the application is up."""
-        if not self.authenticated:
-            await self.login()
-        state = False
-
-        status = await self.get_application_status(application)
-        if status and status in ['active', 'blocked']:
-            state = True
-        self.log.debug("JujuApi: Application {} is {} up".format(
-            application,
-            "" if status else "not",
-        ))
-        return state
-    is_service_up = is_application_up
-
-    async def login(self):
-        """Login to the Juju controller."""
-        if self.authenticated:
-            return
-        cacert = None
-        self.controller = Controller()
-
-        self.log.debug("JujuApi: Logging into controller")
-
-        if self.secret:
-            await self.controller.connect(
-                self.endpoint,
-                self.user,
-                self.secret,
-                cacert,
-            )
-        else:
-            await self.controller.connect_current()
-
-        self.authenticated = True
-        self.model = await self.get_model(self.model_name)
-
-    async def logout(self):
-        """Logout of the Juju controller."""
-        if not self.authenticated:
-            return
-
-        if self.model:
-            await self.model.disconnect()
-            self.model = None
-        if self.controller:
-            await self.controller.disconnect()
-            self.controller = None
-
-        self.authenticated = False
-
-    async def remove_application(self, name):
-        """Remove the application."""
-        if not self.authenticated:
-            await self.login()
-
-        app = await self.get_application(name)
-        if app:
-            self.log.debug("JujuApi: Destroying application {}".format(
-                name,
-            ))
-
-            await app.destroy()
-
-    async def remove_relation(self, a, b):
-        """
-        Remove a relation between two application endpoints
-
-        :param a An application endpoint
-        :param b An application endpoint
-        """
-        if not self.authenticated:
-            await self.login()
-
-        m = await self.get_model()
-        try:
-            m.remove_relation(a, b)
-        finally:
-            await m.disconnect()
-
-    async def resolve_error(self, application=None):
-        """Resolve units in error state."""
-        if not self.authenticated:
-            await self.login()
-
-        app = await self.get_application(application)
-        if app:
-            self.log.debug("JujuApi: Resolving errors for application {}".format(
-                application,
-            ))
-
-            for unit in app.units:
-                app.resolved(retry=True)
-
-    async def run_action(self, application, action_name, **params):
-        """Execute an action and return an Action object."""
-        if not self.authenticated:
-            await self.login()
-        result = {
-            'status': '',
-            'action': {
-                'tag': None,
-                'results': None,
-            }
-        }
-        app = await self.get_application(application)
-        if app:
-            # We currently only have one unit per application
-            # so use the first unit available.
-            unit = app.units[0]
-
-            self.log.debug("JujuApi: Running Action {} against Application {}".format(
-                action_name,
-                application,
-            ))
-
-            action = await unit.run_action(action_name, **params)
-
-            # Wait for the action to complete
-            await action.wait()
-
-            result['status'] = action.status
-            result['action']['tag'] = action.data['id']
-            result['action']['results'] = action.results
-
-        return result
-    execute_action = run_action
-
-    async def set_config(self, application, config):
-        """Apply a configuration to the application."""
-        if not self.authenticated:
-            await self.login()
-
-        app = await self.get_application(application)
-        if app:
-            self.log.debug("JujuApi: Setting config for Application {}".format(
-                application,
-            ))
-            await app.set_config(config)
-
-            # Verify the config is set
-            newconf = await app.get_config()
-            for key in config:
-                if config[key] != newconf[key]:
-                    self.log.debug("JujuApi: Config not set! Key {} Value {} doesn't match {}".format(key, config[key], newconf[key]))
-
-
-    async def set_parameter(self, parameter, value, application=None):
-        """Set a config parameter for a service."""
-        if not self.authenticated:
-            await self.login()
-
-        self.log.debug("JujuApi: Setting {}={} for Application {}".format(
-            parameter,
-            value,
-            application,
-        ))
-        return await self.apply_config(
-            {parameter: value},
-            application=application,
-        )
-
-    async def wait_for_application(self, name, timeout=300):
-        """Wait for an application to become active."""
-        if not self.authenticated:
-            await self.login()
-
-        app = await self.get_application(name)
-        if app:
-            self.log.debug("JujuApi: Waiting {} seconds for Application {}".format(
-                timeout,
-                name,
-            ))
-
-            await self.model.block_until(
-                lambda: all(
-                    unit.agent_status == 'idle'
-                    and unit.workload_status
-                    in ['active', 'unknown'] for unit in app.units
-                    ),
-                timeout=timeout,
-                )
-
-
-def get_argparser():
-    parser = argparse.ArgumentParser(description='Test Driver for Juju API')
-
-    ###################
-    # Authentication  #
-    ###################
-    parser.add_argument(
-        "-s", "--server",
-        default='10.0.202.49',
-        help="Juju controller",
-    )
-    parser.add_argument(
-        "-u", "--user",
-        default='admin',
-        help="User, default user-admin"
-    )
-    parser.add_argument(
-        "-p", "--password",
-        default='',
-        help="Password for the user"
-    )
-    parser.add_argument(
-        "-P", "--port",
-        default=17070,
-        help="Port number, default 17070"
-    )
-    parser.add_argument(
-        "-m", "--model",
-        default='default',
-        help="The model to connect to."
-    )
-
-    ##########
-    # Charm  #
-    ##########
-    parser.add_argument(
-        "-d", "--directory",
-        help="Local directory for the charm"
-    )
-    parser.add_argument(
-        "--application",
-        help="Charm name"
-    )
-
-    #############
-    # Placement #
-    #############
-
-    """
-    To deploy to a non-Juju machine, provide the host and
-    credentials for Juju to manually provision (host, username, (password or key?))
-
-    """
-    parser.add_argument(
-        "--proxy",
-        action='store_true',
-        help="Deploy as a proxy charm.",
-    )
-    parser.add_argument(
-        "--no-proxy",
-        action='store_false',
-        dest='proxy',
-        help="Deploy as a full charm.",
-    )
-    parser.set_defaults(proxy=True)
-
-    # Test options?
-    # unit test?
-    #######
-    # VNF #
-    #######
-
-    return parser.parse_args()
-
-
-async def deploy_charm_and_wait():
-    args = get_argparser()
-
-    # Set logging level to debug so we can see verbose output from the
-    # juju library.
-    logging.basicConfig(level=logging.DEBUG)
-
-    # Quiet logging from the websocket library. If you want to see
-    # everything sent over the wire, set this to DEBUG.
-    ws_logger = logging.getLogger('websockets.protocol')
-    ws_logger.setLevel(logging.INFO)
-
-    """Here's an example of a coroutine that will deploy a charm and wait until
-    it's ready to be used."""
-    api = JujuApi(server=args.server,
-                  port=args.port,
-                  user=args.user,
-                  secret=args.password,
-                  # loop=loop,
-                  log=ws_logger,
-                  model_name=args.model
-                  )
-    print("Logging in...")
-    await api.login()
-
-    if api.authenticated:
-        status = await api.get_status()
-        print('Applications:', list(status.applications.keys()))
-        print('Machines:', list(status.machines.keys()))
-
-    if args.directory and args.application:
-
-
-
-        # Deploy the charm
-        charm = os.path.basename(
-            os.path.expanduser(
-                os.path.dirname(args.directory)
-            )
-        )
-        await api.deploy_application(charm,
-                                     name=args.application,
-                                     path=args.directory,
-                                     )
-
-        # Wait for the application to fully deploy. This will block until the
-        # agent is in an idle state, and the charm's workload is either
-        # 'active' or 'unknown', meaning it's ready but the author did not
-        # explicitly set a workload state.
-        print("Waiting for application '{}' to deploy...".format(charm))
-        while (True):
-            # Deploy the charm and wait, periodically checking its status
-            await api.wait_for_application(charm, 30)
-
-            error = await api.is_application_error(charm)
-            if error:
-                print("This application is in an error state.")
-                break
-
-            blocked = await api.is_application_blocked(charm)
-            if blocked:
-                print("This application is blocked.")
-                break
-
-            # An extra check to see if the charm is ready
-            up = await api.is_application_up(charm)
-            print("Application is {}".format("up" if up else "down"))
-
-        print("Service {} is deployed".format(args.application))
-
-        ###################################
-        # Execute config on a proxy charm #
-        ###################################
-        config = await api.get_config(args.application)
-        hostname = config['ssh-username']['value']
-        rhostname = hostname[::-1]
-
-        # Apply the configuration
-        await api.apply_config(
-            {'ssh-username': rhostname}, application=args.application
-        )
-
-        # Get the configuration
-        config = await api.get_config(args.application)
-
-        # Verify the configuration has been updated
-        assert(config['ssh-username']['value'] == rhostname)
-
-        ####################################
-        # Get the status of an application #
-        ####################################
-        status = await api.get_application_status(charm)
-        print("Application Status: {}".format(status))
-
-        ###########################
-        # Execute a simple action #
-        ###########################
-        result = await api.run_action(charm, 'get-ssh-public-key')
-        print("Action {} status is {} and returned {}".format(
-            result['status'],
-            result['action']['tag'],
-            result['action']['results']
-        ))
-
-        #####################################
-        # Execute an action with parameters #
-        #####################################
-        result = await api.run_action(charm, 'run', command='hostname')
-
-        print("Action {} status is {} and returned {}".format(
-            result['status'],
-            result['action']['tag'],
-            result['action']['results']
-        ))
-
-    print("Logging out...")
-    await api.logout()
-    api = None
-
-# get public key in juju controller? that can be pulled without need of a charm deployed and installed to vm via cloud-init
-
-if __name__ == "__main__":
-    # Create a single event loop for running code asyncronously.
-    loop = asyncio.get_event_loop()
-
-    # An initial set of tasks to run
-    tasks = [
-        deploy_charm_and_wait(),
-    ]
-
-    # TODO: optionally run forever and use a Watcher to monitor what's happening
-    loop.run_until_complete(asyncio.wait(tasks))