+ 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)
+
+
+###########################
+# VCA operations
+###########################
+
+
+@cli_osm.command(name="vca-add", short_help="adds a VCA (Juju controller) to OSM")
+@click.argument("name")
+@click.option(
+ "--endpoints",
+ prompt=True,
+ help="Comma-separated list of IP or hostnames of the Juju controller",
+)
+@click.option("--user", prompt=True, help="Username with admin priviledges")
+@click.option("--secret", prompt=True, help="Password of the specified username")
+@click.option("--cacert", prompt=True, help="CA certificate")
+@click.option(
+ "--lxd-cloud",
+ prompt=True,
+ help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
+)
+@click.option(
+ "--lxd-credentials",
+ prompt=True,
+ help="Name of the cloud credentialsto be used for the LXD cloud",
+)
+@click.option(
+ "--k8s-cloud",
+ prompt=True,
+ help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
+)
+@click.option(
+ "--k8s-credentials",
+ prompt=True,
+ help="Name of the cloud credentialsto be used for the K8s cloud",
+)
+@click.option("--model-config", default={}, help="Configuration options for the models")
+@click.option("--description", default=None, help="human readable description")
+@click.pass_context
+def vca_add(
+ ctx,
+ name,
+ endpoints,
+ user,
+ secret,
+ cacert,
+ lxd_cloud,
+ lxd_credentials,
+ k8s_cloud,
+ k8s_credentials,
+ model_config,
+ description,
+):
+ """adds a VCA to OSM
+
+ NAME: name of the VCA
+ """
+ check_client_version(ctx.obj, ctx.command.name)
+ vca = {}
+ vca["name"] = name
+ vca["endpoints"] = endpoints.split(",")
+ vca["user"] = user
+ vca["secret"] = secret
+ vca["cacert"] = cacert
+ vca["lxd-cloud"] = lxd_cloud
+ vca["lxd-credentials"] = lxd_credentials
+ vca["k8s-cloud"] = k8s_cloud
+ vca["k8s-credentials"] = k8s_credentials
+ if description:
+ vca["description"] = description
+ if model_config:
+ model_config = load(model_config)
+ vca["model-config"] = model_config
+ ctx.obj.vca.create(name, vca)
+
+
+def load(data: Any):
+ if os.path.isfile(data):
+ return load_file(data)
+ else:
+ try:
+ return json.loads(data)
+ except ValueError as e:
+ raise ClientException(e)
+
+
+def load_file(file_path: str) -> Dict:
+ content = None
+ with open(file_path, "r") as f:
+ content = f.read()
+ try:
+ return yaml.safe_load(content)
+ except yaml.scanner.ScannerError:
+ pass
+ try:
+ return json.loads(content)
+ except ValueError:
+ pass
+ raise ClientException(f"{file_path} must be a valid yaml or json file")
+
+
+@cli_osm.command(name="vca-update", short_help="updates a K8s cluster")
+@click.argument("name")
+@click.option(
+ "--endpoints", help="Comma-separated list of IP or hostnames of the Juju controller"
+)
+@click.option("--user", help="Username with admin priviledges")
+@click.option("--secret", help="Password of the specified username")
+@click.option("--cacert", help="CA certificate")
+@click.option(
+ "--lxd-cloud",
+ help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
+)
+@click.option(
+ "--lxd-credentials",
+ help="Name of the cloud credentialsto be used for the LXD cloud",
+)
+@click.option(
+ "--k8s-cloud",
+ help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
+)
+@click.option(
+ "--k8s-credentials",
+ help="Name of the cloud credentialsto be used for the K8s cloud",
+)
+@click.option("--model-config", help="Configuration options for the models")
+@click.option("--description", default=None, help="human readable description")
+@click.pass_context
+def vca_update(
+ ctx,
+ name,
+ endpoints,
+ user,
+ secret,
+ cacert,
+ lxd_cloud,
+ lxd_credentials,
+ k8s_cloud,
+ k8s_credentials,
+ model_config,
+ description,
+):
+ """updates a K8s cluster
+
+ NAME: name or ID of the K8s cluster
+ """
+ check_client_version(ctx.obj, ctx.command.name)
+ vca = {}
+ vca["name"] = name
+ if endpoints:
+ vca["endpoints"] = endpoints.split(",")
+ if user:
+ vca["user"] = user
+ if secret:
+ vca["secret"] = secret
+ if cacert:
+ vca["cacert"] = cacert
+ if lxd_cloud:
+ vca["lxd-cloud"] = lxd_cloud
+ if lxd_credentials:
+ vca["lxd-credentials"] = lxd_credentials
+ if k8s_cloud:
+ vca["k8s-cloud"] = k8s_cloud
+ if k8s_credentials:
+ vca["k8s-credentials"] = k8s_credentials
+ if description:
+ vca["description"] = description
+ if model_config:
+ model_config = load(model_config)
+ vca["model-config"] = model_config
+ ctx.obj.vca.update(name, vca)
+
+
+@cli_osm.command(name="vca-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.pass_context
+def vca_delete(ctx, name, force):
+ """deletes a K8s cluster
+
+ NAME: name or ID of the K8s cluster to be deleted
+ """
+ check_client_version(ctx.obj, ctx.command.name)
+ ctx.obj.vca.delete(name, force=force)
+
+
+@cli_osm.command(name="vca-list")
+@click.option(
+ "--filter",
+ default=None,
+ multiple=True,
+ help="restricts the list to the VCAs matching the filter",
+)
+@click.option("--literal", is_flag=True, help="print literally, no pretty table")
+@click.option("--long", is_flag=True, help="get more details")
+@click.pass_context
+def vca_list(ctx, filter, literal, long):
+ """list VCAs"""
+ check_client_version(ctx.obj, ctx.command.name)
+ if filter:
+ filter = "&".join(filter)
+ resp = ctx.obj.vca.list(filter)
+ if literal:
+ print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
+ return
+ if long:
+ table = PrettyTable(
+ ["Name", "Id", "Project", "Operational State", "Detailed Status"]
+ )
+ project_list = ctx.obj.project.list()
+ else:
+ table = PrettyTable(["Name", "Id", "Operational State"])
+ for vca in resp:
+ logger.debug("VCA details: {}".format(yaml.safe_dump(vca)))
+ if long:
+ project_id, project_name = get_project(project_list, vca)
+ detailed_status = vca.get("_admin", {}).get("detailed-status", "-")
+ table.add_row(
+ [
+ vca["name"],
+ vca["_id"],
+ project_name,
+ vca.get("_admin", {}).get("operationalState", "-"),
+ wrap_text(text=detailed_status, width=40),
+ ]
+ )
+ else:
+ table.add_row(
+ [
+ vca["name"],
+ vca["_id"],
+ vca.get("_admin", {}).get("operationalState", "-"),
+ ]
+ )
+ table.align = "l"
+ print(table)
+
+
+@cli_osm.command(name="vca-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 vca_show(ctx, name, literal):
+ """shows the details of a K8s cluster
+
+ NAME: name or ID of the K8s cluster
+ """
+ # try:
+ resp = ctx.obj.vca.get(name)
+ if literal:
+ print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
+ 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)
+
+
+###########################
+# PaaS operations
+###########################
+
+
+@cli_osm.command(name="paas-add", short_help="adds a PaaS to OSM.")
+@click.argument("name")
+@click.option(
+ "--paas_type",
+ type=click.Choice(["juju"]),
+ default="juju",
+ prompt=True,
+ help="Type of PaaS that can be used. (For the moment, only juju is supported).",
+)
+@click.option(
+ "--endpoints",
+ prompt=True,
+ help="Comma-separated list of IP or hostnames of the PaaS.",
+)
+@click.option("--user", prompt=True, help="Username with admin priviledges.")
+@click.option("--secret", prompt=True, help="Password of the specified username.")
+@click.option(
+ "--config", default={}, help="Extra configuration needed by PaaS service."
+)
+@click.option("--description", default=None, help="Human readable description.")
+@click.pass_context
+def paas_add(ctx, name, paas_type, endpoints, user, secret, config, description):
+ """adds a PaaS to OSM.
+ Args:
+ name (str): Name of the new PaaS.
+ """
+ check_client_version(ctx.obj, ctx.command.name)
+ paas = {
+ "name": name,
+ "paas_type": paas_type,
+ "endpoints": endpoints.split(","),
+ "user": user,
+ "secret": secret,
+ }
+ if description:
+ paas["description"] = description
+ if config:
+ config = load(config)
+ paas["config"] = config
+ ctx.obj.paas.create(paas)
+
+
+@cli_osm.command(name="paas-update", short_help="updates a PaaS")
+@click.argument("name")
+@click.option("--newname", help="New name for the PaaS")
+@click.option(
+ "--paas_type",
+ type=click.Choice(["juju"]),
+ help="Type of PaaS that can be used. (For the moment, only juju is supported)",
+)
+@click.option(
+ "--endpoints", help="Comma-separated list of IP or hostnames of the Juju controller"
+)
+@click.option("--user", help="Username with admin priviledges")
+@click.option("--secret", help="Password of the specified username")
+@click.option("--config", help="Extra configuration needed by PaaS service")
+@click.option("--description", default=None, help="Human readable description")
+@click.pass_context
+def paas_update(
+ ctx, name, newname, paas_type, endpoints, user, secret, config, description
+):
+ """updates a PaaS.
+ Args:
+ name (str): Name or ID of the PaaS to update.
+ """
+ check_client_version(ctx.obj, ctx.command.name)
+ paas = {}
+ if newname:
+ paas["name"] = newname
+ if paas_type:
+ paas["paas_type"] = paas_type
+ if endpoints:
+ paas["endpoints"] = endpoints.split(",")
+ if user:
+ paas["user"] = user
+ if secret:
+ paas["secret"] = secret
+ if description:
+ paas["description"] = description
+ if config:
+ config = load(config)
+ paas["config"] = config
+ ctx.obj.paas.update(name, paas)
+
+
+@cli_osm.command(name="paas-delete", short_help="deletes a PaaS")
+@click.argument("name")
+@click.option(
+ "--force", is_flag=True, help="forces the deletion from the DB (not recommended)"
+)
+@click.pass_context
+def paas_delete(ctx, name, force):
+ """deletes a PaaS.
+
+ Args:
+ name (str): Name or ID of the PaaS to delete.
+ """
+ check_client_version(ctx.obj, ctx.command.name)
+ ctx.obj.paas.delete(name, force=force)
+
+
+@cli_osm.command(name="paas-list")
+@click.option(
+ "--filter",
+ default=None,
+ multiple=True,
+ help="Restricts the list to the PaaS matching the filter",
+)
+@click.option("--literal", is_flag=True, help="Print literally, no pretty table")
+@click.option("--long", is_flag=True, help="get more details")
+@click.pass_context
+def paas_list(ctx, filter, literal, long):
+ """List PaaSs"""
+ check_client_version(ctx.obj, ctx.command.name)
+ if filter:
+ filter = "&".join(filter)
+ resp = ctx.obj.paas.list(filter)
+ if literal:
+ print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
+ return
+
+ table = _get_paas_table_header(long)
+ project_list = ctx.obj.project.list()
+ for paas in resp:
+ logger.debug("PaaS details: {}".format(yaml.safe_dump(paas)))
+ if long:
+ _add_paas_long_row(table, paas, project_list)
+ else:
+ _add_paas_row(table, paas)
+ table.align = "l"