通过 Ansible 一次 api 调用只能同时更新 100 个值
Only update 100 values simultaneously one api call via Ansible
我有一个 .yml 文件,其中包含安讯士网络摄像机的数百个配置值。内容如下所示:
---
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
...
Axis API,称为 Vapix,提供了一个更新值的更新函数,因此我在值中循环并在每次迭代时触发新的 API 调用:
---
- 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 }}"
事实证明这是有效的,但需要很长时间。我手动发现可以通过一个 API 调用来更新多个值,方法是将 key/value-pairs 与 &-符号粘合在一起,如下所示:
https://{{ axis_snmp_role.server_url }}/axis-cgi/param.cgi?action=update&ImageSource.I0.Sensor.ExposureValue=100&Image.I0.Appearance.Compression=50
所以我用它来构建一个大的 API 调用,它将一次设置所有值。
---
- name: Create parameter list
set_fact:
my_parameters: "{{ my_parameters | default([]) + [item.key + '=' + item.value|string|urlencode() ] }}"
with_dict: "{{ axis.config }}"
- name: update parameters
#no_log: true
local_action:
module: uri
user: "{{ axis_snmp_role.login_user }}"
password: "{{ axis_snmp_role.login_password }}"
url: "{{ axis_snmp_role.server_url }}?action=update&{{ my_parameters | join('&') }}"
validate_certs: false
#with_dict: "{{ axis.config }}"
事实证明网络摄像机不喜欢一次获得这么多值,所以我想我不得不将过程分开一点。
是否可以制作一个 Ansible 循环,一次读取 100 key/values-pairs,创建一个包含所有这些的大 api 调用,发送它并重复此操作直到配置结束已到达文件?
Q: "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?"
答:是的。这是可能的。以下是有关如何拆分参数的过程。将变量 period
设置为 100 并进行测试。
给定 axis.config
声明 period
进行测试
vars:
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
period: 2
创建参数列表并计算列表的长度
- set_fact:
config_list: "{{ config_list|default([]) + [item.key ~ '=' ~ item.value] }}"
loop: "{{ axis.config|dict2items }}"
- debug:
var: config_list
- set_fact:
config_length: "{{ config_list|length }}"
- debug:
var: config_length
给予
"config_list": [
"HTTPS.Ciphers=AES256-SHA:AES128-SHA",
"HTTPS.AllowTLS11=no",
"HTTPS.AllowTLS1=no",
"HTTPS.Enabled=yes",
"HTTPS.Port=443",
"Bandwidth.Limit=0",
"HTTPS.AllowSSLV3=no"
]
"config_length": "7"
将 config_list
拆分为长度为 period
的子列表
- set_fact:
split_list: "{{ split_list|default([]) +
[config_list[split0|int:split1|int]] }}"
vars:
split0: "{{ ansible_loop.previtem|default(0) }}"
split1: "{{ ansible_loop.last|ternary(config_length, item) }}"
loop: "{{ range(period, config_length|int, period)|list }}"
loop_control:
extended: yes
- debug:
var: split_list
给予
"split_list": [
[
"HTTPS.Ciphers=AES256-SHA:AES128-SHA",
"HTTPS.AllowTLS11=no"
],
[
"HTTPS.AllowTLS1=no",
"HTTPS.Enabled=yes"
],
[
"HTTPS.Port=443",
"Bandwidth.Limit=0",
"HTTPS.AllowSSLV3=no"
]
]
循环列表并加入参数
- debug:
msg: "{{ item|join('&') }}"
loop: "{{ split_list }}"
给予
"msg": "HTTPS.Ciphers=AES256-SHA:AES128-SHA&HTTPS.AllowTLS11=no"
"msg": "HTTPS.AllowTLS1=no&HTTPS.Enabled=yes"
"msg": "HTTPS.Port=443&Bandwidth.Limit=0&HTTPS.AllowSSLV3=no"
使用一些自定义过滤器(如下),该过程将得到简化
$ cat filter_plugins/dict_filters.py
def dict2list(d):
l = []
for i in d:
h = {i:d[i]}
l.append(h)
return l
class FilterModule(object):
def filters(self):
return {
'dict2list' : dict2list
}
$ cat filter_plugins/list_filters.py
def list_split(l, p):
split_list = []
for i in range(p, len(l)+p, p):
if i == p:
split_list.append(l[0:p])
elif i > len(l):
split_list.append(l[j:])
else:
split_list.append(l[j:i])
j = i
return split_list
class FilterModule(object):
def filters(self):
return {
'list_split' : list_split
}
$ cat filter_plugins/hash_filters.py
def hash_to_tuple(h):
return h.items()[0]
class FilterModule(object):
def filters(self):
return {
'hash_to_tuple': hash_to_tuple
}
下面的任务
- set_fact:
config_list: "{{ axis.config|
dict2list|
map('hash_to_tuple')|
map('join', '=')|
list }}"
- set_fact:
split_list: "{{ config_list|list_split(period) }}"
- debug:
msg: "{{ item|join('&') }}"
loop: "{{ split_list }}"
给出相同的结果
"msg": "HTTPS.Ciphers=AES256-SHA:AES128-SHA&HTTPS.AllowTLS11=no"
"msg": "HTTPS.AllowTLS1=no&HTTPS.Enabled=yes"
"msg": "HTTPS.Port=443&Bandwidth.Limit=0"
"msg": "HTTPS.AllowSSLV3=no"
我有一个 .yml 文件,其中包含安讯士网络摄像机的数百个配置值。内容如下所示:
---
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
...
Axis API,称为 Vapix,提供了一个更新值的更新函数,因此我在值中循环并在每次迭代时触发新的 API 调用:
---
- 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 }}"
事实证明这是有效的,但需要很长时间。我手动发现可以通过一个 API 调用来更新多个值,方法是将 key/value-pairs 与 &-符号粘合在一起,如下所示:
https://{{ axis_snmp_role.server_url }}/axis-cgi/param.cgi?action=update&ImageSource.I0.Sensor.ExposureValue=100&Image.I0.Appearance.Compression=50
所以我用它来构建一个大的 API 调用,它将一次设置所有值。
---
- name: Create parameter list
set_fact:
my_parameters: "{{ my_parameters | default([]) + [item.key + '=' + item.value|string|urlencode() ] }}"
with_dict: "{{ axis.config }}"
- name: update parameters
#no_log: true
local_action:
module: uri
user: "{{ axis_snmp_role.login_user }}"
password: "{{ axis_snmp_role.login_password }}"
url: "{{ axis_snmp_role.server_url }}?action=update&{{ my_parameters | join('&') }}"
validate_certs: false
#with_dict: "{{ axis.config }}"
事实证明网络摄像机不喜欢一次获得这么多值,所以我想我不得不将过程分开一点。
是否可以制作一个 Ansible 循环,一次读取 100 key/values-pairs,创建一个包含所有这些的大 api 调用,发送它并重复此操作直到配置结束已到达文件?
Q: "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?"
答:是的。这是可能的。以下是有关如何拆分参数的过程。将变量 period
设置为 100 并进行测试。
给定 axis.config
声明 period
进行测试
vars:
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
period: 2
创建参数列表并计算列表的长度
- set_fact:
config_list: "{{ config_list|default([]) + [item.key ~ '=' ~ item.value] }}"
loop: "{{ axis.config|dict2items }}"
- debug:
var: config_list
- set_fact:
config_length: "{{ config_list|length }}"
- debug:
var: config_length
给予
"config_list": [
"HTTPS.Ciphers=AES256-SHA:AES128-SHA",
"HTTPS.AllowTLS11=no",
"HTTPS.AllowTLS1=no",
"HTTPS.Enabled=yes",
"HTTPS.Port=443",
"Bandwidth.Limit=0",
"HTTPS.AllowSSLV3=no"
]
"config_length": "7"
将 config_list
拆分为长度为 period
- set_fact:
split_list: "{{ split_list|default([]) +
[config_list[split0|int:split1|int]] }}"
vars:
split0: "{{ ansible_loop.previtem|default(0) }}"
split1: "{{ ansible_loop.last|ternary(config_length, item) }}"
loop: "{{ range(period, config_length|int, period)|list }}"
loop_control:
extended: yes
- debug:
var: split_list
给予
"split_list": [
[
"HTTPS.Ciphers=AES256-SHA:AES128-SHA",
"HTTPS.AllowTLS11=no"
],
[
"HTTPS.AllowTLS1=no",
"HTTPS.Enabled=yes"
],
[
"HTTPS.Port=443",
"Bandwidth.Limit=0",
"HTTPS.AllowSSLV3=no"
]
]
循环列表并加入参数
- debug:
msg: "{{ item|join('&') }}"
loop: "{{ split_list }}"
给予
"msg": "HTTPS.Ciphers=AES256-SHA:AES128-SHA&HTTPS.AllowTLS11=no"
"msg": "HTTPS.AllowTLS1=no&HTTPS.Enabled=yes"
"msg": "HTTPS.Port=443&Bandwidth.Limit=0&HTTPS.AllowSSLV3=no"
使用一些自定义过滤器(如下),该过程将得到简化
$ cat filter_plugins/dict_filters.py
def dict2list(d):
l = []
for i in d:
h = {i:d[i]}
l.append(h)
return l
class FilterModule(object):
def filters(self):
return {
'dict2list' : dict2list
}
$ cat filter_plugins/list_filters.py
def list_split(l, p):
split_list = []
for i in range(p, len(l)+p, p):
if i == p:
split_list.append(l[0:p])
elif i > len(l):
split_list.append(l[j:])
else:
split_list.append(l[j:i])
j = i
return split_list
class FilterModule(object):
def filters(self):
return {
'list_split' : list_split
}
$ cat filter_plugins/hash_filters.py
def hash_to_tuple(h):
return h.items()[0]
class FilterModule(object):
def filters(self):
return {
'hash_to_tuple': hash_to_tuple
}
下面的任务
- set_fact:
config_list: "{{ axis.config|
dict2list|
map('hash_to_tuple')|
map('join', '=')|
list }}"
- set_fact:
split_list: "{{ config_list|list_split(period) }}"
- debug:
msg: "{{ item|join('&') }}"
loop: "{{ split_list }}"
给出相同的结果
"msg": "HTTPS.Ciphers=AES256-SHA:AES128-SHA&HTTPS.AllowTLS11=no"
"msg": "HTTPS.AllowTLS1=no&HTTPS.Enabled=yes"
"msg": "HTTPS.Port=443&Bandwidth.Limit=0"
"msg": "HTTPS.AllowSSLV3=no"