
    Vh                     T   d dl mZmZmZ eZd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mZ dZ	 d dlZdZdZ	 d dlZd d
lmZ d dlmZ dZd dlmZmZ  G d d      Zd Ze dk(  r e        yy# e$ r  ej(                         Zd	ZY Rw xY w# e$ r  ej(                         Zd	ZdZY ]w xY w)    )absolute_importdivisionprint_functiona  
module: clc_server
short_description: Create, Delete, Start and Stop servers in CenturyLink Cloud
description:
  - An Ansible module to Create, Delete, Start and Stop servers in CenturyLink Cloud.
deprecated:
  removed_in: 11.0.0
  why: >
    Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
    See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
  alternative: There is none.
extends_documentation_fragment:
  - community.general.attributes
  - community.general.clc
author:
  - "CLC Runner (@clc-runner)"
attributes:
  check_mode:
    support: full
  diff_mode:
    support: none
options:
  additional_disks:
    description:
      - The list of additional disks for the server.
    type: list
    elements: dict
    default: []
  add_public_ip:
    description:
      - Whether to add a public IP to the server.
    type: bool
    default: false
  alias:
    description:
      - The account alias to provision the servers under.
    type: str
  anti_affinity_policy_id:
    description:
      - The anti-affinity policy to assign to the server. This is mutually exclusive with O(anti_affinity_policy_name).
    type: str
  anti_affinity_policy_name:
    description:
      - The anti-affinity policy to assign to the server. This is mutually exclusive with O(anti_affinity_policy_id).
    type: str
  alert_policy_id:
    description:
      - The alert policy to assign to the server. This is mutually exclusive with O(alert_policy_name).
    type: str
  alert_policy_name:
    description:
      - The alert policy to assign to the server. This is mutually exclusive with O(alert_policy_id).
    type: str
  count:
    description:
      - The number of servers to build (mutually exclusive with O(exact_count)).
    default: 1
    type: int
  count_group:
    description:
      - Required when exact_count is specified. The Server Group use to determine how many servers to deploy.
    type: str
  cpu:
    description:
      - How many CPUs to provision on the server.
    default: 1
    type: int
  cpu_autoscale_policy_id:
    description:
      - The autoscale policy to assign to the server.
    type: str
  custom_fields:
    description:
      - The list of custom fields to set on the server.
    type: list
    default: []
    elements: dict
  description:
    description:
      - The description to set for the server.
    type: str
  exact_count:
    description:
      - Run in idempotent mode. Will insure that this exact number of servers are running in the provided group, creating
        and deleting them to reach that count. Requires O(count_group) to be set.
    type: int
  group:
    description:
      - The Server Group to create servers under.
    type: str
    default: 'Default Group'
  ip_address:
    description:
      - The IP Address for the server. One is assigned if not provided.
    type: str
  location:
    description:
      - The Datacenter to create servers in.
    type: str
  managed_os:
    description:
      - Whether to create the server as 'Managed' or not.
    type: bool
    default: false
    required: false
  memory:
    description:
      - Memory in GB.
    type: int
    default: 1
  name:
    description:
      - A 1 to 6 character identifier to use for the server. This is required when O(state=present).
    type: str
  network_id:
    description:
      - The network UUID on which to create servers.
    type: str
  packages:
    description:
      - The list of blue print packages to run on the server after its created.
    type: list
    elements: dict
    default: []
  password:
    description:
      - Password for the administrator / root user.
    type: str
  primary_dns:
    description:
      - Primary DNS used by the server.
    type: str
  public_ip_protocol:
    description:
      - The protocol to use for the public IP if O(add_public_ip=true).
    type: str
    default: 'TCP'
    choices: ['TCP', 'UDP', 'ICMP']
  public_ip_ports:
    description:
      - A list of ports to allow on the firewall to the servers public IP, if O(add_public_ip=true).
    type: list
    elements: dict
    default: []
  secondary_dns:
    description:
      - Secondary DNS used by the server.
    type: str
  server_ids:
    description:
      - Required for started, stopped, and absent states. A list of server IDs to ensure are started, stopped, or absent.
    type: list
    default: []
    elements: str
  source_server_password:
    description:
      - The password for the source server if a clone is specified.
    type: str
  state:
    description:
      - The state to insure that the provided resources are in.
    type: str
    default: 'present'
    choices: ['present', 'absent', 'started', 'stopped']
  storage_type:
    description:
      - The type of storage to attach to the server.
    type: str
    default: 'standard'
    choices: ['standard', 'hyperscale']
  template:
    description:
      - The template to use for server creation. Will search for a template if a partial string is provided. This is required
        when O(state=present).
    type: str
  ttl:
    description:
      - The time to live for the server in seconds. The server will be deleted when this time expires.
    type: str
  type:
    description:
      - The type of server to create.
    type: str
    default: 'standard'
    choices: ['standard', 'hyperscale', 'bareMetal']
  configuration_id:
    description:
      - Only required for bare metal servers. Specifies the identifier for the specific configuration type of bare metal server
        to deploy.
    type: str
  os_type:
    description:
      - Only required for bare metal servers. Specifies the OS to provision with the bare metal server.
    type: str
    choices: ['redHat6_64Bit', 'centOS6_64Bit', 'windows2012R2Standard_64Bit', 'ubuntu14_64Bit']
  wait:
    description:
      - Whether to wait for the provisioning tasks to finish before returning.
    type: bool
    default: true
aF  
# Note - You must set the CLC_V2_API_USERNAME And CLC_V2_API_PASSWD Environment variables before running these examples

- name: Provision a single Ubuntu Server
  community.general.clc_server:
    name: test
    template: ubuntu-14-64
    count: 1
    group: Default Group
    state: present

- name: Ensure 'Default Group' has exactly 5 servers
  community.general.clc_server:
    name: test
    template: ubuntu-14-64
    exact_count: 5
    count_group: Default Group
    group: Default Group

- name: Stop a Server
  community.general.clc_server:
    server_ids:
      - UC1ACCT-TEST01
    state: stopped

- name: Start a Server
  community.general.clc_server:
    server_ids:
      - UC1ACCT-TEST01
    state: started

- name: Delete a Server
  community.general.clc_server:
    server_ids:
      - UC1ACCT-TEST01
    state: absent
a  
server_ids:
  description: The list of server IDs that are created.
  returned: success
  type: list
  sample: ["UC1TEST-SVR01", "UC1TEST-SVR02"]
partially_created_server_ids:
  description: The list of server IDs that are partially created.
  returned: success
  type: list
  sample: ["UC1TEST-SVR01", "UC1TEST-SVR02"]
servers:
  description: The list of server objects returned from CLC.
  returned: success
  type: list
  sample:
      [
          {
            "changeInfo":{
                "createdBy":"service.wfad",
                "createdDate":1438196820,
                "modifiedBy":"service.wfad",
                "modifiedDate":1438196820
            },
            "description":"test-server",
            "details":{
                "alertPolicies":[

                ],
                "cpu":1,
                "customFields":[

                ],
                "diskCount":3,
                "disks":[
                  {
                      "id":"0:0",
                      "partitionPaths":[

                      ],
                      "sizeGB":1
                  },
                  {
                      "id":"0:1",
                      "partitionPaths":[

                      ],
                      "sizeGB":2
                  },
                  {
                      "id":"0:2",
                      "partitionPaths":[

                      ],
                      "sizeGB":14
                  }
                ],
                "hostName":"",
                "inMaintenanceMode":false,
                "ipAddresses":[
                  {
                      "internal":"10.1.1.1"
                  }
                ],
                "memoryGB":1,
                "memoryMB":1024,
                "partitions":[

                ],
                "powerState":"started",
                "snapshots":[

                ],
                "storageGB":17
            },
            "groupId":"086ac1dfe0b6411989e8d1b77c4065f0",
            "id":"test-server",
            "ipaddress":"10.120.45.23",
            "isTemplate":false,
            "links":[
                {
                  "href":"/v2/servers/wfad/test-server",
                  "id":"test-server",
                  "rel":"self",
                  "verbs":[
                      "GET",
                      "PATCH",
                      "DELETE"
                  ]
                },
                {
                  "href":"/v2/groups/wfad/086ac1dfe0b6411989e8d1b77c4065f0",
                  "id":"086ac1dfe0b6411989e8d1b77c4065f0",
                  "rel":"group"
                },
                {
                  "href":"/v2/accounts/wfad",
                  "id":"wfad",
                  "rel":"account"
                },
                {
                  "href":"/v2/billing/wfad/serverPricing/test-server",
                  "rel":"billing"
                },
                {
                  "href":"/v2/servers/wfad/test-server/publicIPAddresses",
                  "rel":"publicIPAddresses",
                  "verbs":[
                      "POST"
                  ]
                },
                {
                  "href":"/v2/servers/wfad/test-server/credentials",
                  "rel":"credentials"
                },
                {
                  "href":"/v2/servers/wfad/test-server/statistics",
                  "rel":"statistics"
                },
                {
                  "href":"/v2/servers/wfad/510ec21ae82d4dc89d28479753bf736a/upcomingScheduledActivities",
                  "rel":"upcomingScheduledActivities"
                },
                {
                  "href":"/v2/servers/wfad/510ec21ae82d4dc89d28479753bf736a/scheduledActivities",
                  "rel":"scheduledActivities",
                  "verbs":[
                      "GET",
                      "POST"
                  ]
                },
                {
                  "href":"/v2/servers/wfad/test-server/capabilities",
                  "rel":"capabilities"
                },
                {
                  "href":"/v2/servers/wfad/test-server/alertPolicies",
                  "rel":"alertPolicyMappings",
                  "verbs":[
                      "POST"
                  ]
                },
                {
                  "href":"/v2/servers/wfad/test-server/antiAffinityPolicy",
                  "rel":"antiAffinityPolicyMapping",
                  "verbs":[
                      "PUT",
                      "DELETE"
                  ]
                },
                {
                  "href":"/v2/servers/wfad/test-server/cpuAutoscalePolicy",
                  "rel":"cpuAutoscalePolicyMapping",
                  "verbs":[
                      "PUT",
                      "DELETE"
                  ]
                }
            ],
            "locationId":"UC1",
            "name":"test-server",
            "os":"ubuntu14_64Bit",
            "osType":"Ubuntu 14 64-bit",
            "status":"active",
            "storageType":"standard",
            "type":"standard"
          }
      ]
z
${version}N)LooseVersionTF)CLCException)APIFailedResponse)AnsibleModulemissing_required_libc                      e Zd ZeZd Zd Zed        Zd Z	ed        Z
ed        Zed        Zed        Zed	        Zed
        Zed        Zed        Zed        Zed        Zed        Zed        Zed        Zd%dZd Zed        Zed        Zed        Zed        Zed        Zed        Zed        Zed        Z ed        Z!ed        Z"ed%d       Z#ed         Z$ed!        Z%ed"        Z&e	 d&d#       Z'ed$        Z(y)'	ClcServerc                    t         | _        || _        i | _        t        s*| j                  j                  t        d      t               t        s*| j                  j                  t        d      t               t        j                  rAt        t        j                        t        d      k  r| j                  j                  d       | j                  | j                         y)z"
        Construct module
        zclc-sdk)msg	exceptionrequestsz2.5.0z,requests library  version should be >= 2.5.0r   N)clc_sdkclcmodule
group_dict	CLC_FOUND	fail_jsonr
   CLC_IMP_ERRREQUESTS_FOUNDREQUESTS_IMP_ERRr   __version__r   _set_user_agent)selfr   s     p/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/general/plugins/modules/clc_server.py__init__zClcServer.__init__  s     KK!!&:9&EQ\!]KK!!&::&FRb!cL1E1E$FV]I^$^KK!!B " D 	TXX&    c                 4   d}g }g }| j                          | j                  | j                  | j                        | j                  _        | j                  j                  }|j                  d      }g }|dk(  rb|d   }t        |t              s| j                  j                  d|z        S | j                  | j                  | j                  |      \  }}}n|dv rl|j                  d      }t        |t              s| j                  j                  d	|z        S | j                  | j                  | j                  |      \  }}}n|d
k(  r|j                  d      s0|j                  d      dk7  r| j                  j                  d      S |j                  d      ,| j                  | j                  | j                        \  }}}}n+| j                  | j                  | j                        \  }}}}| j                  j                  ||||       y)zu
        Process the request - Main Code Path
        :return: Returns with either an exit_json or fail_json
        Fstateabsent
server_idsz8server_ids needs to be a list of instances to delete: %sr   )r   r   r$   )startedstoppedz3server_ids needs to be a list of servers to run: %spresenttemplatetype	bareMetalz/template parameter is required for new instanceexact_countN)changedr$   partially_created_server_idsservers)_set_clc_credentials_from_env_validate_module_paramsr   r   paramsget
isinstancelistr   _delete_servers_start_stop_servers_create_servers_enforce_count	exit_json)r   r,   new_server_idsserver_dict_arraypr"   partial_servers_idsr$   s           r   process_requestzClcServer.process_request  s0   
 **,!99HHKK KKg
 !H<Jj$/{{,,R -      $334;;8<?I  4  KW ,,|,Jj$/{{,,M -      $778<8B DW i55$v+)E{{,,I - K K uu]#+ !0015;"$ !//04:"$ 	%)<%	 	 	'r    c            
         t        d@i dt               dt               dt        d      dt               dt               dt        d	d
      dt        d	d
      dt               dt        d      dt               dt        dddg      dt        dg d      dt               dt               dt        dg d      dt        dg d      dt               d t        d!d"#      d$t               d%t        d      d&t               d't               d(t               d)t               d*t               d+t        dg d      d,t        d-g d.      d/t        d
d	#      d0t        d
1      d2t               d3t        dg d4      d5t        d!d"#      d6t        d7g d8      d9t        dg d      d:t               d;t        g d<=      d>t        d!d#      } d0d/gd0d,gd'd(gd)d*gg}| |d?S )Azk
        Define the argument spec for the ansible module
        :return: argument spec dictionary
        namer(   groupzDefault Group)default
network_idlocationcpu   int)rB   r)   memoryaliaspasswordT)no_log
ip_addressstorage_typestandard
hyperscale)rB   choicesr)   )rN   rO   r*   primary_dnssecondary_dnsadditional_disksr4   dict)r)   rB   elementscustom_fieldsttl
managed_osboolF)r)   rB   descriptionsource_server_passwordcpu_autoscale_policy_idanti_affinity_policy_idanti_affinity_policy_namealert_policy_idalert_policy_namepackagesr"   r'   )r'   r#   r%   r&   countr+   )r)   count_groupr$   stradd_public_ippublic_ip_protocolTCP)rg   UDPICMPpublic_ip_portsconfiguration_idos_type)redHat6_64BitcentOS6_64Bitwindows2012R2Standard_64Bitubuntu14_64Bit)rP   waitargument_specmutually_exclusive )rT   rr   s     r   _define_module_argument_specz&ClcServer._define_module_argument_spec'  s     9292V92 /92 v	92
 V92 QU+92 .92 &92 &92 v92 " "#92  j2YZ!92" #92$ &%92& "vrFK'92( FBH)92* +92, 7-92. /920 $(t#41922 %)F3924 %)F5926 '+f7928 !F992: #f;92< vrFC=92> ! ?92L E1-M92N %*O92P Q92R eDS92T FE:U92V  $ W92b !fb6Jc92d "Ve92f  " g92r 640s92x G$G$&(CD 34	
 "/&8: 	:r    c                    t         j                  }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|r|| j                  j                  _        |r6|r4|| j                  _        d| j                  _        || j                  _        y|r*|r(| j                  j                  j                  ||       y| j                  j                  d	
      S )zk
        Set the CLC Credentials on the sdk by reading environment variables
        :return: none
        CLC_V2_API_TOKENFCLC_V2_API_USERNAMECLC_V2_API_PASSWDCLC_ACCT_ALIASCLC_V2_API_URLT)api_username
api_passwdzPYou must set the CLC_V2_API_USERNAME and CLC_V2_API_PASSWD environment variablesr   N)osenvironr2   r   defaultsENDPOINT_URL_V2_LOGIN_TOKEN_V2_V2_ENABLEDALIASv2SetCredentialsr   r   )r   envv2_api_tokenv2_api_usernamev2_api_passwd	clc_aliasapi_urls          r   r/   z'ClcServer._set_clc_credentials_from_envq  s    
 jjww159''"7? 3U;GG,e4	''*E207DHH-I'3DHH$#'DHH &DHHNHHKK&&,( ' * ;;((, ) - -r    c                    |j                   }t        j                  | |      }t        j                  |       t        j	                  |       t        j                  | |      |d<   t        j                  | |      |d<   t        j                  | |      |d<   t        j                  |      |d<   t        j                  | |      |d<   t        j                  ||      |d<   t        j                  ||      j                  |d<   t        j                  ||      |d<   t        j                  | |      |d	<   t        j                  | |      |d
<   |S )z
        Validate the module params, and lookup default values.
        :param clc: clc-sdk instance to use
        :param module: module to validate
        :return: dictionary of validated params
        rI   rE   rH   rZ   rW   r(   rA   rC   r]   r_   )r1   r   _find_datacenter_validate_types_validate_name_find_alias	_find_cpu_find_memory_find_description	_find_ttl_find_template_id_find_groupid_find_network_id_find_aa_policy_id_find_alert_policy_id)r   r   r1   
datacenters       r   r0   z!ClcServer._validate_module_params  s4    //V<
!!&)  (#//V<w!++C8u$11#v>x ) ; ;F C}!++C8u&88Lz#//
CFFw(99&*M|,5,H,H-() %.$C$C% ! r    c                 B   |j                   j                  d      }	 |s5| j                  j                         }|j                  j                  d      }| j                  j                  |      }|S # t        $ r$ |j                  dj                  |             Y yw xY w)z
        Find the datacenter by calling the CLC API.
        :param clc: clc-sdk instance to use
        :param module: module to validate
        :return: clc-sdk.Datacenter instance
        rD   primaryDataCenterzUnable to find location: {0}r   N)	r1   r2   r   Accountdata
Datacenterr   r   format)r   r   rD   accountdata_centers        r   r   zClcServer._find_datacenter  s     ==$$Z0	R&&..*"<<++,?@&&++H5K 	R!?!F!Fx!PQ	Rs   AA1 1*BBc                    |j                   j                  d      }|s'	 | j                  j                  j	                         }|S |S # t
        $ r6}|j                  dj                  |j                               Y d}~|S d}~ww xY w)z
        Find or Validate the Account Alias by calling the CLC API
        :param clc: clc-sdk instance to use
        :param module: module to validate
        :return: clc-sdk.Account instance
        rI   z!Unable to find account alias. {0}r   N)	r1   r2   r   r   GetAliasr   r   r   message)r   r   rI   exs       r   r   zClcServer._find_alias  s     !!'*//1
 u	     %H%O%OJJ&    	s   $A 	B+BBc                    |j                   j                  d      }|j                   j                  d      }|j                   j                  d      }|j                   j                  d      }|sa|dk(  r\| j                  j                  ||      }|j	                  d      r|j	                  d      }|S |j                  t        d             |S )	z
        Find or validate the CPU value by calling the CLC API
        :param clc: clc-sdk instance to use
        :param module: module to validate
        :return: Int value for CPU
        rE   group_idrI   r"   r'   r   rI   zDCan't determine a default cpu value. Please provide a value for cpu.r   r1   r2   r   GroupDefaultsr   rd   )r   r   rE   r   rI   r"   rA   s          r   r   zClcServer._find_cpu  s     mm&==$$Z0!!'*!!'*u	)FFLLH', ! .E~~e$nnU+ 
   cd ! f
r    c                    |j                   j                  d      }|j                   j                  d      }|j                   j                  d      }|j                   j                  d      }|sa|dk(  r\| j                  j                  ||      }|j	                  d      r|j	                  d      }|S |j                  t        d             |S )	z
        Find or validate the Memory value by calling the CLC API
        :param clc: clc-sdk instance to use
        :param module: module to validate
        :return: Int value for Memory
        rH   r   rI   r"   r'   r   zJCan't determine a default memory value. Please provide a value for memory.r   r   )r   r   rH   r   rI   r"   rA   s          r   r   zClcServer._find_memory  s     ""8,==$$Z0!!'*!!'*%9,FFLLH', ! .E~~h'1    Sa&c  dr    c                 v    | j                   j                  d      }|s| j                   j                  d      }|S )z
        Set the description module param to name if description is blank
        :param module: the module to validate
        :return: string description
        rZ   r@   )r1   r2   )r   rZ   s     r   r   zClcServer._find_description  s5     mm''6 --++F3Kr    c                    | j                   j                  d      }| j                   j                  d      r)| j                   j                  d      j                         nd}| j                   j                  d      r)| j                   j                  d      j                         nd}|dk(  rL|dk(  r|dvr| j                  t	        d      	       |d
k(  r"|d
k7  r| j                  t	        d      	       yyyy)z
        Validate that type and storage_type are set appropriately, and fail if not
        :param module: the module to validate
        :return: none
        r"   r)   NrM   r'   rN   )rN   premiumz=Standard VMs must have storage_type = 'standard' or 'premium'r   rO   z4Hyperscale VMs must have storage_type = 'hyperscale')r1   r2   lowerr   rd   )r   r"   server_typerM   s       r   r   zClcServer._validate_types	  s     !!'*%}}008 mm''EGd 	 (.}}'8'8'H }}((!EGd 	 Ij(\ B+ .+  [\ ! ^ l*||/K  RS ! U 0L* r    c                     | j                   j                  d      }| j                   j                  d      }|dk(  r9t        |      dk  st        |      dkD  r| j                  t	        d             yyy)	z
        Validate that name is the correct length if provided, fail if it is not
        :param module: the module to validate
        :return: none
        r@   r"   r'   rF      zbWhen state = 'present', name must be a string with a minimum length of 1 and a maximum length of 6r   N)r1   r2   lenr   rd   )r   server_namer"   s      r   r   zClcServer._validate_name   st     mm''/!!'*IK 1$K(81(<t"v w )= r    c                    |j                   j                  d      }|rc|dk  r|j                  t        d            S | j                  j
                  j                  t        t        j                               |z         }|S )z
        Validate that TTL is > 3600 if set, and fail if not
        :param clc: clc-sdk instance to use
        :param module: module to validate
        :return: validated ttl
        rW   i  zTtl cannot be <= 3600r   )	r1   r2   r   rd   r   
time_utilsSecondsToZuluTSrG   time)r   r   rW   s      r   r   zClcServer._find_ttl/  sk     mm&d{''C0G,H'IIff''77DIIK8H38NO
r    c                    | j                   j                  d      }| j                   j                  d      }| j                   j                  d      }d}|dk(  r4|dk7  r/	 |j                         j                  |      d   j                  }|S |S # t
        $ r2 | j                  t        d|z   d	z   |j                  z         
       Y |S w xY w)z
        Find the template id by calling the CLC API.
        :param module: the module to validate
        :param datacenter: the datacenter to search for the template
        :return: a valid clc template id
        r(   r"   r)   Nr'   r*   r   zUnable to find a template:  in location: r   )r1   r2   	TemplatesSearchr   r   r   rd   )r   r   lookup_templater"   r)   results         r   r   zClcServer._find_template_id@  s     !--++J7!!'*}}  (I$+"5(#--/66GJMM v   (  5'(() #&' ! ( (s   ,B 7C
	C
c                    | j                   j                  d      }|s*	 |j                         j                  d   j                  }|S |S # t
        $ r, | j                  t        d|j                  z                Y |S w xY w)z
        Validate the provided network id or return a default.
        :param module: the module to validate
        :param datacenter: the datacenter to search for a network id
        :return: a valid network id
        rC   r   z&Unable to find a network in location: r   )r1   r2   Networksnetworksr   r   r   rd   )r   r   rC   s      r   r   zClcServer._find_network_idY  s     ]]&&|4
('002;;A>AA
 z   (  @"&' ! (
 (s   'A
 
1A?>A?c                    |j                   j                  d      }|j                   j                  d      }|sL|rJ|j                   j                  d      }t        j                  | |||      }|s|j	                  d|z         |S )a  
        Validate if the anti affinity policy exist for the given name and throw error if not
        :param clc: the clc-sdk instance
        :param module: the module to validate
        :return: aa_policy_id: the anti affinity policy id of the given name.
        r]   r^   rI   z7No anti affinity policy was found with policy name : %sr   )r1   r2   r   _get_anti_affinity_policy_idr   )r   r   aa_policy_idaa_policy_namerI   s        r   r   zClcServer._find_aa_policy_ids  s     }}(()BC**+FGMM%%g.E$AA	 L
    QTbb ! dr    c                    |j                   j                  d      }|j                   j                  d      }|sM|rK|j                   j                  d      }t        j                  | |||      }|s|j	                  d|z         |S )z
        Validate if the alert policy exist for the given name and throw error if not
        :param clc: the clc-sdk instance
        :param module: the module to validate
        :return: alert_policy_id: the alert policy id of the given name.
        r_   r`   rI   )r   r   rI   r`   z$No alert policy exist with name : %sr   )r1   r2   r   _get_alert_policy_id_by_namer   )r   r   r_   r`   rI   s        r   r   zClcServer._find_alert_policy_id  s     !--++,=>"MM--.AB#4MM%%g.E'DD"3	 E O #  >ARR ! Tr    Nc           
         |j                   }g }g }g }g }g }	|j                  d      }
|j                  d      }|j                  d      }i d|j                  d      d|j                  d      d|j                  d      d|j                  d      d	|j                  d	      d
|j                  d
      d|j                  d      d|j                  d      d|j                  d      d|j                  d      d|j                  d      d|j                  d      d|j                  d      d|j                  d      d|j                  d      d|j                  d      d|j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      d}|r|n|j                  d      }|dk(  rd nd!}|s|||	|fS t        d|      D ]b  }|j                  r| j	                  |||"      }|j
                  d   j                         }|j                  |       |j                  |       d | j                  ||       | j                  ||       | j                  ||
|||#      }| j                  |||$      }|D ]  }||v s||v r|	j                  |j                         n|j                  j                  |j                        }|j                  d%   d   d&   |j                  d'<   |
rYt!        |j#                         j$                        dkD  r3t'        |j#                         j$                  d         |j                  d(<   |j                  |j                         |j                  |j                          |||	|fS ))z
        Create New Servers in CLC cloud
        :param module: the AnsibleModule object
        :param clc: the clc-sdk instance to use
        :return: a list of dictionaries with server information about the servers that were created
        re   rf   rj   r@   r(   r   rA   rC   rE   rH   rI   rJ   rL   rM   r)   rQ   rR   rS   rV   rW   rX   rZ   r[   r\   r]   ra   rk   rl   )rZ   r[   r\   r]   ra   rk   rl   rb   r   FT)r   r   server_params)r   should_add_public_ipr.   rf   rj   )r   r   r.   ipAddressesinternal	ipaddresspublicip)r1   r2   range
check_mode_create_clc_serverr   Serverappend_wait_for_requests_refresh_servers_add_public_ip_to_servers_add_alert_policy_to_serversr   r   detailsr   r   	PublicIPs
public_ipsrd   )r   r   r   override_countr<   request_listr.   r;   created_server_idspartial_created_servers_idsre   rf   rj   r1   rb   r,   ireqserverip_failed_serversap_failed_serverss                        r   r7   zClcServer._create_servers  s    MM&(#o.UU#78%% 12
AEE&M
j)
 g
 !%%-	

 155<
 aeeHo
 QUU7^
 j)
 !%%-
 AEE.1
 AEE&M
 155/
 QUU?3
 &8 9
 QUU?3
  155<!
" !%%-#
$ 55/&'ee,D&E'(uu-F'G'(uu-F'Gj) !&8 9uuY'1
6 #1aeeGn A:%4$&8:UW^^^q% 	'A$$--#5;<B . D a//1##C(v&	' 	5fg. ::!.1+ ; - !==#EKFM > O  	2F**f8I.I+22699= vyy1+1>>!,##$,&&0,2K( !S)9)9);)F)F%G!%K.1((*55a8/:FKK
+"))&))4$$V[[1	2 !"46QSZZZr    c                    |j                   }d}|j                  d      }t        j                  ||      }|j                  d      }g }g }	g }
|r||j	                  d      S t        j                  |||      \  }}t        |      |k(  rd}nt        |      |k  r@|t        |      z
  }| j                  |||      \  }}
}	}|D ]  }|j                  |        n_t        |      |kD  rQt        |      |z
  }t        |D cg c]  }|j                   c}      }|d| }t        j                  |||      \  }}}
||
|	|fS c c}w )aW  
        Enforce that there is the right number of servers in the provided group.
        Starts or stops servers as necessary.
        :param module: the AnsibleModule object
        :param clc: the clc-sdk instance to use
        :return: a list of dictionaries with server information about the servers that were created or deleted
        Frc   r+   z6you must use the 'count_group' option with exact_countr   )r   r   )r1   r2   r   r   r   _find_running_servers_by_groupr   r7   r   sortedr   r5   )r   r   r   r<   r,   rc   r   r+   r;   r=   changed_server_idsr.   running_servers	to_creater   	to_removexall_server_ids
remove_idss                      r   r8   zClcServer._enforce_count  s    MMeeM*//V<
eeM*  ;.##L $ N N $-#K#KJ$-  ;.G!K/#c/&::I&&vs9&M P13F , /&&v./ !K/O,{:I#?$CaQTT$CDN')4J ++FCD =W'); !"46I7RR %Ds   Ec                     | j                   j                  d      }|r@t        |D cg c]  }|j                          c}      }|dkD  r| j	                  d       yyyc c}w )z
        Block until server provisioning requests are completed.
        :param module: the AnsibleModule object
        :param request_list: a list of clc-sdk.Request instances
        :return: none
        rq   r   z Unable to process server requestr   N)r1   r2   sumWaitUntilCompleter   )r   r   rq   requestfailed_requests_counts        r   r   zClcServer._wait_for_requests)  sn     }}  ($'<HI**,I%K! %q(  : ! < )  Js   Ac                     |D ]  }	 |j                           y# t        $ r@}| j                  dj                  |j                  |j
                               Y d}~[d}~ww xY w)z
        Loop through a list of servers and refresh them.
        :param module: the AnsibleModule object
        :param servers: list of clc-sdk.Server instances to refresh
        :return: none
        z%Unable to refresh the server {0}. {1}r   N)Refreshr   r   r   r   r   )r   r.   r   r   s       r   r   zClcServer._refresh_servers;  se      	F 	     %L%S%SIIrzz&   s   	A#6AA#c                 H   g }|s|S g }g }d}|D ]  }	|j                  ||	d        	 | j                  s7|D ]2  }|j                         j                  |      }
|j                  |
       4 t
        j                  | |       |S # t        $ r |j                  |       Y 4w xY w)a  
        Create a public IP for servers
        :param module: the AnsibleModule object
        :param should_add_public_ip: boolean - whether or not to provision a public ip for servers.  Skipped if False
        :param servers: List of servers to add public ips to
        :param public_ip_protocol: a protocol to allow for the public ips
        :param public_ip_ports: list of ports to allow for the public ips
        :return: none
        N)protocolport)r   r   r   Addr   r   r   )r   r   r.   rf   rj   failed_servers	ports_lstr   r   r   r   s              r   r   z#ClcServer._add_public_ip_to_serversK  s      #!!	# 	@D/>@	@	*$$% 1F$..044Y?G ''01
 	$$V\: ! 	*!!&)	*s   AB B! B!c                    g }|j                   }|j                  d      }|j                  d      }|r7|j                  s+|D ]&  }	 t        j	                  | ||j
                  |       ( |S # t        $ r |j                  |       Y Gw xY w)a7  
        Associate the alert policy to servers
        :param clc: the clc-sdk instance to use
        :param module: the AnsibleModule object
        :param servers: List of servers to add alert policy to
        :return: failed_servers: the list of servers which failed while associating alert policy
        r_   rI   )r   rI   	server_idr_   )r1   r2   r   r   _add_alert_policy_to_serverr   r   r   )r   r   r.   r   r<   r_   rI   r   s           r   r   z&ClcServer._add_alert_policy_to_serversp  s     MM%% 12g6#4#4! 2299#"())(7	 : 92  $ 2"))&12s   #A,,B	B	c           	         	 | j                   j                  j                  dd|d|dt        j                  d|i             y# t
        $ r3}t        dj                  |t        |j                                    d}~ww xY w)	a,  
        Associate an alert policy to a clc server
        :param clc: the clc-sdk instance to use
        :param alias: the clc account alias
        :param server_id: The clc server id
        :param alert_policy_id: the alert policy id to be associated to the server
        :return: none
        POSTservers//z/alertPoliciesr   methodurlpayloadzCFailed to associate alert policy to the server : {0} with Error {1}N)
r   APICalljsondumpsr   r   r   rd   response_text)r   rI   r  r_   es        r   r  z%ClcServer._add_alert_policy_to_server  s|    	6FFJJOO5:IF

o   ! 	6U\\s1??356 6	6s   AA 	B.A>>Bc                    d}| j                   j                  j                  dd|z        }|s|S |j                  d      D ]A  }|j                  d      |k(  s|s|j                  d      },|j	                  d|z        c S  |S )	aN  
        Returns the alert policy id for the given alert policy name
        :param clc: the clc-sdk instance to use
        :param module: the AnsibleModule object
        :param alias: the clc account alias
        :param alert_policy_name: the name of the alert policy
        :return: alert_policy_id: the alert policy id
        NGETz/v2/alertPolicies/%sitemsr@   r   z8multiple alert policies were found with policy name : %sr   )r   r  r  r2   r   )r   r   rI   r`   r_   policiespolicys          r   r   z&ClcServer._get_alert_policy_id_by_name  s     66::??5*@5*HI""ll7+ 	lFzz&!%66&&,jj&6O!++VYjj , l l	l r    c                    g }g }g }t        |t              rt        |      dk  r| j                  d      S |j                  j                  |      j                         }|D ].  }| j                  r|j                  |j                                0 t        j                  | |       |D ]  }|j                  |j                          d||fS )a2  
        Delete the servers on the provided list
        :param module: the AnsibleModule object
        :param clc: the clc-sdk instance to use
        :param server_ids: list of servers to delete
        :return: a list of dictionaries with server information about the servers that were deleted
        rF   0server_ids should be a list of servers, abortingr   T)r3   r4   r   r   r   Serversr   r   Deleter   r   r   )r   r   r$   terminated_server_idsr;   r   r.   r   s           r   r5   zClcServer._delete_servers  s     !#*d+s:/B##F $ H H &&..,446 	5F$$##FMMO4	5 	$$V\: 	4F!((3	4 &(===r    c                    | j                   }|j                  d      }d}g }g }g }g }	t        |t              rt	        |      dk  r| j                  d      S |j                  j                  |      j                         }
|
D ]W  }|j                  |k7  s|j                  |       | j                  s&|	j                  t        j                  | ||             d}Y t        j                  | |	       t        j                  | |       t        ||
z         D ]  }	 |j                   d   d   d	   |j"                  d
<   t%        |j'                         j(                  d         |j"                  d<   |j                  |j"                         |j                  |j.                          |||fS # t*        t,        f$ r Y Nw xY w)aK  
        Start or Stop the servers on the provided list
        :param module: the AnsibleModule object
        :param clc: the clc-sdk instance to use
        :param server_ids: list of servers to start or stop
        :return: a list of dictionaries with server information about the servers that were started or stopped
        r"   FrF   r  r   Tr   r   r   r   r   )r1   r2   r3   r4   r   r   r   r  
powerStater   r   r   _change_server_power_stater   r   setr   r   rd   r   r   KeyError
IndexErrorr   )r   r   r$   r<   r"   r,   changed_serversr;   result_server_idsr   r.   r   s               r   r6   zClcServer._start_stop_servers  s    MMg*d+s:/B##F $ H H &&..,446 		F  E)&&v.(( ''!<<""!#$
 		 	$$V\:""6?;/G34 
	0F+1>>!,##$,&&0,2K(*-$$&11!4+6J'
 $$V[[1$$VYY/
	0 )+<<< j) s   AF--F?>F?c                 0   d}	 |dk(  r|j                         }|S |j                         }|rt        |d      r|j                  d   r|S |j	                         }	 |S # t
        $ r/ | j                  dj                  |j                               Y |S w xY w)a  
        Change the server powerState
        :param module: the module to check for intended state
        :param server: the server to start or stop
        :param state: the intended powerState for the server
        :return: the request object from clc-sdk call
        Nr%   r   r   z+Unable to change power state for server {0}r   )	PowerOnShutDownhasattrr   PowerOffr   r   r   r   )r   r   r"   r   s       r   r  z$ClcServer._change_server_power_state  s     	 	!)   *gfj9fooa>P!M#__.F
 	  	 AHHII    		 s   A .A 
A 4BBc                     t         j                  | ||      }|j                         j                         }g }|D ]3  }|j                  dk(  s|j                  dk(  s#|j                  |       5 ||fS )aE  
        Find a list of running servers in the provided group
        :param module: the AnsibleModule object
        :param datacenter: the clc-sdk.Datacenter instance to use to lookup the group
        :param count_group: the group to count the servers
        :return: list of servers, and list of running servers
        )r   r   lookup_groupactiver%   )r   r   r  statusr  r   )r   r   rc   rA   r.   r   r   s          r   r   z(ClcServer._find_running_servers_by_group!  s     %%!$ & &
 --/))+ 	/F}}(V->->)-K&&v.	/ ''r    c                 H   |s| j                   j                  d      }	 |j                         j                  |      S # t        $ r Y nw xY wt
        j                  | |j                         |      }|.| j                  t        d|z   dz   |j                  z                |S )a9  
        Find a server group in a datacenter by calling the CLC API
        :param module: the AnsibleModule instance
        :param datacenter: clc-sdk.Datacenter instance to search for the group
        :param lookup_group: string name of the group to search for
        :return: clc-sdk.Group instance
        rA   zUnable to find group: r   r   )
r1   r2   GroupsGetr   r   _find_group_recursiver   rd   r   )r   r   r)  r   s       r   r   zClcServer._find_group8  s     !==,,W5L	$$&**<88 		 00
 >, !$% MM"#  $ s   > 	A
	A
c                     d}|j                   D ]%  }|j                         }	 |j                  |      c S  |S # t        $ r t        j                  | ||      }Y nw xY w|S |S )a  
        Find a server group by recursively walking the tree
        :param module: the AnsibleModule instance to use
        :param group_list: a list of groups to search
        :param lookup_group: the group to look for
        :return: list of groups
        N)groups	Subgroupsr.  r   r   r/  )r   
group_listr)  r   rA   	subgroupss         r   r/  zClcServer._find_group_recursiveX  s     && 	E)I" }}\22	    ""88 "" !s   9 AAc                 ,    	  j                   j                  j                  ddj                  d      z  t	        j
                  i dj                  d      dj                  d      dj                  d      dj                  d	      d
j                  d      dj                  d      dj                  d      dj                  d      dj                  d      dj                  d      dj                  d      dj                  d      dj                  d      dj                  d      dj                  d      dj                  d      dj                  d       j                  d!      j                  d"      j                  d#      j                  d$      j                  d%      j                  d&      d'      (      } j                   j                  |      }|d,   D cg c]  }|d-   d.k(  r|d/    c}d0    fd1|j                  d0   _        |S # t        $ rE}j                  d)j                  j                  d      |j                        *      cY d+}~S d+}~ww xY wc c}w )2aH  
        Call the CLC Rest API to Create a Server
        :param clc: the clc-python-sdk instance to use
        :param module: the AnsibleModule instance to use
        :param server_params: a dictionary of params to use to create the servers
        :return: clc-sdk.Request object linked to the queued server request
        r  z
servers/%srI   r@   rZ   groupIdr   sourceServerIdr(   isManagedOSrX   
primaryDNSrQ   secondaryDNSrR   	networkIdrC   	ipAddressrL   rJ   sourceServerPasswordr[   rE   cpuAutoscalePolicyIdr\   memoryGBrH   r)   storageTyperM   antiAffinityPolicyIdr]   rV   rS   rW   ra   rk   rl   )customFieldsadditionalDisksrW   ra   configurationIdosTyper  z%Unable to create the server: {0}. {1}r   Nlinksrelr   r   r   c                  R    t         j                   j                  d            S )NrI   )r   _find_server_by_uuid_w_retryr2   )r   r   r   server_uuids   r   <lambda>z.ClcServer._create_clc_server.<locals>.<lambda>  s)    I,R,Rg&	-( r    )r   r  r  r2   r  r  Requestsr   r   r   r  r   r   )r   r   r   resr   r   objrJ  s   ```    @r   r   zClcServer._create_clc_serverq  s   $	&&**// ""7+-

@ 1 1& 9@%}'8'8'G@ "=#4#4Z#@@ )-*;*;J*G	@
 &}'8'8'F@ %m&7&7&F@ '(9(9/(J@ $]%6%6|%D@ $]%6%6|%D@ #M$5$5j$A@ /0A0ABZ0[@ }007@ /0A0AB[0\@ #M$5$5h$?@  1 1& 9@  &}'8'8'H!@" /0A0AB[0\#@$ )6(9(9/(J+8+<+<=O+P,007$1$5$5j$A+8+<+<=O+P"/"3"3I">/@A	 " BC< VV__S)F #&g,H#e*2F 4y HHIK
%(! + ! 	##(O(V(V!!&)  )#  	Hs$   G=I  
J 	J	:J	J	Jc                    d}	 | j                   j                  j                  dd|z        }|j                  d      D ]A  }|j                  d      |k(  s|s|j                  d	      },|j	                  d
|z        c S  |S # t        $ r6}|j	                  dj                  ||j                              cY d}~S d}~ww xY w)ai  
        retrieves the anti affinity policy id of the server based on the name of the policy
        :param clc: the clc-sdk instance to use
        :param module: the AnsibleModule object
        :param alias: the CLC account alias
        :param aa_policy_name: the anti affinity policy name
        :return: aa_policy_id: The anti affinity policy id
        Nr  zantiAffinityPolicies/%sr  r	  z<Unable to fetch anti affinity policies for account: {0}. {1}r   r  r@   r   z@multiple anti affinity policies were found with policy name : %s)r   r  r  r   r   r   r  r2   )r   r   rI   r   r   aa_policiesr   	aa_policys           r   r   z&ClcServer._get_anti_affinity_policy_id  s     	*&&**//.G%.O * QK
 %1 	qI}}V$6##,==#6L!++^aoo , q q	q  ! 	*##(f(m(mr''))# * *	*s   *B 	C+B?9C?Cc                    |s$| j                   j                  j                         }	 |dz  }	 | j                   j                  j	                  dd|d|d      }|d   }| j                   j                  |||      }|S # t        $ r}	|	j                  d	k7  r1|j                  d
||	j                  |	j                  fz        cY d}	~	S |dk(  r|j                  d      cY d}	~	S t        j                  |       |dz  }Y d}	~	nd}	~	ww xY w)a  
        Find the clc server by the UUID returned from the provisioning request.  Retry the request if a 404 is returned.
        :param clc: the clc-sdk instance to use
        :param module: the AnsibleModule object
        :param svr_uuid: UUID of the server
        :param retries: the number of retry attempts to make prior to fail. default is 5
        :param alias: the Account Alias to search
        :return: a clc-sdk.Server instance
        rF   r  r  r  z
?uuid=truerP  r   )r   rI   
server_obji  zwA failure response was received from CLC API when attempting to get details for a server:  UUID=%s, Code=%i, Message=%sr   Nr   z,Unable to reach the CLC API after 5 attempts   )r   r   r   r  r  r   r   response_status_coder   r   r   sleep)
r   r   svr_uuidrI   retriesback_outrT  r  r   r  s
             r   rI  z&ClcServer._find_server_by_uuid_w_retry  s#    FFNN++-E qLG VVZZ__ H'& - '
 't,	 ) ' + $ 
))S0!++`!1#9#9199EF , G G a<!++J , L L

8$A
 s0   AB 	D

:DD

D D
&DD
c                     t        | d      rfdt        z   }t        j                         }|j                  j                  d|i       |j                  dxx   d|z   z  cc<   | j                  |       y y )NSetRequestsSessionzClcAnsibleModule/z
Api-Clientz
User-Agent )r&  r   r   Sessionheadersupdater\  )r   agent_stringsess      r   r   zClcServer._set_user_agent  sh    3,-.<L""$CKKl;<KK%|);;%""3' .r    )N)N   rU  ))__name__
__module____qualname__r   r   r   r>   staticmethodrv   r/   r0   r   r   r   r   r   r   r   r   r   r   r   r   r7   r8   r   r   r   r   r  r   r5   r6   r  r   r   r/  r   r   rI  r   ru   r    r   r   r     s   
C'$E'N G: G:R-6  < R R"  "  ,  , 	 	 U U, w w     0  2  *  ,X[t-S^ < <"   " "H  2 6 6.  , > >6 /= /=b  2 ( (,  >  0 A AF  : CD& &P ( (r    r   c                  |    t         j                         } t        dddi| }t        |      }|j                          y)zb
    The main function.  Instantiates the module and calls process_request.
    :return: none
    supports_check_modeTNru   )r   rv   r	   r>   )argument_dictr   
clc_servers      r   mainrl    s:    
 ::<MEtE}EF6"J r    __main__)!
__future__r   r   r   r)   __metaclass__DOCUMENTATIONEXAMPLESRETURNr   r  r   r   	tracebackBansible_collections.community.general.plugins.module_utils.versionr   r   r   r   ImportError
format_excr   r   r   r   r   r   ansible.module_utils.basicr	   r
   r   rl  rd  ru   r    r   <module>rx     s    A @HT$Lh
T   	   [ 
 N 	 % I Jx( x(v!! zF "  +y++-N  &)&&(KIGs"   A, B
 ,BB
B'&B'