def set_options(self): if self.vars.options is None: return actionable_snaps = [s for s in self.vars.name if self.is_snap_installed(s)] overall_options_changed = [] for snap_name in actionable_snaps: option_map = self.retrieve_option_map(snap_name=snap_name) options_changed = [] for option_string in self.vars.options: match = self.__set_param_re.match(option_string) if not match: msg = "Cannot parse set option '{option_string}'".format(option_string=option_string) raise ModuleHelperException(msg) snap_prefix = match.group("snap_prefix") selected_snap_name = snap_prefix[:-1] if snap_prefix else None if selected_snap_name is not None and selected_snap_name not in self.vars.name: msg = "Snap option '{option_string}' refers to snap which is not in the list of snap names".format(option_string=option_string) raise ModuleHelperException(msg) if selected_snap_name is None or (snap_name is not None and snap_name == selected_snap_name): key = match.group("key") value = match.group("value") if key not in option_map or key in option_map and option_map[key] != value: option_without_prefix = key + "=" + value option_with_prefix = option_string if selected_snap_name is not None else snap_name + ":" + option_string options_changed.append(option_without_prefix) overall_options_changed.append(option_with_prefix) if options_changed: self.changed = True if not self.module.check_mode: params = [{'state': 'set'}, {'name': snap_name}, {'options': options_changed}] rc, out, err = self.run_command(params=params) if rc != 0: if 'has no "configure" hook' in err: msg = "Snap '{snap}' does not have any configurable options".format(snap=snap_name) raise ModuleHelperException(msg) msg = "Cannot set options '{options}' for snap '{snap}': error={error}".format( options=" ".join(options_changed), snap=snap_name, error=err) raise ModuleHelperException(msg) if overall_options_changed: self.vars.options_changed = overall_options_changed
def __init_module__(self): v = self.vars if v.mode == "compatibility": if v.name_check: raise ModuleHelperException("Parameter name_check can only be used with mode=new") else: if v.name and v.from_path: raise ModuleHelperException("Parameters 'name' and 'from_path' are mutually exclusive when 'mode=new'") if v.system_lib: raise ModuleHelperException("Parameter 'system_lib' is invalid when 'mode=new'") self.command = self.module.get_bin_path(v.executable if v.executable else self.command) self.vars.set("binary", self.command)
def sanitize_pkg_spec_version(pkg_spec, version): if version is None: return pkg_spec if pkg_spec.endswith('.tar.gz'): raise ModuleHelperException(msg="parameter 'version' must not be used when installing from a file") if os.path.isdir(pkg_spec): raise ModuleHelperException(msg="parameter 'version' must not be used when installing from a directory") if pkg_spec.endswith('.git'): if version.startswith('~'): raise ModuleHelperException(msg="operator '~' not allowed in version parameter when installing from git repository") version = version if version.startswith('@') else '@' + version elif version[0] not in ('@', '~'): version = '~' + version return pkg_spec + version
def state_reinstall(self): if not self.vars.application: raise ModuleHelperException( "Trying to reinstall a non-existent application: {0}".format(self.vars.name)) self.changed = True if not self.module.check_mode: self.run_command(params=['state', 'name', 'python'])
def state_present(self): self.vars.meta('classic').set(output=True) self.vars.meta('channel').set(output=True) actionable_snaps = [s for s in self.vars.name if not self.is_snap_installed(s)] if not actionable_snaps: return self.changed = True self.vars.snaps_installed = actionable_snaps if self.module.check_mode: return params = ['state', 'classic', 'channel'] # get base cmd parts has_one_pkg_params = bool(self.vars.classic) or self.vars.channel != 'stable' has_multiple_snaps = len(actionable_snaps) > 1 if has_one_pkg_params and has_multiple_snaps: commands = [params + [{'actionable_snaps': [s]}] for s in actionable_snaps] else: commands = [params + [{'actionable_snaps': actionable_snaps}]] self.vars.cmd, rc, out, err = self._run_multiple_commands(commands) if rc == 0: return classic_snap_pattern = re.compile(r'^error: This revision of snap "(?P<package_name>\w+)"' r' was published using classic confinement') match = classic_snap_pattern.match(err) if match: err_pkg = match.group('package_name') msg = "Couldn't install {name} because it requires classic confinement".format(name=err_pkg) else: msg = "Ooops! Snap installation failed while executing '{cmd}', please examine logs and " \ "error output for more details.".format(cmd=self.vars.cmd) raise ModuleHelperException(msg=msg)
def state_inject(self): if not self.vars.application: raise ModuleHelperException( "Trying to inject packages into a non-existent application: {0}".format(self.vars.name)) if self.vars.force: self.changed = True if not self.module.check_mode: self.run_command(params=['state', 'index_url', 'force', 'name', 'inject_packages'])
def state_upgrade(self): if not self.vars.application: raise ModuleHelperException( "Trying to upgrade a non-existent application: {0}".format(self.vars.name)) if self.vars.force: self.changed = True if not self.module.check_mode: self.run_command(params=['state', 'index_url', 'install_deps', 'force', 'name'])
def __init_module__(self): self.does_not = 'Property "{0}" does not exist on channel "{1}".'.format(self.module.params['property'], self.module.params['channel']) self.vars.set('previous_value', self._get(), fact=True) self.vars.set('type', self.vars.value_type, fact=True) self.vars.meta('value').set(initial_value=self.vars.previous_value) if self.module.params['disable_facts'] is False: raise ModuleHelperException('Returning results as facts has been removed. Stop using disable_facts=false.')
def is_snap_enabled(self, snap_name): rc, out, err = self.run_command(params=[{'state': 'list'}, {'name': snap_name}]) if rc != 0: return None result = out.splitlines()[1] match = self.__disable_re.match(result) if not match: raise ModuleHelperException(msg="Unable to parse 'snap list {0}' output:\n{1}".format(snap_name, out)) notes = match.group('notes') return "disabled" not in notes.split(',')
def _generic_state_action(self, actionable_func, actionable_var, params=None): actionable_snaps = [s for s in self.vars.name if actionable_func(s)] if not actionable_snaps: return self.changed = True self.vars[actionable_var] = actionable_snaps if self.module.check_mode: return if params is None: params = ['state'] commands = [params + [{'actionable_snaps': actionable_snaps}]] self.vars.cmd, rc, out, err = self._run_multiple_commands(commands) if rc == 0: return msg = "Ooops! Snap operation failed while executing '{cmd}', please examine logs and " \ "error output for more details.".format(cmd=self.vars.cmd) raise ModuleHelperException(msg=msg)
def convert_json_subtree_to_map(self, json_subtree, prefix=None): option_map = {} if not isinstance(json_subtree, dict): raise ModuleHelperException("Non-dict non-leaf element encountered while parsing option map. " "The output format of 'snap set' may have changed. Aborting!") for key, value in json_subtree.items(): full_key = key if prefix is None else prefix + "." + key if isinstance(value, (str, float, bool, numbers.Integral)): option_map[full_key] = str(value) else: option_map.update(self.convert_json_subtree_to_map(json_subtree=value, prefix=full_key)) return option_map
def state_disabled(self): self.validate_input_snaps() actionable_snaps = [s for s in self.vars.name if self.is_snap_enabled(s) is True] if not actionable_snaps: return self.changed = True self.vars.snaps_enabled = actionable_snaps if self.module.check_mode: return params = ['classic', 'channel', 'state'] # get base cmd parts commands = [params + actionable_snaps] self.vars.cmd, rc, out, err = self._run_multiple_commands(commands) if rc == 0: return msg = "Ooops! Snap disabling failed while executing '{cmd}', please examine logs and " \ "error output for more details.".format(cmd=self.vars.cmd) raise ModuleHelperException(msg=msg)
def state_absent(self): self.validate_input_snaps( ) # if snap doesnt exist, it will be absent by definition actionable_snaps = [ s for s in self.vars.name if self.is_snap_installed(s) ] if not actionable_snaps: return self.changed = True self.vars.snaps_removed = actionable_snaps if self.module.check_mode: return params = ['classic', 'channel', 'state'] # get base cmd parts commands = [params + [{'actionable_snaps': actionable_snaps}]] self.vars.cmd, rc, out, err = self._run_multiple_commands(commands) if rc == 0: return msg = "Ooops! Snap removal failed while executing '{cmd}', please examine logs and " \ "error output for more details.".format(cmd=self.vars.cmd) raise ModuleHelperException(msg=msg)
def retrieve_option_map(self, snap_name): params = [{'state': 'get'}, {'name': snap_name}, {'json_format': True}] rc, out, err = self.run_command(params=params) if rc != 0: return {} result = out.splitlines() if "has no configuration" in result[0]: return {} try: option_map = self.convert_json_to_map(out) except Exception as e: raise ModuleHelperException( msg="Parsing option map returned by 'snap get {0}' triggers exception '{1}', output:\n'{2}'".format(snap_name, str(e), out)) return option_map
def process_command_output(self, rc, out, err): if rc != 0: raise ModuleHelperException("mksysb failed.") self.vars.msg = out
def process_command_output(self, rc, out, err): if self.vars.mode == "compatibility" and rc != 0: raise ModuleHelperException(msg=err, cmd=self.vars.cmd_args) return 'is up to date' not in err and 'is up to date' not in out
def validate_input_snaps(self): """Ensure that all exist.""" for snap_name in self.vars.name: if not self.snap_exists(snap_name): raise ModuleHelperException( msg="No snap matching '%s' available." % snap_name)
def __init_module__(self): if not os.path.isdir(self.vars.storage_path): raise ModuleHelperException("Storage path %s is not valid." % self.vars.storage_path)