-
Notifications
You must be signed in to change notification settings - Fork 3
Support Application Credentials in shiftstack-qa automation #13
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
8d5c917
bda356e
b4546d3
7756aed
35985b8
6c996c3
8548bec
3624afa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,107 @@ | ||||||||||
| --- | ||||||||||
| # Source: https://github.com/shiftstack/installer/blob/master/docs/user/openstack/README.md#openstack-credentials-update | ||||||||||
| - name: Delete existing Application Credential | ||||||||||
| ansible.builtin.shell: | | ||||||||||
| openstack application credential delete {{ app_credential_name }} | ||||||||||
| environment: | ||||||||||
| OS_CLOUD: "{{ user_cloud }}" | ||||||||||
| failed_when: false | ||||||||||
| changed_when: false | ||||||||||
|
|
||||||||||
| - name: Create Application Credential | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The IR plugin's - name: Make sure we are using user/password so we can create additional app creds
include_role:
name: prepare
tasks_from: project/clouds.ymlThis ensures full permissions for the creation step in case the cluster was already rotated to app creds in a prior run. For the current
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed. Added |
||||||||||
| ansible.builtin.shell: | | ||||||||||
| openstack application credential create \ | ||||||||||
| --description "App Creds - All roles" \ | ||||||||||
| "{{ app_credential_name }}" -f yaml | ||||||||||
| environment: | ||||||||||
| OS_CLOUD: "{{ user_cloud }}" | ||||||||||
| register: app_cred_output | ||||||||||
| changed_when: true | ||||||||||
|
|
||||||||||
| - name: Parse Application Credential output | ||||||||||
| ansible.builtin.set_fact: | ||||||||||
| app_cred_info: "{{ app_cred_output.stdout | from_yaml }}" | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The clouds.yaml update logic (lines 25-65) is duplicated almost verbatim in In shiftstack-qa's collection structure, a relative
This would also fix the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed. Refactored |
||||||||||
|
|
||||||||||
| - name: Read current clouds.yaml | ||||||||||
| ansible.builtin.slurp: | ||||||||||
| src: "{{ clouds_yaml_file_path }}" | ||||||||||
| register: clouds_yaml_file | ||||||||||
|
|
||||||||||
| - name: Set clouds.yaml fact | ||||||||||
| ansible.builtin.set_fact: | ||||||||||
| clouds_yaml_params: "{{ clouds_yaml_file.content | b64decode | from_yaml }}" | ||||||||||
|
|
||||||||||
| - name: Build updated cloud entry with application credentials | ||||||||||
| ansible.builtin.set_fact: | ||||||||||
| updated_cloud_entry: | ||||||||||
| auth: | ||||||||||
| auth_url: "{{ clouds_yaml_params.clouds[user_cloud].auth.auth_url }}" | ||||||||||
| application_credential_id: "{{ app_cred_info.id }}" | ||||||||||
| application_credential_secret: "{{ app_cred_info.secret }}" | ||||||||||
| auth_type: v3applicationcredential | ||||||||||
| identity_api_version: "{{ clouds_yaml_params.clouds[user_cloud].identity_api_version | default('3') }}" | ||||||||||
| region_name: "{{ clouds_yaml_params.clouds[user_cloud].region_name | default(omit) }}" | ||||||||||
|
|
||||||||||
| - name: Add cacert to updated cloud entry | ||||||||||
| ansible.builtin.set_fact: | ||||||||||
| updated_cloud_entry: "{{ updated_cloud_entry | combine({'cacert': clouds_yaml_params.clouds[user_cloud].cacert}, recursive=True) }}" | ||||||||||
| when: clouds_yaml_params.clouds[user_cloud].cacert is defined | ||||||||||
|
|
||||||||||
| - name: Update clouds.yaml with application credentials | ||||||||||
| ansible.builtin.set_fact: | ||||||||||
| clouds_yaml_params: "{{ {'clouds': (clouds_yaml_params.clouds | combine({user_cloud: updated_cloud_entry}))} }}" | ||||||||||
|
|
||||||||||
| - name: Write updated clouds.yaml | ||||||||||
| ansible.builtin.copy: | ||||||||||
| content: "{{ clouds_yaml_params | to_nice_yaml(indent=4) }}" | ||||||||||
| dest: "{{ clouds_yaml_file_path }}" | ||||||||||
| mode: u=rw,g=rw,o=r | ||||||||||
|
|
||||||||||
| - name: Update clouds.yaml copy in osp_config_dir | ||||||||||
| ansible.builtin.copy: | ||||||||||
| content: "{{ clouds_yaml_params | to_nice_yaml(indent=4) }}" | ||||||||||
| dest: "{{ osp_config_dir }}/clouds.yaml" | ||||||||||
| mode: u=rw,g=rw,o=r | ||||||||||
|
|
||||||||||
| - name: Create clouds.yaml copy with cloud renamed for OCP secret | ||||||||||
| ansible.builtin.shell: | | ||||||||||
| set -o pipefail && \ | ||||||||||
| cat {{ clouds_yaml_file_path }} | sed 's/{{ user_cloud }}:/openstack:/' > /tmp/clouds_for_ocp.yaml | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This writes the modified
Suggested change
The
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed. Replaced the temp file pattern with piping directly via clouds.yaml=-: Eliminates the intermediate file and cleanup task. |
||||||||||
| changed_when: false | ||||||||||
|
|
||||||||||
| - name: Rotate OpenShift Cloud Credentials | ||||||||||
| ansible.builtin.shell: | | ||||||||||
| oc set data -n kube-system secret/openstack-credentials clouds.yaml="$(cat /tmp/clouds_for_ocp.yaml)" | ||||||||||
| environment: | ||||||||||
| KUBECONFIG: "{{ kubeconfig }}" | ||||||||||
| changed_when: true | ||||||||||
|
|
||||||||||
| - name: Clean up temporary file | ||||||||||
| ansible.builtin.file: | ||||||||||
| path: /tmp/clouds_for_ocp.yaml | ||||||||||
| state: absent | ||||||||||
|
|
||||||||||
| - name: Get OpenStack Credentials from OCP cluster | ||||||||||
| ansible.builtin.shell: | | ||||||||||
| set -o pipefail && \ | ||||||||||
| oc get secret -n kube-system openstack-credentials -o json | jq -r '.data."clouds.yaml"' | base64 -d | ||||||||||
| environment: | ||||||||||
| KUBECONFIG: "{{ kubeconfig }}" | ||||||||||
| register: ocp_creds_output | ||||||||||
| changed_when: false | ||||||||||
|
|
||||||||||
| - name: Parse OCP credentials | ||||||||||
| ansible.builtin.set_fact: | ||||||||||
| ocp_creds: "{{ ocp_creds_output.stdout | from_yaml }}" | ||||||||||
|
|
||||||||||
| - name: Verify credentials rotated to application credentials | ||||||||||
| ansible.builtin.assert: | ||||||||||
| that: | ||||||||||
| - ocp_creds.clouds.openstack.auth_type == 'v3applicationcredential' | ||||||||||
| fail_msg: "Credential rotation failed — auth_type is not v3applicationcredential" | ||||||||||
| success_msg: "Credential rotation verified — auth_type is v3applicationcredential" | ||||||||||
|
|
||||||||||
| - name: Wait until the Cluster Operators are healthy | ||||||||||
| ansible.builtin.include_role: | ||||||||||
| name: tools_cluster_checks | ||||||||||
| tasks_from: wait_until_cluster_operators_ready.yml | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| --- | ||
| - name: Delete existing Application Credential | ||
| ansible.builtin.shell: | | ||
| openstack application credential delete {{ app_credential_name }} | ||
| environment: | ||
| OS_CLOUD: "{{ user_cloud }}" | ||
| failed_when: false | ||
| changed_when: false | ||
|
|
||
| - name: Create Application Credential | ||
| ansible.builtin.shell: | | ||
| openstack application credential create \ | ||
| --description "App Creds - All roles" \ | ||
| "{{ app_credential_name }}" -f yaml | ||
| environment: | ||
| OS_CLOUD: "{{ user_cloud }}" | ||
| register: app_cred_output | ||
| changed_when: true | ||
|
|
||
| - name: Parse Application Credential output | ||
| ansible.builtin.set_fact: | ||
| app_cred_info: "{{ app_cred_output.stdout | from_yaml }}" | ||
|
|
||
| - name: Read current clouds.yaml | ||
| ansible.builtin.slurp: | ||
| src: "{{ clouds_yaml_file_path }}" | ||
| register: clouds_yaml_file | ||
|
|
||
| - name: Set clouds.yaml fact | ||
| ansible.builtin.set_fact: | ||
| clouds_yaml_params: "{{ clouds_yaml_file.content | b64decode | from_yaml }}" | ||
|
|
||
| - name: Build updated cloud entry with application credentials | ||
| ansible.builtin.set_fact: | ||
| updated_cloud_entry: | ||
| auth: | ||
| auth_url: "{{ clouds_yaml_params.clouds[user_cloud].auth.auth_url }}" | ||
| application_credential_id: "{{ app_cred_info.id }}" | ||
| application_credential_secret: "{{ app_cred_info.secret }}" | ||
| auth_type: v3applicationcredential | ||
| identity_api_version: "{{ clouds_yaml_params.clouds[user_cloud].identity_api_version | default('3') }}" | ||
| region_name: "{{ clouds_yaml_params.clouds[user_cloud].region_name | default(omit) }}" | ||
|
|
||
| - name: Add cacert to updated cloud entry | ||
| ansible.builtin.set_fact: | ||
| updated_cloud_entry: "{{ updated_cloud_entry | combine({'cacert': clouds_yaml_params.clouds[user_cloud].cacert}, recursive=True) }}" | ||
| when: clouds_yaml_params.clouds[user_cloud].cacert is defined | ||
|
|
||
| - name: Update clouds.yaml with application credentials | ||
| ansible.builtin.set_fact: | ||
| clouds_yaml_params: "{{ {'clouds': (clouds_yaml_params.clouds | combine({user_cloud: updated_cloud_entry}))} }}" | ||
|
|
||
| - name: Write updated clouds.yaml | ||
| ansible.builtin.copy: | ||
| content: "{{ clouds_yaml_params | to_nice_yaml(indent=4) }}" | ||
| dest: "{{ clouds_yaml_file_path }}" | ||
| mode: u=rw,g=rw,o=r | ||
|
|
||
| - name: Update clouds.yaml copy in osp_config_dir | ||
| ansible.builtin.copy: | ||
| content: "{{ clouds_yaml_params | to_nice_yaml(indent=4) }}" | ||
| dest: "{{ osp_config_dir }}/clouds.yaml" | ||
| mode: u=rw,g=rw,o=r | ||
| when: osp_config_dir is defined | ||
|
|
||
| - name: Validate application credentials work | ||
| openstack.cloud.auth: | ||
| cloud: "{{ user_cloud }}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,9 +19,13 @@ stages: | |
| - install | ||
| - post | ||
| - verification | ||
| - day2ops | ||
| - openstack_test | ||
| - lb_tests | ||
|
|
||
| day2ops_procedures: | ||
| - rotate_app_creds | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Is this the intended test flow? The Jenkins cp-migration multijob passes
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, intentional for this PR — the test flow is: install with user/password, then |
||
|
|
||
| ocp_deployment_topology: | ||
| network_type: OVNKubernetes | ||
| primary_ip_protocol: ipv4 # ipv4 or ipv6 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The delete-before-create pattern means if
openstack application credential createfails (line 11), there's no credential at all - the old one was already deleted here.The IR plugin's
update_app_creds.ymlshares this pattern, so it's consistent with the source. But worth considering a create-first approach (create with a temp name, verify, update clouds.yaml, then delete the old one) for robustness - especially since the day2opsrescueblock doesn't restore the deleted credential.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed. Implemented the create-first approach you suggested. The flow now:
If creation fails, the old credential stays intact in clouds.yaml. Also handles cleanup of stale
-newcredentials from interrupted prior runs.