Example #1
0
def assert_storage_is_intact(client, expected_results):
    """Ensure stored tokens match the expected values in `expected_results`.

    Checks the token values stored on the storage assigned to the deployed
    dummy-storage charm.

    Only matches the provided expected token values and ignores any that have
    no values provided for them.

    :param client: ModelClient object where dummy-storage application is
      deployed
    :param expected_results: Dict containing 'token name' -> 'expected value'
      look up values.
    :raises JujuAssertionError: If expected token values are not present in the
      stored token details.
    """
    stored_content = get_stored_token_content(client)

    for expected_name, expected_value in expected_results.iteritems():
        try:
            stored_value = stored_content[expected_name]
        except KeyError:
            raise JujuAssertionError(
                'Expected token "{}" not found in stored results.'.format(
                    expected_name))
        if stored_value != expected_value:
            raise JujuAssertionError(
                'Token values do not match. Expected: {} got: {}'.format(
                    expected_value, stored_value))
Example #2
0
def assert_cloud_details_are_correct(client, cloud_name, example_cloud):
    """
    Check juju add-cloud is performed successfully and it is available
    in the juju client.
    :param client: The juju client
    :param cloud_name: The name of the cloud added
    :param example_cloud: The content of the cloud
    """
    clouds = client.env.read_clouds()
    try:
        if clouds['clouds'][cloud_name] != example_cloud:
            raise JujuAssertionError('Cloud mismatch')
    except KeyError:
        raise JujuAssertionError('Cloud missing {}'.format(cloud_name))
def assess_instance_type(client, provider, instance_type):
    """Assess the instance-type option for constraints"""
    if instance_type not in INSTANCE_TYPES[provider]:
        raise JujuAssertionError(instance_type)
    constraints = Constraints(instance_type=instance_type)
    charm_name = 'instance-type-{}'.format(instance_type.replace('.', '-'))
    assess_constraints_deploy(client, constraints, charm_name)
def assert_model_has_correct_controller_uuid(client):
    model_details = client.show_model()
    model_controller_uuid = model_details[
        client.env.environment]['controller-uuid']
    controller_uuid = client.get_controller_uuid()
    if model_controller_uuid != controller_uuid:
        raise JujuAssertionError()
def assert_deploy(client, test, charm_path, repository=None):
    """Deploy a charm and assert a success or fail.

    :param client: Juju client
    :type client: jujupy.ModelClient
    :param test: Deploy test data.
    :type  test: Test
    :param charm_dir:
    :type charm_dir: str
    :param repository: Direcotry path to the repository
    :type repository: str
    :return: None
    """
    if test.success:
        client.deploy(charm=charm_path,
                      series=test.series,
                      service=test.service,
                      force=test.force,
                      repository=repository)
        client.wait_for_started()
    else:
        try:
            client.deploy(charm=charm_path,
                          series=test.series,
                          service=test.service,
                          force=test.force,
                          repository=repository)
        except subprocess.CalledProcessError:
            return
        raise JujuAssertionError('Assert deploy failed for {}'.format(test))
Example #6
0
def destroy_model(client, new_client):
    log.info('Destroying model "{}"'.format(TEST_MODEL))
    new_client.destroy_model()
    new_model = get_current_model(client)
    if new_model:
        error = 'Juju failed to unset model after it was destroyed'
        raise JujuAssertionError(error)
def assert_command_succeeds(check_callable, command_type, permission):
    try:
        check_callable()
    except subprocess.CalledProcessError:
        raise JujuAssertionError(
            'FAIL User unable to perform {} operation with '
            'permission {}'.format(command_type, permission))
def expect_migration_attempt_to_fail(source_client, dest_client):
    """Ensure that the migration attempt fails due to permissions.

    As we're capturing the stderr output it after we're done with it so it
    appears in test logs.
    """
    try:
        if after_22beta4(source_client.version):
            args = [
                '{}:{}'.format(source_client.env.controller.name,
                               source_client.env.environment),
                dest_client.env.controller.name
            ]
        else:
            args = [
                '-c', source_client.env.controller.name,
                source_client.env.environment, dest_client.env.controller.name
            ]
        log_output = source_client.get_juju_output('migrate',
                                                   *args,
                                                   merge_stderr=True,
                                                   include_e=False)
    except CalledProcessError as e:
        print(e.output, file=sys.stderr)
        if 'permission denied' not in e.output:
            raise
        log.info('SUCCESS: Migrate command failed as expected.')
    else:
        print(log_output, file=sys.stderr)
        raise JujuAssertionError('Migration did not fail as expected.')
def wait_until_model_disappears(client, model_name, timeout=60):
    """Waits for a while for 'model_name' model to no longer be listed.

    :raises JujuAssertionError: If the named model continues to be listed in
      list-models after specified timeout.
    """
    def model_check(client):
        try:
            models = client.get_controller_client().get_models()
        except CalledProcessError as e:
            # It's possible that we've tried to get status from the model as
            # it's being removed.
            # We can't consider the model gone yet until we don't get this
            # error and the model is no longer in the output.
            if 'cannot get model details' not in e.stderr:
                raise
        else:
            # 2.2-rc1 introduced new model listing output name/short-name.
            all_model_names = [
                m.get('short-name', m['name']) for m in models['models']
            ]
            if model_name not in all_model_names:
                return True

    try:
        _wait_for_model_check(client, model_check, timeout)
    except ModelCheckFailed:
        raise JujuAssertionError(
            'Model "{}" failed to be removed after {} seconds'.format(
                model_name, timeout))
def ensure_api_login_redirects(source_client, dest_client):
    """Login attempts must get transparently redirected to the new controller.
    """
    new_model_client = deploy_dummy_source_to_new_model(
        source_client, 'api-redirection')

    # show model controller details
    before_model_details = source_client.show_model()
    assert_model_has_correct_controller_uuid(source_client)

    log.info('Attempting migration process')

    migrated_model_client = migrate_model_to_controller(
        new_model_client, dest_client)

    # check show model controller details
    assert_model_has_correct_controller_uuid(migrated_model_client)

    after_migration_details = migrated_model_client.show_model()
    before_controller_uuid = before_model_details[
        source_client.env.environment]['controller-uuid']
    after_controller_uuid = after_migration_details[
        migrated_model_client.env.environment]['controller-uuid']
    if before_controller_uuid == after_controller_uuid:
        raise JujuAssertionError()

    # Check file for details.
    assert_data_file_lists_correct_controller_for_model(
        migrated_model_client,
        expected_controller=dest_client.env.controller.name)
def assert_deployed_charm_is_responding(client, expected_output=None):
    """Ensure that the deployed simple-server charm is still responding."""
    # Set default value if needed.
    if expected_output is None:
        expected_output = 'simple-server.'
    ipaddress = get_unit_ipaddress(client, 'simple-resource-http/0')
    if expected_output != get_server_response(ipaddress):
        raise JujuAssertionError('Server charm is not responding as expected.')
def assert_config_value(client, attribute, source, value):
    config_values = client.get_model_config()
    try:
        source_value = config_values[attribute]['source']
        attr_value = config_values[attribute]['value']
        if attr_value != value:
            raise JujuAssertionError(
                'Unexpected value for {}.\nGot {} instead of {}'.format(
                    attribute, attr_value, value))

        if source_value != source:
            raise JujuAssertionError(
                'Unexpected source for {}.\nGot {} instead of {}'.format(
                    attribute, source_value, source))
    except KeyError:
        raise ValueError(
            'Attribute {} not found in config values.'.format(attribute))
Example #13
0
def private_address(client, host):
    default_route = ssh(client, host, 'ip -4 -o route list 0/0')
    log.info("Default route from {}: {}".format(host, default_route))
    # Match the device that is the word after 'dev'. eg.
    # default via 10.0.30.1 dev br-eth1 onlink'
    route_match = re.search(r'\sdev\s([\w-]+)', default_route)
    if route_match is None:
        raise JujuAssertionError(
            "Failed to find device in {}".format(default_route))
    device = route_match.group(1)
    log.info("Fetching the device IP of {}".format(device))
    device_ip = ssh(client, host, 'ip -4 -o addr show {}'.format(device))
    log.info("Device IP for {}: {}".format(host, device_ip))
    ip_match = re.search(r'inet\s+(\S+)/\d+\s', device_ip)
    if ip_match is None:
        raise JujuAssertionError(
            "Failed to find ip for device: {}".format(device))
    return ip_match.group(1)
def assert_command_fails(check_callable, command_type, permission):
    try:
        check_callable()
    except subprocess.CalledProcessError:
        pass
    else:
        raise JujuAssertionError('FAIL User performed {} operation with '
                                 'permission {}'.format(
                                     command_type, permission))
Example #15
0
def assess_to(bs_manager, to):
    """Assess bootstraping with the --to option."""
    if to is None:
        raise ValueError('--to not given when testing to')
    with thin_booted_context(bs_manager) as client:
        log.info('To {} bootstrap successful.'.format(to))
        addr = get_controller_hostname(client)
    if addr != to:
        raise JujuAssertionError('Not bootstrapped to the correct address.')
Example #16
0
def check_remote_log_for_content(remote_machine, unit, check_string,
                                 script_path):
    try:
        remote_machine.juju('ssh', (unit, 'sudo', 'python', script_path,
                                    check_string, '/var/log/syslog'))
        log.info('Check script passed on target machine.')
    except subprocess.CalledProcessError:
        # This is where a failure happened
        raise JujuAssertionError('Forwarded log message never appeared.')
def assess_virt_type(client, virt_type):
    """Assess the virt-type option for constraints"""
    if virt_type not in VIRT_TYPES:
        raise JujuAssertionError(virt_type)
    constraints = Constraints(virt_type=virt_type)
    charm_name = 'virt-type-{}'.format(virt_type)
    charm_series = 'xenial'
    with temp_dir() as charm_dir:
        deploy_charm_constraint(client, constraints, charm_name, charm_series,
                                charm_dir)
def mem_to_int(size):
    """Convert an argument size into a number of megabytes."""
    if not re.match(re.compile('^[0123456789]+[MGTP]?$'), size):
        raise JujuAssertionError('Not a size format:', size)
    if size[-1] in 'MGTP':
        val = int(size[0:-1])
        unit = size[-1]
        return val * (1024**'MGTP'.find(unit))
    else:
        return int(size)
def raise_if_contents_differ(resource_contents, file_contents):
    if resource_contents != file_contents:
        raise JujuAssertionError(
            dedent("""\
            Resource contents mismatch.
            Expected:
            {}
            Got:
            {}""".format(
                file_contents,
                resource_contents)))
def check_resource_uploaded_revno(
        charm_command, charm_url, resource_name, revno):
    """Parse list-resources and ensure resource revno is equal to `revno`.

    :raises JujuAssertionError: If the resources revision is not equal to
      `revno`

    """
    revno = int(revno)
    output = charm_command.run('list-resources', charm_url)

    for line in output.split('\n'):
        if line.startswith(resource_name):
            rev = int(line.split(None, 1)[-1])
            if rev != revno:
                raise JujuAssertionError(
                    'Failed to upload resource and increment revision number.')
            return
    raise JujuAssertionError(
        'Failed to find named resource "{}" in output'.format(resource_name))
def assert_data_file_lists_correct_controller_for_model(
        client, expected_controller):
    models_path = os.path.join(client.env.juju_home, 'models.yaml')
    with open(models_path, 'rt') as f:
        models_data = yaml.safe_load(f)

    controller_models = models_data['controllers'][expected_controller][
        'models']

    if client.env.environment not in controller_models:
        raise JujuAssertionError()
Example #22
0
def assess_metadata(bs_manager, local_source):
    client = bs_manager.client
    # This disconnects from the metadata source, as INVALID_URL is different.
    # agent-metadata-url | tools-metadata-url
    client.env.update_config({'agent-metadata-url': INVALID_URL})
    with prepare_temp_metadata(client, local_source) as metadata_dir:
        log.info('Metadata written to: {}'.format(metadata_dir))
        with thin_booted_context(bs_manager, metadata_source=metadata_dir):
            log.info('Metadata bootstrap successful.')
            data = client.get_model_config()
    if INVALID_URL != data['agent-metadata-url']['value']:
        raise JujuAssertionError('Error, possible web metadata.')
def verify_credentials_match(env, cred):
    """Verify the credentials entered match the stored credentials.

    :param env: String environment name
    :param cred: Dict of credential information
    """
    with open(os.path.join(os.environ['JUJU_DATA'], 'credentials.yaml')) as f:
        test_creds = yaml.load(f)
        test_creds = test_creds['credentials'][env][env]
    if not test_creds == cred['credentials']:
        error = 'Credential miss-match after manual add'
        raise JujuAssertionError(error)
def raise_if_shared_machines(unit_machines):
    """Raise an exception if `unit_machines` contain double ups of machine ids.

    A unique list of machine ids will be equal in length to the set of those
    machine ids.

    :raises ValueError: if an empty list is passed in.
    :raises JujuAssertionError: if any double-ups of machine ids are detected.
    """
    if not unit_machines:
        raise ValueError('Cannot share 0 machines. Empty list provided.')
    if len(unit_machines) != len(set(unit_machines)):
        raise JujuAssertionError('Appliction units reside on the same machine')
Example #25
0
def verify_deployed_tool(agent_dir, client, agent_stream):
    """
    Verify the bootstrapped controller makes use of the the specified
    agent-metadata-url.
    :param agent_dir:  The top level directory location of agent file.
    :param client: Juju client
    :param agent_stream: String representing agent stream name
    """
    controller_url, controller_sha256 = get_controller_url_and_sha256(client)

    local_url, local_sha256 = get_local_url_and_sha256(
        agent_dir, controller_url, agent_stream)

    if local_url != controller_url:
        raise JujuAssertionError(
            "mismatch local URL {} and controller URL {}".format(
                local_url, controller_url))

    if local_sha256 != controller_sha256:
        raise JujuAssertionError(
            "mismatch local SHA256 {} and controller SHA256 {}".format(
                local_sha256, controller_sha256))
def assess_virt_type_constraints(client, test_kvm=False):
    """Assess deployment with virt-type constraints."""
    if test_kvm:
        VIRT_TYPES.append("kvm")
    for virt_type in VIRT_TYPES:
        assess_virt_type(client, virt_type)
    try:
        assess_virt_type(client, 'aws')
    except JujuAssertionError:
        log.info("Correctly rejected virt-type aws")
    else:
        raise JujuAssertionError("FAIL: Client deployed with virt-type aws")
    if test_kvm:
        VIRT_TYPES.remove("kvm")
def verify_status(status, resource_id, name, fingerprint, size):
    resources = status['resources']
    for resource in resources:
        if resource['expected']['resourceid'] == resource_id:
            if 'serviceid' in resource['unit']:
                service_app_id = 'serviceid'
            else:
                service_app_id = 'applicationId'
            expected_values = _resource_info(name, fingerprint, size,
                                             service_app_id)
            assert_dict_is_subset(expected_values, resource['expected'])
            assert_dict_is_subset(expected_values, resource['unit'])
            break
    else:
        raise JujuAssertionError('Resource id not found.')
Example #28
0
def assert_metadata_is_correct(expected_agent_metadata_url, client):
    """
    verify the client agent-metadata-url matches the specified value
    :param expected_agent_metadata_url: The expected agent file path.
    :param client: Juju client
    """
    data = client.get_model_config()
    actual_agent_metadata_url = data['agent-metadata-url']['value']
    if expected_agent_metadata_url != actual_agent_metadata_url:
        raise JujuAssertionError(
            'agent-metadata-url mismatch. Expected: {} Got: {}'.format(
                expected_agent_metadata_url, actual_agent_metadata_url))

    log.info('bootstrap successfully with agent-metadata-url={}'.format(
        actual_agent_metadata_url))
Example #29
0
def switch_model(client, current_model, current_controller):
    """Switches back to the old model.

    :param client: Jujupy ModelClient object
    :param current_model: String name of initial testing model
    :param current_controller: String name of testing controller
    """
    client.switch(model=current_model, controller=current_controller)
    new_model = get_current_model(client)
    if new_model == current_model:
        log.info('Current model and switch target match')
    else:
        error = ('Juju failed to switch back to existing model. '
                 'Expected {} got {}'.format(TEST_MODEL, new_model))
        raise JujuAssertionError(error)
def assert_logs_appear_in_client_model(client, expected_logs, timeout):
    """Assert that `expected_logs` appear in client logs within timeout.

    :param client: ModelClient object to query logs of.
    :param expected_logs: string containing log contents to check for.
    :param timeout: int seconds to wait for before raising JujuAssertionError.
    """
    for _ in until_timeout(timeout):
        current_logs = client.get_juju_output('debug-log', '--no-tail',
                                              '--replay', '-l', 'DEBUG')
        if expected_logs in current_logs:
            log.info('SUCCESS: logs migrated.')
            return
        sleep(1)
    raise JujuAssertionError(
        'Logs failed to be migrated after {}'.format(timeout))