Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provisioning a new device via equinix.metal.device can sometimes succeed with 0 returned devices. #35

Open
ischeinkman opened this issue May 1, 2021 · 2 comments · May be fixed by #36

Comments

@ischeinkman
Copy link

SUMMARY

There seems to be a race condition when provisioning a new device and waiting for the provisioning to complete (either via setting state: active or via wait_for_public_IPv: 4/6). Specifically, if the device disappears from the active devices list while waiting for either of those conditions, the equinix.metal.device module will success with an empty device list instead of failing. This can happen, for example, when attempting to provision a new host with the same hostname as a host in the process of being de-provisioned.

This seems to be due to the fact that the wait_for_devices_active and wait_for_public_IPv functions attempt to wait for their conditions to be met by polling the results refresh_devices_list and checking that all devices returned match their requirements, but refresh_devices_list only returns devices visible from the API without checking to see if that includes all the device IDs passed as a parameter.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

equinix.metal.device

STEPS TO REPRODUCE
  1. Provision a server with the following play:
- name: Provision an Equinix server.
  register: output
  equinix.metal.device:
            api_token: "{{ apikey }}"
            project_id: "{{ project }}"
            name: "{{ name }}"
            state: present
            plan: "{{ plan }}"
            operating_system: "ubuntu_20_04"
            facility: "{{ region }}"
            wait_for_public_IPv: 6
            user_data: "{{ user_data }}"
  1. Begin a de-provisioning of that server, either via the web UI or via setting state to absent on the above play.

  2. Before the de-provisioning of the host created in Step 1 completes, re-run the above play.

EXPECTED RESULTS

Either the module to throw an error or to wait for the previous host to finish de-provisioning before attempting to re-provision.

ACTUAL RESULTS

The play succeeds, except output.devices is empty.

@displague
Copy link
Member

Thanks for reporting this @ischeinkman.

by polling the results refresh_devices_list and checking that all devices returned match their requirements, but refresh_devices_list only returns devices visible from the API without checking to see if that includes all the device IDs passed as a parameter.

Actually, it looks like refresh_devices_list is correctly filtering the list of results to those matching the devices specified (by id).

The bug here is in the "all". As a vacuous truth the condition is met. We can add a len() check to ensure that the expected number of refreshed devices are found.

>>> if all(d == 1 for d in []):
...   print("yes")
... 
yes

@ischeinkman
Copy link
Author

Actually, it looks like refresh_devices_list is correctly filtering the list of results to those matching the devices specified (by id).

Yes, that is true. What I was referring to was that refresh_devices_list only returns entries found in the list of results returned from module.get_devices(). If a devices passed in the initial devices list cannot be found in the return value of module.get_devices() then the function will not include an entry for that device ( as opposed to doing something like creating a Device object with a state of deleted/deprovisioned or something to that effect ).

Sorry that I wasn't clear!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants