1 |
|
# Copyright ETSI Contributors and Others. |
2 |
|
# All Rights Reserved. |
3 |
|
# |
4 |
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may |
5 |
|
# not use this file except in compliance with the License. You may obtain |
6 |
|
# a copy of the License at |
7 |
|
# |
8 |
|
# http://www.apache.org/licenses/LICENSE-2.0 |
9 |
|
# |
10 |
|
# Unless required by applicable law or agreed to in writing, software |
11 |
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
12 |
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
13 |
|
# License for the specific language governing permissions and limitations |
14 |
|
# under the License. |
15 |
|
|
16 |
1 |
import click |
17 |
1 |
from osmclient.cli_commands import utils |
18 |
1 |
from prettytable import PrettyTable |
19 |
1 |
import yaml |
20 |
1 |
import json |
21 |
1 |
import logging |
22 |
|
|
23 |
1 |
logger = logging.getLogger("osmclient") |
24 |
|
|
25 |
|
|
26 |
1 |
@click.command(name="k8scluster-add", short_help="adds a K8s cluster to OSM") |
27 |
1 |
@click.argument("name") |
28 |
1 |
@click.option( |
29 |
|
"--creds", prompt=True, help="credentials file, i.e. a valid `.kube/config` file" |
30 |
|
) |
31 |
1 |
@click.option("--version", prompt=True, help="Kubernetes version") |
32 |
1 |
@click.option( |
33 |
|
"--vim", prompt=True, help="VIM target, the VIM where the cluster resides" |
34 |
|
) |
35 |
1 |
@click.option( |
36 |
|
"--k8s-nets", |
37 |
|
prompt=True, |
38 |
|
help='''list of VIM networks, in JSON inline format, where the cluster is |
39 |
|
accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''', |
40 |
|
) |
41 |
1 |
@click.option( |
42 |
|
"--init-helm3/--skip-helm3", |
43 |
|
required=False, |
44 |
|
default=True, |
45 |
|
help="Initialize helm v3", |
46 |
|
) |
47 |
1 |
@click.option( |
48 |
|
"--init-jujubundle/--skip-jujubundle", |
49 |
|
required=False, |
50 |
|
default=True, |
51 |
|
help="Initialize juju-bundle", |
52 |
|
) |
53 |
1 |
@click.option("--description", default=None, help="human readable description") |
54 |
1 |
@click.option( |
55 |
|
"--namespace", |
56 |
|
default="kube-system", |
57 |
|
help="namespace to be used for its operation, defaults to `kube-system`", |
58 |
|
) |
59 |
1 |
@click.option( |
60 |
|
"--wait", |
61 |
|
required=False, |
62 |
|
default=False, |
63 |
|
is_flag=True, |
64 |
|
help="do not return the control immediately, but keep it " |
65 |
|
"until the operation is completed, or timeout", |
66 |
|
) |
67 |
1 |
@click.option( |
68 |
|
"--cni", |
69 |
|
default=None, |
70 |
|
help="list of CNI plugins, in JSON inline format, used in the cluster", |
71 |
|
) |
72 |
|
# @click.option('--skip-init', |
73 |
|
# is_flag=True, |
74 |
|
# help='If set, K8s cluster is assumed to be ready for its use with OSM') |
75 |
1 |
@click.pass_context |
76 |
1 |
def k8scluster_add( |
77 |
|
ctx, |
78 |
|
name, |
79 |
|
creds, |
80 |
|
version, |
81 |
|
vim, |
82 |
|
k8s_nets, |
83 |
|
init_helm3, |
84 |
|
init_jujubundle, |
85 |
|
description, |
86 |
|
namespace, |
87 |
|
wait, |
88 |
|
cni, |
89 |
|
): |
90 |
|
"""adds a K8s cluster to OSM |
91 |
|
|
92 |
|
NAME: name of the K8s cluster |
93 |
|
""" |
94 |
0 |
utils.check_client_version(ctx.obj, ctx.command.name) |
95 |
0 |
cluster = {} |
96 |
0 |
cluster["name"] = name |
97 |
0 |
with open(creds, "r") as cf: |
98 |
0 |
cluster["credentials"] = yaml.safe_load(cf.read()) |
99 |
0 |
cluster["k8s_version"] = version |
100 |
0 |
cluster["vim_account"] = vim |
101 |
0 |
cluster["nets"] = yaml.safe_load(k8s_nets) |
102 |
0 |
if not (init_jujubundle and init_helm3): |
103 |
0 |
cluster["deployment_methods"] = { |
104 |
|
"juju-bundle": init_jujubundle, |
105 |
|
"helm-chart-v3": init_helm3, |
106 |
|
} |
107 |
0 |
if description: |
108 |
0 |
cluster["description"] = description |
109 |
0 |
if namespace: |
110 |
0 |
cluster["namespace"] = namespace |
111 |
0 |
if cni: |
112 |
0 |
cluster["cni"] = yaml.safe_load(cni) |
113 |
0 |
ctx.obj.k8scluster.create(name, cluster, wait) |
114 |
|
|
115 |
|
|
116 |
1 |
@click.command(name="k8scluster-update", short_help="updates a K8s cluster") |
117 |
1 |
@click.argument("name") |
118 |
1 |
@click.option("--newname", help="New name for the K8s cluster") |
119 |
1 |
@click.option("--creds", help="credentials file, i.e. a valid `.kube/config` file") |
120 |
1 |
@click.option("--version", help="Kubernetes version") |
121 |
1 |
@click.option("--vim", help="VIM target, the VIM where the cluster resides") |
122 |
1 |
@click.option( |
123 |
|
"--k8s-nets", |
124 |
|
help='''list of VIM networks, in JSON inline format, where the cluster is accessible |
125 |
|
via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''', |
126 |
|
) |
127 |
1 |
@click.option("--description", help="human readable description") |
128 |
1 |
@click.option( |
129 |
|
"--namespace", |
130 |
|
help="namespace to be used for its operation, defaults to `kube-system`", |
131 |
|
) |
132 |
1 |
@click.option( |
133 |
|
"--wait", |
134 |
|
required=False, |
135 |
|
default=False, |
136 |
|
is_flag=True, |
137 |
|
help="do not return the control immediately, but keep it " |
138 |
|
"until the operation is completed, or timeout", |
139 |
|
) |
140 |
1 |
@click.option( |
141 |
|
"--cni", help="list of CNI plugins, in JSON inline format, used in the cluster" |
142 |
|
) |
143 |
1 |
@click.pass_context |
144 |
1 |
def k8scluster_update( |
145 |
|
ctx, name, newname, creds, version, vim, k8s_nets, description, namespace, wait, cni |
146 |
|
): |
147 |
|
"""updates a K8s cluster |
148 |
|
|
149 |
|
NAME: name or ID of the K8s cluster |
150 |
|
""" |
151 |
0 |
utils.check_client_version(ctx.obj, ctx.command.name) |
152 |
0 |
cluster = {} |
153 |
0 |
if newname: |
154 |
0 |
cluster["name"] = newname |
155 |
0 |
if creds: |
156 |
0 |
with open(creds, "r") as cf: |
157 |
0 |
cluster["credentials"] = yaml.safe_load(cf.read()) |
158 |
0 |
if version: |
159 |
0 |
cluster["k8s_version"] = version |
160 |
0 |
if vim: |
161 |
0 |
cluster["vim_account"] = vim |
162 |
0 |
if k8s_nets: |
163 |
0 |
cluster["nets"] = yaml.safe_load(k8s_nets) |
164 |
0 |
if description: |
165 |
0 |
cluster["description"] = description |
166 |
0 |
if namespace: |
167 |
0 |
cluster["namespace"] = namespace |
168 |
0 |
if cni: |
169 |
0 |
cluster["cni"] = yaml.safe_load(cni) |
170 |
0 |
ctx.obj.k8scluster.update(name, cluster, wait) |
171 |
|
|
172 |
|
|
173 |
1 |
@click.command(name="k8scluster-delete", short_help="deletes a K8s cluster") |
174 |
1 |
@click.argument("name") |
175 |
1 |
@click.option( |
176 |
|
"--force", is_flag=True, help="forces the deletion from the DB (not recommended)" |
177 |
|
) |
178 |
1 |
@click.option( |
179 |
|
"--wait", |
180 |
|
required=False, |
181 |
|
default=False, |
182 |
|
is_flag=True, |
183 |
|
help="do not return the control immediately, but keep it " |
184 |
|
"until the operation is completed, or timeout", |
185 |
|
) |
186 |
1 |
@click.pass_context |
187 |
1 |
def k8scluster_delete(ctx, name, force, wait): |
188 |
|
"""deletes a K8s cluster |
189 |
|
|
190 |
|
NAME: name or ID of the K8s cluster to be deleted |
191 |
|
""" |
192 |
0 |
utils.check_client_version(ctx.obj, ctx.command.name) |
193 |
0 |
ctx.obj.k8scluster.delete(name, force, wait) |
194 |
|
|
195 |
|
|
196 |
1 |
@click.command(name="k8scluster-list") |
197 |
1 |
@click.option( |
198 |
|
"--filter", |
199 |
|
default=None, |
200 |
|
multiple=True, |
201 |
|
help="restricts the list to the K8s clusters matching the filter", |
202 |
|
) |
203 |
1 |
@click.option("--literal", is_flag=True, help="print literally, no pretty table") |
204 |
1 |
@click.option("--long", is_flag=True, help="get more details") |
205 |
1 |
@click.pass_context |
206 |
1 |
def k8scluster_list(ctx, filter, literal, long): |
207 |
|
"""list all K8s clusters""" |
208 |
0 |
utils.check_client_version(ctx.obj, ctx.command.name) |
209 |
0 |
if filter: |
210 |
0 |
filter = "&".join(filter) |
211 |
0 |
resp = ctx.obj.k8scluster.list(filter) |
212 |
0 |
if literal: |
213 |
0 |
print(yaml.safe_dump(resp, indent=4, default_flow_style=False)) |
214 |
0 |
return |
215 |
0 |
if long: |
216 |
0 |
table = PrettyTable( |
217 |
|
[ |
218 |
|
"Name", |
219 |
|
"Id", |
220 |
|
"Project", |
221 |
|
"Version", |
222 |
|
"VIM", |
223 |
|
"K8s-nets", |
224 |
|
"Deployment methods", |
225 |
|
"Operational State", |
226 |
|
"Op. state (details)", |
227 |
|
"Description", |
228 |
|
"Detailed status", |
229 |
|
] |
230 |
|
) |
231 |
0 |
project_list = ctx.obj.project.list() |
232 |
|
else: |
233 |
0 |
table = PrettyTable( |
234 |
|
["Name", "Id", "VIM", "Operational State", "Op. state details"] |
235 |
|
) |
236 |
0 |
try: |
237 |
0 |
vim_list = ctx.obj.vim.list() |
238 |
0 |
except Exception: |
239 |
0 |
vim_list = [] |
240 |
0 |
for cluster in resp: |
241 |
0 |
logger.debug("Cluster details: {}".format(yaml.safe_dump(cluster))) |
242 |
0 |
vim_name = utils.get_vim_name(vim_list, cluster["vim_account"]) |
243 |
|
# vim_info = '{} ({})'.format(vim_name,cluster['vim_account']) |
244 |
0 |
vim_info = vim_name |
245 |
0 |
op_state_details = "Helm: {}\nJuju: {}".format( |
246 |
|
cluster["_admin"].get("helm-chart", {}).get("operationalState", "-"), |
247 |
|
cluster["_admin"].get("juju-bundle", {}).get("operationalState", "-"), |
248 |
|
) |
249 |
0 |
if long: |
250 |
0 |
project_id, project_name = utils.get_project(project_list, cluster) |
251 |
|
# project_info = '{} ({})'.format(project_name, project_id) |
252 |
0 |
project_info = project_name |
253 |
0 |
detailed_status = cluster["_admin"].get("detailed-status", "-") |
254 |
0 |
table.add_row( |
255 |
|
[ |
256 |
|
cluster["name"], |
257 |
|
cluster["_id"], |
258 |
|
project_info, |
259 |
|
cluster["k8s_version"], |
260 |
|
vim_info, |
261 |
|
json.dumps(cluster["nets"]), |
262 |
|
json.dumps(cluster["deployment_methods"]), |
263 |
|
cluster["_admin"]["operationalState"], |
264 |
|
op_state_details, |
265 |
|
utils.trunc_text(cluster.get("description") or "", 40), |
266 |
|
utils.wrap_text(text=detailed_status, width=40), |
267 |
|
] |
268 |
|
) |
269 |
|
else: |
270 |
0 |
table.add_row( |
271 |
|
[ |
272 |
|
cluster["name"], |
273 |
|
cluster["_id"], |
274 |
|
vim_info, |
275 |
|
cluster["_admin"]["operationalState"], |
276 |
|
op_state_details, |
277 |
|
] |
278 |
|
) |
279 |
0 |
table.align = "l" |
280 |
0 |
print(table) |
281 |
|
|
282 |
|
|
283 |
1 |
@click.command(name="k8scluster-show", short_help="shows the details of a K8s cluster") |
284 |
1 |
@click.argument("name") |
285 |
1 |
@click.option("--literal", is_flag=True, help="print literally, no pretty table") |
286 |
1 |
@click.pass_context |
287 |
1 |
def k8scluster_show(ctx, name, literal): |
288 |
|
"""shows the details of a K8s cluster |
289 |
|
|
290 |
|
NAME: name or ID of the K8s cluster |
291 |
|
""" |
292 |
0 |
resp = ctx.obj.k8scluster.get(name) |
293 |
0 |
if literal: |
294 |
0 |
print(yaml.safe_dump(resp, indent=4, default_flow_style=False)) |
295 |
0 |
return |
296 |
0 |
table = PrettyTable(["key", "attribute"]) |
297 |
0 |
for k, v in list(resp.items()): |
298 |
0 |
table.add_row([k, utils.wrap_text(text=json.dumps(v, indent=2), width=100)]) |
299 |
0 |
table.align = "l" |
300 |
0 |
print(table) |