Server IP : 85.214.239.14 / Your IP : 18.223.119.139 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /lib/python3/dist-packages/ansible_collections/infinidat/infinibox/plugins/modules/ |
Upload File : |
#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright: (c) 2022, Infinidat <info@infinidat.com> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import (absolute_import, division, print_function) __metaclass__ = type DOCUMENTATION = r''' --- module: infini_port version_added: '2.9.0' short_description: Add and Delete fiber channel and iSCSI ports to a host on Infinibox description: - This module adds or deletes fiber channel or iSCSI ports to hosts on Infinibox. author: David Ohlemacher (@ohlemacher) options: host: description: - Host Name required: true state: description: - Creates mapping when present, removes when absent, or provides details of a mapping when stat. required: false default: present choices: [ "stat", "present", "absent" ] type: str wwns: description: - List of wwns of the host required: false default: [] type: list elements: str iqns: description: - List of iqns of the host required: false default: [] type: list elements: str extends_documentation_fragment: - infinibox ''' EXAMPLES = r''' - name: Make sure host bar is available with wwn/iqn ports infini_host: name: bar.example.com state: present wwns: - "00:00:00:00:00:00:00" - "11:11:11:11:11:11:11" iqns: - "iqn.yyyy-mm.reverse-domain:unique-string" system: ibox01 user: admin password: secret ''' # RETURN = r''' # ''' from ansible.module_utils.basic import AnsibleModule, missing_required_lib import traceback from ansible_collections.infinidat.infinibox.plugins.module_utils.infinibox import ( HAS_INFINISDK, api_wrapper, infinibox_argument_spec, get_system, get_host, merge_two_dicts, ) try: from infi.dtypes.wwn import WWN from infi.dtypes.iqn import make_iscsi_name except ImportError: pass # Handled by HAS_INFINISDK from module_utils @api_wrapper def update_ports(module, system): """ Updated mapping of volume to host. If already mapped, exit_json with changed False. """ changed = False host = system.hosts.get(name=module.params["host"]) for wwn_port in module.params["wwns"]: wwn = WWN(wwn_port) if not system.hosts.get_host_by_initiator_address(wwn) == host: if not module.check_mode: host.add_port(wwn) changed = True for iscsi_port in module.params["iqns"]: iscsi_name = make_iscsi_name(iscsi_port) if not system.hosts.get_host_by_initiator_address(iscsi_name) == host: if not module.check_mode: host.add_port(iscsi_name) changed = True return changed @api_wrapper def delete_ports(module, system): """ Remove ports from host. """ changed = False host = system.hosts.get(name=module.params["host"]) for wwn_port in module.params["wwns"]: wwn = WWN(wwn_port) if system.hosts.get_host_by_initiator_address(wwn) == host: if not module.check_mode: host.remove_port(wwn) changed = True for iscsi_port in module.params["iqns"]: iscsi_name = make_iscsi_name(iscsi_port) if system.hosts.get_host_by_initiator_address(iscsi_name) == host: if not module.check_mode: host.remove_port(iscsi_name) changed = True return changed def get_sys_host(module): system = get_system(module) host = get_host(module, system) return (system, host) def edit_initiator_keys(host_initiators, include_key_list): """ For each host initiator, remove keys not in the include_key_list. For FCs, add a long address. This is the address with colons inserted. Return the edited host initiators list. """ trimmed_initiators = [] for init in host_initiators: if init["type"] == "FC" and "address" in init.keys(): # Add address_long key to init whose value is the address with colons inserted. address_str = str(init["address"]) address_iter = iter(address_str) long_address = ":".join(a + b for a, b in zip(address_iter, address_iter)) init["address_long"] = long_address trimmed_item = { key: val for key, val in init.items() if key in include_key_list } trimmed_initiators.append(trimmed_item) return trimmed_initiators def find_host_initiators_data(module, system, host, initiator_type): """ Given a host object, find its initiators that match initiator_type. Only include desired initiator keys for each initiator. Return the filtered and edited host initiator list. """ request = "initiators?page=1&page_size=1000&host_id={0}".format(host.id) # print("\nrequest:", request, "initiator_type:", initiator_type) get_initiators_result = system.api.get(request, check_version=False) result_code = get_initiators_result.status_code if result_code != 200: msg = "get initiators REST call failed. code: {0}".format(result_code) module.fail_json(msg=msg) # Only return initiators of the desired type. host_initiators_by_type = [ initiator for initiator in get_initiators_result.get_result() if initiator["type"] == initiator_type ] # print("host_initiators_by_type:", host_initiators_by_type) # print() # Only include certain keys in the returned initiators if initiator_type == "FC": include_key_list = [ "address", "address_long", "host_id", "port_key", "targets", "type", ] elif initiator_type == "ISCSI": include_key_list = ["address", "host_id", "port_key", "targets", "type"] else: msg = "Cannot search for host initiator types other than FC and ISCSI" module.fail_json(msg=msg) host_initiators_by_type = edit_initiator_keys( host_initiators_by_type, include_key_list ) return host_initiators_by_type def get_port_fields(module, system, host): """ Return a dict with desired fields from FC and ISCSI ports associated with the host. """ host_fc_initiators = find_host_initiators_data( module, system, host, initiator_type="FC" ) host_iscsi_initiators = find_host_initiators_data( module, system, host, initiator_type="ISCSI" ) field_dict = dict(ports=[],) connectivity_lut = {0: "DISCONNECTED", 1: "DEGRADED", 2: "DEGRADED", 3: "CONNECTED"} ports = host.get_ports() for port in ports: if str(type(port)) == "<class 'infi.dtypes.wwn.WWN'>": found_initiator = False for initiator in host_fc_initiators: if initiator["address"] == str(port).replace(":", ""): found_initiator = True # print("initiator targets:", initiator['targets']) unique_initiator_target_ids = { target["node_id"] for target in initiator["targets"] } port_dict = { "address": str(port), "address_long": initiator["address_long"], "connectivity": connectivity_lut[ len(unique_initiator_target_ids) ], "targets": initiator["targets"], "type": initiator["type"], } if not found_initiator: address_str = str(port) address_iter = iter(address_str) long_address = ":".join( a + b for a, b in zip(address_iter, address_iter) ) port_dict = { "address": str(port), "address_long": long_address, "connectivity": connectivity_lut[0], "targets": [], "type": "FC", } field_dict["ports"].append(port_dict) if str(type(port)) == "<class 'infi.dtypes.iqn.IQN'>": found_initiator = False for initiator in host_iscsi_initiators: if initiator["address"] == str(port): found_initiator = True # print("initiator targets:", initiator['targets']) unique_initiator_target_ids = { target["node_id"] for target in initiator["targets"] } port_dict = { "address": str(port), "connectivity": connectivity_lut[ len(unique_initiator_target_ids) ], "targets": initiator["targets"], "type": initiator["type"], } if not found_initiator: port_dict = { "address": str(port), "connectivity": connectivity_lut[0], "targets": [], "type": "ISCSI", } field_dict["ports"].append(port_dict) return field_dict def handle_stat(module): """ Handle stat state. Fail if host is None. Return json with status. """ system, host = get_sys_host(module) host_name = module.params["host"] if not host: module.fail_json(msg="Host {0} not found".format(host_name)) field_dict = get_port_fields(module, system, host) result = dict(changed=False, msg="Host {0} ports found".format(host_name),) result = merge_two_dicts(result, field_dict) module.exit_json(**result) def handle_present(module): """ Handle present state. Fail if host is None. """ system, host = get_sys_host(module) host_name = module.params["host"] if not host: module.fail_json(msg="Host {0} not found".format(host_name)) changed = update_ports(module, system) if changed: msg = "Mapping created for host {0}".format(host.get_name()) else: msg = "No mapping changes were required for host {0}".format(host.get_name()) result = dict(changed=changed, msg=msg,) module.exit_json(**result) def handle_absent(module): """ Handle absent state. Fail if host is None. """ system, host = get_sys_host(module) if not host: module.exit_json( changed=False, msg="Host {0} not found".format(module.params["host"]) ) changed = delete_ports(module, system) if changed: msg = "Mapping removed from host {0}".format(host.get_name()) else: msg = "No mapping changes were required. Mapping already removed from host {0}".format( host.get_name() ) result = dict(changed=changed, msg=msg,) module.exit_json(**result) def execute_state(module): """ Handle states. Always logout. """ state = module.params["state"] try: if state == "stat": handle_stat(module) elif state == "present": handle_present(module) elif state == "absent": handle_absent(module) else: module.fail_json( msg="Internal handler error. Invalid state: {0}".format(state) ) finally: system = get_system(module) system.logout() def check_options(module): pass def main(): """ Gather auguments and manage mapping of vols to hosts. """ argument_spec = infinibox_argument_spec() null_list = list() argument_spec.update( dict( host=dict(required=True, type=str), state=dict(default="present", choices=["stat", "present", "absent"]), wwns=dict(type="list", elements="str", default=list()), iqns=dict(type="list", elements="str", default=list()), ) ) module = AnsibleModule(argument_spec, supports_check_mode=True) if not HAS_INFINISDK: module.fail_json(msg=missing_required_lib("infinisdk")) check_options(module) execute_state(module) if __name__ == "__main__": main()