Skip to content

Commit 346e120

Browse files
committed
sketch out further
Signed-off-by: Matthias Büchse <[email protected]>
1 parent 1b8d6a0 commit 346e120

File tree

1 file changed

+59
-17
lines changed

1 file changed

+59
-17
lines changed

Tests/kaas/plugin/plugin_clusterstacks.py

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,41 @@
44
import os.path
55
from pathlib import Path
66

7-
from interface import KubernetesClusterPlugin
87
from jinja2 import Environment
98
import kubernetes
9+
from kubernetes.client.exceptions import ApiException
1010
import yaml
1111

12+
from interface import KubernetesClusterPlugin
13+
1214
logger = logging.getLogger(__name__)
1315

1416

1517
TEMPLATE_KEYS = ('cluster', 'clusterstack', 'kubeconfig')
1618

1719

20+
def _setup_client_config(client_config, kubeconfig, cwd='.'):
21+
"""transfer authentication data from kubeconfig to client_config, creating file `ca.crt`s"""
22+
token = kubeconfig['users'][0]['user']['token']
23+
client_config.api_key['authorization'] = 'Bearer {}'.format(token)
24+
client_config.host = kubeconfig['clusters'][0]['cluster']['server']
25+
client_config.ssl_ca_cert = os.path.abspath(os.path.join(cwd, 'ca.crt'))
26+
with open(client_config.ssl_ca_cert, "wb") as fileobj:
27+
fileobj.write(base64.standard_b64decode(
28+
kubeconfig['clusters'][0]['cluster']['certificate-authority-data'].encode()
29+
))
30+
31+
32+
def _kubectl_apply_cr(api_client, namespace, resource_dict):
33+
"""mimic `kubectl apply` with a custom resource"""
34+
api_instance = kubernetes.client.CustomObjectsApi(api_client)
35+
group, ver = resource_dict['apiVersion'].split('/', 1)
36+
plural = resource_dict['kind'].lower() + 's'
37+
return api_instance.create_namespaced_custom_object(
38+
group, ver, namespace, plural, resource_dict, field_manager='plugin_clusterstacks',
39+
)
40+
41+
1842
def load_templates(env, basepath, fn_map, keys=TEMPLATE_KEYS):
1943
new_map = {}
2044
for key in keys:
@@ -45,19 +69,14 @@ def __init__(self, config, basepath='.', cwd='.'):
4569
self.vars = self.config['vars']
4670
self.vars['name'] = self.config['name']
4771
self.secrets = self.config['secrets']
48-
self.kubeconfig = yaml.load(
49-
self.template_map['kubeconfig'].render(**self.vars, **self.secrets),
50-
Loader=yaml.SafeLoader,
51-
)
72+
self.kubeconfig = yaml.load(self._render_template('kubeconfig'), Loader=yaml.SafeLoader)
5273
self.client_config = kubernetes.client.Configuration()
53-
token = self.kubeconfig['users'][0]['user']['token']
54-
self.client_config.api_key['authorization'] = 'Bearer {}'.format(token)
55-
self.client_config.host = self.kubeconfig['clusters'][0]['cluster']['server']
56-
self.client_config.ssl_ca_cert = os.path.abspath(os.path.join(self.cwd, 'ca.crt'))
57-
with open(self.client_config.ssl_ca_cert, "wb") as fileobj:
58-
fileobj.write(base64.standard_b64decode(self.kubeconfig['clusters'][0]['cluster']['certificate-authority-data'].encode()))
74+
_setup_client_config(self.client_config, self.kubeconfig, cwd=self.cwd)
5975
self.namespace = self.kubeconfig['contexts'][0]['context']['namespace']
6076

77+
def _render_template(self, key):
78+
return self.template_map[key].render(**self.vars, **self.secrets)
79+
6180
def auto_vars_syself(self, api_client):
6281
# beware: the following is quite the incantation
6382
prefix = f"v{self.config['kubernetesVersion']}"
@@ -82,15 +101,38 @@ def create_cluster(self):
82101
with kubernetes.client.ApiClient(self.client_config) as api_client:
83102
if self.config.get('autoVars') == 'syself':
84103
self.auto_vars_syself(api_client)
85-
# write out cluster.yaml for purposes of documentation; we won't use kubectl apply -f
86-
cluster_yaml = self.template_map['cluster'].render(**self.vars)
104+
# write out cluster.yaml for purposes of documentation
105+
# we will however use the dict instead of calling the shell with `kubectl apply -f`
106+
cluster_yaml = self._render_template('cluster')
87107
cluster_dict = yaml.load(cluster_yaml, Loader=yaml.SafeLoader)
88108
with open(os.path.join(self.cwd, 'cluster.yaml'), "w") as fileobj:
89109
fileobj.write(cluster_yaml)
90-
# kubernetes.utils.create_from_dict(api_client, cluster_dict)
91-
api_instance = kubernetes.client.CustomObjectsApi(api_client)
92-
# mimic `kubectl apply -f` (it's a bit more involved with the API)
93-
res = api_instance.create_namespaced_custom_object('cluster.x-k8s.io', 'v1beta1', self.namespace, 'clusters', cluster_dict, field_manager='plugin_clusterstacks')
110+
try:
111+
_kubectl_apply_cr(api_client, self.namespace, cluster_dict)
112+
except ApiException as e:
113+
# 409 means that the object already exists; don't treat that as error
114+
if e.status != 409:
115+
raise
116+
name = self.config['name']
117+
secret_name = f'{name}-kubeconfig'
118+
api_instance = kubernetes.client.CustomObjectsApi(api_client)
119+
while True:
120+
# mimic `kubectl get machines` (it's a bit more involved with the API)
121+
res = api_instance.list_namespaced_custom_object('cluster.x-k8s.io', 'v1beta1', self.namespace, 'machines')
122+
items = [
123+
(item['metadata']['name'], item['status']['phase'].lower())
124+
for item in res['items']
125+
if item['spec']['clusterName'] == name
126+
]
127+
working = [item[0] for item in items if item[1] != 'provisioned']
128+
if not working:
129+
break
130+
logger.debug('waiting 30 s for machines to become ready:', items)
131+
time.sleep(30)
132+
# mimic `kubectl get secrets NAME -o=jsonpath='{.data.value}' | base64 -d > kubeconfig.yaml`
133+
res = kubernetes.client.CoreV1Api(api_client).read_namespaced_secret(secret_name, self.namespace)
134+
with open(os.path.join(self.cwd, 'kubeconfig.yaml'), 'wb') as fileobj:
135+
fileobj.write(base64.standard_b64decode(res.data['value'].encode()))
94136

95137
def delete_cluster(self):
96138
cluster_name = self.config['name']

0 commit comments

Comments
 (0)