+###########################
+# K8s cluster operations
+###########################
+
+@cli_osm.command(name='k8scluster-add', short_help='adds a K8s cluster to OSM')
+@click.argument('name')
+@click.option('--creds',
+ prompt=True,
+ help='credentials file, i.e. a valid `.kube/config` file')
+@click.option('--version',
+ prompt=True,
+ help='Kubernetes version')
+@click.option('--vim',
+ prompt=True,
+ help='VIM target, the VIM where the cluster resides')
+@click.option('--k8s-nets',
+ prompt=True,
+ help='list of VIM networks, in JSON inline format, where the cluster is accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"')
+@click.option('--description',
+ default=None,
+ help='human readable description')
+@click.option('--namespace',
+ default='kube-system',
+ help='namespace to be used for its operation, defaults to `kube-system`')
+@click.option('--cni',
+ default=None,
+ help='list of CNI plugins, in JSON inline format, used in the cluster')
+#@click.option('--skip-init',
+# is_flag=True,
+# help='If set, K8s cluster is assumed to be ready for its use with OSM')
+#@click.option('--wait',
+# is_flag=True,
+# help='do not return the control immediately, but keep it until the operation is completed, or timeout')
+@click.pass_context
+def k8scluster_add(ctx,
+ name,
+ creds,
+ version,
+ vim,
+ k8s_nets,
+ description,
+ namespace,
+ cni):
+ """adds a K8s cluster to OSM
+
+ NAME: name of the K8s cluster
+ """
+ # try:
+ check_client_version(ctx.obj, ctx.command.name)
+ cluster = {}
+ cluster['name'] = name
+ with open(creds, 'r') as cf:
+ cluster['credentials'] = yaml.safe_load(cf.read())
+ cluster['k8s_version'] = version
+ cluster['vim_account'] = vim
+ cluster['nets'] = yaml.safe_load(k8s_nets)
+ if description:
+ cluster['description'] = description
+ if namespace: cluster['namespace'] = namespace
+ if cni: cluster['cni'] = yaml.safe_load(cni)
+ ctx.obj.k8scluster.create(name, cluster)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+@cli_osm.command(name='k8scluster-update', short_help='updates a K8s cluster')
+@click.argument('name')
+@click.option('--newname', help='New name for the K8s cluster')
+@click.option('--creds', help='credentials file, i.e. a valid `.kube/config` file')
+@click.option('--version', help='Kubernetes version')
+@click.option('--vim', help='VIM target, the VIM where the cluster resides')
+@click.option('--k8s-nets', help='list of VIM networks, in JSON inline format, where the cluster is accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"')
+@click.option('--description', help='human readable description')
+@click.option('--namespace', help='namespace to be used for its operation, defaults to `kube-system`')
+@click.option('--cni', help='list of CNI plugins, in JSON inline format, used in the cluster')
+@click.pass_context
+def k8scluster_update(ctx,
+ name,
+ newname,
+ creds,
+ version,
+ vim,
+ k8s_nets,
+ description,
+ namespace,
+ cni):
+ """updates a K8s cluster
+
+ NAME: name or ID of the K8s cluster
+ """
+ # try:
+ check_client_version(ctx.obj, ctx.command.name)
+ cluster = {}
+ if newname: cluster['name'] = newname
+ if creds:
+ with open(creds, 'r') as cf:
+ cluster['credentials'] = yaml.safe_load(cf.read())
+ if version: cluster['k8s_version'] = version
+ if vim: cluster['vim_account'] = vim
+ if k8s_nets: cluster['nets'] = yaml.safe_load(k8s_nets)
+ if description: cluster['description'] = description
+ if namespace: cluster['namespace'] = namespace
+ if cni: cluster['cni'] = yaml.safe_load(cni)
+ ctx.obj.k8scluster.update(name, cluster)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+@cli_osm.command(name='k8scluster-delete', short_help='deletes a K8s cluster')
+@click.argument('name')
+@click.option('--force', is_flag=True, help='forces the deletion from the DB (not recommended)')
+#@click.option('--wait',
+# is_flag=True,
+# help='do not return the control immediately, but keep it until the operation is completed, or timeout')
+@click.pass_context
+def k8scluster_delete(ctx, name, force):
+ """deletes a K8s cluster
+
+ NAME: name or ID of the K8s cluster to be deleted
+ """
+ # try:
+ check_client_version(ctx.obj, ctx.command.name)
+ ctx.obj.k8scluster.delete(name, force=force)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+@cli_osm.command(name='k8scluster-list')
+@click.option('--filter', default=None,
+ help='restricts the list to the K8s clusters matching the filter')
+@click.option('--literal', is_flag=True,
+ help='print literally, no pretty table')
+@click.pass_context
+def k8scluster_list(ctx, filter, literal):
+ """list all K8s clusters"""
+ # try:
+ check_client_version(ctx.obj, ctx.command.name)
+ resp = ctx.obj.k8scluster.list(filter)
+ if literal:
+ print(yaml.safe_dump(resp))
+ return
+ table = PrettyTable(['Name', 'Id', 'Version', 'VIM', 'K8s-nets', 'Operational State', 'Description'])
+ for cluster in resp:
+ table.add_row([cluster['name'], cluster['_id'], cluster['k8s_version'], cluster['vim_account'],
+ json.dumps(cluster['nets']), cluster["_admin"]["operationalState"],
+ trunc_text(cluster.get('description',''),40)])
+ table.align = 'l'
+ print(table)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+@cli_osm.command(name='k8scluster-show', short_help='shows the details of a K8s cluster')
+@click.argument('name')
+@click.option('--literal', is_flag=True,
+ help='print literally, no pretty table')
+@click.pass_context
+def k8scluster_show(ctx, name, literal):
+ """shows the details of a K8s cluster
+
+ NAME: name or ID of the K8s cluster
+ """
+ # try:
+ resp = ctx.obj.k8scluster.get(name)
+ if literal:
+ print(yaml.safe_dump(resp))
+ return
+ table = PrettyTable(['key', 'attribute'])
+ for k, v in list(resp.items()):
+ table.add_row([k, wrap_text(text=json.dumps(v, indent=2),width=100)])
+ table.align = 'l'
+ print(table)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+
+###########################
+# Repo operations
+###########################
+
+@cli_osm.command(name='repo-add', short_help='adds a repo to OSM')
+@click.argument('name')
+@click.argument('uri')
+@click.option('--type',
+ type=click.Choice(['helm-chart', 'juju-bundle']),
+ prompt=True,
+ help='type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles)')
+@click.option('--description',
+ default=None,
+ help='human readable description')
+#@click.option('--wait',
+# is_flag=True,
+# help='do not return the control immediately, but keep it until the operation is completed, or timeout')
+@click.pass_context
+def repo_add(ctx,
+ name,
+ uri,
+ type,
+ description):
+ """adds a repo to OSM
+
+ NAME: name of the repo
+ URI: URI of the repo
+ """
+ # try:
+ check_client_version(ctx.obj, ctx.command.name)
+ repo = {}
+ repo['name'] = name
+ repo['url'] = uri
+ repo['type'] = type
+ if description:
+ repo['description'] = description
+ ctx.obj.repo.create(name, repo)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+@cli_osm.command(name='repo-update', short_help='updates a repo in OSM')
+@click.argument('name')
+@click.option('--newname', help='New name for the repo')
+@click.option('--uri', help='URI of the repo')
+@click.option('--type', type=click.Choice(['helm-chart', 'juju-bundle']),
+ help='type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles)')
+@click.option('--description', help='human readable description')
+#@click.option('--wait',
+# is_flag=True,
+# help='do not return the control immediately, but keep it until the operation is completed, or timeout')
+@click.pass_context
+def repo_update(ctx,
+ name,
+ newname,
+ uri,
+ type,
+ description):
+ """updates a repo in OSM
+
+ NAME: name of the repo
+ """
+ # try:
+ check_client_version(ctx.obj, ctx.command.name)
+ repo = {}
+ if newname: repo['name'] = newname
+ if uri: repo['uri'] = uri
+ if type: repo['type'] = type
+ if description: repo['description'] = description
+ ctx.obj.repo.update(name, repo)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+@cli_osm.command(name='repo-delete', short_help='deletes a repo')
+@click.argument('name')
+@click.option('--force', is_flag=True, help='forces the deletion from the DB (not recommended)')
+#@click.option('--wait',
+# is_flag=True,
+# help='do not return the control immediately, but keep it until the operation is completed, or timeout')
+@click.pass_context
+def repo_delete(ctx, name, force):
+ """deletes a repo
+
+ NAME: name or ID of the repo to be deleted
+ """
+ # try:
+ check_client_version(ctx.obj, ctx.command.name)
+ ctx.obj.repo.delete(name, force=force)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+@cli_osm.command(name='repo-list')
+@click.option('--filter', default=None,
+ help='restricts the list to the repos matching the filter')
+@click.option('--literal', is_flag=True,
+ help='print literally, no pretty table')
+@click.pass_context
+def repo_list(ctx, filter, literal):
+ """list all repos"""
+ # try:
+ check_client_version(ctx.obj, ctx.command.name)
+ resp = ctx.obj.repo.list(filter)
+ if literal:
+ print(yaml.safe_dump(resp))
+ return
+ table = PrettyTable(['Name', 'Id', 'Type', 'URI', 'Description'])
+ for repo in resp:
+ #cluster['k8s-nets'] = json.dumps(yaml.safe_load(cluster['k8s-nets']))
+ table.add_row([repo['name'], repo['_id'], repo['type'], repo['url'], trunc_text(repo.get('description',''),40)])
+ table.align = 'l'
+ print(table)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+@cli_osm.command(name='repo-show', short_help='shows the details of a repo')
+@click.argument('name')
+@click.option('--literal', is_flag=True,
+ help='print literally, no pretty table')
+@click.pass_context
+def repo_show(ctx, name, literal):
+ """shows the details of a repo
+
+ NAME: name or ID of the repo
+ """
+ # try:
+ resp = ctx.obj.repo.get(name)
+ if literal:
+ print(yaml.safe_dump(resp))
+ return
+ table = PrettyTable(['key', 'attribute'])
+ for k, v in list(resp.items()):
+ table.add_row([k, json.dumps(v, indent=2)])
+ table.align = 'l'
+ print(table)
+ # except ClientException as e:
+ # print(str(e))
+ # exit(1)
+
+
+