This is an automated email from the ASF dual-hosted git repository.
yzheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new 87841359c Python code format (#1954)
87841359c is described below
commit 87841359c489f35f808e6a0ab9f232fd08f9fbd5
Author: Yong Zheng <[email protected]>
AuthorDate: Fri Jun 27 16:13:57 2025 -0500
Python code format (#1954)
---
client/python/cli/command/__init__.py | 63 ++-
client/python/cli/command/catalog_roles.py | 52 +-
client/python/cli/command/catalogs.py | 134 +++--
client/python/cli/command/namespaces.py | 43 +-
client/python/cli/command/principal_roles.py | 42 +-
client/python/cli/command/principals.py | 97 ++--
client/python/cli/command/privileges.py | 78 +--
client/python/cli/command/profiles.py | 47 +-
client/python/cli/constants.py | 274 ++++++-----
client/python/cli/options/option_tree.py | 712 ++++++++++++++++++++-------
client/python/cli/options/parser.py | 128 +++--
client/python/cli/polaris_cli.py | 117 +++--
12 files changed, 1212 insertions(+), 575 deletions(-)
diff --git a/client/python/cli/command/__init__.py
b/client/python/cli/command/__init__.py
index 414ce43f5..897cbaaa5 100644
--- a/client/python/cli/command/__init__.py
+++ b/client/python/cli/command/__init__.py
@@ -32,8 +32,7 @@ class Command(ABC):
"""
@staticmethod
- def from_options(options: argparse.Namespace) -> 'Command':
-
+ def from_options(options: argparse.Namespace) -> "Command":
def options_get(key, f=lambda x: x):
return f(getattr(options, key)) if hasattr(options, key) else None
@@ -44,8 +43,9 @@ class Command(ABC):
command = None
if options.command == Commands.CATALOGS:
from cli.command.catalogs import CatalogsCommand
+
command = CatalogsCommand(
- options_get(f'{Commands.CATALOGS}_subcommand'),
+ options_get(f"{Commands.CATALOGS}_subcommand"),
catalog_type=options_get(Arguments.TYPE),
default_base_location=options_get(Arguments.DEFAULT_BASE_LOCATION),
storage_type=options_get(Arguments.STORAGE_TYPE),
@@ -61,81 +61,100 @@ class Command(ABC):
catalog_name=options_get(Arguments.CATALOG),
properties={} if properties is None else properties,
set_properties={} if set_properties is None else
set_properties,
- remove_properties=[] if remove_properties is None else
remove_properties
+ remove_properties=[]
+ if remove_properties is None
+ else remove_properties,
)
elif options.command == Commands.PRINCIPALS:
from cli.command.principals import PrincipalsCommand
+
command = PrincipalsCommand(
- options_get(f'{Commands.PRINCIPALS}_subcommand'),
+ options_get(f"{Commands.PRINCIPALS}_subcommand"),
type=options_get(Arguments.TYPE),
principal_name=options_get(Arguments.PRINCIPAL),
client_id=options_get(Arguments.CLIENT_ID),
principal_role=options_get(Arguments.PRINCIPAL_ROLE),
properties={} if properties is None else properties,
set_properties={} if set_properties is None else
set_properties,
- remove_properties=[] if remove_properties is None else
remove_properties
+ remove_properties=[]
+ if remove_properties is None
+ else remove_properties,
)
elif options.command == Commands.PRINCIPAL_ROLES:
from cli.command.principal_roles import PrincipalRolesCommand
+
command = PrincipalRolesCommand(
- options_get(f'{Commands.PRINCIPAL_ROLES}_subcommand'),
+ options_get(f"{Commands.PRINCIPAL_ROLES}_subcommand"),
principal_role_name=options_get(Arguments.PRINCIPAL_ROLE),
principal_name=options_get(Arguments.PRINCIPAL),
catalog_name=options_get(Arguments.CATALOG),
catalog_role_name=options_get(Arguments.CATALOG_ROLE),
properties={} if properties is None else properties,
set_properties={} if set_properties is None else
set_properties,
- remove_properties=[] if remove_properties is None else
remove_properties
+ remove_properties=[]
+ if remove_properties is None
+ else remove_properties,
)
elif options.command == Commands.CATALOG_ROLES:
from cli.command.catalog_roles import CatalogRolesCommand
+
command = CatalogRolesCommand(
- options_get(f'{Commands.CATALOG_ROLES}_subcommand'),
+ options_get(f"{Commands.CATALOG_ROLES}_subcommand"),
catalog_name=options_get(Arguments.CATALOG),
catalog_role_name=options_get(Arguments.CATALOG_ROLE),
principal_role_name=options_get(Arguments.PRINCIPAL_ROLE),
properties={} if properties is None else properties,
set_properties={} if set_properties is None else
set_properties,
- remove_properties=[] if remove_properties is None else
remove_properties
+ remove_properties=[]
+ if remove_properties is None
+ else remove_properties,
)
elif options.command == Commands.PRIVILEGES:
from cli.command.privileges import PrivilegesCommand
- subcommand = options_get(f'{Commands.PRIVILEGES}_subcommand')
+
+ subcommand = options_get(f"{Commands.PRIVILEGES}_subcommand")
command = PrivilegesCommand(
subcommand,
- action=options_get(f'{subcommand}_subcommand'),
+ action=options_get(f"{subcommand}_subcommand"),
catalog_name=options_get(Arguments.CATALOG),
catalog_role_name=options_get(Arguments.CATALOG_ROLE),
- namespace=options_get(Arguments.NAMESPACE, lambda s:
s.split('.') if s else None),
+ namespace=options_get(
+ Arguments.NAMESPACE, lambda s: s.split(".") if s else None
+ ),
view=options_get(Arguments.VIEW),
table=options_get(Arguments.TABLE),
privilege=options_get(Arguments.PRIVILEGE),
- cascade=options_get(Arguments.CASCADE)
+ cascade=options_get(Arguments.CASCADE),
)
elif options.command == Commands.NAMESPACES:
from cli.command.namespaces import NamespacesCommand
- subcommand = options_get(f'{Commands.NAMESPACES}_subcommand')
+
+ subcommand = options_get(f"{Commands.NAMESPACES}_subcommand")
command = NamespacesCommand(
subcommand,
catalog=options_get(Arguments.CATALOG),
- namespace=options_get(Arguments.NAMESPACE, lambda s:
s.split('.')),
- parent=options_get(Arguments.PARENT, lambda s: s.split('.') if
s else None),
+ namespace=options_get(Arguments.NAMESPACE, lambda s:
s.split(".")),
+ parent=options_get(
+ Arguments.PARENT, lambda s: s.split(".") if s else None
+ ),
location=options_get(Arguments.LOCATION),
- properties=properties
+ properties=properties,
)
elif options.command == Commands.PROFILES:
from cli.command.profiles import ProfilesCommand
- subcommand = options_get(f'{Commands.PROFILES}_subcommand')
+
+ subcommand = options_get(f"{Commands.PROFILES}_subcommand")
command = ProfilesCommand(
- subcommand,
- profile_name=options_get(Arguments.PROFILE)
+ subcommand, profile_name=options_get(Arguments.PROFILE)
)
if command is not None:
command.validate()
return command
else:
- raise Exception("Please specify a command or run ./polaris --help
to view the available commands")
+ raise Exception(
+ "Please specify a command or run ./polaris --help to view the
available commands"
+ )
def execute(self, api: PolarisDefaultApi) -> None:
"""
diff --git a/client/python/cli/command/catalog_roles.py
b/client/python/cli/command/catalog_roles.py
index 1c7d4df9a..3fa7cebb5 100644
--- a/client/python/cli/command/catalog_roles.py
+++ b/client/python/cli/command/catalog_roles.py
@@ -24,8 +24,13 @@ from pydantic import StrictStr
from cli.command import Command
from cli.constants import Subcommands, Arguments
from cli.options.option_tree import Argument
-from polaris.management import PolarisDefaultApi, CreateCatalogRoleRequest,
CatalogRole, UpdateCatalogRoleRequest, \
- GrantCatalogRoleRequest
+from polaris.management import (
+ PolarisDefaultApi,
+ CreateCatalogRoleRequest,
+ CatalogRole,
+ UpdateCatalogRoleRequest,
+ GrantCatalogRoleRequest,
+)
@dataclass
@@ -51,34 +56,44 @@ class CatalogRolesCommand(Command):
def validate(self):
if not self.catalog_name:
- raise Exception(f'Missing required argument:
{Argument.to_flag_name(Arguments.CATALOG)}')
+ raise Exception(
+ f"Missing required argument:
{Argument.to_flag_name(Arguments.CATALOG)}"
+ )
if self.catalog_roles_subcommand in {Subcommands.GRANT,
Subcommands.REVOKE}:
if not self.principal_role_name:
- raise Exception(f'Missing required argument:
{Argument.to_flag_name(Arguments.PRINCIPAL_ROLE)}')
+ raise Exception(
+ f"Missing required argument:
{Argument.to_flag_name(Arguments.PRINCIPAL_ROLE)}"
+ )
def execute(self, api: PolarisDefaultApi) -> None:
if self.catalog_roles_subcommand == Subcommands.CREATE:
request = CreateCatalogRoleRequest(
catalog_role=CatalogRole(
- name=self.catalog_role_name,
- properties=self.properties
+ name=self.catalog_role_name, properties=self.properties
)
)
api.create_catalog_role(self.catalog_name, request)
elif self.catalog_roles_subcommand == Subcommands.DELETE:
api.delete_catalog_role(self.catalog_name, self.catalog_role_name)
elif self.catalog_roles_subcommand == Subcommands.GET:
- print(api.get_catalog_role(self.catalog_name,
self.catalog_role_name).to_json())
+ print(
+ api.get_catalog_role(
+ self.catalog_name, self.catalog_role_name
+ ).to_json()
+ )
elif self.catalog_roles_subcommand == Subcommands.LIST:
if self.principal_role_name:
for catalog_role in api.list_catalog_roles_for_principal_role(
- self.principal_role_name, self.catalog_name).roles:
+ self.principal_role_name, self.catalog_name
+ ).roles:
print(catalog_role.to_json())
else:
for catalog_role in
api.list_catalog_roles(self.catalog_name).roles:
print(catalog_role.to_json())
elif self.catalog_roles_subcommand == Subcommands.UPDATE:
- catalog_role = api.get_catalog_role(self.catalog_name,
self.catalog_role_name)
+ catalog_role = api.get_catalog_role(
+ self.catalog_name, self.catalog_role_name
+ )
new_properties = catalog_role.properties or {}
# Add or update all entries specified in set_properties
@@ -92,19 +107,22 @@ class CatalogRolesCommand(Command):
request = UpdateCatalogRoleRequest(
current_entity_version=catalog_role.entity_version,
- properties=new_properties
+ properties=new_properties,
)
api.update_catalog_role(self.catalog_name, self.catalog_role_name,
request)
elif self.catalog_roles_subcommand == Subcommands.GRANT:
request = GrantCatalogRoleRequest(
- catalog_role=CatalogRole(
- name=self.catalog_role_name
- ),
- properties=self.properties
+ catalog_role=CatalogRole(name=self.catalog_role_name),
+ properties=self.properties,
+ )
+ api.assign_catalog_role_to_principal_role(
+ self.principal_role_name, self.catalog_name, request
)
-
api.assign_catalog_role_to_principal_role(self.principal_role_name,
self.catalog_name, request)
elif self.catalog_roles_subcommand == Subcommands.REVOKE:
api.revoke_catalog_role_from_principal_role(
- self.principal_role_name, self.catalog_name,
self.catalog_role_name)
+ self.principal_role_name, self.catalog_name,
self.catalog_role_name
+ )
else:
- raise Exception(f'{self.catalog_roles_subcommand} is not supported
in the CLI')
+ raise Exception(
+ f"{self.catalog_roles_subcommand} is not supported in the CLI"
+ )
diff --git a/client/python/cli/command/catalogs.py
b/client/python/cli/command/catalogs.py
index 718e6d11a..0baf2cffa 100644
--- a/client/python/cli/command/catalogs.py
+++ b/client/python/cli/command/catalogs.py
@@ -24,9 +24,18 @@ from pydantic import StrictStr
from cli.command import Command
from cli.constants import StorageType, CatalogType, Subcommands, Arguments
from cli.options.option_tree import Argument
-from polaris.management import PolarisDefaultApi, CreateCatalogRequest,
UpdateCatalogRequest, \
- StorageConfigInfo, ExternalCatalog, AwsStorageConfigInfo,
AzureStorageConfigInfo, GcpStorageConfigInfo, \
- PolarisCatalog, CatalogProperties
+from polaris.management import (
+ PolarisDefaultApi,
+ CreateCatalogRequest,
+ UpdateCatalogRequest,
+ StorageConfigInfo,
+ ExternalCatalog,
+ AwsStorageConfigInfo,
+ AzureStorageConfigInfo,
+ GcpStorageConfigInfo,
+ PolarisCatalog,
+ CatalogProperties,
+)
@dataclass
@@ -63,38 +72,58 @@ class CatalogsCommand(Command):
def validate(self):
if self.catalogs_subcommand == Subcommands.CREATE:
if not self.storage_type:
- raise Exception(f'Missing required argument:'
- f'
{Argument.to_flag_name(Arguments.STORAGE_TYPE)}')
+ raise Exception(
+ f"Missing required argument:"
+ f" {Argument.to_flag_name(Arguments.STORAGE_TYPE)}"
+ )
if not self.default_base_location:
- raise Exception(f'Missing required argument:'
- f'
{Argument.to_flag_name(Arguments.DEFAULT_BASE_LOCATION)}')
+ raise Exception(
+ f"Missing required argument:"
+ f"
{Argument.to_flag_name(Arguments.DEFAULT_BASE_LOCATION)}"
+ )
if self.storage_type == StorageType.S3.value:
if not self.role_arn:
- raise Exception(f"Missing required argument for storage type
's3':"
- f"
{Argument.to_flag_name(Arguments.ROLE_ARN)}")
+ raise Exception(
+ f"Missing required argument for storage type 's3':"
+ f" {Argument.to_flag_name(Arguments.ROLE_ARN)}"
+ )
if self._has_azure_storage_info() or self._has_gcs_storage_info():
- raise Exception(f"Storage type 's3' supports the storage
credentials"
- f"
{Argument.to_flag_name(Arguments.ROLE_ARN)},"
- f" {Argument.to_flag_name(Arguments.REGION)},"
- f"
{Argument.to_flag_name(Arguments.EXTERNAL_ID)}, and"
- f"
{Argument.to_flag_name(Arguments.USER_ARN)}")
+ raise Exception(
+ f"Storage type 's3' supports the storage credentials"
+ f" {Argument.to_flag_name(Arguments.ROLE_ARN)},"
+ f" {Argument.to_flag_name(Arguments.REGION)},"
+ f" {Argument.to_flag_name(Arguments.EXTERNAL_ID)}, and"
+ f" {Argument.to_flag_name(Arguments.USER_ARN)}"
+ )
elif self.storage_type == StorageType.AZURE.value:
if not self.tenant_id:
- raise Exception("Missing required argument for storage type
'azure': "
- f"
{Argument.to_flag_name(Arguments.TENANT_ID)}")
+ raise Exception(
+ "Missing required argument for storage type 'azure': "
+ f" {Argument.to_flag_name(Arguments.TENANT_ID)}"
+ )
if self._has_aws_storage_info() or self._has_gcs_storage_info():
- raise Exception("Storage type 'azure' supports the storage
credentials"
- f"
{Argument.to_flag_name(Arguments.TENANT_ID)},"
- f"
{Argument.to_flag_name(Arguments.MULTI_TENANT_APP_NAME)}, and"
- f"
{Argument.to_flag_name(Arguments.CONSENT_URL)}")
+ raise Exception(
+ "Storage type 'azure' supports the storage credentials"
+ f" {Argument.to_flag_name(Arguments.TENANT_ID)},"
+ f"
{Argument.to_flag_name(Arguments.MULTI_TENANT_APP_NAME)}, and"
+ f" {Argument.to_flag_name(Arguments.CONSENT_URL)}"
+ )
elif self.storage_type == StorageType.GCS.value:
if self._has_aws_storage_info() or self._has_azure_storage_info():
- raise Exception("Storage type 'gcs' supports the storage
credential"
- f"
{Argument.to_flag_name(Arguments.SERVICE_ACCOUNT)}")
+ raise Exception(
+ "Storage type 'gcs' supports the storage credential"
+ f" {Argument.to_flag_name(Arguments.SERVICE_ACCOUNT)}"
+ )
elif self.storage_type == StorageType.FILE.value:
- if self._has_aws_storage_info() or self._has_azure_storage_info()
or self._has_gcs_storage_info():
- raise Exception("Storage type 'file' does not support any
storage credentials")
+ if (
+ self._has_aws_storage_info()
+ or self._has_azure_storage_info()
+ or self._has_gcs_storage_info()
+ ):
+ raise Exception(
+ "Storage type 'file' does not support any storage
credentials"
+ )
def _has_aws_storage_info(self):
return self.role_arn or self.external_id or self.user_arn or
self.region
@@ -114,7 +143,7 @@ class CatalogsCommand(Command):
role_arn=self.role_arn,
external_id=self.external_id,
user_arn=self.user_arn,
- region=self.region
+ region=self.region,
)
elif self.storage_type == StorageType.AZURE.value:
config = AzureStorageConfigInfo(
@@ -128,12 +157,12 @@ class CatalogsCommand(Command):
config = GcpStorageConfigInfo(
storage_type=self.storage_type.upper(),
allowed_locations=self.allowed_locations,
- gcs_service_account=self.service_account
+ gcs_service_account=self.service_account,
)
elif self.storage_type == StorageType.FILE.value:
config = StorageConfigInfo(
storage_type=self.storage_type.upper(),
- allowed_locations=self.allowed_locations
+ allowed_locations=self.allowed_locations,
)
return config
@@ -148,8 +177,8 @@ class CatalogsCommand(Command):
storage_config_info=config,
properties=CatalogProperties(
default_base_location=self.default_base_location,
- additional_properties=self.properties
- )
+ additional_properties=self.properties,
+ ),
)
)
else:
@@ -160,8 +189,8 @@ class CatalogsCommand(Command):
storage_config_info=config,
properties=CatalogProperties(
default_base_location=self.default_base_location,
- additional_properties=self.properties
- )
+ additional_properties=self.properties,
+ ),
)
)
api.create_catalog(request)
@@ -175,13 +204,25 @@ class CatalogsCommand(Command):
elif self.catalogs_subcommand == Subcommands.UPDATE:
catalog = api.get_catalog(self.catalog_name)
- if self.default_base_location or self.set_properties or
self.remove_properties:
- new_default_base_location = self.default_base_location or
catalog.properties.default_base_location
- new_additional_properties =
catalog.properties.additional_properties or {}
+ if (
+ self.default_base_location
+ or self.set_properties
+ or self.remove_properties
+ ):
+ new_default_base_location = (
+ self.default_base_location
+ or catalog.properties.default_base_location
+ )
+ new_additional_properties = (
+ catalog.properties.additional_properties or {}
+ )
# Add or update all entries specified in set_properties
if self.set_properties:
- new_additional_properties = {**new_additional_properties,
**self.set_properties}
+ new_additional_properties = {
+ **new_additional_properties,
+ **self.set_properties,
+ }
# Remove all keys specified in remove_properties
if self.remove_properties:
@@ -190,11 +231,15 @@ class CatalogsCommand(Command):
catalog.properties = CatalogProperties(
default_base_location=new_default_base_location,
- additional_properties=new_additional_properties
+ additional_properties=new_additional_properties,
)
- if (self._has_aws_storage_info() or self._has_azure_storage_info()
or
- self._has_gcs_storage_info() or self.allowed_locations):
+ if (
+ self._has_aws_storage_info()
+ or self._has_azure_storage_info()
+ or self._has_gcs_storage_info()
+ or self.allowed_locations
+ ):
# We must first reconstitute local storage-config related
settings from the existing
# catalog to properly construct the complete updated
storage-config
updated_storage_info = catalog.storage_config_info
@@ -204,7 +249,9 @@ class CatalogsCommand(Command):
# in option_tree.py should be applied individually against the
existing
# storage_config_info here.
if self.allowed_locations:
-
updated_storage_info.allowed_locations.extend(self.allowed_locations)
+ updated_storage_info.allowed_locations.extend(
+ self.allowed_locations
+ )
if self.region:
# Note: We have to lowercase the returned value because
the server enum
@@ -212,20 +259,21 @@ class CatalogsCommand(Command):
storage_type = updated_storage_info.storage_type
if storage_type.lower() != StorageType.S3.value:
raise Exception(
- f'--region requires S3 storage_type, got:
{storage_type}')
+ f"--region requires S3 storage_type, got:
{storage_type}"
+ )
updated_storage_info.region = self.region
request = UpdateCatalogRequest(
current_entity_version=catalog.entity_version,
properties=catalog.properties.to_dict(),
- storage_config_info=updated_storage_info
+ storage_config_info=updated_storage_info,
)
else:
request = UpdateCatalogRequest(
current_entity_version=catalog.entity_version,
- properties=catalog.properties.to_dict()
+ properties=catalog.properties.to_dict(),
)
api.update_catalog(self.catalog_name, request)
else:
- raise Exception(f'{self.catalogs_subcommand} is not supported in
the CLI')
+ raise Exception(f"{self.catalogs_subcommand} is not supported in
the CLI")
diff --git a/client/python/cli/command/namespaces.py
b/client/python/cli/command/namespaces.py
index 65687226a..763138473 100644
--- a/client/python/cli/command/namespaces.py
+++ b/client/python/cli/command/namespaces.py
@@ -26,7 +26,12 @@ from pydantic import StrictStr
from cli.command import Command
from cli.constants import Subcommands, Arguments, UNIT_SEPARATOR
from cli.options.option_tree import Argument
-from polaris.catalog import IcebergCatalogAPI, CreateNamespaceRequest,
ApiClient, Configuration
+from polaris.catalog import (
+ IcebergCatalogAPI,
+ CreateNamespaceRequest,
+ ApiClient,
+ Configuration,
+)
from polaris.management import PolarisDefaultApi
@@ -51,16 +56,19 @@ class NamespacesCommand(Command):
def validate(self):
if not self.catalog:
- raise Exception(f'Missing required argument:'
- f' {Argument.to_flag_name(Arguments.CATALOG)}')
+ raise Exception(
+ f"Missing required argument:
{Argument.to_flag_name(Arguments.CATALOG)}"
+ )
def _get_catalog_api(self, api: PolarisDefaultApi):
"""
Convert a management API to a catalog API
"""
- catalog_host = re.match(r'(https?://.+)/api/management',
api.api_client.configuration.host).group(1)
+ catalog_host = re.match(
+ r"(https?://.+)/api/management", api.api_client.configuration.host
+ ).group(1)
configuration = Configuration(
- host=f'{catalog_host}/api/catalog',
+ host=f"{catalog_host}/api/catalog",
username=api.api_client.configuration.username,
password=api.api_client.configuration.password,
access_token=api.api_client.configuration.access_token,
@@ -74,26 +82,29 @@ class NamespacesCommand(Command):
if self.location:
req_properties = {**req_properties, Arguments.LOCATION:
self.location}
request = CreateNamespaceRequest(
- namespace=self.namespace,
- properties=req_properties
+ namespace=self.namespace, properties=req_properties
)
catalog_api.create_namespace(
- prefix=self.catalog,
- create_namespace_request=request)
+ prefix=self.catalog, create_namespace_request=request
+ )
elif self.namespaces_subcommand == Subcommands.LIST:
if self.parent is not None:
result = catalog_api.list_namespaces(
- prefix=self.catalog,
- parent=UNIT_SEPARATOR.join(self.parent))
+ prefix=self.catalog,
parent=UNIT_SEPARATOR.join(self.parent)
+ )
else:
result = catalog_api.list_namespaces(prefix=self.catalog)
for namespace in result.namespaces:
- print(json.dumps({"namespace": '.'.join(namespace)}))
+ print(json.dumps({"namespace": ".".join(namespace)}))
elif self.namespaces_subcommand == Subcommands.DELETE:
- catalog_api.drop_namespace(prefix=self.catalog,
namespace=UNIT_SEPARATOR.join(self.namespace))
+ catalog_api.drop_namespace(
+ prefix=self.catalog,
namespace=UNIT_SEPARATOR.join(self.namespace)
+ )
elif self.namespaces_subcommand == Subcommands.GET:
- print(catalog_api.load_namespace_metadata(
- prefix=self.catalog,
- namespace=UNIT_SEPARATOR.join(self.namespace)).to_json())
+ print(
+ catalog_api.load_namespace_metadata(
+ prefix=self.catalog,
namespace=UNIT_SEPARATOR.join(self.namespace)
+ ).to_json()
+ )
else:
raise Exception(f"{self.namespaces_subcommand} is not supported in
the CLI")
diff --git a/client/python/cli/command/principal_roles.py
b/client/python/cli/command/principal_roles.py
index 911f741f5..8dd48bb74 100644
--- a/client/python/cli/command/principal_roles.py
+++ b/client/python/cli/command/principal_roles.py
@@ -24,8 +24,13 @@ from pydantic import StrictStr
from cli.command import Command
from cli.constants import Subcommands, Arguments
from cli.options.option_tree import Argument
-from polaris.management import PolarisDefaultApi, CreatePrincipalRoleRequest,
PrincipalRole, UpdatePrincipalRoleRequest, \
- GrantPrincipalRoleRequest
+from polaris.management import (
+ PolarisDefaultApi,
+ CreatePrincipalRoleRequest,
+ PrincipalRole,
+ UpdatePrincipalRoleRequest,
+ GrantPrincipalRoleRequest,
+)
@dataclass
@@ -52,19 +57,22 @@ class PrincipalRolesCommand(Command):
def validate(self):
if self.principal_roles_subcommand == Subcommands.LIST:
if self.principal_name and self.catalog_role_name:
- raise Exception(f'You may provide either
{Argument.to_flag_name(Arguments.PRINCIPAL)} or'
- f'
{Argument.to_flag_name(Arguments.CATALOG_ROLE)}, but not both')
+ raise Exception(
+ f"You may provide either
{Argument.to_flag_name(Arguments.PRINCIPAL)} or"
+ f" {Argument.to_flag_name(Arguments.CATALOG_ROLE)}, but
not both"
+ )
if self.principal_roles_subcommand in {Subcommands.GRANT,
Subcommands.REVOKE}:
if not self.principal_name:
- raise Exception(f'Missing required argument for
{self.principal_roles_subcommand}:'
- f'
{Argument.to_flag_name(Arguments.PRINCIPAL)}')
+ raise Exception(
+ f"Missing required argument for
{self.principal_roles_subcommand}:"
+ f" {Argument.to_flag_name(Arguments.PRINCIPAL)}"
+ )
def execute(self, api: PolarisDefaultApi) -> None:
if self.principal_roles_subcommand == Subcommands.CREATE:
request = CreatePrincipalRoleRequest(
principal_role=PrincipalRole(
- name=self.principal_role_name,
- properties=self.properties
+ name=self.principal_role_name, properties=self.properties
)
)
api.create_principal_role(request)
@@ -74,10 +82,14 @@ class PrincipalRolesCommand(Command):
print(api.get_principal_role(self.principal_role_name).to_json())
elif self.principal_roles_subcommand == Subcommands.LIST:
if self.catalog_role_name:
- for principal_role in
api.list_principal_roles(self.catalog_role_name).roles:
+ for principal_role in api.list_principal_roles(
+ self.catalog_role_name
+ ).roles:
print(principal_role.to_json())
elif self.principal_name:
- for principal_role in
api.list_principal_roles_assigned(self.principal_name).roles:
+ for principal_role in api.list_principal_roles_assigned(
+ self.principal_name
+ ).roles:
print(principal_role.to_json())
else:
for principal_role in api.list_principal_roles().roles:
@@ -97,17 +109,17 @@ class PrincipalRolesCommand(Command):
request = UpdatePrincipalRoleRequest(
current_entity_version=principal_role.entity_version,
- properties=new_properties
+ properties=new_properties,
)
api.update_principal_role(self.principal_role_name, request)
elif self.principal_roles_subcommand == Subcommands.GRANT:
request = GrantPrincipalRoleRequest(
- principal_role=PrincipalRole(
- name=self.principal_role_name
- ),
+ principal_role=PrincipalRole(name=self.principal_role_name),
)
api.assign_principal_role(self.principal_name, request)
elif self.principal_roles_subcommand == Subcommands.REVOKE:
api.revoke_principal_role(self.principal_name,
self.principal_role_name)
else:
- raise Exception(f"{self.principal_roles_subcommand} is not
supported in the CLI")
+ raise Exception(
+ f"{self.principal_roles_subcommand} is not supported in the
CLI"
+ )
diff --git a/client/python/cli/command/principals.py
b/client/python/cli/command/principals.py
index a25c2a0c1..58779f77d 100644
--- a/client/python/cli/command/principals.py
+++ b/client/python/cli/command/principals.py
@@ -24,7 +24,13 @@ from pydantic import StrictStr
from cli.command import Command
from cli.constants import Subcommands
-from polaris.management import PolarisDefaultApi, CreatePrincipalRequest,
Principal, PrincipalWithCredentials, UpdatePrincipalRequest
+from polaris.management import (
+ PolarisDefaultApi,
+ CreatePrincipalRequest,
+ Principal,
+ PrincipalWithCredentials,
+ UpdatePrincipalRequest,
+)
@dataclass
@@ -52,23 +58,40 @@ class PrincipalsCommand(Command):
def _get_catalogs(self, api: PolarisDefaultApi):
for catalog in api.list_catalogs().catalogs:
- yield catalog.to_dict()['name']
-
+ yield catalog.to_dict()["name"]
+
def _get_principal_roles(self, api: PolarisDefaultApi):
- for principal_role in
api.list_principal_roles_assigned(self.principal_name).roles:
- yield principal_role.to_dict()['name']
-
- def _get_catalog_roles(self, api: PolarisDefaultApi, principal_role_name:
str, catalog_name: str):
- for catalog_role in
api.list_catalog_roles_for_principal_role(principal_role_name,
catalog_name).roles:
- yield catalog_role.to_dict()['name']
-
- def _get_privileges(self, api: PolarisDefaultApi, catalog_name: str,
catalog_role_name: str):
- for grant in api.list_grants_for_catalog_role(catalog_name,
catalog_role_name).grants:
+ for principal_role in api.list_principal_roles_assigned(
+ self.principal_name
+ ).roles:
+ yield principal_role.to_dict()["name"]
+
+ def _get_catalog_roles(
+ self, api: PolarisDefaultApi, principal_role_name: str, catalog_name:
str
+ ):
+ for catalog_role in api.list_catalog_roles_for_principal_role(
+ principal_role_name, catalog_name
+ ).roles:
+ yield catalog_role.to_dict()["name"]
+
+ def _get_privileges(
+ self, api: PolarisDefaultApi, catalog_name: str, catalog_role_name: str
+ ):
+ for grant in api.list_grants_for_catalog_role(
+ catalog_name, catalog_role_name
+ ).grants:
yield grant.to_dict()
- def build_credential_json(self, principal_with_credentials:
PrincipalWithCredentials):
+ def build_credential_json(
+ self, principal_with_credentials: PrincipalWithCredentials
+ ):
credentials = principal_with_credentials.credentials
- return json.dumps({"clientId": credentials.client_id, "clientSecret":
credentials.client_secret.get_secret_value()})
+ return json.dumps(
+ {
+ "clientId": credentials.client_id,
+ "clientSecret": credentials.client_secret.get_secret_value(),
+ }
+ )
def validate(self):
pass
@@ -80,7 +103,7 @@ class PrincipalsCommand(Command):
type=self.type.upper(),
name=self.principal_name,
client_id=self.client_id,
- properties=self.properties
+ properties=self.properties,
)
)
print(self.build_credential_json(api.create_principal(request)))
@@ -90,13 +113,17 @@ class PrincipalsCommand(Command):
print(api.get_principal(self.principal_name).to_json())
elif self.principals_subcommand == Subcommands.LIST:
if self.principal_role:
- for principal in
api.list_assignee_principals_for_principal_role(self.principal_role).principals:
+ for principal in
api.list_assignee_principals_for_principal_role(
+ self.principal_role
+ ).principals:
print(principal.to_json())
else:
for principal in api.list_principals().principals:
print(principal.to_json())
elif self.principals_subcommand == Subcommands.ROTATE_CREDENTIALS:
-
print(self.build_credential_json(api.rotate_credentials(self.principal_name)))
+ print(
+
self.build_credential_json(api.rotate_credentials(self.principal_name))
+ )
elif self.principals_subcommand == Subcommands.UPDATE:
principal = api.get_principal(self.principal_name)
new_properties = principal.properties or {}
@@ -112,37 +139,37 @@ class PrincipalsCommand(Command):
request = UpdatePrincipalRequest(
current_entity_version=principal.entity_version,
- properties=new_properties
+ properties=new_properties,
)
api.update_principal(self.principal_name, request)
elif self.principals_subcommand == Subcommands.ACCESS:
- principal =
api.get_principal(self.principal_name).to_dict()['name']
+ principal =
api.get_principal(self.principal_name).to_dict()["name"]
principal_roles = self._get_principal_roles(api)
# Initialize the result structure
- result = {
- 'principal': principal,
- 'principal_roles': []
- }
-
+ result = {"principal": principal, "principal_roles": []}
+
# Construct the result structure for each principal role
for principal_role in principal_roles:
- role_data = {
- 'name': principal_role,
- 'catalog_roles': []
- }
+ role_data = {"name": principal_role, "catalog_roles": []}
# For each catalog role, get associated privileges
for catalog in self._get_catalogs(api):
- catalog_roles = self._get_catalog_roles(api,
principal_role, catalog)
+ catalog_roles = self._get_catalog_roles(
+ api, principal_role, catalog
+ )
for catalog_role in catalog_roles:
catalog_data = {
- 'name': catalog_role,
- 'catalog': catalog,
- 'privileges': []
+ "name": catalog_role,
+ "catalog": catalog,
+ "privileges": [],
}
- catalog_data['privileges'] =
list(self._get_privileges(api, catalog_data['catalog'], catalog_role))
- role_data['catalog_roles'].append(catalog_data)
- result['principal_roles'].append(role_data)
+ catalog_data["privileges"] = list(
+ self._get_privileges(
+ api, catalog_data["catalog"], catalog_role
+ )
+ )
+ role_data["catalog_roles"].append(catalog_data)
+ result["principal_roles"].append(role_data)
print(json.dumps(result))
else:
raise Exception(f"{self.principals_subcommand} is not supported in
the CLI")
diff --git a/client/python/cli/command/privileges.py
b/client/python/cli/command/privileges.py
index c7db21555..6cd19913f 100644
--- a/client/python/cli/command/privileges.py
+++ b/client/python/cli/command/privileges.py
@@ -24,9 +24,19 @@ from pydantic import StrictStr
from cli.command import Command
from cli.constants import Subcommands, Actions, Arguments
from cli.options.option_tree import Argument
-from polaris.management import PolarisDefaultApi, AddGrantRequest,
NamespaceGrant, \
- RevokeGrantRequest, CatalogGrant, TableGrant, ViewGrant, CatalogPrivilege,
NamespacePrivilege, TablePrivilege, \
- ViewPrivilege
+from polaris.management import (
+ PolarisDefaultApi,
+ AddGrantRequest,
+ NamespaceGrant,
+ RevokeGrantRequest,
+ CatalogGrant,
+ TableGrant,
+ ViewGrant,
+ CatalogPrivilege,
+ NamespacePrivilege,
+ TablePrivilege,
+ ViewPrivilege,
+)
@dataclass
@@ -54,75 +64,87 @@ class PrivilegesCommand(Command):
def validate(self):
if not self.catalog_name:
- raise Exception(f'Missing required argument:
{Argument.to_flag_name(Arguments.CATALOG)}')
+ raise Exception(
+ f"Missing required argument:
{Argument.to_flag_name(Arguments.CATALOG)}"
+ )
if not self.catalog_role_name:
- raise Exception(f'Missing required argument:
{Argument.to_flag_name(Arguments.CATALOG_ROLE)}')
+ raise Exception(
+ f"Missing required argument:
{Argument.to_flag_name(Arguments.CATALOG_ROLE)}"
+ )
if not self.privileges_subcommand:
- raise Exception('A subcommand must be provided')
- if (self.privileges_subcommand in {Subcommands.NAMESPACE,
Subcommands.TABLE, Subcommands.VIEW}
- and not self.namespace):
- raise Exception(f'Missing required argument:
{Argument.to_flag_name(Arguments.NAMESPACE)}')
+ raise Exception("A subcommand must be provided")
+ if (
+ self.privileges_subcommand
+ in {Subcommands.NAMESPACE, Subcommands.TABLE, Subcommands.VIEW}
+ and not self.namespace
+ ):
+ raise Exception(
+ f"Missing required argument:
{Argument.to_flag_name(Arguments.NAMESPACE)}"
+ )
if self.action == Actions.GRANT and self.cascade:
- raise Exception('Unrecognized argument for GRANT: --cascade')
+ raise Exception("Unrecognized argument for GRANT: --cascade")
if self.privileges_subcommand == Subcommands.CATALOG:
if self.privilege not in {i.value for i in CatalogPrivilege}:
- raise Exception(f'Invalid catalog privilege: {self.privilege}')
+ raise Exception(f"Invalid catalog privilege: {self.privilege}")
if self.privileges_subcommand == Subcommands.NAMESPACE:
if self.privilege not in {i.value for i in NamespacePrivilege}:
- raise Exception(f'Invalid namespace privilege:
{self.privilege}')
+ raise Exception(f"Invalid namespace privilege:
{self.privilege}")
if self.privileges_subcommand == Subcommands.TABLE:
if self.privilege not in {i.value for i in TablePrivilege}:
- raise Exception(f'Invalid table privilege: {self.privilege}')
+ raise Exception(f"Invalid table privilege: {self.privilege}")
if self.privileges_subcommand == Subcommands.VIEW:
if self.privilege not in {i.value for i in ViewPrivilege}:
- raise Exception(f'Invalid view privilege: {self.privilege}')
+ raise Exception(f"Invalid view privilege: {self.privilege}")
def execute(self, api: PolarisDefaultApi) -> None:
if self.privileges_subcommand == Subcommands.LIST:
- for grant in api.list_grants_for_catalog_role(self.catalog_name,
self.catalog_role_name).grants:
+ for grant in api.list_grants_for_catalog_role(
+ self.catalog_name, self.catalog_role_name
+ ).grants:
print(grant.to_json())
else:
grant = None
if self.privileges_subcommand == Subcommands.CATALOG:
grant = CatalogGrant(
- type=Subcommands.CATALOG,
- privilege=CatalogPrivilege(self.privilege)
+ type=Subcommands.CATALOG,
privilege=CatalogPrivilege(self.privilege)
)
elif self.privileges_subcommand == Subcommands.NAMESPACE:
grant = NamespaceGrant(
type=Subcommands.NAMESPACE,
namespace=self.namespace,
- privilege=NamespacePrivilege(self.privilege)
+ privilege=NamespacePrivilege(self.privilege),
)
elif self.privileges_subcommand == Subcommands.TABLE:
grant = TableGrant(
type=Subcommands.TABLE,
namespace=self.namespace,
table_name=self.table,
- privilege=TablePrivilege(self.privilege)
+ privilege=TablePrivilege(self.privilege),
)
elif self.privileges_subcommand == Subcommands.VIEW:
grant = ViewGrant(
type=Subcommands.VIEW,
namespace=self.namespace,
view_name=self.view,
- privilege=ViewPrivilege(self.privilege)
+ privilege=ViewPrivilege(self.privilege),
)
if not grant:
- raise Exception(f'{self.privileges_subcommand} is not
supported in the CLI')
+ raise Exception(
+ f"{self.privileges_subcommand} is not supported in the CLI"
+ )
elif self.action == Actions.GRANT:
- request = AddGrantRequest(
- grant=grant
+ request = AddGrantRequest(grant=grant)
+ api.add_grant_to_catalog_role(
+ self.catalog_name, self.catalog_role_name, request
)
- api.add_grant_to_catalog_role(self.catalog_name,
self.catalog_role_name, request)
elif self.action == Actions.REVOKE:
- request = RevokeGrantRequest(
- grant=grant
+ request = RevokeGrantRequest(grant=grant)
+ api.revoke_grant_from_catalog_role(
+ self.catalog_name, self.catalog_role_name, self.cascade,
request
)
- api.revoke_grant_from_catalog_role(self.catalog_name,
self.catalog_role_name, self.cascade, request)
else:
- raise Exception(f'{self.action} is not supported in the CLI')
+ raise Exception(f"{self.action} is not supported in the CLI")
diff --git a/client/python/cli/command/profiles.py
b/client/python/cli/command/profiles.py
index 8679907b0..fc689ae2b 100644
--- a/client/python/cli/command/profiles.py
+++ b/client/python/cli/command/profiles.py
@@ -24,7 +24,13 @@ from typing import Dict, Optional, List
from cli.command import Command
-from cli.constants import Subcommands, DEFAULT_HOSTNAME, DEFAULT_PORT,
CONFIG_DIR, CONFIG_FILE
+from cli.constants import (
+ Subcommands,
+ DEFAULT_HOSTNAME,
+ DEFAULT_PORT,
+ CONFIG_DIR,
+ CONFIG_FILE,
+)
from polaris.management import PolarisDefaultApi
@@ -61,20 +67,20 @@ class ProfilesCommand(Command):
def _create_profile(self, name: str) -> None:
profiles = self._load_profiles()
if name not in profiles:
- client_id = input("Polaris Client ID: ")
- client_secret = input("Polaris Client Secret: ")
- host = input(f"Polaris Host [{DEFAULT_HOSTNAME}]: ") or
DEFAULT_HOSTNAME
- port = input(f"Polaris Port [{DEFAULT_PORT}]: ") or DEFAULT_PORT
- profiles[name] = {
- "client_id": client_id,
- "client_secret": client_secret,
- "host": host,
- "port": port
- }
- self._save_profiles(profiles)
+ client_id = input("Polaris Client ID: ")
+ client_secret = input("Polaris Client Secret: ")
+ host = input(f"Polaris Host [{DEFAULT_HOSTNAME}]: ") or
DEFAULT_HOSTNAME
+ port = input(f"Polaris Port [{DEFAULT_PORT}]: ") or DEFAULT_PORT
+ profiles[name] = {
+ "client_id": client_id,
+ "client_secret": client_secret,
+ "host": host,
+ "port": port,
+ }
+ self._save_profiles(profiles)
else:
- print(f"Profile {name} already exists.")
- sys.exit(1)
+ print(f"Profile {name} already exists.")
+ sys.exit(1)
def _get_profile(self, name: str) -> Optional[Dict[str, str]]:
profiles = self._load_profiles()
@@ -98,15 +104,20 @@ class ProfilesCommand(Command):
current_host = profiles[name].get("host")
current_port = profiles[name].get("port")
- client_id = input(f"Polaris Client ID [{current_client_id}]: ") or
current_client_id
- client_secret = input(f"Polaris Client Secret
[{current_client_secret}]: ") or current_client_secret
+ client_id = (
+ input(f"Polaris Client ID [{current_client_id}]: ") or
current_client_id
+ )
+ client_secret = (
+ input(f"Polaris Client Secret [{current_client_secret}]: ")
+ or current_client_secret
+ )
host = input(f"Polaris Client ID [{current_host}]: ") or
current_host
port = input(f"Polaris Client Secret [{current_port}]: ") or
current_port
profiles[name] = {
"client_id": client_id,
"client_secret": client_secret,
"host": host,
- "port": port
+ "port": port,
}
self._save_profiles(profiles)
else:
@@ -125,7 +136,7 @@ class ProfilesCommand(Command):
print(f"Polaris profile {self.profile_name} deleted successfully.")
elif self.profiles_subcommand == Subcommands.UPDATE:
self._update_profile(self.profile_name)
- print(f"Polaris profile {self.profile_name} updated
successfully.")
+ print(f"Polaris profile {self.profile_name} updated successfully.")
elif self.profiles_subcommand == Subcommands.GET:
profile = self._get_profile(self.profile_name)
if profile:
diff --git a/client/python/cli/constants.py b/client/python/cli/constants.py
index c9f28ba3c..91fff0dc0 100644
--- a/client/python/cli/constants.py
+++ b/client/python/cli/constants.py
@@ -25,10 +25,10 @@ class StorageType(Enum):
Represents a Storage Type within the Polaris API -- `s3`, `azure`, `gcs`,
or `file`.
"""
- S3 = 's3'
- AZURE = 'azure'
- GCS = 'gcs'
- FILE = 'file'
+ S3 = "s3"
+ AZURE = "azure"
+ GCS = "gcs"
+ FILE = "file"
class CatalogType(Enum):
@@ -36,8 +36,8 @@ class CatalogType(Enum):
Represents a Catalog Type within the Polaris API -- `internal` or
`external`
"""
- INTERNAL = 'internal'
- EXTERNAL = 'external'
+ INTERNAL = "internal"
+ EXTERNAL = "external"
class PrincipalType(Enum):
@@ -45,7 +45,7 @@ class PrincipalType(Enum):
Represents a Principal Type within the Polaris API -- currently only
`service`
"""
- SERVICE = 'service'
+ SERVICE = "service"
class Commands:
@@ -53,13 +53,13 @@ class Commands:
Represents the various commands available in the CLI
"""
- CATALOGS = 'catalogs'
- PRINCIPALS = 'principals'
- PRINCIPAL_ROLES = 'principal-roles'
- CATALOG_ROLES = 'catalog-roles'
- PRIVILEGES = 'privileges'
- NAMESPACES = 'namespaces'
- PROFILES = 'profiles'
+ CATALOGS = "catalogs"
+ PRINCIPALS = "principals"
+ PRINCIPAL_ROLES = "principal-roles"
+ CATALOG_ROLES = "catalog-roles"
+ PRIVILEGES = "privileges"
+ NAMESPACES = "namespaces"
+ PROFILES = "profiles"
class Subcommands:
@@ -68,19 +68,19 @@ class Subcommands:
all these subcommands.
"""
- CREATE = 'create'
- DELETE = 'delete'
- GET = 'get'
- LIST = 'list'
- UPDATE = 'update'
- ROTATE_CREDENTIALS = 'rotate-credentials'
- CATALOG = 'catalog'
- NAMESPACE = 'namespace'
- TABLE = 'table'
- VIEW = 'view'
- GRANT = 'grant'
- REVOKE = 'revoke'
- ACCESS = 'access'
+ CREATE = "create"
+ DELETE = "delete"
+ GET = "get"
+ LIST = "list"
+ UPDATE = "update"
+ ROTATE_CREDENTIALS = "rotate-credentials"
+ CATALOG = "catalog"
+ NAMESPACE = "namespace"
+ TABLE = "table"
+ VIEW = "view"
+ GRANT = "grant"
+ REVOKE = "revoke"
+ ACCESS = "access"
class Actions:
@@ -89,8 +89,8 @@ class Actions:
`privileges` command support actions.
"""
- GRANT = 'grant'
- REVOKE = 'revoke'
+ GRANT = "grant"
+ REVOKE = "revoke"
class Arguments:
@@ -102,40 +102,40 @@ class Arguments:
These values should be snake_case, but they will get mapped to kebab-case
in `Parser.parse`
"""
- TYPE = 'type'
- DEFAULT_BASE_LOCATION = 'default_base_location'
- STORAGE_TYPE = 'storage_type'
- ALLOWED_LOCATION = 'allowed_location'
- ROLE_ARN = 'role_arn'
- EXTERNAL_ID = 'external_id'
- USER_ARN = 'user_arn'
- TENANT_ID = 'tenant_id'
- MULTI_TENANT_APP_NAME = 'multi_tenant_app_name'
- CONSENT_URL = 'consent_url'
- SERVICE_ACCOUNT = 'service_account'
- CATALOG_ROLE = 'catalog_role'
- CATALOG = 'catalog'
- PRINCIPAL = 'principal'
- CLIENT_ID = 'client_id'
- PRINCIPAL_ROLE = 'principal_role'
- PROPERTY = 'property'
- SET_PROPERTY = 'set_property'
- REMOVE_PROPERTY = 'remove_property'
- PRIVILEGE = 'privilege'
- NAMESPACE = 'namespace'
- TABLE = 'table'
- VIEW = 'view'
- CASCADE = 'cascade'
- CLIENT_SECRET = 'client_secret'
- ACCESS_TOKEN = 'access_token'
- HOST = 'host'
- PORT = 'port'
- BASE_URL = 'base_url'
- PARENT = 'parent'
- LOCATION = 'location'
- REGION = 'region'
- PROFILE = 'profile'
- PROXY = 'proxy'
+ TYPE = "type"
+ DEFAULT_BASE_LOCATION = "default_base_location"
+ STORAGE_TYPE = "storage_type"
+ ALLOWED_LOCATION = "allowed_location"
+ ROLE_ARN = "role_arn"
+ EXTERNAL_ID = "external_id"
+ USER_ARN = "user_arn"
+ TENANT_ID = "tenant_id"
+ MULTI_TENANT_APP_NAME = "multi_tenant_app_name"
+ CONSENT_URL = "consent_url"
+ SERVICE_ACCOUNT = "service_account"
+ CATALOG_ROLE = "catalog_role"
+ CATALOG = "catalog"
+ PRINCIPAL = "principal"
+ CLIENT_ID = "client_id"
+ PRINCIPAL_ROLE = "principal_role"
+ PROPERTY = "property"
+ SET_PROPERTY = "set_property"
+ REMOVE_PROPERTY = "remove_property"
+ PRIVILEGE = "privilege"
+ NAMESPACE = "namespace"
+ TABLE = "table"
+ VIEW = "view"
+ CASCADE = "cascade"
+ CLIENT_SECRET = "client_secret"
+ ACCESS_TOKEN = "access_token"
+ HOST = "host"
+ PORT = "port"
+ BASE_URL = "base_url"
+ PARENT = "parent"
+ LOCATION = "location"
+ REGION = "region"
+ PROFILE = "profile"
+ PROXY = "proxy"
class Hints:
@@ -145,97 +145,119 @@ class Hints:
parameter used by `catalog-roles create` and `catalog-roles delete` may be
the same.
"""
- PROPERTY = ('A key/value pair such as: tag=value. Multiple can be provided
by specifying this option'
- ' more than once')
- SET_PROPERTY = ('A key/value pair such as: tag=value. Merges the specified
key/value into an existing'
- ' properties map by updating the value if the key already
exists or creating a new'
- ' entry if not. Multiple can be provided by specifying
this option more than once')
- REMOVE_PROPERTY = ('A key to remove from a properties map. If the key
already does not exist then'
- ' no action is takn for the specified key. If
properties are also being set in'
- ' the same update command then the list of removals is
applied last. Multiple'
- ' can be provided by specifying this option more than
once')
+ PROPERTY = (
+ "A key/value pair such as: tag=value. Multiple can be provided by
specifying this option"
+ " more than once"
+ )
+ SET_PROPERTY = (
+ "A key/value pair such as: tag=value. Merges the specified key/value
into an existing"
+ " properties map by updating the value if the key already exists or
creating a new"
+ " entry if not. Multiple can be provided by specifying this option
more than once"
+ )
+ REMOVE_PROPERTY = (
+ "A key to remove from a properties map. If the key already does not
exist then"
+ " no action is takn for the specified key. If properties are also
being set in"
+ " the same update command then the list of removals is applied last.
Multiple"
+ " can be provided by specifying this option more than once"
+ )
class Catalogs:
- GRANT = 'Grant a catalog role to a catalog'
- REVOKE = 'Revoke a catalog role from a catalog'
+ GRANT = "Grant a catalog role to a catalog"
+ REVOKE = "Revoke a catalog role from a catalog"
class Create:
- TYPE = 'The type of catalog to create in [INTERNAL, EXTERNAL].
INTERNAL by default.'
- DEFAULT_BASE_LOCATION = '(Required) Default base location of the
catalog'
- STORAGE_TYPE = '(Required) The type of storage to use for the
catalog'
- ALLOWED_LOCATION = ('An allowed location for files tracked by the
catalog. '
- 'Multiple locations can be provided by
specifying this option more than once.')
-
- ROLE_ARN = '(Required for S3) A role ARN to use when connecting to
S3'
- EXTERNAL_ID = '(Only for S3) The external ID to use when
connecting to S3'
- REGION = '(Only for S3) The region to use when connecting to S3'
- USER_ARN = '(Only for S3) A user ARN to use when connecting to S3'
-
- TENANT_ID = '(Required for Azure) A tenant ID to use when
connecting to Azure Storage'
- MULTI_TENANT_APP_NAME = '(Only for Azure) The app name to use when
connecting to Azure Storage'
- CONSENT_URL = '(Only for Azure) A consent URL granting permissions
for the Azure Storage location'
-
- SERVICE_ACCOUNT = '(Only for GCS) The service account to use when
connecting to GCS'
+ TYPE = "The type of catalog to create in [INTERNAL, EXTERNAL].
INTERNAL by default."
+ DEFAULT_BASE_LOCATION = "(Required) Default base location of the
catalog"
+ STORAGE_TYPE = "(Required) The type of storage to use for the
catalog"
+ ALLOWED_LOCATION = (
+ "An allowed location for files tracked by the catalog. "
+ "Multiple locations can be provided by specifying this option
more than once."
+ )
+
+ ROLE_ARN = "(Required for S3) A role ARN to use when connecting to
S3"
+ EXTERNAL_ID = "(Only for S3) The external ID to use when
connecting to S3"
+ REGION = "(Only for S3) The region to use when connecting to S3"
+ USER_ARN = "(Only for S3) A user ARN to use when connecting to S3"
+
+ TENANT_ID = "(Required for Azure) A tenant ID to use when
connecting to Azure Storage"
+ MULTI_TENANT_APP_NAME = (
+ "(Only for Azure) The app name to use when connecting to Azure
Storage"
+ )
+ CONSENT_URL = "(Only for Azure) A consent URL granting permissions
for the Azure Storage location"
+
+ SERVICE_ACCOUNT = (
+ "(Only for GCS) The service account to use when connecting to
GCS"
+ )
class Update:
- DEFAULT_BASE_LOCATION = 'A new default base location for the
catalog'
+ DEFAULT_BASE_LOCATION = "A new default base location for the
catalog"
class Principals:
class Create:
- TYPE = 'The type of principal to create in [SERVICE]'
- NAME = 'The principal name'
- CLIENT_ID = 'The output-only OAuth clientId associated with this
principal if applicable'
+ TYPE = "The type of principal to create in [SERVICE]"
+ NAME = "The principal name"
+ CLIENT_ID = "The output-only OAuth clientId associated with this
principal if applicable"
class Revoke:
- PRINCIPAL_ROLE = 'A principal role to revoke from this principal'
+ PRINCIPAL_ROLE = "A principal role to revoke from this principal"
class PrincipalRoles:
- PRINCIPAL_ROLE = 'The name of a principal role'
- LIST = 'List principal roles, optionally limited to those held a given
principal'
+ PRINCIPAL_ROLE = "The name of a principal role"
+ LIST = (
+ "List principal roles, optionally limited to those held a given
principal"
+ )
- GRANT = 'Grant a principal role to a principal'
- REVOKE = 'Revoke a principal role from a principal'
+ GRANT = "Grant a principal role to a principal"
+ REVOKE = "Revoke a principal role from a principal"
class Grant:
- PRINCIPAL = 'A principal to grant this principal role to'
+ PRINCIPAL = "A principal to grant this principal role to"
class Revoke:
- PRINCIPAL = 'A principal to revoke this principal role from'
+ PRINCIPAL = "A principal to revoke this principal role from"
class List:
- CATALOG_ROLE = ('The name of a catalog role. If provided, show
only principal roles assigned to this'
- ' catalog role.')
- PRINCIPAL_NAME = ('The name of a principal. If provided, show only
principal roles assigned to this'
- ' principal.')
+ CATALOG_ROLE = (
+ "The name of a catalog role. If provided, show only principal
roles assigned to this"
+ " catalog role."
+ )
+ PRINCIPAL_NAME = (
+ "The name of a principal. If provided, show only principal
roles assigned to this"
+ " principal."
+ )
class CatalogRoles:
- CATALOG_NAME = 'The name of an existing catalog'
- CATALOG_ROLE = 'The name of a catalog role'
- LIST = 'List catalog roles within a catalog. Optionally, specify a
principal role.'
- REVOKE_CATALOG_ROLE = 'Revoke a catalog role from a principal role'
- GRANT_CATALOG_ROLE = 'Grant a catalog role to a principal role'
+ CATALOG_NAME = "The name of an existing catalog"
+ CATALOG_ROLE = "The name of a catalog role"
+ LIST = (
+ "List catalog roles within a catalog. Optionally, specify a
principal role."
+ )
+ REVOKE_CATALOG_ROLE = "Revoke a catalog role from a principal role"
+ GRANT_CATALOG_ROLE = "Grant a catalog role to a principal role"
class Grant:
- CATALOG_NAME = 'The name of a catalog'
- CATALOG_ROLE = 'The name of a catalog role'
- PRIVILEGE = 'The privilege to grant or revoke'
- NAMESPACE = 'A period-delimited namespace'
- TABLE = 'The name of a table'
- VIEW = 'The name of a view'
- CASCADE = 'When revoking privileges, additionally revoke privileges
that depend on the specified privilege'
+ CATALOG_NAME = "The name of a catalog"
+ CATALOG_ROLE = "The name of a catalog role"
+ PRIVILEGE = "The privilege to grant or revoke"
+ NAMESPACE = "A period-delimited namespace"
+ TABLE = "The name of a table"
+ VIEW = "The name of a view"
+ CASCADE = "When revoking privileges, additionally revoke privileges
that depend on the specified privilege"
class Namespaces:
- LOCATION = 'If specified, the location at which to store the namespace
and entities inside it'
- PARENT = 'If specified, list namespaces inside this parent namespace'
+ LOCATION = "If specified, the location at which to store the namespace
and entities inside it"
+ PARENT = "If specified, list namespaces inside this parent namespace"
UNIT_SEPARATOR = chr(0x1F)
-CLIENT_ID_ENV = 'CLIENT_ID'
-CLIENT_SECRET_ENV = 'CLIENT_SECRET'
-CLIENT_PROFILE_ENV = 'CLIENT_PROFILE'
-DEFAULT_HOSTNAME = 'localhost'
+CLIENT_ID_ENV = "CLIENT_ID"
+CLIENT_SECRET_ENV = "CLIENT_SECRET"
+CLIENT_PROFILE_ENV = "CLIENT_PROFILE"
+DEFAULT_HOSTNAME = "localhost"
DEFAULT_PORT = 8181
-CONFIG_DIR = os.environ.get('SCRIPT_DIR')
+CONFIG_DIR = os.environ.get("SCRIPT_DIR")
if CONFIG_DIR is None:
- raise Exception("The SCRIPT_DIR environment variable is not set. Please
set it to the Polaris's script directory.")
-CONFIG_FILE = os.path.join(CONFIG_DIR, '.polaris.json')
+ raise Exception(
+ "The SCRIPT_DIR environment variable is not set. Please set it to the
Polaris's script directory."
+ )
+CONFIG_FILE = os.path.join(CONFIG_DIR, ".polaris.json")
diff --git a/client/python/cli/options/option_tree.py
b/client/python/cli/options/option_tree.py
index f926230e1..aaec9476d 100644
--- a/client/python/cli/options/option_tree.py
+++ b/client/python/cli/options/option_tree.py
@@ -19,7 +19,16 @@
from dataclasses import dataclass, field
from typing import List
-from cli.constants import StorageType, CatalogType, PrincipalType, Hints,
Commands, Arguments, Subcommands, Actions
+from cli.constants import (
+ StorageType,
+ CatalogType,
+ PrincipalType,
+ Hints,
+ Commands,
+ Arguments,
+ Subcommands,
+ Actions,
+)
@dataclass
@@ -37,18 +46,19 @@ class Argument:
default: object = None
def __post_init__(self):
- if self.name.startswith('--'):
- raise Exception(f'Argument name {self.name} starts with `--`:
should this be a flag_name?')
+ if self.name.startswith("--"):
+ raise Exception(
+ f"Argument name {self.name} starts with `--`: should this be a
flag_name?"
+ )
@staticmethod
def to_flag_name(argument_name):
- return '--' + argument_name.replace('_', '-')
+ return "--" + argument_name.replace("_", "-")
def get_flag_name(self):
return Argument.to_flag_name(self.name)
-
@dataclass
class Option:
"""
@@ -60,7 +70,7 @@ class Option:
hint: str = None
input_name: str = None
args: List[Argument] = field(default_factory=list)
- children: List['Option'] = field(default_factory=list)
+ children: List["Option"] = field(default_factory=list)
class OptionTree:
@@ -71,171 +81,537 @@ class OptionTree:
_CATALOG_ROLE_AND_CATALOG = [
Argument(Arguments.CATALOG, str, Hints.CatalogRoles.CATALOG_NAME),
- Argument(Arguments.CATALOG_ROLE, str, Hints.CatalogRoles.CATALOG_ROLE)
+ Argument(Arguments.CATALOG_ROLE, str, Hints.CatalogRoles.CATALOG_ROLE),
]
@staticmethod
def get_tree() -> List[Option]:
return [
- Option(Commands.CATALOGS, 'manage catalogs', children=[
- Option(Subcommands.CREATE, args=[
- Argument(Arguments.TYPE, str, Hints.Catalogs.Create.TYPE,
lower=True,
- choices=[ct.value for ct in CatalogType],
default=CatalogType.INTERNAL.value),
- Argument(Arguments.STORAGE_TYPE, str,
Hints.Catalogs.Create.STORAGE_TYPE, lower=True,
- choices=[st.value for st in StorageType]),
- Argument(Arguments.DEFAULT_BASE_LOCATION, str,
Hints.Catalogs.Create.DEFAULT_BASE_LOCATION),
- Argument(Arguments.ALLOWED_LOCATION, str,
Hints.Catalogs.Create.ALLOWED_LOCATION,
- allow_repeats=True),
- Argument(Arguments.ROLE_ARN, str,
Hints.Catalogs.Create.ROLE_ARN),
- Argument(Arguments.REGION, str,
Hints.Catalogs.Create.REGION),
- Argument(Arguments.EXTERNAL_ID, str,
Hints.Catalogs.Create.EXTERNAL_ID),
- Argument(Arguments.TENANT_ID, str,
Hints.Catalogs.Create.TENANT_ID),
- Argument(Arguments.MULTI_TENANT_APP_NAME, str,
Hints.Catalogs.Create.MULTI_TENANT_APP_NAME),
- Argument(Arguments.CONSENT_URL, str,
Hints.Catalogs.Create.CONSENT_URL),
- Argument(Arguments.SERVICE_ACCOUNT, str,
Hints.Catalogs.Create.SERVICE_ACCOUNT),
- Argument(Arguments.PROPERTY, str, Hints.PROPERTY,
allow_repeats=True),
- ], input_name=Arguments.CATALOG),
- Option(Subcommands.DELETE, input_name=Arguments.CATALOG),
- Option(Subcommands.GET, input_name=Arguments.CATALOG),
- Option(Subcommands.LIST, args=[
- Argument(Arguments.PRINCIPAL_ROLE, str,
Hints.PrincipalRoles.PRINCIPAL_ROLE)
- ]),
- Option(Subcommands.UPDATE, args=[
- Argument(Arguments.DEFAULT_BASE_LOCATION, str,
Hints.Catalogs.Update.DEFAULT_BASE_LOCATION),
- Argument(Arguments.ALLOWED_LOCATION, str,
Hints.Catalogs.Create.ALLOWED_LOCATION,
- allow_repeats=True),
- Argument(Arguments.REGION, str,
Hints.Catalogs.Create.REGION),
- Argument(Arguments.SET_PROPERTY, str, Hints.SET_PROPERTY,
allow_repeats=True),
- Argument(Arguments.REMOVE_PROPERTY, str,
Hints.REMOVE_PROPERTY, allow_repeats=True),
- ], input_name=Arguments.CATALOG)
- ]),
- Option(Commands.PRINCIPALS, 'manage principals', children=[
- Option(Subcommands.CREATE, args=[
- Argument(Arguments.TYPE, str,
Hints.Principals.Create.TYPE, lower=True,
- choices=[pt.value for pt in PrincipalType],
default=PrincipalType.SERVICE.value),
- Argument(Arguments.PROPERTY, str, Hints.PROPERTY,
allow_repeats=True)
- ], input_name=Arguments.PRINCIPAL),
- Option(Subcommands.DELETE, input_name=Arguments.PRINCIPAL),
- Option(Subcommands.GET, input_name=Arguments.PRINCIPAL),
- Option(Subcommands.LIST),
- Option(Subcommands.ROTATE_CREDENTIALS,
input_name=Arguments.PRINCIPAL),
- Option(Subcommands.UPDATE, args=[
- Argument(Arguments.SET_PROPERTY, str, Hints.SET_PROPERTY,
allow_repeats=True),
- Argument(Arguments.REMOVE_PROPERTY, str,
Hints.REMOVE_PROPERTY, allow_repeats=True),
- ], input_name=Arguments.PRINCIPAL),
- Option(Subcommands.ACCESS, input_name=Arguments.PRINCIPAL),
- ]),
- Option(Commands.PRINCIPAL_ROLES, 'manage principal roles',
children=[
- Option(Subcommands.CREATE, args=[
- Argument(Arguments.PROPERTY, str, Hints.PROPERTY,
allow_repeats=True)
- ], input_name=Arguments.PRINCIPAL_ROLE),
- Option(Subcommands.DELETE,
input_name=Arguments.PRINCIPAL_ROLE),
- Option(Subcommands.GET, input_name=Arguments.PRINCIPAL_ROLE),
- Option(Subcommands.LIST, hint=Hints.PrincipalRoles.LIST, args=[
- Argument(Arguments.CATALOG_ROLE, str,
Hints.PrincipalRoles.List.CATALOG_ROLE),
- Argument(Arguments.PRINCIPAL, str,
Hints.PrincipalRoles.List.PRINCIPAL_NAME)
- ]),
- Option(Subcommands.UPDATE, args=[
- Argument(Arguments.SET_PROPERTY, str, Hints.SET_PROPERTY,
allow_repeats=True),
- Argument(Arguments.REMOVE_PROPERTY, str,
Hints.REMOVE_PROPERTY, allow_repeats=True),
- ], input_name=Arguments.PRINCIPAL_ROLE),
- Option(Subcommands.GRANT, hint=Hints.PrincipalRoles.GRANT,
args=[
- Argument(Arguments.PRINCIPAL, str,
Hints.PrincipalRoles.Grant.PRINCIPAL)
- ], input_name=Arguments.PRINCIPAL_ROLE),
- Option(Subcommands.REVOKE, hint=Hints.PrincipalRoles.REVOKE,
args=[
- Argument(Arguments.PRINCIPAL, str,
Hints.PrincipalRoles.Revoke.PRINCIPAL)
- ], input_name=Arguments.PRINCIPAL_ROLE)
- ]),
- Option(Commands.CATALOG_ROLES, 'manage catalog roles', children=[
- Option(Subcommands.CREATE, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME),
- Argument(Arguments.PROPERTY, str, Hints.PROPERTY,
allow_repeats=True)
- ], input_name=Arguments.CATALOG_ROLE),
- Option(Subcommands.DELETE, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME),
- ], input_name=Arguments.CATALOG_ROLE),
- Option(Subcommands.GET, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME),
- ], input_name=Arguments.CATALOG_ROLE),
- Option(Subcommands.LIST, hint=Hints.CatalogRoles.LIST, args=[
- Argument(Arguments.PRINCIPAL_ROLE, str,
Hints.PrincipalRoles.PRINCIPAL_ROLE)
- ], input_name=Arguments.CATALOG),
- Option(Subcommands.UPDATE, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME),
- Argument(Arguments.SET_PROPERTY, str, Hints.SET_PROPERTY,
allow_repeats=True),
- Argument(Arguments.REMOVE_PROPERTY, str,
Hints.REMOVE_PROPERTY, allow_repeats=True),
- ], input_name=Arguments.CATALOG_ROLE),
- Option(Subcommands.GRANT,
hint=Hints.CatalogRoles.GRANT_CATALOG_ROLE, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME),
- Argument(Arguments.PRINCIPAL_ROLE, str,
Hints.CatalogRoles.CATALOG_ROLE)
- ], input_name=Arguments.CATALOG_ROLE),
- Option(Subcommands.REVOKE,
hint=Hints.CatalogRoles.GRANT_CATALOG_ROLE, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME),
- Argument(Arguments.PRINCIPAL_ROLE, str,
Hints.CatalogRoles.CATALOG_ROLE)
- ], input_name=Arguments.CATALOG_ROLE)
- ]),
- Option(Commands.PRIVILEGES, 'manage privileges for a catalog
role', children=[
- Option(Subcommands.LIST,
args=OptionTree._CATALOG_ROLE_AND_CATALOG),
- Option(Subcommands.CATALOG, children=[
- Option(Actions.GRANT,
args=OptionTree._CATALOG_ROLE_AND_CATALOG, input_name=Arguments.PRIVILEGE),
- Option(Actions.REVOKE, args=[
- Argument(Arguments.CASCADE, bool, Hints.Grant.CASCADE)
- ] + OptionTree._CATALOG_ROLE_AND_CATALOG,
input_name=Arguments.PRIVILEGE),
- ]),
- Option(Subcommands.NAMESPACE, children=[
- Option(Actions.GRANT, args=[
- Argument(Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE)
- ] + OptionTree._CATALOG_ROLE_AND_CATALOG,
input_name=Arguments.PRIVILEGE),
- Option(Actions.REVOKE, args=[
- Argument(Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE),
- Argument(Arguments.CASCADE, bool, Hints.Grant.CASCADE)
- ] + OptionTree._CATALOG_ROLE_AND_CATALOG,
input_name=Arguments.PRIVILEGE),
- ]),
- Option(Subcommands.TABLE, children=[
- Option(Actions.GRANT, args=[
- Argument(Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE),
- Argument(Arguments.TABLE, str, Hints.Grant.TABLE)
- ] + OptionTree._CATALOG_ROLE_AND_CATALOG,
input_name=Arguments.PRIVILEGE),
- Option(Actions.REVOKE, args=[
- Argument(Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE),
- Argument(Arguments.TABLE, str, Hints.Grant.TABLE),
- Argument(Arguments.CASCADE, bool, Hints.Grant.CASCADE)
- ] + OptionTree._CATALOG_ROLE_AND_CATALOG,
input_name=Arguments.PRIVILEGE),
- ]),
- Option(Subcommands.VIEW, children=[
- Option(Actions.GRANT, args=[
- Argument(Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE),
- Argument(Arguments.VIEW, str, Hints.Grant.VIEW)
- ] + OptionTree._CATALOG_ROLE_AND_CATALOG,
input_name=Arguments.PRIVILEGE),
- Option(Actions.REVOKE, args=[
- Argument(Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE),
- Argument(Arguments.VIEW, str, Hints.Grant.VIEW),
- Argument(Arguments.CASCADE, bool, Hints.Grant.CASCADE)
- ] + OptionTree._CATALOG_ROLE_AND_CATALOG,
input_name=Arguments.PRIVILEGE),
- ])
- ]),
- Option(Commands.NAMESPACES, 'manage namespaces', children=[
- Option(Subcommands.CREATE, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME),
- Argument(Arguments.LOCATION, str,
Hints.Namespaces.LOCATION),
- Argument(Arguments.PROPERTY, str, Hints.PROPERTY,
allow_repeats=True)
- ], input_name=Arguments.NAMESPACE),
- Option(Subcommands.LIST, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME),
- Argument(Arguments.PARENT, str, Hints.Namespaces.PARENT)
- ]),
- Option(Subcommands.DELETE, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME)
- ], input_name=Arguments.NAMESPACE),
- Option(Subcommands.GET, args=[
- Argument(Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME)
- ], input_name=Arguments.NAMESPACE),
- ]),
- Option(Commands.PROFILES, 'manage profiles', children=[
- Option(Subcommands.CREATE, input_name=Arguments.PROFILE),
- Option(Subcommands.DELETE, input_name=Arguments.PROFILE),
- Option(Subcommands.UPDATE, input_name=Arguments.PROFILE),
- Option(Subcommands.GET, input_name=Arguments.PROFILE),
- Option(Subcommands.LIST),
- ])
+ Option(
+ Commands.CATALOGS,
+ "manage catalogs",
+ children=[
+ Option(
+ Subcommands.CREATE,
+ args=[
+ Argument(
+ Arguments.TYPE,
+ str,
+ Hints.Catalogs.Create.TYPE,
+ lower=True,
+ choices=[ct.value for ct in CatalogType],
+ default=CatalogType.INTERNAL.value,
+ ),
+ Argument(
+ Arguments.STORAGE_TYPE,
+ str,
+ Hints.Catalogs.Create.STORAGE_TYPE,
+ lower=True,
+ choices=[st.value for st in StorageType],
+ ),
+ Argument(
+ Arguments.DEFAULT_BASE_LOCATION,
+ str,
+ Hints.Catalogs.Create.DEFAULT_BASE_LOCATION,
+ ),
+ Argument(
+ Arguments.ALLOWED_LOCATION,
+ str,
+ Hints.Catalogs.Create.ALLOWED_LOCATION,
+ allow_repeats=True,
+ ),
+ Argument(
+ Arguments.ROLE_ARN, str,
Hints.Catalogs.Create.ROLE_ARN
+ ),
+ Argument(
+ Arguments.REGION, str,
Hints.Catalogs.Create.REGION
+ ),
+ Argument(
+ Arguments.EXTERNAL_ID,
+ str,
+ Hints.Catalogs.Create.EXTERNAL_ID,
+ ),
+ Argument(
+ Arguments.TENANT_ID,
+ str,
+ Hints.Catalogs.Create.TENANT_ID,
+ ),
+ Argument(
+ Arguments.MULTI_TENANT_APP_NAME,
+ str,
+ Hints.Catalogs.Create.MULTI_TENANT_APP_NAME,
+ ),
+ Argument(
+ Arguments.CONSENT_URL,
+ str,
+ Hints.Catalogs.Create.CONSENT_URL,
+ ),
+ Argument(
+ Arguments.SERVICE_ACCOUNT,
+ str,
+ Hints.Catalogs.Create.SERVICE_ACCOUNT,
+ ),
+ Argument(
+ Arguments.PROPERTY,
+ str,
+ Hints.PROPERTY,
+ allow_repeats=True,
+ ),
+ ],
+ input_name=Arguments.CATALOG,
+ ),
+ Option(Subcommands.DELETE, input_name=Arguments.CATALOG),
+ Option(Subcommands.GET, input_name=Arguments.CATALOG),
+ Option(
+ Subcommands.LIST,
+ args=[
+ Argument(
+ Arguments.PRINCIPAL_ROLE,
+ str,
+ Hints.PrincipalRoles.PRINCIPAL_ROLE,
+ )
+ ],
+ ),
+ Option(
+ Subcommands.UPDATE,
+ args=[
+ Argument(
+ Arguments.DEFAULT_BASE_LOCATION,
+ str,
+ Hints.Catalogs.Update.DEFAULT_BASE_LOCATION,
+ ),
+ Argument(
+ Arguments.ALLOWED_LOCATION,
+ str,
+ Hints.Catalogs.Create.ALLOWED_LOCATION,
+ allow_repeats=True,
+ ),
+ Argument(
+ Arguments.REGION, str,
Hints.Catalogs.Create.REGION
+ ),
+ Argument(
+ Arguments.SET_PROPERTY,
+ str,
+ Hints.SET_PROPERTY,
+ allow_repeats=True,
+ ),
+ Argument(
+ Arguments.REMOVE_PROPERTY,
+ str,
+ Hints.REMOVE_PROPERTY,
+ allow_repeats=True,
+ ),
+ ],
+ input_name=Arguments.CATALOG,
+ ),
+ ],
+ ),
+ Option(
+ Commands.PRINCIPALS,
+ "manage principals",
+ children=[
+ Option(
+ Subcommands.CREATE,
+ args=[
+ Argument(
+ Arguments.TYPE,
+ str,
+ Hints.Principals.Create.TYPE,
+ lower=True,
+ choices=[pt.value for pt in PrincipalType],
+ default=PrincipalType.SERVICE.value,
+ ),
+ Argument(
+ Arguments.PROPERTY,
+ str,
+ Hints.PROPERTY,
+ allow_repeats=True,
+ ),
+ ],
+ input_name=Arguments.PRINCIPAL,
+ ),
+ Option(Subcommands.DELETE, input_name=Arguments.PRINCIPAL),
+ Option(Subcommands.GET, input_name=Arguments.PRINCIPAL),
+ Option(Subcommands.LIST),
+ Option(
+ Subcommands.ROTATE_CREDENTIALS,
input_name=Arguments.PRINCIPAL
+ ),
+ Option(
+ Subcommands.UPDATE,
+ args=[
+ Argument(
+ Arguments.SET_PROPERTY,
+ str,
+ Hints.SET_PROPERTY,
+ allow_repeats=True,
+ ),
+ Argument(
+ Arguments.REMOVE_PROPERTY,
+ str,
+ Hints.REMOVE_PROPERTY,
+ allow_repeats=True,
+ ),
+ ],
+ input_name=Arguments.PRINCIPAL,
+ ),
+ Option(Subcommands.ACCESS, input_name=Arguments.PRINCIPAL),
+ ],
+ ),
+ Option(
+ Commands.PRINCIPAL_ROLES,
+ "manage principal roles",
+ children=[
+ Option(
+ Subcommands.CREATE,
+ args=[
+ Argument(
+ Arguments.PROPERTY,
+ str,
+ Hints.PROPERTY,
+ allow_repeats=True,
+ )
+ ],
+ input_name=Arguments.PRINCIPAL_ROLE,
+ ),
+ Option(Subcommands.DELETE,
input_name=Arguments.PRINCIPAL_ROLE),
+ Option(Subcommands.GET,
input_name=Arguments.PRINCIPAL_ROLE),
+ Option(
+ Subcommands.LIST,
+ hint=Hints.PrincipalRoles.LIST,
+ args=[
+ Argument(
+ Arguments.CATALOG_ROLE,
+ str,
+ Hints.PrincipalRoles.List.CATALOG_ROLE,
+ ),
+ Argument(
+ Arguments.PRINCIPAL,
+ str,
+ Hints.PrincipalRoles.List.PRINCIPAL_NAME,
+ ),
+ ],
+ ),
+ Option(
+ Subcommands.UPDATE,
+ args=[
+ Argument(
+ Arguments.SET_PROPERTY,
+ str,
+ Hints.SET_PROPERTY,
+ allow_repeats=True,
+ ),
+ Argument(
+ Arguments.REMOVE_PROPERTY,
+ str,
+ Hints.REMOVE_PROPERTY,
+ allow_repeats=True,
+ ),
+ ],
+ input_name=Arguments.PRINCIPAL_ROLE,
+ ),
+ Option(
+ Subcommands.GRANT,
+ hint=Hints.PrincipalRoles.GRANT,
+ args=[
+ Argument(
+ Arguments.PRINCIPAL,
+ str,
+ Hints.PrincipalRoles.Grant.PRINCIPAL,
+ )
+ ],
+ input_name=Arguments.PRINCIPAL_ROLE,
+ ),
+ Option(
+ Subcommands.REVOKE,
+ hint=Hints.PrincipalRoles.REVOKE,
+ args=[
+ Argument(
+ Arguments.PRINCIPAL,
+ str,
+ Hints.PrincipalRoles.Revoke.PRINCIPAL,
+ )
+ ],
+ input_name=Arguments.PRINCIPAL_ROLE,
+ ),
+ ],
+ ),
+ Option(
+ Commands.CATALOG_ROLES,
+ "manage catalog roles",
+ children=[
+ Option(
+ Subcommands.CREATE,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ ),
+ Argument(
+ Arguments.PROPERTY,
+ str,
+ Hints.PROPERTY,
+ allow_repeats=True,
+ ),
+ ],
+ input_name=Arguments.CATALOG_ROLE,
+ ),
+ Option(
+ Subcommands.DELETE,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ ),
+ ],
+ input_name=Arguments.CATALOG_ROLE,
+ ),
+ Option(
+ Subcommands.GET,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ ),
+ ],
+ input_name=Arguments.CATALOG_ROLE,
+ ),
+ Option(
+ Subcommands.LIST,
+ hint=Hints.CatalogRoles.LIST,
+ args=[
+ Argument(
+ Arguments.PRINCIPAL_ROLE,
+ str,
+ Hints.PrincipalRoles.PRINCIPAL_ROLE,
+ )
+ ],
+ input_name=Arguments.CATALOG,
+ ),
+ Option(
+ Subcommands.UPDATE,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ ),
+ Argument(
+ Arguments.SET_PROPERTY,
+ str,
+ Hints.SET_PROPERTY,
+ allow_repeats=True,
+ ),
+ Argument(
+ Arguments.REMOVE_PROPERTY,
+ str,
+ Hints.REMOVE_PROPERTY,
+ allow_repeats=True,
+ ),
+ ],
+ input_name=Arguments.CATALOG_ROLE,
+ ),
+ Option(
+ Subcommands.GRANT,
+ hint=Hints.CatalogRoles.GRANT_CATALOG_ROLE,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ ),
+ Argument(
+ Arguments.PRINCIPAL_ROLE,
+ str,
+ Hints.CatalogRoles.CATALOG_ROLE,
+ ),
+ ],
+ input_name=Arguments.CATALOG_ROLE,
+ ),
+ Option(
+ Subcommands.REVOKE,
+ hint=Hints.CatalogRoles.GRANT_CATALOG_ROLE,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ ),
+ Argument(
+ Arguments.PRINCIPAL_ROLE,
+ str,
+ Hints.CatalogRoles.CATALOG_ROLE,
+ ),
+ ],
+ input_name=Arguments.CATALOG_ROLE,
+ ),
+ ],
+ ),
+ Option(
+ Commands.PRIVILEGES,
+ "manage privileges for a catalog role",
+ children=[
+ Option(Subcommands.LIST,
args=OptionTree._CATALOG_ROLE_AND_CATALOG),
+ Option(
+ Subcommands.CATALOG,
+ children=[
+ Option(
+ Actions.GRANT,
+ args=OptionTree._CATALOG_ROLE_AND_CATALOG,
+ input_name=Arguments.PRIVILEGE,
+ ),
+ Option(
+ Actions.REVOKE,
+ args=[
+ Argument(
+ Arguments.CASCADE, bool,
Hints.Grant.CASCADE
+ )
+ ]
+ + OptionTree._CATALOG_ROLE_AND_CATALOG,
+ input_name=Arguments.PRIVILEGE,
+ ),
+ ],
+ ),
+ Option(
+ Subcommands.NAMESPACE,
+ children=[
+ Option(
+ Actions.GRANT,
+ args=[
+ Argument(
+ Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE
+ )
+ ]
+ + OptionTree._CATALOG_ROLE_AND_CATALOG,
+ input_name=Arguments.PRIVILEGE,
+ ),
+ Option(
+ Actions.REVOKE,
+ args=[
+ Argument(
+ Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE
+ ),
+ Argument(
+ Arguments.CASCADE, bool,
Hints.Grant.CASCADE
+ ),
+ ]
+ + OptionTree._CATALOG_ROLE_AND_CATALOG,
+ input_name=Arguments.PRIVILEGE,
+ ),
+ ],
+ ),
+ Option(
+ Subcommands.TABLE,
+ children=[
+ Option(
+ Actions.GRANT,
+ args=[
+ Argument(
+ Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE
+ ),
+ Argument(Arguments.TABLE, str,
Hints.Grant.TABLE),
+ ]
+ + OptionTree._CATALOG_ROLE_AND_CATALOG,
+ input_name=Arguments.PRIVILEGE,
+ ),
+ Option(
+ Actions.REVOKE,
+ args=[
+ Argument(
+ Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE
+ ),
+ Argument(Arguments.TABLE, str,
Hints.Grant.TABLE),
+ Argument(
+ Arguments.CASCADE, bool,
Hints.Grant.CASCADE
+ ),
+ ]
+ + OptionTree._CATALOG_ROLE_AND_CATALOG,
+ input_name=Arguments.PRIVILEGE,
+ ),
+ ],
+ ),
+ Option(
+ Subcommands.VIEW,
+ children=[
+ Option(
+ Actions.GRANT,
+ args=[
+ Argument(
+ Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE
+ ),
+ Argument(Arguments.VIEW, str,
Hints.Grant.VIEW),
+ ]
+ + OptionTree._CATALOG_ROLE_AND_CATALOG,
+ input_name=Arguments.PRIVILEGE,
+ ),
+ Option(
+ Actions.REVOKE,
+ args=[
+ Argument(
+ Arguments.NAMESPACE, str,
Hints.Grant.NAMESPACE
+ ),
+ Argument(Arguments.VIEW, str,
Hints.Grant.VIEW),
+ Argument(
+ Arguments.CASCADE, bool,
Hints.Grant.CASCADE
+ ),
+ ]
+ + OptionTree._CATALOG_ROLE_AND_CATALOG,
+ input_name=Arguments.PRIVILEGE,
+ ),
+ ],
+ ),
+ ],
+ ),
+ Option(
+ Commands.NAMESPACES,
+ "manage namespaces",
+ children=[
+ Option(
+ Subcommands.CREATE,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ ),
+ Argument(
+ Arguments.LOCATION, str,
Hints.Namespaces.LOCATION
+ ),
+ Argument(
+ Arguments.PROPERTY,
+ str,
+ Hints.PROPERTY,
+ allow_repeats=True,
+ ),
+ ],
+ input_name=Arguments.NAMESPACE,
+ ),
+ Option(
+ Subcommands.LIST,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ ),
+ Argument(Arguments.PARENT, str,
Hints.Namespaces.PARENT),
+ ],
+ ),
+ Option(
+ Subcommands.DELETE,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ )
+ ],
+ input_name=Arguments.NAMESPACE,
+ ),
+ Option(
+ Subcommands.GET,
+ args=[
+ Argument(
+ Arguments.CATALOG, str,
Hints.CatalogRoles.CATALOG_NAME
+ )
+ ],
+ input_name=Arguments.NAMESPACE,
+ ),
+ ],
+ ),
+ Option(
+ Commands.PROFILES,
+ "manage profiles",
+ children=[
+ Option(Subcommands.CREATE, input_name=Arguments.PROFILE),
+ Option(Subcommands.DELETE, input_name=Arguments.PROFILE),
+ Option(Subcommands.UPDATE, input_name=Arguments.PROFILE),
+ Option(Subcommands.GET, input_name=Arguments.PROFILE),
+ Option(Subcommands.LIST),
+ ],
+ ),
]
diff --git a/client/python/cli/options/parser.py
b/client/python/cli/options/parser.py
index 8613474fe..26f5c8dfc 100644
--- a/client/python/cli/options/parser.py
+++ b/client/python/cli/options/parser.py
@@ -37,57 +37,84 @@ class Parser(object):
"""
_ROOT_ARGUMENTS = [
- Argument(Arguments.HOST, str, hint='hostname'),
- Argument(Arguments.PORT, int, hint='port'),
- Argument(Arguments.BASE_URL, str, hint='complete base URL instead of
hostname:port'),
- Argument(Arguments.CLIENT_ID, str, hint='client ID for token-based
authentication'),
- Argument(Arguments.CLIENT_SECRET, str, hint='client secret for
token-based authentication'),
- Argument(Arguments.ACCESS_TOKEN, str, hint='access token for
token-based authentication'),
- Argument(Arguments.PROFILE, str, hint='profile for token-based
authentication'),
- Argument(Arguments.PROXY, str, hint='proxy URL'),
+ Argument(Arguments.HOST, str, hint="hostname"),
+ Argument(Arguments.PORT, int, hint="port"),
+ Argument(
+ Arguments.BASE_URL, str, hint="complete base URL instead of
hostname:port"
+ ),
+ Argument(
+ Arguments.CLIENT_ID, str, hint="client ID for token-based
authentication"
+ ),
+ Argument(
+ Arguments.CLIENT_SECRET,
+ str,
+ hint="client secret for token-based authentication",
+ ),
+ Argument(
+ Arguments.ACCESS_TOKEN,
+ str,
+ hint="access token for token-based authentication",
+ ),
+ Argument(Arguments.PROFILE, str, hint="profile for token-based
authentication"),
+ Argument(Arguments.PROXY, str, hint="proxy URL"),
]
@staticmethod
def _build_parser() -> argparse.ArgumentParser:
- parser = TreeHelpParser(description='Polaris CLI')
+ parser = TreeHelpParser(description="Polaris CLI")
for arg in Parser._ROOT_ARGUMENTS:
if arg.default is not None:
- parser.add_argument(arg.get_flag_name(), type=arg.type,
help=arg.hint, default=arg.default)
+ parser.add_argument(
+ arg.get_flag_name(),
+ type=arg.type,
+ help=arg.hint,
+ default=arg.default,
+ )
else:
parser.add_argument(arg.get_flag_name(), type=arg.type,
help=arg.hint)
# Add everything from the option tree to the parser:
def add_arguments(parser, args: List[Argument]):
for arg in args:
- kwargs = {'help': arg.hint, 'type': arg.type}
+ kwargs = {"help": arg.hint, "type": arg.type}
if arg.choices:
- kwargs['choices'] = arg.choices
+ kwargs["choices"] = arg.choices
if arg.lower:
- kwargs['type'] = kwargs['type'].lower
+ kwargs["type"] = kwargs["type"].lower
if arg.default:
- kwargs['default'] = arg.default
+ kwargs["default"] = arg.default
if arg.type is bool:
- del kwargs['type']
- parser.add_argument(arg.get_flag_name(), **kwargs,
action='store_true')
+ del kwargs["type"]
+ parser.add_argument(
+ arg.get_flag_name(), **kwargs, action="store_true"
+ )
elif arg.allow_repeats:
- parser.add_argument(arg.get_flag_name(), **kwargs,
action='append')
+ parser.add_argument(arg.get_flag_name(), **kwargs,
action="append")
else:
parser.add_argument(arg.get_flag_name(), **kwargs)
def recurse_options(subparser, options: List[Option]):
for option in options:
- option_parser = subparser.add_parser(option.name,
help=option.hint or option.name)
+ option_parser = subparser.add_parser(
+ option.name, help=option.hint or option.name
+ )
add_arguments(option_parser, option.args)
if option.input_name:
- option_parser.add_argument(option.input_name, type=str,
-
help=option.input_name.replace('_', ' '), default=None)
+ option_parser.add_argument(
+ option.input_name,
+ type=str,
+ help=option.input_name.replace("_", " "),
+ default=None,
+ )
if option.children:
- children_subparser =
option_parser.add_subparsers(dest=f'{option.name}_subcommand', required=False)
+ children_subparser = option_parser.add_subparsers(
+ dest=f"{option.name}_subcommand", required=False
+ )
recurse_options(children_subparser, option.children)
- subparser = parser.add_subparsers(dest='command', required=False)
+ subparser = parser.add_subparsers(dest="command", required=False)
recurse_options(subparser, OptionTree.get_tree())
return parser
@@ -102,13 +129,13 @@ class Parser(object):
return None
results = dict()
for property in properties:
- if '=' not in property:
- raise Exception(f'Could not parse property `{property}`')
- key, value = property.split('=', 1)
+ if "=" not in property:
+ raise Exception(f"Could not parse property `{property}`")
+ key, value = property.split("=", 1)
if not value:
- raise Exception(f'Could not parse property `{property}`')
+ raise Exception(f"Could not parse property `{property}`")
if key in results:
- raise Exception(f'Duplicate property key `{key}`')
+ raise Exception(f"Duplicate property key `{key}`")
results[key] = value
return results
@@ -118,19 +145,21 @@ class TreeHelpParser(argparse.ArgumentParser):
Replaces the default help behavior with a more readable message.
"""
- INDENT = ' ' * 2
+ INDENT = " " * 2
def parse_args(self, args=None, namespace=None):
if args is None:
args = sys.argv[1:]
- help_index = min([float('inf')] + [args.index(x) for x in ['-h',
'--help'] if x in args])
- if help_index < float('inf'):
+ help_index = min(
+ [float("inf")] + [args.index(x) for x in ["-h", "--help"] if x in
args]
+ )
+ if help_index < float("inf"):
tree_str = self._get_tree_str(args[:help_index])
if tree_str:
- print(f'input: polaris {" ".join(args)}')
- print('options:')
+ print(f"input: polaris {' '.join(args)}")
+ print("options:")
print(tree_str)
- print('\n')
+ print("\n")
self.print_usage()
super().exit()
else:
@@ -141,11 +170,15 @@ class TreeHelpParser(argparse.ArgumentParser):
def _get_tree_str(self, args: List[str]) -> Optional[str]:
command_path = self._get_command_path(args, OptionTree.get_tree())
if len(command_path) == 0:
- result = TreeHelpParser.INDENT + 'polaris'
+ result = TreeHelpParser.INDENT + "polaris"
for arg in Parser._ROOT_ARGUMENTS:
- result += '\n' + (TreeHelpParser.INDENT * 2) +
f"{arg.get_flag_name()} {arg.hint}"
+ result += (
+ "\n"
+ + (TreeHelpParser.INDENT * 2)
+ + f"{arg.get_flag_name()} {arg.hint}"
+ )
for option in OptionTree.get_tree():
- result += '\n' + self._get_tree_for_option(option, indent=2)
+ result += "\n" + self._get_tree_for_option(option, indent=2)
return result
else:
option_node = self._get_option_node(command_path,
OptionTree.get_tree())
@@ -159,19 +192,25 @@ class TreeHelpParser(argparse.ArgumentParser):
result += (TreeHelpParser.INDENT * indent) + option.name
if option.args:
- result += '\n' + (TreeHelpParser.INDENT * (indent + 1)) + "Named
arguments:"
+ result += "\n" + (TreeHelpParser.INDENT * (indent + 1)) + "Named
arguments:"
for arg in option.args:
- result += '\n' + (TreeHelpParser.INDENT * (indent + 2)) +
f"{arg.get_flag_name()} {arg.hint}"
+ result += (
+ "\n"
+ + (TreeHelpParser.INDENT * (indent + 2))
+ + f"{arg.get_flag_name()} {arg.hint}"
+ )
if option.input_name:
- result += '\n' + (TreeHelpParser.INDENT * (indent + 1)) +
"Positional arguments:"
- result += '\n' + (TreeHelpParser.INDENT * (indent + 2)) +
option.input_name
+ result += (
+ "\n" + (TreeHelpParser.INDENT * (indent + 1)) + "Positional
arguments:"
+ )
+ result += "\n" + (TreeHelpParser.INDENT * (indent + 2)) +
option.input_name
if len(option.args) > 0 and len(option.children) > 0:
- result += '\n'
+ result += "\n"
for child in sorted(option.children, key=lambda o: o.name):
- result += '\n' + self._get_tree_for_option(child, indent + 1)
+ result += "\n" + self._get_tree_for_option(child, indent + 1)
return result
@@ -194,7 +233,9 @@ class TreeHelpParser(argparse.ArgumentParser):
break
return command_path
- def _get_option_node(self, command_path: List[str], nodes: List[Option])
-> Optional[Option]:
+ def _get_option_node(
+ self, command_path: List[str], nodes: List[Option]
+ ) -> Optional[Option]:
if len(command_path) > 0:
for node in nodes:
if node.name == command_path[0]:
@@ -203,4 +244,3 @@ class TreeHelpParser(argparse.ArgumentParser):
else:
return self._get_option_node(command_path[1:],
node.children)
return None
-
diff --git a/client/python/cli/polaris_cli.py b/client/python/cli/polaris_cli.py
index d60791232..83341ada4 100644
--- a/client/python/cli/polaris_cli.py
+++ b/client/python/cli/polaris_cli.py
@@ -24,12 +24,22 @@ from json import JSONDecodeError
from typing import Dict
-from cli.constants import Arguments, Commands, CLIENT_ID_ENV,
CLIENT_SECRET_ENV, CLIENT_PROFILE_ENV, DEFAULT_HOSTNAME, DEFAULT_PORT,
CONFIG_FILE
+from cli.constants import (
+ Arguments,
+ Commands,
+ CLIENT_ID_ENV,
+ CLIENT_SECRET_ENV,
+ CLIENT_PROFILE_ENV,
+ DEFAULT_HOSTNAME,
+ DEFAULT_PORT,
+ CONFIG_FILE,
+)
from cli.options.option_tree import Argument
from cli.options.parser import Parser
from polaris.management import ApiClient, Configuration
from polaris.management import PolarisDefaultApi
+
class PolarisCli:
"""
Implements a basic Command-Line Interface (CLI) for interacting with a
Polaris service. The CLI can be used to
@@ -51,6 +61,7 @@ class PolarisCli:
options = Parser.parse(args)
if options.command == Commands.PROFILES:
from cli.command import Command
+
command = Command.from_options(options)
command.execute()
else:
@@ -58,6 +69,7 @@ class PolarisCli:
with client_builder() as api_client:
try:
from cli.command import Command
+
admin_api = PolarisDefaultApi(api_client)
command = Command.from_options(options)
command.execute(admin_api)
@@ -68,15 +80,20 @@ class PolarisCli:
@staticmethod
def _try_print_exception(e):
try:
- error = json.loads(e.body)['error']
- sys.stderr.write(f'Exception when communicating with the Polaris
server.'
- f' {error["type"]}:
{error["message"]}{os.linesep}')
+ error = json.loads(e.body)["error"]
+ sys.stderr.write(
+ f"Exception when communicating with the Polaris server."
+ f" {error['type']}: {error['message']}{os.linesep}"
+ )
except JSONDecodeError as _:
- sys.stderr.write(f'Exception when communicating with the Polaris
server.'
- f' {e.status}: {e.reason}{os.linesep}')
+ sys.stderr.write(
+ f"Exception when communicating with the Polaris server."
+ f" {e.status}: {e.reason}{os.linesep}"
+ )
except Exception as _:
- sys.stderr.write(f'Exception when communicating with the Polaris
server.'
- f' {e}{os.linesep}')
+ sys.stderr.write(
+ f"Exception when communicating with the Polaris server.
{e}{os.linesep}"
+ )
@staticmethod
def _load_profiles() -> Dict[str, Dict[str, str]]:
@@ -88,19 +105,19 @@ class PolarisCli:
@staticmethod
def _get_token(api_client: ApiClient, catalog_url, client_id,
client_secret) -> str:
response = api_client.call_api(
- 'POST',
- f'{catalog_url}/oauth/tokens',
- header_params={'Content-Type':
'application/x-www-form-urlencoded'},
+ "POST",
+ f"{catalog_url}/oauth/tokens",
+ header_params={"Content-Type":
"application/x-www-form-urlencoded"},
post_params={
- 'grant_type': 'client_credentials',
- 'client_id': client_id,
- 'client_secret': client_secret,
- 'scope': 'PRINCIPAL_ROLE:ALL'
- }
+ "grant_type": "client_credentials",
+ "client_id": client_id,
+ "client_secret": client_secret,
+ "scope": "PRINCIPAL_ROLE:ALL",
+ },
).response.data
- if 'access_token' not in json.loads(response):
- raise Exception('Failed to get access token')
- return json.loads(response)['access_token']
+ if "access_token" not in json.loads(response):
+ raise Exception("Failed to get access token")
+ return json.loads(response)["access_token"]
@staticmethod
def _get_client_builder(options):
@@ -110,38 +127,50 @@ class PolarisCli:
profiles = PolarisCli._load_profiles()
profile = profiles.get(client_profile)
if not profile:
- raise Exception(f'Polaris profile {client_profile} not found')
+ raise Exception(f"Polaris profile {client_profile} not found")
# Determine which credentials to use
- client_id = options.client_id or os.getenv(CLIENT_ID_ENV) or
profile.get('client_id')
- client_secret = options.client_secret or os.getenv(CLIENT_SECRET_ENV)
or profile.get('client_secret')
-
+ client_id = (
+ options.client_id or os.getenv(CLIENT_ID_ENV) or
profile.get("client_id")
+ )
+ client_secret = (
+ options.client_secret
+ or os.getenv(CLIENT_SECRET_ENV)
+ or profile.get("client_secret")
+ )
+
# Validates
has_access_token = options.access_token is not None
has_client_secret = client_id is not None and client_secret is not None
if has_access_token and (options.client_id or options.client_secret):
- raise Exception(f'Please provide credentials via either
{Argument.to_flag_name(Arguments.CLIENT_ID)} &'
- f'
{Argument.to_flag_name(Arguments.CLIENT_SECRET)} or'
- f'
{Argument.to_flag_name(Arguments.ACCESS_TOKEN)}, but not both')
+ raise Exception(
+ f"Please provide credentials via either
{Argument.to_flag_name(Arguments.CLIENT_ID)} &"
+ f" {Argument.to_flag_name(Arguments.CLIENT_SECRET)} or"
+ f" {Argument.to_flag_name(Arguments.ACCESS_TOKEN)}, but not
both"
+ )
if not has_access_token and not has_client_secret:
- raise Exception(f'Please provide credentials via either
{Argument.to_flag_name(Arguments.CLIENT_ID)} &'
- f'
{Argument.to_flag_name(Arguments.CLIENT_SECRET)} or'
- f'
{Argument.to_flag_name(Arguments.ACCESS_TOKEN)}.'
- f' Alternatively, you may set the environment
variables {CLIENT_ID_ENV} &'
- f' {CLIENT_SECRET_ENV}.')
+ raise Exception(
+ f"Please provide credentials via either
{Argument.to_flag_name(Arguments.CLIENT_ID)} &"
+ f" {Argument.to_flag_name(Arguments.CLIENT_SECRET)} or"
+ f" {Argument.to_flag_name(Arguments.ACCESS_TOKEN)}."
+ f" Alternatively, you may set the environment variables
{CLIENT_ID_ENV} &"
+ f" {CLIENT_SECRET_ENV}."
+ )
# Authenticate accordingly
if options.base_url:
if options.host is not None or options.port is not None:
- raise Exception(f'Please provide either
{Argument.to_flag_name(Arguments.BASE_URL)} or'
- f' {Argument.to_flag_name(Arguments.HOST)} &'
- f' {Argument.to_flag_name(Arguments.PORT)},
but not both')
-
- polaris_management_url = f'{options.base_url}/api/management/v1'
- polaris_catalog_url = f'{options.base_url}/api/catalog/v1'
+ raise Exception(
+ f"Please provide either
{Argument.to_flag_name(Arguments.BASE_URL)} or"
+ f" {Argument.to_flag_name(Arguments.HOST)} &"
+ f" {Argument.to_flag_name(Arguments.PORT)}, but not both"
+ )
+
+ polaris_management_url = f"{options.base_url}/api/management/v1"
+ polaris_catalog_url = f"{options.base_url}/api/catalog/v1"
else:
- host = options.host or profile.get('host') or DEFAULT_HOSTNAME
- port = options.port or profile.get('port') or DEFAULT_PORT
- polaris_management_url = f'http://{host}:{port}/api/management/v1'
- polaris_catalog_url = f'http://{host}:{port}/api/catalog/v1'
+ host = options.host or profile.get("host") or DEFAULT_HOSTNAME
+ port = options.port or profile.get("port") or DEFAULT_PORT
+ polaris_management_url = f"http://{host}:{port}/api/management/v1"
+ polaris_catalog_url = f"http://{host}:{port}/api/catalog/v1"
config = Configuration(host=polaris_management_url)
config.proxy = options.proxy
@@ -152,7 +181,9 @@ class PolarisCli:
config.password = client_secret
if not has_access_token and not
PolarisCli.DIRECT_AUTHENTICATION_ENABLED:
- token = PolarisCli._get_token(ApiClient(config),
polaris_catalog_url, client_id, client_secret)
+ token = PolarisCli._get_token(
+ ApiClient(config), polaris_catalog_url, client_id,
client_secret
+ )
config.username = None
config.password = None
config.access_token = token
@@ -160,5 +191,5 @@ class PolarisCli:
return lambda: ApiClient(config)
-if __name__ == '__main__':
+if __name__ == "__main__":
PolarisCli.execute()