
    Vh<                     @   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Z	 d dlZdZdZ	 d dlmZ dZd d	lmZmZ d d
lmZ d dlmZ d dlmZ ddZd Zd Z d Z!e"dk(  r e!        yy# e$ r  e
j                          ZdZY Zw xY w# e$ r  e
j                          ZdZY mw xY w)    )absolute_importdivisionprint_functiona*  
module: imc_rest
short_description: Manage Cisco IMC hardware through its REST API
description:
  - Provides direct access to the Cisco IMC REST API.
  - Perform any configuration changes and actions that the Cisco IMC supports.
  - More information about the IMC REST API is available from
    U(http://www.cisco.com/c/en/us/td/docs/unified_computing/ucs/c/sw/api/3_0/b_Cisco_IMC_api_301.html).
author:
  - Dag Wieers (@dagwieers)
requirements:
  - lxml
  - xmljson >= 0.1.8
extends_documentation_fragment:
  - community.general.attributes
attributes:
  check_mode:
    support: full
  diff_mode:
    support: none
options:
  hostname:
    description:
      - IP Address or hostname of Cisco IMC, resolvable by Ansible control host.
    required: true
    aliases: [host, ip]
    type: str
  username:
    description:
      - Username used to login to the switch.
    default: admin
    aliases: [user]
    type: str
  password:
    description:
      - The password to use for authentication.
    default: password
    type: str
  path:
    description:
      - Name of the absolute path of the filename that includes the body of the http request being sent to the Cisco IMC REST
        API.
      - Parameter O(path) is mutual exclusive with parameter O(content).
    aliases: ['src', 'config_file']
    type: path
  content:
    description:
      - When used instead of O(path), sets the content of the API requests directly.
      - This may be convenient to template simple requests, for anything complex use the M(ansible.builtin.template) module.
      - You can collate multiple IMC XML fragments and they will be processed sequentially in a single stream, the Cisco IMC
        output is subsequently merged.
      - Parameter O(content) is mutual exclusive with parameter O(path).
    type: str
  protocol:
    description:
      - Connection protocol to use.
    default: https
    choices: [http, https]
    type: str
  timeout:
    description:
      - The socket level timeout in seconds.
      - This is the time that every single connection (every fragment) can spend. If this O(timeout) is reached, the module
        will fail with a C(Connection failure) indicating that C(The read operation timed out).
    default: 60
    type: int
  validate_certs:
    description:
      - If V(false), SSL certificates will not be validated.
      - This should only set to V(false) used on personally controlled sites using self-signed certificates.
    type: bool
    default: true
notes:
  - The XML fragments do not need an authentication cookie, this is injected by the module automatically.
  - The Cisco IMC XML output is being translated to JSON using the Cobra convention.
  - Any configConfMo change requested has a return status of C(modified), even if there was no actual change from the previous
    configuration. As a result, this module will always report a change on subsequent runs. In case this behaviour is fixed
    in a future update to Cisco IMC, this module will automatically adapt.
  - If you get a C(Connection failure) related to C(The read operation timed out) increase the O(timeout) parameter. Some
    XML fragments can take longer than the default timeout.
  - More information about the IMC REST API is available from
    U(http://www.cisco.com/c/en/us/td/docs/unified_computing/ucs/c/sw/api/3_0/b_Cisco_IMC_api_301.html).
a   
- name: Power down server
  community.general.imc_rest:
    hostname: '{{ imc_hostname }}'
    username: '{{ imc_username }}'
    password: '{{ imc_password }}'
    validate_certs: false # only do this when you trust the network!
    content: |
      <configConfMo><inConfig>
        <computeRackUnit dn="sys/rack-unit-1" adminPower="down"/>
      </inConfig></configConfMo>
  delegate_to: localhost

- name: Configure IMC using multiple XML fragments
  community.general.imc_rest:
    hostname: '{{ imc_hostname }}'
    username: '{{ imc_username }}'
    password: '{{ imc_password }}'
    validate_certs: false # only do this when you trust the network!
    timeout: 120
    content: |
      <!-- Configure Serial-on-LAN -->
      <configConfMo><inConfig>
        <solIf dn="sys/rack-unit-1/sol-if" adminState="enable" speed=="115200" comport="com0"/>
      </inConfig></configConfMo>

      <!-- Configure Console Redirection -->
      <configConfMo><inConfig>
        <biosVfConsoleRedirection dn="sys/rack-unit-1/bios/bios-settings/Console-redirection"
          vpBaudRate="115200"
          vpConsoleRedirection="com-0"
          vpFlowControl="none"
          vpTerminalType="vt100"
          vpPuttyKeyPad="LINUX"
          vpRedirectionAfterPOST="Always Enable"/>
      </inConfig></configConfMo>
  delegate_to: localhost

- name: Enable PXE boot and power-cycle server
  community.general.imc_rest:
    hostname: '{{ imc_hostname }}'
    username: '{{ imc_username }}'
    password: '{{ imc_password }}'
    validate_certs: false # only do this when you trust the network!
    content: |
      <!-- Configure PXE boot -->
      <configConfMo><inConfig>
        <lsbootLan dn="sys/rack-unit-1/boot-policy/lan-read-only" access="read-only" order="1" prot="pxe" type="lan"/>
      </inConfig></configConfMo>

      <!-- Power cycle server -->
      <configConfMo><inConfig>
        <computeRackUnit dn="sys/rack-unit-1" adminPower="cycle-immediate"/>
      </inConfig></configConfMo>
  delegate_to: localhost

- name: Reconfigure IMC to boot from storage
  community.general.imc_rest:
    hostname: '{{ imc_host }}'
    username: '{{ imc_username }}'
    password: '{{ imc_password }}'
    validate_certs: false # only do this when you trust the network!
    content: |
      <configConfMo><inConfig>
        <lsbootStorage dn="sys/rack-unit-1/boot-policy/storage-read-write" access="read-write" order="1" type="storage"/>
      </inConfig></configConfMo>
  delegate_to: localhost

- name: Add customer description to server
  community.general.imc_rest:
    hostname: '{{ imc_host }}'
    username: '{{ imc_username }}'
    password: '{{ imc_password }}'
    validate_certs: false # only do this when you trust the network!
    content: |
      <configConfMo><inConfig>
        <computeRackUnit dn="sys/rack-unit-1" usrLbl="Customer Lab - POD{{ pod_id }} - {{ inventory_hostname_short }}"/>
      </inConfig></configConfMo>
    delegate_to: localhost

- name: Disable HTTP and increase session timeout to max value 10800 secs
  community.general.imc_rest:
    hostname: '{{ imc_host }}'
    username: '{{ imc_username }}'
    password: '{{ imc_password }}'
    validate_certs: false # only do this when you trust the network!
    timeout: 120
    content: |
      <configConfMo><inConfig>
        <commHttp dn="sys/svc-ext/http-svc" adminState="disabled"/>
      </inConfig></configConfMo>

      <configConfMo><inConfig>
        <commHttps dn="sys/svc-ext/https-svc" adminState="enabled" sessionTimeout="10800"/>
      </inConfig></configConfMo>
    delegate_to: localhost
a 	  
aaLogin:
  description: Cisco IMC XML output for the login, translated to JSON using Cobra convention.
  returned: success
  type: dict
  sample: |
    "attributes": {
        "cookie": "",
        "outCookie": "1498902428/9de6dc36-417c-157c-106c-139efe2dc02a",
        "outPriv": "admin",
        "outRefreshPeriod": "600",
        "outSessionId": "114",
        "outVersion": "2.0(13e)",
        "response": "yes"
    }
configConfMo:
  description: Cisco IMC XML output for any configConfMo XML fragments, translated to JSON using Cobra convention.
  returned: success
  type: dict
  sample: |
elapsed:
  description: Elapsed time in seconds.
  returned: always
  type: int
  sample: 31
response:
  description: HTTP response message, including content length.
  returned: always
  type: str
  sample: OK (729 bytes)
status:
  description: The HTTP response status code.
  returned: always
  type: dict
  sample: 200
error:
  description: Cisco IMC XML error output for last request, translated to JSON using Cobra convention.
  returned: failed
  type: dict
  sample: |
    "attributes": {
        "cookie": "",
        "errorCode": "ERR-xml-parse-error",
        "errorDescr": "XML PARSING ERROR: Element 'computeRackUnit', attribute 'admin_Power': The attribute 'admin_Power' is not allowed. ",
        "invocationResult": "594",
        "response": "yes"
    }
error_code:
  description: Cisco IMC error code.
  returned: failed
  type: str
  sample: ERR-xml-parse-error
error_text:
  description: Cisco IMC error message.
  returned: failed
  type: str
  sample: |
    XML PARSING ERROR: Element 'computeRackUnit', attribute 'admin_Power': The attribute 'admin_Power' is not allowed.
input:
  description: RAW XML input sent to the Cisco IMC, causing the error.
  returned: failed
  type: str
  sample: |
    <configConfMo><inConfig><computeRackUnit dn="sys/rack-unit-1" admin_Power="down"/></inConfig></configConfMo>
output:
  description: RAW XML output received from the Cisco IMC, with error details.
  returned: failed
  type: str
  sample: >
    <error cookie=""
      response="yes"
      errorCode="ERR-xml-parse-error"
      invocationResult="594"
      errorDescr="XML PARSING ERROR: Element 'computeRackUnit', attribute 'admin_Power': The attribute 'admin_Power' is not allowed.\n" />
NTF)cobra)AnsibleModulemissing_required_lib)zip_longest	fetch_url)nowc                 H   t         j                  j                  |      }t        j                  |      }|j                  d      r\|j                  d      rK|r||d<   ||d<   |j                  d      |d<   |j                  d      |d<    | j                  d	dd|z  i| |S )
z Handle IMC returned data 	errorCode
errorDescrinputoutput
error_code
error_textmsgzRequest failed: %(error_text)s )lxmletree
fromstringr   dataget	fail_json)module	rawoutputrawinput	xmloutputresults        n/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/general/plugins/modules/imc_rest.pyimc_responser"   )  s    

%%i0IZZ	"F }}[!immL&A&F7O$x(}}[9|(}}\:|Q=FQ&QM    c                 <    d|d|d}t        | ||d|      \  }}y)z Perform a logout, if needed z<aaaLogout cookie="z" inCookie=""/>POSTr   methodtimeoutNr
   )r   urlcookier)   r   respauths          r!   logoutr.   :  s"    7=vFD63T&'RJD$r#   c                    t        | t              rZt        |t              rJt        |       }|j                  |D ci c]"  }|t        | j	                  |d      ||         $ c}       |S t        | t
              r9t        |t
              r)t        | |      D cg c]  \  }}t        ||       c}}S || S |S c c}w c c}}w )z1 Merge two complex nested datastructures into oneN)
isinstancedictupdatemerger   listr	   )onetwocopykeyalphabetas         r!   r3   r3   @  s    #tC!6CyM#S%T 2CH==MN	C	:c4#88CC8MN}teT"NN+3&3& N Os   'B:B?c                  N   t        t        t        ddddg      t        dddg      t        dd	d
      t        d      t        dddg      t        ddddg      t        dd      t        dd            dddgg      } t        s | j                  t	        d      t
               t        s | j                  t	        d      t               | j                  d   }| j                  d   }| j                  d	   }| j                  d   }| j                  d   }| j                  d   }| j                  d    }t        d!d!"      }d!}	|r7t        j                  j                  |      rd}	n| j                  d#|z  $       t               }
|d%|d&}d'|d(|d)}t        | ||d*|+      \  }}||d,   d-k7  r1t               |
z
  j                  |d.<    | j                  d?d/d0|z  i| |j                  t!        | |j#                                      d1}	 |d2   d3   d4   }	 |r|}n'|	r%t'        |d6      5 }|j#                         }d d d        t(        j*                  j-                  d7j/                  d8d1      z        }t1        |      D ]  }|j2                  t(        j*                  j4                  u r+|j7                  d9|       t(        j*                  j9                  |      }t        | ||d*|+      \  }}||d,   d-k7  r1t               |
z
  j                  |d.<    | j                  d?d/d0|z  i| |j#                         }t;        |t!        | ||:            }|d/   |d;<   |d,   |d,<   t(        j*                  j-                  |      }|j=                  d<      }d=|v |d><    t               |
z
  j                  |d.<    | j>                  d?i | tA        | |||       y # t$        $ r  | j                  d?d/d5i| Y w xY w# 1 sw Y   xY w# tA        | |||       w xY w)@NstrThostip)typerequiredaliasesadminuser)r?   defaultrA   password)r?   rD   no_log)r?   pathconfig_filesrc)r?   rA   httpshttp)r?   rD   choicesint<   )r?   rD   bool)hostnameusernamerE   contentrG   protocolr)   validate_certsrR   )argument_specsupports_check_modemutually_exclusiver   )r   	exceptionzxmljson >= 0.1.8rP   rQ   rS   r)   F)failedchangedzCannot find/access path:
%s)r   z://z/nuovaz<aaaLogin inName="z" inPassword="r%   r&   r'   status   elapsedr   z*Task failed with error %(status)s: %(msg)s aaaLogin
attributes	outCookiezCould not find cookie in outputrz<root>%s</root>
r+   )r   responsez!/configConfMo/outConfig/*/@statusmodifiedrZ   r   )!r   r1   HAS_LXML_ETREEr   r   LXML_ETREE_IMP_ERRHAS_XMLJSON_COBRAXMLJSON_COBRA_IMP_ERRparamsosrG   isfiler   r   secondsr2   r"   read	Exceptionopenr   r   r   replacer4   tagCommentsettostringr3   xpath	exit_jsonr.   )r   rP   rQ   rE   rR   rG   rS   r)   r    file_existsstartr*   r   r,   r-   r+   rawdataconfig_objectxmldataxmldocinfor   r   resultss                           r!   mainr   M  s    utfd^LugxHujFe$6M5+ABug?PQeR0VT:	
 !&/0F 1&9EWX12DEQfg}}Z(H}}Z(H}}Z(HmmI&G== D}}Z(HmmI&GF K77>>$K!?$!FGEE &x
0C8@(KD63T&'RJD$|tH~, UU]33y[IDP[TZ[
MM,vtyy{34 FJ
#L1+>)-GdC /M',,./ **''(9GOODRT<U(UV 7m 	8FzzTZZ///JJx(::&&v.D #63T&RYZJD$|tH~4%(UU]$;$;y!   c%QTX%Xc\bc 		I6<	D#QRF!%eF:#H~F8 

--i8Ioo&IJG!+w!6F9/	84 !UU]33y"6"vsFG,Y  JI>I&IJ/ /H 	vsFG,s7   O# #P 6PFP #PPPP P$__main__)r^   )#
__future__r   r   r   r?   __metaclass__DOCUMENTATIONEXAMPLESRETURNrk   	tracebackrg   
lxml.etreer   rf   ImportError
format_excri   xmljsonr   rh   ansible.module_utils.basicr   r   ansible.module_utils.six.movesr	   ansible.module_utils.urlsr   Cansible_collections.community.general.plugins.module_utils.datetimer   r"   r.   r3   r   __name__r   r#   r!   <module>r      s    A @Rh`DJ
X 
  N
  
 K 6 /
"S
'h-V zF I  ---/N  0I002s"   A$ B $A?>A?BB