
    VhH                        d dl mZmZmZ eZddgddZdZdZdZ	d d	l
Z
d d	lZd d	lZ	 d d
lmZmZmZmZ dZ	 d dlmZ dZ	 d dlmZ dZ	 d d	lZdZd dlmZ d dlm Z m!Z!m"Z" d dl#m$Z$ d dl%m&Z& d Z'd Z(d Z) G d de       Z*d Z+e,dk(  r e+        y	y	# e$ r dZY cw xY w# e$ r dZY gw xY w# e$ r dZY kw xY w# e$ r dZY qw xY w)    )absolute_importdivisionprint_functionz1.1preview	certified)metadata_versionstatussupported_bya  
---
module: aci_rest
short_description: Direct access to the Cisco APIC REST API
description:
- Enables the management of the Cisco ACI fabric through direct access to the Cisco APIC REST API.
- Thanks to the idempotent nature of the APIC, this module is idempotent and reports changes.
requirements:
- lxml (when using XML payload)
- xmljson >= 0.1.8 (when using XML payload)
- python 2.7+ (when using xmljson)
options:
  method:
    description:
    - The HTTP method of the request.
    - Using C(delete) is typically used for deleting objects.
    - Using C(get) is typically used for querying objects.
    - Using C(post) is typically used for modifying objects.
    type: str
    choices: [ delete, get, post ]
    default: get
    aliases: [ action ]
  path:
    description:
    - URI being used to execute API calls.
    - Must end in C(.xml) or C(.json).
    type: str
    required: true
    aliases: [ uri ]
  content:
    description:
    - When used instead of C(src), sets the payload of the API request directly.
    - This may be convenient to template simple requests.
    - For anything complex use the C(template) lookup plugin (see examples)
      or the C(template) module with parameter C(src).
    type: raw
  src:
    description:
    - Name of the absolute path of the filename that includes the body
      of the HTTP request being sent to the ACI fabric.
    - If you require a templated payload, use the C(content) parameter
      together with the C(template) lookup plugin, or use C(template).
    type: path
    aliases: [ config_file ]
  rsp_subtree_preserve:
    description:
    - Preserve the response for the provided path.
    type: bool
    default: false
  page_size:
    description:
    - The number of items to return in a single page.
    type: int
  page:
    description:
    - The page number to return.
    type: int
extends_documentation_fragment:
- cisco.aci.aci
- cisco.aci.annotation

notes:
- Certain payloads are known not to be idempotent, so be careful when constructing payloads,
  e.g. using C(status="created") will cause idempotency issues, use C(status="modified") instead.
  More information in :ref:`the ACI documentation <aci_guide_known_issues>`.
- Certain payloads (and used paths) are known to report no changes happened when changes did happen.
  This is a known APIC problem and has been reported to the vendor. A workaround for this issue exists.
  More information in :ref:`the ACI documentation <aci_guide_known_issues>`.
- XML payloads require the C(lxml) and C(xmljson) python libraries. For JSON payloads nothing special is needed.
- If you do not have any attributes, it may be necessary to add the "attributes" key with an empty dictionnary "{}" for value
  as the APIC does expect the entry to precede any children.
- Annotation set directly in c(src) or C(content) will take precedent over the C(annotation) parameter.
seealso:
- module: cisco.aci.aci_tenant
- name: Cisco APIC REST API Configuration Guide
  description: More information about the APIC REST API.
  link: http://www.cisco.com/c/en/us/td/docs/switches/datacenter/aci/apic/sw/2-x/rest_cfg/2_1_x/b_Cisco_APIC_REST_API_Configuration_Guide.html
author:
- Dag Wieers (@dagwieers)
- Cindy Zhao (@cizhao)
- Samita Bhattacharjee (@samitab)
a  
- name: Add a tenant using certificate authentication
  cisco.aci.aci_rest:
    host: apic
    username: admin
    private_key: pki/admin.key
    method: post
    path: /api/mo/uni.xml
    src: /home/cisco/ansible/aci/configs/aci_config.xml
  delegate_to: localhost

- name: Add a tenant from a templated payload file from templates/
  cisco.aci.aci_rest:
    host: apic
    username: admin
    private_key: pki/admin.key
    method: post
    path: /api/mo/uni.xml
    content: "{{ lookup('template', 'aci/tenant.xml.j2') }}"
  delegate_to: localhost

- name: Add a tenant using inline YAML
  cisco.aci.aci_rest:
    host: apic
    username: admin
    private_key: pki/admin.key
    validate_certs: false
    path: /api/mo/uni.json
    method: post
    content:
      fvTenant:
        attributes:
          name: Sales
          descr: Sales department
  delegate_to: localhost

- name: Add a tenant using a JSON string
  cisco.aci.aci_rest:
    host: apic
    username: admin
    private_key: pki/admin.key
    validate_certs: false
    path: /api/mo/uni.json
    method: post
    content:
      {
        "fvTenant": {
          "attributes": {
            "name": "Sales",
            "descr": "Sales department"
          }
        }
      }
  delegate_to: localhost

- name: Add a tenant using an XML string
  cisco.aci.aci_rest:
    host: apic
    username: admin
    private_key: pki/{{ aci_username }}.key
    validate_certs: false
    path: /api/mo/uni.xml
    method: post
    content: '<fvTenant name="Sales" descr="Sales departement"/>'
  delegate_to: localhost

- name: Get tenants using password authentication
  cisco.aci.aci_rest:
    host: apic
    username: admin
    password: SomeSecretPassword
    method: get
    path: /api/node/class/fvTenant.json
  delegate_to: localhost
  register: query_result

- name: Get first 5 tenants using password authentication and pagination
  cisco.aci.aci_rest:
    host: apic
    username: admin
    password: SomeSecretPassword
    method: get
    page_size: 5
    path: /api/node/class/fvTenant.json
  delegate_to: localhost
  register: query_result

- name: Configure contracts
  cisco.aci.aci_rest:
    host: apic
    username: admin
    private_key: pki/admin.key
    method: post
    path: /api/mo/uni.xml
    src: /home/cisco/ansible/aci/configs/contract_config.xml
  delegate_to: localhost

- name: Register leaves and spines
  cisco.aci.aci_rest:
    host: apic
    username: admin
    private_key: pki/admin.key
    validate_certs: false
    method: post
    path: /api/mo/uni/controller/nodeidentpol.xml
    content:
      <fabricNodeIdentPol>
        <fabricNodeIdentP name="{{ item.name }}" nodeId="{{ item.nodeid }}" status="{{ item.status }}" serial="{{ item.serial }}"/>
      </fabricNodeIdentPol>
  with_items:
    - '{{ apic_leavesspines }}'
  delegate_to: localhost

- name: Wait for all controllers to become ready
  cisco.aci.aci_rest:
    host: apic
    username: admin
    private_key: pki/admin.key
    validate_certs: false
    path: /api/node/class/topSystem.json?query-target-filter=eq(topSystem.role,"controller")
  register: apics
  until: "'totalCount' in apics and apics.totalCount|int >= groups['apic']|count"
  retries: 120
  delay: 30
  delegate_to: localhost
  run_once: true
a~  
error_code:
  description: The REST ACI return code, useful for troubleshooting on failure
  returned: always
  type: int
  sample: 122
error_text:
  description: The REST ACI descriptive text, useful for troubleshooting on failure
  returned: always
  type: str
  sample: unknown managed object class foo
imdata:
  description: Converted output returned by the APIC REST (register this for post-processing)
  returned: always
  type: str
  sample: [{"error": {"attributes": {"code": "122", "text": "unknown managed object class foo"}}}]
payload:
  description: The (templated) payload send to the APIC REST API (xml or json)
  returned: always
  type: str
  sample: '<foo bar="boo"/>'
raw:
  description: The raw output returned by the APIC REST API (xml or json)
  returned: parse error
  type: str
  sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
response:
  description: HTTP response string
  returned: always
  type: str
  sample: 'HTTP Error 400: Bad Request'
status:
  description: HTTP status code
  returned: always
  type: int
  sample: 400
totalCount:
  description: Number of items in the imdata array
  returned: always
  type: str
  sample: '0'
url:
  description: URL used for APIC REST call
  returned: success
  type: str
  sample: https://1.2.3.4/api/mo/uni/tn-[Dag].json?rsp-subtree=modified
N)	parse_qsl	urlencodeurlparse
urlunparseTF)etree)cobra)AnsibleModule)	ACIModuleaci_argument_specaci_annotation_spec)to_text)ANNOTATION_UNSUPPORTEDc           
         t         rUt        t        |             }t        t	        |d               }|j                  |       t        |      |d<   t        |      S d| v r=| dz   dj                  |j                         D cg c]  \  }}|d| c}}      z   S | dz   dj                  |j                         D cg c]  \  }}|d| c}}      z   S c c}}w c c}}w )z Add or update a URL query string   ?&=)
HAS_URLPARSElistr   dictr   updater   r   joinitems)urlparams	url_partsquerykvs         f/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/cisco/aci/plugins/modules/aci_rest.py
update_qslr)   =  s     #'	Yy|,-V '	!)$$	Sy388&,,.$Q$!Q1%5$QRRRSy388&,,.$Q$!Q1%5$QRRR %R$Qs   C?C c                 2   | rt        |t              r|j                         D ]p  \  }}|t        v rt        |t              s |j	                  di       }d|j                         vr| |d<   |j	                  dd      }|s^|D ]  }t        | |        r yyy)z?Add annotation to payload only if it has not already been added
attributes
annotationchildrenN)
isinstancer   r!   r   getkeysadd_annotation)r,   payloadkeyvalattr-   childs          r(   r1   r1   L  s    j$/ 	:HC,,#t$gglB/sxxz1(2C%77:t4!) :&z59:	: 0z    c                     | rO|j                         D ];  }|j                  t        v r|j                  d      }|*|j	                  d|        = yy)zCAdd annotation to payload xml only if it has not already been addedr,   N)itertagr   r/   set)r,   treeelementanns       r(   add_annotation_xmlr?   ]  sP    yy{ 	6G{{44++l+C{L*5	6 r7   c                       e Zd Zd ZddZy)ACIRESTModulec                     t        |t              r9|j                         D ]%  \  }}|dk(  r|dv r y| j                  |      du s% y yt        |t              r|D ]  }| j                  |      du s y y)zCheck ACI response for changesr	   )createdmodifieddeletedTF)r.   r   r!   changedr   )selfdr&   r'   is        r(   rF   zACIRESTModule.changedi  s     a	  1=Q*L%L\\!_,	   4   <<?d*  r7   c                     |dk(  r| j                  |       n| j                  |       t        r)| j                  | j                        | j
                  d<   yy)zHandle APIC response outputjsonrF   N)response_jsonresponse_xmlr   rF   imdataresult)rG   	rawoutput	rest_types      r(   response_typezACIRESTModule.response_typey  sM     y)i( %)\\$++%>DKK	" r7   N)xml)__name__
__module____qualname__rF   rR    r7   r(   rA   rA   h  s     
?r7   rA   c                     t               } | j                  t                      | j                  t        dddg      t        ddg ddg      t        d	d
g      t        d      t        dd      t        d      t        d             t	        | dddgg      }|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  r|r|j                  d       d}	|rCt        j                  j                  |      rd}	n!|j                  dj                  |             |j                  d      dk7  r3d }
t        s|j                  d!       t        s<|j                  d"       n)|j                  d#      dk7  rd$}
n|j                  d%       t        |      }d|j                   d&<   |}|	r%t#        |d'      5 }|j%                         }d d d        
d$k(  r|r2t'        |t              r"t)        ||       t+        j,                  |      }n|rt'        |t.              rt0        r	 t3        j4                  |      }t)        ||       t+        j,                  |      }n|
d k(  rt        r|rPt'        |t              r@t        r:t)        ||       t;        j<                  t?        j:                  |      d*   d+,      }nK|rIt'        |t.              r9	 t;        j@                  |      }tC        ||       t;        j<                  |d+,      }|jE                  d/      |_	        d0j                  |jF                  |j                        |_$        |j
                  j                  d      dk(  r>|r<tK        |j                  ||d1      |_	        tK        |jH                  ||d1      |_$        |j
                  j                  d      dk7  r?|s=d2j                  |j                        |_	        tK        |jH                  d3d4i      |_$        |j
                  j                  d      jM                         }|jN                  jP                  s|jS                  ||jH                  |d5      \  }}|j                  d&      d6k7  rA	 |jU                  |d7   |
       |j                  d8jW                  |jX                               	 |jU                  |j%                         |
       |j^                  |j                   d&<   |j`                  |j                   d:<   |jb                  |j                   d;<   n|jd                  |j
                  j                  d<      stg        ti        |jH                        jk                  tm        jn                  d=d>|jd                  jq                  d<            js                  d?      d*   @            |_$        ||_:        d|j                   dA<   |r|dBk(  r|
d$k(  rt+        jv                  |      }||j                   dC<   |j
                  j                  dD      }|Lt#        |dE      5 }|
d$k(  rt+        jx                  |g|       n|j{                  t/        |             d d d         |j|                  dFi |j                    y # 1 sw Y   xY w# t6        $ r@}|j                  d(j                  t9        |            t9        |      |)       Y d }~d }~ww xY w# t6        $ r6}|j                  d-j                  t9        |            |.       Y d }~d }~ww xY w# tZ        $ r% |j                  d9jW                  |             Y w xY w# t\        $ r% |jU                  |j                  d7      |
       Y w xY w# 1 sw Y   $xY w)GNstrTuri)typerequiredaliasesr/   )deleter/   postaction)r[   defaultchoicesr]   pathconfig_file)r[   r]   raw)r[   boolF)r[   ra   int)rc   methodsrccontentrsp_subtree_preserve	page_sizepagerj   ri   )argument_specsupports_check_modemutually_exclusiverk   r,   rl   rm   rh   zHPagination parameters (page and page_size) are only valid for GET method)msgzCannot find/access src '{0}'z.xmlrS   z;The lxml python library is missing, or lacks etree support.z>The xmljson python library is missing, or lacks cobra support.z.jsonrK   z>Failed to find REST API payload type (neither .xml nor .json).r	   rz/Failed to parse provided JSON/YAML payload: {0})rq   	exceptionr2   r   unicode)encodingz)Failed to parse provided XML payload: {0})rq   r2   /z{0}/{1})rm   z	page-sizez{0}?rsp-subtree=modifiedzrsp-subtreerD   )datareturn_response   bodyzAPIC Error {code}: {text}z"Connection failed for {url}. {msg}rN   
totalCounthostz[[\]] ,)netlocrF   POSTproposedoutput_patharW   )?r   r   r   r   r   r#   r/   	fail_jsonosrc   isfileformatfindHAS_LXML_ETREEHAS_XMLJSON_COBRArA   rO   openreadr.   r1   rK   dumpsrY   HAS_YAMLyaml	safe_load	Exceptionr   r   tostringr   
fromstringr?   lstripbase_urlr"   r)   uppermodule
check_modeapi_callrR   
format_maperrorKeyErrorAttributeErrorr	   rN   r|   
connectionr   r   _replaceresub
get_optionsplitrh   loadsdumpwrite	exit_json)rn   r   rj   rc   ri   rk   r,   rl   rm   file_existsrQ   acir2   config_objecterh   respinfor   output_files                       r(   mainr     s   %'M,./uteW=7P[cZdef}o6% !vu=E"u   # &./F mm	*G==V$D
--

E
"C!==,,-CD""<0J!!+.I==V$D}}"e+	gh K
77>>#K!?!F!Fs!KL yyB	!^_ !ab	7	r	!	]^

CCJJx G#s^ 	+}#((*G	+
 Fz'40:w/jj)GGS1hR..1z73**W- 
e	z'405F:w/nnU[[%9!%<yQGGS1v**73":w7..9E {{3CHs||SXX6CG
zz~~h5(YchhI(NOSWWt)&LM
zz~~h5(1E-44SXX>SWW}j&ABZZ^^H%++-F::  \\&#''QU\V
d88H$Y!!$v,	:"="H"H"ST
	;diik95  #zz

8"zz

8#&>>

<  >>%#**..*@*H #''!2!;!;266(TVX[XfXfXqXqrxXyCz  DA  DA  BE  DF  GH  DI!;  "J  KCG
 $

9 6V#jj)G!(

:jjnn]3"k3' 4;&IIwi5%%c'l3	4 CMMCJJy	+ 	+   R  %V%]%]^efg^h%iu|}~u  JQ   R  RR  v  %P%W%WX_`aXb%cmt uuv2  Y"F"Q"QRV"WXY  	;dhhv.	:	;24 4sm   /\<6]	 8^ )A _ * ` 8`9<]		^5^^	_+__*``*`65`69a__main__)-
__future__r   r   r   r[   __metaclass__ANSIBLE_METADATADOCUMENTATIONEXAMPLESRETURNrK   r   r   +ansible.module_utils.six.moves.urllib.parser   r   r   r   r   r   lxmlr   r   ImportErrorxmljsonr   r   r   r   ansible.module_utils.basicr   6ansible_collections.cisco.aci.plugins.module_utils.acir   r   r   ansible.module_utils._textr   Iansible_collections.cisco.aci.plugins.module_utils.annotation_unsupportedr   r)   r1   r?   rA   r   rT   rW   r7   r(   <module>r      s!   A @(-)Vab Qf~@.
`  	 	ffL
N

H 5 t t .
S:"6?I ?<S l zF E  L  N    HsE   B B B) B6 BBB&%B&)B32B36C ?C 