Ansible and Satellite 6.4 - Waiting for Promote To Finish

I created a playbook to connect to Satellite via API, publish new content views, and promote the various lifecycle environments to these new Content View versions, looping through a list of Lifecycle Environments. The issue I’m having is I can’t figure out a way for my task to wait until the promotion of one Lifecycle Environment is completed before attempting to promote the next. If it tries to promote while a promotion is already in progress, the task fails. I’ve added a delay to the task to try to wait it out but that doesn’t always work and was hoping for a more clever solution. Here’s my task:

  • name: Promote new RHEL7 version to Lifecycle Environments
    uri:
    url: “https://satelliteserver/katello/api/v2/content_view_versions/{{ (content_views7.json.results[0].id | int) }}/promote”
    method: POST
    body:
    description: “Promoted by Tower”
    environment_id: “{{ item }}”
    organization_id: 3
    force: true
    user: “{{ satellite_user }}”
    password: “{{ satellite_pass }}”
    force_basic_auth: yes
    validate_certs: no
    body_format: json
    status_code: 202
    loop:
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
    loop_control:
    pause: 180

Any input on a way to wait for the promotion to finish, or a cleaner way of doing the same thing?

Cade,

Check out https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html There’s delays, retries etc. You can use any of this to accomplish what you want.

So I’m still having trouble with this. Here’s my task:

`

  • name: Promote new RHEL7 version to Lifecycle Environments
    uri:
    url: “https://satellite/katello/api/v2/content_view_versions/{{ (content_views7.json.results[0].id | int) }}/promote”
    method: POST
    body:
    description: “Promoted by Tower”
    environment_id: “{{ item }}”
    organization_id: 3
    force: true
    user: “{{ satellite_user }}”
    password: “{{ satellite_pass }}”
    force_basic_auth: yes
    validate_certs: no
    body_format: json
    status_code: 202
    register: promote_rhel7
    loop:
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
    until: promote_rhel7.json.result == ‘success’
    retries: 10
    delay: 20

`

I tried this but it error’d out with:

`
fatal: [localhost]: FAILED! => {“msg”: “The conditional check ‘promote_rhel7.json.result == ‘success’’ failed. The error was: error while evaluating conditional (promote_rhel7.json.result == ‘success’): ‘dict object’ has no attribute ‘result’”}

`

Which I kind of expected because it doesn’t seem like it’s returning anything. I’m trying to loop through all the lifecycle environments in one task, but I also need to check the tasks from satellite to ensure the promotion is done before it attempts to promote to the next lifecycle environment, or it’ll throw a lock error. I know I could ditch the loop and create a task for each lifecycle environment, and check satellite tasks prior to each promotion, but I was hoping there was a sleeker way to do it.

I’ve used loop_control and pause previously, but I’d like to know for certain a promote is complete before attempting the next one.

I don't know anything about the api you are using so I can't comment on that, but this type of error can be solved by checking if the variable is defined first.

   until: promote_rhel7.json.result is defined and promote_rhel7.json.result == 'success'

Yeah, it’s not defined because it’s not a value that’s returned when the API call is sent. I’m not sure there’s a way to do what I’m trying to do with a loop.

I think Kai’s suggestion is correct, don’t know much about your specific use case, but I’ve had similar issues looping with return values. The reason is on there first check the call hasn’t been made yet and “results” won’t exist you’re right, but on subsequent calls within that loop it will, so that extra clause should fix that error.

I tested that just now. It doesn’t work. The API doesn’t send a response about the status of the promote task. When I make the call to promote, it immediately responds with info that it started, and that’s all. So the solution Kai provided really just keeps sending the same API request using the same loop item, because it never gets a response back from the API about result.

root@tower /etc/ansible/playbooks $ ansible-playbook test.yml

PLAY [localhost] ********************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] **************************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Promote new RHEL7 version to Lifecycle Environments] **************************************************************************************************************************************************************************************
FAILED - RETRYING: Promote new RHEL7 version to Lifecycle Environments (10 retries left).
FAILED - RETRYING: Promote new RHEL7 version to Lifecycle Environments (9 retries left).
FAILED - RETRYING: Promote new RHEL7 version to Lifecycle Environments (8 retries left).
FAILED - RETRYING: Promote new RHEL7 version to Lifecycle Environments (7 retries left).
FAILED - RETRYING: Promote new RHEL7 version to Lifecycle Environments (6 retries left).
FAILED - RETRYING: Promote new RHEL7 version to Lifecycle Environments (5 retries left).
FAILED - RETRYING: Promote new RHEL7 version to Lifecycle Environments (4 retries left).
FAILED - RETRYING: Promote new RHEL7 version to Lifecycle Environments (3 retries left).

Okay, looking more closely I think I see. I don’t believe “results” becomes populated in a loop object until the end of the first iteration and with a retry technically you have never ended that first iteration. What I would do then is this:

include_tasks: register_environment
loop:

  • 3
  • 4
    etc

Interesting, I’ll try that later. For now, I just went ahead and created the role with each lifecycle environment having it’s own register task and then importing a separate task file that contains the tasks to query the task queue in satellite and wait until the task is finished… I think if I combined that with your idea, it’d probably work and have less code.