Пример #1
0
def connect_to_membership(params):
    control_console = helpers.get_control_console(params['console_sock'])
    module_hostvars = params['module_hostvars']
    play_hosts = params['play_hosts']

    changed = False

    for instance_name, instance_vars in module_hostvars.items():
        if helpers.is_expelled(instance_vars) or helpers.is_stateboard(
                instance_vars):
            continue

        if 'config' not in instance_vars or 'advertise_uri' not in instance_vars[
                'config']:
            continue

        connected, err = probe_server(control_console,
                                      instance_vars['config']['advertise_uri'])
        if err is not None and instance_name in play_hosts:
            return helpers.ModuleRes(failed=True, msg=err)

        if connected:
            changed = True

    return helpers.ModuleRes(changed=changed)
def get_configured_replicasets(module_hostvars, play_hosts):
    replicasets = {}

    for instance_name in play_hosts:
        instance_vars = module_hostvars[instance_name]

        if helpers.is_expelled(instance_vars) or helpers.is_stateboard(
                instance_vars):
            continue

        if instance_vars.get('replicaset_alias') is None:
            continue

        replicaset_alias = instance_vars['replicaset_alias']
        if replicaset_alias not in replicasets:
            replicasets.update({
                replicaset_alias: {
                    'instances': [],
                    'roles':
                    instance_vars.get('roles', None),
                    'failover_priority':
                    instance_vars.get('failover_priority', None),
                    'all_rw':
                    instance_vars.get('all_rw', None),
                    'weight':
                    instance_vars.get('weight', None),
                    'vshard_group':
                    instance_vars.get('vshard_group', None),
                    'alias':
                    replicaset_alias,
                }
            })
        replicasets[replicaset_alias]['instances'].append(instance_name)

    return replicasets
Пример #3
0
def get_replicaset_leaders_by_aliases(specified_replicaset_leaders,
                                      control_console):
    if not specified_replicaset_leaders:
        return {}, None

    cluster_instances = helpers.get_cluster_instances(control_console)
    cluster_replicasets = helpers.get_cluster_replicasets(control_console)

    replicaset_leaders = {}
    for replicaset_alias, leader_alias in specified_replicaset_leaders.items():
        cluster_replicaset = cluster_replicasets.get(replicaset_alias)
        if cluster_replicaset is None:
            return None, "Replicaset '%s' isn't found in cluster" % replicaset_alias

        if leader_alias not in cluster_replicaset['instances']:
            return None, "Instance '%s' isn't found in replicaset '%s'" % (
                leader_alias, replicaset_alias)

        leader_instance = cluster_instances.get(leader_alias)
        if leader_instance is None:
            return None, "Instance '%s' isn't found in cluster" % leader_alias

        leader_instance_uuid = leader_instance.get('uuid')
        if not leader_instance_uuid:
            return None, "Instance '%s' has no UUID" % leader_alias

        replicaset_leaders.update({
            cluster_replicaset['uuid']:
            leader_instance_uuid,
        })

    return replicaset_leaders, None
Пример #4
0
def manage_failover(params):
    failover_params = params.get('failover_params')

    if isinstance(failover_params, bool):
        failover_params = {
            'mode': 'eventual' if failover_params is True else 'disabled'
        }

    rename_dict_key_if_exists(failover_params, 'stateboard_params',
                              'tarantool_params')
    if failover_params.get('state_provider') == 'stateboard':
        failover_params['state_provider'] = 'tarantool'

    control_console = helpers.get_control_console(params['console_sock'])

    helpers.set_twophase_options_from_params(control_console, params)

    version = get_tarantool_version(control_console)
    if version is not None and version >= NEW_FAILOVER_API_CARTRIDGE_VERSION:
        return manage_failover_new(control_console, failover_params)
    else:
        if failover_params['mode'] == 'stateful':
            errmsg = 'Stateful failover is supported since cartridge {}'.format(
                NEW_FAILOVER_API_CARTRIDGE_VERSION)
            return helpers.ModuleRes(failed=True, msg=errmsg)
        return manage_failover_old(control_console, failover_params)
def get_control_instance(params):
    module_hostvars = params['module_hostvars']
    play_hosts = params['play_hosts']
    console_sock = params['console_sock']
    app_name = params['app_name']

    control_console = helpers.get_control_console(console_sock)

    control_instance_name, err = get_control_instance_name(
        module_hostvars, play_hosts, control_console)
    if err is not None:
        return helpers.ModuleRes(failed=True, msg=err)

    # in the ideal imagined world we could just use
    # instance_vars['instance_info'], but if control instance is not
    # in play_hosts, instance_info isn't computed for it
    instance_vars = module_hostvars[control_instance_name]

    run_dir = instance_vars.get('cartridge_run_dir')
    control_instance_console_sock = helpers.get_instance_console_sock(
        run_dir,
        app_name,
        control_instance_name,
    )

    http_port = instance_vars.get('config', {}).get('http_port')

    return helpers.ModuleRes(changed=False,
                             fact={
                                 'name': control_instance_name,
                                 'console_sock': control_instance_console_sock,
                                 'http_port': http_port,
                             })
def get_server_params(instance_name, instance_params, cluster_instances,
                      allow_missed_instances):
    if instance_name not in cluster_instances:
        if instance_params.get('expelled') is True:
            return None, None

        msg = "Instance %s isn't found in cluster" % instance_name
        if allow_missed_instances:
            helpers.warn(msg)
            return None, None
        else:
            return None, msg

    cluster_instance = cluster_instances[instance_name]

    if not cluster_instance.get('uuid'):  # uuid is '' for unjoined instances
        return None, None

    server_params = {
        'uuid': cluster_instance.get('uuid'),
    }

    if instance_params.get('expelled') is True:
        server_params['expelled'] = True
    else:
        for param_name in ['zone', 'uri']:
            add_server_param_if_required(server_params, instance_params,
                                         cluster_instance, param_name)

    if len(server_params) == 1:
        # there are only `uuid`, all instance parameters are the same as configured
        return None, None

    return server_params, None
Пример #7
0
def check_instance_state(control_console, expected_states,
                         check_buckets_are_discovered):
    instance_state, err = control_console.eval_res_err('''
        return require('cartridge.confapplier').get_state()
    ''')
    if not instance_state:
        return helpers.ModuleRes(failed=True,
                                 msg="Impossible to get state: %s" % err)
    if instance_state not in expected_states:
        return helpers.ModuleRes(
            failed=True,
            msg="Instance is not in one of states: %s, it's in '%s' state" % (
                expected_states,
                instance_state,
            ),
        )

    if check_buckets_are_discovered:
        buckets_ok, err = control_console.eval_res_err('''
            local vshard_utils = require('cartridge.vshard-utils')
            local vshard_router = require('cartridge.roles.vshard-router')

            local function check_group_buckets(group_name, group_opts)
                if not group_opts.bootstrapped then
                    return true
                end

                local router = vshard_router.get(group_name)
                if router == nil then
                    return true
                end

                local unknown_buckets = router:info().bucket.unknown
                if unknown_buckets == 0 then
                    return true
                end

                return nil, string.format(
                    "%s out of %s buckets are not discovered in group '%s'",
                    unknown_buckets,
                    group_opts.bucket_count,
                    group_name
                )
            end

            local groups = vshard_utils.get_known_groups()
            for group_name, group_opts in pairs(groups) do
                local _, err = check_group_buckets(group_name, group_opts)
                if err ~= nil then
                    return nil, err
                end
            end

            return true
        ''')
        if not buckets_ok:
            return helpers.ModuleRes(failed=True, msg=err)

    return helpers.ModuleRes(changed=False)
def check_members_alive(params):
    console_sock = params['console_sock']
    allowed_states = params['allowed_states']

    control_console = helpers.get_control_console(console_sock)

    bad_members, err = control_console.eval_res_err(
        '''
        local fun = require('fun')
        local membership = require('membership')

        local cartridge_topology = require('cartridge.topology')
        local confapplier = require('cartridge.confapplier')

        local topology_cfg = confapplier.get_readonly('topology')

        if topology_cfg == nil then
            return nil, "Instances aren't joined to cluster yet"
        end

        local allowed_states = ...
        local bad_members = {}

        for _it, instance_uuid, server in fun.filter(cartridge_topology.not_disabled, topology_cfg.servers) do
            local member = membership.get_member(server.uri) or {}

            if (member.payload.uuid ~= instance_uuid) then
                table.insert(bad_members, string.format(
                    '%s uuid mismatch: expected %s, have %s',
                    server.uri, instance_uuid, member.payload.uuid
                ))
            elseif (member.status ~= 'alive') then
                table.insert(bad_members, string.format(
                    '%s status is %s',
                    server.uri, member.status
                ))
            elseif allowed_states ~= nil and next(allowed_states) ~= nil then
                local member_state = member.payload.state
                if fun.index(member_state, allowed_states) == nil then
                    table.insert(bad_members, string.format(
                    '%s state is %s',
                    server.uri, member_state
                ))
                end
            end
        end

        return bad_members
    ''', allowed_states)

    if err is not None:
        return helpers.ModuleRes(failed=True, msg=err)

    if bad_members:
        return helpers.ModuleRes(failed=True,
                                 msg="Some instances aren't alive: %s" %
                                 ', '.join(sorted(bad_members)))

    return helpers.ModuleRes(changed=False)
Пример #9
0
def eval_code(params):
    body = params['body']
    args = params['args']

    control_console = helpers.get_control_console(params['console_sock'])
    eval_res = control_console.eval(body, *args)

    return helpers.ModuleRes(changed=False, fact=eval_res)
Пример #10
0
def patch_instance_in_runtime(params):
    console_sock = params['console_sock']
    instance_config = params['instance_config']
    cartridge_defaults = params['cartridge_defaults']
    strict_mode = params['strict_mode']

    changed, error = configure_box_cfg_params(console_sock, instance_config,
                                              cartridge_defaults, strict_mode)
    if error is not None:
        return helpers.ModuleRes(failed=True, msg=error)
    return helpers.ModuleRes(changed=changed)
Пример #11
0
def check_stateboard_state(control_console):
    box_status, err = control_console.eval_res_err('''
        if type(box.cfg) == 'function' or box.cfg.listen == nil then
            return nil, "box hasn't been configured"
        end
        return true
    ''')
    if not box_status:
        return helpers.ModuleRes(failed=True,
                                 msg="Stateboard is not running: %s" % err)

    return helpers.ModuleRes(changed=False)
def get_alive_not_expelled_instance(params):
    module_hostvars = params['module_hostvars']
    play_hosts = params['play_hosts']
    app_name = params['app_name']

    canditates_by_uris = {}

    for instance_name in play_hosts:
        instance_vars = module_hostvars[instance_name]
        if helpers.is_expelled(instance_vars) or helpers.is_stateboard(
                instance_vars):
            continue

        instance_config = instance_vars.get('config')
        if instance_config is None:
            continue

        advertise_uri = instance_config['advertise_uri']
        canditates_by_uris[advertise_uri] = instance_name

    alive_not_expelled_instance_name = None
    for uri, instance_name in sorted(canditates_by_uris.items()):
        host, port = uri.rsplit(':', 1)

        try:
            conn = socket.create_connection((host, port),
                                            timeout=CONNECTION_TIMEOUT)
            conn.settimeout(CONNECTION_TIMEOUT)
            conn.recv(1024)
        except socket.error:
            continue

        alive_not_expelled_instance_name = instance_name
        break

    if alive_not_expelled_instance_name is None:
        errmsg = "Not found any alive instance that is not expelled and is not a stateboard"
        return helpers.ModuleRes(failed=True, msg=errmsg)

    instance_vars = module_hostvars[alive_not_expelled_instance_name]
    run_dir = instance_vars.get('cartridge_run_dir')
    console_sock = helpers.get_instance_console_sock(
        run_dir,
        app_name,
        alive_not_expelled_instance_name,
    )

    return helpers.ModuleRes(changed=False,
                             fact={
                                 'name': alive_not_expelled_instance_name,
                                 'console_sock': console_sock,
                             })
def check_filtered_instances(instances, filtered_instances, fmt,
                             allow_missed_instances):
    if len(instances) == len(filtered_instances):
        return None

    missed_instances = ', '.join(
        sorted(set(instances).difference(filtered_instances)))

    msg = fmt % missed_instances

    if allow_missed_instances:
        helpers.warn(msg)
        return None

    return msg
Пример #14
0
def check_state(params):
    try:
        control_console = helpers.get_control_console(params['console_sock'])

        if params['stateboard']:
            return check_stateboard_state(control_console)
        else:
            return check_instance_state(
                control_console,
                params['expected_states'],
                params['check_buckets_are_discovered'],
            )

    except helpers.CartridgeException as e:
        return helpers.ModuleRes(exception=e)
Пример #15
0
def get_replicaset_leaders_by_play_hosts(play_hosts, module_hostvars,
                                         control_console):
    cluster_instances = helpers.get_cluster_instances_with_replicasets_info(
        control_console)

    dead_replicasets = set()
    chosen_leaders_priority = {}  # replicaset uuid: leader priority

    replicaset_leaders = {}
    for instance_name in play_hosts:
        instance_vars = module_hostvars[instance_name]

        if helpers.is_stateboard(instance_vars) or helpers.is_expelled(
                instance_vars):
            continue

        cluster_instance = cluster_instances.get(instance_name)
        if cluster_instance is None:
            continue

        instance_uuid = cluster_instance.get('uuid')
        if not instance_uuid:
            continue

        replicaset_uuid = cluster_instance.get('replicaset_uuid')
        if replicaset_uuid is None:
            continue

        replicaset_alias = cluster_instance.get('replicaset_alias',
                                                replicaset_uuid)

        if cluster_instance.get('status') != 'healthy':
            if replicaset_uuid not in replicaset_leaders:
                # there is no alive instances found for this replicaset
                dead_replicasets.add(replicaset_alias)
            continue

        if chosen_leaders_priority.get(replicaset_uuid) is not None:
            if cluster_instance['priority'] > chosen_leaders_priority[
                    replicaset_uuid]:
                # leader with less priority was already chosen
                continue

        replicaset_leaders[replicaset_uuid] = instance_uuid
        chosen_leaders_priority[replicaset_uuid] = cluster_instance['priority']
        dead_replicasets.discard(replicaset_alias)

    return replicaset_leaders, dead_replicasets
Пример #16
0
def get_output_format_and_apply_config_func_for_lua(console_sock):
    assert console_sock is not None, "Console socket is required for Lua mode"

    control_console = helpers.get_control_console(console_sock)

    return FILE_OUTPUT_FORMAT, lambda path: patch_file_clusterwide(
        control_console, path)
Пример #17
0
def get_tdg_http_headers(console_sock, tdg_token):
    if tdg_token is None:
        return {}

    assert console_sock is not None, "Console socket is required for TDG mode"
    control_console = helpers.get_control_console(console_sock)

    tdg_version = control_console.eval_res_err('''
        local ok, app_version = pcall(require, 'common.app_version')
        if not ok then
            return '1.6.0-0-0'
        end
        return app_version.get()
    ''')[0].split('.')

    if tdg_version[0] == 'scm-1':
        return {
            'auth-token': tdg_token,  # TDG <= 1.6
            'Authorization': 'Bearer ' + tdg_token,  # TDG >= 1.7
        }

    major = int(tdg_version[0])
    minor = int(tdg_version[1])
    if major < 1 or major == 1 and minor <= 6:
        return {'auth-token': tdg_token}
    return {'Authorization': 'Bearer ' + tdg_token}
Пример #18
0
def manage_failover_new(control_console, failover_params):
    current_failover_params = get_failover_params(control_console)

    func_body = '''
        return require('cartridge').failover_set_params(...)
    '''
    res, err = control_console.eval_res_err(func_body, failover_params)

    if err is not None:
        errmsg = 'Failed to set failover params: {}'.format(err)
        return helpers.ModuleRes(failed=True, msg=errmsg)

    new_failover_params = get_failover_params(control_console)

    changed = new_failover_params != current_failover_params
    return helpers.ModuleRes(changed=changed)
def main():
    module = AnsibleModule(argument_spec=argument_spec)
    try:
        res = get_systemd_units_info(module.params)
    except Exception as e:
        res = helpers.ModuleRes(exception=e)
    res.exit(module)
Пример #20
0
def apply_tdg_config(console_sock, path):
    control_console = helpers.get_control_console(console_sock)
    _, err = control_console.eval_res_err(
        '''
        return admin.upload_config_api(...)
    ''', path)
    assert err is None, err
    return True
def candidate_is_ok(uri, names_by_uris, module_hostvars):
    instance_name = names_by_uris[uri]
    instance_vars = module_hostvars[instance_name]

    if helpers.is_expelled(instance_vars):
        return False

    return True
Пример #22
0
def patch_file_clusterwide(control_console, file_path):
    file_ext = os.path.splitext(file_path)[1]
    assert file_ext in [
        '.yml', '.yaml'
    ], "Impossible to use '%s' file in patch clusterwide function" % file_ext

    new_sections, err = helpers.read_yaml_file(control_console, file_path)
    assert err is None, err

    old_sections, err = helpers.get_clusterwide_config(control_console)
    assert err is None, err

    for section, value in old_sections.items():
        new_sections[section] = new_sections.get(section)

    changed, err = helpers.patch_clusterwide_config(control_console,
                                                    new_sections)
    assert err is None, err
    return changed
def get_one_not_expelled_instance_for_machine(params):
    module_hostvars = params['module_hostvars']
    play_hosts = params['play_hosts']

    machine_hostnames = set()
    instance_names = []

    for instance_name in play_hosts:
        instance_vars = module_hostvars[instance_name]

        if helpers.is_expelled(instance_vars):
            continue

        machine_hostname = get_machine_hostname(instance_vars, instance_name)
        if machine_hostname not in machine_hostnames:
            machine_hostnames.add(machine_hostname)
            instance_names.append(instance_name)

    return helpers.ModuleRes(changed=False, fact=instance_names)
Пример #24
0
def read_yaml_file_section(control_console, file_path, section):
    sections, err = helpers.read_yaml_file(control_console, file_path)
    if err is not None:
        return None, err

    if section not in sections:
        return None, 'File {} does not contain section: {}'.format(
            file_path, section)

    return sections[section], None
Пример #25
0
def get_scenario_steps(params):
    steps_paths = get_steps_paths(params['role_path'], params['custom_steps_dir'], params['custom_steps'])
    scenario, err = get_scenario(
        params['scenario'],
        params['role_scenarios'], params['custom_scenarios'], params['scenario_name'],
    )
    if err:
        return helpers.ModuleRes(failed=True, msg=err)

    scenario_steps = []
    for step_name in scenario:
        if step_name not in steps_paths:
            return helpers.ModuleRes(failed=True, msg="Unknown step '%s'" % step_name)

        scenario_steps.append({
            'name': step_name,
            'path': steps_paths[step_name],
        })

    return helpers.ModuleRes(changed=False, fact=scenario_steps)
Пример #26
0
def get_tdg_upload_mode(console_sock):
    if console_sock is None:
        return 'http'

    control_console = helpers.get_control_console(console_sock)
    return control_console.eval_res_err('''
        if rawget(_G, 'admin') ~= nil and rawget(_G.admin, 'upload_config_api') ~= nil then
            return 'lua'
        end
        return 'http'
    ''')[0]
Пример #27
0
def configure_box_cfg_params(console_sock,
                             instance_config,
                             defaults=None,
                             strict_mode=False):
    control_console, err = helpers.get_control_console_if_started(
        console_sock, strict_mode)
    if err is not None:
        return None, err
    if not control_console:
        return False, None

    if not helpers.box_cfg_was_called(control_console):
        if strict_mode:
            return None, "Impossible to patch instance config: 'box.cfg' wasn't called"
        return False, None

    old_box_config = helpers.get_box_cfg(control_console)
    new_config = deepcopy(defaults or {})
    new_config.update(instance_config)

    return change_dynamic_params(control_console, old_box_config, new_config,
                                 strict_mode)
Пример #28
0
def manage_failover_old(control_console, failover_params):
    failover_enabled = failover_params['mode'] == 'eventual'

    current_failover, _ = control_console.eval_res_err('''
        return require('cartridge').admin_get_failover()
    ''')

    if current_failover == failover_enabled:
        return helpers.ModuleRes(changed=False)

    function_name = 'admin_enable_failover' if failover_enabled else 'admin_disable_failover'

    func_body = '''
        local function_name = ...
        return require('cartridge')[function_name]()
    '''
    _, err = control_console.eval_res_err(func_body, function_name)

    if err is not None:
        errmsg = 'Failed {}: {}'.format(function_name, err)
        return helpers.ModuleRes(failed=True, msg=errmsg)

    return helpers.ModuleRes()
def get_package_info(params):
    package_path = params['package_path']
    app_name = params['app_name']

    package_type = get_package_type(package_path)

    if package_type == 'rpm':
        package_info = get_rpm_info(package_path)
    elif package_type == 'deb':
        package_info = get_deb_info(package_path)
    elif package_type == 'tgz':
        package_info = get_tgz_info(package_path)
    else:
        return helpers.ModuleRes(failed=True,
                                 msg='Unknown package type: %s' % package_type)

    if package_type != 'tgz' and package_info['name'] != app_name:
        msg = "Value 'cartridge_app_name' should be equal to package name. " + \
              "Found 'cartridge_app_name': '%s', package name: '%s'" % (app_name, package_info['name'])
        return helpers.ModuleRes(failed=True, msg=msg)

    package_info['type'] = package_type

    return helpers.ModuleRes(changed=False, fact=package_info)
def get_instances_to_configure(module_hostvars, play_hosts):
    instances = {}

    for instance_name in play_hosts:
        instance_vars = module_hostvars[instance_name]

        if helpers.is_stateboard(instance_vars):
            continue

        instance = {}

        if helpers.is_expelled(instance_vars):
            instance['expelled'] = True
        else:
            if 'zone' in instance_vars:
                instance['zone'] = instance_vars['zone']
            if 'config' in instance_vars:
                if 'advertise_uri' in instance_vars['config']:
                    instance['uri'] = instance_vars['config']['advertise_uri']

        if instance:
            instances[instance_name] = instance

    return instances