0

I've got a .yml file filled with hundreds of configuration values for an Axis network camera. The contents look like this:

---
axis:
  config:
    "Bandwidth.Limit": 0
    "HTTPS.AllowTLS1": "no"
    "HTTPS.AllowTLS11": "no"
    "HTTPS.AllowSSLV3": "no"
    "HTTPS.Ciphers": AES256-SHA:AES128-SHA
    "HTTPS.Enabled": "yes"
    "HTTPS.Port": 443
    ...

The Axis API, called Vapix, provides an update function that updates a value, so I circled through the values and triggered a new API call with every iteration:

---
  - name: update parameters
    local_action:
      module: uri 
      user: "{{ axis_snmp_role.login_user }}"
      password: "{{ axis_snmp_role.login_password }}"
      url: "{{ axis_snmp_role.server_url }}?action=update&{{ item.key }}={{ item.value }}"
      validate_certs: false
    with_dict: "{{ axis.config }}"

Turns out this works, but takes forever. I manually found out that it's possible to update multiple values with one API call by glueing the key/value-pairs together with the &-symbol like this:

https://{{ axis_snmp_role.server_url }}/axis-cgi/param.cgi?action=update&ImageSource.I0.Sensor.ExposureValue=100&Image.I0.Appearance.Compression=50

Is it possible to craft an Ansible loop that reads 100 key/values-pairs at once, creates one big api call with all of them, sends it off and repeats this until the end of the config file is reached?

Nuokh
  • 43
  • 5

1 Answers1

1

Simply create a list of query parameters in a loop and send it at once joining them with &.

---
- name: Create a parameter list
  set_fact:
    my_params: "{{ my_params | default([]) + [îtem.key + '=' + item.value] }}"
  with_dict: "{{ axis.config }}"

- name: Update parameters
  uri:
    user: "{{ axis_snmp_role.login_user }}"
    password: "{{ axis_snmp_role.login_password }}"
    url: "{{ axis_snmp_role.server_url }}?action=update&{{ my_params | join('&') }}"
    validate_certs: false
  delegate_to: localhost

Notes:

  • You might hit a url max length if you really have a lot or params. In this case, cut the following in several iterations.
  • You may have to encode your values with the urlencode filter if they contain special chars.
Zeitounator
  • 38,476
  • 7
  • 53
  • 66
  • First and foremost tahnk you for the detailed answer! How exactly could I cut this into several iterations of (for example) 100 params until all are set? – Nuokh Jan 16 '20 at 12:15
  • 1
    You will need to `count` and [slice](https://stackoverflow.com/questions/509211/understanding-slice-notation) – Zeitounator Jan 16 '20 at 13:06
  • Sorry but could you modify your example to show how you would count and slice the requests? – Nuokh Jan 16 '20 at 14:37
  • 1
    There is one trick because your var is a dict and you can only slice lists. You get the total number of elements in your dict with `axis.config | count`. From there it is rather easy to slice by sets of 100 until your reach the end. To slice your object, what you can do is `(axis.config | dict2items)[x:y] | items2dict`. This will transform your dict in a list like `[{key: keyname, value: keyvalue}, ...]`. You can then slice that list from elements `x` to `y` and transform it back to a dict with `items2dict`. – Zeitounator Jan 16 '20 at 17:22