Exemple #1
0
async def connect_juju(ctrl_name=None,
                       model_name=None,
                       endpoint=None,
                       username=None,
                       password=None,
                       cacert=None):
    controller = Controller(max_frame_size=MAX_FRAME_SIZE)  # noqa

    if endpoint:
        await controller.connect(endpoint=endpoint,
                                 username=username,
                                 password=password,
                                 cacert=cacert)
    else:
        await controller.connect(ctrl_name)

    if endpoint:
        model = Model(max_frame_size=MAX_FRAME_SIZE)
        await model.connect(uuid=model_name,
                            endpoint=endpoint,
                            username=username,
                            password=password,
                            cacert=cacert)
    elif model_name:
        model = await controller.get_model(model_name)
    else:
        model = Model(max_frame_size=MAX_FRAME_SIZE)  # noqa
        await model.connect()

    # HACK low unsettable timeout in the model
    model.charmstore._cs = CharmStore(timeout=60)

    return controller, model
    async def test_normal_use(self, mock_connect, mock_disconnect):

        async with Model() as model:
            self.assertTrue(isinstance(model, Model))

        self.assertTrue(mock_connect.called)
        self.assertTrue(mock_disconnect.called)
Exemple #3
0
async def scaleDownWorkersOnMachineId(controller, machineId):
    if not ScalerDbConnector.isRemovable(machineId):
        return ("Cannot remove machine: " + machineId +
                " because it is marked as non removable")
    else:
        defaultModel = await controller.get_model("default")
        await defaultModel.get_status()
        model = Model()
        await model.connect()

        for units in defaultModel.units.items():
            if units[1].machine is not None:
                if units[1].machine.entity_id == machineId:
                    unitName = units[1].entity_id
                    machineName = units[1].machine.entity_id
                    machineToRemove = units[1].machine
                    await units[1].remove()
                    await machineToRemove.remove()
                    ScalerDbConnector.deleteMachine(machineId)
                    await model.disconnect()
                    await controller.disconnect()
                    return "Removed unit: " + unitName + " and machine: " + machineName

    await model.disconnect()
    await controller.disconnect()

    return "fail"
Exemple #4
0
    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 test_wait_for_active_status(self):
        # create a custom apps mock
        from types import SimpleNamespace
        apps = {"dummy_app": SimpleNamespace(
            status="active",
            units=[SimpleNamespace(
                name="mockunit/0",
                workload_status="active",
                workload_status_message="workload_status_message",
                machine=None,
                agent_status="idle",
            )],
        )}

        with patch.object(Model, 'applications', new_callable=PropertyMock) as mock_apps:
            mock_apps.return_value = apps
            m = Model()

            # pass "active" via `status` (str)
            await m.wait_for_idle(apps=["dummy_app"], status="active")

            # pass "active" via `wait_for_active` (bool; deprecated)
            await m.wait_for_idle(apps=["dummy_app"], wait_for_active=True)

            # use both `status` and `wait_for_active` - `wait_for_active` takes precedence
            await m.wait_for_idle(apps=["dummy_app"], wait_for_active=True, status="doesn't matter")

        mock_apps.assert_called_with()
async def model(request, tools):
    model = Model()
    await model.connect(tools.connection)
    if request.config.getoption("--is-upgrade"):
        upgrade_snap_channel = request.config.getoption(
            "--upgrade-snap-channel")
        upgrade_charm_channel = request.config.getoption(
            "--upgrade-charm-channel")
        if not upgrade_snap_channel and upgrade_charm_channel:
            raise Exception(
                "Must have both snap and charm upgrade "
                "channels set to perform upgrade prior to validation test.")
        print("Upgrading charms")
        await upgrade_charms(model, upgrade_charm_channel, tools)
        print("Upgrading snaps")
        await upgrade_snaps(model, upgrade_snap_channel, tools)
    if request.config.getoption("--snapd-upgrade"):
        snapd_channel = request.config.getoption("--snapd-channel")
        await log_snap_versions(model, prefix="Before")
        for unit in model.units.values():
            if unit.dead:
                continue
            await unit.run(f"sudo snap refresh core --{snapd_channel}")
            await unit.run(f"sudo snap refresh snapd --{snapd_channel}")
        await log_snap_versions(model, prefix="After")
    yield model
    await model.disconnect()
Exemple #7
0
async def main():
    model = Model()
    await model.connect()
    await model.reset(force=True)

    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)
async def model(request, event_loop, connection_name):
    event_loop.set_exception_handler(lambda l, _: l.stop())
    model = Model(event_loop)
    await model.connect(connection_name)
    if request.config.getoption("--is-upgrade"):
        upgrade_snap_channel = request.config.getoption(
            "--upgrade-snap-channel")
        upgrade_charm_channel = request.config.getoption(
            "--upgrade-charm-channel")
        if not upgrade_snap_channel and upgrade_charm_channel:
            raise Exception(
                "Must have both snap and charm upgrade channels set to perform upgrade prior to validation test."
            )
        print("Upgrading charms")
        await upgrade_charms(model, upgrade_charm_channel)
        print("Upgrading snaps")
        await upgrade_snaps(model, upgrade_snap_channel)
    if request.config.getoption("--snapd-upgrade"):
        snapd_channel = request.config.getoption("--snapd-channel")
        cmd = f"sudo snap refresh core --{snapd_channel}"
        cloudinit_userdata = {"postruncmd": [cmd]}
        cloudinit_userdata_str = yaml.dump(cloudinit_userdata)
        await model.set_config({"cloudinit-userdata": cloudinit_userdata_str})
        await model.deploy("cs:~containers/charmed-kubernetes")
        await log_snap_versions(model, prefix="Before")
        await asyncify(_juju_wait)()
        await log_snap_versions(model, prefix="After")
    yield model
    await model.disconnect()
async def model(controller):
    """Return the model for the test."""
    model_name = os.getenv("PYTEST_MODEL")
    if model_name:
        # Reuse existing model
        _model = Model()
        full_name = "{}:{}".format(controller.controller_name,
                                   os.getenv("PYTEST_MODEL"))
        try:
            await _model.connect(full_name)
        except JujuConnectionError:
            # Let's create it since it's missing
            _model = await controller.add_model(
                model_name,
                cloud_name=os.getenv("PYTEST_CLOUD_NAME"),
                region=os.getenv("PYTEST_CLOUD_REGION"),
            )
    else:
        # Create a new random model
        model_name = "functest-{}".format(str(uuid.uuid4())[-12:])
        _model = await controller.add_model(
            model_name,
            cloud_name=os.getenv("PYTEST_CLOUD_NAME"),
            region=os.getenv("PYTEST_CLOUD_REGION"),
        )
    # https://github.com/juju/python-libjuju/issues/267
    subprocess.check_call(["juju", "models"])
    while model_name not in await controller.list_models():
        await asyncio.sleep(1)
    yield _model
    await _model.disconnect()
    if not os.getenv("PYTEST_KEEP_MODEL"):
        await controller.destroy_model(model_name)
        while model_name in await controller.list_models():
            await asyncio.sleep(1)
Exemple #10
0
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 local-charm')
        base_dir = Path(__file__).absolute().parent.parent
        charm_path = '{}/tests/integration/oci-image-charm'.format(base_dir)
        resources = {"oci-image": "ubuntu/latest"}
        application = await model.deploy(
            charm_path,
            resources=resources,
        )

        print('Waiting for active')
        await model.block_until(
            lambda: all(unit.workload_status == 'active'
                        for unit in application.units),
            timeout=120,
        )

        print('Removing Charm')
        await application.remove()
    finally:
        print('Disconnecting from model')
        await model.disconnect()
Exemple #11
0
async def run():
    model = Model()
    await model.connect_current()
    await model.reset(force=True)

    ubuntu_app = await model.deploy(
        'mysql',
        service_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()
    model.loop.stop()
Exemple #12
0
async def run_in_model(model_name, f, add_model_arg=False, awaitable=True):
    """Run the given function in the model matching the model_name

    :param model_name: Name of model to run function in
    :type model_name: str
    :param f: Function to run with given moel in focus
    :type f: functools.partial
    :param add_model_arg: Whether to add kwarg pointing at model to the given
                          function before running it
    :type add_model_arg: boolean
    :param awaitable: Whether f is awaitable
    :type awaitable: boolean
    :returns: Output of f
    :rtype: Unknown, depends on the passed in function
    """
    model = Model()
    await model.connect_model(model_name)
    output = None
    try:
        if add_model_arg:
            f.keywords.update(model=model)
        if awaitable:
            output = await f()
        else:
            output = f()
    finally:
        # Disconnect from the api server and cleanup.
        await model.disconnect()
        return output
Exemple #13
0
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 trusted bundle application ubuntu')
        applications = await model.deploy(
            'cs:~juju-qa/bundle/basic-trusted-1',
            channel='beta',
            trust=True,
        )

        print('Waiting for active')
        await model.block_until(
            lambda: all(unit.workload_status == 'active'
                        for application in applications for unit in application.units))
        print("Successfully deployed!")
        print('Removing bundle')
        for application in applications:
            await application.remove()
    finally:
        print('Disconnecting from model')
        await model.disconnect()
async def test_deploy():
    # Get env variables
    CHARM_NAME = os.environ.get('CHARM_NAME')
    CHARM_PATH = os.path.join(os.environ.get('CHARM_BUILD_DIR'), CHARM_NAME)

    model = Model()
    print('Connecting to model')
    await model.connect_current()
    print('Resetting model')
    await model.reset(force=True)

    try:
        print('Deploying {} from {}'.format(CHARM_NAME, CHARM_PATH))
        application = await model.deploy(entity_url=CHARM_PATH,
                                         application_name=CHARM_NAME)

        print('Waiting for active')
        await model.block_until(
            lambda: all(unit.workload_status == 'blocked'
                        for unit in application.units))

        print('Removing {}'.format(CHARM_NAME))
        await application.remove()
    finally:
        print('Disconnecting from model')
        await model.disconnect()
    async def _manual_scale(self, expected_units):
        log.info("Scaling '{}' to {} unit(s)...".format(
            SCALABLE_APP, expected_units))

        self._configure({
            "scaling_units_min": expected_units,
            "scaling_units_max": expected_units
        })

        try:
            m = Model()
            await m.connect_current()
            try:
                for i in amulet.helpers.timeout_gen(300):
                    actual_units = len(m.applications[SCALABLE_APP].units)
                    if actual_units == expected_units:
                        break
                    await asyncio.sleep(5)
            finally:
                await m.disconnect()
        except amulet.helpers.TimeoutError:
            msg = ("The CharmScaler did not scale the application '{}' to {} "
                   "unit(s) in time.").format(SCALABLE_APP, expected_units)
            amulet.raise_status(amulet.FAIL, msg=msg)
        except JujuAPIError as e:
            msg = ("Juju API error: {}").format(str(e))
            amulet.raise_status(amulet.FAIL, msg=msg)
async def remove_ssh_key(usr, pwd, ssh_key, url, port, username):
    try:
        controllers = redis.StrictRedis(host=url,
                                        port=port,
                                        charset="utf-8",
                                        decode_responses=True,
                                        db=10)
        users = redis.StrictRedis(host=url,
                                  port=port,
                                  charset="utf-8",
                                  decode_responses=True,
                                  db=11)
        user = json.loads(users.get(username))
        if ssh_key in user['ssh-keys']:
            user['ssh-keys'].remove(ssh_key)
            users.set(username, json.dumps(user))
            for con in user['controllers']:
                for mod in con['models']:
                    controller = json.loads(controllers.get(con['name']))
                    for modl in controller['models']:
                        if modl['name'] == mod['name']:
                            model = Model()
                            logger.info(
                                'Setting up Modelconnection for model: %s',
                                mod['name'])
                            await model.connect(controller['endpoints'][0],
                                                modl['uuid'], usr, pwd,
                                                controller['ca-cert'])
                            await model.remove_ssh_key(username, ssh_key)
                            await model.disconnect()
    except Exception as e:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
        for l in lines:
            logger.error(l)
Exemple #17
0
    async def test_expose_with_exposed_endpoints_as_raw_dict(self, mock_conn):
        mock_facade_version = mock.MagicMock(return_value=13)
        mock_facade = mock.MagicMock(name="application_facade")
        mock_facade().Expose.return_value = asyncio.Future()
        mock_facade().Expose.return_value.set_result([])

        app = Application(entity_id="app-id", model=Model())
        app.name = "panther"
        app._facade = mock_facade
        app._facade_version = mock_facade_version

        # Check that if we pass a dict as would be the case when processing an
        # expose change, it gets correctly converted to ExposedEndpoint values,
        # validated and converted to a dictionary with the right format before
        # it gets passed to the facade.
        await app.expose(exposed_endpoints={
            "": {
                "expose-to-spaces": ["alpha"],
                "expose-to-cidrs": ["0.0.0.0/0"]
            }
        })

        mock_facade().Expose.assert_called_once_with(
            application="panther",
            exposed_endpoints={
                "": {
                    "expose-to-spaces": ["alpha"],
                    "expose-to-cidrs": ["0.0.0.0/0"]
                }
            })
Exemple #18
0
async def main():
    model = Model()
    # connect to current model with current user, per Juju CLI
    await model.connect()

    ubuntu_app = await model.deploy(
        'cs: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()
Exemple #19
0
    def test_apply_delta(self):
        from juju.model import Model
        from juju.application import Application

        model = Model()
        model._connector = mock.MagicMock()
        delta = _make_delta('application', 'add', dict(name='foo'))

        # test add
        prev, new = model.state.apply_delta(delta)
        self.assertEqual(
            len(model.state.state[delta.entity][delta.get_id()]), 1)
        self.assertIsNone(prev)
        self.assertIsInstance(new, Application)

        # test remove
        delta.type = 'remove'
        prev, new = model.state.apply_delta(delta)
        # length of the entity history deque is now 3:
        # - 1 for the first delta
        # - 1 for the second delta
        # - 1 for the None sentinel appended after the 'remove'
        self.assertEqual(
            len(model.state.state[delta.entity][delta.get_id()]), 3)
        self.assertIsInstance(new, Application)
        # new object is falsy because its data is None
        self.assertFalse(new)
        self.assertIsInstance(prev, Application)
        self.assertTrue(prev)
async def add_unit(c_name, m_name, usr, pwd, url, port, app_name, amount,
                   target):
    try:
        controllers = redis.StrictRedis(host=url,
                                        port=port,
                                        charset="utf-8",
                                        decode_responses=True,
                                        db=10)
        controller = json.loads(controllers.get(c_name))
        model = Model()
        logger.info('Setting up Model connection for %s:%s', c_name, m_name)
        for mod in controller['models']:
            if mod['name'] == m_name:
                await model.connect(controller['endpoints'][0], mod['uuid'],
                                    usr, pwd, controller['ca-cert'])
                for app, entity in model.state.applications.items():
                    if app == app_name:
                        logger.info('Adding units to %s', app_name)
                        if target == 'None':
                            target = None
                        await entity.add_unit(count=int(amount), to=target)
        logger.info('Units added to %s', app_name)
    except Exception as e:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
        for l in lines:
            logger.error(l)
    finally:
        if 'model' in locals():
            await model.disconnect()
Exemple #21
0
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(
            'cs: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()
Exemple #22
0
    async def add_model(self,
                        model_name,
                        cloud_name=None,
                        credential_name=None,
                        owner=None,
                        config=None,
                        region=None):
        """Add a model to this controller.

        :param str model_name: Name to give the new model.
        :param str cloud_name: Name of the cloud in which to create the
            model, e.g. 'aws'. Defaults to same cloud as controller.
        :param str credential_name: Name of the credential to use when
            creating the model. If not given, it will attempt to find a
            default credential.
        :param str owner: Username that will own the model. Defaults to
            the current user.
        :param dict config: Model configuration.
        :param str region: Region in which to create the model.
        :return Model: A connection to the newly created model.
        """
        model_facade = client.ModelManagerFacade.from_connection(
            self.connection())

        owner = owner or self.connection().info['user-info']['identity']
        cloud_name = cloud_name or await self.get_cloud()

        try:
            # attempt to add/update the credential from local data if available
            credential_name = await self.add_credential(name=credential_name,
                                                        cloud=cloud_name,
                                                        owner=owner)
        except errors.JujuError:
            # if it's not available locally, assume it's on the controller
            pass

        if credential_name:
            credential = tag.credential(cloud_name, tag.untag('user-', owner),
                                        credential_name)
        else:
            credential = None

        log.debug('Creating model %s', model_name)

        if not config or 'authorized-keys' not in config:
            config = config or {}
            config['authorized-keys'] = await utils.read_ssh_key(
                loop=self._connector.loop)

        model_info = await model_facade.CreateModel(tag.cloud(cloud_name),
                                                    config, credential,
                                                    model_name, owner, region)
        from juju.model import Model
        model = Model(jujudata=self._connector.jujudata)
        kwargs = self.connection().connect_params()
        kwargs['uuid'] = model_info.uuid
        await model._connect_direct(**kwargs)

        return model
Exemple #23
0
 async def __aenter__(self):
     loop = asyncio.get_event_loop()
     loop.set_exception_handler(lambda l, _: l.stop())
     self._model = Model(loop)
     model_name = "{}:{}".format(self._controller_name,
                                 self._model_name)
     await self._model.connect(model_name)
     return self._model
Exemple #24
0
 def __init__(self, token, controller, model):
     con = datastore.get_controller(controller)
     self.c_endpoint = con['endpoints'][0]
     self.c_cacert = con['ca-cert']
     self.m_name = model
     self.m_access = datastore.get_model_access(controller, self.m_name, token.username)
     self.m_uuid = datastore.get_model(controller, self.m_name)['uuid']
     self.m_connection = Model()
 async def test_with_endpoint_and_uuid_with_bakery(self, mock_connect, _):
     m = Model()
     await m.connect(endpoint='0.1.2.3:4566',
                     uuid='some-uuid',
                     bakery_client='bakery')
     mock_connect.assert_called_once_with(endpoint='0.1.2.3:4566',
                                          uuid='some-uuid',
                                          bakery_client='bakery')
Exemple #26
0
async def _deploy_in_loop(new_loop, model_name, jujudata):
    new_model = Model(new_loop, jujudata=jujudata)
    await new_model.connect(model_name)
    try:
        await new_model.deploy('cs:xenial/ubuntu')
        assert 'ubuntu' in new_model.applications
    finally:
        await new_model.disconnect()
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(
            'cs:~jameinel/ubuntu-lite-7',
            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('Expose all opened port ranges')
        await application.expose()

        print(
            'Expose all opened port ranges to the CIDRs that correspond to a list of spaces'
        )
        await application.expose(
            exposed_endpoints={"": ExposedEndpoint(to_spaces=["alpha"])})

        print('Expose all opened port ranges to a list of CIDRs')
        await application.expose(
            exposed_endpoints={"": ExposedEndpoint(to_cidrs=["10.0.0.0/24"])})

        print('Expose all opened port ranges to a list of spaces and CIDRs')
        await application.expose(exposed_endpoints={
            "":
            ExposedEndpoint(to_spaces=["alpha"], to_cidrs=["10.0.0.0/24"])
        })

        print(
            'Expose individual endpoints to different space/CIDR combinations')
        await application.expose(
            exposed_endpoints={
                "": ExposedEndpoint(to_spaces=["alpha"],
                                    to_cidrs=["10.0.0.0/24"]),
                "ubuntu": ExposedEndpoint(to_cidrs=["10.42.42.0/24"])
            })

        print('Unexpose individual endpoints (other endpoints remain exposed)')
        await application.unexpose(exposed_endpoints=["ubuntu"])

        print('Unexpose application')
        await application.unexpose()

        print('Removing ubuntu')
        await application.remove()
    finally:
        print('Disconnecting from model')
        await model.disconnect()
Exemple #28
0
async def get_units():
    model = Model()
    if MODEL is None:
        await model.connect()
    else:
        await model.connect_model(MODEL)
    units = sorted(model.applications['ubuntu'].units, key=lambda u: u.name)
    await model.disconnect()
    return units
Exemple #29
0
 async def test_model_connect_with_endpoint_and_uuid(
     self,
     mock_after_connect,
     mock_connect,
 ):
     from juju.model import Model
     m = Model()
     await m.connect(endpoint='0.1.2.3:4566', uuid='some-uuid')
     mock_connect.assert_called_once_with(endpoint='0.1.2.3:4566', uuid='some-uuid')
Exemple #30
0
async def watch():
    model = Model()
    await model.connect()

    allwatcher = client.AllWatcherFacade.from_connection(model.connection())
    while True:
        change = await allwatcher.Next()
        for delta in change.deltas:
            print(delta.deltas)