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
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
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
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)
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)
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)
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
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)
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
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)
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}
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)
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
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)
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
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)
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]
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)
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