Обработка параллелизма в модуле Ansible Python

#python #ansible

#питон #ансибль

Вопрос:

У меня есть модуль Ansible, который способен создавать корзину БД. Отлично работает, когда в игре только один хост, но когда есть несколько хостов, для которых playbook работает параллельно — только один получает идентификатор корзины, остальные-нет. Вот код модуля:

 #!/usr/bin/python  from ansible.module_utils.basic import * import requests import re import json  def bucket_present(data):  has_changed = False  has_failed = False  ssl_verify = True  bucket_id = 0   url = data['url']   '/api/v2/buckets'  access_token = data['auth_token']  bucket_name = data['name']  organization_id = data['org_id']  description = data['description']  retention_policy = data['retention_policy']  if data['selfsigned_ssl'] and data['selfsigned_ssl'] == "yes":  ssl_verify = False   headers = {'Authorization': 'Token '   access_token}   # Retention policy is in days  p = re.compile('^[0-9] d

и модуль выполняется следующим образом:

 - name: Create new bucket for tenant  influxdb_bucket:  url: "https://{{ influxdb_host }}:{{ influxdb_port }}"  auth_token: "{{ influxdb_admin_token }}"  org_id: "{{ organization_id }}"  name: "{{ client_bucket }}"  description: "For client {{ client_bucket }} by Ansible"  retention_policy: 365d  state: "{{ state }}"  selfsigned_ssl: "yes"  register: bucket  

Чего я хочу достичь: 3 хоста, на которых запущен модуль, один из них создает корзины, два других получают идентификатор корзины. Похоже, что модуль отправляет несколько запросов на отдых в конечную точку базы данных и не ожидает ответа в случае двух других хостов. Какие у меня есть варианты? Введение какой-то случайной команды сна, некоторых продвинутых механизмов параллелизма/блокировки Python или какой-то "магии" Ansible может решить эту проблему? Заранее спасибо.

Комментарии:

1. Ansible запускает ваш модуль на каждой цели параллельно и совершенно независимо. Ты неправильно это воспринимаешь, ИМО. Вам не нужно запускать это на каждой удаленной цели. На самом деле ты можешь delegate_to: localhost . Ты тоже должен run_once: true . Это создаст/проверит, что ведро существует только один раз в вашей игре, и зарегистрированный var будет назначен каждому хосту в игре с одинаковыми значениями (т. е. идентификатор созданного/существующего ведра)

2. Да, в этом вы совершенно правы. Я уже получил delegate_to: localhost , но пропустил эту run_once: true часть, вероятно, по недосмотру. Спасибо, что сэкономили мне время на дальнейшее расследование. Очевидно, теперь это работает так, как задумывалось.

) if p.match(retention_policy): retention_policy_s = int(retention_policy.strip('d')) * 86400 else: print(json.dumps({ "changed": False, "failed": True, "msg": "Invalid retention policy parameter. Example: 100d" })) sys.exit(1) # Check if the bucket already exists in influxdb r = requests.get(url, headers=headers, verify=ssl_verify) if r.status_code != 200: has_failed = True return has_changed, has_failed, r.json() for bucket in r.json()['buckets']: if bucket['name'] == bucket_name: bucket_id = bucket['id'] meta = {"present": "Bucket: " bucket_name " already exists.", "bucket_id": bucket_id} return has_changed, has_failed, meta payload = { "orgID": organization_id, "name": bucket_name, "description": description, "rp": bucket_name, "retentionRules": [ { "type": "expire", "everySeconds": retention_policy_s } ] } # Create new bucket r = requests.post(url, headers=headers, json=payload, verify=ssl_verify) if r.status_code != 201: if r.json()['code'] == 'conflict': meta = {"present": "Bucket: " bucket_name " already exists.", "bucket_id": bucket_id} has_changed = False return has_changed, has_failed, meta else: has_failed = True return has_changed, has_failed, r.json() else: has_changed = True meta = {"created": r.json(), "bucket_id": r.json()['id']} return has_changed, has_failed, meta def bucket_absent(data): has_changed = False has_failed = False found = False bucket_id = 0 ssl_verify = True url = data['url'] '/api/v2/buckets' access_token = data['auth_token'] bucket_name = data['name'] if data['selfsigned_ssl'] and data['selfsigned_ssl'] == "yes": ssl_verify = False headers = {'Authorization': 'Token ' access_token} # Check bucket ID and if it exists in database r = requests.get(url, headers=headers, verify=ssl_verify) if r.status_code != 200: has_failed = True return has_changed, has_failed, r.json() for bucket in r.json()['buckets']: if bucket['name'] == bucket_name: found = True bucket_id = bucket['id'] if found: r = requests.delete(url '/' bucket_id, headers=headers, verify=ssl_verify) # REST code for 'bucket does not exist' if r.status_code == 404: has_changed = False meta = {"absent": "Bucket: " bucket_name " does not exist in InfluxDB. Skipping..."} return has_changed, has_failed, meta # REST code for 'bucket successfully deleted' elif r.status_code == 204: has_changed = True meta = {"deleted": "SUCCESS: Bucket " bucket_name " deleted.", "bucket_id": bucket_id} return has_changed, has_failed, meta else: meta = {"absent": r.json()} has_failed = True return has_changed, has_failed, meta else: has_changed = False meta = {"absent": "Bucket: " bucket_name " does not exist in InfluxDB. Skipping..."} return has_changed, has_failed, meta def main(): fields = { "url": {"required": True, "type": "str"}, "auth_token": {"required": True, "type": "str"}, "org_id": {"default": "example.org", "type": "str"}, "name": {"required": True, "type": "str"}, "description": {"required": False, "type": "str"}, "retention_policy": {"default": "30d", "type": "str"}, "selfsigned_ssl": {"required": False, "type": "str"}, "state": { "default": "present", "choices": ["present", "absent"], "type": "str" }, } choice_map = { "present": bucket_present, "absent": bucket_absent, } module = AnsibleModule(argument_spec=fields) has_changed, has_failed, result = choice_map.get(module.params['state'])(module.params) module.exit_json(changed=has_changed, failed=has_failed, meta=result) if __name__ == '__main__': main() и модуль выполняется следующим образом:


Чего я хочу достичь: 3 хоста, на которых запущен модуль, один из них создает корзины, два других получают идентификатор корзины. Похоже, что модуль отправляет несколько запросов на отдых в конечную точку базы данных и не ожидает ответа в случае двух других хостов. Какие у меня есть варианты? Введение какой-то случайной команды сна, некоторых продвинутых механизмов параллелизма/блокировки Python или какой-то «магии» Ansible может решить эту проблему? Заранее спасибо.

Комментарии:

1. Ansible запускает ваш модуль на каждой цели параллельно и совершенно независимо. Ты неправильно это воспринимаешь, ИМО. Вам не нужно запускать это на каждой удаленной цели. На самом деле ты можешь delegate_to: localhost . Ты тоже должен run_once: true . Это создаст/проверит, что ведро существует только один раз в вашей игре, и зарегистрированный var будет назначен каждому хосту в игре с одинаковыми значениями (т. е. идентификатор созданного/существующего ведра)

2. Да, в этом вы совершенно правы. Я уже получил delegate_to: localhost , но пропустил эту run_once: true часть, вероятно, по недосмотру. Спасибо, что сэкономили мне время на дальнейшее расследование. Очевидно, теперь это работает так, как задумывалось.