
    Vh/W                     X   d dl mZmZmZ eZdZdZdZd dl	Z	d dl
Z
d dlZd dlZd dlZd dlmZ d dlmZ dZ	 d dlZd
j+                  dd      Zdj+                  e      ZdZdZdZg dZd Zd Zd Z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# e$ r d	ZY nw xY w)!    )absolute_importdivisionprint_functiona%  
module: packet_device

short_description: Manage a bare metal server in the Packet Host

description:
  - Manage a bare metal server in the Packet Host (a "device" in the API terms).
  - When the machine is created it can optionally wait for public IP address, or for active state.
  - This module has a dependency on packet >= 1.0.
  - API is documented at U(https://www.packet.net/developers/api/devices).
author:
  - Tomas Karasek (@t0mk) <tom.to.the.k@gmail.com>
  - Matt Baldwin (@baldwinSPC) <baldwin@stackpointcloud.com>
  - Thibaud Morel l'Horset (@teebes) <teebes@gmail.com>

extends_documentation_fragment:
  - community.general.attributes

attributes:
  check_mode:
    support: none
  diff_mode:
    support: none

options:
  auth_token:
    description:
      - Packet API token. You can also supply it in environment variable E(PACKET_API_TOKEN).
    type: str

  count:
    description:
      - The number of devices to create. Count number can be included in hostname using the C(%d) string formatter.
    default: 1
    type: int

  count_offset:
    description:
      - From which number to start the count.
    default: 1
    type: int

  device_ids:
    description:
      - List of device IDs on which to operate.
    type: list
    elements: str

  tags:
    description:
      - List of device tags.
      - Currently implemented only for device creation.
    type: list
    elements: str
    version_added: '0.2.0'

  facility:
    description:
      - Facility slug for device creation. See Packet API for current list - U(https://www.packet.net/developers/api/facilities/).
    type: str

  features:
    description:
      - Dict with "features" for device creation. See Packet API docs for details.
    type: dict

  hostnames:
    description:
      - A hostname of a device, or a list of hostnames.
      - If given string or one-item list, you can use the C("%d") Python string format to expand numbers from O(count).
      - If only one hostname, it might be expanded to list if O(count)>1.
    aliases: [name]
    type: list
    elements: str

  locked:
    description:
      - Whether to lock a created device.
    default: false
    aliases: [lock]
    type: bool

  operating_system:
    description:
      - OS slug for device creation. See Packet API for current list - U(https://www.packet.net/developers/api/operatingsystems/).
    type: str

  plan:
    description:
      - Plan slug for device creation. See Packet API for current list - U(https://www.packet.net/developers/api/plans/).
    type: str

  project_id:
    description:
      - ID of project of the device.
    required: true
    type: str

  state:
    description:
      - Desired state of the device.
      - If set to V(present) (the default), the module call will return immediately after the device-creating HTTP request
        successfully returns.
      - If set to V(active), the module call will block until all the specified devices are in state active due to the Packet
        API, or until O(wait_timeout).
    choices: [present, absent, active, inactive, rebooted]
    default: present
    type: str

  user_data:
    description:
      - Userdata blob made available to the machine.
    type: str

  wait_for_public_IPv:
    description:
      - Whether to wait for the instance to be assigned a public IPv4/IPv6 address.
      - If set to 4, it will wait until IPv4 is assigned to the instance.
      - If set to 6, wait until public IPv6 is assigned to the instance.
    choices: [4, 6]
    type: int

  wait_timeout:
    description:
      - How long (seconds) to wait either for automatic IP address assignment, or for the device to reach the V(active) state.
      - If O(wait_for_public_IPv) is set and O(state=active), the module will wait for both events consequently, applying
        the timeout twice.
    default: 900
    type: int

  ipxe_script_url:
    description:
      - URL of custom iPXE script for provisioning.
      - More about custom iPXE for Packet devices at U(https://help.packet.net/technical/infrastructure/custom-ipxe).
    type: str
    default: ''

  always_pxe:
    description:
      - Persist PXE as the first boot option.
      - Normally, the PXE process happens only on the first boot. Set this arg to have your device continuously boot to iPXE.
    default: false
    type: bool


requirements:
  - "packet-python >= 1.35"
a  
# All the examples assume that you have your Packet API token in environment variable PACKET_API_TOKEN.
# You can also pass it to the auth_token parameter of the module instead.

# Creating devices

- name: Create 1 device
  hosts: localhost
  tasks:
    - community.general.packet_device:
        project_id: 89b497ee-5afc-420a-8fb5-56984898f4df
        hostnames: myserver
        tags: ci-xyz
        operating_system: ubuntu_16_04
        plan: baremetal_0
        facility: sjc1

# Create the same device and wait until it is in state "active", (when it is
# ready for other API operations). Fail if the device is not "active" in
# 10 minutes.

- name: Create device and wait up to 10 minutes for active state
  hosts: localhost
  tasks:
    - community.general.packet_device:
        project_id: 89b497ee-5afc-420a-8fb5-56984898f4df
        hostnames: myserver
        operating_system: ubuntu_16_04
        plan: baremetal_0
        facility: sjc1
        state: active
        wait_timeout: 600

- name: Create 3 ubuntu devices called server-01, server-02 and server-03
  hosts: localhost
  tasks:
    - community.general.packet_device:
        project_id: 89b497ee-5afc-420a-8fb5-56984898f4df
        hostnames: server-%02d
        count: 3
        operating_system: ubuntu_16_04
        plan: baremetal_0
        facility: sjc1

- name: Create 3 coreos devices with userdata, wait until they get IPs and then wait for SSH
  hosts: localhost
  tasks:
    - name: Create 3 devices and register their facts
      community.general.packet_device:
        hostnames: [coreos-one, coreos-two, coreos-three]
        operating_system: coreos_stable
        plan: baremetal_0
        facility: ewr1
        locked: true
        project_id: 89b497ee-5afc-420a-8fb5-56984898f4df
        wait_for_public_IPv: 4
        user_data: |
          #cloud-config
          ssh_authorized_keys:
            - {{ lookup('file', 'my_packet_sshkey') }}
          coreos:
            etcd:
              discovery: https://discovery.etcd.io/6a28e078895c5ec737174db2419bb2f3
              addr: $private_ipv4:4001
              peer-addr: $private_ipv4:7001
            fleet:
              public-ip: $private_ipv4
            units:
              - name: etcd.service
                command: start
              - name: fleet.service
                command: start
      register: newhosts

    - name: Wait for ssh
      ansible.builtin.wait_for:
        delay: 1
        host: "{{ item.public_ipv4 }}"
        port: 22
        state: started
        timeout: 500
      with_items: "{{ newhosts.devices }}"


# Other states of devices

- name: Remove 3 devices by uuid
  hosts: localhost
  tasks:
    - community.general.packet_device:
        project_id: 89b497ee-5afc-420a-8fb5-56984898f4df
        state: absent
        device_ids:
          - 1fb4faf8-a638-4ac7-8f47-86fe514c30d8
          - 2eb4faf8-a638-4ac7-8f47-86fe514c3043
          - 6bb4faf8-a638-4ac7-8f47-86fe514c301f
a  
changed:
  description: True if a device was altered in any way (created, modified or removed).
  type: bool
  sample: true
  returned: success

devices:
  description: Information about each device that was processed.
  type: list
  sample:
    - "hostname": "my-server.com"
      "id": "2a5122b9-c323-4d5c-b53c-9ad3f54273e7"
      "public_ipv4": "147.229.15.12"
      "private-ipv4": "10.0.15.12"
      "tags": []
      "locked": false
      "state": "provisioning"
      "public_ipv6": "2604:1380:2:5200::3"
  returned: success
N)AnsibleModule)	to_nativeTFz({0}|{0}{1}*{0})z[a-zA-Z0-9]z[a-zA-Z0-9\-]z({0}\.)*{0}$d   )queuedprovisioningfailedpowering_onactivepowering_offinactive	rebootingPACKET_API_TOKEN)absentr   r   rebootedpresentc                    i }| j                   |d<   | j                  |d<   | j                  |d<   | j                  |d<   | j                  |d<   | j
                  D cg c]  }|d   |d   |d   d	 c}|d
<   |d
   D ]R  }|d   r#|d   dk(  r	|d   |d<   |d   dk(  s"|d   |d<   +|d   r1|d   dk(  r	|d   |d<   B|d   dk(  sK|d   |d<   T |S c c}w )a  
    Standard representation for a device as returned by various tasks::

        {
            'id': 'device_id'
            'hostname': 'device_hostname',
            'tags': [],
            'locked': false,
            'state': 'provisioning',
            'ip_addresses': [
                {
                    "address": "147.75.194.227",
                    "address_family": 4,
                    "public": true
                },
                {
                    "address": "2604:1380:2:5200::3",
                    "address_family": 6,
                    "public": true
                },
                {
                    "address": "10.100.11.129",
                    "address_family": 4,
                    "public": false
                }
            ],
            "private_ipv4": "10.100.11.129",
            "public_ipv4": "147.75.194.227",
            "public_ipv6": "2604:1380:2:5200::3",
        }

    idhostnametagslockedstateaddressaddress_familypublic)r   r   r   ip_addresses   public_ipv6   public_ipv4private_ipv6private_ipv4)r   r   r   r   r   r   )devicedevice_data	addr_dataipdatas       s/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/general/plugins/modules/packet_device.pyserialize_devicer*   @  s=   B K		K$ooK
 ++K"MMK!<<K  ,,# 	 !+'(89)	
#K n- @(&'1,-3I->M*()Q.-3I->M*!&'1, /5Y.?N+()Q..4Y.?N+@ 7#s   Cc                 :    t        j                  t        |       d uS N)rematchHOSTNAME_RE)r   s    r)   is_valid_hostnamer0     s    88K*$66    c                 l    	 t        j                  | d      }t        |      | k(  S # t        $ r Y yw xY w)Nr!   )versionF)uuidUUID
ValueErrorstr)myuuidvals     r)   is_valid_uuidr:     s<    ii* s8v  s   ' 	33c                 2    d| v r| j                  d      S | gS )N,)split)ss    r)   listify_string_name_or_idr?     s    
axwws|s
r1   c                    | j                   j                  d      }| j                   j                  d      }| j                   j                  d      }t        |t              rt	        |      }t        |t
              st        d|z        |D cg c]  }|j                          }}t        |      dkD  r|dkD  rd}t        |      t        |      dk(  r^|dkD  rY|d   }t        |||z         }t        j                  d|      r|D cg c]  }||z  	 }}n|dkD  rd	|z  }|D cg c]  }||z  	 }}|D ]  }	t        |	      rt        d
|	z         t        |      t        kD  rt        dt        z        |S c c}w c c}w c c}w )N	hostnamescountcount_offsetz"name %s is not convertible to list   zhIf you set count>1, you should only specify one hostname with the %d formatter, not a list of hostnames.r   z	%\d{0,2}dz%s%%02dz'Hostname '%s' does not seem to be validz+You specified too many hostnames, max is %d)paramsget
isinstancer7   r?   list	Exceptionstriplenranger-   searchr0   MAX_DEVICES)
modulerA   rB   rC   h_msghostname_speccount_rangeihns
             r)   get_hostname_listrV     s    !!+.IMMg&E==$$^4L)S!-i8	i&<yHII %..q.I.IBoI!%!)!!L,*>?99\=14?@q*@I@QY%5M4?@q*@I@ L $EJKKL 9~#E#$ % 	%/ / A As   E:	E?&Fc                 >   | j                   j                  d      }t        |t              rt	        |      }|D cg c]  }|j                          }}|D ]  }t        |      rt        d|z         t        |      t        kD  rt        dt        z        |S c c}w )N
device_idsz(Device ID '%s' does not seem to be validz)You specified too many devices, max is %d)
rE   rF   rG   r7   r?   rJ   r:   rI   rK   rN   )rO   rX   dis      r)   get_device_id_listrZ     s    ""<0J*c".z:
'12"((*2J2 MR FKLLM :$C#$ % 	% 3s   Bc                    dD ]+  }| j                   j                  |      rt        d|z         | j                   j                  d      }| j                   j                  d      }| j                   j                  d      }| j                   j                  d      }| j                   j                  d      }| j                   j                  d      }	| j                   j                  d	      }
| j                   j                  d
      }| j                   j                  d      }|	dk7  r0dD ]+  }| j                   j                  |      st        d|z         |j                  ||||||	||
||
      }|S )N)rA   operating_systemplanz(%s parameter is required for new device.
project_idr]   r   	user_datafacilityr\   r   ipxe_script_url
always_pxecustom_ipxe)ra   rb   z?%s parameter is not valid for non custom_ipxe operating_system.)
r^   r   r   r]   r`   r\   userdatar   ra   rb   )rE   rF   rI   create_device)rO   packet_connr   paramr^   r]   r   r_   r`   r\   r   ra   rb   r%   s                 r)   create_single_devicerh     sm   : %}}  'F#$ % %% ""<0J==V$D==V$D!!+.I}}  ,H}}(();<]]x(Fmm''(9:O""<0J=(6 	kE}}  ' adi ijj	k &&)' ' 
F Mr1   c                     |D cg c]  }|j                    }}t        | |      }|D cg c]  }|j                   |v s| c}S c c}w c c}w r,   )r   get_existing_devices)rO   rf   devicesdrX   new_device_lists         r)   refresh_device_listrn     sI     '(1!$$(J(*6;?O&=!!$$**<A== )=s   AA
A
c                    | j                   j                  d      }t        j                         |z   }|}|t        j                         kD  rNt        | ||      }t	        d |D              r|S t        j
                  d       |t        j                         kD  rNt        d|D cg c]  }|j                  dk7  s|j                    c}z        c c}w )Nwait_timeoutc              3   :   K   | ]  }|j                   d k(    yw)r   N)r   ).0rl   s     r)   	<genexpr>z*wait_for_devices_active.<locals>.<genexpr>  s     6qqww("6s      z4Waiting for state "active" timed out for devices: %sr   )	rE   rF   timern   allsleeprI   r   r   )rO   rf   watched_devicesrp   	refreshedrl   s         r)   wait_for_devices_activerz     s    ==$$^4L99;-LI

$'_M	6I66

1	 
$
 L+4La88KqzzLM N NLs   $C
9C
c                    d fd}| j                   j                  d      }| j                   j                  d      }t        j                         |z   }|t        j                         kD  rEt        | ||      } |||      r|S t        j                  d       |t        j                         kD  rEt        d||D cg c]  }|j                   c}fz        c c}w )Nc                 ,    t        fd| D              S )Nc              3   J   K   | ]  }|d    xr |d   k(  xr |d     yw)r   r   r   N )rr   aip_vs     r)   rs   z=wait_for_public_IPv.<locals>.has_public_ip.<locals>.<genexpr>	  s2     cTU1X;O1%5#6$#>O1Y<Ocs    #)any)	addr_listr   s    `r)   has_public_ipz*wait_for_public_IPv.<locals>.has_public_ip  s    cYbcccr1   c                 0    t        fd| D              S )Nc              3   D   K   | ]  } |j                           y wr,   )r   )rr   rl   r   r   s     r)   rs   zBwait_for_public_IPv.<locals>.all_have_public_ip.<locals>.<genexpr>  s     C1=6Cs    )rv   )dsr   r   s    `r)   all_have_public_ipz/wait_for_public_IPv.<locals>.all_have_public_ip  s    CCCCr1   wait_for_public_IPvrp   rt   z2Waiting for IPv%d address timed out. Hostnames: %s)rE   rF   ru   rn   rw   rI   r   )	rO   rf   created_devicesr   r   rp   ry   rl   r   s	           @r)   r   r     s    dD ]]&&'<=N==$$^4L99;-L

$'_M	i8

1	 
$ H%O'Lq

'LMN O O'Ls   >Cc                 j    | j                   j                  d      }|j                  |dt        i      S )Nr^   per_page)rE   )rE   rF   list_devicesrN   )rO   rf   r^   s      r)   rj   rj     s;    ""<0J##% $ & &r1   c                     | j                   j                  d      rt        |       }|g dS | j                   j                  d      rt        |       }|g dS y )NrX   )idsrA   rA   )rA   r   )rE   rF   rZ   rV   )rO   device_id_listhostname_lists      r)    get_specified_device_identifiersr   #  sU    }}&+F3%B77			;	')&1*266 
(r1   c                 f   t        |       }t        | |      }d}g }|dv r/|D cg c]  }|j                   }}|d   D 	cg c]  }	|	|vr|	
 }}	|D 
cg c]&  }
|
j                  |d   v s|
j                  |d   v r|
( }}
|dk7  ri }t        D ]  }t
        j                  j                  ||<   ! |t
        j                  j                  d d ddt
        j                  j                  it
        j                  j                  t
        j                  j                  d d dd	}|D ]x  }
|
j                  |k(  r|
j                  ||   v r,||   j                  |
j                        }|E ||
       d
}Pd|
j                  d|
j                  d|}t        |       g }|rD|D cg c]  }t        | ||       }}| j                  j                  d      rt!        | ||      }d
}||z   }|dk(  rt#        | ||      }||D 
cg c]  }
t%        |
       c}
dS c c}w c c}	w c c}
w c c}w c c}
w )NF)r   r   r   rA   r   r   )r   r
   r   r   )r   r   r
   r   )r   r   r   r   Tz,I don't know how to process existing device z from state z
 to state r   )changedrk   )r   rj   r   r   PACKET_DEVICE_STATESpacketDevicedeletepower_on	power_offrebootr   rF   rI   rh   rE   r   rz   r*   )rO   rf   target_statespecified_identifiersexisting_devicesr   create_hostnamesedexisting_devices_namesrU   rl   process_devices_absent_state_mapr>   	state_mapapi_operationrQ   r   nprocessed_devicess                       r)   act_on_devicesr   ,  s   <VD+FK@G888H!I""++!I!I)>{)K A2!)??  A A #3 KQ44#8#??

&;K&HH  KO K y % 	8A#)==#7#7a 	8 (#)==#9#9'+$ "6==#:#:;#)==#7#7%+]]%;%;)-D

	 ! 	&Aww,&ww)L11 ), 7 ; ;AGG D ,!!$"G	 2 ZZ,8   o%	&  O$46  0QG 6 6==231_6O'/9x3K!24 1BCA$Q'C q "JAKP6 Ds   H H+H$'H)H.c                  h   t        t        d6i dt        t        j                  j	                  t
              d      dt        dd      dt        dd      d	t        d
d      dt               dt        d      dt        d
ddg      dt        d
d      dt        dddg      dt               dt               dt        d      dt        t        d       d!t               d"t        dd#d$g%      d&t        dd'      d(t        d)*      d+t        dd      d,gg d-.      } t        s| j                  d/0       | j                  j	                  d      sd1t
        z  }| j                  |0       | j                  j	                  d      }t        j                  |2      }| j                  j	                  d      }	  | j                  d6i t        | ||       y # t        $ r>}| j                  d3|d4t        |      t!        j"                         5       Y d }~y d }~ww xY w)7N
auth_tokenT)defaultno_logrB   intrD   )typer   rC   rX   rH   r7   )r   elementsr`   featuresdict)r   rA   name)r   r   aliasesr   r   boolFlock)r   r   r   r\   r]   r^   )requiredr   r   )choicesr   r_   r   r!   r   )r   r   rp   i  ra    )r   rb   )rX   rA   ))rA   rX   )rB   rX   )rC   rX   )argument_specrequired_one_ofmutually_exclusivezpacket required for this module)msgz[if Packet API token is not in environment variable %s, the auth_token parameter is required)r   zfailed to set device state z	, error: )r   	exceptionr~   )r   r   osenvironrF   PACKET_API_TOKEN_ENV_VARALLOWED_STATESHAS_PACKET_SDK	fail_jsonrE   r   Manager	exit_jsonr   rI   r   	traceback
format_exc)rO   	_fail_msgr   rf   r   es         r)   mainr   q  s=    
BJJNN3K$L#')
 E1-
 5!4	

 %8
 V
 v&
 I
 6E2
 VUVHE
 "V
 
 T*
 ~yA
 f
  !%%!Q @!
" 5#6#
$ !,%
& 7'
* 66
/F< >?==\*<-.	 	Y'""<0J..J7KMMg&ERF>&+uEF R1/:C:N:N:P 	 	R 	RRs   G* *	H134H,,H1__main__)+
__future__r   r   r   r   __metaclass__DOCUMENTATIONEXAMPLESRETURNr   r-   ru   r4   r   ansible.module_utils.basicr   +ansible.module_utils.common.text.convertersr   r   r   ImportErrorformatNAME_REr/   rN   r   r   r   r*   r0   r:   r?   rV   rZ   rh   rn   rz   r   rj   r   r   r   __name__r~   r1   r)   <module>r      s   A @Sj`D
. 
 	    4 A
 
$
$^5E
F$$W-	  .  IBJ7$N$D>
NO,&7BJ2Rj zF   Ns   B B)(B)