Coverage for osmclient/cli_commands/repo.py: 46%

227 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2024-06-22 09:01 +0000

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 

16import click 

17from osmclient.common.exceptions import NotFound, ClientException 

18from osmclient.cli_commands import utils 

19from prettytable import PrettyTable 

20import yaml 

21import json 

22import logging 

23 

24logger = logging.getLogger("osmclient") 

25 

26 

27@click.command(name="repo-add", short_help="adds a repo to OSM") 

28@click.argument("name") 

29@click.argument("uri") 

30@click.option( 

31 "--type", 

32 type=click.Choice(["osm", "helm-chart", "juju-bundle"]), 

33 default="osm", 

34 help="type of repo (osm for OSM repositories, helm-chart for Helm Charts, juju-bundle for Juju Bundles)", 

35) 

36@click.option("--description", default=None, help="human readable description") 

37@click.option( 

38 "--user", default=None, help="OSM repository: The username of the OSM repository" 

39) 

40@click.option( 

41 "--password", 

42 default=None, 

43 help="OSM repository: The password of the OSM repository", 

44) 

45@click.option( 

46 "--oci", 

47 is_flag=True, 

48 help="enable OCI (only for helm-chart repos, default: false, automatically set to true for oci:// URI)", 

49) 

50@click.option( 

51 "--ca-file", 

52 default=None, 

53 help="cert to use when adding a repository (only for helm)", 

54) 

55@click.pass_context 

56def repo_add(ctx, **kwargs): 

57 """adds a repo to OSM 

58 

59 NAME: name of the repo 

60 URI: URI of the repo 

61 """ 

62 kwargs = {k: v for k, v in kwargs.items() if v is not None} 

63 repo = kwargs 

64 repo["url"] = repo.pop("uri") 

65 if repo["url"].startswith("oci://"): 

66 repo["oci"] = True 

67 if "ca_file" in kwargs: 

68 try: 

69 with open(kwargs["ca_file"], "r") as ca_cert: 

70 repo["cacert"] = ca_cert.read() 

71 repo.pop("ca_file") 

72 except FileNotFoundError: 

73 raise ClientException("CA file not found !") 

74 except EOFError: 

75 raise ClientException("Empty CA file !") 

76 except PermissionError: 

77 raise ClientException("Can not read CA file ! Insufficient permissions") 

78 except Exception as e: 

79 raise ClientException(f"Can not read the cert file ! Error: {e}") 

80 if repo["type"] in ["helm-chart", "juju-bundle"]: 

81 ctx.obj.repo.create(repo["name"], repo) 

82 else: 

83 ctx.obj.osmrepo.create(repo["name"], repo) 

84 

85 

86@click.command(name="repo-update", short_help="updates a repo in OSM") 

87@click.argument("name") 

88@click.option("--newname", help="New name for the repo") 

89@click.option("--uri", help="URI of the repo") 

90@click.option("--description", help="human readable description") 

91@click.option( 

92 "--oci", 

93 is_flag=True, 

94 help="enable OCI (only for helm-chart repos, default: false, automatically set to true for oci:// URI)", 

95) 

96@click.pass_context 

97def repo_update(ctx, name, newname, uri, description, oci): 

98 """updates a repo in OSM 

99 

100 NAME: name of the repo 

101 """ 

102 utils.check_client_version(ctx.obj, ctx.command.name) 

103 repo = {} 

104 if newname: 

105 repo["name"] = newname 

106 if uri: 

107 repo["url"] = uri 

108 if uri.startswith("oci://"): 

109 repo["oci"] = True 

110 if description: 

111 repo["description"] = description 

112 if oci: 

113 repo["oci"] = oci 

114 try: 

115 ctx.obj.repo.update(name, repo) 

116 except NotFound: 

117 ctx.obj.osmrepo.update(name, repo) 

118 

119 

120@click.command( 

121 name="repo-index", short_help="Index a repository from a folder with artifacts" 

122) 

123@click.option( 

124 "--origin", default=".", help="origin path where the artifacts are located" 

125) 

126@click.option( 

127 "--destination", default=".", help="destination path where the index is deployed" 

128) 

129@click.pass_context 

130def repo_index(ctx, origin, destination): 

131 """Index a repository 

132 

133 NAME: name or ID of the repo to be deleted 

134 """ 

135 utils.check_client_version(ctx.obj, ctx.command.name) 

136 ctx.obj.osmrepo.repo_index(origin, destination) 

137 

138 

139@click.command(name="repo-delete", short_help="deletes a repo") 

140@click.argument("name") 

141@click.option( 

142 "--force", is_flag=True, help="forces the deletion from the DB (not recommended)" 

143) 

144@click.pass_context 

145def repo_delete(ctx, name, force): 

146 """deletes a repo 

147 

148 NAME: name or ID of the repo to be deleted 

149 """ 

150 logger.debug("") 

151 try: 

152 ctx.obj.repo.delete(name, force=force) 

153 except NotFound: 

154 ctx.obj.osmrepo.delete(name, force=force) 

155 

156 

157@click.command(name="repo-list") 

158@click.option( 

159 "--filter", 

160 default=None, 

161 multiple=True, 

162 help="restricts the list to the repos matching the filter", 

163) 

164@click.option("--literal", is_flag=True, help="print literally, no pretty table") 

165@click.pass_context 

166def repo_list(ctx, filter, literal): 

167 """list all repos""" 

168 # K8s Repositories 

169 utils.check_client_version(ctx.obj, ctx.command.name) 

170 if filter: 

171 filter = "&".join(filter) 

172 resp = ctx.obj.repo.list(filter) 

173 resp += ctx.obj.osmrepo.list(filter) 

174 if literal: 

175 print(yaml.safe_dump(resp, indent=4, default_flow_style=False)) 

176 return 

177 table = PrettyTable(["Name", "Id", "Type", "URI", "Description"]) 

178 for repo in resp: 

179 # cluster['k8s-nets'] = json.dumps(yaml.safe_load(cluster['k8s-nets'])) 

180 table.add_row( 

181 [ 

182 repo["name"], 

183 repo["_id"], 

184 repo["type"], 

185 repo["url"], 

186 utils.trunc_text(repo.get("description") or "", 40), 

187 ] 

188 ) 

189 table.align = "l" 

190 print(table) 

191 

192 

193@click.command(name="repo-show", short_help="shows the details of a repo") 

194@click.argument("name") 

195@click.option("--literal", is_flag=True, help="print literally, no pretty table") 

196@click.pass_context 

197def repo_show(ctx, name, literal): 

198 """shows the details of a repo 

199 

200 NAME: name or ID of the repo 

201 """ 

202 try: 

203 resp = ctx.obj.repo.get(name) 

204 except NotFound: 

205 resp = ctx.obj.osmrepo.get(name) 

206 

207 if literal: 

208 if resp: 

209 print(yaml.safe_dump(resp, indent=4, default_flow_style=False)) 

210 return 

211 table = PrettyTable(["key", "attribute"]) 

212 if resp: 

213 for k, v in list(resp.items()): 

214 table.add_row([k, json.dumps(v, indent=2)]) 

215 

216 table.align = "l" 

217 print(table) 

218 

219 

220######################## 

221# Catalogue commands 

222######################## 

223 

224 

225def pkg_repo_list(ctx, pkgtype, filter, repo, long): 

226 resp = ctx.obj.osmrepo.pkg_list(pkgtype, filter, repo) 

227 if long: 

228 table = PrettyTable( 

229 ["nfpkg name", "vendor", "version", "latest", "description", "repository"] 

230 ) 

231 else: 

232 table = PrettyTable(["nfpkg name", "repository"]) 

233 for vnfd in resp: 

234 name = vnfd.get("id", vnfd.get("name", "-")) 

235 repository = vnfd.get("repository") 

236 if long: 

237 vendor = vnfd.get("provider", vnfd.get("vendor")) 

238 version = vnfd.get("version") 

239 description = vnfd.get("description") 

240 latest = vnfd.get("latest") 

241 table.add_row([name, vendor, version, latest, description, repository]) 

242 else: 

243 table.add_row([name, repository]) 

244 table.align = "l" 

245 print(table) 

246 

247 

248def pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal): 

249 logger.debug("") 

250 if filter: 

251 filter = "&".join(filter) 

252 resp = ctx.obj.osmrepo.pkg_get(pkgtype, name, repo, version, filter) 

253 

254 if literal: 

255 print(yaml.safe_dump(resp, indent=4, default_flow_style=False)) 

256 return 

257 pkgtype += "d" 

258 catalog = pkgtype + "-catalog" 

259 full_catalog = pkgtype + ":" + catalog 

260 if resp.get(catalog): 

261 resp = resp.pop(catalog)[pkgtype][0] 

262 elif resp.get(full_catalog): 

263 resp = resp.pop(full_catalog)[pkgtype][0] 

264 

265 table = PrettyTable(["field", "value"]) 

266 for k, v in list(resp.items()): 

267 table.add_row([k, utils.wrap_text(text=json.dumps(v, indent=2), width=100)]) 

268 table.align = "l" 

269 print(table) 

270 

271 

272@click.command(name="vnfpkg-repo-list", short_help="list all xNF from OSM repositories") 

273@click.option( 

274 "--filter", 

275 default=None, 

276 multiple=True, 

277 help="restricts the list to the NFpkg matching the filter", 

278) 

279@click.option( 

280 "--repo", default=None, help="restricts the list to a particular OSM repository" 

281) 

282@click.option("--long", is_flag=True, help="get more details") 

283@click.pass_context 

284def nfpkg_repo_list1(ctx, filter, repo, long): 

285 """list xNF packages from OSM repositories""" 

286 pkgtype = "vnf" 

287 pkg_repo_list(ctx, pkgtype, filter, repo, long) 

288 

289 

290@click.command(name="nfpkg-repo-list", short_help="list all xNF from OSM repositories") 

291@click.option( 

292 "--filter", 

293 default=None, 

294 multiple=True, 

295 help="restricts the list to the NFpkg matching the filter", 

296) 

297@click.option( 

298 "--repo", default=None, help="restricts the list to a particular OSM repository" 

299) 

300@click.option("--long", is_flag=True, help="get more details") 

301@click.pass_context 

302def nfpkg_repo_list2(ctx, filter, repo, long): 

303 """list xNF packages from OSM repositories""" 

304 pkgtype = "vnf" 

305 pkg_repo_list(ctx, pkgtype, filter, repo, long) 

306 

307 

308@click.command(name="nsd-repo-list", short_help="list all NS from OSM repositories") 

309@click.option( 

310 "--filter", 

311 default=None, 

312 multiple=True, 

313 help="restricts the list to the NS matching the filter", 

314) 

315@click.option( 

316 "--repo", default=None, help="restricts the list to a particular OSM repository" 

317) 

318@click.option("--long", is_flag=True, help="get more details") 

319@click.pass_context 

320def nspkg_repo_list(ctx, filter, repo, long): 

321 """list xNF packages from OSM repositories""" 

322 pkgtype = "ns" 

323 pkg_repo_list(ctx, pkgtype, filter, repo, long) 

324 

325 

326@click.command(name="nspkg-repo-list", short_help="list all NS from OSM repositories") 

327@click.option( 

328 "--filter", 

329 default=None, 

330 multiple=True, 

331 help="restricts the list to the NS matching the filter", 

332) 

333@click.option( 

334 "--repo", default=None, help="restricts the list to a particular OSM repository" 

335) 

336@click.option("--long", is_flag=True, help="get more details") 

337@click.pass_context 

338def nspkg_repo_list2(ctx, filter, repo, long): 

339 """list xNF packages from OSM repositories""" 

340 pkgtype = "ns" 

341 pkg_repo_list(ctx, pkgtype, filter, repo, long) 

342 

343 

344@click.command( 

345 name="vnfpkg-repo-show", 

346 short_help="shows the details of a NF package in an OSM repository", 

347) 

348@click.option("--literal", is_flag=True, help="print literally, no pretty table") 

349@click.option("--repo", required=True, help="Repository name") 

350@click.argument("name") 

351@click.option("--filter", default=None, multiple=True, help="filter by fields") 

352@click.option("--version", default="latest", help="package version") 

353@click.pass_context 

354def vnfd_show1(ctx, name, repo, version, literal=None, filter=None): 

355 """shows the content of a VNFD in a repository 

356 

357 NAME: name or ID of the VNFD/VNFpkg 

358 """ 

359 pkgtype = "vnf" 

360 pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal) 

361 

362 

363@click.command( 

364 name="nsd-repo-show", 

365 short_help="shows the details of a NS package in an OSM repository", 

366) 

367@click.option("--literal", is_flag=True, help="print literally, no pretty table") 

368@click.option("--repo", required=True, help="Repository name") 

369@click.argument("name") 

370@click.option("--filter", default=None, multiple=True, help="filter by fields") 

371@click.option("--version", default="latest", help="package version") 

372@click.pass_context 

373def nsd_repo_show(ctx, name, repo, version, literal=None, filter=None): 

374 """shows the content of a VNFD in a repository 

375 

376 NAME: name or ID of the VNFD/VNFpkg 

377 """ 

378 pkgtype = "ns" 

379 pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal) 

380 

381 

382@click.command( 

383 name="nspkg-repo-show", 

384 short_help="shows the details of a NS package in an OSM repository", 

385) 

386@click.option("--literal", is_flag=True, help="print literally, no pretty table") 

387@click.option("--repo", required=True, help="Repository name") 

388@click.argument("name") 

389@click.option("--filter", default=None, multiple=True, help="filter by fields") 

390@click.option("--version", default="latest", help="package version") 

391@click.pass_context 

392def nsd_repo_show2(ctx, name, repo, version, literal=None, filter=None): 

393 """shows the content of a VNFD in a repository 

394 

395 NAME: name or ID of the VNFD/VNFpkg 

396 """ 

397 pkgtype = "ns" 

398 pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal) 

399 

400 

401@click.command( 

402 name="nfpkg-repo-show", 

403 short_help="shows the details of a NF package in an OSM repository", 

404) 

405@click.option("--literal", is_flag=True, help="print literally, no pretty table") 

406@click.option("--repo", required=True, help="Repository name") 

407@click.argument("name") 

408@click.option("--filter", default=None, multiple=True, help="filter by fields") 

409@click.option("--version", default="latest", help="package version") 

410@click.pass_context 

411def vnfd_show2(ctx, name, repo, version, literal=None, filter=None): 

412 """shows the content of a VNFD in a repository 

413 

414 NAME: name or ID of the VNFD/VNFpkg 

415 """ 

416 pkgtype = "vnf" 

417 pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal)