blob: b06286df04e851b4707c675866f80bc38a21e553 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
import functools
import json
import os
import sys
from json import JSONDecodeError
import urllib3
from apache_polaris.cli.api_client_builder import ApiClientBuilder
from apache_polaris.cli.constants import Commands
from apache_polaris.cli.options.parser import Parser
from apache_polaris.sdk.management import PolarisDefaultApi
class PolarisCli:
"""
Implements a basic Command-Line Interface (CLI) for interacting with a Polaris service. The CLI can be used to
manage entities like catalogs, principals, and grants within Polaris and can perform most operations that are
available in the Python client API.
Example usage:
* ./polaris --client-id ${id} --client-secret ${secret} --host ${hostname} --port ${port} principals create example_user
* ./polaris --client-id ${id} --client-secret ${secret} --host ${hostname} --port ${port} principal-roles create example_role
* ./polaris --client-id ${id} --client-secret ${secret} --host ${hostname} --port ${port} catalog-roles list
* ./polaris --client-id ${id} --client-secret ${secret} --base-url https://custom-polaris-domain.example.com/service-prefix catalogs list
"""
# Can be enabled if the client is able to authenticate directly without first fetching a token
DIRECT_AUTHENTICATION_ENABLED = False
@staticmethod
def execute(args=None):
options = Parser.parse(args)
if options.command == Commands.PROFILES:
from apache_polaris.cli.command import Command
command = Command.from_options(options)
command.execute()
else:
api_client = ApiClientBuilder(
options, direct_authentication=PolarisCli.DIRECT_AUTHENTICATION_ENABLED
).get_api_client()
try:
from apache_polaris.cli.command import Command
admin_api = PolarisDefaultApi(api_client)
command = Command.from_options(options)
if options.debug:
PolarisCli._enable_api_request_logging()
command.execute(admin_api)
except Exception as e:
PolarisCli._try_print_exception(e)
sys.exit(1)
@staticmethod
def _enable_api_request_logging():
# Store the original urlopen method
if not hasattr(urllib3.PoolManager, "original_urlopen"):
urllib3.PoolManager.original_urlopen = urllib3.PoolManager.urlopen
# Define the wrapper function
@functools.wraps(urllib3.PoolManager.original_urlopen)
def urlopen_wrapper(self, method, url, **kwargs):
sys.stderr.write(f"Request: {method} {url}\n")
if "headers" in kwargs:
sys.stderr.write(f"Headers: {kwargs['headers']}\n")
if "body" in kwargs:
sys.stderr.write(f"Body: {kwargs['body']}\n")
sys.stderr.write("\n")
# Call the original urlopen method
return urllib3.PoolManager.original_urlopen(self, method, url, **kwargs)
urllib3.PoolManager.urlopen = urlopen_wrapper
@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}"
)
except JSONDecodeError as _:
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. {e}{os.linesep}"
)
def main():
PolarisCli.execute()
if __name__ == "__main__":
main()