From 579cf3b707b1c48dccb00d109a334c588609434e Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 25 Apr 2018 17:13:42 +0200 Subject: [PATCH 01/24] Revert "Revert "Merge pull request #31 from InfraBox/cli_project_features"" This reverts commit 7edafb4c5faa083c90f2f06de2887d650e7fa4f5. --- .gitignore | 5 + infraboxcli/__init__.py | 85 +++++++++++++- infraboxcli/dashboard/__init__.py | 0 infraboxcli/dashboard/cli_client.py | 24 ++++ infraboxcli/dashboard/external.py | 43 +++++++ infraboxcli/dashboard/project.py | 166 ++++++++++++++++++++++++++++ infraboxcli/dashboard/user.py | 32 ++++++ infraboxcli/run.py | 9 ++ setup.py | 1 + 9 files changed, 360 insertions(+), 5 deletions(-) create mode 100644 infraboxcli/dashboard/__init__.py create mode 100644 infraboxcli/dashboard/cli_client.py create mode 100644 infraboxcli/dashboard/external.py create mode 100644 infraboxcli/dashboard/project.py create mode 100644 infraboxcli/dashboard/user.py diff --git a/.gitignore b/.gitignore index 7d77160..47076d2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ __pycache__/ *.swp +.idea/ + # C extensions *.so @@ -102,3 +104,6 @@ ENV/ # mypy .mypy_cache/ + +# exuberant ctags +tags diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index a2414f7..d85700b 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -2,14 +2,17 @@ import os import sys -from infraboxcli.push import push -from infraboxcli.run import run from infraboxcli.graph import graph -from infraboxcli.validate import validate +from infraboxcli.init import init from infraboxcli.list_jobs import list_jobs from infraboxcli.log import logger -from infraboxcli.init import init from infraboxcli.pull import pull +from infraboxcli.push import push +from infraboxcli.run import run +from infraboxcli.validate import validate + +from infraboxcli.dashboard import user +from infraboxcli.dashboard import project version = '0.6.4' @@ -94,10 +97,73 @@ def main(): parser_run.add_argument("--local-cache", required=False, type=str, default="/tmp/{}/infrabox/local-cache".format(username), help="Path to the local cache") - + parser_run.add_argument("--memory", required=False, type=float, + help="Override a memory limit for your job") + parser_run.add_argument("--cpu", required=False, type=float, + help="Override a cpu limit for your job") parser_run.set_defaults(no_rm=False) parser_run.set_defaults(func=run) + # Collaborators + parser_collaborators = sub_parser.add_parser('collaborators', help='Add or remove collaborators for your project') + sub_collaborators = parser_collaborators.add_subparsers() + + parser_list_collaborators = sub_collaborators.add_parser('list', help='Show collaborators list') + parser_list_collaborators.add_argument('--verbose', required=False, default=True, type=str2bool) + parser_list_collaborators.set_defaults(func=project.list_collaborators) + + parser_add_collaborator = sub_collaborators.add_parser('add', help='Add a collaborator') + parser_add_collaborator.add_argument('--username', required=True, type=str, + help='Username of the collaborator you want to add') + parser_add_collaborator.set_defaults(func=project.add_collaborator) + + parser_remove_collaborator = sub_collaborators.add_parser('remove', help='Remove a collaborator') + parser_remove_collaborator.add_argument('--username', required=True, type=str, + help='Username of the collaborator you want to remove') + parser_remove_collaborator.set_defaults(func=project.remove_collaborator) + + # Secrets + parser_secrets = sub_parser.add_parser('secrets', help='Create or delete secrets') + sub_secrets = parser_secrets.add_subparsers() + + parser_create_secret = sub_secrets.add_parser('create', help='Create a secret') + parser_create_secret.add_argument('--name', required=True, type=str, help='Name of the secret') + parser_create_secret.add_argument('--value', required=True, type=str, help='Value of the secret') + parser_create_secret.set_defaults(func=project.add_secret) + + parser_delete_secret = sub_secrets.add_parser('delete', help='Delete a secret') + parser_delete_secret.add_argument('--name', required=True, type=str, help='Name of the secret you want to delete') + parser_delete_secret.set_defaults(func=project.delete_secret) + + # Tokens + parsers_project_tokens = sub_parser.add_parser('project-token', help='Manage your project tokens') + sub_project_tokens = parsers_project_tokens.add_subparsers() + + parser_list_project_tokens = sub_project_tokens.add_parser('list', help='Show all your project tokens') + parser_list_project_tokens.add_argument('--verbose', required=False, default=True, type=str2bool) + parser_list_project_tokens.set_defaults(func=project.list_project_tokens) + + parser_add_project_token = sub_project_tokens.add_parser('create', help='Create a project token') + parser_add_project_token.add_argument('--description', required=True, type=str, + help='Description of the project token you want to create') + #TODO when scope push/pull functionality is implemented, uncomment following 2 lines + #parser_add_project_token.add_argument('--scope_push', required=False, default=True, type=str2bool, help='Scope push') + #parser_add_project_token.add_argument('--scope_pull', required=False, default=True, type=str2bool, help='Scope pull') + parser_add_project_token.set_defaults(func=project.add_project_token) + + parser_remove_project_token = sub_project_tokens.add_parser('delete', help='Delete a project token') + parser_remove_project_token.add_argument('--id', required=False, type=str, + help='Id of the project token you want to delete') + parser_remove_project_token.add_argument('--description', required=False, type=str, + help='Description of the project token you want to delete') + parser_remove_project_token.set_defaults(func=project.delete_project_token) + + # User + parser_login = sub_parser.add_parser('login', help='Login to infrabox') + parser_login.add_argument('--email', required=False, default=None, type=str, help='Email of the user') + parser_login.add_argument('--password', required=False, default=None, type=str, help='Password of the user') + parser_login.set_defaults(func=user.login) + # Parse args args = parser.parse_args() @@ -151,3 +217,12 @@ def main(): # Run command args.func(args) + + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') diff --git a/infraboxcli/dashboard/__init__.py b/infraboxcli/dashboard/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infraboxcli/dashboard/cli_client.py b/infraboxcli/dashboard/cli_client.py new file mode 100644 index 0000000..f789016 --- /dev/null +++ b/infraboxcli/dashboard/cli_client.py @@ -0,0 +1,24 @@ +import requests + +session = requests.Session() + + +def get(url, headers=None, cookies_handler=None): + response = session.get(url, headers=headers) + if cookies_handler: + cookies_handler(session.cookies.get_dict()) + return response + + +def post(url, data, headers=None, cookies_handler=None): + response = session.post(url, json=data, headers=headers) + if cookies_handler: + cookies_handler(session.cookies.get_dict()) + return response + + +def delete(url, headers=None, cookies_handler=None): + response = session.delete(url, headers=headers) + if cookies_handler: + cookies_handler(session.cookies.get_dict()) + return response \ No newline at end of file diff --git a/infraboxcli/dashboard/external.py b/infraboxcli/dashboard/external.py new file mode 100644 index 0000000..297dfe4 --- /dev/null +++ b/infraboxcli/dashboard/external.py @@ -0,0 +1,43 @@ +import pickle +from os.path import expanduser + +home = expanduser("~") + +def save_user_token(dict): + try: + f = open(home + '/.infra.data', 'rb') + obj = pickle.load(f) + f.close() + + except: + obj = {} + + obj['current_user_token'] = dict['token'] + + f = open(home + '/.infra.data', 'wb') + pickle.dump(obj, f) + f.close() + + +def load_current_user_token(): + try: + f = open(home + '/.infra.data', 'rb') + obj = pickle.load(f) + f.close() + curr_token = obj['current_user_token'] + except: + raise EnvironmentError('Could not load current user token. Please log in') + + return curr_token + + +def load_current_project_token(): + try: + f = open(home + '/.infra.data', 'rb') + obj = pickle.load(f) + f.close() + curr_token = obj['current_project_token'] + except: + raise EnvironmentError('Could not load current project token. Please set current project') + + return curr_token \ No newline at end of file diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py new file mode 100644 index 0000000..75b52eb --- /dev/null +++ b/infraboxcli/dashboard/project.py @@ -0,0 +1,166 @@ +from infraboxcli.dashboard.cli_client import get, post, delete +from infraboxcli.dashboard.user import get_user_headers +import infraboxcli.env + +api_projects_endpoint_url = '/api/v1/projects/' + + +def delete_project(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + response = get(url, get_user_headers()) + + return response + + +def list_collaborators(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators' + response = get(url, get_user_headers()) + + if args.verbose: + print('=== Collaborators ===') + for collaborator in response.json(): + print('Username: %s' % collaborator['username']) + print('E-mail: %s' % collaborator['email']) + print('---') + + return response + + +def add_collaborator(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators' + data = { 'username': args.username } + + response = post(url, data, get_user_headers()) + print(response.json()['message']) + + return response + + +def remove_collaborator(args): + infraboxcli.env.check_env_cli_token(args) + + args.verbose = False + all_project_collaborators = list_collaborators(args).json() + collaborator_id = None + for collaborator in all_project_collaborators: + if collaborator['username'] == args.username: + collaborator_id = collaborator['id'] + break + + if collaborator_id is None: + print('Specified user is not in collaborators list.') + return + + url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators/' + collaborator_id + response = delete(url, get_user_headers()) + print(response.json()['message']) + + return response + + +def add_secret(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' + data = {'name': args.name, 'value': args.value} + + response = post(url, data, get_user_headers()) + + return response + + +def delete_secret(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/secrets/' + args.name + response = delete(url, get_user_headers()) + + return response + + +def list_project_tokens(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/tokens' + + response = get(url, get_user_headers()) + if args.verbose: + print('=== Project tokens ===') + for project_token in response.json(): + print('Description: %s' % project_token['description']) + print('Id: %s' % project_token['id']) + print('Scope push: %s' % project_token['scope_push']) + print('Scope pull: %s' % project_token['scope_pull']) + print('---') + + return response + + +def get_project_token_id_by_description(args): + args.verbose = False + all_project_tokens = list_project_tokens(args).json() + + for project_token in all_project_tokens: + if args.description == project_token['description']: + return project_token['id'] + + return None + + +def add_project_token(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/tokens' + + data = { + 'description': args.description, + #TODO when scope push/pull functionality is implemented, + # delete following 2 lines and uncomment next 2 lines + 'scope_push': True, + 'scope_pull': True + #'scope_push': args.scope_push, + #'scope_pull': args.scope_pull + } + + response = post(url, data, get_user_headers()) + + if response.status_code != 200: + print(response.json()['message']) + return + + # Print project token to the CLI + print('=== Authentication Token ===') + print('Please save your token at a secure place. We will not show it to you again.\n\n') + print(response.json()['data']['token']) + + return response + + +def delete_project_token(args): + if args.id: + delete_project_token_by_id(args) + elif args.description: + delete_project_token_by_description(args) + else: + print('Please, provide either token id or description.') + + +def delete_project_token_by_description(args): + infraboxcli.env.check_env_cli_token(args) + token_id = get_project_token_id_by_description(args) + + if not token_id: + print('Token with such a description does not exist.') + return + + args.id = token_id + return delete_project_token_by_id(args) + + +def delete_project_token_by_id(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/tokens/' + args.id + response = delete(url, get_user_headers()) + + print(response.json()['message']) + + return response diff --git a/infraboxcli/dashboard/user.py b/infraboxcli/dashboard/user.py new file mode 100644 index 0000000..6e26431 --- /dev/null +++ b/infraboxcli/dashboard/user.py @@ -0,0 +1,32 @@ +import getpass +import json + +from infraboxcli.dashboard.cli_client import post, get +from infraboxcli.dashboard.external import load_current_user_token, save_user_token + +api_endpoint_url = '/api/v1/' + +def get_user_token(): + return load_current_user_token() + +def get_user_headers(): + return {'Authorization': 'token %s' % get_user_token()} + +def login(args): + email = args.email + password = args.password + + if email is None: + email = raw_input("Email: ") + # Don't allow to pass password without email + password = None + + if password is None: + password = getpass.getpass('Password: ') + + data = { "email": email, "password": password} + + url = args.url + api_endpoint_url + 'account/login' + response = post(url, data, cookies_handler=save_user_token) + + return response diff --git a/infraboxcli/run.py b/infraboxcli/run.py index ceaeeb3..441bfe4 100644 --- a/infraboxcli/run.py +++ b/infraboxcli/run.py @@ -453,6 +453,15 @@ def run(args): # validate infrabox.json data = load_infrabox_json(args.infrabox_json) + if args.memory: + print('WARNING: only int resource limits are supported right now. Using rounded int instead of provided value.') + for job in data['jobs']: + job['resources']['limits']['memory'] = int(args.memory) + if args.cpu: + print('WARNING: only int resource limits are supported right now. Using rounded int instead of provided value.') + for job in data['jobs']: + job['resources']['limits']['cpu'] = int(args.cpu) + jobs = get_job_list(data, args, infrabox_context=args.project_root) if not args.job_name: diff --git a/setup.py b/setup.py index cbbed82..35e6280 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,7 @@ def readme(): author='infrabox', license='MIT', packages=['infraboxcli', + 'infraboxcli.dashboard', 'pyinfrabox', 'pyinfrabox.infrabox', 'pyinfrabox.badge', From 1be33777c47c6e9ad8a9fab47ad08d97fa50df6c Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 25 Apr 2018 19:38:33 +0200 Subject: [PATCH 02/24] New CLI API: login api improvements. * Check if remote URL is specified; * Check cli arguments in login method; * Display an error if user entered invalid credentials during login; * Login functionality doesn't require `INFRABOX_CLI_TOKEN` env var anymore. --- infraboxcli/dashboard/external.py | 10 +++++++++- infraboxcli/dashboard/user.py | 3 +++ infraboxcli/env.py | 11 +++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/infraboxcli/dashboard/external.py b/infraboxcli/dashboard/external.py index 297dfe4..cce770c 100644 --- a/infraboxcli/dashboard/external.py +++ b/infraboxcli/dashboard/external.py @@ -1,8 +1,12 @@ +import os import pickle from os.path import expanduser +from infraboxcli.log import logger + home = expanduser("~") + def save_user_token(dict): try: f = open(home + '/.infra.data', 'rb') @@ -12,6 +16,10 @@ def save_user_token(dict): except: obj = {} + if 'token' not in dict.keys(): + logger.error('Unauthorized: invalid username and/or password.') + exit(1) + obj['current_user_token'] = dict['token'] f = open(home + '/.infra.data', 'wb') @@ -40,4 +48,4 @@ def load_current_project_token(): except: raise EnvironmentError('Could not load current project token. Please set current project') - return curr_token \ No newline at end of file + return curr_token diff --git a/infraboxcli/dashboard/user.py b/infraboxcli/dashboard/user.py index 6e26431..2e29b11 100644 --- a/infraboxcli/dashboard/user.py +++ b/infraboxcli/dashboard/user.py @@ -3,6 +3,8 @@ from infraboxcli.dashboard.cli_client import post, get from infraboxcli.dashboard.external import load_current_user_token, save_user_token +import infraboxcli.env + api_endpoint_url = '/api/v1/' @@ -13,6 +15,7 @@ def get_user_headers(): return {'Authorization': 'token %s' % get_user_token()} def login(args): + infraboxcli.env.check_env_url(args) email = args.email password = args.password diff --git a/infraboxcli/env.py b/infraboxcli/env.py index 90a4ad5..b217cfa 100644 --- a/infraboxcli/env.py +++ b/infraboxcli/env.py @@ -1,9 +1,20 @@ import os import jwt +import textwrap from infraboxcli.log import logger + +def check_env_url(args): + if not args.url: + error_msg = textwrap.dedent("\ + Remote URL is not specified. Either set INFRABOX_URL env var " + + "or specify an url via `--url` argument.") + logger.error(error_msg) + exit(1) + def check_env_cli_token(args): + check_env_url(args) token = os.environ.get('INFRABOX_CLI_TOKEN', None) if not token: logger.error('INFRABOX_CLI_TOKEN env var must be set') From 7f35852912fb577564e3dc596f7516355979db34 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Thu, 26 Apr 2018 15:35:22 +0200 Subject: [PATCH 03/24] Bug fixes. Warning msgs are written to logger. --- infraboxcli/run.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/infraboxcli/run.py b/infraboxcli/run.py index 441bfe4..c7ae645 100644 --- a/infraboxcli/run.py +++ b/infraboxcli/run.py @@ -319,8 +319,9 @@ def build_and_run_docker(args, job): cmd += ['-e', 'INFRABOX_CLI=true'] - for e in args.env: - cmd += ['-e', e] + if args.env: + for e in args.env: + cmd += ['-e', e] if args.env_file: cmd += ['--env-file', args.env_file] @@ -454,11 +455,11 @@ def run(args): # validate infrabox.json data = load_infrabox_json(args.infrabox_json) if args.memory: - print('WARNING: only int resource limits are supported right now. Using rounded int instead of provided value.') + logger.warn('WARNING: only int resource limits are supported right now. Using rounded int instead of provided value.') for job in data['jobs']: job['resources']['limits']['memory'] = int(args.memory) if args.cpu: - print('WARNING: only int resource limits are supported right now. Using rounded int instead of provided value.') + logger.warn('WARNING: only int resource limits are supported right now. Using rounded int instead of provided value.') for job in data['jobs']: job['resources']['limits']['cpu'] = int(args.cpu) From 66a9003ec909cce0bfe7e8575472689f43de6a84 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Thu, 26 Apr 2018 16:13:54 +0200 Subject: [PATCH 04/24] Messages are now printed into logs. Logger improvements. --- infraboxcli/dashboard/project.py | 48 +++++++++++++++++++------------- infraboxcli/log.py | 3 ++ 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index 75b52eb..991b038 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -2,6 +2,8 @@ from infraboxcli.dashboard.user import get_user_headers import infraboxcli.env +from infraboxcli.log import logger + api_projects_endpoint_url = '/api/v1/projects/' @@ -19,11 +21,13 @@ def list_collaborators(args): response = get(url, get_user_headers()) if args.verbose: - print('=== Collaborators ===') + logger.info('Collaborators:') + msg = "" for collaborator in response.json(): - print('Username: %s' % collaborator['username']) - print('E-mail: %s' % collaborator['email']) - print('---') + msg += 'Username: %s' % collaborator['username']\ + + '\nE-mail: %s' % collaborator['email']\ + + '\n---\n' + logger.log(msg, print_header=False) return response @@ -34,7 +38,7 @@ def add_collaborator(args): data = { 'username': args.username } response = post(url, data, get_user_headers()) - print(response.json()['message']) + logger.info(response.json()['message']) return response @@ -51,12 +55,12 @@ def remove_collaborator(args): break if collaborator_id is None: - print('Specified user is not in collaborators list.') + logger.info('Specified user is not in collaborators list.') return url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators/' + collaborator_id response = delete(url, get_user_headers()) - print(response.json()['message']) + logger.info(response.json()['message']) return response @@ -67,6 +71,7 @@ def add_secret(args): data = {'name': args.name, 'value': args.value} response = post(url, data, get_user_headers()) + logger.info(response.json()['message']) return response @@ -75,6 +80,7 @@ def delete_secret(args): infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id + '/secrets/' + args.name response = delete(url, get_user_headers()) + logger.info(response.json()['message']) return response @@ -85,13 +91,15 @@ def list_project_tokens(args): response = get(url, get_user_headers()) if args.verbose: - print('=== Project tokens ===') + logger.info('Project tokens:') + msg = "" for project_token in response.json(): - print('Description: %s' % project_token['description']) - print('Id: %s' % project_token['id']) - print('Scope push: %s' % project_token['scope_push']) - print('Scope pull: %s' % project_token['scope_pull']) - print('---') + msg += 'Description: %s' % project_token['description']\ + + '\nId: %s' % project_token['id']\ + + '\nScope push: %s' % project_token['scope_push']\ + + '\nScope pull: %s' % project_token['scope_pull']\ + + '\n---\n' + logger.log(msg, print_header=False) return response @@ -124,13 +132,13 @@ def add_project_token(args): response = post(url, data, get_user_headers()) if response.status_code != 200: - print(response.json()['message']) + logger.error(response.json()['message']) return # Print project token to the CLI - print('=== Authentication Token ===') - print('Please save your token at a secure place. We will not show it to you again.\n\n') - print(response.json()['data']['token']) + logger.info('Authentication Token:' + + '\nPlease save your token at a secure place. We will not show it to you again.\n\n\n') + logger.log(response.json()['data']['token']) return response @@ -141,7 +149,7 @@ def delete_project_token(args): elif args.description: delete_project_token_by_description(args) else: - print('Please, provide either token id or description.') + logger.error('Please, provide either token id or description.') def delete_project_token_by_description(args): @@ -149,7 +157,7 @@ def delete_project_token_by_description(args): token_id = get_project_token_id_by_description(args) if not token_id: - print('Token with such a description does not exist.') + logger.info('Token with such a description does not exist.') return args.id = token_id @@ -161,6 +169,6 @@ def delete_project_token_by_id(args): url = args.url + api_projects_endpoint_url + args.project_id + '/tokens/' + args.id response = delete(url, get_user_headers()) - print(response.json()['message']) + logger.info(response.json()['message']) return response diff --git a/infraboxcli/log.py b/infraboxcli/log.py index fed7750..5a485b3 100644 --- a/infraboxcli/log.py +++ b/infraboxcli/log.py @@ -8,6 +8,9 @@ def __init__(self): def _print(self, color, s): print("%s[infrabox] %s%s" % (color, s, Fore.RESET)) + def log(self, s, print_header=True): + print("%s%s" % ("[infrabox] " if print_header else "", s)) + def info(self, s): self._print(Fore.BLUE, s) From a2c49aa71c7d368e6d59366ca2937127451e3052 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Thu, 26 Apr 2018 17:00:28 +0200 Subject: [PATCH 05/24] New CLI API: secrets API improvements. * Added `secrets list` command to list all project' secrets; * Fixed secrets deleting functionality; * Added possibility to delete secret by id. --- infraboxcli/__init__.py | 9 +++++- infraboxcli/dashboard/project.py | 53 +++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index d85700b..58bba22 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -126,13 +126,20 @@ def main(): parser_secrets = sub_parser.add_parser('secrets', help='Create or delete secrets') sub_secrets = parser_secrets.add_subparsers() + parser_list_secrets = sub_secrets.add_parser('list', help='Show all your secrets') + parser_list_secrets.add_argument('--verbose', required=False, default=True, type=str2bool) + parser_list_secrets.set_defaults(func=project.list_secrets) + parser_create_secret = sub_secrets.add_parser('create', help='Create a secret') parser_create_secret.add_argument('--name', required=True, type=str, help='Name of the secret') parser_create_secret.add_argument('--value', required=True, type=str, help='Value of the secret') parser_create_secret.set_defaults(func=project.add_secret) parser_delete_secret = sub_secrets.add_parser('delete', help='Delete a secret') - parser_delete_secret.add_argument('--name', required=True, type=str, help='Name of the secret you want to delete') + parser_delete_secret.add_argument('--name', required=False, type=str, + help='Name of the secret you want to delete') + parser_delete_secret.add_argument('--id', required=False, type=str, + help='Id of the secret you want to delete') parser_delete_secret.set_defaults(func=project.delete_secret) # Tokens diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index 991b038..9234911 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -65,6 +65,34 @@ def remove_collaborator(args): return response +def list_secrets(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' + + response = get(url, get_user_headers()) + if args.verbose: + logger.info('Secrects:') + msg = "" + for secret in response.json(): + msg += 'Name: %s' % secret['name']\ + + '\nId: %s' % secret['id']\ + + '\n---\n' + logger.log(msg, print_header=False) + + return response + + +def get_secret_id_by_name(args): + args.verbose = False + all_secrets = list_secrets(args).json() + + for secret in all_secrets: + if args.name == secret['name']: + return secret['id'] + + return None + + def add_secret(args): infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' @@ -77,8 +105,31 @@ def add_secret(args): def delete_secret(args): + if args.id: + delete_secret_by_id(args) + elif args.name: + delete_secret_by_name(args) + else: + logger.error('Please, provide either token id or description.') + + +def delete_secret_by_name(args): infraboxcli.env.check_env_cli_token(args) - url = args.url + api_projects_endpoint_url + args.project_id + '/secrets/' + args.name + + secret_id = get_secret_id_by_name(args) + + if not secret_id: + logger.info('Secret with such a name does not exist.') + return + + args.id = secret_id + return delete_secret_by_id(args) + + +def delete_secret_by_id(args): + infraboxcli.env.check_env_cli_token(args) + + url = args.url + api_projects_endpoint_url + args.project_id + '/secrets/' + args.id response = delete(url, get_user_headers()) logger.info(response.json()['message']) From 8493fa84056d5a94013b83f6597c9add17e829a9 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Thu, 26 Apr 2018 17:52:27 +0200 Subject: [PATCH 06/24] New CLI API: project requests imrpovements. * All project requests send `ca_bundle` and `timeout` in arguments; * Changed project-token on-creation message. --- infraboxcli/dashboard/cli_client.py | 14 +++++++------- infraboxcli/dashboard/project.py | 25 +++++++++++++------------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/infraboxcli/dashboard/cli_client.py b/infraboxcli/dashboard/cli_client.py index f789016..0c292c7 100644 --- a/infraboxcli/dashboard/cli_client.py +++ b/infraboxcli/dashboard/cli_client.py @@ -3,22 +3,22 @@ session = requests.Session() -def get(url, headers=None, cookies_handler=None): - response = session.get(url, headers=headers) +def get(url, headers=None, cookies_handler=None, verify=None, timeout=60): + response = session.get(url, headers=headers, verify=verify, timeout=timeout) if cookies_handler: cookies_handler(session.cookies.get_dict()) return response -def post(url, data, headers=None, cookies_handler=None): - response = session.post(url, json=data, headers=headers) +def post(url, data, headers=None, cookies_handler=None, verify=None, timeout=60): + response = session.post(url, json=data, headers=headers, verify=verify, timeout=timeout) if cookies_handler: cookies_handler(session.cookies.get_dict()) return response -def delete(url, headers=None, cookies_handler=None): - response = session.delete(url, headers=headers) +def delete(url, headers=None, cookies_handler=None, verify=None, timeout=60): + response = session.delete(url, headers=headers, verify=verify, timeout=timeout) if cookies_handler: cookies_handler(session.cookies.get_dict()) - return response \ No newline at end of file + return response diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index 9234911..24712df 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -10,7 +10,7 @@ def delete_project(args): infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id - response = get(url, get_user_headers()) + response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) return response @@ -18,7 +18,7 @@ def delete_project(args): def list_collaborators(args): infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators' - response = get(url, get_user_headers()) + response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) if args.verbose: logger.info('Collaborators:') @@ -37,7 +37,7 @@ def add_collaborator(args): url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators' data = { 'username': args.username } - response = post(url, data, get_user_headers()) + response = post(url, data, get_user_headers(), verify=args.ca_bundle, timeout=60) logger.info(response.json()['message']) return response @@ -59,7 +59,8 @@ def remove_collaborator(args): return url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators/' + collaborator_id - response = delete(url, get_user_headers()) + response = delete(url, get_user_headers(), verify=args.ca_bundle, timeout=60) + logger.info(response.json()['message']) return response @@ -69,7 +70,7 @@ def list_secrets(args): infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' - response = get(url, get_user_headers()) + response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) if args.verbose: logger.info('Secrects:') msg = "" @@ -98,7 +99,7 @@ def add_secret(args): url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' data = {'name': args.name, 'value': args.value} - response = post(url, data, get_user_headers()) + response = post(url, data, get_user_headers(), verify=args.ca_bundle, timeout=60) logger.info(response.json()['message']) return response @@ -130,7 +131,7 @@ def delete_secret_by_id(args): infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id + '/secrets/' + args.id - response = delete(url, get_user_headers()) + response = delete(url, get_user_headers(), verify=args.ca_bundle, timeout=60) logger.info(response.json()['message']) return response @@ -140,7 +141,7 @@ def list_project_tokens(args): infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id + '/tokens' - response = get(url, get_user_headers()) + response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) if args.verbose: logger.info('Project tokens:') msg = "" @@ -180,7 +181,7 @@ def add_project_token(args): #'scope_pull': args.scope_pull } - response = post(url, data, get_user_headers()) + response = post(url, data, get_user_headers(), verify=args.ca_bundle, timeout=60) if response.status_code != 200: logger.error(response.json()['message']) @@ -188,8 +189,8 @@ def add_project_token(args): # Print project token to the CLI logger.info('Authentication Token:' - + '\nPlease save your token at a secure place. We will not show it to you again.\n\n\n') - logger.log(response.json()['data']['token']) + + '\nPlease save your token at a secure place. We will not show it to you again.\n') + logger.log(response.json()['data']['token'], print_header=False) return response @@ -218,7 +219,7 @@ def delete_project_token_by_description(args): def delete_project_token_by_id(args): infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id + '/tokens/' + args.id - response = delete(url, get_user_headers()) + response = delete(url, get_user_headers(), verify=args.ca_bundle, timeout=60) logger.info(response.json()['message']) From 58485437e14492e2df0a9dced3002bdb05727006 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Thu, 26 Apr 2018 18:03:07 +0200 Subject: [PATCH 07/24] New CLI API: added basic project API. Refactoring. * Renamed `project-token` command to `tokens`; * `collaborators`, `secrets`, `tokens` commands became a sub-commands of `project` command so: - `infrabox collaborators` -> `infrabox project collaborators`; - `infrabox secrets` -> `infrabox project secrets`; - `infrabox project-token` -> `infrabox project tokens`. --- infraboxcli/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index 58bba22..7d1e1d0 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -104,8 +104,12 @@ def main(): parser_run.set_defaults(no_rm=False) parser_run.set_defaults(func=run) + # Project + parser_project = sub_parser.add_parser('project', help='Manage your project') + sub_project = parser_project.add_subparsers() + # Collaborators - parser_collaborators = sub_parser.add_parser('collaborators', help='Add or remove collaborators for your project') + parser_collaborators = sub_project.add_parser('collaborators', help='Add or remove collaborators for your project') sub_collaborators = parser_collaborators.add_subparsers() parser_list_collaborators = sub_collaborators.add_parser('list', help='Show collaborators list') @@ -123,7 +127,7 @@ def main(): parser_remove_collaborator.set_defaults(func=project.remove_collaborator) # Secrets - parser_secrets = sub_parser.add_parser('secrets', help='Create or delete secrets') + parser_secrets = sub_project.add_parser('secrets', help='Create or delete secrets') sub_secrets = parser_secrets.add_subparsers() parser_list_secrets = sub_secrets.add_parser('list', help='Show all your secrets') @@ -143,7 +147,7 @@ def main(): parser_delete_secret.set_defaults(func=project.delete_secret) # Tokens - parsers_project_tokens = sub_parser.add_parser('project-token', help='Manage your project tokens') + parsers_project_tokens = sub_project.add_parser('tokens', help='Manage your project tokens') sub_project_tokens = parsers_project_tokens.add_subparsers() parser_list_project_tokens = sub_project_tokens.add_parser('list', help='Show all your project tokens') From 7bcc0f7e7a15fcbe556dad6bd09eb730e659055f Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Thu, 26 Apr 2018 19:15:35 +0200 Subject: [PATCH 08/24] New CLI API: project API improvements. * Added `project list` command to list all projects which belong to the current user. --- infraboxcli/__init__.py | 4 ++++ infraboxcli/dashboard/project.py | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index 7d1e1d0..726329a 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -108,6 +108,10 @@ def main(): parser_project = sub_parser.add_parser('project', help='Manage your project') sub_project = parser_project.add_subparsers() + parser_projects_list = sub_project.add_parser('list', help='Get a list of all your projects') + parser_projects_list.add_argument('--verbose', required=False, default=True, type=str2bool) + parser_projects_list.set_defaults(func=project.list_projects) + # Collaborators parser_collaborators = sub_project.add_parser('collaborators', help='Add or remove collaborators for your project') sub_collaborators = parser_collaborators.add_subparsers() diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index 24712df..08bdc48 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -7,6 +7,23 @@ api_projects_endpoint_url = '/api/v1/projects/' +def list_projects(args): + infraboxcli.env.check_env_url(args) + url = args.url + api_projects_endpoint_url[:len(api_projects_endpoint_url) - 1] + response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) + + if args.verbose: + logger.info('Projects:') + msg = "" + for project in response.json(): + #TODO: display if project is public or not + msg += 'Name: {}\nId: {}\nType: {}\n---\n'\ + .format(project['name'], project['id'], project['type']) + logger.log(msg, print_header=False) + + return response + + def delete_project(args): infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id From bffc481cba2de606becad2841fee2995dee8d2ec Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Fri, 27 Apr 2018 15:33:38 +0200 Subject: [PATCH 09/24] Project API: display if project is public or not. --- infraboxcli/dashboard/project.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index 08bdc48..95465f2 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -9,16 +9,15 @@ def list_projects(args): infraboxcli.env.check_env_url(args) - url = args.url + api_projects_endpoint_url[:len(api_projects_endpoint_url) - 1] + url = args.url + api_projects_endpoint_url[:-1] response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) if args.verbose: logger.info('Projects:') msg = "" for project in response.json(): - #TODO: display if project is public or not - msg += 'Name: {}\nId: {}\nType: {}\n---\n'\ - .format(project['name'], project['id'], project['type']) + msg += 'Name: {}\nId: {}\nType: {}\nPublic: {}\n---\n'\ + .format(project['name'], project['id'], project['type'], project['public']) logger.log(msg, print_header=False) return response From 85bb25a67f8bc29ba5494de8501cc2d32ab230a8 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Fri, 27 Apr 2018 16:57:26 +0200 Subject: [PATCH 10/24] Project API: added create and delete project cmd. --- infraboxcli/__init__.py | 19 +++++++ infraboxcli/dashboard/project.py | 86 ++++++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index 726329a..1152b14 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -112,6 +112,25 @@ def main(): parser_projects_list.add_argument('--verbose', required=False, default=True, type=str2bool) parser_projects_list.set_defaults(func=project.list_projects) + parser_project_create = sub_project.add_parser('create', help='Create a new project') + parser_project_create.add_argument('--name', required=True, type=str, + help='Name of the project you want to create') + parser_project_create.add_argument('--type', required=True, type=str, + help='Name of the project { upload, github, gerrit } you want to create') + parser_project_create.add_argument('--public', required=False, default=False, action='store_true', + help='Make your project public') + parser_project_create.add_argument('--private', required=False, default=False, action='store_true', + help='Make your project private') + parser_project_create.set_defaults(func=project.create_project) + + parser_project_delete = sub_project.add_parser('delete', help='Delete a project') + parser_project_delete.add_argument('--name', required=False, type=str, + help='Name of the project you want to delete') + parser_project_delete.add_argument('--id', required=False, type=str, + help='Id of the project you want to delete') + parser_project_delete.set_defaults(func=project.delete_project) + + # Collaborators parser_collaborators = sub_project.add_parser('collaborators', help='Add or remove collaborators for your project') sub_collaborators = parser_collaborators.add_subparsers() diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index 95465f2..d70a26f 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -5,11 +5,12 @@ from infraboxcli.log import logger api_projects_endpoint_url = '/api/v1/projects/' +allowed_project_types = ['upload'] #TODO: add ['github', 'gitlab', 'gerrit'] def list_projects(args): infraboxcli.env.check_env_url(args) - url = args.url + api_projects_endpoint_url[:-1] + url = args.url + api_projects_endpoint_url response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) if args.verbose: @@ -23,10 +24,87 @@ def list_projects(args): return response +def create_project(args): + infraboxcli.env.check_env_url(args) + + if not args.private and not args.public: + logger.error('Specify if your project is going to be public or private, please.') + return + + if args.private and args.public: + logger.error('Project can\'t be public and private simultaneously. ' + + 'Choose only one option, please.') + return + + is_private_project = True + if args.public: + is_private_project = False + + if args.type not in allowed_project_types: + logger.error('Provided project type is not supported.' + + '\nAllowed project types are: [{allowed_types}]' + .format(allowed_types=', '.join(allowed_project_types))) + return + + url = args.url + api_projects_endpoint_url + + data = { + 'name': args.name, + 'type': args.type, + 'private': is_private_project + } + response = post(url, data=data, headers=get_user_headers(), verify=args.ca_bundle, timeout=60) + + if response.status_code != 200: + logger.error(response.json()['message']) + else: + logger.info(response.json()['message']) + + return response + + +def get_project_id_by_name(args): + args.verbose = False + all_projects = list_projects(args).json() + + for project in all_projects: + if args.name == project['name']: + return project['id'] + + return None + + def delete_project(args): - infraboxcli.env.check_env_cli_token(args) - url = args.url + api_projects_endpoint_url + args.project_id - response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) + if args.id: + delete_project_by_id(args) + elif args.name: + delete_project_by_name(args) + else: + logger.error('Please, provide either token id or name.') + + +def delete_project_by_name(args): + infraboxcli.env.check_env_url(args) + + project_id = get_project_id_by_name(args) + + if not project_id: + logger.info('Project with such a name does not exist.') + return + + args.id = project_id + return delete_project_by_id(args) + + +def delete_project_by_id(args): + infraboxcli.env.check_env_url(args) + url = args.url + api_projects_endpoint_url + args.id + response = delete(url, headers=get_user_headers(), verify=args.ca_bundle, timeout=60) + + if response.status_code != 200: + logger.error(response.json()['message']) + else: + logger.info(response.json()['message']) return response From 6c68a3030df3dae46e410caab9fd1047c3805502 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 2 May 2018 15:28:16 +0200 Subject: [PATCH 11/24] Refactoring --- infraboxcli/dashboard/project.py | 6 +++--- infraboxcli/env.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index d70a26f..d1f5def 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -71,6 +71,7 @@ def get_project_id_by_name(args): if args.name == project['name']: return project['id'] + logger.info('Project with such a name does not exist.') return None @@ -89,7 +90,6 @@ def delete_project_by_name(args): project_id = get_project_id_by_name(args) if not project_id: - logger.info('Project with such a name does not exist.') return args.id = project_id @@ -185,6 +185,7 @@ def get_secret_id_by_name(args): if args.name == secret['name']: return secret['id'] + logger.info('Secret with such a name does not exist.') return None @@ -214,7 +215,6 @@ def delete_secret_by_name(args): secret_id = get_secret_id_by_name(args) if not secret_id: - logger.info('Secret with such a name does not exist.') return args.id = secret_id @@ -258,6 +258,7 @@ def get_project_token_id_by_description(args): if args.description == project_token['description']: return project_token['id'] + logger.info('Token with such a description does not exist.') return None @@ -303,7 +304,6 @@ def delete_project_token_by_description(args): token_id = get_project_token_id_by_description(args) if not token_id: - logger.info('Token with such a description does not exist.') return args.id = token_id diff --git a/infraboxcli/env.py b/infraboxcli/env.py index b217cfa..43316f6 100644 --- a/infraboxcli/env.py +++ b/infraboxcli/env.py @@ -13,6 +13,7 @@ def check_env_url(args): logger.error(error_msg) exit(1) + def check_env_cli_token(args): check_env_url(args) token = os.environ.get('INFRABOX_CLI_TOKEN', None) From 98838c919534034e6b2554d3e94874a4ee728e2a Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 2 May 2018 18:14:45 +0200 Subject: [PATCH 12/24] Project API: new argument added. Refactoring. * Added argument `proj-name` to the `project` to specify project name for the subsequent command (`collaborators`, `secrets`, `tokens`); * Refactoring. --- infraboxcli/__init__.py | 1 + infraboxcli/dashboard/project.py | 132 ++++++++++++++++++++----------- infraboxcli/env.py | 6 ++ 3 files changed, 95 insertions(+), 44 deletions(-) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index 1152b14..45d2766 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -106,6 +106,7 @@ def main(): # Project parser_project = sub_parser.add_parser('project', help='Manage your project') + parser_project.add_argument('--proj-name', required=False, type=str) sub_project = parser_project.add_subparsers() parser_projects_list = sub_project.add_parser('list', help='Get a list of all your projects') diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index d1f5def..8dcf12a 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -8,21 +8,43 @@ allowed_project_types = ['upload'] #TODO: add ['github', 'gitlab', 'gerrit'] -def list_projects(args): +def check_project_name_set(args): + infraboxcli.env.check_env_url(args) + if args.proj_name: + args.name = args.proj_name + + args.project_id = get_project_id_by_name(args) + + if args.project_id is not None: + if 'project_name_printed' not in args: + logger.info('Project: {project_name}'.format(project_name=args.proj_name)) + args.project_name_printed = True + + return True + + return False + + +def get_projects(args): infraboxcli.env.check_env_url(args) + url = args.url + api_projects_endpoint_url response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) + return response + + +def list_projects(args): if args.verbose: + all_projects = get_projects(args).json() + logger.info('Projects:') msg = "" - for project in response.json(): + for project in all_projects: msg += 'Name: {}\nId: {}\nType: {}\nPublic: {}\n---\n'\ .format(project['name'], project['id'], project['type'], project['public']) logger.log(msg, print_header=False) - return response - def create_project(args): infraboxcli.env.check_env_url(args) @@ -64,8 +86,7 @@ def create_project(args): def get_project_id_by_name(args): - args.verbose = False - all_projects = list_projects(args).json() + all_projects = get_projects(args).json() for project in all_projects: if args.name == project['name']: @@ -109,39 +130,45 @@ def delete_project_by_id(args): return response -def list_collaborators(args): - infraboxcli.env.check_env_cli_token(args) +def get_collaborators(args): + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators' response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) + return response + +def list_collaborators(args): if args.verbose: + all_collaborators = get_collaborators(args).json() + logger.info('Collaborators:') msg = "" - for collaborator in response.json(): + for collaborator in all_collaborators: msg += 'Username: %s' % collaborator['username']\ + '\nE-mail: %s' % collaborator['email']\ + '\n---\n' logger.log(msg, print_header=False) - return response - def add_collaborator(args): - infraboxcli.env.check_env_cli_token(args) + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators' data = { 'username': args.username } - response = post(url, data, get_user_headers(), verify=args.ca_bundle, timeout=60) - logger.info(response.json()['message']) + logger.info(response.json()['message']) return response def remove_collaborator(args): - infraboxcli.env.check_env_cli_token(args) + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) - args.verbose = False - all_project_collaborators = list_collaborators(args).json() + all_project_collaborators = get_collaborators(args).json() collaborator_id = None for collaborator in all_project_collaborators: if collaborator['username'] == args.username: @@ -156,30 +183,34 @@ def remove_collaborator(args): response = delete(url, get_user_headers(), verify=args.ca_bundle, timeout=60) logger.info(response.json()['message']) - return response -def list_secrets(args): - infraboxcli.env.check_env_cli_token(args) - url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' +def get_secrets(args): + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) + + return response + + +def list_secrets(args): if args.verbose: + all_secrets = get_secrets(args).json() + logger.info('Secrects:') msg = "" - for secret in response.json(): + for secret in all_secrets: msg += 'Name: %s' % secret['name']\ + '\nId: %s' % secret['id']\ + '\n---\n' logger.log(msg, print_header=False) - return response - def get_secret_id_by_name(args): - args.verbose = False - all_secrets = list_secrets(args).json() + all_secrets = get_secrets(args).json() for secret in all_secrets: if args.name == secret['name']: @@ -190,13 +221,14 @@ def get_secret_id_by_name(args): def add_secret(args): - infraboxcli.env.check_env_cli_token(args) + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' data = {'name': args.name, 'value': args.value} - response = post(url, data, get_user_headers(), verify=args.ca_bundle, timeout=60) - logger.info(response.json()['message']) + logger.info(response.json()['message']) return response @@ -210,7 +242,8 @@ def delete_secret(args): def delete_secret_by_name(args): - infraboxcli.env.check_env_cli_token(args) + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) secret_id = get_secret_id_by_name(args) @@ -222,24 +255,33 @@ def delete_secret_by_name(args): def delete_secret_by_id(args): - infraboxcli.env.check_env_cli_token(args) + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) url = args.url + api_projects_endpoint_url + args.project_id + '/secrets/' + args.id response = delete(url, get_user_headers(), verify=args.ca_bundle, timeout=60) - logger.info(response.json()['message']) + logger.info(response.json()['message']) return response -def list_project_tokens(args): - infraboxcli.env.check_env_cli_token(args) - url = args.url + api_projects_endpoint_url + args.project_id + '/tokens' +def get_project_tokens(args): + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/tokens' response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) + + return response + + +def list_project_tokens(args): if args.verbose: + all_project_tokens = get_project_tokens(args).json() + logger.info('Project tokens:') msg = "" - for project_token in response.json(): + for project_token in all_project_tokens: msg += 'Description: %s' % project_token['description']\ + '\nId: %s' % project_token['id']\ + '\nScope push: %s' % project_token['scope_push']\ @@ -247,12 +289,9 @@ def list_project_tokens(args): + '\n---\n' logger.log(msg, print_header=False) - return response - def get_project_token_id_by_description(args): - args.verbose = False - all_project_tokens = list_project_tokens(args).json() + all_project_tokens = get_project_tokens(args).json() for project_token in all_project_tokens: if args.description == project_token['description']: @@ -263,7 +302,9 @@ def get_project_token_id_by_description(args): def add_project_token(args): - infraboxcli.env.check_env_cli_token(args) + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/tokens' data = { @@ -300,7 +341,9 @@ def delete_project_token(args): def delete_project_token_by_description(args): - infraboxcli.env.check_env_cli_token(args) + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) + token_id = get_project_token_id_by_description(args) if not token_id: @@ -311,10 +354,11 @@ def delete_project_token_by_description(args): def delete_project_token_by_id(args): - infraboxcli.env.check_env_cli_token(args) + if not check_project_name_set(args): + infraboxcli.env.check_env_cli_token(args) + url = args.url + api_projects_endpoint_url + args.project_id + '/tokens/' + args.id response = delete(url, get_user_headers(), verify=args.ca_bundle, timeout=60) logger.info(response.json()['message']) - return response diff --git a/infraboxcli/env.py b/infraboxcli/env.py index 43316f6..51c983d 100644 --- a/infraboxcli/env.py +++ b/infraboxcli/env.py @@ -16,6 +16,12 @@ def check_env_url(args): def check_env_cli_token(args): check_env_url(args) + + # If we provided project name and enter this function for some reasons + # just return from it + if args.proj_name: + exit(1) + token = os.environ.get('INFRABOX_CLI_TOKEN', None) if not token: logger.error('INFRABOX_CLI_TOKEN env var must be set') From c715e13aa78e7b9102904b3f1245f4200ef499df Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 2 May 2018 18:57:47 +0200 Subject: [PATCH 13/24] Project API: refactoring and fixes. * Renamed argument `proj_name` to `project_name`; * Some bugs fixes. --- infraboxcli/__init__.py | 11 +++++++++-- infraboxcli/dashboard/project.py | 9 ++++----- infraboxcli/env.py | 5 ++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index 45d2766..38f03d6 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -106,8 +106,9 @@ def main(): # Project parser_project = sub_parser.add_parser('project', help='Manage your project') - parser_project.add_argument('--proj-name', required=False, type=str) - sub_project = parser_project.add_subparsers() + parser_project.add_argument('--project-name', required=False, type=str) + parser_project.set_defaults(project_command=True) + sub_project = parser_project.add_subparsers(dest='project') parser_projects_list = sub_project.add_parser('list', help='Get a list of all your projects') parser_projects_list.add_argument('--verbose', required=False, default=True, type=str2bool) @@ -202,6 +203,12 @@ def main(): # Parse args args = parser.parse_args() + # Prevent collision on `project-name` argument with `run`, `pull`, `push` commands + if 'project' in args: + # Run command + args.func(args) + return + if 'version' in args: print('infraboxcli %s' % version) return diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index 8dcf12a..a0b4ab3 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -10,14 +10,12 @@ def check_project_name_set(args): infraboxcli.env.check_env_url(args) - if args.proj_name: - args.name = args.proj_name - + if args.project_name: args.project_id = get_project_id_by_name(args) if args.project_id is not None: if 'project_name_printed' not in args: - logger.info('Project: {project_name}'.format(project_name=args.proj_name)) + logger.info('Project: {project_name}'.format(project_name=args.project_name)) args.project_name_printed = True return True @@ -89,7 +87,7 @@ def get_project_id_by_name(args): all_projects = get_projects(args).json() for project in all_projects: - if args.name == project['name']: + if args.project_name == project['name']: return project['id'] logger.info('Project with such a name does not exist.') @@ -108,6 +106,7 @@ def delete_project(args): def delete_project_by_name(args): infraboxcli.env.check_env_url(args) + args.project_name = args.name project_id = get_project_id_by_name(args) if not project_id: diff --git a/infraboxcli/env.py b/infraboxcli/env.py index 51c983d..1e505e0 100644 --- a/infraboxcli/env.py +++ b/infraboxcli/env.py @@ -19,7 +19,10 @@ def check_env_cli_token(args): # If we provided project name and enter this function for some reasons # just return from it - if args.proj_name: + if 'project_name' in args \ + and args.project_name \ + and 'project_command' in args \ + and args.project_command: exit(1) token = os.environ.get('INFRABOX_CLI_TOKEN', None) From d148f46b931cc71df9d0f0ca64937ba9ec67da91 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Fri, 4 May 2018 23:55:40 +0200 Subject: [PATCH 14/24] Login API: major improvements. Other fixes. * Added possibility to login to specified remote url by providing it after login command, e.g: `$ infrabox login http://localhost:8080` * All config data now is stored in `~/.infrabox/config.json` file: - list of remotes; - each remote contains current user token and current project; - current remote. * Minor improvements; * Refactoring. --- infraboxcli/__init__.py | 1 + infraboxcli/dashboard/cli_client.py | 6 +- infraboxcli/dashboard/external.py | 89 +++++++++++++++++++---------- infraboxcli/dashboard/user.py | 8 ++- infraboxcli/env.py | 6 ++ pyinfrabox/utils.py | 32 +++++++++++ 6 files changed, 107 insertions(+), 35 deletions(-) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index 38f03d6..898202d 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -196,6 +196,7 @@ def main(): # User parser_login = sub_parser.add_parser('login', help='Login to infrabox') + parser_login.add_argument('remote_url', nargs='?', type=str, help='Name of remote') parser_login.add_argument('--email', required=False, default=None, type=str, help='Email of the user') parser_login.add_argument('--password', required=False, default=None, type=str, help='Password of the user') parser_login.set_defaults(func=user.login) diff --git a/infraboxcli/dashboard/cli_client.py b/infraboxcli/dashboard/cli_client.py index 0c292c7..c3e45fc 100644 --- a/infraboxcli/dashboard/cli_client.py +++ b/infraboxcli/dashboard/cli_client.py @@ -6,19 +6,19 @@ def get(url, headers=None, cookies_handler=None, verify=None, timeout=60): response = session.get(url, headers=headers, verify=verify, timeout=timeout) if cookies_handler: - cookies_handler(session.cookies.get_dict()) + cookies_handler(url, session.cookies.get_dict()) return response def post(url, data, headers=None, cookies_handler=None, verify=None, timeout=60): response = session.post(url, json=data, headers=headers, verify=verify, timeout=timeout) if cookies_handler: - cookies_handler(session.cookies.get_dict()) + cookies_handler(url, session.cookies.get_dict()) return response def delete(url, headers=None, cookies_handler=None, verify=None, timeout=60): response = session.delete(url, headers=headers, verify=verify, timeout=timeout) if cookies_handler: - cookies_handler(session.cookies.get_dict()) + cookies_handler(url, session.cookies.get_dict()) return response diff --git a/infraboxcli/dashboard/external.py b/infraboxcli/dashboard/external.py index cce770c..8a68960 100644 --- a/infraboxcli/dashboard/external.py +++ b/infraboxcli/dashboard/external.py @@ -1,51 +1,80 @@ import os -import pickle +import json from os.path import expanduser from infraboxcli.log import logger +from pyinfrabox.utils import get_remote_url, safe_open_w home = expanduser("~") +config_file_path = '/.infrabox/config.json' -def save_user_token(dict): - try: - f = open(home + '/.infra.data', 'rb') - obj = pickle.load(f) - f.close() +def save_user_token(url, cookies_dict): + config = get_config() + if config is None: + config = {} - except: - obj = {} + config.setdefault('remotes', {}) + + is_new_remote_or_null = False + remote_url = get_remote_url(url) + if remote_url not in config['remotes'] \ + or config['remotes'][remote_url] is None: + is_new_remote_or_null = True - if 'token' not in dict.keys(): - logger.error('Unauthorized: invalid username and/or password.') - exit(1) + # Decide what are we going to do if user entered invalid username or password: + # either use `current_user_token` if it exists or raise an error + allow_login_if_current_user_token_is_set = False - obj['current_user_token'] = dict['token'] + user_token = None + if 'token' not in cookies_dict: + if is_new_remote_or_null or not allow_login_if_current_user_token_is_set: + logger.error('Unauthorized: invalid username and/or password.') + exit(1) + else: + user_token = config['remotes'][remote_url]['current_user_token'] + else: + user_token = cookies_dict['token'] - f = open(home + '/.infra.data', 'wb') - pickle.dump(obj, f) - f.close() + config['current_remote'] = remote_url + config['remotes'].setdefault(remote_url, {}) + config['remotes'][remote_url]['current_user_token'] = user_token + with safe_open_w(home + config_file_path) as config_file: + json.dump(config, config_file) + logger.info('Logged in successfully.') -def load_current_user_token(): + +def get_config(): try: - f = open(home + '/.infra.data', 'rb') - obj = pickle.load(f) - f.close() - curr_token = obj['current_user_token'] - except: - raise EnvironmentError('Could not load current user token. Please log in') + with open(home + config_file_path, 'r') as config_file: + config = json.load(config_file) - return curr_token + return config + except: + return None + #logger.info('Config file does not exist or invalid.') -def load_current_project_token(): +def get_current_remote(): try: - f = open(home + '/.infra.data', 'rb') - obj = pickle.load(f) - f.close() - curr_token = obj['current_project_token'] + return get_config()['current_remote'] except: - raise EnvironmentError('Could not load current project token. Please set current project') + return None - return curr_token + +def get_current_user_token(): + try: + config = get_config() + + current_remote = config['current_remote'] + if not current_remote: + raise + + current_user_token = config['remotes'][current_remote]['current_user_token'] + if current_user_token is None: + raise + + return current_user_token + except: + logger.error('Could not load current user token. Please, log in.') diff --git a/infraboxcli/dashboard/user.py b/infraboxcli/dashboard/user.py index 2e29b11..33c949e 100644 --- a/infraboxcli/dashboard/user.py +++ b/infraboxcli/dashboard/user.py @@ -2,20 +2,24 @@ import json from infraboxcli.dashboard.cli_client import post, get -from infraboxcli.dashboard.external import load_current_user_token, save_user_token +from infraboxcli.dashboard.external import get_current_user_token, save_user_token import infraboxcli.env api_endpoint_url = '/api/v1/' def get_user_token(): - return load_current_user_token() + return get_current_user_token() def get_user_headers(): return {'Authorization': 'token %s' % get_user_token()} def login(args): + if args.remote_url: + args.url = args.remote_url + infraboxcli.env.check_env_url(args) + email = args.email password = args.password diff --git a/infraboxcli/env.py b/infraboxcli/env.py index 1e505e0..896d758 100644 --- a/infraboxcli/env.py +++ b/infraboxcli/env.py @@ -3,10 +3,16 @@ import textwrap from infraboxcli.log import logger +from infraboxcli.dashboard.external import get_current_remote def check_env_url(args): if not args.url: + current_remote = get_current_remote() + if current_remote: + args.url = current_remote + return + error_msg = textwrap.dedent("\ Remote URL is not specified. Either set INFRABOX_URL env var " + "or specify an url via `--url` argument.") diff --git a/pyinfrabox/utils.py b/pyinfrabox/utils.py index 0a543e9..d51be5b 100644 --- a/pyinfrabox/utils.py +++ b/pyinfrabox/utils.py @@ -1,8 +1,17 @@ +import os +import errno + from builtins import int, range, str from past.builtins import basestring from pyinfrabox import ValidationError +#python3 +#from urllib.parse.urlparse import urlparse +#python2 +from urlparse import urlparse + + def check_text(t, path, allowEmpty=False): if not isinstance(t, basestring): raise ValidationError(path, "is not a string") @@ -49,3 +58,26 @@ def check_number(d, path): def check_color(d, path): if d not in ("red", "green", "blue", "yellow", "orange", "white", "black", "grey"): raise ValidationError(path, "not a valid value") + +def get_remote_url(url): + parsed_url = urlparse(url) + return parsed_url.scheme + '://' + parsed_url.netloc + +def mkdir_p(path): + """ + An implementation of `mkdir -p` UNIX command. + """ + try: + os.makedirs(path) + except OSError as e: + if e.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + raise + +def safe_open_w(path): + """ + Open 'path' variable for writing with creating all parent directories if needed. + """ + mkdir_p(os.path.dirname(path)) + return open(path, 'w') From 31af2b9c5535648d788c1e84dcaa38eec02a68b2 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Sat, 5 May 2018 00:00:44 +0200 Subject: [PATCH 15/24] Refactoring. --- infraboxcli/dashboard/external.py | 2 +- infraboxcli/env.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/infraboxcli/dashboard/external.py b/infraboxcli/dashboard/external.py index 8a68960..acd2cbf 100644 --- a/infraboxcli/dashboard/external.py +++ b/infraboxcli/dashboard/external.py @@ -56,7 +56,7 @@ def get_config(): #logger.info('Config file does not exist or invalid.') -def get_current_remote(): +def get_current_remote_url(): try: return get_config()['current_remote'] except: diff --git a/infraboxcli/env.py b/infraboxcli/env.py index 896d758..6a6992d 100644 --- a/infraboxcli/env.py +++ b/infraboxcli/env.py @@ -3,14 +3,14 @@ import textwrap from infraboxcli.log import logger -from infraboxcli.dashboard.external import get_current_remote +from infraboxcli.dashboard.external import get_current_remote_url def check_env_url(args): if not args.url: - current_remote = get_current_remote() - if current_remote: - args.url = current_remote + current_remote_url = get_current_remote_url() + if current_remote_url: + args.url = current_remote_url return error_msg = textwrap.dedent("\ From 8d71d057ca5d238b0be3bcdabf8c39c7bec7d4d9 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Mon, 7 May 2018 13:46:27 +0200 Subject: [PATCH 16/24] Remotes API: added `list_remotes` feature. * Added method to get all available remotes (stored in infrabox config file). To perform this command: `$ infrabox remotes list`. --- infraboxcli/__init__.py | 8 ++++++++ infraboxcli/dashboard/external.py | 15 +++++++++++++++ infraboxcli/dashboard/remotes.py | 12 ++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 infraboxcli/dashboard/remotes.py diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index 898202d..14a56e1 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -13,6 +13,7 @@ from infraboxcli.dashboard import user from infraboxcli.dashboard import project +from infraboxcli.dashboard import remotes version = '0.6.4' @@ -201,6 +202,13 @@ def main(): parser_login.add_argument('--password', required=False, default=None, type=str, help='Password of the user') parser_login.set_defaults(func=user.login) + # Remotes + parser_remotes = sub_parser.add_parser('remotes', help='Current remotes') + sub_remotes = parser_remotes.add_subparsers() + parser_remotes_list = sub_remotes.add_parser('list', help='Show your all remotes') + parser_remotes_list.add_argument('--verbose', required=False, default=True, type=str2bool) + parser_remotes_list.set_defaults(func=remotes.list_remotes) + # Parse args args = parser.parse_args() diff --git a/infraboxcli/dashboard/external.py b/infraboxcli/dashboard/external.py index acd2cbf..e9b0a2d 100644 --- a/infraboxcli/dashboard/external.py +++ b/infraboxcli/dashboard/external.py @@ -78,3 +78,18 @@ def get_current_user_token(): return current_user_token except: logger.error('Could not load current user token. Please, log in.') + exit(1) + + +def get_all_remotes(): + try: + config = get_config() + + remotes = config['remotes'].keys() + if not remotes: + raise + + return remotes + except: + logger.error('No available remotes. Please, log in.') + exit(1) diff --git a/infraboxcli/dashboard/remotes.py b/infraboxcli/dashboard/remotes.py new file mode 100644 index 0000000..14749b7 --- /dev/null +++ b/infraboxcli/dashboard/remotes.py @@ -0,0 +1,12 @@ +from infraboxcli.dashboard import external +from infraboxcli.log import logger + + +def list_remotes(args): + if args.verbose: + remotes = external.get_all_remotes() + + msg = ': ' + msg += '\n: '.join(remotes) + logger.info('Remotes:') + logger.log(msg, print_header=False) From d95b9f122f790f257b1a2d238c55d65581471dbb Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Mon, 7 May 2018 20:16:26 +0200 Subject: [PATCH 17/24] Config API: added `set-current-project` command. * It's possible to add and store current project for the cli workflow: `$ infrabox config set-current-project PROJECT_NAME`; * Config functionality: minor improvements and refactoring; * Minor bugs fixes. --- infraboxcli/__init__.py | 12 ++++++-- infraboxcli/dashboard/external.py | 50 ++++++++++++++++++++++++++++--- infraboxcli/dashboard/project.py | 9 ++++++ infraboxcli/env.py | 4 +-- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index 14a56e1..91b36c0 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -14,6 +14,7 @@ from infraboxcli.dashboard import user from infraboxcli.dashboard import project from infraboxcli.dashboard import remotes +from infraboxcli.dashboard import external version = '0.6.4' @@ -133,7 +134,6 @@ def main(): help='Id of the project you want to delete') parser_project_delete.set_defaults(func=project.delete_project) - # Collaborators parser_collaborators = sub_project.add_parser('collaborators', help='Add or remove collaborators for your project') sub_collaborators = parser_collaborators.add_subparsers() @@ -202,6 +202,14 @@ def main(): parser_login.add_argument('--password', required=False, default=None, type=str, help='Password of the user') parser_login.set_defaults(func=user.login) + # Config + parser_config = sub_parser.add_parser('config', help='Configure your infrabox') + sub_config = parser_config.add_subparsers(dest='config') + + parser_config_current_project = sub_config.add_parser('set-current-project', help='Set new current project') + parser_config_current_project.add_argument('project_name', nargs='?', type=str, help='Name of the project') + parser_config_current_project.set_defaults(func=external.set_current_project_name) + # Remotes parser_remotes = sub_parser.add_parser('remotes', help='Current remotes') sub_remotes = parser_remotes.add_subparsers() @@ -213,7 +221,7 @@ def main(): args = parser.parse_args() # Prevent collision on `project-name` argument with `run`, `pull`, `push` commands - if 'project' in args: + if 'project' in args or 'config' in args: # Run command args.func(args) return diff --git a/infraboxcli/dashboard/external.py b/infraboxcli/dashboard/external.py index e9b0a2d..d8ff496 100644 --- a/infraboxcli/dashboard/external.py +++ b/infraboxcli/dashboard/external.py @@ -4,6 +4,7 @@ from infraboxcli.log import logger from pyinfrabox.utils import get_remote_url, safe_open_w +#from infraboxcli.dashboard import project home = expanduser("~") config_file_path = '/.infrabox/config.json' @@ -40,9 +41,41 @@ def save_user_token(url, cookies_dict): config['remotes'].setdefault(remote_url, {}) config['remotes'][remote_url]['current_user_token'] = user_token - with safe_open_w(home + config_file_path) as config_file: - json.dump(config, config_file) - logger.info('Logged in successfully.') + save_config(config) + logger.info('Logged in successfully.') + + +def set_current_project_name(args): + #infraboxcli.env.check_env_url(args) + #all_projects = project.get_projects(args).json() + + #project_exists = False + #for project in all_projects: + # if args.project_name == project['name']: + # project_exists = True + # break + + #if not project_exists: + # logger.error('Project with such a name does not exist.') + # exit(1) + + try: + config = get_config() + + config['remotes'][get_current_remote_url()]['current_project'] = args.project_name + save_config(config) + + return True + except: + return False + + +def get_current_project_name(args): + #infraboxcli.env.check_env_url(args) + try: + return get_config()['remotes'][get_current_remote_url()]['current_project'] + except: + return None def get_config(): @@ -53,7 +86,16 @@ def get_config(): return config except: return None - #logger.info('Config file does not exist or invalid.') + + +def save_config(config): + try: + with safe_open_w(home + config_file_path) as config_file: + json.dump(config, config_file) + + return True + except: + return False def get_current_remote_url(): diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index a0b4ab3..4480dbd 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -1,5 +1,6 @@ from infraboxcli.dashboard.cli_client import get, post, delete from infraboxcli.dashboard.user import get_user_headers +from infraboxcli.dashboard.external import get_current_project_name import infraboxcli.env from infraboxcli.log import logger @@ -10,6 +11,14 @@ def check_project_name_set(args): infraboxcli.env.check_env_url(args) + + # Use project name from config only if no extra project name was provided + if not args.project_name: + current_config_project_name = get_current_project_name(args) + if current_config_project_name: + args.project_name = current_config_project_name + args.project_name_printed = True + if args.project_name: args.project_id = get_project_id_by_name(args) diff --git a/infraboxcli/env.py b/infraboxcli/env.py index 6a6992d..8cb1c16 100644 --- a/infraboxcli/env.py +++ b/infraboxcli/env.py @@ -3,7 +3,7 @@ import textwrap from infraboxcli.log import logger -from infraboxcli.dashboard.external import get_current_remote_url +from infraboxcli.dashboard.external import get_current_remote_url, get_current_project_name def check_env_url(args): @@ -11,7 +11,7 @@ def check_env_url(args): current_remote_url = get_current_remote_url() if current_remote_url: args.url = current_remote_url - return + return True error_msg = textwrap.dedent("\ Remote URL is not specified. Either set INFRABOX_URL env var " From f430b110357d4cfa634df6c33aff8c5a45259ff5 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Tue, 8 May 2018 19:52:25 +0200 Subject: [PATCH 18/24] Config API: minor improvements and refactoring. * When we `set-current-project` it's checked whether valid project name is provided; * Refactoring. --- infraboxcli/__init__.py | 4 +- infraboxcli/dashboard/external.py | 89 ++------------------------- infraboxcli/dashboard/local_config.py | 81 ++++++++++++++++++++++++ infraboxcli/dashboard/project.py | 50 +++++---------- infraboxcli/dashboard/remotes.py | 4 +- infraboxcli/env.py | 27 +++++--- 6 files changed, 124 insertions(+), 131 deletions(-) create mode 100644 infraboxcli/dashboard/local_config.py diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index 91b36c0..e944ba4 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -14,7 +14,7 @@ from infraboxcli.dashboard import user from infraboxcli.dashboard import project from infraboxcli.dashboard import remotes -from infraboxcli.dashboard import external +from infraboxcli.dashboard import local_config version = '0.6.4' @@ -208,7 +208,7 @@ def main(): parser_config_current_project = sub_config.add_parser('set-current-project', help='Set new current project') parser_config_current_project.add_argument('project_name', nargs='?', type=str, help='Name of the project') - parser_config_current_project.set_defaults(func=external.set_current_project_name) + parser_config_current_project.set_defaults(func=local_config.set_current_project_name) # Remotes parser_remotes = sub_parser.add_parser('remotes', help='Current remotes') diff --git a/infraboxcli/dashboard/external.py b/infraboxcli/dashboard/external.py index d8ff496..e95ad1b 100644 --- a/infraboxcli/dashboard/external.py +++ b/infraboxcli/dashboard/external.py @@ -1,17 +1,10 @@ -import os -import json -from os.path import expanduser - from infraboxcli.log import logger -from pyinfrabox.utils import get_remote_url, safe_open_w -#from infraboxcli.dashboard import project - -home = expanduser("~") -config_file_path = '/.infrabox/config.json' +from pyinfrabox.utils import get_remote_url +from infraboxcli.dashboard import local_config def save_user_token(url, cookies_dict): - config = get_config() + config = local_config.get_config() if config is None: config = {} @@ -41,73 +34,13 @@ def save_user_token(url, cookies_dict): config['remotes'].setdefault(remote_url, {}) config['remotes'][remote_url]['current_user_token'] = user_token - save_config(config) + local_config.save_config(config) logger.info('Logged in successfully.') -def set_current_project_name(args): - #infraboxcli.env.check_env_url(args) - #all_projects = project.get_projects(args).json() - - #project_exists = False - #for project in all_projects: - # if args.project_name == project['name']: - # project_exists = True - # break - - #if not project_exists: - # logger.error('Project with such a name does not exist.') - # exit(1) - - try: - config = get_config() - - config['remotes'][get_current_remote_url()]['current_project'] = args.project_name - save_config(config) - - return True - except: - return False - - -def get_current_project_name(args): - #infraboxcli.env.check_env_url(args) - try: - return get_config()['remotes'][get_current_remote_url()]['current_project'] - except: - return None - - -def get_config(): - try: - with open(home + config_file_path, 'r') as config_file: - config = json.load(config_file) - - return config - except: - return None - - -def save_config(config): - try: - with safe_open_w(home + config_file_path) as config_file: - json.dump(config, config_file) - - return True - except: - return False - - -def get_current_remote_url(): - try: - return get_config()['current_remote'] - except: - return None - - def get_current_user_token(): try: - config = get_config() + config = local_config.get_config() current_remote = config['current_remote'] if not current_remote: @@ -123,15 +56,3 @@ def get_current_user_token(): exit(1) -def get_all_remotes(): - try: - config = get_config() - - remotes = config['remotes'].keys() - if not remotes: - raise - - return remotes - except: - logger.error('No available remotes. Please, log in.') - exit(1) diff --git a/infraboxcli/dashboard/local_config.py b/infraboxcli/dashboard/local_config.py new file mode 100644 index 0000000..7f8fb79 --- /dev/null +++ b/infraboxcli/dashboard/local_config.py @@ -0,0 +1,81 @@ +import json + +from os.path import expanduser +from infraboxcli.log import logger +from pyinfrabox.utils import safe_open_w + +config_file_path = '/.infrabox/config.json' +home = expanduser("~") + + +def set_current_project_name(args): + from infraboxcli.dashboard import project + all_projects = project.get_projects(args).json() + + project_exists = False + for project in all_projects: + if args.project_name == project['name']: + project_exists = True + break + + if not project_exists: + logger.error('Project with such a name does not exist.') + exit(1) + + try: + config = get_config() + + config['remotes'][get_current_remote_url()]['current_project'] = args.project_name + save_config(config) + + return True + except: + return False + + +def get_current_project_name(args): + try: + return get_config()['remotes'][get_current_remote_url()]['current_project'] + except: + return None + + +def get_current_remote_url(): + try: + return get_config()['current_remote'] + except: + return None + + +def get_all_remotes(): + try: + config = get_config() + + remotes = config['remotes'].keys() + if not remotes: + raise + + return remotes + except: + logger.error('No available remotes. Please, log in.') + exit(1) + + +def get_config(): + try: + with open(home + config_file_path, 'r') as config_file: + config = json.load(config_file) + + return config + except: + return None + + +def save_config(config): + try: + with safe_open_w(home + config_file_path) as config_file: + json.dump(config, config_file) + + return True + except: + return False diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index 4480dbd..bf730db 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -1,6 +1,5 @@ from infraboxcli.dashboard.cli_client import get, post, delete from infraboxcli.dashboard.user import get_user_headers -from infraboxcli.dashboard.external import get_current_project_name import infraboxcli.env from infraboxcli.log import logger @@ -9,27 +8,21 @@ allowed_project_types = ['upload'] #TODO: add ['github', 'gitlab', 'gerrit'] -def check_project_name_set(args): - infraboxcli.env.check_env_url(args) - - # Use project name from config only if no extra project name was provided - if not args.project_name: - current_config_project_name = get_current_project_name(args) - if current_config_project_name: - args.project_name = current_config_project_name - args.project_name_printed = True +def check_project_is_set(args): + infraboxcli.env.check_env_cli_token(args) if args.project_name: args.project_id = get_project_id_by_name(args) if args.project_id is not None: - if 'project_name_printed' not in args: + if 'project_name_printed' not in args \ + and 'using_default_project' not in args: logger.info('Project: {project_name}'.format(project_name=args.project_name)) args.project_name_printed = True return True - return False + exit(1) def get_projects(args): @@ -139,8 +132,7 @@ def delete_project_by_id(args): def get_collaborators(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators' response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) @@ -161,8 +153,7 @@ def list_collaborators(args): def add_collaborator(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) url = args.url + api_projects_endpoint_url + args.project_id + '/collaborators' data = { 'username': args.username } @@ -173,8 +164,7 @@ def add_collaborator(args): def remove_collaborator(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) all_project_collaborators = get_collaborators(args).json() collaborator_id = None @@ -195,8 +185,7 @@ def remove_collaborator(args): def get_secrets(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) @@ -229,8 +218,7 @@ def get_secret_id_by_name(args): def add_secret(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) url = args.url + api_projects_endpoint_url + args.project_id + '/secrets' data = {'name': args.name, 'value': args.value} @@ -250,8 +238,7 @@ def delete_secret(args): def delete_secret_by_name(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) secret_id = get_secret_id_by_name(args) @@ -263,8 +250,7 @@ def delete_secret_by_name(args): def delete_secret_by_id(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) url = args.url + api_projects_endpoint_url + args.project_id + '/secrets/' + args.id response = delete(url, get_user_headers(), verify=args.ca_bundle, timeout=60) @@ -274,8 +260,7 @@ def delete_secret_by_id(args): def get_project_tokens(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) url = args.url + api_projects_endpoint_url + args.project_id + '/tokens' response = get(url, get_user_headers(), verify=args.ca_bundle, timeout=60) @@ -310,8 +295,7 @@ def get_project_token_id_by_description(args): def add_project_token(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) url = args.url + api_projects_endpoint_url + args.project_id + '/tokens' @@ -349,8 +333,7 @@ def delete_project_token(args): def delete_project_token_by_description(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) token_id = get_project_token_id_by_description(args) @@ -362,8 +345,7 @@ def delete_project_token_by_description(args): def delete_project_token_by_id(args): - if not check_project_name_set(args): - infraboxcli.env.check_env_cli_token(args) + check_project_is_set(args) url = args.url + api_projects_endpoint_url + args.project_id + '/tokens/' + args.id response = delete(url, get_user_headers(), verify=args.ca_bundle, timeout=60) diff --git a/infraboxcli/dashboard/remotes.py b/infraboxcli/dashboard/remotes.py index 14749b7..a8013b4 100644 --- a/infraboxcli/dashboard/remotes.py +++ b/infraboxcli/dashboard/remotes.py @@ -1,10 +1,10 @@ -from infraboxcli.dashboard import external +from infraboxcli.dashboard import local_config from infraboxcli.log import logger def list_remotes(args): if args.verbose: - remotes = external.get_all_remotes() + remotes = local_config.get_all_remotes() msg = ': ' msg += '\n: '.join(remotes) diff --git a/infraboxcli/env.py b/infraboxcli/env.py index 8cb1c16..48b1c08 100644 --- a/infraboxcli/env.py +++ b/infraboxcli/env.py @@ -3,7 +3,7 @@ import textwrap from infraboxcli.log import logger -from infraboxcli.dashboard.external import get_current_remote_url, get_current_project_name +from infraboxcli.dashboard.local_config import get_current_remote_url, get_current_project_name def check_env_url(args): @@ -22,14 +22,8 @@ def check_env_url(args): def check_env_cli_token(args): check_env_url(args) - - # If we provided project name and enter this function for some reasons - # just return from it - if 'project_name' in args \ - and args.project_name \ - and 'project_command' in args \ - and args.project_command: - exit(1) + if __check_project_name_set(args): + return True token = os.environ.get('INFRABOX_CLI_TOKEN', None) if not token: @@ -40,3 +34,18 @@ def check_env_cli_token(args): t = jwt.decode(token, verify=False) args.project_id = t['project']['id'] + + return True + + +def __check_project_name_set(args): + # Use project name from config only if no extra project name was provided + if not args.project_name: + current_config_project_name = get_current_project_name(args) + if current_config_project_name: + args.project_name = current_config_project_name + args.using_default_project = True + + return args.project_name + + From 3dead8f437a6e11c3bf8b44b36d6300369d6804f Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Tue, 8 May 2018 20:53:30 +0200 Subject: [PATCH 19/24] Implemented `infrabox logout` feature. --- infraboxcli/__init__.py | 6 +++++- infraboxcli/dashboard/external.py | 19 ++++++++++++++++++- infraboxcli/dashboard/user.py | 12 +++++++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index e944ba4..ab72444 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -195,13 +195,17 @@ def main(): help='Description of the project token you want to delete') parser_remove_project_token.set_defaults(func=project.delete_project_token) - # User + # Login parser_login = sub_parser.add_parser('login', help='Login to infrabox') parser_login.add_argument('remote_url', nargs='?', type=str, help='Name of remote') parser_login.add_argument('--email', required=False, default=None, type=str, help='Email of the user') parser_login.add_argument('--password', required=False, default=None, type=str, help='Password of the user') parser_login.set_defaults(func=user.login) + # Logout + parser_logout = sub_parser.add_parser('logout', help='Logout from current remote') + parser_logout.set_defaults(func=user.logout) + # Config parser_config = sub_parser.add_parser('config', help='Configure your infrabox') sub_config = parser_config.add_subparsers(dest='config') diff --git a/infraboxcli/dashboard/external.py b/infraboxcli/dashboard/external.py index e95ad1b..844fb93 100644 --- a/infraboxcli/dashboard/external.py +++ b/infraboxcli/dashboard/external.py @@ -47,7 +47,7 @@ def get_current_user_token(): raise current_user_token = config['remotes'][current_remote]['current_user_token'] - if current_user_token is None: + if current_user_token is None or not current_user_token: raise return current_user_token @@ -56,3 +56,20 @@ def get_current_user_token(): exit(1) +def delete_current_user_token(args=None): + try: + config = local_config.get_config() + + current_remote = config['current_remote'] + if not current_remote: + raise + + if not config['remotes'][current_remote]['current_user_token']: + return False + + config['remotes'][current_remote]['current_user_token'] = "" + local_config.save_config(config) + + return True + except: + return False diff --git a/infraboxcli/dashboard/user.py b/infraboxcli/dashboard/user.py index 33c949e..5b163a3 100644 --- a/infraboxcli/dashboard/user.py +++ b/infraboxcli/dashboard/user.py @@ -1,8 +1,9 @@ import getpass import json +from infraboxcli.log import logger from infraboxcli.dashboard.cli_client import post, get -from infraboxcli.dashboard.external import get_current_user_token, save_user_token +from infraboxcli.dashboard.external import get_current_user_token, save_user_token, delete_current_user_token import infraboxcli.env @@ -37,3 +38,12 @@ def login(args): response = post(url, data, cookies_handler=save_user_token) return response + + +def logout(args): + token_deleted = delete_current_user_token(args) + + if token_deleted: + logger.info('Successfully logged out.') + else: + logger.info('Already logged out.') From aa3bc672c26306398028a013b8fd99f538965edb Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 9 May 2018 17:33:52 +0200 Subject: [PATCH 20/24] Fixed python3 import modules. --- pyinfrabox/utils.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pyinfrabox/utils.py b/pyinfrabox/utils.py index d51be5b..e581cb7 100644 --- a/pyinfrabox/utils.py +++ b/pyinfrabox/utils.py @@ -6,10 +6,12 @@ from pyinfrabox import ValidationError -#python3 -#from urllib.parse.urlparse import urlparse -#python2 -from urlparse import urlparse +try: + #python2 + from urlparse import urlparse +except: + #python3 + from urllib.parse import urlparse def check_text(t, path, allowEmpty=False): From 2dac9185f494dd95620bee330f9828300cd7eeaa Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 9 May 2018 17:59:45 +0200 Subject: [PATCH 21/24] Login API: added url validation. --- infraboxcli/dashboard/user.py | 5 +++++ pyinfrabox/utils.py | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/infraboxcli/dashboard/user.py b/infraboxcli/dashboard/user.py index 5b163a3..4f0a256 100644 --- a/infraboxcli/dashboard/user.py +++ b/infraboxcli/dashboard/user.py @@ -4,6 +4,7 @@ from infraboxcli.log import logger from infraboxcli.dashboard.cli_client import post, get from infraboxcli.dashboard.external import get_current_user_token, save_user_token, delete_current_user_token +from pyinfrabox.utils import validate_url import infraboxcli.env @@ -19,6 +20,10 @@ def login(args): if args.remote_url: args.url = args.remote_url + if args.remote_url and not validate_url(args.remote_url): + logger.error('Invalid url.') + exit(1) + infraboxcli.env.check_env_url(args) email = args.email diff --git a/pyinfrabox/utils.py b/pyinfrabox/utils.py index e581cb7..77ac523 100644 --- a/pyinfrabox/utils.py +++ b/pyinfrabox/utils.py @@ -65,6 +65,13 @@ def get_remote_url(url): parsed_url = urlparse(url) return parsed_url.scheme + '://' + parsed_url.netloc +def validate_url(url): + try: + result = urlparse(url) + return result.scheme and result.netloc + except: + return False + def mkdir_p(path): """ An implementation of `mkdir -p` UNIX command. From 214298d3ea9ebf41d4f00082918c494e72bdc989 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 9 May 2018 18:10:14 +0200 Subject: [PATCH 22/24] Improved HTTP errors handling. --- infraboxcli/dashboard/cli_client.py | 33 ++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/infraboxcli/dashboard/cli_client.py b/infraboxcli/dashboard/cli_client.py index c3e45fc..76e3e3a 100644 --- a/infraboxcli/dashboard/cli_client.py +++ b/infraboxcli/dashboard/cli_client.py @@ -1,24 +1,51 @@ import requests +from infraboxcli.log import logger + session = requests.Session() +connection_error_message = 'Can\'t connect to the remote. Please, check your connection or remote url.' def get(url, headers=None, cookies_handler=None, verify=None, timeout=60): - response = session.get(url, headers=headers, verify=verify, timeout=timeout) + try: + response = session.get(url, headers=headers, verify=verify, timeout=timeout) + except requests.ConnectionError: + logger.error(connection_error_message) + exit(1) + except Exception as e: + logger.error(e.message) + exit(1) + if cookies_handler: cookies_handler(url, session.cookies.get_dict()) return response def post(url, data, headers=None, cookies_handler=None, verify=None, timeout=60): - response = session.post(url, json=data, headers=headers, verify=verify, timeout=timeout) + try: + response = session.post(url, json=data, headers=headers, verify=verify, timeout=timeout) + except requests.ConnectionError: + logger.error(connection_error_message) + exit(1) + except Exception as e: + logger.error(e.message) + exit(1) + if cookies_handler: cookies_handler(url, session.cookies.get_dict()) return response def delete(url, headers=None, cookies_handler=None, verify=None, timeout=60): - response = session.delete(url, headers=headers, verify=verify, timeout=timeout) + try: + response = session.delete(url, headers=headers, verify=verify, timeout=timeout) + except requests.ConnectionError: + logger.error(connection_error_message) + exit(1) + except Exception as e: + logger.error(e.message) + exit(1) + if cookies_handler: cookies_handler(url, session.cookies.get_dict()) return response From 7c679c4cef43a130a198f1f486fc8e19487dd48e Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 9 May 2018 18:21:28 +0200 Subject: [PATCH 23/24] Minor fixes. --- infraboxcli/dashboard/project.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index bf730db..62839bf 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -62,9 +62,10 @@ def create_project(args): if args.public: is_private_project = False + args.type = args.type.lower() if args.type not in allowed_project_types: logger.error('Provided project type is not supported.' - + '\nAllowed project types are: [{allowed_types}]' + + '\nAllowed project types are: [ {allowed_types} ]' .format(allowed_types=', '.join(allowed_project_types))) return From 53ea1d504585ba3a0f966bfd9a631f9409616be6 Mon Sep 17 00:00:00 2001 From: Kirill Abramov Date: Wed, 9 May 2018 18:53:20 +0200 Subject: [PATCH 24/24] Added `project status` feature. * You can call this module by `infrabox project status`; * Improved projects module. --- infraboxcli/__init__.py | 7 +++++ infraboxcli/dashboard/project.py | 49 ++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/infraboxcli/__init__.py b/infraboxcli/__init__.py index ab72444..caf51b8 100644 --- a/infraboxcli/__init__.py +++ b/infraboxcli/__init__.py @@ -112,10 +112,17 @@ def main(): parser_project.set_defaults(project_command=True) sub_project = parser_project.add_subparsers(dest='project') + # Project list parser_projects_list = sub_project.add_parser('list', help='Get a list of all your projects') parser_projects_list.add_argument('--verbose', required=False, default=True, type=str2bool) parser_projects_list.set_defaults(func=project.list_projects) + # Project status + parser_projects_list = sub_project.add_parser('status', help='Get some info about your current project') + parser_projects_list.add_argument('--verbose', required=False, default=True, type=str2bool) + parser_projects_list.set_defaults(func=project.print_status) + + # Create project parser_project_create = sub_project.add_parser('create', help='Create a new project') parser_project_create.add_argument('--name', required=True, type=str, help='Name of the project you want to create') diff --git a/infraboxcli/dashboard/project.py b/infraboxcli/dashboard/project.py index 62839bf..ed02cec 100644 --- a/infraboxcli/dashboard/project.py +++ b/infraboxcli/dashboard/project.py @@ -46,6 +46,30 @@ def list_projects(args): logger.log(msg, print_header=False) +def print_status(args): + if args.verbose: + infraboxcli.env.check_env_cli_token(args) + + if args.project_name: + project = get_project_by_name(args) + elif args.project_id: + project = get_project_by_id(args) + + if project is None: + logger.error('Current project is not set.') + exit(1) + + num_collaborators = len(get_collaborators(args).json()) + num_tokens = len(get_project_tokens(args).json()) + num_secrets = len(get_secrets(args).json()) + + logger.info('Project status:') + msg = 'Name: {}\nId: {}\nType: {}\nPublic: {}\n---\n' \ + + 'Total collaborators: {}\nTotal tokens: {}\nTotal secrets: {}\n---\n' + logger.log(msg.format(project['name'], project['id'], project['type'], project['public'], + num_collaborators, num_tokens, num_secrets), print_header=False) + + def create_project(args): infraboxcli.env.check_env_url(args) @@ -97,6 +121,31 @@ def get_project_id_by_name(args): return None +def get_project_name_by_id(args): + project = get_project_by_id(args) + if project: + return project['name'] + + +def get_project_by_id(args): + all_projects = get_projects(args).json() + + for project in all_projects: + if args.project_id == project['id']: + return project + + logger.info('Project with such an id does not exist.') + return None + + +def get_project_by_name(args): + project_id = get_project_id_by_name(args) + + if project_id: + args.project_id = project_id + return get_project_by_id(args) + + def delete_project(args): if args.id: delete_project_by_id(args)