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