class NetAppCDOTLUN(object): def __init__(self): self._size_unit_map = dict(bytes=1, b=1, kb=1024, mb=1024**2, gb=1024**3, tb=1024**4, pb=1024**5, eb=1024**6, zb=1024**7, yb=1024**8) self.argument_spec = netapp_utils.ontap_sf_host_argument_spec() self.argument_spec.update( dict( state=dict(required=True, choices=['present', 'absent']), name=dict(required=True, type='str'), size=dict(type='int'), size_unit=dict(default='gb', choices=[ 'bytes', 'b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb' ], type='str'), force_resize=dict(default=False, type='bool'), force_remove=dict(default=False, type='bool'), force_remove_fenced=dict(default=False, type='bool'), flexvol_name=dict(type='str'), vserver=dict(required=True, type='str'), )) self.module = AnsibleModule(argument_spec=self.argument_spec, required_if=[('state', 'present', ['flexvol_name', 'size'])], supports_check_mode=True) p = self.module.params # set up state variables self.state = p['state'] self.name = p['name'] self.size_unit = p['size_unit'] if p['size'] is not None: self.size = p['size'] * self._size_unit_map[self.size_unit] else: self.size = None self.force_resize = p['force_resize'] self.force_remove = p['force_remove'] self.force_remove_fenced = p['force_remove_fenced'] self.flexvol_name = p['flexvol_name'] self.vserver = p['vserver'] if HAS_NETAPP_LIB is False: self.module.fail_json( msg="the python NetApp-Lib module is required") else: self.server = netapp_utils.setup_ontap_zapi(module=self.module, vserver=self.vserver) def get_lun(self): """ Return details about the LUN :return: Details about the lun :rtype: dict """ luns = [] tag = None while True: lun_info = netapp_utils.zapi.NaElement('lun-get-iter') if tag: lun_info.add_new_child('tag', tag, True) query_details = netapp_utils.zapi.NaElement('lun-info') query_details.add_new_child('vserver', self.vserver) query_details.add_new_child('volume', self.flexvol_name) query = netapp_utils.zapi.NaElement('query') query.add_child_elem(query_details) lun_info.add_child_elem(query) result = self.server.invoke_successfully(lun_info, True) if result.get_child_by_name('num-records') and int( result.get_child_content('num-records')) >= 1: attr_list = result.get_child_by_name('attributes-list') luns.extend(attr_list.get_children()) tag = result.get_child_content('next-tag') if tag is None: break # The LUNs have been extracted. # Find the specified lun and extract details. return_value = None for lun in luns: path = lun.get_child_content('path') _rest, _splitter, found_name = path.rpartition('/') if found_name == self.name: size = lun.get_child_content('size') # Find out if the lun is attached attached_to = None lun_id = None if lun.get_child_content('mapped') == 'true': lun_map_list = netapp_utils.zapi.NaElement.create_node_with_children( 'lun-map-list-info', **{'path': path}) result = self.server.invoke_successfully( lun_map_list, enable_tunneling=True) igroups = result.get_child_by_name('initiator-groups') if igroups: for igroup_info in igroups.get_children(): igroup = igroup_info.get_child_content( 'initiator-group-name') attached_to = igroup lun_id = igroup_info.get_child_content('lun-id') return_value = { 'name': found_name, 'size': size, 'attached_to': attached_to, 'lun_id': lun_id } else: continue return return_value def create_lun(self): """ Create LUN with requested name and size """ path = '/vol/%s/%s' % (self.flexvol_name, self.name) lun_create = netapp_utils.zapi.NaElement.create_node_with_children( 'lun-create-by-size', **{ 'path': path, 'size': str(self.size), 'ostype': 'linux' }) try: self.server.invoke_successfully(lun_create, enable_tunneling=True) except netapp_utils.zapi.NaApiError as e: self.module.fail_json( msg="Error provisioning lun %s of size %s: %s" % (self.name, self.size, to_native(e)), exception=traceback.format_exc()) def delete_lun(self): """ Delete requested LUN """ path = '/vol/%s/%s' % (self.flexvol_name, self.name) lun_delete = netapp_utils.zapi.NaElement.create_node_with_children( 'lun-destroy', **{ 'path': path, 'force': str(self.force_remove), 'destroy-fenced-lun': str(self.force_remove_fenced) }) try: self.server.invoke_successfully(lun_delete, enable_tunneling=True) except netapp_utils.zapi.NaApiError as e: self.module.fail_json(msg="Error deleting lun %s: %s" % (path, to_native(e)), exception=traceback.format_exc()) def resize_lun(self): """ Resize requested LUN. :return: True if LUN was actually re-sized, false otherwise. :rtype: bool """ path = '/vol/%s/%s' % (self.flexvol_name, self.name) lun_resize = netapp_utils.zapi.NaElement.create_node_with_children( 'lun-resize', **{ 'path': path, 'size': str(self.size), 'force': str(self.force_resize) }) try: self.server.invoke_successfully(lun_resize, enable_tunneling=True) except netapp_utils.zapi.NaApiError as e: if to_native(e.code) == "9042": # Error 9042 denotes the new LUN size being the same as the # old LUN size. This happens when there's barely any difference # in the two sizes. For example, from 8388608 bytes to # 8194304 bytes. This should go away if/when the default size # requested/reported to/from the controller is changed to a # larger unit (MB/GB/TB). return False else: self.module.fail_json(msg="Error resizing lun %s: %s" % (path, to_native(e)), exception=traceback.format_exc()) return True def apply(self): property_changed = False multiple_properties_changed = False size_changed = False lun_exists = False lun_detail = self.get_lun() if lun_detail: lun_exists = True current_size = lun_detail['size'] if self.state == 'absent': property_changed = True elif self.state == 'present': if not int(current_size) == self.size: size_changed = True property_changed = True else: if self.state == 'present': property_changed = True if property_changed: if self.module.check_mode: pass else: if self.state == 'present': if not lun_exists: self.create_lun() else: if size_changed: # Ensure that size was actually changed. Please # read notes in 'resize_lun' function for details. size_changed = self.resize_lun() if not size_changed and not \ multiple_properties_changed: property_changed = False elif self.state == 'absent': self.delete_lun() changed = property_changed or size_changed # TODO: include other details about the lun (size, etc.) self.module.exit_json(changed=changed)
def main(): fields = { "host": { "required": False, "type": "str" }, "username": { "required": False, "type": "str" }, "password": { "required": False, "type": "str", "default": "", "no_log": True }, "vdom": { "required": False, "type": "str", "default": "root" }, "https": { "required": False, "type": "bool", "default": True }, "ssl_verify": { "required": False, "type": "bool", "default": True }, "state": { "required": False, "type": "str", "choices": ["present", "absent"] }, "firewall_service_custom": { "required": False, "type": "dict", "default": None, "options": { "state": { "required": False, "type": "str", "choices": ["present", "absent"] }, "app_category": { "required": False, "type": "list", "options": { "id": { "required": True, "type": "int" } } }, "app_service_type": { "required": False, "type": "str", "choices": ["disable", "app-id", "app-category"] }, "application": { "required": False, "type": "list", "options": { "id": { "required": True, "type": "int" } } }, "category": { "required": False, "type": "str" }, "check_reset_range": { "required": False, "type": "str", "choices": ["disable", "strict", "default"] }, "color": { "required": False, "type": "int" }, "comment": { "required": False, "type": "str" }, "fqdn": { "required": False, "type": "str" }, "helper": { "required": False, "type": "str", "choices": [ "auto", "disable", "ftp", "tftp", "ras", "h323", "tns", "mms", "sip", "pptp", "rtsp", "dns-udp", "dns-tcp", "pmap", "rsh", "dcerpc", "mgcp", "gtp-c", "gtp-u", "gtp-b" ] }, "icmpcode": { "required": False, "type": "int" }, "icmptype": { "required": False, "type": "int" }, "iprange": { "required": False, "type": "str" }, "name": { "required": True, "type": "str" }, "protocol": { "required": False, "type": "str", "choices": [ "TCP/UDP/SCTP", "ICMP", "ICMP6", "IP", "HTTP", "FTP", "CONNECT", "SOCKS-TCP", "SOCKS-UDP", "ALL" ] }, "protocol_number": { "required": False, "type": "int" }, "proxy": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "sctp_portrange": { "required": False, "type": "str" }, "session_ttl": { "required": False, "type": "int" }, "tcp_halfclose_timer": { "required": False, "type": "int" }, "tcp_halfopen_timer": { "required": False, "type": "int" }, "tcp_portrange": { "required": False, "type": "str" }, "tcp_timewait_timer": { "required": False, "type": "int" }, "udp_idle_timer": { "required": False, "type": "int" }, "udp_portrange": { "required": False, "type": "str" }, "visibility": { "required": False, "type": "str", "choices": ["enable", "disable"] } } } } module = AnsibleModule(argument_spec=fields, supports_check_mode=False) # legacy_mode refers to using fortiosapi instead of HTTPAPI legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 'username' in module.params and module.params['username'] is not None and \ 'password' in module.params and module.params['password'] is not None if not legacy_mode: if module._socket_path: connection = Connection(module._socket_path) fos = FortiOSHandler(connection) is_error, has_changed, result = fortios_firewall_service( module.params, fos) else: module.fail_json(**FAIL_SOCKET_MSG) else: try: from fortiosapi import FortiOSAPI except ImportError: module.fail_json(msg="fortiosapi module is required") fos = FortiOSAPI() login(module.params, fos) is_error, has_changed, result = fortios_firewall_service( module.params, fos) fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) else: module.fail_json(msg="Error in repo", meta=result)
def main(): fields = { "host": { "required": False, "type": "str" }, "username": { "required": False, "type": "str" }, "password": { "required": False, "type": "str", "default": "", "no_log": True }, "vdom": { "required": False, "type": "str", "default": "root" }, "https": { "required": False, "type": "bool", "default": True }, "ssl_verify": { "required": False, "type": "bool", "default": True }, "state": { "required": True, "type": "str", "choices": ["present", "absent"] }, "system_ips_urlfilter_dns6": { "required": False, "type": "dict", "default": None, "options": { "address6": { "required": True, "type": "str" }, "status": { "required": False, "type": "str", "choices": ["enable", "disable"] } } } } module = AnsibleModule(argument_spec=fields, supports_check_mode=False) # legacy_mode refers to using fortiosapi instead of HTTPAPI legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 'username' in module.params and module.params['username'] is not None and \ 'password' in module.params and module.params['password'] is not None if not legacy_mode: if module._socket_path: connection = Connection(module._socket_path) fos = FortiOSHandler(connection) is_error, has_changed, result = fortios_system(module.params, fos) else: module.fail_json(**FAIL_SOCKET_MSG) else: try: from fortiosapi import FortiOSAPI except ImportError: module.fail_json(msg="fortiosapi module is required") fos = FortiOSAPI() login(module.params, fos) is_error, has_changed, result = fortios_system(module.params, fos) fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) else: module.fail_json(msg="Error in repo", meta=result)
class ElementSWInitiators(object): """ Element Software Manage Element SW initiators """ def __init__(self): self.argument_spec = netapp_utils.ontap_sf_host_argument_spec() self.argument_spec.update(dict( initiators=dict( type='list', options=dict( name=dict(type='str', required=True), alias=dict(type='str', default=None), initiator_id=dict(type='int', default=None), volume_access_groups=dict(type='list', default=None), volume_access_group_id=dict(type='int', default=None), attributes=dict(type='dict', default=None), ) ), state=dict(choices=['present', 'absent'], default='present'), )) self.module = AnsibleModule( argument_spec=self.argument_spec, supports_check_mode=True ) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) if HAS_SF_SDK is False: self.module.fail_json(msg="Unable to import the SolidFire Python SDK") else: self.sfe = netapp_utils.create_sf_connection(module=self.module) self.elementsw_helper = NaElementSWModule(self.sfe) # iterate over each user-provided initiator for initiator in self.parameters.get('initiators'): # add telemetry attributes if 'attributes' in initiator: initiator['attributes'].update(self.elementsw_helper.set_element_attributes(source='na_elementsw_initiators')) else: initiator['attributes'] = self.elementsw_helper.set_element_attributes(source='na_elementsw_initiators') def compare_initiators(self, user_initiator, existing_initiator): """ compare user input initiator with existing dict :return: True if matched, False otherwise """ if user_initiator is None or existing_initiator is None: return False for param in user_initiator: # lookup initiator_name instead of name if param == 'name': if user_initiator['name'] == existing_initiator['initiator_name']: pass elif user_initiator[param] == existing_initiator[param]: pass else: return True return False def initiator_to_dict(self, initiator_obj): """ converts initiator class object to dict :return: reconstructed initiator dict """ known_params = ['initiator_name', 'alias', 'initiator_id', 'volume_access_groups', 'volume_access_group_id', 'attributes'] initiator_dict = {} # missing parameter cause error # so assign defaults for param in known_params: initiator_dict[param] = getattr(initiator_obj, param, None) return initiator_dict def find_initiator(self, id=None, name=None): """ find a specific initiator :return: initiator dict """ initiator_details = None if self.all_existing_initiators is None: return initiator_details for initiator in self.all_existing_initiators: # if name is provided or # if id is provided if name is not None: if initiator.initiator_name == name: initiator_details = self.initiator_to_dict(initiator) elif id is not None: if initiator.initiator_id == id: initiator_details = self.initiator_to_dict(initiator) else: # if neither id nor name provided # return everything initiator_details = self.all_existing_initiators return initiator_details def create_initiators(self, initiator): """ create initiators """ # create_initiators needs an array # so enclose this initiator in an array initiator_list = [initiator] try: self.sfe.create_initiators(initiator_list) except Exception as exception_object: self.module.fail_json(msg='Error creating initiator %s' % (to_native(exception_object)), exception=traceback.format_exc()) def delete_initiators(self, initiator): """ delete initiators """ # delete_initiators needs an array # so enclose this initiator in an array initiator_id_array = [initiator] try: self.sfe.delete_initiators(initiator_id_array) except Exception as exception_object: self.module.fail_json(msg='Error deleting initiator %s' % (to_native(exception_object)), exception=traceback.format_exc()) def modify_initiators(self, initiator, existing_initiator): """ modify initiators """ # create the new initiator dict # by merging old and new values merged_initiator = existing_initiator.copy() merged_initiator.update(initiator) # we MUST create an object before sending # the new initiator to modify_initiator initiator_object = ModifyInitiator(initiator_id=merged_initiator['initiator_id'], alias=merged_initiator['alias'], volume_access_group_id=merged_initiator['volume_access_group_id'], attributes=merged_initiator['attributes']) initiator_list = [initiator_object] try: self.sfe.modify_initiators(initiators=initiator_list) except Exception as exception_object: self.module.fail_json(msg='Error modifying initiator %s' % (to_native(exception_object)), exception=traceback.format_exc()) def apply(self): """ configure initiators """ changed = False modify = None result_message = None # get all user provided initiators input_initiators = self.parameters.get('initiators') # get all initiators # store in a cache variable self.all_existing_initiators = self.sfe.list_initiators().initiators # iterate over each user-provided initiator for in_initiator in input_initiators: if self.parameters.get('state') == 'present': # check if initiator_id is provided and exists if 'initiator_id' in in_initiator and in_initiator['initiator_id'] is not None and \ self.find_initiator(id=in_initiator['initiator_id']) is not None: if self.compare_initiators(in_initiator, self.find_initiator(id=in_initiator['initiator_id'])): changed = True result_message = 'modifying initiator(s)' self.modify_initiators(in_initiator, self.find_initiator(id=in_initiator['initiator_id'])) # otherwise check if name is provided and exists elif 'name' in in_initiator and in_initiator['name'] is not None and self.find_initiator(name=in_initiator['name']) is not None: if self.compare_initiators(in_initiator, self.find_initiator(name=in_initiator['name'])): changed = True result_message = 'modifying initiator(s)' self.modify_initiators(in_initiator, self.find_initiator(name=in_initiator['name'])) # this is a create op if initiator doesn't exist else: changed = True result_message = 'creating initiator(s)' self.create_initiators(in_initiator) elif self.parameters.get('state') == 'absent': # delete_initiators only processes ids # so pass ids of initiators to method if 'name' in in_initiator and in_initiator['name'] is not None and \ self.find_initiator(name=in_initiator['name']) is not None: changed = True result_message = 'deleting initiator(s)' self.delete_initiators(self.find_initiator(name=in_initiator['name'])['initiator_id']) elif 'initiator_id' in in_initiator and in_initiator['initiator_id'] is not None and \ self.find_initiator(id=in_initiator['initiator_id']) is not None: changed = True result_message = 'deleting initiator(s)' self.delete_initiators(in_initiator['initiator_id']) if self.module.check_mode is True: result_message = "Check mode, skipping changes" self.module.exit_json(changed=changed, msg=result_message)
def __init__(self): argument_spec = eseries_host_argument_spec() argument_spec.update( dict( name=dict(type='str', required=False, aliases=['alias']), ping=dict(type='bool', required=False, default=True), chap_secret=dict(type='str', required=False, aliases=['chap', 'password'], no_log=True), unnamed_discovery=dict(type='bool', required=False, default=True), log_path=dict(type='str', required=False), )) self.module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) args = self.module.params self.name = args['name'] self.ping = args['ping'] self.chap_secret = args['chap_secret'] self.unnamed_discovery = args['unnamed_discovery'] self.ssid = args['ssid'] self.url = args['api_url'] self.creds = dict( url_password=args['api_password'], validate_certs=args['validate_certs'], url_username=args['api_username'], ) self.check_mode = self.module.check_mode self.post_body = dict() self.controllers = list() log_path = args['log_path'] # logging setup self._logger = logging.getLogger(self.__class__.__name__) if log_path: logging.basicConfig( level=logging.DEBUG, filename=log_path, filemode='w', format= '%(relativeCreated)dms %(levelname)s %(module)s.%(funcName)s:%(lineno)d\n %(message)s' ) if not self.url.endswith('/'): self.url += '/' if self.chap_secret: if len(self.chap_secret) < 12 or len(self.chap_secret) > 57: self.module.fail_json( msg= "The provided CHAP secret is not valid, it must be between 12 and 57" " characters in length.") for c in self.chap_secret: ordinal = ord(c) if ordinal < 32 or ordinal > 126: self.module.fail_json( msg= "The provided CHAP secret is not valid, it may only utilize ascii" " characters with decimal values between 32 and 126.")
def main(): module = AnsibleModule( argument_spec=dict( path=dict(type='path', required=True, aliases=['dest', 'destfile', 'name']), state=dict(type='str', default='present', choices=['absent', 'present']), marker=dict(type='str', default='# {mark} ANSIBLE MANAGED BLOCK'), block=dict(type='str', default='', aliases=['content']), insertafter=dict(type='str'), insertbefore=dict(type='str'), create=dict(type='bool', default=False), backup=dict(type='bool', default=False), validate=dict(type='str'), marker_begin=dict(type='str', default='BEGIN'), marker_end=dict(type='str', default='END'), ), mutually_exclusive=[['insertbefore', 'insertafter']], add_file_common_args=True, supports_check_mode=True ) params = module.params path = params['path'] if os.path.isdir(path): module.fail_json(rc=256, msg='Path %s is a directory !' % path) path_exists = os.path.exists(path) if not path_exists: if not module.boolean(params['create']): module.fail_json(rc=257, msg='Path %s does not exist !' % path) destpath = os.path.dirname(path) if not os.path.exists(destpath) and not module.check_mode: try: os.makedirs(destpath) except Exception as e: module.fail_json(msg='Error creating %s Error code: %s Error description: %s' % (destpath, e[0], e[1])) original = None lines = [] else: f = open(path, 'rb') original = f.read() f.close() lines = original.splitlines() diff = {'before': '', 'after': '', 'before_header': '%s (content)' % path, 'after_header': '%s (content)' % path} if module._diff and original: diff['before'] = original insertbefore = params['insertbefore'] insertafter = params['insertafter'] block = to_bytes(params['block']) marker = to_bytes(params['marker']) present = params['state'] == 'present' if not present and not path_exists: module.exit_json(changed=False, msg="File %s not present" % path) if insertbefore is None and insertafter is None: insertafter = 'EOF' if insertafter not in (None, 'EOF'): insertre = re.compile(to_bytes(insertafter, errors='surrogate_or_strict')) elif insertbefore not in (None, 'BOF'): insertre = re.compile(to_bytes(insertbefore, errors='surrogate_or_strict')) else: insertre = None marker0 = re.sub(b(r'{mark}'), b(params['marker_begin']), marker) marker1 = re.sub(b(r'{mark}'), b(params['marker_end']), marker) if present and block: # Escape sequences like '\n' need to be handled in Ansible 1.x if module.ansible_version.startswith('1.'): block = re.sub('', block, '') blocklines = [marker0] + block.splitlines() + [marker1] else: blocklines = [] n0 = n1 = None for i, line in enumerate(lines): if line == marker0: n0 = i if line == marker1: n1 = i if None in (n0, n1): n0 = None if insertre is not None: for i, line in enumerate(lines): if insertre.search(line): n0 = i if n0 is None: n0 = len(lines) elif insertafter is not None: n0 += 1 elif insertbefore is not None: n0 = 0 # insertbefore=BOF else: n0 = len(lines) # insertafter=EOF elif n0 < n1: lines[n0:n1 + 1] = [] else: lines[n1:n0 + 1] = [] n0 = n1 lines[n0:n0] = blocklines if lines: result = b('\n').join(lines) if original is None or original.endswith(b('\n')): result += b('\n') else: result = b'' if module._diff: diff['after'] = result if original == result: msg = '' changed = False elif original is None: msg = 'File created' changed = True elif not blocklines: msg = 'Block removed' changed = True else: msg = 'Block inserted' changed = True if changed and not module.check_mode: if module.boolean(params['backup']) and path_exists: module.backup_local(path) # We should always follow symlinks so that we change the real file real_path = os.path.realpath(params['path']) write_changes(module, result, real_path) if module.check_mode and not path_exists: module.exit_json(changed=changed, msg=msg, diff=diff) attr_diff = {} msg, changed = check_file_attrs(module, changed, msg, attr_diff) attr_diff['before_header'] = '%s (file attributes)' % path attr_diff['after_header'] = '%s (file attributes)' % path difflist = [diff, attr_diff] module.exit_json(changed=changed, msg=msg, diff=difflist)
def main(): module = AnsibleModule( argument_spec=dict( vg=dict(type='str', required=True), lv=dict(type='str'), size=dict(type='str'), opts=dict(type='str'), state=dict(type='str', default='present', choices=['absent', 'present']), force=dict(type='bool', default=False), shrink=dict(type='bool', default=True), active=dict(type='bool', default=True), snapshot=dict(type='str'), pvs=dict(type='str'), resizefs=dict(type='bool', default=False), thinpool=dict(type='str'), ), supports_check_mode=True, required_one_of=(['lv', 'thinpool'], ), ) module.run_command_environ_update = LVOL_ENV_VARS # Determine if the "--yes" option should be used version_found = get_lvm_version(module) if version_found is None: module.fail_json(msg="Failed to get LVM version number") version_yesopt = mkversion(2, 2, 99) # First LVM with the "--yes" option if version_found >= version_yesopt: yesopt = "--yes" else: yesopt = "" vg = module.params['vg'] lv = module.params['lv'] size = module.params['size'] opts = module.params['opts'] state = module.params['state'] force = module.boolean(module.params['force']) shrink = module.boolean(module.params['shrink']) active = module.boolean(module.params['active']) resizefs = module.boolean(module.params['resizefs']) thinpool = module.params['thinpool'] size_opt = 'L' size_unit = 'm' snapshot = module.params['snapshot'] pvs = module.params['pvs'] if pvs is None: pvs = "" else: pvs = pvs.replace(",", " ") if opts is None: opts = "" # Add --test option when running in check-mode if module.check_mode: test_opt = ' --test' else: test_opt = '' if size: # LVCREATE(8) -l --extents option with percentage if '%' in size: size_parts = size.split('%', 1) size_percent = int(size_parts[0]) if size_percent > 100: module.fail_json( msg="Size percentage cannot be larger than 100%") size_whole = size_parts[1] if size_whole == 'ORIGIN': module.fail_json(msg="Snapshot Volumes are not supported") elif size_whole not in ['VG', 'PVS', 'FREE']: module.fail_json( msg="Specify extents as a percentage of VG|PVS|FREE") size_opt = 'l' size_unit = '' if '%' not in size: # LVCREATE(8) -L --size option unit if size[-1].lower() in 'bskmgtpe': size_unit = size[-1].lower() size = size[0:-1] try: float(size) if not size[0].isdigit(): raise ValueError() except ValueError: module.fail_json(msg="Bad size specification of '%s'" % size) # when no unit, megabytes by default if size_opt == 'l': unit = 'm' else: unit = size_unit # Get information on volume group requested vgs_cmd = module.get_bin_path("vgs", required=True) rc, current_vgs, err = module.run_command( "%s --noheadings --nosuffix -o vg_name,size,free,vg_extent_size --units %s --separator ';' %s" % (vgs_cmd, unit, vg)) if rc != 0: if state == 'absent': module.exit_json(changed=False, stdout="Volume group %s does not exist." % vg) else: module.fail_json(msg="Volume group %s does not exist." % vg, rc=rc, err=err) vgs = parse_vgs(current_vgs) this_vg = vgs[0] # Get information on logical volume requested lvs_cmd = module.get_bin_path("lvs", required=True) rc, current_lvs, err = module.run_command( "%s -a --noheadings --nosuffix -o lv_name,size,lv_attr --units %s --separator ';' %s" % (lvs_cmd, unit, vg)) if rc != 0: if state == 'absent': module.exit_json(changed=False, stdout="Volume group %s does not exist." % vg) else: module.fail_json(msg="Volume group %s does not exist." % vg, rc=rc, err=err) changed = False lvs = parse_lvs(current_lvs) if snapshot: # Check snapshot pre-conditions for test_lv in lvs: if test_lv['name'] == lv or test_lv['name'] == thinpool: if not test_lv['thinpool'] and not thinpool: break else: module.fail_json( msg="Snapshots of thin pool LVs are not supported.") else: module.fail_json( msg="Snapshot origin LV %s does not exist in volume group %s." % (lv, vg)) check_lv = snapshot elif thinpool: if lv: # Check thin volume pre-conditions for test_lv in lvs: if test_lv['name'] == thinpool: break else: module.fail_json( msg="Thin pool LV %s does not exist in volume group %s." % (thinpool, vg)) check_lv = lv else: check_lv = thinpool else: check_lv = lv for test_lv in lvs: if test_lv['name'] in (check_lv, check_lv.rsplit('/', 1)[-1]): this_lv = test_lv break else: this_lv = None msg = '' if this_lv is None: if state == 'present': # Require size argument except for snapshot of thin volumes if (lv or thinpool) and not size: for test_lv in lvs: if test_lv['name'] == lv and test_lv[ 'thinvol'] and snapshot: break else: module.fail_json(msg="No size given.") # create LV lvcreate_cmd = module.get_bin_path("lvcreate", required=True) if snapshot is not None: if size: cmd = "%s %s %s -%s %s%s -s -n %s %s %s/%s" % ( lvcreate_cmd, test_opt, yesopt, size_opt, size, size_unit, snapshot, opts, vg, lv) else: cmd = "%s %s %s -s -n %s %s %s/%s" % ( lvcreate_cmd, test_opt, yesopt, snapshot, opts, vg, lv) elif thinpool and lv: if size_opt == 'l': module.fail_json( changed=False, msg="Thin volume sizing with percentage not supported." ) size_opt = 'V' cmd = "%s %s -n %s -%s %s%s %s -T %s/%s" % ( lvcreate_cmd, yesopt, lv, size_opt, size, size_unit, opts, vg, thinpool) elif thinpool and not lv: cmd = "%s %s -%s %s%s %s -T %s/%s" % ( lvcreate_cmd, yesopt, size_opt, size, size_unit, opts, vg, thinpool) else: cmd = "%s %s %s -n %s -%s %s%s %s %s %s" % ( lvcreate_cmd, test_opt, yesopt, lv, size_opt, size, size_unit, opts, vg, pvs) rc, _, err = module.run_command(cmd) if rc == 0: changed = True else: module.fail_json(msg="Creating logical volume '%s' failed" % lv, rc=rc, err=err) else: if state == 'absent': # remove LV if not force: module.fail_json( msg= "Sorry, no removal of logical volume %s without force=yes." % (this_lv['name'])) lvremove_cmd = module.get_bin_path("lvremove", required=True) rc, _, err = module.run_command( "%s %s --force %s/%s" % (lvremove_cmd, test_opt, vg, this_lv['name'])) if rc == 0: module.exit_json(changed=True) else: module.fail_json(msg="Failed to remove logical volume %s" % (lv), rc=rc, err=err) elif not size: pass elif size_opt == 'l': # Resize LV based on % value tool = None size_free = this_vg['free'] if size_whole == 'VG' or size_whole == 'PVS': size_requested = size_percent * this_vg['size'] / 100 else: # size_whole == 'FREE': size_requested = size_percent * this_vg['free'] / 100 if '+' in size: size_requested += this_lv['size'] if this_lv['size'] < size_requested: if (size_free > 0) and (('+' not in size) or (size_free >= (size_requested - this_lv['size']))): tool = module.get_bin_path("lvextend", required=True) else: module.fail_json( msg= "Logical Volume %s could not be extended. Not enough free space left (%s%s required / %s%s available)" % (this_lv['name'], (size_requested - this_lv['size']), unit, size_free, unit)) elif shrink and this_lv['size'] > size_requested + this_vg[ 'ext_size']: # more than an extent too large if size_requested == 0: module.fail_json( msg="Sorry, no shrinking of %s to 0 permitted." % (this_lv['name'])) elif not force: module.fail_json( msg="Sorry, no shrinking of %s without force=yes" % (this_lv['name'])) else: tool = module.get_bin_path("lvreduce", required=True) tool = '%s %s' % (tool, '--force') if tool: if resizefs: tool = '%s %s' % (tool, '--resizefs') cmd = "%s %s -%s %s%s %s/%s %s" % (tool, test_opt, size_opt, size, size_unit, vg, this_lv['name'], pvs) rc, out, err = module.run_command(cmd) if "Reached maximum COW size" in out: module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err, out=out) elif rc == 0: changed = True msg = "Volume %s resized to %s%s" % (this_lv['name'], size_requested, unit) elif "matches existing size" in err: module.exit_json(changed=False, vg=vg, lv=this_lv['name'], size=this_lv['size']) elif "not larger than existing size" in err: module.exit_json( changed=False, vg=vg, lv=this_lv['name'], size=this_lv['size'], msg="Original size is larger than requested size", err=err) else: module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err) else: # resize LV based on absolute values tool = None if float(size) > this_lv['size']: tool = module.get_bin_path("lvextend", required=True) elif shrink and float(size) < this_lv['size']: if float(size) == 0: module.fail_json( msg="Sorry, no shrinking of %s to 0 permitted." % (this_lv['name'])) if not force: module.fail_json( msg="Sorry, no shrinking of %s without force=yes." % (this_lv['name'])) else: tool = module.get_bin_path("lvreduce", required=True) tool = '%s %s' % (tool, '--force') if tool: if resizefs: tool = '%s %s' % (tool, '--resizefs') cmd = "%s %s -%s %s%s %s/%s %s" % (tool, test_opt, size_opt, size, size_unit, vg, this_lv['name'], pvs) rc, out, err = module.run_command(cmd) if "Reached maximum COW size" in out: module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err, out=out) elif rc == 0: changed = True elif "matches existing size" in err: module.exit_json(changed=False, vg=vg, lv=this_lv['name'], size=this_lv['size']) elif "not larger than existing size" in err: module.exit_json( changed=False, vg=vg, lv=this_lv['name'], size=this_lv['size'], msg="Original size is larger than requested size", err=err) else: module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err) if this_lv is not None: if active: lvchange_cmd = module.get_bin_path("lvchange", required=True) rc, _, err = module.run_command( "%s -ay %s/%s" % (lvchange_cmd, vg, this_lv['name'])) if rc == 0: module.exit_json(changed=((not this_lv['active']) or changed), vg=vg, lv=this_lv['name'], size=this_lv['size']) else: module.fail_json(msg="Failed to activate logical volume %s" % (lv), rc=rc, err=err) else: lvchange_cmd = module.get_bin_path("lvchange", required=True) rc, _, err = module.run_command( "%s -an %s/%s" % (lvchange_cmd, vg, this_lv['name'])) if rc == 0: module.exit_json(changed=(this_lv['active'] or changed), vg=vg, lv=this_lv['name'], size=this_lv['size']) else: module.fail_json(msg="Failed to deactivate logical volume %s" % (lv), rc=rc, err=err) module.exit_json(changed=changed, msg=msg)
def main(): module = AnsibleModule( argument_spec=dict( host=dict(type='str', default='127.0.0.1'), timeout=dict(type='int', default=300), connect_timeout=dict(type='int', default=5), delay=dict(type='int', default=0), port=dict(type='int'), active_connection_states=dict(type='list', default=['ESTABLISHED', 'FIN_WAIT1', 'FIN_WAIT2', 'SYN_RECV', 'SYN_SENT', 'TIME_WAIT']), path=dict(type='path'), search_regex=dict(type='str'), state=dict(type='str', default='started', choices=['absent', 'drained', 'present', 'started', 'stopped']), exclude_hosts=dict(type='list'), sleep=dict(type='int', default=1), msg=dict(type='str'), ), ) host = module.params['host'] timeout = module.params['timeout'] connect_timeout = module.params['connect_timeout'] delay = module.params['delay'] port = module.params['port'] state = module.params['state'] path = module.params['path'] search_regex = module.params['search_regex'] msg = module.params['msg'] if search_regex is not None: compiled_search_re = re.compile(search_regex, re.MULTILINE) else: compiled_search_re = None match_groupdict = {} match_groups = () if port and path: module.fail_json(msg="port and path parameter can not both be passed to wait_for", elapsed=0) if path and state == 'stopped': module.fail_json(msg="state=stopped should only be used for checking a port in the wait_for module", elapsed=0) if path and state == 'drained': module.fail_json(msg="state=drained should only be used for checking a port in the wait_for module", elapsed=0) if module.params['exclude_hosts'] is not None and state != 'drained': module.fail_json(msg="exclude_hosts should only be with state=drained", elapsed=0) for _connection_state in module.params['active_connection_states']: try: get_connection_state_id(_connection_state) except Exception: module.fail_json(msg="unknown active_connection_state (%s) defined" % _connection_state, elapsed=0) start = datetime.datetime.utcnow() if delay: time.sleep(delay) if not port and not path and state != 'drained': time.sleep(timeout) elif state in ['absent', 'stopped']: # first wait for the stop condition end = start + datetime.timedelta(seconds=timeout) while datetime.datetime.utcnow() < end: if path: try: if not os.access(path, os.F_OK): break except IOError: break elif port: try: s = socket.create_connection((host, port), connect_timeout) s.shutdown(socket.SHUT_RDWR) s.close() except Exception: break # Conditions not yet met, wait and try again time.sleep(module.params['sleep']) else: elapsed = datetime.datetime.utcnow() - start if port: module.fail_json(msg=msg or "Timeout when waiting for %s:%s to stop." % (host, port), elapsed=elapsed.seconds) elif path: module.fail_json(msg=msg or "Timeout when waiting for %s to be absent." % (path), elapsed=elapsed.seconds) elif state in ['started', 'present']: # wait for start condition end = start + datetime.timedelta(seconds=timeout) while datetime.datetime.utcnow() < end: if path: try: os.stat(path) except OSError as e: # If anything except file not present, throw an error if e.errno != 2: elapsed = datetime.datetime.utcnow() - start module.fail_json(msg=msg or "Failed to stat %s, %s" % (path, e.strerror), elapsed=elapsed.seconds) # file doesn't exist yet, so continue else: # File exists. Are there additional things to check? if not compiled_search_re: # nope, succeed! break try: f = open(path) try: search = re.search(compiled_search_re, f.read()) if search: if search.groupdict(): match_groupdict = search.groupdict() if search.groups(): match_groups = search.groups() break finally: f.close() except IOError: pass elif port: alt_connect_timeout = math.ceil(_timedelta_total_seconds(end - datetime.datetime.utcnow())) try: s = socket.create_connection((host, port), min(connect_timeout, alt_connect_timeout)) except Exception: # Failed to connect by connect_timeout. wait and try again pass else: # Connected -- are there additional conditions? if compiled_search_re: data = '' matched = False while datetime.datetime.utcnow() < end: max_timeout = math.ceil(_timedelta_total_seconds(end - datetime.datetime.utcnow())) (readable, w, e) = select.select([s], [], [], max_timeout) if not readable: # No new data. Probably means our timeout # expired continue response = s.recv(1024) if not response: # Server shutdown break data += to_native(response, errors='surrogate_or_strict') if re.search(compiled_search_re, data): matched = True break # Shutdown the client socket try: s.shutdown(socket.SHUT_RDWR) except socket.error as e: if e.errno != errno.ENOTCONN: raise # else, the server broke the connection on its end, assume it's not ready else: s.close() if matched: # Found our string, success! break else: # Connection established, success! try: s.shutdown(socket.SHUT_RDWR) except socket.error as e: if e.errno != errno.ENOTCONN: raise # else, the server broke the connection on its end, assume it's not ready else: s.close() break # Conditions not yet met, wait and try again time.sleep(module.params['sleep']) else: # while-else # Timeout expired elapsed = datetime.datetime.utcnow() - start if port: if search_regex: module.fail_json(msg=msg or "Timeout when waiting for search string %s in %s:%s" % (search_regex, host, port), elapsed=elapsed.seconds) else: module.fail_json(msg=msg or "Timeout when waiting for %s:%s" % (host, port), elapsed=elapsed.seconds) elif path: if search_regex: module.fail_json(msg=msg or "Timeout when waiting for search string %s in %s" % (search_regex, path), elapsed=elapsed.seconds) else: module.fail_json(msg=msg or "Timeout when waiting for file %s" % (path), elapsed=elapsed.seconds) elif state == 'drained': # wait until all active connections are gone end = start + datetime.timedelta(seconds=timeout) tcpconns = TCPConnectionInfo(module) while datetime.datetime.utcnow() < end: try: if tcpconns.get_active_connections_count() == 0: break except IOError: pass # Conditions not yet met, wait and try again time.sleep(module.params['sleep']) else: elapsed = datetime.datetime.utcnow() - start module.fail_json(msg=msg or "Timeout when waiting for %s:%s to drain" % (host, port), elapsed=elapsed.seconds) elapsed = datetime.datetime.utcnow() - start module.exit_json(state=state, port=port, search_regex=search_regex, match_groups=match_groups, match_groupdict=match_groupdict, path=path, elapsed=elapsed.seconds)
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 platform.system().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 platform.system().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 main(): # define the available arguments/parameters that a user can pass to # the module fixed_ip_arg_spec = dict( mac=dict(type='str'), ip=dict(type='str'), name=dict(type='str'), ) reserved_ip_arg_spec = dict( start=dict(type='str'), end=dict(type='str'), comment=dict(type='str'), ) argument_spec = meraki_argument_spec() argument_spec.update( net_id=dict(type='str'), net_name=dict(type='str'), name=dict(type='str'), subnet=dict(type='str'), gateway_ip=dict(type='str'), state=dict(type='str', default='present', choices=['absent', 'present', 'query']), fixed_ip_assignments=dict(type='list', elements='dict', options=fixed_ip_arg_spec), reserved_ip_ranges=dict(type='list', elements='dict', options=reserved_ip_arg_spec), route_id=dict(type='str'), enabled=dict(type='bool'), ) # the AnsibleModule object will be our abstraction working with Ansible # this includes instantiation, a couple of common attr would be the # args/params passed to the execution, as well as if the module # supports check mode module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) meraki = MerakiModule(module, function='static_route') module.params['follow_redirects'] = 'all' payload = None query_urls = {'static_route': '/networks/{net_id}/staticRoutes'} query_one_urls = { 'static_route': '/networks/{net_id}/staticRoutes/{route_id}' } create_urls = {'static_route': '/networks/{net_id}/staticRoutes/'} update_urls = { 'static_route': '/networks/{net_id}/staticRoutes/{route_id}' } delete_urls = { 'static_route': '/networks/{net_id}/staticRoutes/{route_id}' } meraki.url_catalog['get_all'].update(query_urls) meraki.url_catalog['get_one'].update(query_one_urls) meraki.url_catalog['create'] = create_urls meraki.url_catalog['update'] = update_urls meraki.url_catalog['delete'] = delete_urls if not meraki.params['org_name'] and not meraki.params['org_id']: meraki.fail_json( msg="Parameters 'org_name' or 'org_id' parameters are required") if not meraki.params['net_name'] and not meraki.params['net_id']: meraki.fail_json( msg="Parameters 'net_name' or 'net_id' parameters are required") if meraki.params['net_name'] and meraki.params['net_id']: meraki.fail_json(msg="'net_name' and 'net_id' are mutually exclusive") # Construct payload if meraki.params['state'] == 'present': payload = dict() if meraki.params['net_name']: payload['name'] = meraki.params['net_name'] # manipulate or modify the state as needed (this is going to be the # part where your module will do what it needs to do) org_id = meraki.params['org_id'] if not org_id: org_id = meraki.get_org_id(meraki.params['org_name']) net_id = meraki.params['net_id'] if net_id is None: nets = meraki.get_nets(org_id=org_id) net_id = meraki.get_net_id(net_name=meraki.params['net_name'], data=nets) if meraki.params['state'] == 'query': if meraki.params['route_id'] is not None: meraki.result['data'] = get_static_route(meraki, net_id, meraki.params['route_id']) else: meraki.result['data'] = get_static_routes(meraki, net_id) elif meraki.params['state'] == 'present': payload = { 'name': meraki.params['name'], 'subnet': meraki.params['subnet'], 'gatewayIp': meraki.params['gateway_ip'], } if meraki.params['fixed_ip_assignments'] is not None: payload['fixedIpAssignments'] = fixed_ip_factory( meraki, meraki.params['fixed_ip_assignments']) if meraki.params['reserved_ip_ranges'] is not None: payload['reservedIpRanges'] = meraki.params['reserved_ip_ranges'] # meraki.fail_json(msg="payload", payload=payload) if meraki.params['enabled'] is not None: payload['enabled'] = meraki.params['enabled'] if meraki.params['route_id']: existing_route = get_static_route(meraki, net_id, meraki.params['route_id']) proposed = existing_route.copy() proposed.update(payload) if module.check_mode: meraki.result['data'] = proposed meraki.result['data'].update(payload) meraki.exit_json(**meraki.result) if meraki.is_update_required(existing_route, proposed, optional_ignore=['id']): path = meraki.construct_path( 'update', net_id=net_id, custom={'route_id': meraki.params['route_id']}) meraki.result['data'] = meraki.request( path, method="PUT", payload=json.dumps(payload)) meraki.result['changed'] = True else: meraki.result['data'] = existing_route else: if module.check_mode: meraki.result['data'] = payload meraki.exit_json(**meraki.result) path = meraki.construct_path('create', net_id=net_id) meraki.result['data'] = meraki.request(path, method="POST", payload=json.dumps(payload)) meraki.result['changed'] = True elif meraki.params['state'] == 'absent': if module.check_mode: meraki.exit_json(**meraki.result) path = meraki.construct_path( 'delete', net_id=net_id, custom={'route_id': meraki.params['route_id']}) meraki.result['data'] = meraki.request(path, method='DELETE') meraki.result['changed'] = True # in the event of a successful module execution, you will want to # simple AnsibleModule.exit_json(), passing the key/value results meraki.exit_json(**meraki.result)
def main(): module = AnsibleModule( argument_spec=dict(list_all=dict(required=False, type='bool', default=False), name=dict(type='str'), repo=dict(type='path'), scope=dict(required=False, type='str', choices=['local', 'global', 'system']), state=dict(required=False, type='str', default='present', choices=['present', 'absent']), value=dict(required=False)), mutually_exclusive=[['list_all', 'name'], ['list_all', 'value'], ['list_all', 'state']], required_if=[('scope', 'local', ['repo'])], required_one_of=[['list_all', 'name']], supports_check_mode=True, ) git_path = module.get_bin_path('git', True) params = module.params # We check error message for a pattern, so we need to make sure the messages appear in the form we're expecting. # Set the locale to C to ensure consistent messages. module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C') if params['name']: name = params['name'] else: name = None if params['scope']: scope = params['scope'] elif params['list_all']: scope = None else: scope = 'system' if params['state'] == 'absent': unset = 'unset' params['value'] = None else: unset = None if params['value']: new_value = params['value'] else: new_value = None args = [git_path, "config", "--includes"] if params['list_all']: args.append('-l') if scope: args.append("--" + scope) if name: args.append(name) if scope == 'local': dir = params['repo'] elif params['list_all'] and params['repo']: # Include local settings from a specific repo when listing all available settings dir = params['repo'] else: # Run from root directory to avoid accidentally picking up any local config settings dir = "/" (rc, out, err) = module.run_command(' '.join(args), cwd=dir) if params[ 'list_all'] and scope and rc == 128 and 'unable to read config file' in err: # This just means nothing has been set at the given scope module.exit_json(changed=False, msg='', config_values={}) elif rc >= 2: # If the return code is 1, it just means the option hasn't been set yet, which is fine. module.fail_json(rc=rc, msg=err, cmd=' '.join(args)) if params['list_all']: values = out.rstrip().splitlines() config_values = {} for value in values: k, v = value.split('=', 1) config_values[k] = v module.exit_json(changed=False, msg='', config_values=config_values) elif not new_value and not unset: module.exit_json(changed=False, msg='', config_value=out.rstrip()) elif unset and not out: module.exit_json(changed=False, msg='no setting to unset') else: old_value = out.rstrip() if old_value == new_value: module.exit_json(changed=False, msg="") if not module.check_mode: if unset: args.insert(len(args) - 1, "--" + unset) cmd = ' '.join(args) else: new_value_quoted = shlex_quote(new_value) cmd = ' '.join(args + [new_value_quoted]) (rc, out, err) = module.run_command(cmd, cwd=dir) if err: module.fail_json(rc=rc, msg=err, cmd=cmd) module.exit_json(msg='setting changed', diff=dict(before_header=' '.join(args), before=old_value + "\n", after_header=' '.join(args), after=(new_value or '') + "\n"), changed=True)
class ElementSWClusterPair(object): """ class to handle cluster pairing operations """ def __init__(self): """ Setup Ansible parameters and ElementSW connection """ self.argument_spec = netapp_utils.ontap_sf_host_argument_spec() self.argument_spec.update( dict(state=dict(required=False, choices=['present', 'absent'], default='present'), dest_mvip=dict(required=True, type='str'), dest_username=dict(required=False, type='str'), dest_password=dict(required=False, type='str', no_log=True))) self.module = AnsibleModule(argument_spec=self.argument_spec, supports_check_mode=True) if HAS_SF_SDK is False: self.module.fail_json( msg="Unable to import the SolidFire Python SDK") else: self.elem = netapp_utils.create_sf_connection(module=self.module) self.elementsw_helper = NaElementSWModule(self.elem) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) # get element_sw_connection for destination cluster # overwrite existing source host, user and password with destination credentials self.module.params['hostname'] = self.parameters['dest_mvip'] # username and password is same as source, # if dest_username and dest_password aren't specified if self.parameters.get('dest_username'): self.module.params['username'] = self.parameters['dest_username'] if self.parameters.get('dest_password'): self.module.params['password'] = self.parameters['dest_password'] self.dest_elem = netapp_utils.create_sf_connection(module=self.module) self.dest_elementsw_helper = NaElementSWModule(self.dest_elem) def check_if_already_paired(self, paired_clusters, hostname): for pair in paired_clusters.cluster_pairs: if pair.mvip == hostname: return pair.cluster_pair_id return None def get_src_pair_id(self): """ Check for idempotency """ # src cluster and dest cluster exist paired_clusters = self.elem.list_cluster_pairs() return self.check_if_already_paired(paired_clusters, self.parameters['dest_mvip']) def get_dest_pair_id(self): """ Getting destination cluster_pair_id """ paired_clusters = self.dest_elem.list_cluster_pairs() return self.check_if_already_paired(paired_clusters, self.parameters['hostname']) def pair_clusters(self): """ Start cluster pairing on source, and complete on target cluster """ try: pair_key = self.elem.start_cluster_pairing() self.dest_elem.complete_cluster_pairing( cluster_pairing_key=pair_key.cluster_pairing_key) except solidfire.common.ApiServerError as err: self.module.fail_json( msg="Error pairing cluster %s and %s" % (self.parameters['hostname'], self.parameters['dest_mvip']), exception=to_native(err)) def unpair_clusters(self, pair_id_source, pair_id_dest): """ Delete cluster pair """ try: self.elem.remove_cluster_pair(cluster_pair_id=pair_id_source) self.dest_elem.remove_cluster_pair(cluster_pair_id=pair_id_dest) except solidfire.common.ApiServerError as err: self.module.fail_json( msg="Error unpairing cluster %s and %s" % (self.parameters['hostname'], self.parameters['dest_mvip']), exception=to_native(err)) def apply(self): """ Call create / delete cluster pair methods """ pair_id_source = self.get_src_pair_id() # If already paired, find the cluster_pair_id of destination cluster if pair_id_source: pair_id_dest = self.get_dest_pair_id() # calling helper to determine action cd_action = self.na_helper.get_cd_action(pair_id_source, self.parameters) if cd_action == "create": self.pair_clusters() elif cd_action == "delete": self.unpair_clusters(pair_id_source, pair_id_dest) self.module.exit_json(changed=self.na_helper.changed)
def main(): module = AnsibleModule( argument_spec=dict( name=dict(type='str', required=True), state=dict(type='str', choices=[ 'killed', 'once', 'reloaded', 'restarted', 'started', 'stopped' ]), enabled=dict(type='bool'), downed=dict(type='bool'), service_dir=dict(type='str', default='/service'), service_src=dict(type='str', default='/etc/service'), ), supports_check_mode=True, ) module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C') state = module.params['state'] enabled = module.params['enabled'] downed = module.params['downed'] svc = Svc(module) changed = False orig_state = svc.report() if enabled is not None and enabled != svc.enabled: changed = True if not module.check_mode: try: if enabled: svc.enable() else: svc.disable() except (OSError, IOError) as e: module.fail_json(msg="Could not change service link: %s" % to_native(e)) if state is not None and state != svc.state: changed = True if not module.check_mode: getattr(svc, state[:-2])() if downed is not None and downed != svc.downed: changed = True if not module.check_mode: d_file = "%s/down" % svc.svc_full try: if downed: open(d_file, "a").close() else: os.unlink(d_file) except (OSError, IOError) as e: module.fail_json(msg="Could not change downed file: %s " % (to_native(e))) module.exit_json(changed=changed, svc=svc.report())
def main(): fields = { "host": { "required": False, "type": "str" }, "username": { "required": False, "type": "str" }, "password": { "required": False, "type": "str", "default": "", "no_log": True }, "vdom": { "required": False, "type": "str", "default": "root" }, "https": { "required": False, "type": "bool", "default": True }, "ssl_verify": { "required": False, "type": "bool", "default": True }, "state": { "required": False, "type": "str", "choices": ["present", "absent"] }, "vpn_ipsec_manualkey": { "required": False, "type": "dict", "default": None, "options": { "state": { "required": False, "type": "str", "choices": ["present", "absent"] }, "authentication": { "required": False, "type": "str", "choices": ["null", "md5", "sha1", "sha256", "sha384", "sha512"] }, "authkey": { "required": False, "type": "str" }, "enckey": { "required": False, "type": "str" }, "encryption": { "required": False, "type": "str", "choices": ["null", "des"] }, "interface": { "required": False, "type": "str" }, "local_gw": { "required": False, "type": "str" }, "localspi": { "required": False, "type": "str" }, "name": { "required": True, "type": "str" }, "remote_gw": { "required": False, "type": "str" }, "remotespi": { "required": False, "type": "str" } } } } module = AnsibleModule(argument_spec=fields, supports_check_mode=False) # legacy_mode refers to using fortiosapi instead of HTTPAPI legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 'username' in module.params and module.params['username'] is not None and \ 'password' in module.params and module.params['password'] is not None if not legacy_mode: if module._socket_path: connection = Connection(module._socket_path) fos = FortiOSHandler(connection) is_error, has_changed, result = fortios_vpn_ipsec( module.params, fos) else: module.fail_json(**FAIL_SOCKET_MSG) else: try: from fortiosapi import FortiOSAPI except ImportError: module.fail_json(msg="fortiosapi module is required") fos = FortiOSAPI() login(module.params, fos) is_error, has_changed, result = fortios_vpn_ipsec(module.params, fos) fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) else: module.fail_json(msg="Error in repo", meta=result)
def main(): fields = { "host": { "required": False, "type": "str" }, "username": { "required": False, "type": "str" }, "password": { "required": False, "type": "str", "default": "", "no_log": True }, "vdom": { "required": False, "type": "str", "default": "root" }, "https": { "required": False, "type": "bool", "default": True }, "ssl_verify": { "required": False, "type": "bool", "default": True }, "system_ha": { "required": False, "type": "dict", "default": None, "options": { "arps": { "required": False, "type": "int" }, "arps_interval": { "required": False, "type": "int" }, "authentication": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "cpu_threshold": { "required": False, "type": "str" }, "encryption": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "ftp_proxy_threshold": { "required": False, "type": "str" }, "gratuitous_arps": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "group_id": { "required": False, "type": "int" }, "group_name": { "required": False, "type": "str" }, "ha_direct": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "ha_eth_type": { "required": False, "type": "str" }, "ha_mgmt_interfaces": { "required": False, "type": "list", "options": { "dst": { "required": False, "type": "str" }, "gateway": { "required": False, "type": "str" }, "gateway6": { "required": False, "type": "str" }, "id": { "required": True, "type": "int" }, "interface": { "required": False, "type": "str" } } }, "ha_mgmt_status": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "ha_uptime_diff_margin": { "required": False, "type": "int" }, "hb_interval": { "required": False, "type": "int" }, "hb_lost_threshold": { "required": False, "type": "int" }, "hbdev": { "required": False, "type": "str" }, "hc_eth_type": { "required": False, "type": "str" }, "hello_holddown": { "required": False, "type": "int" }, "http_proxy_threshold": { "required": False, "type": "str" }, "imap_proxy_threshold": { "required": False, "type": "str" }, "inter_cluster_session_sync": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "key": { "required": False, "type": "str" }, "l2ep_eth_type": { "required": False, "type": "str" }, "link_failed_signal": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "load_balance_all": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "memory_compatible_mode": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "memory_threshold": { "required": False, "type": "str" }, "mode": { "required": False, "type": "str", "choices": ["standalone", "a-a", "a-p"] }, "monitor": { "required": False, "type": "str" }, "multicast_ttl": { "required": False, "type": "int" }, "nntp_proxy_threshold": { "required": False, "type": "str" }, "override": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "override_wait_time": { "required": False, "type": "int" }, "password": { "required": False, "type": "str" }, "pingserver_failover_threshold": { "required": False, "type": "int" }, "pingserver_flip_timeout": { "required": False, "type": "int" }, "pingserver_monitor_interface": { "required": False, "type": "str" }, "pingserver_slave_force_reset": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "pop3_proxy_threshold": { "required": False, "type": "str" }, "priority": { "required": False, "type": "int" }, "route_hold": { "required": False, "type": "int" }, "route_ttl": { "required": False, "type": "int" }, "route_wait": { "required": False, "type": "int" }, "schedule": { "required": False, "type": "str", "choices": [ "none", "hub", "leastconnection", "round-robin", "weight-round-robin", "random", "ip", "ipport" ] }, "secondary_vcluster": { "required": False, "type": "dict", "options": { "monitor": { "required": False, "type": "str" }, "override": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "override_wait_time": { "required": False, "type": "int" }, "pingserver_failover_threshold": { "required": False, "type": "int" }, "pingserver_monitor_interface": { "required": False, "type": "str" }, "pingserver_slave_force_reset": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "priority": { "required": False, "type": "int" }, "vcluster_id": { "required": False, "type": "int" }, "vdom": { "required": False, "type": "str" } } }, "session_pickup": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "session_pickup_connectionless": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "session_pickup_delay": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "session_pickup_expectation": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "session_pickup_nat": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "session_sync_dev": { "required": False, "type": "str" }, "smtp_proxy_threshold": { "required": False, "type": "str" }, "standalone_config_sync": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "standalone_mgmt_vdom": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "sync_config": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "sync_packet_balance": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "unicast_hb": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "unicast_hb_netmask": { "required": False, "type": "str" }, "unicast_hb_peerip": { "required": False, "type": "str" }, "uninterruptible_upgrade": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "vcluster_id": { "required": False, "type": "int" }, "vcluster2": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "vdom": { "required": False, "type": "str" }, "weight": { "required": False, "type": "str" } } } } module = AnsibleModule(argument_spec=fields, supports_check_mode=False) # legacy_mode refers to using fortiosapi instead of HTTPAPI legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 'username' in module.params and module.params['username'] is not None and \ 'password' in module.params and module.params['password'] is not None if not legacy_mode: if module._socket_path: connection = Connection(module._socket_path) fos = FortiOSHandler(connection) is_error, has_changed, result = fortios_system(module.params, fos) else: module.fail_json(**FAIL_SOCKET_MSG) else: try: from fortiosapi import FortiOSAPI except ImportError: module.fail_json(msg="fortiosapi module is required") fos = FortiOSAPI() login(module.params, fos) is_error, has_changed, result = fortios_system(module.params, fos) fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) else: module.fail_json(msg="Error in repo", meta=result)
class NetAppontapExportRule(object): ''' object initialize and class methods ''' def __init__(self): self.argument_spec = netapp_utils.na_ontap_host_argument_spec() self.argument_spec.update( dict( state=dict(required=False, type='str', choices=['present', 'absent'], default='present'), name=dict(required=True, type='str', aliases=['policy_name']), protocol=dict(required=False, type='list', default=None, choices=[ 'any', 'nfs', 'nfs3', 'nfs4', 'cifs', 'flexcache' ]), client_match=dict(required=False, type='list'), ro_rule=dict(required=False, type='list', default=None, choices=[ 'any', 'none', 'never', 'krb5', 'krb5i', 'krb5p', 'ntlm', 'sys' ]), rw_rule=dict(required=False, type='list', default=None, choices=[ 'any', 'none', 'never', 'krb5', 'krb5i', 'krb5p', 'ntlm', 'sys' ]), super_user_security=dict(required=False, type='list', default=None, choices=[ 'any', 'none', 'never', 'krb5', 'krb5i', 'krb5p', 'ntlm', 'sys' ]), allow_suid=dict(required=False, type='bool'), rule_index=dict(required=False, type='int'), vserver=dict(required=True, type='str'), )) self.module = AnsibleModule(argument_spec=self.argument_spec, supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) self.set_playbook_zapi_key_map() if HAS_NETAPP_LIB is False: self.module.fail_json( msg="the python NetApp-Lib module is required") else: self.server = netapp_utils.setup_na_ontap_zapi( module=self.module, vserver=self.parameters['vserver']) def set_playbook_zapi_key_map(self): self.na_helper.zapi_string_keys = { 'client_match': 'client-match', 'name': 'policy-name' } self.na_helper.zapi_list_keys = { 'protocol': ('protocol', 'access-protocol'), 'ro_rule': ('ro-rule', 'security-flavor'), 'rw_rule': ('rw-rule', 'security-flavor'), 'super_user_security': ('super-user-security', 'security-flavor'), } self.na_helper.zapi_bool_keys = { 'allow_suid': 'is-allow-set-uid-enabled' } self.na_helper.zapi_int_keys = {'rule_index': 'rule-index'} def set_query_parameters(self): """ Return dictionary of query parameters and :return: """ query = { 'policy-name': self.parameters['name'], 'vserver': self.parameters['vserver'] } if self.parameters.get('rule_index'): query['rule-index'] = self.parameters['rule_index'] elif self.parameters.get('client_match'): query['client-match'] = self.parameters['client_match'] else: self.module.fail_json( msg= "Need to specify at least one of the rule_index and client_match option." ) attributes = {'query': {'export-rule-info': query}} return attributes def get_export_policy_rule(self): """ Return details about the export policy rule :param: name : Name of the export_policy :return: Details about the export_policy. None if not found. :rtype: dict """ current, result = None, None rule_iter = netapp_utils.zapi.NaElement('export-rule-get-iter') rule_iter.translate_struct(self.set_query_parameters()) try: result = self.server.invoke_successfully(rule_iter, True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json( msg='Error getting export policy rule %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) if result is not None and \ result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1: current = dict() rule_info = result.get_child_by_name( 'attributes-list').get_child_by_name('export-rule-info') for item_key, zapi_key in self.na_helper.zapi_string_keys.items(): current[item_key] = rule_info.get_child_content(zapi_key) for item_key, zapi_key in self.na_helper.zapi_bool_keys.items(): current[item_key] = self.na_helper.get_value_for_bool( from_zapi=True, value=rule_info[zapi_key]) for item_key, zapi_key in self.na_helper.zapi_int_keys.items(): current[item_key] = self.na_helper.get_value_for_int( from_zapi=True, value=rule_info[zapi_key]) for item_key, zapi_key in self.na_helper.zapi_list_keys.items(): parent, dummy = zapi_key current[item_key] = self.na_helper.get_value_for_list( from_zapi=True, zapi_parent=rule_info.get_child_by_name(parent)) current['num_records'] = int( result.get_child_content('num-records')) if not self.parameters.get('rule_index'): self.parameters['rule_index'] = current['rule_index'] return current def get_export_policy(self): """ Return details about the export-policy :param: name : Name of the export-policy :return: Details about the export-policy. None if not found. :rtype: dict """ export_policy_iter = netapp_utils.zapi.NaElement( 'export-policy-get-iter') attributes = { 'query': { 'export-policy-info': { 'policy-name': self.parameters['name'], 'vserver': self.parameters['vserver'] } } } export_policy_iter.translate_struct(attributes) try: result = self.server.invoke_successfully(export_policy_iter, True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error getting export policy %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) if result.get_child_by_name('num-records') and int( result.get_child_content('num-records')) == 1: return result return None def add_parameters_for_create_or_modify(self, na_element_object, values): """ Add children node for create or modify NaElement object :param na_element_object: modify or create NaElement object :param values: dictionary of cron values to be added :return: None """ for key in values: if key in self.na_helper.zapi_string_keys: zapi_key = self.na_helper.zapi_string_keys.get(key) na_element_object[zapi_key] = values[key] elif key in self.na_helper.zapi_list_keys: parent_key, child_key = self.na_helper.zapi_list_keys.get(key) na_element_object.add_child_elem( self.na_helper.get_value_for_list(from_zapi=False, zapi_parent=parent_key, zapi_child=child_key, data=values[key])) elif key in self.na_helper.zapi_int_keys: zapi_key = self.na_helper.zapi_int_keys.get(key) na_element_object[zapi_key] = self.na_helper.get_value_for_int( from_zapi=False, value=values[key]) elif key in self.na_helper.zapi_bool_keys: zapi_key = self.na_helper.zapi_bool_keys.get(key) na_element_object[ zapi_key] = self.na_helper.get_value_for_bool( from_zapi=False, value=values[key]) def create_export_policy_rule(self): """ create rule for the export policy. """ for key in ['client_match', 'ro_rule', 'rw_rule']: if self.parameters.get(key) is None: self.module.fail_json( msg= 'Error: Missing required param for creating export policy rule %s' % key) export_rule_create = netapp_utils.zapi.NaElement('export-rule-create') self.add_parameters_for_create_or_modify(export_rule_create, self.parameters) try: self.server.invoke_successfully(export_rule_create, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json( msg='Error creating export policy rule %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) def create_export_policy(self): """ Creates an export policy """ export_policy_create = netapp_utils.zapi.NaElement.create_node_with_children( 'export-policy-create', **{'policy-name': self.parameters['name']}) try: self.server.invoke_successfully(export_policy_create, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error creating export-policy %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) def delete_export_policy_rule(self, rule_index): """ delete rule for the export policy. """ export_rule_delete = netapp_utils.zapi.NaElement.create_node_with_children( 'export-rule-destroy', **{ 'policy-name': self.parameters['name'], 'rule-index': str(rule_index) }) try: self.server.invoke_successfully(export_rule_delete, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json( msg='Error deleting export policy rule %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) def modify_export_policy_rule(self, params): ''' Modify an existing export policy rule :param params: dict() of attributes with desired values :return: None ''' export_rule_modify = netapp_utils.zapi.NaElement.create_node_with_children( 'export-rule-modify', **{ 'policy-name': self.parameters['name'], 'rule-index': str(self.parameters['rule_index']) }) self.add_parameters_for_create_or_modify(export_rule_modify, params) try: self.server.invoke_successfully(export_rule_modify, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json( msg='Error modifying allow_suid %s: %s' % (self.parameters['allow_suid'], to_native(error)), exception=traceback.format_exc()) def autosupport_log(self): netapp_utils.ems_log_event("na_ontap_export_policy_rules", self.server) def apply(self): ''' Apply required action from the play''' self.autosupport_log() # convert client_match list to comma-separated string if self.parameters.get('client_match') is not None: self.parameters['client_match'] = ','.join( self.parameters['client_match']) self.parameters['client_match'] = self.parameters[ 'client_match'].replace(' ', '') current, modify = self.get_export_policy_rule(), None action = self.na_helper.get_cd_action(current, self.parameters) if action is None and self.parameters['state'] == 'present': modify = self.na_helper.get_modified_attributes( current, self.parameters) if self.na_helper.changed: if self.module.check_mode: pass else: # create export policy (if policy doesn't exist) only when changed=True if not self.get_export_policy(): self.create_export_policy() if action == 'create': self.create_export_policy_rule() elif action == 'delete': if current['num_records'] > 1: self.module.fail_json( msg='Multiple export policy rules exist.' 'Please specify a rule_index to delete') self.delete_export_policy_rule(current['rule_index']) elif modify: self.modify_export_policy_rule(modify) self.module.exit_json(changed=self.na_helper.changed)
def main(): argument_spec = dict( adom=dict(required=False, type="str", default="root"), device_unique_name=dict(required=True, type="str"), device_hostname=dict(required=False, type="str"), interface=dict(required=False, type="str"), interface_ip=dict(required=False, type="str"), interface_allow_access=dict(required=False, type="str"), install_config=dict(required=False, type="str", default="disable"), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=False, ) paramgram = { "device_unique_name": module.params["device_unique_name"], "device_hostname": module.params["device_hostname"], "interface": module.params["interface"], "interface_ip": module.params["interface_ip"], "interface_allow_access": module.params["interface_allow_access"], "install_config": module.params["install_config"], "adom": module.params["adom"] } module.paramgram = paramgram fmgr = None if module._socket_path: connection = Connection(module._socket_path) fmgr = FortiManagerHandler(connection, module) fmgr.tools = FMGRCommon() else: module.fail_json(**FAIL_SOCKET_MSG) # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION results = DEFAULT_RESULT_OBJ try: if paramgram["device_hostname"] is not None: results = update_device_hostname(fmgr, paramgram) fmgr.govern_response(module=module, results=results, ansible_facts=fmgr.construct_ansible_facts( results, module.params, paramgram)) if paramgram["interface_ip"] is not None or paramgram[ "interface_allow_access"] is not None: results = update_device_interface(fmgr, paramgram) fmgr.govern_response(module=module, results=results, ansible_facts=fmgr.construct_ansible_facts( results, module.params, paramgram)) if paramgram["install_config"] == "enable": results = exec_config(fmgr, paramgram) fmgr.govern_response(module=module, results=results, ansible_facts=fmgr.construct_ansible_facts( results, module.params, paramgram)) except Exception as err: raise FMGBaseException(err) return module.exit_json(**results[1])
def main(): """ This section is for arguments parsing """ module = AnsibleModule( argument_spec=dict( pn_cliusername=dict(required=False, type='str'), pn_clipassword=dict(required=False, type='str', no_log=True), pn_cliswitch=dict(required=False, type='str', default='local'), state=dict(type='str', default='present', choices=['present', 'absent']), pn_vrouter_name=dict(required=True, type='str'), pn_network_ip=dict(required=True, type='str'), pn_ospf_area=dict(type='str') ), required_if=( ['state', 'present', ['pn_network_ip', 'pn_ospf_area']], ['state', 'absent', ['pn_network_ip']] ) ) # Accessing the arguments state = module.params['state'] vrouter_name = module.params['pn_vrouter_name'] network_ip = module.params['pn_network_ip'] ospf_area = module.params['pn_ospf_area'] command = get_command_from_state(state) # Building the CLI command string cli = pn_cli(module) check_cli(module, cli) if state == 'present': if VROUTER_EXISTS is False: module.exit_json( skipped=True, msg='vRouter %s does not exist' % vrouter_name ) if NETWORK_EXISTS is True: module.exit_json( skipped=True, msg=('OSPF with network ip %s already exists on %s' % (network_ip, vrouter_name)) ) cli += (' %s vrouter-name %s network %s ospf-area %s' % (command, vrouter_name, network_ip, ospf_area)) if state == 'absent': if VROUTER_EXISTS is False: module.exit_json( skipped=True, msg='vRouter %s does not exist' % vrouter_name ) if NETWORK_EXISTS is False: module.exit_json( skipped=True, msg=('OSPF with network ip %s already exists on %s' % (network_ip, vrouter_name)) ) cli += (' %s vrouter-name %s network %s' % (command, vrouter_name, network_ip)) run_cli(module, cli)
def main(): argument_spec = dict( ip_address=dict(required=True, type='str'), password=dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME']), default="admin"), interval=dict(default=0.5), timeout=dict(), sync=dict(type='bool', default=True), description=dict(type='str'), commit_changes_by=dict(type='list'), commit_vsys=dict(type='list') ) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) if not HAS_LIB: module.fail_json(msg='pan-python is required for this module') ip_address = module.params["ip_address"] if not ip_address: module.fail_json(msg="ip_address should be specified") password = module.params["password"] if not password: module.fail_json(msg="password is required") username = module.params['username'] if not username: module.fail_json(msg="username is required") interval = module.params['interval'] timeout = module.params['timeout'] sync = module.params['sync'] xapi = pan.xapi.PanXapi( hostname=ip_address, api_username=username, api_password=password ) cmd = "<commit>" description = module.params["description"] if description: cmd += "<description>" + description + "</description>" commit_changes_by = module.params["commit_changes_by"] commit_vsys = module.params["commit_vsys"] if commit_changes_by or commit_vsys: cmd += "<partial>" if commit_changes_by: cmd += "<admin>" for admin in commit_changes_by: cmd += "<member>" + admin + "</member>" cmd += "</admin>" if commit_vsys: cmd += "<vsys>" for vsys in commit_vsys: cmd += "<member>" + vsys + "</member>" cmd += "</vsys>" cmd += "</partial><force></force>" cmd += "</commit>" xapi.commit( cmd=cmd, sync=sync, interval=interval, timeout=timeout ) try: result = xapi.xml_root().encode('utf-8') root = etree.fromstring(result) job_id = root.find('./result/job/id').text except AttributeError: job_id = None panos_commit_details = dict( status_text=xapi.status, status_code=xapi.status_code, status_detail=xapi.status_detail, job_id=job_id ) if "Commit failed" in xapi.status_detail: module.fail_json(msg=xapi.status_detail, panos_commit=panos_commit_details) if job_id: module.exit_json(changed=True, msg="Commit successful.", panos_commit=panos_commit_details) else: module.exit_json(changed=False, msg="No changes to commit.", panos_commit=panos_commit_details)
class NetAppONTAPFlexCache(object): """ Class with FlexCache methods """ def __init__(self): self.argument_spec = netapp_utils.na_ontap_host_argument_spec() self.argument_spec.update( dict( state=dict(required=False, type='str', choices=['present', 'absent'], default='present'), origin_volume=dict(required=False, type='str'), origin_vserver=dict(required=False, type='str'), origin_cluster=dict(required=False, type='str'), auto_provision_as=dict(required=False, type='str'), volume=dict(required=True, type='str'), junction_path=dict(required=False, type='str'), size=dict(required=False, type='int'), size_unit=dict(default='gb', choices=[ 'bytes', 'b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb' ], type='str'), vserver=dict(required=True, type='str'), aggr_list=dict(required=False, type='list'), aggr_list_multiplier=dict(required=False, type='int'), force_offline=dict(required=False, type='bool', default=False), force_unmount=dict(required=False, type='bool', default=False), time_out=dict(required=False, type='int', default=180), )) self.module = AnsibleModule(argument_spec=self.argument_spec, mutually_exclusive=[ ('aggr_list', 'auto_provision_as'), ], supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) if self.parameters.get('size'): self.parameters['size'] = self.parameters['size'] * \ netapp_utils.POW2_BYTE_MAP[self.parameters['size_unit']] # setup later if required self.origin_server = None if HAS_NETAPP_LIB is False: self.module.fail_json( msg="the python NetApp-Lib module is required") else: self.server = netapp_utils.setup_na_ontap_zapi( module=self.module, vserver=self.parameters['vserver']) def add_parameter_to_dict(self, adict, name, key=None, tostr=False): ''' add defined parameter (not None) to adict using key ''' if key is None: key = name if self.parameters.get(name) is not None: if tostr: adict[key] = str(self.parameters.get(name)) else: adict[key] = self.parameters.get(name) def get_job(self, jobid, server): """ Get job details by id """ job_get = netapp_utils.zapi.NaElement('job-get') job_get.add_new_child('job-id', jobid) try: result = server.invoke_successfully(job_get, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: if to_native(error.code) == "15661": # Not found return None self.module.fail_json(msg='Error fetching job info: %s' % to_native(error), exception=traceback.format_exc()) results = dict() job_info = result.get_child_by_name('attributes').get_child_by_name( 'job-info') results = { 'job-progress': job_info['job-progress'], 'job-state': job_info['job-state'] } if job_info.get_child_by_name('job-completion') is not None: results['job-completion'] = job_info['job-completion'] else: results['job-completion'] = None return results def check_job_status(self, jobid): """ Loop until job is complete """ server = self.server sleep_time = 5 time_out = self.parameters['time_out'] while time_out > 0: results = self.get_job(jobid, server) # If running as cluster admin, the job is owned by cluster vserver # rather than the target vserver. if results is None and server == self.server: results = netapp_utils.get_cserver(self.server) server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results) continue if results is None: error = 'cannot locate job with id: %d' % jobid break if results['job-state'] in ('queued', 'running'): time.sleep(sleep_time) time_out -= sleep_time continue if results['job-state'] in ('success', 'failure'): break else: self.module.fail_json(msg='Unexpected job status in: %s' % repr(results)) if results is not None: if results['job-state'] == 'success': error = None elif results['job-state'] in ('queued', 'running'): error = 'job completion exceeded expected timer of: %s seconds' % \ self.parameters['time_out'] else: if results['job-completion'] is not None: error = results['job-completion'] else: error = results['job-progress'] return error def flexcache_get_iter(self): """ Compose NaElement object to query current FlexCache relation """ options = {'volume': self.parameters['volume']} self.add_parameter_to_dict(options, 'origin_volume', 'origin-volume') self.add_parameter_to_dict(options, 'origin_vserver', 'origin-vserver') self.add_parameter_to_dict(options, 'origin_cluster', 'origin-cluster') flexcache_info = netapp_utils.zapi.NaElement.create_node_with_children( 'flexcache-info', **options) query = netapp_utils.zapi.NaElement('query') query.add_child_elem(flexcache_info) flexcache_get_iter = netapp_utils.zapi.NaElement('flexcache-get-iter') flexcache_get_iter.add_child_elem(query) return flexcache_get_iter def flexcache_get(self): """ Get current FlexCache relations :return: Dictionary of current FlexCache details if query successful, else None """ flexcache_get_iter = self.flexcache_get_iter() flex_info = dict() try: result = self.server.invoke_successfully(flexcache_get_iter, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error fetching FlexCache info: %s' % to_native(error), exception=traceback.format_exc()) if result.get_child_by_name('num-records') and \ int(result.get_child_content('num-records')) == 1: flexcache_info = result.get_child_by_name('attributes-list') \ .get_child_by_name('flexcache-info') flex_info['origin_cluster'] = flexcache_info.get_child_content( 'origin-cluster') flex_info['origin_volume'] = flexcache_info.get_child_content( 'origin-volume') flex_info['origin_vserver'] = flexcache_info.get_child_content( 'origin-vserver') flex_info['size'] = flexcache_info.get_child_content('size') flex_info['volume'] = flexcache_info.get_child_content('volume') flex_info['vserver'] = flexcache_info.get_child_content('vserver') flex_info['auto_provision_as'] = flexcache_info.get_child_content( 'auto-provision-as') return flex_info if result.get_child_by_name('num-records') and \ int(result.get_child_content('num-records')) > 1: msg = 'Multiple records found for %s:' % self.parameters['volume'] self.module.fail_json(msg='Error fetching FlexCache info: %s' % msg) return None def flexcache_create_async(self): """ Create a FlexCache relationship """ options = { 'origin-volume': self.parameters['origin_volume'], 'origin-vserver': self.parameters['origin_vserver'], 'volume': self.parameters['volume'] } self.add_parameter_to_dict(options, 'junction_path', 'junction-path') self.add_parameter_to_dict(options, 'auto_provision_as', 'auto-provision-as') self.add_parameter_to_dict(options, 'size', 'size', tostr=True) if self.parameters.get('aggr_list'): if self.parameters.get('aggr_list_multiplier'): self.tobytes_aggr_list_multiplier = bytes( self.parameters['aggr_list_multiplier']) self.add_parameter_to_dict(options, 'tobytes_aggr_list_multiplier', 'aggr-list-multiplier') flexcache_create = netapp_utils.zapi.NaElement.create_node_with_children( 'flexcache-create-async', **options) if self.parameters.get('aggr_list'): aggregates = netapp_utils.zapi.NaElement('aggr-list') for aggregate in self.parameters['aggr_list']: aggregates.add_new_child('aggr-name', aggregate) flexcache_create.add_child_elem(aggregates) try: result = self.server.invoke_successfully(flexcache_create, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error creating FlexCache %s' % to_native(error), exception=traceback.format_exc()) results = dict() for key in ('result-status', 'result-jobid'): if result.get_child_by_name(key): results[key] = result[key] return results def flexcache_create(self): """ Create a FlexCache relationship Check job status """ results = self.flexcache_create_async() status = results.get('result-status') if status == 'in_progress' and 'result-jobid' in results: if self.parameters['time_out'] == 0: # asynchronous call, assuming success! return error = self.check_job_status(results['result-jobid']) if error is None: return else: self.module.fail_json(msg='Error when creating flexcache: %s' % error) self.module.fail_json( msg='Unexpected error when creating flexcache: results is: %s' % repr(results)) def flexcache_delete_async(self): """ Delete FlexCache relationship at destination cluster """ options = {'volume': self.parameters['volume']} flexcache_delete = netapp_utils.zapi.NaElement.create_node_with_children( 'flexcache-destroy-async', **options) try: result = self.server.invoke_successfully(flexcache_delete, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error deleting FlexCache : %s' % (to_native(error)), exception=traceback.format_exc()) results = dict() for key in ('result-status', 'result-jobid'): if result.get_child_by_name(key): results[key] = result[key] return results def volume_offline(self): """ Offline FlexCache volume at destination cluster """ options = {'name': self.parameters['volume']} xml = netapp_utils.zapi.NaElement.create_node_with_children( 'volume-offline', **options) try: self.server.invoke_successfully(xml, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error offlining FlexCache volume: %s' % (to_native(error)), exception=traceback.format_exc()) def volume_unmount(self): """ Unmount FlexCache volume at destination cluster """ options = {'volume-name': self.parameters['volume']} xml = netapp_utils.zapi.NaElement.create_node_with_children( 'volume-unmount', **options) try: self.server.invoke_successfully(xml, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error unmounting FlexCache volume: %s' % (to_native(error)), exception=traceback.format_exc()) def flexcache_delete_async(self): """ Delete FlexCache relationship at destination cluster """ options = {'volume': self.parameters['volume']} flexcache_delete = netapp_utils.zapi.NaElement.create_node_with_children( 'flexcache-destroy-async', **options) try: result = self.server.invoke_successfully(flexcache_delete, enable_tunneling=True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error deleting FlexCache : %s' % (to_native(error)), exception=traceback.format_exc()) results = dict() for key in ('result-status', 'result-jobid'): if result.get_child_by_name(key): results[key] = result[key] return results def flexcache_delete(self): """ Delete FlexCache relationship at destination cluster Check job status """ if self.parameters['force_unmount']: self.volume_unmount() if self.parameters['force_offline']: self.volume_offline() results = self.flexcache_delete_async() status = results.get('result-status') if status == 'in_progress' and 'result-jobid' in results: if self.parameters['time_out'] == 0: # asynchronous call, assuming success! return error = self.check_job_status(results['result-jobid']) if error is None: return else: self.module.fail_json(msg='Error when deleting flexcache: %s' % error) self.module.fail_json( msg='Unexpected error when deleting flexcache: results is: %s' % repr(results)) def check_parameters(self): """ Validate parameters and fail if one or more required params are missing """ missings = list() expected = ('origin_volume', 'origin_vserver') if self.parameters['state'] == 'present': for param in expected: if not self.parameters.get(param): missings.append(param) if missings: plural = 's' if len(missings) > 1 else '' msg = 'Missing parameter%s: %s' % (plural, ', '.join(missings)) self.module.fail_json(msg=msg) def apply(self): """ Apply action to FlexCache """ netapp_utils.ems_log_event("na_ontap_flexcache", self.server) current = self.flexcache_get() cd_action = self.na_helper.get_cd_action(current, self.parameters) if cd_action == 'create': self.check_parameters() self.flexcache_create() elif cd_action == 'delete': self.flexcache_delete() self.module.exit_json(changed=self.na_helper.changed)
def main(): argument_spec = cs_argument_spec() argument_spec.update( dict( name=dict(required=True), disk_offering=dict(), display_volume=dict(type='bool'), max_iops=dict(type='int'), min_iops=dict(type='int'), size=dict(type='int'), snapshot=dict(), vm=dict(), device_id=dict(type='int'), custom_id=dict(), force=dict(type='bool', default=False), shrink_ok=dict(type='bool', default=False), state=dict(default='present', choices=[ 'present', 'absent', 'attached', 'detached', 'extracted', 'uploaded', ]), zone=dict(), domain=dict(), account=dict(), project=dict(), poll_async=dict(type='bool', default=True), tags=dict(type='list', aliases=['tag']), url=dict(), mode=dict(choices=['http_download', 'ftp_upload'], default='http_download'), format=dict(choices=['QCOW2', 'RAW', 'VHD', 'VHDX', 'OVA']), )) module = AnsibleModule(argument_spec=argument_spec, required_together=cs_required_together(), mutually_exclusive=(['snapshot', 'disk_offering'], ), required_if=[ ('state', 'uploaded', ['url', 'format']), ], supports_check_mode=True) acs_vol = AnsibleCloudStackVolume(module) state = module.params.get('state') if state in ['absent']: volume = acs_vol.absent_volume() elif state in ['attached']: volume = acs_vol.attached_volume() elif state in ['detached']: volume = acs_vol.detached_volume() elif state == 'extracted': volume = acs_vol.extract_volume() elif state == 'uploaded': volume = acs_vol.upload_volume() else: volume = acs_vol.present_volume() result = acs_vol.get_result(volume) module.exit_json(**result)
class Lacp(object): """ Manages Eth-Trunk interfaces LACP. """ def __init__(self, argument_spec): self.spec = argument_spec self.module = None self.init_module() # module input info self.trunk_id = self.module.params['trunk_id'] self.mode = self.module.params['mode'] self.param = dict() self.state = self.module.params['state'] # state self.changed = False self.updates_cmd = list() self.results = dict() self.proposed = dict() self.existing = dict() self.end_state = dict() def init_module(self): """ init AnsibleModule """ self.module = AnsibleModule( argument_spec=self.spec, mutually_exclusive=[['trunk_id', 'global_priority']], required_one_of=[['trunk_id', 'global_priority']], supports_check_mode=True) def check_params(self): """check module params """ for key in self.module.params.keys(): if key in LACP.keys() and self.module.params[key] is not None: self.param[key] = self.module.params[key] if isinstance(self.module.params[key], bool): self.param[key] = str(self.module.params[key]).lower() msg = check_param(self.param) if msg != 'ok': self.module.fail_json(msg=msg) def get_existing(self): """get existing""" xml_str = bulid_xml(self.param) xml = get_nc_config(self.module, xml_str) return xml_to_dict(xml) def get_proposed(self): """get proposed""" proposed = dict(state=self.state) proposed.update(self.param) return proposed def get_end_state(self): """ get end_state""" xml_str = bulid_xml(self.param) xml = get_nc_config(self.module, xml_str) return xml_to_dict(xml) def work(self): """worker""" self.check_params() existing = self.get_existing() proposed = self.get_proposed() # deal present or absent if self.state == "present": operation = 'merge' else: operation = 'delete' xml_str = bulid_xml(self.param, operation=operation) set_nc_config(self.module, xml_str) end_state = self.get_end_state() self.results['proposed'] = proposed self.results['existing'] = existing self.results['end_state'] = end_state updates_cmd = compare_config(self.module, existing, end_state) self.results['updates'] = updates_cmd if updates_cmd: self.results['changed'] = True else: self.results['changed'] = False self.module.exit_json(**self.results)
class IscsiTarget(object): def __init__(self): argument_spec = eseries_host_argument_spec() argument_spec.update( dict( name=dict(type='str', required=False, aliases=['alias']), ping=dict(type='bool', required=False, default=True), chap_secret=dict(type='str', required=False, aliases=['chap', 'password'], no_log=True), unnamed_discovery=dict(type='bool', required=False, default=True), log_path=dict(type='str', required=False), )) self.module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) args = self.module.params self.name = args['name'] self.ping = args['ping'] self.chap_secret = args['chap_secret'] self.unnamed_discovery = args['unnamed_discovery'] self.ssid = args['ssid'] self.url = args['api_url'] self.creds = dict( url_password=args['api_password'], validate_certs=args['validate_certs'], url_username=args['api_username'], ) self.check_mode = self.module.check_mode self.post_body = dict() self.controllers = list() log_path = args['log_path'] # logging setup self._logger = logging.getLogger(self.__class__.__name__) if log_path: logging.basicConfig( level=logging.DEBUG, filename=log_path, filemode='w', format= '%(relativeCreated)dms %(levelname)s %(module)s.%(funcName)s:%(lineno)d\n %(message)s' ) if not self.url.endswith('/'): self.url += '/' if self.chap_secret: if len(self.chap_secret) < 12 or len(self.chap_secret) > 57: self.module.fail_json( msg= "The provided CHAP secret is not valid, it must be between 12 and 57" " characters in length.") for c in self.chap_secret: ordinal = ord(c) if ordinal < 32 or ordinal > 126: self.module.fail_json( msg= "The provided CHAP secret is not valid, it may only utilize ascii" " characters with decimal values between 32 and 126.") @property def target(self): """Provide information on the iSCSI Target configuration Sample: { 'alias': 'myCustomName', 'ping': True, 'unnamed_discovery': True, 'chap': False, 'iqn': 'iqn.1992-08.com.netapp:2800.000a132000b006d2000000005a0e8f45', } """ target = dict() try: (rc, data) = request( self.url + 'storage-systems/%s/graph/xpath-filter?query=/storagePoolBundle/target' % self.ssid, headers=HEADERS, **self.creds) # This likely isn't an iSCSI-enabled system if not data: self.module.fail_json( msg= "This storage-system doesn't appear to have iSCSI interfaces. Array Id [%s]." % (self.ssid)) data = data[0] chap = any([ auth for auth in data['configuredAuthMethods']['authMethodData'] if auth['authMethod'] == 'chap' ]) target.update( dict(alias=data['alias']['iscsiAlias'], iqn=data['nodeName']['iscsiNodeName'], chap=chap)) (rc, data) = request( self.url + 'storage-systems/%s/graph/xpath-filter?query=/sa/iscsiEntityData' % self.ssid, headers=HEADERS, **self.creds) data = data[0] target.update( dict( ping=data['icmpPingResponseEnabled'], unnamed_discovery=data['unnamedDiscoverySessionsEnabled'])) except Exception as err: self.module.fail_json( msg= "Failed to retrieve the iSCSI target information. Array Id [%s]. Error [%s]." % (self.ssid, to_native(err))) return target def apply_iscsi_settings(self): """Update the iSCSI target alias and CHAP settings""" update = False target = self.target body = dict() if self.name is not None and self.name != target['alias']: update = True body['alias'] = self.name # If the CHAP secret was provided, we trigger an update. if self.chap_secret: update = True body.update( dict(enableChapAuthentication=True, chapSecret=self.chap_secret)) # If no secret was provided, then we disable chap elif target['chap']: update = True body.update(dict(enableChapAuthentication=False)) if update and not self.check_mode: try: request(self.url + 'storage-systems/%s/iscsi/target-settings' % self.ssid, method='POST', data=json.dumps(body), headers=HEADERS, **self.creds) except Exception as err: self.module.fail_json( msg= "Failed to update the iSCSI target settings. Array Id [%s]. Error [%s]." % (self.ssid, to_native(err))) return update def apply_target_changes(self): update = False target = self.target body = dict() if self.ping != target['ping']: update = True body['icmpPingResponseEnabled'] = self.ping if self.unnamed_discovery != target['unnamed_discovery']: update = True body['unnamedDiscoverySessionsEnabled'] = self.unnamed_discovery self._logger.info(pformat(body)) if update and not self.check_mode: try: request(self.url + 'storage-systems/%s/iscsi/entity' % self.ssid, method='POST', data=json.dumps(body), timeout=60, headers=HEADERS, **self.creds) except Exception as err: self.module.fail_json( msg= "Failed to update the iSCSI target settings. Array Id [%s]. Error [%s]." % (self.ssid, to_native(err))) return update def update(self): update = self.apply_iscsi_settings() update = self.apply_target_changes() or update target = self.target data = dict( (key, target[key]) for key in target if key in ['iqn', 'alias']) self.module.exit_json(msg="The interface settings have been updated.", changed=update, **data) def __call__(self, *args, **kwargs): self.update()
def main(): fields = { "host": { "required": False, "type": "str" }, "username": { "required": False, "type": "str" }, "password": { "required": False, "type": "str", "default": "", "no_log": True }, "vdom": { "required": False, "type": "str", "default": "root" }, "https": { "required": False, "type": "bool", "default": True }, "ssl_verify": { "required": False, "type": "bool", "default": True }, "state": { "required": True, "type": "str", "choices": ["present", "absent"] }, "system_snmp_user": { "required": False, "type": "dict", "default": None, "options": { "auth_proto": { "required": False, "type": "str", "choices": ["md5", "sha"] }, "auth_pwd": { "required": False, "type": "str" }, "events": { "required": False, "type": "list", "choices": [ "cpu-high", "mem-low", "log-full", "intf-ip", "vpn-tun-up", "vpn-tun-down", "ha-switch", "ha-hb-failure", "ips-signature", "ips-anomaly", "av-virus", "av-oversize", "av-pattern", "av-fragmented", "fm-if-change", "fm-conf-change", "bgp-established", "bgp-backward-transition", "ha-member-up", "ha-member-down", "ent-conf-change", "av-conserve", "av-bypass", "av-oversize-passed", "av-oversize-blocked", "ips-pkg-update", "ips-fail-open", "faz-disconnect", "wc-ap-up", "wc-ap-down", "fswctl-session-up", "fswctl-session-down", "load-balance-real-server-down", "device-new", "per-cpu-high" ] }, "ha_direct": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "name": { "required": True, "type": "str" }, "notify_hosts": { "required": False, "type": "list" }, "notify_hosts6": { "required": False, "type": "list" }, "priv_proto": { "required": False, "type": "str", "choices": ["aes", "des", "aes256", "aes256cisco"] }, "priv_pwd": { "required": False, "type": "str" }, "queries": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "query_port": { "required": False, "type": "int" }, "security_level": { "required": False, "type": "str", "choices": ["no-auth-no-priv", "auth-no-priv", "auth-priv"] }, "source_ip": { "required": False, "type": "str" }, "source_ipv6": { "required": False, "type": "str" }, "status": { "required": False, "type": "str", "choices": ["enable", "disable"] }, "trap_lport": { "required": False, "type": "int" }, "trap_rport": { "required": False, "type": "int" }, "trap_status": { "required": False, "type": "str", "choices": ["enable", "disable"] } } } } module = AnsibleModule(argument_spec=fields, supports_check_mode=False) # legacy_mode refers to using fortiosapi instead of HTTPAPI legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 'username' in module.params and module.params['username'] is not None and \ 'password' in module.params and module.params['password'] is not None if not legacy_mode: if module._socket_path: connection = Connection(module._socket_path) fos = FortiOSHandler(connection) is_error, has_changed, result = fortios_system_snmp( module.params, fos) else: module.fail_json(**FAIL_SOCKET_MSG) else: try: from fortiosapi import FortiOSAPI except ImportError: module.fail_json(msg="fortiosapi module is required") fos = FortiOSAPI() login(module.params, fos) is_error, has_changed, result = fortios_system_snmp(module.params, fos) fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) else: module.fail_json(msg="Error in repo", meta=result)
def main(): module = AnsibleModule( argument_spec=dict( paths=dict(type='list', required=True, aliases=['name', 'path']), patterns=dict(type='list', default=['*'], aliases=['pattern']), excludes=dict(type='list', aliases=['exclude']), contains=dict(type='str'), file_type=dict(type='str', default="file", choices=['any', 'directory', 'file', 'link']), age=dict(type='str'), age_stamp=dict(type='str', default="mtime", choices=['atime', 'ctime', 'mtime']), size=dict(type='str'), recurse=dict(type='bool', default=False), hidden=dict(type='bool', default=False), follow=dict(type='bool', default=False), get_checksum=dict(type='bool', default=False), use_regex=dict(type='bool', default=False), depth=dict(type='int'), ), supports_check_mode=True, ) params = module.params filelist = [] if params['age'] is None: age = None else: # convert age to seconds: m = re.match(r"^(-?\d+)(s|m|h|d|w)?$", params['age'].lower()) seconds_per_unit = { "s": 1, "m": 60, "h": 3600, "d": 86400, "w": 604800 } if m: age = int(m.group(1)) * seconds_per_unit.get(m.group(2), 1) else: module.fail_json(age=params['age'], msg="failed to process age") if params['size'] is None: size = None else: # convert size to bytes: m = re.match(r"^(-?\d+)(b|k|m|g|t)?$", params['size'].lower()) bytes_per_unit = { "b": 1, "k": 1024, "m": 1024**2, "g": 1024**3, "t": 1024**4 } if m: size = int(m.group(1)) * bytes_per_unit.get(m.group(2), 1) else: module.fail_json(size=params['size'], msg="failed to process size") now = time.time() msg = '' looked = 0 for npath in params['paths']: npath = os.path.expanduser(os.path.expandvars(npath)) if os.path.isdir(npath): for root, dirs, files in os.walk(npath, followlinks=params['follow']): if params['depth']: depth = root.replace(npath.rstrip(os.path.sep), '').count(os.path.sep) if files or dirs: depth += 1 if depth > params['depth']: del (dirs[:]) continue looked = looked + len(files) + len(dirs) for fsobj in (files + dirs): fsname = os.path.normpath(os.path.join(root, fsobj)) if os.path.basename(fsname).startswith( '.') and not params['hidden']: continue try: st = os.lstat(fsname) except Exception: msg += "%s was skipped as it does not seem to be a valid file or it cannot be accessed\n" % fsname continue r = {'path': fsname} if params['file_type'] == 'any': if pfilter(fsobj, params['patterns'], params['excludes'], params['use_regex']) and agefilter( st, now, age, params['age_stamp']): r.update(statinfo(st)) if stat.S_ISREG( st.st_mode) and params['get_checksum']: r['checksum'] = module.sha1(fsname) filelist.append(r) elif stat.S_ISDIR( st.st_mode) and params['file_type'] == 'directory': if pfilter(fsobj, params['patterns'], params['excludes'], params['use_regex']) and agefilter( st, now, age, params['age_stamp']): r.update(statinfo(st)) filelist.append(r) elif stat.S_ISREG( st.st_mode) and params['file_type'] == 'file': if pfilter(fsobj, params['patterns'], params['excludes'], params['use_regex']) and \ agefilter(st, now, age, params['age_stamp']) and \ sizefilter(st, size) and contentfilter(fsname, params['contains']): r.update(statinfo(st)) if params['get_checksum']: r['checksum'] = module.sha1(fsname) filelist.append(r) elif stat.S_ISLNK( st.st_mode) and params['file_type'] == 'link': if pfilter(fsobj, params['patterns'], params['excludes'], params['use_regex']) and agefilter( st, now, age, params['age_stamp']): r.update(statinfo(st)) filelist.append(r) if not params['recurse']: break else: msg += "%s was skipped as it does not seem to be a valid directory or it cannot be accessed\n" % npath matched = len(filelist) module.exit_json(files=filelist, changed=False, msg=msg, matched=matched, examined=looked)
def main(): fields = { "host": { "required": False, "type": "str" }, "username": { "required": False, "type": "str" }, "password": { "required": False, "type": "str", "default": "", "no_log": True }, "vdom": { "required": False, "type": "str", "default": "root" }, "https": { "required": False, "type": "bool", "default": True }, "ssl_verify": { "required": False, "type": "bool", "default": True }, "state": { "required": False, "type": "str", "choices": ["present", "absent"] }, "firewall_vip46": { "required": False, "type": "dict", "default": None, "options": { "state": { "required": False, "type": "str", "choices": ["present", "absent"] }, "arp_reply": { "required": False, "type": "str", "choices": ["disable", "enable"] }, "color": { "required": False, "type": "int" }, "comment": { "required": False, "type": "str" }, "extip": { "required": False, "type": "str" }, "extport": { "required": False, "type": "str" }, "id": { "required": False, "type": "int" }, "ldb_method": { "required": False, "type": "str", "choices": [ "static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive" ] }, "mappedip": { "required": False, "type": "str" }, "mappedport": { "required": False, "type": "str" }, "monitor": { "required": False, "type": "list", "options": { "name": { "required": True, "type": "str" } } }, "name": { "required": True, "type": "str" }, "portforward": { "required": False, "type": "str", "choices": ["disable", "enable"] }, "protocol": { "required": False, "type": "str", "choices": ["tcp", "udp"] }, "realservers": { "required": False, "type": "list", "options": { "client_ip": { "required": False, "type": "str" }, "healthcheck": { "required": False, "type": "str", "choices": ["disable", "enable", "vip"] }, "holddown_interval": { "required": False, "type": "int" }, "id": { "required": True, "type": "int" }, "ip": { "required": False, "type": "str" }, "max_connections": { "required": False, "type": "int" }, "monitor": { "required": False, "type": "str" }, "port": { "required": False, "type": "int" }, "status": { "required": False, "type": "str", "choices": ["active", "standby", "disable"] }, "weight": { "required": False, "type": "int" } } }, "server_type": { "required": False, "type": "str", "choices": ["http", "tcp", "udp", "ip"] }, "src_filter": { "required": False, "type": "list", "options": { "range": { "required": True, "type": "str" } } }, "type": { "required": False, "type": "str", "choices": ["static-nat", "server-load-balance"] }, "uuid": { "required": False, "type": "str" } } } } module = AnsibleModule(argument_spec=fields, supports_check_mode=False) # legacy_mode refers to using fortiosapi instead of HTTPAPI legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 'username' in module.params and module.params['username'] is not None and \ 'password' in module.params and module.params['password'] is not None if not legacy_mode: if module._socket_path: connection = Connection(module._socket_path) fos = FortiOSHandler(connection) is_error, has_changed, result = fortios_firewall( module.params, fos) else: module.fail_json(**FAIL_SOCKET_MSG) else: try: from fortiosapi import FortiOSAPI except ImportError: module.fail_json(msg="fortiosapi module is required") fos = FortiOSAPI() login(module.params, fos) is_error, has_changed, result = fortios_firewall(module.params, fos) fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) else: module.fail_json(msg="Error in repo", meta=result)
def main(): """entry point for module execution """ argument_spec = dict( path=dict(required=True), content=dict(), method=dict(choices=['post', 'put', 'patch', 'delete'], default='post'), format=dict(choices=['json', 'xml'], default='json'), ) required_if = [ ['method', 'post', ['content']], ['method', 'put', ['content']], ['method', 'patch', ['content']], ] module = AnsibleModule( argument_spec=argument_spec, required_if=required_if, supports_check_mode=True ) path = module.params['path'] candidate = module.params['content'] method = module.params['method'] format = module.params['format'] if isinstance(candidate, string_types): candidate = json.loads(candidate) warnings = list() result = {'changed': False, 'warnings': warnings} running = None commit = not module.check_mode try: running = restconf.get(module, path, output=format) except ConnectionError as exc: if exc.code == 404: running = None else: module.fail_json(msg=to_text(exc), code=exc.code) try: if method == 'delete': if running: if commit: restconf.edit_config(module, path=path, method='DELETE') result['changed'] = True else: warnings.append("delete not executed as resource '%s' does not exist" % path) else: if running: if method == 'post': module.fail_json(msg="resource '%s' already exist" % path, code=409) diff = dict_diff(running, candidate) result['candidate'] = candidate result['running'] = running else: method = 'POST' diff = candidate if diff: if module._diff: result['diff'] = {'prepared': diff, 'before': candidate, 'after': running} if commit: restconf.edit_config(module, path=path, content=diff, method=method.upper(), format=format) result['changed'] = True except ConnectionError as exc: module.fail_json(msg=str(exc), code=exc.code) module.exit_json(**result)
def main(): argument_spec = ucs_argument_spec argument_spec.update( org_dn=dict(type='str', default='org-root'), name=dict(type='str', required=True), descr=dict(type='str', default='', aliases=['description', 'descrption']), order=dict(type='str', default='default', choices=['default', 'sequential']), first_addr=dict(type='str'), last_addr=dict(type='str'), state=dict(default='present', choices=['present', 'absent'], type='str'), ) module = AnsibleModule( argument_spec, supports_check_mode=True, ) # UCSModule verifies ucsmsdk is present and exits on failure. Imports are below ucs object creation. ucs = UCSModule(module) err = False from ucsmsdk.mometa.macpool.MacpoolPool import MacpoolPool from ucsmsdk.mometa.macpool.MacpoolBlock import MacpoolBlock changed = False try: mo_exists = False props_match = False # dn is <org_dn>/mac-pool-<name> dn = module.params['org_dn'] + '/mac-pool-' + module.params['name'] mo = ucs.login_handle.query_dn(dn) if mo: mo_exists = True if module.params['state'] == 'absent': if mo_exists: if not module.check_mode: ucs.login_handle.remove_mo(mo) ucs.login_handle.commit() changed = True else: if mo_exists: # check top-level mo props kwargs = dict(assignment_order=module.params['order']) kwargs['descr'] = module.params['descr'] if (mo.check_prop_match(**kwargs)): # top-level props match, check next level mo/props if module.params['last_addr'] and module.params[ 'first_addr']: # mac address block specified, check properties block_dn = dn + '/block-' + module.params[ 'first_addr'].upper( ) + '-' + module.params['last_addr'].upper() mo_1 = ucs.login_handle.query_dn(block_dn) if mo_1: props_match = True else: # no MAC address block specified, but top-level props matched props_match = True if not props_match: if not module.check_mode: # create if mo does not already exist mo = MacpoolPool( parent_mo_or_dn=module.params['org_dn'], name=module.params['name'], descr=module.params['descr'], assignment_order=module.params['order'], ) if module.params['last_addr'] and module.params[ 'first_addr']: mo_1 = MacpoolBlock( parent_mo_or_dn=mo, to=module.params['last_addr'], r_from=module.params['first_addr'], ) ucs.login_handle.add_mo(mo, True) ucs.login_handle.commit() changed = True except Exception as e: err = True ucs.result['msg'] = "setup error: %s " % str(e) ucs.result['changed'] = changed if err: module.fail_json(**ucs.result) module.exit_json(**ucs.result)
def main(): module = AnsibleModule(argument_spec=dict( server_url=dict(type='str', required=True, aliases=['url']), login_user=dict(type='str', required=True), login_password=dict(type='str', required=True, no_log=True), host_name=dict(type='str', required=True), http_login_user=dict(type='str', required=False, default=None), http_login_password=dict(type='str', required=False, default=None, no_log=True), validate_certs=dict(type='bool', required=False, default=True), host_groups=dict(type='list', required=False), link_templates=dict(type='list', required=False), status=dict(type='str', default="enabled", choices=['enabled', 'disabled']), state=dict(type='str', default="present", choices=['present', 'absent']), inventory_mode=dict(type='str', required=False, choices=['automatic', 'manual', 'disabled']), ipmi_authtype=dict(type='int', default=None), ipmi_privilege=dict(type='int', default=None), ipmi_username=dict(type='str', required=False, default=None), ipmi_password=dict(type='str', required=False, default=None, no_log=True), tls_connect=dict(type='int', default=1), tls_accept=dict(type='int', default=1), tls_psk_identity=dict(type='str', required=False), tls_psk=dict(type='str', required=False), ca_cert=dict(type='str', required=False, aliases=['tls_issuer']), tls_subject=dict(type='str', required=False), inventory_zabbix=dict(type='dict', required=False), timeout=dict(type='int', default=10), interfaces=dict(type='list', required=False), force=dict(type='bool', default=True), proxy=dict(type='str', required=False), visible_name=dict(type='str', required=False), description=dict(type='str', required=False)), supports_check_mode=True) if not HAS_ZABBIX_API: module.fail_json(msg=missing_required_lib( 'zabbix-api', url='https://pypi.org/project/zabbix-api/'), exception=ZBX_IMP_ERR) server_url = module.params['server_url'] login_user = module.params['login_user'] login_password = module.params['login_password'] http_login_user = module.params['http_login_user'] http_login_password = module.params['http_login_password'] validate_certs = module.params['validate_certs'] host_name = module.params['host_name'] visible_name = module.params['visible_name'] description = module.params['description'] host_groups = module.params['host_groups'] link_templates = module.params['link_templates'] inventory_mode = module.params['inventory_mode'] ipmi_authtype = module.params['ipmi_authtype'] ipmi_privilege = module.params['ipmi_privilege'] ipmi_username = module.params['ipmi_username'] ipmi_password = module.params['ipmi_password'] tls_connect = module.params['tls_connect'] tls_accept = module.params['tls_accept'] tls_psk_identity = module.params['tls_psk_identity'] tls_psk = module.params['tls_psk'] tls_issuer = module.params['ca_cert'] tls_subject = module.params['tls_subject'] inventory_zabbix = module.params['inventory_zabbix'] status = module.params['status'] state = module.params['state'] timeout = module.params['timeout'] interfaces = module.params['interfaces'] force = module.params['force'] proxy = module.params['proxy'] # convert enabled to 0; disabled to 1 status = 1 if status == "disabled" else 0 zbx = None # login to zabbix try: zbx = ZabbixAPI(server_url, timeout=timeout, user=http_login_user, passwd=http_login_password, validate_certs=validate_certs) zbx.login(login_user, login_password) atexit.register(zbx.logout) except Exception as e: module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) host = Host(module, zbx) template_ids = [] if link_templates: template_ids = host.get_template_ids(link_templates) group_ids = [] if host_groups: group_ids = host.get_group_ids_by_group_names(host_groups) ip = "" if interfaces: # ensure interfaces are well-formed for interface in interfaces: if 'type' not in interface: module.fail_json( msg= "(interface) type needs to be specified for interface '%s'." % interface) interfacetypes = {'agent': 1, 'snmp': 2, 'ipmi': 3, 'jmx': 4} if interface['type'] in interfacetypes.keys(): interface['type'] = interfacetypes[interface['type']] if interface['type'] < 1 or interface['type'] > 4: module.fail_json( msg="Interface type can only be 1-4 for interface '%s'." % interface) if 'useip' not in interface: interface['useip'] = 0 if 'dns' not in interface: if interface['useip'] == 0: module.fail_json( msg= "dns needs to be set if useip is 0 on interface '%s'." % interface) interface['dns'] = '' if 'ip' not in interface: if interface['useip'] == 1: module.fail_json( msg= "ip needs to be set if useip is 1 on interface '%s'." % interface) interface['ip'] = '' if 'main' not in interface: interface['main'] = 0 if 'port' in interface and not isinstance(interface['port'], str): try: interface['port'] = str(interface['port']) except ValueError: module.fail_json( msg= "port should be convertable to string on interface '%s'." % interface) if 'port' not in interface: if interface['type'] == 1: interface['port'] = "10050" elif interface['type'] == 2: interface['port'] = "161" elif interface['type'] == 3: interface['port'] = "623" elif interface['type'] == 4: interface['port'] = "12345" if interface['type'] == 1: ip = interface['ip'] # Use proxy specified, or set to 0 if proxy: proxy_id = host.get_proxyid_by_proxy_name(proxy) else: proxy_id = 0 # check if host exist is_host_exist = host.is_host_exist(host_name) if is_host_exist: # get host id by host name zabbix_host_obj = host.get_host_by_host_name(host_name) host_id = zabbix_host_obj['hostid'] # If proxy is not specified as a module parameter, use the existing setting if proxy is None: proxy_id = int(zabbix_host_obj['proxy_hostid']) if state == "absent": # remove host host.delete_host(host_id, host_name) module.exit_json(changed=True, result="Successfully delete host %s" % host_name) else: if not host_groups: # if host_groups have not been specified when updating an existing host, just # get the group_ids from the existing host without updating them. group_ids = host.get_group_ids_by_host_id(host_id) # get existing host's interfaces exist_interfaces = host._zapi.hostinterface.get({ 'output': 'extend', 'hostids': host_id }) # if no interfaces were specified with the module, start with an empty list if not interfaces: interfaces = [] # When force=no is specified, append existing interfaces to interfaces to update. When # no interfaces have been specified, copy existing interfaces as specified from the API. # Do the same with templates and host groups. if not force or not interfaces: for interface in copy.deepcopy(exist_interfaces): # remove values not used during hostinterface.add/update calls for key in tuple(interface.keys()): if key in ['interfaceid', 'hostid', 'bulk']: interface.pop(key, None) for index in interface.keys(): if index in ['useip', 'main', 'type']: interface[index] = int(interface[index]) if interface not in interfaces: interfaces.append(interface) if not force or link_templates is None: template_ids = list( set(template_ids + host.get_host_templates_by_host_id(host_id))) if not force: for group_id in host.get_group_ids_by_host_id(host_id): if group_id not in group_ids: group_ids.append(group_id) # update host if host.check_all_properties( host_id, group_ids, status, interfaces, template_ids, exist_interfaces, zabbix_host_obj, proxy_id, visible_name, description, host_name, inventory_mode, inventory_zabbix, tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject, tls_connect, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password): host.update_host(host_name, group_ids, status, host_id, interfaces, exist_interfaces, proxy_id, visible_name, description, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password) host.link_or_clear_template(host_id, template_ids, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password) host.update_inventory_mode(host_id, inventory_mode) host.update_inventory_zabbix(host_id, inventory_zabbix) module.exit_json( changed=True, result= "Successfully update host %s (%s) and linked with template '%s'" % (host_name, ip, link_templates)) else: module.exit_json(changed=False) else: if state == "absent": # the host is already deleted. module.exit_json(changed=False) if not group_ids: module.fail_json( msg="Specify at least one group for creating host '%s'." % host_name) if not interfaces or (interfaces and len(interfaces) == 0): module.fail_json( msg="Specify at least one interface for creating host '%s'." % host_name) # create host host_id = host.add_host(host_name, group_ids, status, interfaces, proxy_id, visible_name, description, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password) host.link_or_clear_template(host_id, template_ids, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password) host.update_inventory_mode(host_id, inventory_mode) host.update_inventory_zabbix(host_id, inventory_zabbix) module.exit_json( changed=True, result= "Successfully added host %s (%s) and linked with template '%s'" % (host_name, ip, link_templates))
def main(): module = AnsibleModule(argument_spec=dict( hosts=dict(required=True, type='str'), name=dict(required=True, type='str'), value=dict(required=False, default=None, type='str'), op=dict(required=False, default=None, choices=['get', 'wait', 'list']), state=dict(choices=['present', 'absent']), timeout=dict(required=False, default=300, type='int'), recursive=dict(required=False, default=False, type='bool')), supports_check_mode=False) if not KAZOO_INSTALLED: module.fail_json(msg=missing_required_lib('kazoo >= 2.1'), exception=KAZOO_IMP_ERR) check = check_params(module.params) if not check['success']: module.fail_json(msg=check['msg']) zoo = KazooCommandProxy(module) try: zoo.start() except KazooTimeoutError: module.fail_json( msg='The connection to the ZooKeeper ensemble timed out.') command_dict = { 'op': { 'get': zoo.get, 'list': zoo.list, 'wait': zoo.wait }, 'state': { 'present': zoo.present, 'absent': zoo.absent } } command_type = 'op' if 'op' in module.params and module.params[ 'op'] is not None else 'state' method = module.params[command_type] result, result_dict = command_dict[command_type][method]() zoo.shutdown() if result: module.exit_json(**result_dict) else: module.fail_json(**result_dict)