Skip to content

Commit 35985b8

Browse files
Use curl + kubeconfig certs for pull secret and bootstrap oc from mirror to eliminate file-cache dependency
1 parent 7756aed commit 35985b8

1 file changed

Lines changed: 82 additions & 44 deletions

File tree

collection/tools/roles/tools_get_openshift_release/tasks/get_openshift_release_binaries.yml

Lines changed: 82 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,18 @@
33
# using `oc adm release extract --tools` instead of the release-controller's
44
# file-cache (openshift-release-artifacts), which has no SLA and can get stuck
55
# indefinitely during tool extraction.
6+
#
7+
# Since the shiftstackclient pod starts with no `oc` binary, we bootstrap one
8+
# from mirror.openshift.com, extract the pull secret from the host cluster via
9+
# the Kubernetes API (using the kubeconfig's client certificate), then use
10+
# `oc adm release extract --tools` to get the version-matched binaries.
611
- name: Get the OCP installer and/or client binaries
712
vars:
813
installer_tarball: "openshift-install-linux-{{ release_name }}.tar.gz"
914
client_tarball: "openshift-client-linux-{{ release_name }}.tar.gz"
1015
pull_secret_file: "{{ home_dir }}/pull-secret.json"
16+
bootstrap_oc_dir: "{{ home_dir }}/bootstrap-oc"
17+
bootstrap_oc_url: "{{ openshift_mirror_url }}/stable/openshift-client-linux.tar.gz"
1118
block:
1219
- name: Fail if release_name var is not defined
1320
ansible.builtin.fail:
@@ -19,56 +26,82 @@
1926
msg: "'openshift_release_pull_spec' must be set by get_openshift_release_build_name.yml"
2027
when: openshift_release_pull_spec is not defined or openshift_release_pull_spec == ''
2128

22-
- name: Check if rhoso_kubeconfig file exists
23-
ansible.builtin.stat:
24-
path: "{{ rhoso_kubeconfig }}"
25-
register: _rhoso_kubeconfig_stat
29+
- name: Extract pull secret from host cluster via Kubernetes API
30+
ansible.builtin.script:
31+
cmd: python3 -
32+
stdin: |
33+
import yaml, json, base64, subprocess, os, sys
2634
27-
- name: Debug kubeconfig and environment info
28-
ansible.builtin.debug:
29-
msg: |
30-
rhoso_kubeconfig path: {{ rhoso_kubeconfig }}
31-
rhoso_kubeconfig exists: {{ _rhoso_kubeconfig_stat.stat.exists }}
32-
home_dir: {{ home_dir }}
33-
KUBECONFIG env: {{ lookup('ansible.builtin.env', 'KUBECONFIG', default='(not set)') }}
35+
kubeconfig_path = "{{ rhoso_kubeconfig }}"
36+
output_path = "{{ pull_secret_file }}"
3437
35-
- name: Extract pull secret using rhoso_kubeconfig
36-
ansible.builtin.shell: >-
37-
set -o pipefail &&
38-
oc get secret pull-secret -n openshift-config
39-
--kubeconfig={{ rhoso_kubeconfig }}
40-
-o jsonpath='{.data.\.dockerconfigjson}'
41-
| base64 -d > {{ pull_secret_file }}
42-
register: _pull_secret_rhoso
43-
ignore_errors: true
44-
no_log: true
45-
when: _rhoso_kubeconfig_stat.stat.exists
38+
with open(kubeconfig_path) as f:
39+
kc = yaml.safe_load(f)
4640
47-
- name: Extract pull secret using default kubeconfig (fallback)
48-
ansible.builtin.shell: >-
49-
set -o pipefail &&
50-
oc get secret pull-secret -n openshift-config
51-
-o jsonpath='{.data.\.dockerconfigjson}'
52-
| base64 -d > {{ pull_secret_file }}
53-
register: _pull_secret_default
54-
ignore_errors: true
41+
server = kc['clusters'][0]['cluster']['server']
42+
user = kc['users'][0]['user']
43+
44+
ca_path = '/tmp/k8s-ca.crt'
45+
cert_path = '/tmp/k8s-client.crt'
46+
key_path = '/tmp/k8s-client.key'
47+
48+
with open(ca_path, 'wb') as f:
49+
f.write(base64.b64decode(kc['clusters'][0]['cluster']['certificate-authority-data']))
50+
with open(cert_path, 'wb') as f:
51+
f.write(base64.b64decode(user['client-certificate-data']))
52+
with open(key_path, 'wb') as f:
53+
f.write(base64.b64decode(user['client-key-data']))
54+
55+
result = subprocess.run([
56+
'curl', '-s', '--fail',
57+
'--cacert', ca_path,
58+
'--cert', cert_path,
59+
'--key', key_path,
60+
f'{server}/api/v1/namespaces/openshift-config/secrets/pull-secret'
61+
], capture_output=True, text=True)
62+
63+
for f in [ca_path, cert_path, key_path]:
64+
os.remove(f)
65+
66+
if result.returncode != 0:
67+
print(f"Failed to fetch pull secret from {server}: {result.stderr}", file=sys.stderr)
68+
sys.exit(1)
69+
70+
data = json.loads(result.stdout)
71+
decoded = base64.b64decode(data['data']['.dockerconfigjson']).decode()
72+
auths = json.loads(decoded)
73+
74+
with open(output_path, 'w') as f:
75+
f.write(decoded)
76+
77+
print(f"Pull secret extracted: {len(auths.get('auths', {}))} registries")
78+
register: _pull_secret_result
5579
no_log: true
56-
when: _rhoso_kubeconfig_stat.stat.exists == false or _pull_secret_rhoso is failed
5780

58-
- name: Verify pull secret file was created and is valid JSON
59-
ansible.builtin.shell: python3 -c "import json; d=json.load(open('{{ pull_secret_file }}')); print(len(d.get('auths',{})), 'registries found')"
81+
- name: Verify pull secret file is valid
82+
ansible.builtin.shell: >-
83+
python3 -c "import json; d=json.load(open('{{ pull_secret_file }}'));
84+
print(len(d.get('auths',{})), 'registries found')"
6085
register: _pull_secret_verify
61-
ignore_errors: true
86+
changed_when: false
6287

63-
- name: Fail with diagnostic info if pull secret extraction failed
64-
ansible.builtin.fail:
65-
msg: |
66-
Failed to extract pull secret from host cluster.
67-
rhoso_kubeconfig exists: {{ _rhoso_kubeconfig_stat.stat.exists }}
68-
rhoso_kubeconfig result: {{ 'skipped' if _pull_secret_rhoso is skipped else ('ok' if _pull_secret_rhoso is success else 'FAILED rc=' + (_pull_secret_rhoso.rc | default('?') | string)) }}
69-
default kubeconfig result: {{ 'skipped' if _pull_secret_default is skipped else ('ok' if _pull_secret_default is success else 'FAILED rc=' + (_pull_secret_default.rc | default('?') | string)) }}
70-
pull secret validation: {{ _pull_secret_verify.stdout | default('FAILED - ' + _pull_secret_verify.stderr | default('unknown error')) }}
71-
when: _pull_secret_verify is failed
88+
- name: Bootstrap oc client from {{ bootstrap_oc_url }}
89+
block:
90+
- name: Create bootstrap directory
91+
ansible.builtin.file:
92+
path: "{{ bootstrap_oc_dir }}"
93+
state: directory
94+
mode: u=rwx,g=rw,o=r
95+
96+
- name: Download stable oc client from mirror
97+
ansible.builtin.unarchive:
98+
src: "{{ bootstrap_oc_url }}"
99+
dest: "{{ bootstrap_oc_dir }}"
100+
remote_src: yes
101+
register: _bootstrap_download
102+
until: _bootstrap_download is not failed
103+
retries: 3
104+
delay: 10
72105

73106
- name: Create the installer directory
74107
ansible.builtin.file:
@@ -79,7 +112,7 @@
79112
- name: Extract OCP tools from release image {{ openshift_release_pull_spec }}
80113
ansible.builtin.command:
81114
cmd: >-
82-
oc adm release extract
115+
{{ bootstrap_oc_dir }}/oc adm release extract
83116
--tools
84117
--registry-config={{ pull_secret_file }}
85118
--to={{ home_dir }}/{{ release_name }}
@@ -133,3 +166,8 @@
133166
ansible.builtin.file:
134167
path: "{{ pull_secret_file }}"
135168
state: absent
169+
170+
- name: Remove bootstrap oc directory
171+
ansible.builtin.file:
172+
path: "{{ bootstrap_oc_dir }}"
173+
state: absent

0 commit comments

Comments
 (0)