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.common.exceptions import ClientException |
18 |
1 |
from osmclient.cli_commands import utils |
19 |
1 |
from prettytable import PrettyTable |
20 |
1 |
import yaml |
21 |
1 |
import json |
22 |
1 |
import os |
23 |
1 |
from typing import Any, Dict |
24 |
1 |
import logging |
25 |
|
|
26 |
1 |
logger = logging.getLogger("osmclient") |
27 |
|
|
28 |
|
|
29 |
1 |
@click.command(name="vca-add", short_help="adds a VCA (Juju controller) to OSM") |
30 |
1 |
@click.argument("name") |
31 |
1 |
@click.option( |
32 |
|
"--endpoints", |
33 |
|
prompt=True, |
34 |
|
help="Comma-separated list of IP or hostnames of the Juju controller", |
35 |
|
) |
36 |
1 |
@click.option("--user", prompt=True, help="Username with admin priviledges") |
37 |
1 |
@click.option("--secret", prompt=True, help="Password of the specified username") |
38 |
1 |
@click.option("--cacert", prompt=True, help="CA certificate") |
39 |
1 |
@click.option( |
40 |
|
"--lxd-cloud", |
41 |
|
prompt=True, |
42 |
|
help="Name of the cloud that will be used for LXD containers (LXD proxy charms)", |
43 |
|
) |
44 |
1 |
@click.option( |
45 |
|
"--lxd-credentials", |
46 |
|
prompt=True, |
47 |
|
help="Name of the cloud credentialsto be used for the LXD cloud", |
48 |
|
) |
49 |
1 |
@click.option( |
50 |
|
"--k8s-cloud", |
51 |
|
prompt=True, |
52 |
|
help="Name of the cloud that will be used for K8s containers (K8s proxy charms)", |
53 |
|
) |
54 |
1 |
@click.option( |
55 |
|
"--k8s-credentials", |
56 |
|
prompt=True, |
57 |
|
help="Name of the cloud credentialsto be used for the K8s cloud", |
58 |
|
) |
59 |
1 |
@click.option( |
60 |
|
"--model-config", |
61 |
|
default={}, |
62 |
|
help="Configuration options for the models", |
63 |
|
) |
64 |
1 |
@click.option("--description", default=None, help="human readable description") |
65 |
1 |
@click.pass_context |
66 |
1 |
def vca_add( |
67 |
|
ctx, |
68 |
|
name, |
69 |
|
endpoints, |
70 |
|
user, |
71 |
|
secret, |
72 |
|
cacert, |
73 |
|
lxd_cloud, |
74 |
|
lxd_credentials, |
75 |
|
k8s_cloud, |
76 |
|
k8s_credentials, |
77 |
|
model_config, |
78 |
|
description, |
79 |
|
): |
80 |
|
"""adds a VCA to OSM |
81 |
|
|
82 |
|
NAME: name of the VCA |
83 |
|
""" |
84 |
1 |
logger.debug("") |
85 |
1 |
utils.check_client_version(ctx.obj, ctx.command.name) |
86 |
1 |
vca = {} |
87 |
1 |
vca["name"] = name |
88 |
1 |
vca["endpoints"] = endpoints.split(",") |
89 |
1 |
vca["user"] = user |
90 |
1 |
vca["secret"] = secret |
91 |
1 |
vca["cacert"] = cacert |
92 |
1 |
vca["lxd-cloud"] = lxd_cloud |
93 |
1 |
vca["lxd-credentials"] = lxd_credentials |
94 |
1 |
vca["k8s-cloud"] = k8s_cloud |
95 |
1 |
vca["k8s-credentials"] = k8s_credentials |
96 |
1 |
if description: |
97 |
1 |
vca["description"] = description |
98 |
1 |
if model_config: |
99 |
1 |
model_config = load(model_config) |
100 |
1 |
vca["model-config"] = model_config |
101 |
1 |
ctx.obj.vca.create(name, vca) |
102 |
|
|
103 |
|
|
104 |
1 |
def load(data: Any): |
105 |
1 |
logger.debug("") |
106 |
1 |
if os.path.isfile(data): |
107 |
0 |
return load_file(data) |
108 |
|
else: |
109 |
1 |
try: |
110 |
1 |
return json.loads(data) |
111 |
0 |
except ValueError as e: |
112 |
0 |
raise ClientException(e) |
113 |
|
|
114 |
|
|
115 |
1 |
def load_file(file_path: str) -> Dict: |
116 |
0 |
logger.debug("") |
117 |
0 |
content = None |
118 |
0 |
with open(file_path, "r") as f: |
119 |
0 |
content = f.read() |
120 |
0 |
try: |
121 |
0 |
return yaml.safe_load(content) |
122 |
0 |
except yaml.scanner.ScannerError: |
123 |
0 |
pass |
124 |
0 |
try: |
125 |
0 |
return json.loads(content) |
126 |
0 |
except ValueError: |
127 |
0 |
pass |
128 |
0 |
raise ClientException(f"{file_path} must be a valid yaml or json file") |
129 |
|
|
130 |
|
|
131 |
1 |
@click.command(name="vca-update", short_help="updates a VCA") |
132 |
1 |
@click.argument("name") |
133 |
1 |
@click.option( |
134 |
|
"--endpoints", help="Comma-separated list of IP or hostnames of the Juju controller" |
135 |
|
) |
136 |
1 |
@click.option("--user", help="Username with admin priviledges") |
137 |
1 |
@click.option("--secret", help="Password of the specified username") |
138 |
1 |
@click.option("--cacert", help="CA certificate") |
139 |
1 |
@click.option( |
140 |
|
"--lxd-cloud", |
141 |
|
help="Name of the cloud that will be used for LXD containers (LXD proxy charms)", |
142 |
|
) |
143 |
1 |
@click.option( |
144 |
|
"--lxd-credentials", |
145 |
|
help="Name of the cloud credentialsto be used for the LXD cloud", |
146 |
|
) |
147 |
1 |
@click.option( |
148 |
|
"--k8s-cloud", |
149 |
|
help="Name of the cloud that will be used for K8s containers (K8s proxy charms)", |
150 |
|
) |
151 |
1 |
@click.option( |
152 |
|
"--k8s-credentials", |
153 |
|
help="Name of the cloud credentialsto be used for the K8s cloud", |
154 |
|
) |
155 |
1 |
@click.option( |
156 |
|
"--model-config", |
157 |
|
help="Configuration options for the models", |
158 |
|
) |
159 |
1 |
@click.option("--description", default=None, help="human readable description") |
160 |
1 |
@click.pass_context |
161 |
1 |
def vca_update( |
162 |
|
ctx, |
163 |
|
name, |
164 |
|
endpoints, |
165 |
|
user, |
166 |
|
secret, |
167 |
|
cacert, |
168 |
|
lxd_cloud, |
169 |
|
lxd_credentials, |
170 |
|
k8s_cloud, |
171 |
|
k8s_credentials, |
172 |
|
model_config, |
173 |
|
description, |
174 |
|
): |
175 |
|
"""updates a VCA |
176 |
|
|
177 |
|
NAME: name or ID of the VCA |
178 |
|
""" |
179 |
1 |
logger.debug("") |
180 |
1 |
utils.check_client_version(ctx.obj, ctx.command.name) |
181 |
1 |
vca = {} |
182 |
1 |
vca["name"] = name |
183 |
1 |
if endpoints: |
184 |
1 |
vca["endpoints"] = endpoints.split(",") |
185 |
1 |
if user: |
186 |
1 |
vca["user"] = user |
187 |
1 |
if secret: |
188 |
1 |
vca["secret"] = secret |
189 |
1 |
if cacert: |
190 |
1 |
vca["cacert"] = cacert |
191 |
1 |
if lxd_cloud: |
192 |
1 |
vca["lxd-cloud"] = lxd_cloud |
193 |
1 |
if lxd_credentials: |
194 |
1 |
vca["lxd-credentials"] = lxd_credentials |
195 |
1 |
if k8s_cloud: |
196 |
1 |
vca["k8s-cloud"] = k8s_cloud |
197 |
1 |
if k8s_credentials: |
198 |
1 |
vca["k8s-credentials"] = k8s_credentials |
199 |
1 |
if description: |
200 |
1 |
vca["description"] = description |
201 |
1 |
if model_config: |
202 |
1 |
model_config = load(model_config) |
203 |
1 |
vca["model-config"] = model_config |
204 |
1 |
ctx.obj.vca.update(name, vca) |
205 |
|
|
206 |
|
|
207 |
1 |
@click.command(name="vca-delete", short_help="deletes a VCA") |
208 |
1 |
@click.argument("name") |
209 |
1 |
@click.option( |
210 |
|
"--force", is_flag=True, help="forces the deletion from the DB (not recommended)" |
211 |
|
) |
212 |
1 |
@click.pass_context |
213 |
1 |
def vca_delete(ctx, name, force): |
214 |
|
"""deletes a VCA |
215 |
|
|
216 |
|
NAME: name or ID of the VCA to be deleted |
217 |
|
""" |
218 |
1 |
logger.debug("") |
219 |
1 |
utils.check_client_version(ctx.obj, ctx.command.name) |
220 |
1 |
ctx.obj.vca.delete(name, force=force) |
221 |
|
|
222 |
|
|
223 |
1 |
@click.command(name="vca-list") |
224 |
1 |
@click.option( |
225 |
|
"--filter", |
226 |
|
default=None, |
227 |
|
multiple=True, |
228 |
|
help="restricts the list to the VCAs matching the filter", |
229 |
|
) |
230 |
1 |
@click.option("--literal", is_flag=True, help="print literally, no pretty table") |
231 |
1 |
@click.option("--long", is_flag=True, help="get more details") |
232 |
1 |
@click.pass_context |
233 |
1 |
def vca_list(ctx, filter, literal, long): |
234 |
|
"""list VCAs""" |
235 |
1 |
logger.debug("") |
236 |
1 |
utils.check_client_version(ctx.obj, ctx.command.name) |
237 |
1 |
if filter: |
238 |
1 |
filter = "&".join(filter) |
239 |
1 |
resp = ctx.obj.vca.list(filter) |
240 |
1 |
if literal: |
241 |
1 |
print(yaml.safe_dump(resp, indent=4, default_flow_style=False)) |
242 |
1 |
return |
243 |
1 |
if long: |
244 |
1 |
table = PrettyTable( |
245 |
|
["Name", "Id", "Project", "Operational State", "Detailed Status"] |
246 |
|
) |
247 |
1 |
project_list = ctx.obj.project.list() |
248 |
|
else: |
249 |
1 |
table = PrettyTable(["Name", "Id", "Operational State"]) |
250 |
1 |
for vca in resp: |
251 |
1 |
logger.debug("VCA details: {}".format(yaml.safe_dump(vca))) |
252 |
1 |
if long: |
253 |
1 |
project_id, project_name = utils.get_project(project_list, vca) |
254 |
1 |
detailed_status = vca.get("_admin", {}).get("detailed-status", "-") |
255 |
1 |
table.add_row( |
256 |
|
[ |
257 |
|
vca["name"], |
258 |
|
vca["_id"], |
259 |
|
project_name, |
260 |
|
vca.get("_admin", {}).get("operationalState", "-"), |
261 |
|
utils.wrap_text(text=detailed_status, width=40), |
262 |
|
] |
263 |
|
) |
264 |
|
else: |
265 |
1 |
table.add_row( |
266 |
|
[ |
267 |
|
vca["name"], |
268 |
|
vca["_id"], |
269 |
|
vca.get("_admin", {}).get("operationalState", "-"), |
270 |
|
] |
271 |
|
) |
272 |
1 |
table.align = "l" |
273 |
1 |
print(table) |
274 |
|
|
275 |
|
|
276 |
1 |
@click.command(name="vca-show", short_help="shows the details of a VCA") |
277 |
1 |
@click.argument("name") |
278 |
1 |
@click.option("--literal", is_flag=True, help="print literally, no pretty table") |
279 |
1 |
@click.pass_context |
280 |
1 |
def vca_show(ctx, name, literal): |
281 |
|
"""shows the details of a VCA |
282 |
|
|
283 |
|
NAME: name or ID of the VCA |
284 |
|
""" |
285 |
1 |
logger.debug("") |
286 |
1 |
resp = ctx.obj.vca.get(name) |
287 |
1 |
if literal: |
288 |
1 |
print(yaml.safe_dump(resp, indent=4, default_flow_style=False)) |
289 |
1 |
return |
290 |
1 |
table = PrettyTable(["key", "attribute"]) |
291 |
1 |
for k, v in list(resp.items()): |
292 |
1 |
table.add_row([k, utils.wrap_text(text=json.dumps(v, indent=2), width=100)]) |
293 |
1 |
table.align = "l" |
294 |
1 |
print(table) |