
    VhY                         d dl mZmZmZ eZdZdZdZd dl	m
Z
 d dlmZ d dlmZmZmZmZ d dlmZmZmZ d d	lZ	 d d
lmZ d dlmZmZ  G d d      Zd Zedk(  r e        y	y	# e$ r Y "w xY w)    )absolute_importdivisionprint_functiona  
module: api
author: "Nikolay Dachev (@NikolayDachev)"
short_description: Ansible module for RouterOS API
description:
  - Ansible module for RouterOS API with the Python C(librouteros) library.
  - This module can add, remove, update, query, and execute arbitrary command in RouterOS through the API.
notes:
  - O(add), O(remove), O(update), O(cmd), and O(query) are mutually exclusive.
  - Use the M(community.routeros.api_modify) and M(community.routeros.api_find_and_modify) modules for more specific modifications,
    and the M(community.routeros.api_info) module for a more controlled way of returning all entries for a path.
extends_documentation_fragment:
  - community.routeros.api
  - community.routeros.attributes
  - community.routeros.attributes.actiongroup_api
attributes:
  check_mode:
    support: none
  diff_mode:
    support: none
  platform:
    support: full
    platforms: RouterOS
  action_group:
    version_added: 2.1.0
  idempotent:
    support: N/A
    details:
      - Whether the executed command is idempotent depends on the operation performed.
options:
  path:
    description:
      - Main path for all other arguments.
      - If other arguments are not set, the module will return all items in selected path.
      - Example V(ip address). Equivalent of RouterOS CLI C(/ip address print).
    required: true
    type: str
  add:
    description:
      - Will add selected arguments in selected path to RouterOS config.
      - Example V(address=1.1.1.1/32 interface=ether1).
      - Equivalent in RouterOS CLI C(/ip address add address=1.1.1.1/32 interface=ether1).
    type: str
  remove:
    description:
      - Remove config/value from RouterOS by '.id'.
      - Example V(*03) will remove config/value with C(id=*03) in selected path.
      - Equivalent in RouterOS CLI C(/ip address remove numbers=1).
      - Note C(number) in RouterOS CLI is different from C(.id).
    type: str
  update:
    description:
      - Update config/value in RouterOS by '.id' in selected path.
      - Example V(.id=*03 address=1.1.1.3/32) and path V(ip address) will replace the existing IP address with C(.id=*03).
      - Equivalent in RouterOS CLI C(/ip address set address=1.1.1.3/32 numbers=1).
      - Note C(number) in RouterOS CLI is different from C(.id).
    type: str
  query:
    description:
      - Query given path for selected query attributes from RouterOS API.
      - WHERE is key word which extend query. WHERE format is key operator value - with spaces.
      - WHERE valid operators are V(==) or V(eq), V(!=) or V(not), V(>) or V(more), V(<) or V(less).
      - Example path V(ip address) and query V(.id address) will return only C(.id) and C(address) for all items in V(ip address)
        path.
      - Example path V(ip address) and query V(.id address WHERE address == 1.1.1.3/32). will return only C(.id) and C(address)
        for items in V(ip address) path, where address is eq to 1.1.1.3/32.
      - Example path V(interface) and query V(mtu name WHERE mut > 1400) will return only interfaces C(mtu,name) where mtu
        is bigger than 1400.
      - Equivalent in RouterOS CLI C(/interface print where mtu > 1400).
    type: str
  extended_query:
    description:
      - Extended query given path for selected query attributes from RouterOS API.
      - Extended query allow conjunctive input. If there is no matching entry, an empty list will be returned.
    type: dict
    suboptions:
      attributes:
        description:
          - The list of attributes to return.
          - Every attribute used in a O(extended_query.where[]) clause need to be listed here.
        type: list
        elements: str
        required: true
      where:
        description:
          - Allows to restrict the objects returned.
          - The conditions here must all match. An O(extended_query.where[].or) condition needs at least one of its conditions
            to match.
        type: list
        elements: dict
        suboptions:
          attribute:
            description:
              - The attribute to match. Must be part of O(extended_query.attributes).
              - Either O(extended_query.where[].or) or all of O(extended_query.where[].attribute), O(extended_query.where[].is),
                and O(extended_query.where[].value) have to be specified.
            type: str
          is:
            description:
              - The operator to use for matching.
              - For equality use V(==) or V(eq). For less use V(<) or V(less). For more use V(>) or V(more).
              - Use V(in) to check whether the value is part of a list. In that case, O(extended_query.where[].value) must
                be a list.
              - Either O(extended_query.where[].or) or all of O(extended_query.where[].attribute), O(extended_query.where[].is),
                and O(extended_query.where[].value) have to be specified.
            type: str
            choices: ["==", "!=", ">", "<", "in", "eq", "not", "more", "less"]
          value:
            description:
              - The value to compare to. Must be a list for O(extended_query.where[].is=in).
              - Either O(extended_query.where[].or) or all of O(extended_query.where[].attribute), O(extended_query.where[].is),
                and O(extended_query.where[].value) have to be specified.
            type: raw
          or:
            description:
              - A list of conditions so that at least one of them has to match.
              - Either O(extended_query.where[].or) or all of O(extended_query.where[].attribute), O(extended_query.where[].is),
                and O(extended_query.where[].value) have to be specified.
            type: list
            elements: dict
            suboptions:
              attribute:
                description:
                  - The attribute to match. Must be part of O(extended_query.attributes).
                type: str
                required: true
              is:
                description:
                  - The operator to use for matching.
                  - For equality use V(==) or V(eq). For less use V(<) or V(less). For more use V(>) or V(more).
                  - Use V(in) to check whether the value is part of a list. In that case, O(extended_query.where[].or[].value)
                    must be a list.
                type: str
                choices: ["==", "!=", ">", "<", "in", "eq", "not", "more", "less"]
                required: true
              value:
                description:
                  - The value to compare to. Must be a list for O(extended_query.where[].or[].is=in).
                type: raw
                required: true
  cmd:
    description:
      - Execute any/arbitrary command in selected path, after the command we can add C(.id).
      - Example path V(system script) and cmd V(run .id=*03) is equivalent in RouterOS CLI C(/system script run number=0).
      - Example path V(ip address) and cmd V(print) is equivalent in RouterOS CLI C(/ip address print).
    type: str
seealso:
  - ref: ansible_collections.community.routeros.docsite.quoting
    description: How to quote and unquote commands and arguments.
  - module: community.routeros.api_facts
  - module: community.routeros.api_find_and_modify
  - module: community.routeros.api_info
  - module: community.routeros.api_modify
a
  
---
- name: Get example - ip address print
  community.routeros.api:
    hostname: "{{ hostname }}"
    password: "{{ password }}"
    username: "{{ username }}"
    path: "ip address"
  register: ipaddrd_printout

- name: Dump "Get example" output
  ansible.builtin.debug:
    msg: '{{ ipaddrd_printout }}'

- name: Add example - ip address
  community.routeros.api:
    hostname: "{{ hostname }}"
    password: "{{ password }}"
    username: "{{ username }}"
    path: "ip address"
    add: "address=192.168.255.10/24 interface=ether2"

- name: Query example - ".id, address" in "ip address WHERE address == 192.168.255.10/24"
  community.routeros.api:
    hostname: "{{ hostname }}"
    password: "{{ password }}"
    username: "{{ username }}"
    path: "ip address"
    query: ".id address WHERE address == {{ ip2 }}"
  register: queryout

- name: Dump "Query example" output
  ansible.builtin.debug:
    msg: '{{ queryout }}'

- name: Extended query example - ".id,address,network" where address is not 192.168.255.10/24 or is 10.20.36.20/24
  community.routeros.api:
    hostname: "{{ hostname }}"
    password: "{{ password }}"
    username: "{{ username }}"
    path: "ip address"
    extended_query:
      attributes:
        - network
        - address
        - .id
      where:
        - attribute: "network"
          is: "=="
          value: "192.168.255.0"
        - or:
            - attribute: "address"
              is: "!="
              value: "192.168.255.10/24"
            - attribute: "address"
              is: "eq"
              value: "10.20.36.20/24"
        - attribute: "network"
          is: "in"
          value:
            - "10.20.36.0"
            - "192.168.255.0"
  register: extended_queryout

- name: Dump "Extended query example" output
  ansible.builtin.debug:
    msg: '{{ extended_queryout }}'

- name: Update example - ether2 ip address with ".id = *14"
  community.routeros.api:
    hostname: "{{ hostname }}"
    password: "{{ password }}"
    username: "{{ username }}"
    path: "ip address"
    update: >-
      .id=*14
      address=192.168.255.20/24
      comment={{ 'Update 192.168.255.10/24 to 192.168.255.20/24 on ether2' | community.routeros.quote_argument_value }}

- name: Remove example - ether2 ip 192.168.255.20/24 with ".id = *14"
  community.routeros.api:
    hostname: "{{ hostname }}"
    password: "{{ password }}"
    username: "{{ username }}"
    path: "ip address"
    remove: "*14"

- name: Arbitrary command example "/system identity print"
  community.routeros.api:
    hostname: "{{ hostname }}"
    password: "{{ password }}"
    username: "{{ username }}"
    path: "system identity"
    cmd: "print"
  register: arbitraryout

- name: Dump "Arbitrary command example" output
  ansible.builtin.debug:
    msg: '{{ arbitraryout }}'
z
message:
  description: All outputs are in list with dictionary elements returned from RouterOS API.
  sample:
    - address: 1.2.3.4
    - address: 2.3.4.5
  type: list
  returned: always
)AnsibleModule)	to_native)
ParseErrorconvert_list_to_dictionaryparse_argument_valuesplit_routeros_command)api_argument_speccheck_has_library
create_apiN)LibRouterosError)KeyOrc                   v    e Zd Zd Zd ZddZd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd ZddZd Zy)ROS_api_modulec                    t        t        dd      t        d      t        d      t        d      t        d      t        d      t        dt        t        ddd      t        ddt        d      t        dg d	      t        d
      t        ddt        dd      t        dg dd      t        d
d      d      ddgdgdg                        }|j                  t                      t        |dd      | _        t        | j                         t        | j                        | _        | j                  j                  d   j                         | _
        | j                  j                  d   | _        | j                  j                  d   | _        | j                  j                  d   | _        | j                  j                  d   | _        d | _        | j                  j                  d   | _        | j                  j                  d   | _        t        g       | _        | j%                  | j                  | j                        | _        	 | j                  r| j)                          y | j                  r| j+                          y | j                  r| j-                          y | j                  r!| j/                          | j1                          y | j                   r!| j3                          | j5                          y | j                  r| j7                          y | j9                          y # t:        $ r6}| j                  j=                  dj?                  |       !       Y d }~y d }~ww xY w)"NstrT)typerequired)r   dictlist)r   elementsr   )	==!=><ineqnotmoreless)r   choicesraw)r   r$   r   )	attributeisvalue)r   r   options)r&   r'   r(   or)r&   r*   )r   r   r)   required_togethermutually_exclusiverequired_one_of)
attributeswhere)r   r)   )pathaddremoveupdatecmdqueryextended_queryF))r1   r2   r3   r4   r5   r6   )argument_specsupports_check_moder,   r0   r1   r2   r3   r4   r5   r6   )messagez"Error while encoding text: {error})errormsg) r   r3   r   r   moduler   r   apiparamssplitr0   r1   r2   	arbitraryr/   r5   r6   resultapi_add_pathapi_pathapi_add
api_remove
api_updatecheck_query	api_querycheck_extended_queryapi_extended_queryapi_arbitraryapi_get_allUnicodeEncodeError	fail_jsonformat)selfmodule_argsexcs      j/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/routeros/plugins/modules/api.py__init__zROS_api_module.__init__0  s   540% U#U#% E"VTVedK#%)u%5"7pq!%5!1")-54)H"&E;t  @D  #E%)ut%DJ 		 (D&D(;'<%8$96 
8 	,./#+8=8]_
 	$++&dkk*KK&&v.446	;;%%e,kk((2kk((2++E2
[[''0
"kk001AB ))$((DII>	^xx!!  " $$))+'')""$  "! 	^KK!!&J&Q&QX[&Q&\!]]	^s<   L< :L< L< 4,L< !,L< L< +L< <	M;,M66M;c                    | j                   j                  d      }|dk  r!| j                  | j                         | _         n| j                   |t        d      z   d  }| j                  | j                   d |       | _         t	        j
                  d|      }|s| j                  d|z         	 |j                  d      |j                  d      t        |j                  d      j                               d   g| _
        	 | j                   j                  d
      }| j                   |dz   d  | _
        | j                   d | | _         y # t        $ r!}| j                  d|d	|       Y d }~md }~ww xY w# t        $ r Y y w xY w)Nz WHERE r   z^\s*([^ ]+)\s+([^ ]+)\s+(.*)$zinvalid syntax for 'WHERE %s'         zinvalid syntax for 'WHERE z': WHERE)r5   findsplit_paramslenrematcherrorsgroupr
   rstripr/   r   index
ValueError)rQ   where_indexr/   mrS   idxs         rT   rH   zROS_api_module.check_query}  sM   jjooi0?**4::6DJJJ{S^;<=E**4::l{+CDDJ95AA;eCDPGGAJGGAJ():):)<=a@
	**""7+CC!GH-DJDS)DJ  P5#NOOP  		s,   -AE ?AE3 	E0E++E03	E?>E?c                 l    |d   dk(  r,t        |d   t              s| j                  d||d       y y y )Nr'   r   r(   z(invalid syntax 'extended_query':'where':z 'value' must be a type list)
isinstancer   r`   )rQ   test_atror_msgs      rT   check_extended_query_syntaxz*ROS_api_module.check_extended_query_syntax  s8    D>T!*Xg5F*MKKflnvwx +N!    c                    | j                   d   rp| j                   d   D ]]  }|d   Et        |d         dk  r| j                  d|d   z         |d   D ]  }| j                  |d        M| j                  |       _ y y )Nr/   r*   rX   zOinvalid syntax 'extended_query':'where':'or':%s 'or' requires minimum two itemsz:'or':)r6   r]   r`   rl   )rQ   iorvs      rT   rJ   z#ROS_api_module.check_extended_query  s    w'((1 8T7&1T7|a'$uxyz~x$  A w H88hGH 44Q78 (rm   c                     t        |dd      S )NT)skip_empty_valuesrequire_assignment)r	   )rQ   ldicts     rT   list_to_diczROS_api_module.list_to_dic  s    )%4\`aarm   c                     t        |t              st        dt        |      z        	 t	        |      S # t
        $ r/}| j                  j                  t        |             Y d }~y d }~ww xY w)Nz,Parameters can only be a string, received %sr;   )	ri   r   AssertionErrorr   r   r   r=   rO   r   )rQ   r?   es      rT   r\   zROS_api_module.split_params  s`    &#& !ORVW]R^!^__	4)&11 	4KK!!il!33	4s   
4 	A,%A''A,c                 V    |j                         }|D ]  }|j                  |      } |S N)r0   join)rQ   r>   r0   rD   ps        rT   rC   zROS_api_module.api_add_path  s/    88: 	(A}}Q'H	(rm   c                     	 | j                   D ]   }| j                  d   j                  |       " | j                  dd       y # t        $ r}| j                  |       Y d }~y d }~ww xY w)Nr9   FT)rD   rB   appendreturn_resultr   r`   )rQ   ro   rx   s      rT   rM   zROS_api_module.api_get_all  s^    	]] 1I&--a01ud+ 	KKNN	s   AA 	A(A##A(c                 @   | j                  | j                  | j                              }	 | j                  d   j	                  d | j
                  j                  di |z         | j                  d       y # t        $ r}| j                  |       Y d }~y d }~ww xY w)Nr9   zadded: .id= %sT )	ru   r\   r1   rB   r~   rD   r   r   r`   rQ   paramrx   s      rT   rE   zROS_api_module.api_add  s      !2!2488!<=	KK	"))*:,=DMM,=,=,F,F+G Ht$ 	KKNN	s   AA9 9	BBBc                    	 | j                   j                  | j                         | j                  d   j                  d| j                  z         | j	                  d       y # t
        $ r}| j                  |       Y d }~y d }~ww xY w)Nr9   zremoved: .id= %sT)rD   r2   rB   r~   r   r   r`   rQ   rx   s     rT   rF   zROS_api_module.api_remove  si    	MM  -KK	"))*<t{{*JKt$ 	KKNN	s   A!A$ $	B-BBc                    | j                  | j                  | j                              }d|j                         vr| j	                  d|z         	  | j
                  j                  di | | j                  d   j                  d|z         | j                  d       y # t        $ r}| j	                  |       Y d }~y d }~ww xY w)N.idzmissing '.id' for %sr9   zupdated: %sTr   )
ru   r\   r3   keysr`   rD   rB   r~   r   r   r   s      rT   rG   zROS_api_module.api_update  s      !2!24;;!?@

$KK.67	 DMM  )5)KK	"))-%*?@t$ 	KKNN	s   AB! !	C*C  Cc                    i }| j                   D ]-  }d|v r|dk7  r| j                  d|z         t        |      ||<   / 	 | j                  r| j                  d   dv rJ | j                  j
                  | j                  || j                  d      | j                  d   k(        }nI| j                  d   dv rI | j                  j
                  | j                  || j                  d      | j                  d   k7        }n| j                  d   d	v rI | j                  j
                  | j                  || j                  d      | j                  d   kD        }n| j                  d   d
v rI | j                  j
                  | j                  || j                  d      | j                  d   k        }n;| j                  d| j                  d   z         n | j                  j
                  | }D ]   }| j                  d   j                  |       " t        | j                  d         dk  rddj                  | j                        ddj                  | j                         }| j                  r!|ddj                  | j                        z  z   }| j                  d   j                  |       | j                  d       y # t        $ r}| j                  |       Y d }~y d }~ww xY w)Nidr   z'%s' must be '.id'rW   )r   r    r   rX   )r   r!   )r   r"   )r   r#   z '%s' is not operator for 'where'r9   zno results for ' z	 'query' z	 WHERE %sF)r5   r`   r   r/   rD   selectrB   r~   r]   r{   r0   r   r   )rQ   r   kr   rowr<   rx   s          rT   rI   zROS_api_module.api_query  s    	AqyQ%Z0145!fDG		zz::a=L01T]]1148>>tDJJqM?RVZV`V`abVc?cdFZZ]m31T]]1148>>tDJJqM?RVZV`V`abVc?cdFZZ]m31T]]1148>>tDJJqM?RUYU_U_`aUb?bcFZZ]m31T]]1148>>tDJJqM?RUYU_U_`aUb?bcFKK B"&**Q-!0 1 .--t4 3I&--c234;;y)*Q.9<$))9L9<$**9MO::chhtzz.B BBCI&--c2u% 	KKNN	s    JK 	K,K''K,c                    |d   | j                   d   vr$| j                  d|d| j                   d          |d   dv r| j                  |d      |d   k(  S |d   dv r| j                  |d      |d   k7  S |d   d	v r| j                  |d      |d   k  S |d   d
v r| j                  |d      |d   kD  S |d   dk(  r" | j                  |d      j                  |d    S | j                  d|d   z         y )Nr&   r.   'z"' attribute is not in attributes: r'   )r    r   r(   )r!   r   )r#   r   )r"   r   r   z'%s' is not operator for 'is')r6   r`   
query_keysIn)rQ   items     rT   build_api_extended_queryz'ROS_api_module.build_api_extended_query  s(   D$7$7$EEKK!4!4\!BD E:%??4#45gFF$Z=(??4#45gFF$Z=(??4#45WEE$Z=(??4#45WEE$Z484??4#4588$w-HHKK7$t*DErm   c                 "   i | _         | j                  d   D ]3  }|dk(  r| j                  d|z         t        |      | j                   |<   5 	 | j                  d   rg }| j                  d   D ]k  }|d   rDg }|d   D ]"  }|j	                  | j                  |             $ |j	                  t        |        L|j	                  | j                  |             m   | j                  j                  | j                    j                  | }n& | j                  j                  | j                  d    }|D ]   }| j                  d   j	                  |       " | j                  d       y # t        $ r}| j                  |       Y d }~y d }~ww xY w)Nr.   r   z0'extended_query':'attributes':'%s' must be '.id'r/   r*   r9   F)r   r6   r`   r   r~   r   r   rD   r   r/   rB   r   r   )	rQ   r   
where_argsro   where_or_argsiorr   r   rx   s	            rT   rK   z!ROS_api_module.api_extended_query  s   $$\2 	(ADyNQRRS!$QDOOA	(	""7+
,,W5 LAw(*#$T7 UC)001N1Ns1STU"))"m*<="))$*G*G*JKL F---t?EEzR---t/B/B</PQ 3I&--c23u% 	KKNN	s   DE* *	F3F		Fc                    i }| j                  | j                        | _        | j                  d   }t        | j                        dkD  r| j                  | j                  dd        }	  | j                  |fi |}|D ]   }| j
                  d   j                  |       " | j                  d       y # t        $ r}| j                  |       Y d }~y d }~ww xY w)Nr   rW   r9   F)
r\   rA   r]   ru   rD   rB   r~   r   r   r`   )rQ   r   arb_cmdarbitrary_resultro   rx   s         rT   rL   zROS_api_module.api_arbitrary(  s    **4>>:..#t~~"$$T^^AB%78E	,t}}W>>% 1I&--a01u% 	KKNN	s   )A	B3 3	C<CCc                     |s*| j                   j                  | j                  d          y | j                   j                  || j                  d          y )Nr9   r;   )changedr<   )r=   rO   rB   	exit_json)rQ   	ch_statusstatuss      rT   r   zROS_api_module.return_result6  sH    KK!!dkk)&<!=KK!!)&*kk)&< " >rm   c                    |j                   j                  dk(  r3| j                  d   j                  d|z         | j	                  dd       | j                  d   j                  d|z         | j	                  dd       y )N	TrapErrorr9   z%sF)	__class____name__rB   r~   r   r   s     rT   r`   zROS_api_module.errors=  sj    ;;;.KK	"))$(3ue,I%%dQh/5%(rm   N) )FT)r   
__module____qualname__rU   rH   rl   rJ   ru   r\   rC   rM   rE   rF   rG   rI   r   rK   rL   r   r`   r   rm   rT   r   r   /  s^    K^Z6y	8b4	BF"4>)rm   r   c                      t                y rz   )r   r   rm   rT   mainr   E  s    rm   __main__) 
__future__r   r   r   r   __metaclass__DOCUMENTATIONEXAMPLESRETURNansible.module_utils.basicr   +ansible.module_utils.common.text.convertersr   Cansible_collections.community.routeros.plugins.module_utils.quotingr   r	   r
   r   ?ansible_collections.community.routeros.plugins.module_utils.apir   r   r   r^   librouteros.exceptionsr   librouteros.queryr   r   	Exceptionr   r   r   r   rm   rT   <module>r      s    C BYvcJ
 5 A   
	7)S) S)l
 zF A	  		s   A# #A+*A+