def get_available_addons(self, id=None, k8s_version=None): """Retrieve the available addons for a cluster. :param id: get available addons for a specific cluster (opt) :param k8s_version: get available addons for a cluster version (opt) """ if id is not None and k8s_version is not None: print( "Either 'id' or 'k8s_version' parameter must be provided", file=sys.stderr, ) sys.exit(1) if id is None and k8s_version is None: print( "Either 'id' or 'k8s_version' parameter must be provided", file=sys.stderr, ) sys.exit(1) if id: print(base.get_client().k8s_cluster.get_available_addons(id=id)) else: print(base.get_client().k8s_cluster.get_available_addons( k8s_version=k8s_version))
def set_storage( self, id, ephemeral_disks, persistent_disks=None, ): """Set storage for a k8s worker. Parameters ---------- id : str The k8s worker ID ephemeral_disks : str Comma separated string containing ephemeral disks. e.g: "/dev/nvme2n1,/dev/nvme2n2" persistent_disks : str, optional Comma separated string containing persistent disks, by default None. e.g: "/dev/nvme1n1,/dev/nvme1n2" """ if not ephemeral_disks: print("'ephemeral_disks' must be provided", file=sys.stderr) sys.exit(1) p_disks = ( persistent_disks.split(",") if persistent_disks is not None else [] ) e_disks = ephemeral_disks.split(",") base.get_client().k8s_worker.set_storage( worker_id=id, persistent_disks=p_disks, ephemeral_disks=e_disks, )
def delete_all(self, ): """Delete all licenses.""" response = base.get_client().license.list() all_license_keys = [ str(unicode(li["LicenseKey"])) for li in response["Licenses"] ] for licence_key in all_license_keys: base.get_client().license.delete(license_key=licence_key)
def delete( self, license_key, ): """Delete a license by LicenseKey. :param license_key: The license key, e.g. '1234 1234 ... 1234 "SOMETEXT"' """ base.get_client().license.delete(license_key=license_key)
def delete( self, url, ): """Make HTTP DELETE request. Examples -------- $ hpecp httpclient delete /api/v1/workers/1 """ base.get_client()._request( url, http_method="delete", description="CLI HTTP DELETE", )
def list( self, output="yaml", ): """Get the system and user locks. :param output: how to display the output ['yaml'|'json'] """ if output not in ["yaml", "json"]: print( "'output' parameter must be 'yaml' or 'json'", file=sys.stderr ) sys.exit(1) response = base.get_client().lock.get() if output == "yaml": print( yaml.dump( yaml.load( json.dumps(response), Loader=yaml.FullLoader, ) ) ) else: print(json.dumps(response))
def list( self, output="yaml", license_key_only=False, ): """Retrieve the list of licenses. :param output: how to display the output ['yaml'|'json'] """ response = base.get_client().license.list() if license_key_only: response = [ str(unicode(li["LicenseKey"])) for li in response["Licenses"] ] print("\n".join(response)) else: if output == "yaml": print( yaml.dump( yaml.load( json.dumps(response), Loader=yaml.FullLoader, ))) else: print(json.dumps(response))
def get( self, url, ): """Make HTTP GET request. Examples -------- $ hpecp httpclient get /api/v1/workers > some output $ hpecp httpclient get /api/v2/tag | python3 -c \ 'import json,sys;obj=json.load(sys.stdin);[ print(t["_links"]["self"]["href"]) for t in obj["_embedded"]["tags"] if t["label"]["name"] == "Datafabric"]' /api/v2/tag/1 """ # noqa: E501 response = base.get_client()._request( url, http_method="get", description="CLI HTTP GET", ) try: response_info = json.dumps(response.json()) except Exception: response_info = response.text print(response_info, file=sys.stdout)
def test_config_file_missing(self): def get_config_file(): return "this_file_should_not_exist" with self.assertRaises(SystemExit) as cm: base.get_config_file = get_config_file base.get_client() self.assertEqual(cm.exception.code, 1) self.assertEqual(self.out.getvalue(), "") self.assertEqual( self.err.getvalue(), "Could not find configuration file 'this_file_should_not_exist'\n", )
def import_cluster( self, cluster_type, name, description, pod_dns_domain, server_url, ca, bearer_token, ): """Import a k8s cluster. TODO Returns ------- TODO Raises ------ APIException """ print(base.get_client().k8s_cluster.import_cluster( cluster_type, name, description, pod_dns_domain, server_url, ca, bearer_token, ))
def k8smanifest(self): """Retrieve the k8smanifest.""" response = base.get_client().k8s_cluster.k8smanifest() print( yaml.dump(yaml.load( json.dumps(response), Loader=yaml.FullLoader, )))
def upgrade_cluster(self, id, k8s_upgrade_version, worker_upgrade_percent=20): """Upgrade a cluster. TODO Returns ------- TODO Raises ------ APIException """ base.get_client().k8s_cluster.upgrade_cluster(id, k8s_upgrade_version, worker_upgrade_percent)
def create_with_ssh_key( self, ip, proxy_node_hostname, ssh_key=None, ssh_key_file=None, ssh_passphrase=None, tags=[], ): """Create a Gateway using SSH key authentication. Parameters ---------- ip : string The IP address of the proxy host. Used for internal communication. proxy_node_hostname: string Clients will access cluster services will be accessed using this name. ssh_key: string The ssh key data as a string. Alternatively, use the ssh_key_file parameter. ssh_key_file: string The file path to the ssh key. Alternatively, use the ssh_key parameter. ssh_passphrase: string The passphrase tags: string Tags to add to the gateway, for example: "{ 'tag1': 'foo', 'tag2', 'bar' }". """ if ssh_key is None and ssh_key_file is None: print( "Either ssh_key or ssh_key_file must be provided", file=sys.stderr, ) sys.exit(1) if ssh_key is not None and ssh_key_file is not None: print( "Either ssh_key or ssh_key_file must be provided", file=sys.stderr, ) sys.exit(1) if ssh_key_file: with open(ssh_key_file) as f: ssh_key = f.read() gateway_id = base.get_client().gateway.create_with_ssh_key( ip=ip, proxy_node_hostname=proxy_node_hostname, ssh_key_data=ssh_key, ssh_passphrase=ssh_passphrase, tags=tags, ) print(gateway_id)
def delete_all( self, timeout_secs=300, ): """Delete all locks.""" success = base.get_client().lock.delete_all(timeout_secs=timeout_secs) if not success: print("Could not delete locks.", file=sys.stderr) sys.exit(1)
def admin_kube_config(self, id): """Retrieve a K8s Cluster Admin Kube Config. :param id: the cluster ID """ print(base.get_client().k8s_cluster.get(id).admin_kube_config.replace( "\\n", "\n", ))
def create( self, name=None, description=None, tenant_type=None, k8s_cluster_id=None, is_namespace_owner=None, map_services_to_gateway=None, specified_namespace_name=None, adopt_existing_namespace=None, quota_memory=None, quota_persistent=None, quota_gpus=None, quota_cores=None, quota_disk=None, quota_tenant_storage=None, features=None, ): """Create a tenant. Parameters ---------- name : [type], optional [description], by default None description : [type], optional [description], by default None tenant_type : [type], optional [description], by default None k8s_cluster_id : [type], optional [description], by default None is_namespace_owner : [type], optional [description], by default None map_services_to_gateway : [type], optional [description], by default None specified_namespace_name : [type], optional [description], by default None adopt_existing_namespace : [type], optional [description], by default None """ tenant_id = base.get_client().tenant.create( name=name, description=description, tenant_type=tenant_type, k8s_cluster_id=k8s_cluster_id, is_namespace_owner=is_namespace_owner, map_services_to_gateway=map_services_to_gateway, specified_namespace_name=specified_namespace_name, adopt_existing_namespace=adopt_existing_namespace, quota_memory=quota_memory, quota_persistent=quota_persistent, quota_gpus=quota_gpus, quota_cores=quota_cores, quota_disk=quota_disk, quota_tenant_storage=quota_tenant_storage, features=features, ) print(tenant_id)
def create(self, reason, timeout_secs=300): """Create a lock.""" response = base.get_client().lock.create(reason, timeout_secs) if response is False: print( "Unable to lock within '{}'".format(timeout_secs), file=sys.stderr, ) else: # reponse contains lock ID print(response, file=sys.stdout)
def dashboard_url( self, id, ): """Retrieve a K8s Cluster Dashboard URL. :param id: the cluster ID """ url = (base.get_client().k8s_cluster.get( id=id).dashboard_endpoint_access) print(url)
def register( self, server_filename, ): """Register a license. :param server_filename: Filepath to the license on the server, e.g. '/srv/bluedata/license/LICENSE-1.txt' """ print(base.get_client().license.register( server_filename=server_filename))
def dashboard_token( self, id, ): """Retrieve a K8s Cluster Dashboard Token. :param id: the cluster ID """ token = base.get_client().k8s_cluster.get(id=id).dashboard_token if six.PY2: print(base64.b64decode(token.encode())) else: print(base64.b64decode(token.encode()).decode("utf-8"))
def k8skubeconfig(self): """Retrieve the tenant kubeconfig. This requires the ContainerPlatformClient to be created with a 'tenant' parameter. Returns ------- str Tenant KubeConfig """ conf = base.get_client().tenant.k8skubeconfig() print(conf)
def refresh(self, catalog_id): """Refresh a catalog. Parameters ---------- catalog_id : str The ID of the catalog - format: '/api/v1/catalog/[0-9]+' Examples -------- > hpecp catalog refresh /api/v1/catalog/99 """ try: base.get_client().catalog.refresh(catalog_id) # TODO: Report progress of the refresh workflow except AssertionError as ae: print(ae, file=sys.stderr) sys.exit(1) except (APIException, APIItemNotFoundException) as e: print(e.message, file=sys.stderr) sys.exit(1)
def install(self, catalog_id): """Install a catalog. Parameters ---------- catalog_id : str The ID of the catalog - format: '/api/v1/catalog/[0-9]+' Examples -------- > hpecp catalog install /api/v1/catalog/99 """ try: base.get_client().catalog.install(catalog_id) # TODO: Implement a way to check if the installation is actually # successful (and maybe report progress?) - wait_for_state()? except AssertionError as ae: print(ae, file=sys.stderr) sys.exit(1) except (APIException, APIItemNotFoundException) as e: print(e.message, file=sys.stderr) sys.exit(1)
def users(self, id, output="table", columns="ALL", query={}): """Retrieve users assigned to tenant. Parameters ---------- id : str The tenant ID. """ list_instance = base.get_client().tenant.users(id=id) self.print_list( list_instance=list_instance, output=output, columns=columns, query=query, )
def add_addons(self, id, addons, wait_for_ready_sec=0): """Retrieve the installed addons on the cluster. :param id: get installed addons for a specific cluster :param addons: list of addons to install :param wait_for_ready_sec: wait for ready status (0 = do not wait) """ if id is None: print("'id' parameter must be provided.", file=sys.stderr) sys.exit(1) if addons is None or not isinstance(addons, list) or len(addons) < 1: print( "'addons' must be a list with at least one entry.", file=sys.stderr, ) sys.exit(1) base.get_client().k8s_cluster.add_addons(id=id, addons=addons) if wait_for_ready_sec > 0: self.wait_for_status(id=id, status=["ready"], timeout_secs=wait_for_ready_sec)
def get( self, url, ): """Make HTTP GET request. Examples -------- $ hpecp httpclient get /api/v1/workers """ response = base.get_client()._request( url, http_method="get", description="CLI HTTP GET", ) print(response.text, file=sys.stdout)
def test_configure_cli_reads_hpecp_conf_user_provided_profile(self): # FIXME: why is this broken on 2.7? if six.PY2: return mock_data = dedent(""" [default] api_host = mock_host api_port = 9999 use_ssl = True verify_ssl = False warn_ssl = True username = admin password = admin123 [tenant1] api_host = tenant_mock_host username = tenant-admin password = tenant-password tenant = /api/v1/tenant/2""").encode("utf8") if six.PY2: builtins_name = "__builtin__.open" else: builtins_name = "builtins.open" with patch.dict("os.environ", {"PROFILE": "tenant1"}): with patch(builtins_name, mock_open(read_data=mock_data)): with patch("os.path.exists") as os_path_exists: self.assertEqual(base.get_profile(), "tenant1") # instruct the CLI that the mock file is actually # ~/.hpecp.conf os_path_exists.return_value = True hpecp_client = base.get_client(start_session=False) # this should be from the [default] section self.assertEqual(hpecp_client.api_port, 9999) # this should be from the [tenant1] section self.assertEqual(hpecp_client.api_host, "tenant_mock_host") self.assertEqual(hpecp_client.username, "tenant-admin") self.assertEqual(hpecp_client.tenant_config, "/api/v1/tenant/2")
def post( self, url, json_file="", ): """Make HTTP POST request. Examples -------- $ cat > my.json <<-EOF { "external_identity_server": { "bind_pwd":"5ambaPwd@", "user_attribute":"sAMAccountName", "bind_type":"search_bind", "bind_dn":"cn=Administrator,CN=Users,DC=samdom,DC=example,DC=com", "host":"10.1.0.77", "security_protocol":"ldaps", "base_dn":"CN=Users,DC=samdom,DC=example,DC=com", "verify_peer": false, "type":"Active Directory", "port":636 } } EOF hpecp httpclient post /api/v2/config/auth --json-file my.json """ with open( json_file, "r", ) as f: data = json.load(f) response = base.get_client()._request( url, http_method="post", data=data, description="CLI HTTP POST", ) print(response.text, file=sys.stdout)
def get(self, output="yaml", query=None): """Get the system config. :param output: how to display the output '[yaml|json|json-pp]' """ if output not in ["yaml", "json", "json-pp", "text"]: print( ("'output' parameter must be 'yaml', 'json', " "'json-pp' or 'text'."), file=sys.stderr, ) sys.exit(1) if output == "yaml" and query is not None: print( "output=yaml is not supported with the query parameter.", file=sys.stderr, ) sys.exit(1) response = base.get_client().install.get() if output == "yaml": print( yaml.dump( yaml.load( json.dumps(response), Loader=yaml.FullLoader, ))) else: if query is None: data = response else: data = jmespath.search(str(query), response) if output == "json-pp": print(json.dumps(data, indent=4, sort_keys=True)) elif output == "text": print(TextOutput.dump(data)) else: print(json.dumps(data))
def import_generic_cluster_with_json(self, json_file_path=None, json_content=None): """Import a generic cluster from json. TODO Returns ------- TODO Raises ------ APIException """ assert (json_file_path is not None or json_content is not None ), "Either --json-file-path or --json-content must be provided" assert ( json_file_path is None or json_content is None ), "Either --json-file-path or --json-content must be provided." if json_file_path: try: with open(json_file_path, "r") as f: json_content = f.read() except OSError: print( "Could not open/read json-file-path: {}".format( json_file_path), file=sys.stderr, ) sys.exit(1) json_content = json.loads(json_content) print(base.get_client().k8s_cluster.import_generic_cluster_with_json( json_content))