
    Vh?                         d dl mZmZmZ eZdZdZdZd dl	m	Z	 d dl
mZ d dlmZ d dlmZ d d	lmZmZmZmZmZmZ d
j/                  e      ZddZd Zd Zd Zd Zd Zd Zd Z d Z!d Z"d Z#e$dk(  r e#        yy)    )absolute_importdivisionprint_functiona6
  
module: v_switch
short_description: Manage Hetzner's vSwitch
version_added: 1.7.0
author:
  - Alexander Gil Casas (@pando85)
description:
  - Manage Hetzner's vSwitch.
seealso:
  - name: vSwitch documentation
    description: Hetzner's documentation on vSwitch for connecting dedicated servers.
    link: https://docs.hetzner.com/robot/dedicated-server/network/vswitch
extends_documentation_fragment:
  - community.hrobot.robot
  - community.hrobot.attributes
  - community.hrobot.attributes.actiongroup_robot

attributes:
  check_mode:
    support: full
  diff_mode:
    support: none
  idempotent:
    support: full
  action_group:
    version_added: 2.1.0

options:
  vlan:
    description:
      - The vSwitch's VLAN ID.
      - Range can be from 4000 to 4091.
      - In order to identify a vSwitch both name and VLAN must match. If not, a new vSwitch will be created.
    type: int
    required: true
  name:
    description:
      - The vSwitch's name.
      - In order to identify a vSwitch both name and VLAN must match. If not, a new vSwitch will be created.
    type: str
    required: true
  state:
    description:
      - State of the vSwitch.
      - VSwitch is created if state is V(present), and deleted if state is V(absent).
      - V(absent) just cancels the vSwitch at the end of the current day.
      - When cancelling, you have to specify O(servers=[]) if you want to actively remove the servers in the vSwitch.
    type: str
    default: present
    choices: [present, absent]
  servers:
    description:
      - List of server identifiers (server's numeric ID or server's main IPv4 or IPv6).
      - If servers is not specified, servers are not going to be deleted.
    type: list
    elements: str
  wait:
    description:
      - Whether to wait until the vSwitch has been successfully configured before determining what to do, and before returning
        from the module.
      - The API returns status C(in process) when the vSwitch is currently being set up in the servers. If this happens, the
        module will try again until the status changes to C(ready) or server has been removed from vSwitch.
      - Please note that if you disable wait while deleting and removing servers module will fail with C(VSWITCH_IN_PROCESS)
        error.
    type: bool
    default: true
  wait_delay:
    description:
      - Delay to wait (in seconds) before checking again whether the vSwitch servers has been configured.
    type: int
    default: 10
  timeout:
    description:
      - Timeout (in seconds) for waiting for vSwitch servers to be configured.
    type: int
    default: 180
a  
---
- name: Create vSwitch with VLAN 4010 and name foo
  community.hrobot.v_switch:
    hetzner_user: foo
    hetzner_password: bar
    vlan: 4010
    name: foo

- name: Create vSwitch with VLAN 4020 and name foo with two servers
  community.hrobot.v_switch:
    hetzner_user: foo
    hetzner_password: bar
    vlan: 4010
    name: foo
    servers:
      - 123.123.123.123
      - 154323
a<  
v_switch:
  description:
    - Information on the vSwitch.
  returned: success
  type: dict
  contains:
    id:
      description:
        - The vSwitch's ID.
      type: int
      sample: 4321
      returned: success
    name:
      description:
        - The vSwitch's name.
      type: str
      sample: 'my vSwitch'
      returned: success
    vlan:
      description:
        - The vSwitch's VLAN ID.
      type: int
      sample: 4000
      returned: success
    cancelled:
      description:
        - Cancellation status.
      type: bool
      sample: false
      returned: success
    server:
      description:
        - The vSwitch's VLAN.
      type: list
      elements: dict
      sample:
        - server_ip: '123.123.123.123'
          server_ipv6_net: '2a01:4f8:111:4221::'
          server_number: 321
          status: 'ready'
      contains:
        server_ip:
          description:
            - The server's main IP address.
          type: str
          sample: '123.123.123.123'
        server_ipv6_net:
          description:
            - The server's main IPv6 network address.
          type: str
          sample: '2a01:f48:111:4221::'
        server_number:
          description:
            - The server's numeric ID.
          type: int
          sample: 321
        status:
          description:
            - Status of vSwitch for this server.
          type: str
          choices:
            - ready
            - in process
            - failed
          sample: 'ready'
      returned: success
    subnet:
      description:
        - List of assigned IP addresses.
      type: list
      elements: dict
      sample:
        - ip: '213.239.252.48'
          mask: 29
          gateway: '213.239.252.49'
      contains:
        ip:
          description:
            - IP address.
          type: str
          sample: '213.239.252.48'
        mask:
          description:
            - Subnet mask in CIDR notation.
          type: int
          sample: 29
        gateway:
          description:
            - Gateway of the subnet.
          type: str
          sample: '213.239.252.49'
      returned: success
    cloud_network:
      description:
        - List of assigned Cloud networks.
      type: list
      elements: dict
      sample:
        - id: 123
          ip: '10.0.2.0'
          mask: 24
          gateway: '10.0.2.1'
      contains:
        id:
          description:
            - Cloud network ID.
          type: int
          sample: 123
        ip:
          description:
            - IP address.
          type: str
          sample: '10.0.2.0'
        mask:
          description:
            - Subnet mask in CIDR notation.
          type: int
          sample: 24
        gateway:
          description:
            - Gateway.
          type: str
          sample: '10.0.2.1'
      returned: success
)datetime)AnsibleModule)	to_native)	urlencode)BASE_URLROBOT_DEFAULT_ARGUMENT_SPEC)get_x_www_form_urlenconded_dict_from_listfetch_url_jsonfetch_url_json_with_retriesCheckDoneTimeoutExceptionz{0}/vswitchNc                 <   dj                  t        |      }dg}|r0	 t        | ||| j                  d   | j                  d   |      \  }}nt        | ||      \  }}dk(  r| j                  d	       S # t        $ r}| j                  d       Y d }~9d }~ww xY w)
N{0}/{1}	NOT_FOUND
wait_delaytimeout)check_done_callbackcheck_done_delaycheck_done_timeoutaccept_errorsz+Timeout waiting vSwitch operation to finishmsgr   zvSwitch not found.)formatV_SWITCH_BASE_URLr   paramsr   	fail_jsonr   )moduleid_wait_conditionurlr   resulterrordummys           m/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/hrobot/plugins/modules/v_switch.pyget_v_switchr(     s    


,c
2C MM
	P7$2!'|!<#)==#;+MFE ''
 12M ) 	P!NOO	Ps   .A6 6	B?BBc                     t        | t              r(dj                  | D cg c]  }t        |       c}      S t	        |       S c c}w )Nz, )
isinstancelistjoinr   repr)possible_listxs     r'   
print_listr0     s:    -&yy>1)A,>?? ?s   Ac           	      2   ddi}| j                   d   | j                   d   d}t        | t        t        |      |dddg	      \  }}|dk(  r4t	        |d
   d         }| j                  dj                  |             |S |dk(  r| j                  d       |S )NContent-type!application/x-www-form-urlencodednamevlan)r4   r5   POSTINVALID_INPUTVSWITCH_LIMIT_REACHED)dataheadersmethodr   r%   invalidvSwitch invalid parameter ({0})r   z)The maximum count of vSwitches is reached)r   r   r   r	   r0   r   r   )r    r:   r9   r$   r%   invalid_parameterss         r'   create_v_switchr?   #  s    BCGMM&)6==3HID"t_&(?@MFE 'w	(BC>EEFXYZ M 
)	)HIM    c           	         dj                  t        |      }ddi}dt        j                         j	                  d      i}t        | |t        |      |dg dd	      \  }}|d
k(  r4t        |d   d         }| j                  dj                  |             |S |dk(  r| j                  d       |S |dk(  r| j                  d       |S )Nr   r2   r3   cancellation_datez%y-%m-%dDELETE)r7   r   CONFLICTTr9   r:   r;   r   allow_empty_resultr7   r%   r<   r=   r   r   zvSwitch not found to deleterD   z The vSwitch is already cancelled)	r   r   r   nowstrftimer   r	   r0   r   )r    r!   r#   r:   r9   r$   r%   r>   s           r'   delete_v_switchrI   7  s    


,c
2CBCG!8!8!DED"t_@MFE 'w	(BC>EEFXYZ M 
+	:; M 
*	?@Mr@   c                 ,    t        d | d   D              S )Nc              3   ,   K   | ]  }|d    dk(    yw)statusreadyN ).0servers     r'   	<genexpr>z'is_all_servers_ready.<locals>.<genexpr>P  s     Jvvh7*Js   rP   )all)r$   r&   s     r'   is_all_servers_readyrS   O  s    J9IJJJr@   c           
         dj                  t        |      }ddi}t        d|      }t        | |t	        |      |dg ddd	      \  }}|d
k(  r3t        |d   d         }| j                  dj                  |             nk|dk(  r| j                  |d   d          nM|dk(  r| j                  |d   d          n/|dk(  r| j                  d       n|dk(  r| j                  d       | j                  d   rt        nd }	t        | ||	      S )N{0}/{1}/serverr2   r3   rP   r6   )r7   SERVER_NOT_FOUNDVSWITCH_VLAN_NOT_UNIQUEVSWITCH_IN_PROCESSVSWITCH_SERVER_LIMIT_REACHEDT)   )r9   r:   r;   r   rF   !allowed_empty_result_status_codesr7   r%   r<   z%Invalid parameter adding server ({0})r   rV   messagerW   rX   CThere is a update running, therefore the vswitch can not be updatedrY   z9The maximum number of servers is reached for this vSwitchwait)
r   r   r   r   r	   r0   r   r   rS   r(   )
r    r!   serversr#   r:   r9   r$   r%   r>   r"   s
             r'   add_serversr`   S  s6   

!
!"3S
9CBCG4XwGD"t_
  *0MFE" 'w	(BCDKKL^_`	$	$VG_Y78	+	+VG_Y78	&	&bc	0	0XY .4]]6-B)N^44r@   c           	      @   dj                  t        |      }ddi}t        d|      }t        | |t	        |      |dddgd	      \  }}|dk(  r| j                  |d
   d          n|dk(  r| j                  d       | j                  d   rt        nd }t        | ||      S )NrU   r2   r3   rP   rC   rV   rX   TrE   r%   r\   r   r]   r^   )	r   r   r   r   r	   r   r   rS   r(   )	r    r!   r_   r#   r:   r9   r$   r%   r"   s	            r'   delete_serversrb   {  s    

!
!"3S
9CBCG4XwGD"t_)+?@	MFE ""VG_Y78	&	&bc-3]]6-B)N^44r@   c                 n    | D cg c]%  }|d   |vr|d   |vrt        |d         |vr|d   ' c}S c c}w )N	server_ipserver_ipv6_netserver_numberstr)current_serversdesired_serversrP   s      r'   get_servers_to_deleterk     sV     &+o5$%_<'(?	 	{  s   *2c                     | D cg c]  }t        |d          }}| D cg c]  }|d   	 }}| D cg c]  }|d   	 }}|D cg c]  }||vr
||vr||vr| c}S c c}w c c}w c c}w c c}w )Nrf   rd   re   rg   )ri   rj   rP   current_idscurrent_ipscurrent_ipv6ss         r'   get_servers_to_addrp     s    >MNF3vo./NKN5DE66+&EKE=LM6V-.MMM &${)BvUbGb 	 	 OEMs   AA!A&A+c                 0   t        | |      }d}| j                  d   ||fS t        |d   | j                  d         }|r| j                  st	        | ||      }d}t        |d   | j                  d         }|r| j                  st        | ||      }d}||fS )NFr_   rP   T)r(   r   rk   
check_moderb   rp   r`   )r    r!   v_switchchangedservers_to_deleteservers_to_adds         r'   set_desired_serversrw     s    FC(HG}}Y''""-hx.@&--PYBZ[  %fc3DEH'(:FMM)<TUN  "63?Hgr@   c                  F   t        t        dd      t        dd      t        ddddg      t        dd	      t        d
d      t        dd      t        dd            } | j                  t               t        | d      }t	        |t
        dg      \  }}|r|j                  d       |D cg c].  }|d   |j                  d   k(  r|d   |j                  d   k(  r|0 }}|D cg c]  }|d   du s| }}ddi}t        |      dkD  r|j                  d       nt        |      dk(  rq|d   d   }	t        ||	      \  }
}|rd|d<   |j                  d   dk(  r|
|d<   n|j                  d   dk(  r|j                  st        ||	       d|d<   nnt        d      |j                  d   dk(  rQd|d<   |j                  s@t        |      }
|j                  d    r!t        ||
d   |j                  d          |d<   n|
|d<    |j                  d!i | y c c}w c c}w )"NintT)typerequiredrh   presentabsent)rz   defaultchoicesr+   )rz   elementsbool)rz   r~   
      )r5   r4   stater_   r^   r   r   )argument_specsupports_check_modeUNAUTHORIZEDr   z9Please check your current user and password configurationr   r4   r5   	cancelledFrt      zPMultiple vSwitches with same name and VLAN ID in non cancelled status. Clean it.r   idr   rs   znot reachabler_   rN   )dictupdater   r   r   r   r   r   lenrw   rr   rI   NotImplementedErrorr?   r`   	exit_json)r   r    
v_switchesr%   vmatched_v_switchesmnon_cancelled_v_switchesr$   r!   rs   rt   s               r'   mainr     sW   ut,ut,y9h:OP&51vt,UB/%-M 45# F
 'v/@Q_P`aJXY V9f--!F)v}}V?T2T 	
 
 ,>Ya;SXAXYYF
#$q(b 	 	
 
%	&!	+&q)$//<' $F9==!Y.!)F:]]7#x/$$, $F9%o66==!Y. $F9$$*62==+)4VXd^V]][dMe)fF:&)1F:&FvK
  Zs   33H,H9H__main__)N)%
__future__r   r   r   rz   __metaclass__DOCUMENTATIONEXAMPLESRETURNr   ansible.module_utils.basicr   +ansible.module_utils.common.text.convertersr   +ansible.module_utils.six.moves.urllib.parser	   ?ansible_collections.community.hrobot.plugins.module_utils.robotr
   r   r   r   r   r   r   r   r(   r0   r?   rI   rS   r`   rb   rk   rp   rw   r   __name__rN   r@   r'   <module>r      s    A @L\(}
@  4 A A  "((2 8(0K%5P50	(:z zF r@   