def build_command(module, mode, path, follow, default, recursive, entry=''): '''Builds and returns a getfacl/setfacl command.''' if mode == 'set': cmd = [module.get_bin_path('setfacl', True)] cmd.append('-m "%s"' % entry) elif mode == 'rm': cmd = [module.get_bin_path('setfacl', True)] cmd.append('-x "%s"' % entry) else: # mode == 'get' cmd = [module.get_bin_path('getfacl', True)] # prevents absolute path warnings and removes headers if get_platform().lower() == 'linux': cmd.append('--omit-header') cmd.append('--absolute-names') if recursive: cmd.append('--recursive') if not follow: if get_platform().lower() == 'linux': cmd.append('--physical') elif get_platform().lower() == 'freebsd': cmd.append('-h') if default: cmd.insert(1, '-d') cmd.append(path) return cmd
def build_command(module, mode, path, follow, default, recursive, entry=''): '''Builds and returns a getfacl/setfacl command.''' if mode == 'set': cmd = [module.get_bin_path('setfacl', True)] cmd.append('-m "%s"' % entry) elif mode == 'rm': cmd = [module.get_bin_path('setfacl', True)] cmd.append('-x "%s"' % entry) else: # mode == 'get' cmd = [module.get_bin_path('getfacl', True)] # prevents absolute path warnings and removes headers if get_platform().lower() == 'linux': cmd.append('--omit-header') cmd.append('--absolute-names') if recursive: cmd.append('--recursive') if not follow: if get_platform().lower() == 'linux': cmd.append('--physical') elif get_platform().lower() == 'freebsd': cmd.append('-h') if default: if(mode == 'rm'): cmd.insert(1, '-k') else: # mode == 'set' or mode == 'get' cmd.insert(1, '-d') cmd.append(path) return cmd
def unset_mount(module, args): """Remove a mount point from fstab.""" to_write = [] changed = False escaped_name = _escape_fstab(args['name']) for line in open(args['fstab'], 'r').readlines(): if not line.strip(): to_write.append(line) continue if line.strip().startswith('#'): to_write.append(line) continue # Check if we got a valid line for splitting if ( get_platform() == 'SunOS' and len(line.split()) != 7 or get_platform() != 'SunOS' and len(line.split()) != 6): to_write.append(line) continue ld = {} if get_platform() == 'SunOS': ( ld['src'], dash, ld['name'], ld['fstype'], ld['passno'], ld['boot'], ld['opts'] ) = line.split() else: ( ld['src'], ld['name'], ld['fstype'], ld['opts'], ld['dump'], ld['passno'] ) = line.split() if ld['name'] != escaped_name: to_write.append(line) continue # If we got here we found a match - continue and mark changed changed = True if changed and not module.check_mode: write_fstab(to_write, args['fstab']) return (args['name'], changed)
def main(): module = AnsibleModule(argument_spec=dict( msg=dict(required=True), voice=dict(required=False), ), supports_check_mode=True) msg = module.params['msg'] voice = module.params['voice'] executable = module.get_bin_path('say') if not executable: executable = module.get_bin_path('espeak') elif get_platform() != 'Darwin': # 'say' binary available, it might be GNUstep tool which doesn't support 'voice' parameter voice = None module.warn( "'say' executable found but system is '%s': ignoring voice parameter" % get_platform()) if not executable: module.fail_json( msg="Unable to find either 'say' or 'espeak' executable") if module.check_mode: module.exit_json(msg=msg, changed=False) say(module, executable, msg, voice) module.exit_json(msg=msg, changed=True)
def unset_mount(module, args): """Remove a mount point from fstab.""" to_write = [] changed = False escaped_name = _escape_fstab(args['name']) for line in open(args['fstab'], 'r').readlines(): if not line.strip(): to_write.append(line) continue if line.strip().startswith('#'): to_write.append(line) continue # Check if we got a valid line for splitting if ( get_platform() == 'SunOS' and len(line.split()) != 7 or get_platform() != 'SunOS' and len(line.split()) != 6): to_write.append(line) continue ld = {} if get_platform() == 'SunOS': ( ld['src'], dash, ld['name'], ld['fstype'], ld['passno'], ld['boot'], ld['opts'] ) = line.split() else: ( ld['src'], ld['name'], ld['fstype'], ld['opts'], ld['dump'], ld['passno'] ) = line.split() if ld['name'] != escaped_name: to_write.append(line) continue # If we got here we found a match - continue and mark changed changed = True if changed and not module.check_mode: write_fstab(module, to_write, args['fstab']) return (args['name'], changed)
def _set_fstab_args(fstab_file): result = [] if (fstab_file and fstab_file != '/etc/fstab' and get_platform().lower() != 'sunos'): if get_platform().lower().endswith('bsd'): result.append('-F') else: result.append('-T') result.append(fstab_file) return result
def _set_fstab_args(fstab_file): result = [] if ( fstab_file and fstab_file != '/etc/fstab' and get_platform().lower() != 'sunos'): if get_platform().lower().endswith('bsd'): result.append('-F') else: result.append('-T') result.append(fstab_file) return result
def remount(module, args): """Try to use 'remount' first and fallback to (u)mount if unsupported.""" mount_bin = module.get_bin_path('mount', required=True) cmd = [mount_bin] # Multiplatform remount opts if get_platform().lower().endswith('bsd'): cmd += ['-u'] else: cmd += ['-o', 'remount'] if get_platform().lower() == 'openbsd': # Use module.params['fstab'] here as args['fstab'] has been set to the # default value. if module.params['fstab'] is not None: module.fail_json( msg=( 'OpenBSD does not support alternate fstab files. Do not ' 'specify the fstab parameter for OpenBSD hosts')) else: cmd += _set_fstab_args(args['fstab']) cmd += [args['name']] out = err = '' try: if get_platform().lower().endswith('bsd'): # Note: Forcing BSDs to do umount/mount due to BSD remount not # working as expected (suspect bug in the BSD mount command) # Interested contributor could rework this to use mount options on # the CLI instead of relying on fstab # https://github.com/ansible/ansible-modules-core/issues/5591 rc = 1 else: rc, out, err = module.run_command(cmd) except: rc = 1 msg = '' if rc != 0: msg = out + err rc, msg = umount(module, args['name']) if rc == 0: rc, msg = mount(module, args) return rc, msg
def is_bind_mounted(module, dest, src=None, fstype=None): """Return whether the dest is bind mounted :arg module: The AnsibleModule (used for helper functions) :arg dest: The directory to be mounted under. This is the primary means of identifying whether the destination is mounted. :kwarg src: The source directory. If specified, this is used to help ensure that we are detecting that the correct source is mounted there. :kwarg fstype: The filesystem type. If specified this is also used to help ensure that we are detecting the right mount. :returns: True if the dest is mounted with src otherwise False. """ is_mounted = False bin_path = module.get_bin_path('mount', required=True) cmd = '%s -l' % bin_path if get_platform().lower() == 'linux': bin_path = module.get_bin_path('findmnt', required=True) cmd = '%s -nr %s' % (bin_path, dest) rc, out, err = module.run_command(cmd) mounts = [] if len(out): mounts = out.strip().split('\n') mount_pattern = re.compile('\[(.*)\]') for mnt in mounts: arguments = mnt.split() if get_platform().lower() == 'linux': result = mount_pattern.search(arguments[1]) if len(result.groups()) == 1: if arguments[0] == dest: is_mounted = True elif ( (arguments[0] == src or src is None) and arguments[2] == dest and (arguments[4] == fstype or fstype is None)): is_mounted = True if is_mounted: break return is_mounted
def main(): module = AnsibleModule( argument_spec=dict( msg=dict(required=True), voice=dict(required=False), ), supports_check_mode=True ) msg = module.params['msg'] voice = module.params['voice'] executable = module.get_bin_path('say') if not executable: executable = module.get_bin_path('espeak') elif get_platform() != 'Darwin': # 'say' binary available, it might be GNUstep tool which doesn't support 'voice' parameter voice = None module.warn("'say' executable found but system is '%s': ignoring voice parameter" % get_platform()) if not executable: module.fail_json(msg="Unable to find either 'say' or 'espeak' executable") if module.check_mode: module.exit_json(msg=msg, changed=False) say(module, executable, msg, voice) module.exit_json(msg=msg, changed=True)
def mount(module, args): """Mount up a path or remount if needed.""" mount_bin = module.get_bin_path('mount', required=True) name = args['name'] cmd = [mount_bin] if ismount(name): return remount(module, mount_bin, args) if get_platform().lower() == 'openbsd': # Use module.params['fstab'] here as args['fstab'] has been set to the # default value. if module.params['fstab'] is not None: module.fail_json(msg='OpenBSD does not support alternate fstab files. Do not specify the fstab parameter for OpenBSD hosts') else: cmd += _set_fstab_args(args['fstab']) cmd += [name] rc, out, err = module.run_command(cmd) if rc == 0: return 0, '' else: return rc, out+err
def get_matching_jobs(module, at_cmd, script_file): matching_jobs = [] atq_cmd = module.get_bin_path('atq', True) # Get list of job numbers for the user. atq_command = "%s" % atq_cmd rc, out, err = module.run_command(atq_command, check_rc=True) current_jobs = out.splitlines() if len(current_jobs) == 0: return matching_jobs # Read script_file into a string. with open(script_file) as script_fh: script_file_string = script_fh.read().strip() # Loop through the jobs. # If the script text is contained in a job add job number to list. for current_job in current_jobs: split_current_job = current_job.split() if get_platform() == 'AIX': at_command = "%s -lv %s" % (at_cmd, split_current_job[0]) else: at_command = "%s -c %s" % (at_cmd, split_current_job[0]) rc, out, err = module.run_command(at_command, check_rc=True) if script_file_string in out: matching_jobs.append(split_current_job[0]) # Return the list. return matching_jobs
def remount(module, mount_bin, args): ''' will try to use -o remount first and fallback to unmount/mount if unsupported''' msg = '' cmd = [mount_bin] # multiplatform remount opts if get_platform().lower().endswith('bsd'): cmd += ['-u'] else: cmd += ['-o', 'remount'] cmd += _set_fstab_args(args) cmd += [ args['name'], ] try: rc, out, err = module.run_command(cmd) except: rc = 1 if rc != 0: msg = out + err if ismount(args['name']): rc, msg = umount(module, args['name']) if rc == 0: rc, msg = mount(module, args) return rc, msg
def mount(module, args): """Mount up a path or remount if needed.""" mount_bin = module.get_bin_path('mount', required=True) name = args['name'] cmd = [mount_bin] if get_platform().lower() == 'openbsd': # Use module.params['fstab'] here as args['fstab'] has been set to the # default value. if module.params['fstab'] is not None: module.fail_json( msg=('OpenBSD does not support alternate fstab files. Do not ' 'specify the fstab parameter for OpenBSD hosts')) else: cmd += _set_fstab_args(args['fstab']) cmd += [name] rc, out, err = module.run_command(cmd) if rc == 0: return 0, '' else: return rc, out + err
def main(): module = AnsibleModule(argument_spec=dict( msg=dict(required=True), voice=dict(required=False), ), supports_check_mode=True) msg = module.params['msg'] voice = module.params['voice'] possibles = ('say', 'espeak', 'espeak-ng') if get_platform() != 'Darwin': # 'say' binary available, it might be GNUstep tool which doesn't support 'voice' parameter voice = None for possible in possibles: executable = module.get_bin_path(possible) if executable: break else: module.fail_json(msg='Unable to find either %s' % ', '.join(possibles)) if module.check_mode: module.exit_json(msg=msg, changed=False) say(module, executable, msg, voice) module.exit_json(msg=msg, changed=True)
def __new__(cls, module): """Return the platform-specific subclass. It does not use load_platform_subclass() because it needs to judge based on whether the `timedatectl` command exists and is available. Args: module: The AnsibleModule. """ if get_platform() == 'Linux': timedatectl = module.get_bin_path('timedatectl') if timedatectl is not None and module.run_command(timedatectl)[0] == 0: return super(Timezone, SystemdTimezone).__new__(SystemdTimezone) else: return super(Timezone, NosystemdTimezone).__new__(NosystemdTimezone) elif re.match('^joyent_.*Z', platform.version()): # get_platform() returns SunOS, which is too broad. So look at the # platform version instead. However we have to ensure that we're not # running in the global zone where changing the timezone has no effect. zonename_cmd = module.get_bin_path('zonename') if zonename_cmd is not None: (rc, stdout, _ ) = module.run_command(zonename_cmd) if rc == 0 and stdout.strip() == 'global': module.fail_json(msg='Adjusting timezone is not supported in Global Zone') return super(Timezone, SmartOSTimezone).__new__(SmartOSTimezone) elif re.match('^(Free|Net|Open)BSD', platform.platform()): return super(Timezone, BSDTimezone).__new__(BSDTimezone) else: # Not supported yet return super(Timezone, Timezone).__new__(Timezone)
def main(): module = AnsibleModule(argument_spec=dict(), ) p = get_platform() if p in FW_VTABLE: f = FW_VTABLE[p](module) module.exit_json(changed=False, ansible_facts={'firewall': f}) else: module.fail_json()
def process(self): self.platform = get_platform().lower() # Whitespace is bad self.args['name'] = self.args['name'].strip() self.args['value'] = self._parse_value(self.args['value']) thisname = self.args['name'] # get the current proc fs value self.proc_value = self.get_token_curr_value(thisname) # get the currect sysctl file value self.read_sysctl_file() if thisname not in self.file_values: self.file_values[thisname] = None # update file contents with desired token/value self.fix_lines() # what do we need to do now? if self.file_values[thisname] is None and self.args['state'] == "present": self.changed = True self.write_file = True elif self.file_values[thisname] is None and self.args['state'] == "absent": self.changed = False elif self.file_values[thisname] and self.args['state'] == "absent": self.changed = True self.write_file = True elif self.file_values[thisname] != self.args['value']: self.changed = True self.write_file = True # with reload=yes we should check if the current system values are # correct, so that we know if we should reload elif self.args['reload']: if self.proc_value is None: self.changed = True elif not self._values_is_equal(self.proc_value, self.args['value']): self.changed = True # use the sysctl command or not? if self.args['sysctl_set'] and self.args['state'] == "present": if self.proc_value is None: self.changed = True elif not self._values_is_equal(self.proc_value, self.args['value']): self.changed = True self.set_proc = True # Do the work if not self.module.check_mode: if self.write_file: self.write_sysctl() if self.changed and self.args['reload']: self.reload_sysctl() if self.set_proc: self.set_token_value(self.args['name'], self.args['value'])
def unimplemented_error(self): platform = get_platform() distribution = get_distribution() if distribution is not None: msg_platform = '%s (%s)' % (platform, distribution) else: msg_platform = platform self.module.fail_json( msg='hostname module cannot be used on platform %s' % msg_platform)
def _set_fstab_args(args): result = [] if 'fstab' in args and args['fstab'] != '/etc/fstab': if get_platform().lower().endswith('bsd'): result.append('-F') else: result.append('-T') result.append(args['fstab']) return result
def mount(module, **kwargs): """Mount up a path or remount if needed.""" # solaris kwargs: # name, src, fstype, opts, boot, passno, state, fstab=/etc/vfstab # linux kwargs: # name, src, fstype, opts, dump, passno, state, fstab=/etc/fstab if get_platform() == 'SunOS': args = dict( opts='-', passno='-', fstab='/etc/vfstab', boot='yes' ) else: args = dict( opts='default', dump='0', passno='0', fstab='/etc/fstab' ) args.update(kwargs) mount_bin = module.get_bin_path('mount', required=True) name = kwargs['name'] cmd = [mount_bin] if ismount(name): cmd += ['-o', 'remount'] if get_platform().lower() == 'freebsd': cmd += ['-F', args['fstab']] elif get_platform().lower() == 'linux' and args['fstab'] != '/etc/fstab': cmd += ['-T', args['fstab']] cmd += [name] rc, out, err = module.run_command(cmd) if rc == 0: return 0, '' else: return rc, out+err
def is_bind_mounted(module, linux_mounts, dest, src=None, fstype=None): """Return whether the dest is bind mounted :arg module: The AnsibleModule (used for helper functions) :arg dest: The directory to be mounted under. This is the primary means of identifying whether the destination is mounted. :kwarg src: The source directory. If specified, this is used to help ensure that we are detecting that the correct source is mounted there. :kwarg fstype: The filesystem type. If specified this is also used to help ensure that we are detecting the right mount. :kwarg linux_mounts: Cached list of mounts for Linux. :returns: True if the dest is mounted with src otherwise False. """ is_mounted = False if get_platform() == 'Linux' and linux_mounts is not None: if src is None: # That's for unmounted/absent for m in linux_mounts: if m['dst'] == dest: is_mounted = True else: mounted_src = None for m in linux_mounts: if m['dst'] == dest: mounted_src = m['src'] # That's for mounted if mounted_src is not None and mounted_src == src: is_mounted = True else: bin_path = module.get_bin_path('mount', required=True) cmd = '%s -l' % bin_path rc, out, err = module.run_command(cmd) mounts = [] if len(out): mounts = to_native(out).strip().split('\n') for mnt in mounts: arguments = mnt.split() if ( (arguments[0] == src or src is None) and arguments[2] == dest and (arguments[4] == fstype or fstype is None)): is_mounted = True if is_mounted: break return is_mounted
def delete_job(module, result, at_cmd, command, script_file): for matching_job in get_matching_jobs(module, at_cmd, script_file): if get_platform() == 'AIX': at_command = "%s -r %s" % (at_cmd, matching_job) else: at_command = "%s -d %s" % (at_cmd, matching_job) rc, out, err = module.run_command(at_command, check_rc=True) result['changed'] = True if command: os.unlink(script_file) module.exit_json(**result)
def build_command(module, mode, path, follow, default, recursive, recalculate_mask, entry=''): '''Builds and returns a getfacl/setfacl command.''' if mode == 'set': cmd = [module.get_bin_path('setfacl', True)] cmd.extend(['-m', entry]) elif mode == 'rm': cmd = [module.get_bin_path('setfacl', True)] cmd.extend(['-x', entry]) else: # mode == 'get' cmd = [module.get_bin_path('getfacl', True)] # prevents absolute path warnings and removes headers if get_platform().lower() == 'linux': cmd.append('--omit-header') cmd.append('--absolute-names') if recursive: cmd.append('--recursive') if recalculate_mask == 'mask' and mode in ['set', 'rm']: cmd.append('--mask') elif recalculate_mask == 'no_mask' and mode in ['set', 'rm']: cmd.append('--no-mask') if not follow: if get_platform().lower() == 'linux': cmd.append('--physical') elif get_platform().lower() == 'freebsd': cmd.append('-h') if default: cmd.insert(1, '-d') cmd.append(path) return cmd
def acl_changed(module, cmd): '''Returns true if the provided command affects the existing ACLs, false otherwise.''' # FreeBSD do not have a --test flag, so by default, it is safer to always say "true" if get_platform().lower() == 'freebsd': return True cmd = cmd[:] # lists are mutables so cmd would be overwritten without this cmd.insert(1, '--test') lines = run_acl(module, cmd) for line in lines: if not line.endswith('*,*'): return True return False
def remount(module, mount_bin, args): ''' will try to use -o remount first and fallback to unmount/mount if unsupported''' msg = '' cmd = [mount_bin] # multiplatform remount opts if get_platform().lower().endswith('bsd'): cmd += ['-u'] else: cmd += ['-o', 'remount'] cmd += _set_fstab_args(args) cmd += [ args['name'], ] out = err = '' try: if get_platform().lower().endswith('bsd'): # Note: Forcing BSDs to do umount/mount due to BSD remount not # working as expected (suspect bug in the BSD mount command) # Interested contributor could rework this to use mount options on # the CLI instead of relying on fstab # https://github.com/ansible/ansible-modules-core/issues/5591 rc = 1 else: rc, out, err = module.run_command(cmd) except: rc = 1 if rc != 0: msg = out + err if ismount(args['name']): rc, msg = umount(module, args['name']) if rc == 0: rc, msg = mount(module, args) return rc, msg
def mount(module, args): """Mount up a path or remount if needed.""" mount_bin = module.get_bin_path('mount', required=True) name = args['name'] cmd = [mount_bin] if ismount(name): cmd += ['-o', 'remount'] if args['fstab'] != '/etc/fstab': if get_platform() == 'FreeBSD': cmd += ['-F', args['fstab']] elif get_platform() == 'Linux': cmd += ['-T', args['fstab']] cmd += [name] rc, out, err = module.run_command(cmd) if rc == 0: return 0, '' else: return rc, out+err
def mount(module, args): """Mount up a path or remount if needed.""" mount_bin = module.get_bin_path('mount', required=True) name = args['name'] cmd = [mount_bin] if ismount(name): cmd += ['-o', 'remount'] if args['fstab'] != '/etc/fstab': if get_platform() == 'FreeBSD': cmd += ['-F', args['fstab']] elif get_platform() == 'Linux': cmd += ['-T', args['fstab']] cmd += [name] rc, out, err = module.run_command(cmd) if rc == 0: return 0, '' else: return rc, out + err
def is_bind_mounted(module, linux_mounts, dest, src=None, fstype=None): """Return whether the dest is bind mounted :arg module: The AnsibleModule (used for helper functions) :arg dest: The directory to be mounted under. This is the primary means of identifying whether the destination is mounted. :kwarg src: The source directory. If specified, this is used to help ensure that we are detecting that the correct source is mounted there. :kwarg fstype: The filesystem type. If specified this is also used to help ensure that we are detecting the right mount. :kwarg linux_mounts: Cached list of mounts for Linux. :returns: True if the dest is mounted with src otherwise False. """ is_mounted = False if get_platform() == 'Linux' and linux_mounts is not None: if src is None: # That's for unmounted/absent if dest in linux_mounts: is_mounted = True else: # That's for mounted if dest in linux_mounts and linux_mounts[dest]['src'] == src: is_mounted = True else: bin_path = module.get_bin_path('mount', required=True) cmd = '%s -l' % bin_path rc, out, err = module.run_command(cmd) mounts = [] if len(out): mounts = to_native(out).strip().split('\n') for mnt in mounts: arguments = mnt.split() if ( (arguments[0] == src or src is None) and arguments[2] == dest and (arguments[4] == fstype or fstype is None)): is_mounted = True if is_mounted: break return is_mounted
def process(self): self.platform = get_platform().lower() # Whitespace is bad self.args['name'] = self.args['name'].strip() self.args['value'] = self._parse_value(self.args['value']) thisname = self.args['name'] # get the current proc fs value self.proc_value = self.get_token_curr_value(thisname) # get the currect sysctl file value self.read_sysctl_file() if thisname not in self.file_values: self.file_values[thisname] = None # update file contents with desired token/value self.fix_lines() # what do we need to do now? if self.file_values[thisname] is None and self.args['state'] == "present": self.changed = True self.write_file = True elif self.file_values[thisname] is None and self.args['state'] == "absent": self.changed = False elif self.file_values[thisname] != self.args['value']: self.changed = True self.write_file = True # use the sysctl command or not? if self.args['sysctl_set']: if self.proc_value is None: self.changed = True elif not self._values_is_equal(self.proc_value, self.args['value']): self.changed = True self.set_proc = True # Do the work if not self.module.check_mode: if self.write_file: self.write_sysctl() if self.write_file and self.args['reload']: self.reload_sysctl() if self.set_proc: self.set_token_value(self.args['name'], self.args['value'])
def __new__(cls, module): """Return the platform-specific subclass. It does not use load_platform_subclass() because it need to judge based on whether the `timedatectl` command exists. Args: module: The AnsibleModule. """ if get_platform() == 'Linux': if module.get_bin_path('timedatectl') is not None: return super(Timezone, SystemdTimezone).__new__(SystemdTimezone) else: return super(Timezone, NosystemdTimezone).__new__(NosystemdTimezone) else: # Not supported yet return super(Timezone, Timezone).__new__(Timezone)
class VFAT(Filesystem): if get_platform() == 'FreeBSD': MKFS = "newfs_msdos" else: MKFS = 'mkfs.vfat' GROW = 'fatresize' def get_fs_size(self, dev): cmd = self.module.get_bin_path(self.GROW, required=True) _, output, _ = self.module.run_command([cmd, '--info', str(dev)], check_rc=True) for line in output.splitlines()[1:]: param, value = line.split(':', 1) if param.strip() == 'Size': return int(value.strip()) self.module.fail_json(msg="fatresize failed to provide filesystem size for %s" % dev) def grow_cmd(self, dev): cmd = self.module.get_bin_path(self.GROW) return [cmd, "-s", str(dev.size()), str(dev.path)]
def __new__(cls, module): """Return the platform-specific subclass. It does not use load_platform_subclass() because it needs to judge based on whether the `timedatectl` command exists and is available. Args: module: The AnsibleModule. """ if get_platform() == 'Linux': timedatectl = module.get_bin_path('timedatectl') if timedatectl is not None: rc, stdout, stderr = module.run_command(timedatectl) if rc == 0: return super(Timezone, SystemdTimezone).__new__(SystemdTimezone) else: module.warn('timedatectl command was found but not usable: %s. using other method.' % stderr) return super(Timezone, NosystemdTimezone).__new__(NosystemdTimezone) else: return super(Timezone, NosystemdTimezone).__new__(NosystemdTimezone) elif re.match('^joyent_.*Z', platform.version()): # get_platform() returns SunOS, which is too broad. So look at the # platform version instead. However we have to ensure that we're not # running in the global zone where changing the timezone has no effect. zonename_cmd = module.get_bin_path('zonename') if zonename_cmd is not None: (rc, stdout, _) = module.run_command(zonename_cmd) if rc == 0 and stdout.strip() == 'global': module.fail_json(msg='Adjusting timezone is not supported in Global Zone') return super(Timezone, SmartOSTimezone).__new__(SmartOSTimezone) elif re.match('^Darwin', platform.platform()): return super(Timezone, DarwinTimezone).__new__(DarwinTimezone) elif re.match('^(Free|Net|Open)BSD', platform.platform()): return super(Timezone, BSDTimezone).__new__(BSDTimezone) else: # Not supported yet return super(Timezone, Timezone).__new__(Timezone)
def main(): # The following example playbooks: # # - cron: name="check dirs" hour="5,2" job="ls -alh > /dev/null" # # - name: do the job # cron: name="do the job" hour="5,2" job="/some/dir/job.sh" # # - name: no job # cron: name="an old job" state=absent # # - name: sets env # cron: name="PATH" env=yes value="/bin:/usr/bin" # # Would produce: # PATH=/bin:/usr/bin # # Ansible: check dirs # * * 5,2 * * ls -alh > /dev/null # # Ansible: do the job # * * 5,2 * * /some/dir/job.sh module = AnsibleModule( argument_spec=dict( name=dict(type='str'), user=dict(type='str'), job=dict(type='str', aliases=['value']), cron_file=dict(type='str'), state=dict(type='str', default='present', choices=['present', 'absent']), backup=dict(type='bool', default=False), minute=dict(type='str', default='*'), hour=dict(type='str', default='*'), day=dict(type='str', default='*', aliases=['dom']), month=dict(type='str', default='*'), weekday=dict(type='str', default='*', aliases=['dow']), reboot=dict(type='bool', default=False), special_time=dict(type='str', choices=["reboot", "yearly", "annually", "monthly", "weekly", "daily", "hourly"]), disabled=dict(type='bool', default=False), env=dict(type='bool'), insertafter=dict(type='str'), insertbefore=dict(type='str'), ), supports_check_mode=True, mutually_exclusive=[ ['reboot', 'special_time'], ['insertafter', 'insertbefore'], ], ) name = module.params['name'] user = module.params['user'] job = module.params['job'] cron_file = module.params['cron_file'] state = module.params['state'] backup = module.params['backup'] minute = module.params['minute'] hour = module.params['hour'] day = module.params['day'] month = module.params['month'] weekday = module.params['weekday'] reboot = module.params['reboot'] special_time = module.params['special_time'] disabled = module.params['disabled'] env = module.params['env'] insertafter = module.params['insertafter'] insertbefore = module.params['insertbefore'] do_install = state == 'present' changed = False res_args = dict() warnings = list() if cron_file: cron_file_basename = os.path.basename(cron_file) if not re.search(r'^[A-Z0-9_-]+$', cron_file_basename, re.I): warnings.append('Filename portion of cron_file ("%s") should consist' % cron_file_basename + ' solely of upper- and lower-case letters, digits, underscores, and hyphens') # Ensure all files generated are only writable by the owning user. Primarily relevant for the cron_file option. os.umask(int('022', 8)) crontab = CronTab(module, user, cron_file) module.debug('cron instantiated - name: "%s"' % name) if module._diff: diff = dict() diff['before'] = crontab.existing if crontab.cron_file: diff['before_header'] = crontab.cron_file else: if crontab.user: diff['before_header'] = 'crontab for user "%s"' % crontab.user else: diff['before_header'] = 'crontab' # --- user input validation --- if (special_time or reboot) and \ (True in [(x != '*') for x in [minute, hour, day, month, weekday]]): module.fail_json(msg="You must specify time and date fields or special time.") # cannot support special_time on solaris if (special_time or reboot) and get_platform() == 'SunOS': module.fail_json(msg="Solaris does not support special_time=... or @reboot") if cron_file and do_install: if not user: module.fail_json(msg="To use cron_file=... parameter you must specify user=... as well") if job is None and do_install: module.fail_json(msg="You must specify 'job' to install a new cron job or variable") if (insertafter or insertbefore) and not env and do_install: module.fail_json(msg="Insertafter and insertbefore parameters are valid only with env=yes") if reboot: special_time = "reboot" # if requested make a backup before making a change if backup and not module.check_mode: (backuph, backup_file) = tempfile.mkstemp(prefix='crontab') crontab.write(backup_file) if crontab.cron_file and not name and not do_install: if module._diff: diff['after'] = '' diff['after_header'] = '/dev/null' else: diff = dict() if module.check_mode: changed = os.path.isfile(crontab.cron_file) else: changed = crontab.remove_job_file() module.exit_json(changed=changed, cron_file=cron_file, state=state, diff=diff) if env: if ' ' in name: module.fail_json(msg="Invalid name for environment variable") decl = '%s="%s"' % (name, job) old_decl = crontab.find_env(name) if do_install: if len(old_decl) == 0: crontab.add_env(decl, insertafter, insertbefore) changed = True if len(old_decl) > 0 and old_decl[1] != decl: crontab.update_env(name, decl) changed = True else: if len(old_decl) > 0: crontab.remove_env(name) changed = True else: if do_install: for char in ['\r', '\n']: if char in job.strip('\r\n'): warnings.append('Job should not contain line breaks') break job = crontab.get_cron_job(minute, hour, day, month, weekday, job, special_time, disabled) old_job = crontab.find_job(name, job) if len(old_job) == 0: crontab.add_job(name, job) changed = True if len(old_job) > 0 and old_job[1] != job: crontab.update_job(name, job) changed = True if len(old_job) > 2: crontab.update_job(name, job) changed = True else: old_job = crontab.find_job(name) if len(old_job) > 0: crontab.remove_job(name) changed = True # no changes to env/job, but existing crontab needs a terminating newline if not changed and not crontab.existing == '': if not (crontab.existing.endswith('\r') or crontab.existing.endswith('\n')): changed = True res_args = dict( jobs=crontab.get_jobnames(), envs=crontab.get_envnames(), warnings=warnings, changed=changed ) if changed: if not module.check_mode: crontab.write() if module._diff: diff['after'] = crontab.render() if crontab.cron_file: diff['after_header'] = crontab.cron_file else: if crontab.user: diff['after_header'] = 'crontab for user "%s"' % crontab.user else: diff['after_header'] = 'crontab' res_args['diff'] = diff # retain the backup only if crontab or cron file have changed if backup and not module.check_mode: if changed: res_args['backup_file'] = backup_file else: os.unlink(backup_file) if cron_file: res_args['cron_file'] = cron_file module.exit_json(**res_args) # --- should never get here module.exit_json(msg="Unable to execute cron task.")
def test_module_utils_basic_get_platform(self): with patch('platform.system', return_value='foo'): from ansible.module_utils.basic import get_platform self.assertEqual(get_platform(), 'foo')
def main(): module = AnsibleModule( argument_spec=dict(path=dict(type='path', required=True, aliases=['name']), entry=dict(type='str'), entity=dict(type='str', default=''), etype=dict( type='str', choices=['group', 'mask', 'other', 'user'], ), permissions=dict(type='str'), state=dict( type='str', default='query', choices=['absent', 'present', 'query'], ), follow=dict(type='bool', default=True), default=dict(type='bool', default=False), recursive=dict(type='bool', default=False), recalculate_mask=dict( type='str', default='default', choices=['default', 'mask', 'no_mask'], ), use_nfsv4_acls=dict(type='bool', default=False)), supports_check_mode=True, ) if get_platform().lower() not in ['linux', 'freebsd']: module.fail_json(msg="The acl module is not available on this system.") path = module.params.get('path') entry = module.params.get('entry') entity = module.params.get('entity') etype = module.params.get('etype') permissions = module.params.get('permissions') state = module.params.get('state') follow = module.params.get('follow') default = module.params.get('default') recursive = module.params.get('recursive') recalculate_mask = module.params.get('recalculate_mask') use_nfsv4_acls = module.params.get('use_nfsv4_acls') if not os.path.exists(path): module.fail_json(msg="Path not found or not accessible.") if state == 'query': if recursive: module.fail_json( msg="'recursive' MUST NOT be set when 'state=query'.") if recalculate_mask in ['mask', 'no_mask']: module.fail_json( msg= "'recalculate_mask' MUST NOT be set to 'mask' or 'no_mask' when 'state=query'." ) if not entry: if state == 'absent' and permissions: module.fail_json( msg="'permissions' MUST NOT be set when 'state=absent'.") if state == 'absent' and not entity: module.fail_json(msg="'entity' MUST be set when 'state=absent'.") if state in ['present', 'absent'] and not etype: module.fail_json(msg="'etype' MUST be set when 'state=%s'." % state) if entry: if etype or entity or permissions: module.fail_json( msg= "'entry' MUST NOT be set when 'entity', 'etype' or 'permissions' are set." ) if state == 'present' and not entry.count(":") in [2, 3]: module.fail_json( msg= "'entry' MUST have 3 or 4 sections divided by ':' when 'state=present'." ) if state == 'absent' and not entry.count(":") in [1, 2]: module.fail_json( msg= "'entry' MUST have 2 or 3 sections divided by ':' when 'state=absent'." ) if state == 'query': module.fail_json(msg="'entry' MUST NOT be set when 'state=query'.") default_flag, etype, entity, permissions = split_entry(entry) if default_flag is not None: default = default_flag if get_platform().lower() == 'freebsd': if recursive: module.fail_json( msg="recursive is not supported on that platform.") changed = False msg = "" if state == 'present': entry = build_entry(etype, entity, permissions, use_nfsv4_acls) command = build_command(module, 'set', path, follow, default, recursive, recalculate_mask, entry) changed = acl_changed(module, command) if changed and not module.check_mode: run_acl(module, command) msg = "%s is present" % entry elif state == 'absent': entry = build_entry(etype, entity, use_nfsv4_acls) command = build_command(module, 'rm', path, follow, default, recursive, recalculate_mask, entry) changed = acl_changed(module, command) if changed and not module.check_mode: run_acl(module, command, False) msg = "%s is absent" % entry elif state == 'query': msg = "current acl" acl = run_acl( module, build_command(module, 'get', path, follow, default, recursive, recalculate_mask)) module.exit_json(changed=changed, msg=msg, acl=acl)
def test_get_platform(): with patch('platform.system', return_value='foo'): assert get_platform() == 'foo'
def main(): module = AnsibleModule(argument_spec=dict( boot=dict(default='yes', choices=['yes', 'no']), dump=dict(), fstab=dict(default='/etc/fstab'), fstype=dict(), name=dict(required=True, type='path'), opts=dict(), passno=dict(type='str'), src=dict(type='path'), state=dict(required=True, choices=['present', 'absent', 'mounted', 'unmounted']), ), supports_check_mode=True, required_if=([ 'state', 'mounted', ['src', 'fstype'] ], ['state', 'present', ['src', 'fstype']])) changed = False # solaris args: # name, src, fstype, opts, boot, passno, state, fstab=/etc/vfstab # linux args: # name, src, fstype, opts, dump, passno, state, fstab=/etc/fstab if get_platform() == 'SunOS': args = dict(name=module.params['name'], opts='-', passno='-', fstab='/etc/vfstab', boot='yes') else: args = dict(name=module.params['name'], opts='defaults', dump='0', passno='0', fstab='/etc/fstab') # FreeBSD doesn't have any 'default' so set 'rw' instead if get_platform() == 'FreeBSD': args['opts'] = 'rw' linux_mounts = [] # Cache all mounts here in order we have consistent results if we need to # call is_bind_mouted() multiple times if get_platform() == 'Linux': linux_mounts = get_linux_mounts(module) if linux_mounts is None: args['warnings'] = ('Cannot open file /proc/self/mountinfo. ' 'Bind mounts might be misinterpreted.') # Override defaults with user specified params for key in ('src', 'fstype', 'passno', 'opts', 'dump', 'fstab'): if module.params[key] is not None: args[key] = module.params[key] if get_platform() == 'SunOS' and args['fstab'] == '/etc/fstab': args['fstab'] = '/etc/vfstab' # If fstab file does not exist, we first need to create it. This mainly # happens when fstab option is passed to the module. if not os.path.exists(args['fstab']): if not os.path.exists(os.path.dirname(args['fstab'])): os.makedirs(os.path.dirname(args['fstab'])) open(args['fstab'], 'a').close() # absent: # Remove from fstab and unmounted. # unmounted: # Do not change fstab state, but unmount. # present: # Add to fstab, do not change mount state. # mounted: # Add to fstab if not there and make sure it is mounted. If it has # changed in fstab then remount it. state = module.params['state'] name = module.params['name'] if state == 'absent': name, changed = unset_mount(module, args) if changed and not module.check_mode: if ismount(name) or is_bind_mounted(module, linux_mounts, name): res, msg = umount(module, name) if res: module.fail_json(msg="Error unmounting %s: %s" % (name, msg)) if os.path.exists(name): try: os.rmdir(name) except (OSError, IOError): e = get_exception() module.fail_json(msg="Error rmdir %s: %s" % (name, str(e))) elif state == 'unmounted': if ismount(name) or is_bind_mounted(module, linux_mounts, name): if not module.check_mode: res, msg = umount(module, name) if res: module.fail_json(msg="Error unmounting %s: %s" % (name, msg)) changed = True elif state == 'mounted': if not os.path.exists(name) and not module.check_mode: try: os.makedirs(name) except (OSError, IOError): e = get_exception() module.fail_json(msg="Error making dir %s: %s" % (name, str(e))) name, changed = set_mount(module, args) res = 0 if ismount(name): if changed and not module.check_mode: res, msg = mount(module, args) changed = True elif 'bind' in args.get('opts', []): changed = True if is_bind_mounted(module, linux_mounts, name, args['src'], args['fstype']): changed = False if changed and not module.check_mode: res, msg = mount(module, args) else: changed = True if not module.check_mode: res, msg = mount(module, args) if res: module.fail_json(msg="Error mounting %s: %s" % (name, msg)) elif state == 'present': name, changed = set_mount(module, args) else: module.fail_json(msg='Unexpected position reached') module.exit_json(changed=changed, **args)
def set_mount(module, args): """Set/change a mount point location in fstab.""" to_write = [] exists = False changed = False escaped_args = dict([(k, _escape_fstab(v)) for k, v in iteritems(args)]) new_line = '%(src)s %(name)s %(fstype)s %(opts)s %(dump)s %(passno)s\n' if get_platform() == 'SunOS': new_line = ( '%(src)s - %(name)s %(fstype)s %(passno)s %(boot)s %(opts)s\n') for line in open(args['fstab'], 'r').readlines(): if not line.strip(): to_write.append(line) continue if line.strip().startswith('#'): to_write.append(line) continue # Check if we got a valid line for splitting if ( get_platform() == 'SunOS' and len(line.split()) != 7 or get_platform() != 'SunOS' and len(line.split()) != 6): to_write.append(line) continue ld = {} if get_platform() == 'SunOS': ( ld['src'], dash, ld['name'], ld['fstype'], ld['passno'], ld['boot'], ld['opts'] ) = line.split() else: ( ld['src'], ld['name'], ld['fstype'], ld['opts'], ld['dump'], ld['passno'] ) = line.split() # Check if we found the correct line if ld['name'] != escaped_args['name']: to_write.append(line) continue # If we got here we found a match - let's check if there is any # difference exists = True args_to_check = ('src', 'fstype', 'opts', 'dump', 'passno') if get_platform() == 'SunOS': args_to_check = ('src', 'fstype', 'passno', 'boot', 'opts') for t in args_to_check: if ld[t] != escaped_args[t]: ld[t] = escaped_args[t] changed = True if changed: to_write.append(new_line % ld) else: to_write.append(line) if not exists: to_write.append(new_line % escaped_args) changed = True if changed and not module.check_mode: write_fstab(to_write, args['fstab']) return (args['name'], changed)
def main(): module = AnsibleModule( argument_spec=dict( boot=dict(default='yes', choices=['yes', 'no']), dump=dict(), fstab=dict(default=None), fstype=dict(), name=dict(required=True, type='path'), opts=dict(), passno=dict(type='str'), src=dict(type='path'), state=dict( required=True, choices=['present', 'absent', 'mounted', 'unmounted']), ), supports_check_mode=True, required_if=( ['state', 'mounted', ['src', 'fstype']], ['state', 'present', ['src', 'fstype']] ) ) changed = False # solaris args: # name, src, fstype, opts, boot, passno, state, fstab=/etc/vfstab # linux args: # name, src, fstype, opts, dump, passno, state, fstab=/etc/fstab # Note: Do not modify module.params['fstab'] as we need to know if the user # explicitly specified it in mount() and remount() if get_platform().lower() == 'sunos': args = dict( name=module.params['name'], opts='-', passno='-', fstab=module.params['fstab'], boot='yes' ) if args['fstab'] is None: args['fstab'] = '/etc/vfstab' else: args = dict( name=module.params['name'], opts='defaults', dump='0', passno='0', fstab=module.params['fstab'] ) if args['fstab'] is None: args['fstab'] = '/etc/fstab' # FreeBSD doesn't have any 'default' so set 'rw' instead if get_platform() == 'FreeBSD': args['opts'] = 'rw' linux_mounts = [] # Cache all mounts here in order we have consistent results if we need to # call is_bind_mouted() multiple times if get_platform() == 'Linux': linux_mounts = get_linux_mounts(module) if linux_mounts is None: args['warnings'] = ( 'Cannot open file /proc/self/mountinfo. ' 'Bind mounts might be misinterpreted.') # Override defaults with user specified params for key in ('src', 'fstype', 'passno', 'opts', 'dump', 'fstab'): if module.params[key] is not None: args[key] = module.params[key] # If fstab file does not exist, we first need to create it. This mainly # happens when fstab option is passed to the module. if not os.path.exists(args['fstab']): if not os.path.exists(os.path.dirname(args['fstab'])): os.makedirs(os.path.dirname(args['fstab'])) open(args['fstab'], 'a').close() # absent: # Remove from fstab and unmounted. # unmounted: # Do not change fstab state, but unmount. # present: # Add to fstab, do not change mount state. # mounted: # Add to fstab if not there and make sure it is mounted. If it has # changed in fstab then remount it. state = module.params['state'] name = module.params['name'] if state == 'absent': name, changed = unset_mount(module, args) if changed and not module.check_mode: if ismount(name) or is_bind_mounted(module, linux_mounts, name): res, msg = umount(module, name) if res: module.fail_json( msg="Error unmounting %s: %s" % (name, msg)) if os.path.exists(name): try: os.rmdir(name) except (OSError, IOError): e = get_exception() module.fail_json(msg="Error rmdir %s: %s" % (name, str(e))) elif state == 'unmounted': if ismount(name) or is_bind_mounted(module, linux_mounts, name): if not module.check_mode: res, msg = umount(module, name) if res: module.fail_json( msg="Error unmounting %s: %s" % (name, msg)) changed = True elif state == 'mounted': if not os.path.exists(name) and not module.check_mode: try: os.makedirs(name) except (OSError, IOError): e = get_exception() module.fail_json( msg="Error making dir %s: %s" % (name, str(e))) name, changed = set_mount(module, args) res = 0 if ismount(name): if changed and not module.check_mode: res, msg = mount(module, args) changed = True elif 'bind' in args.get('opts', []): changed = True if is_bind_mounted( module, linux_mounts, name, args['src'], args['fstype']): changed = False if changed and not module.check_mode: res, msg = mount(module, args) else: changed = True if not module.check_mode: res, msg = mount(module, args) if res: module.fail_json(msg="Error mounting %s: %s" % (name, msg)) elif state == 'present': name, changed = set_mount(module, args) else: module.fail_json(msg='Unexpected position reached') module.exit_json(changed=changed, **args)
def main(): module = AnsibleModule( argument_spec=dict( path=dict(required=True, aliases=['name'], type='path'), entry=dict(required=False, type='str'), entity=dict(required=False, type='str', default=''), etype=dict( required=False, choices=['other', 'user', 'group', 'mask'], type='str' ), permissions=dict(required=False, type='str'), state=dict( required=False, default='query', choices=['query', 'present', 'absent'], type='str' ), follow=dict(required=False, type='bool', default=True), default=dict(required=False, type='bool', default=False), recursive=dict(required=False, type='bool', default=False), use_nfsv4_acls=dict(required=False, type='bool', default=False) ), supports_check_mode=True, ) if get_platform().lower() not in ['linux', 'freebsd']: module.fail_json(msg="The acl module is not available on this system.") path = module.params.get('path') entry = module.params.get('entry') entity = module.params.get('entity') etype = module.params.get('etype') permissions = module.params.get('permissions') state = module.params.get('state') follow = module.params.get('follow') default = module.params.get('default') recursive = module.params.get('recursive') use_nfsv4_acls = module.params.get('use_nfsv4_acls') if not os.path.exists(path): module.fail_json(msg="Path not found or not accessible.") if state == 'query' and recursive: module.fail_json(msg="'recursive' MUST NOT be set when 'state=query'.") if not entry: if state == 'absent' and permissions: module.fail_json(msg="'permissions' MUST NOT be set when 'state=absent'.") if state == 'absent' and not entity: module.fail_json(msg="'entity' MUST be set when 'state=absent'.") if state in ['present', 'absent'] and not etype: module.fail_json(msg="'etype' MUST be set when 'state=%s'." % state) if entry: if etype or entity or permissions: module.fail_json(msg="'entry' MUST NOT be set when 'entity', 'etype' or 'permissions' are set.") if state == 'present' and not entry.count(":") in [2, 3]: module.fail_json(msg="'entry' MUST have 3 or 4 sections divided by ':' when 'state=present'.") if state == 'absent' and not entry.count(":") in [1, 2]: module.fail_json(msg="'entry' MUST have 2 or 3 sections divided by ':' when 'state=absent'.") if state == 'query': module.fail_json(msg="'entry' MUST NOT be set when 'state=query'.") default_flag, etype, entity, permissions = split_entry(entry) if default_flag is not None: default = default_flag if get_platform().lower() == 'freebsd': if recursive: module.fail_json(msg="recursive is not supported on that platform.") changed = False msg = "" if state == 'present': entry = build_entry(etype, entity, permissions, use_nfsv4_acls) command = build_command( module, 'set', path, follow, default, recursive, entry ) changed = acl_changed(module, command) if changed and not module.check_mode: run_acl(module, command) msg = "%s is present" % entry elif state == 'absent': entry = build_entry(etype, entity, use_nfsv4_acls) command = build_command( module, 'rm', path, follow, default, recursive, entry ) changed = acl_changed(module, command) if changed and not module.check_mode: run_acl(module, command, False) msg = "%s is absent" % entry elif state == 'query': msg = "current acl" acl = run_acl( module, build_command(module, 'get', path, follow, default, recursive) ) module.exit_json(changed=changed, msg=msg, acl=acl)
def set_mount(module, args): """Set/change a mount point location in fstab.""" to_write = [] exists = False changed = False escaped_args = dict([(k, _escape_fstab(v)) for k, v in iteritems(args)]) new_line = '%(src)s %(name)s %(fstype)s %(opts)s %(dump)s %(passno)s\n' if get_platform() == 'SunOS': new_line = ( '%(src)s - %(name)s %(fstype)s %(passno)s %(boot)s %(opts)s\n') for line in open(args['fstab'], 'r').readlines(): if not line.strip(): to_write.append(line) continue if line.strip().startswith('#'): to_write.append(line) continue # Check if we got a valid line for splitting if (get_platform() == 'SunOS' and len(line.split()) != 7 or get_platform() != 'SunOS' and len(line.split()) != 6): to_write.append(line) continue ld = {} if get_platform() == 'SunOS': (ld['src'], dash, ld['name'], ld['fstype'], ld['passno'], ld['boot'], ld['opts']) = line.split() else: (ld['src'], ld['name'], ld['fstype'], ld['opts'], ld['dump'], ld['passno']) = line.split() # Check if we found the correct line if ld['name'] != escaped_args['name']: to_write.append(line) continue # If we got here we found a match - let's check if there is any # difference exists = True args_to_check = ('src', 'fstype', 'opts', 'dump', 'passno') if get_platform() == 'SunOS': args_to_check = ('src', 'fstype', 'passno', 'boot', 'opts') for t in args_to_check: if ld[t] != escaped_args[t]: ld[t] = escaped_args[t] changed = True if changed: to_write.append(new_line % ld) else: to_write.append(line) if not exists: to_write.append(new_line % escaped_args) changed = True if changed and not module.check_mode: write_fstab(to_write, args['fstab']) return (args['name'], changed)
def main(): # The following example playbooks: # # - cron: name="check dirs" hour="5,2" job="ls -alh > /dev/null" # # - name: do the job # cron: name="do the job" hour="5,2" job="/some/dir/job.sh" # # - name: no job # cron: name="an old job" state=absent # # - name: sets env # cron: name="PATH" env=yes value="/bin:/usr/bin" # # Would produce: # PATH=/bin:/usr/bin # # Ansible: check dirs # * * 5,2 * * ls -alh > /dev/null # # Ansible: do the job # * * 5,2 * * /some/dir/job.sh module = AnsibleModule(argument_spec=dict( name=dict(required=False), user=dict(required=False), job=dict(required=False, aliases=['value']), cron_file=dict(required=False), state=dict(default='present', choices=['present', 'absent']), backup=dict(default=False, type='bool'), minute=dict(default='*'), hour=dict(default='*'), day=dict(aliases=['dom'], default='*'), month=dict(default='*'), weekday=dict(aliases=['dow'], default='*'), reboot=dict(required=False, default=False, type='bool'), special_time=dict(required=False, default=None, choices=[ "reboot", "yearly", "annually", "monthly", "weekly", "daily", "hourly" ], type='str'), disabled=dict(default=False, type='bool'), env=dict(required=False, type='bool'), insertafter=dict(required=False), insertbefore=dict(required=False), ), supports_check_mode=True, mutually_exclusive=[ ['reboot', 'special_time'], ['insertafter', 'insertbefore'], ]) name = module.params['name'] user = module.params['user'] job = module.params['job'] cron_file = module.params['cron_file'] state = module.params['state'] backup = module.params['backup'] minute = module.params['minute'] hour = module.params['hour'] day = module.params['day'] month = module.params['month'] weekday = module.params['weekday'] reboot = module.params['reboot'] special_time = module.params['special_time'] disabled = module.params['disabled'] env = module.params['env'] insertafter = module.params['insertafter'] insertbefore = module.params['insertbefore'] do_install = state == 'present' changed = False res_args = dict() warnings = list() if cron_file: cron_file_basename = os.path.basename(cron_file) if not re.search(r'^[A-Z0-9_-]+$', cron_file_basename, re.I): warnings.append( 'Filename portion of cron_file ("%s") should consist' % cron_file_basename + ' solely of upper- and lower-case letters, digits, underscores, and hyphens' ) # Ensure all files generated are only writable by the owning user. Primarily relevant for the cron_file option. os.umask(int('022', 8)) crontab = CronTab(module, user, cron_file) module.debug('cron instantiated - name: "%s"' % name) if module._diff: diff = dict() diff['before'] = crontab.existing if crontab.cron_file: diff['before_header'] = crontab.cron_file else: if crontab.user: diff['before_header'] = 'crontab for user "%s"' % crontab.user else: diff['before_header'] = 'crontab' # --- user input validation --- if (special_time or reboot) and \ (True in [(x != '*') for x in [minute, hour, day, month, weekday]]): module.fail_json( msg="You must specify time and date fields or special time.") # cannot support special_time on solaris if (special_time or reboot) and get_platform() == 'SunOS': module.fail_json( msg="Solaris does not support special_time=... or @reboot") if cron_file and do_install: if not user: module.fail_json( msg= "To use cron_file=... parameter you must specify user=... as well" ) if job is None and do_install: module.fail_json( msg="You must specify 'job' to install a new cron job or variable") if (insertafter or insertbefore) and not env and do_install: module.fail_json( msg= "Insertafter and insertbefore parameters are valid only with env=yes" ) if reboot: special_time = "reboot" # if requested make a backup before making a change if backup and not module.check_mode: (backuph, backup_file) = tempfile.mkstemp(prefix='crontab') crontab.write(backup_file) if crontab.cron_file and not name and not do_install: if module._diff: diff['after'] = '' diff['after_header'] = '/dev/null' else: diff = dict() if module.check_mode: changed = os.path.isfile(crontab.cron_file) else: changed = crontab.remove_job_file() module.exit_json(changed=changed, cron_file=cron_file, state=state, diff=diff) if env: if ' ' in name: module.fail_json(msg="Invalid name for environment variable") decl = '%s="%s"' % (name, job) old_decl = crontab.find_env(name) if do_install: if len(old_decl) == 0: crontab.add_env(decl, insertafter, insertbefore) changed = True if len(old_decl) > 0 and old_decl[1] != decl: crontab.update_env(name, decl) changed = True else: if len(old_decl) > 0: crontab.remove_env(name) changed = True else: if do_install: for char in ['\r', '\n']: if char in job.strip('\r\n'): warnings.append('Job should not contain line breaks') break job = crontab.get_cron_job(minute, hour, day, month, weekday, job, special_time, disabled) old_job = crontab.find_job(name, job) if len(old_job) == 0: crontab.add_job(name, job) changed = True if len(old_job) > 0 and old_job[1] != job: crontab.update_job(name, job) changed = True if len(old_job) > 2: crontab.update_job(name, job) changed = True else: old_job = crontab.find_job(name) if len(old_job) > 0: crontab.remove_job(name) changed = True # no changes to env/job, but existing crontab needs a terminating newline if not changed and not crontab.existing == '': if not (crontab.existing.endswith('\r') or crontab.existing.endswith('\n')): changed = True res_args = dict(jobs=crontab.get_jobnames(), envs=crontab.get_envnames(), warnings=warnings, changed=changed) if changed: if not module.check_mode: crontab.write() if module._diff: diff['after'] = crontab.render() if crontab.cron_file: diff['after_header'] = crontab.cron_file else: if crontab.user: diff[ 'after_header'] = 'crontab for user "%s"' % crontab.user else: diff['after_header'] = 'crontab' res_args['diff'] = diff # retain the backup only if crontab or cron file have changed if backup and not module.check_mode: if changed: res_args['backup_file'] = backup_file else: os.unlink(backup_file) if cron_file: res_args['cron_file'] = cron_file module.exit_json(**res_args) # --- should never get here module.exit_json(msg="Unable to execute cron task.")