2017-09-06 3 views
0

Diese Frage bezieht sich auf Schleifen in Ansible, nicht über AWS, aber aus Gründen der Klarheit werde ich ein AWS-Bereitstellungsproblem als ein Beispiel verwenden.Wie Regex geschachtelte Werte in Ansible ersetzen

Für unsere Bereitstellungsskripts versuche ich einige Cluster im Amazon EC2-Containerdienst zu durchlaufen. Letztendlich starte ich jeden Dienst im Cluster neu. Ich bin in der Lage, einen Dienst neu zu starten, wenn man seinen Namen angibt. Allerdings brauche ich den einfachen Namen, nicht den voll qualifizierten ARN. So sehe ich die Dienste pro Cluster und so etwas wie dieses:

results: 
- _ansible_item_result: true 
    _ansible_no_log: false 
    _ansible_parsed: true 
    ansible_facts: 
    services: 
    - arn:aws:ecs:eu-central-1:55:service/test-services 
    changed: false 
    failed: false 
    invocation: 
    module_args: 
     aws_access_key: null 
     aws_secret_key: null 
     cluster: services 
     details: false 
     ec2_url: null 
     profile: null 
     region: null 
     security_token: null 
     service: null 
     validate_certs: true 
    item: services 
- _ansible_item_result: true 
    _ansible_no_log: false 
    _ansible_parsed: true 
    ansible_facts: 
    services: 
    - arn:aws:ecs:eu-central-1:55:service/test-service 
    - arn:aws:ecs:eu-central-1:55:service/frontend 
    - arn:aws:ecs:eu-central-1:55:service/beats 
    changed: false 
    failed: false 
    invocation: 
    module_args: 
     aws_access_key: null 
     aws_secret_key: null 
     cluster: test-service 
     details: false 
     ec2_url: null 
     profile: null 
     region: null 
     security_token: null 
     service: null 
     validate_certs: true 
    item: test-service module_args: 
    aws_access_key: null 
    aws_secret_key: null 
    cluster: test-service 
    details: false 
    ec2_url: null 
    profile: null 
    region: null 
    security_token: null 
    service: null 
    validate_certs: true 

Artikel: Test-Service

Jetzt habe ich jeden ARN durch den kurzen Namen des Dienstes ersetzen möchten. Zum Beispiel: arn:aws:ecs:eu-central-1:55:service/test-service wird test-service.

Nach dem Austausch kann ich Schleife über die Dienste und schalten Sie sie, indem Sie die gewünschte Zählung auf 0 (später werde ich schalten Sie sie wieder ein) aus:

- name: "Turn services off" 
    ecs_service: 
    name: "{{ item[1]}}" 
    desired_count: 0 
    task_definition: "{{ taskdefinitions[item[1]] }}" 
    cluster: "{{ item[0].item }}" 
    state: present 
with_subelements: 
    - "{{ result.results }}" 
    - ansible_facts.services 
register: turnOffServiceResult 

Wo taskdefinitions eine einfache dict I definierte im Textbuch:

taskdefinitions: 
    services: 
    - test-services 
    test-xde-worker-service: 
    - test-service 

So, nachdem ich die AWS-Liste erhalte oben in eine Variable result ich versuche gezeigt folgendes zu regex zu ersetzen, indem Sie:

- set_fact: 
    result: 
    results: 
     ansible_facts: 
     services: "{{ result.results.1.ansible_facts.services | map('regex_replace', '.*/(.*?)$', '\\1') | list }}" 

Das funktioniert gut, aber es ersetzt offensichtlich nur die Dienstnamen für einen Cluster und ich verliere alle anderen Felder im dict ansible_facts. Letzteres ist akzeptabel, ersteres nicht. Also hier ist die Frage: Wie kann ich Text in einer verschachtelten Liste ersetzen? Ein anderes Problem wäre, die Dienste, die nicht in taskdefinitions enthalten sind, zu überspringen, aber das ist nicht die Sache.

+0

Warum Werte innerhalb ganzer dict ersetzen und nicht, wenn sie 'ecs_service' vorbei? –

+0

Guter Punkt, ich habe versucht, den Filter beim Übergeben der Variablen, aber das scheint nicht zu funktionieren. Sie werden bemerken, dass ich 'item [1]' als benannten Index verwende, um die task_definition nachzuschlagen. Wenn Sie mir sagen können, wie ich dort einen Filter anwenden kann, wäre ich sehr glücklich, ich könnte es nicht zur Arbeit bringen. Ich bin auch ziemlich sicher, dass jemand irgendwann einige Werte in einer verschachtelten Liste filtern muss. Daher die allgemeinere Frage. – titusn

Antwort

2

Ich kenne keine integrierte Methode, um beliebige Objekte in komplexen Objekten in-Place (zumindest in aktuellen Ansible 2.3) zu ändern.

Sie wählen entweder die gewünschten Objekte aus dem Originalobjekt (mit select, map(attribute=...), json_query, usw.) und ändern dann die Objekte in dieser reduzierten Menge/Liste. In Ihrem hypothetischen Beispiel mit JMESPath wie result.results[].ansible_facts.services[], um alle Dienste über alle Cluster und map('regex_replace',... diese Liste auszuwählen.

Oder iterieren komplexes Objekt und wendet Modifikation innerhalb einer Schleife, zum Beispiel:

- name: "Turn services off" 
    ecs_service: 
    name: "{{ myname }}" 
    desired_count: 0 
    task_definition: "{{ taskdefinitions[myname] }}" 
    cluster: "{{ mycluster }}" 
    state: present 
    vars: 
    mycluster: "{{ item[0].item }}" 
    myname: "{{ item[1] | regex_search('[^/]*$') }}" 
    with_subelements: 
    - "{{ result.results }}" 
    - ansible_facts.services 
+0

Das klingt vielversprechend, ich werde es ausprobieren und zurückkommen. – titusn

+0

Ja, mit Vars funktioniert. Es stellte sich heraus, dass mein früherer Versuch auch funktionierte, aber ich erhielt die Fehlermeldung "Ein Fehler ist aufgetreten (ClientException) beim Aufruf der UpdateService-Operation: Familie enthält ungültige Zeichen." Offenbar hatte ich gerade einen noob-Fehler gemacht und es ergab sich eine Liste anstelle eines einzelnen Wertes. Gute auf der Regex Verbesserung auch. – titusn

+0

Aus reiner Neugier, warum haben Sie in Ihrer Antwort geschrieben, dass ich keine gültigen Daten zur Verfügung gestellt habe? Ich denke, alles war in der Frage, ich habe nur unsere Kontonummer und einige Servicenamen anonymisiert. – titusn