diff --git a/src/config.py b/src/config.py index 350e860..b1d394f 100644 --- a/src/config.py +++ b/src/config.py @@ -1,11 +1,11 @@ -from src.cranecloud.utils.config import create_config, read_config +from src.cranecloud.utils.config import create_config, read_config , create_initial_config # Example usage of the config values config_file = read_config() try: API_BASE_URL = config_file['GlobalSettings']['base_url'] except KeyError: - create_config() + create_initial_config() config_file = read_config() API_BASE_URL = config_file['GlobalSettings'].get('base_url') try: diff --git a/src/cranecloud/__init__.py b/src/cranecloud/__init__.py index 3a2f4c3..84ce574 100644 --- a/src/cranecloud/__init__.py +++ b/src/cranecloud/__init__.py @@ -1,26 +1,23 @@ -from src.cranecloud.commands.apps import apps_group -from src.cranecloud.commands.clusters import clusters_group import click from os.path import join, dirname from dotenv import load_dotenv -from src.cranecloud.utils.config import create_config +from src.cranecloud.utils.config import create_config , write_config , get_base_dir from src.cranecloud.commands.user_management import user_group from src.cranecloud.commands.projects import projects_group from src.cranecloud.commands.config_management import config_group - - -dotenv_path = join(dirname(__file__), '.env') -load_dotenv(dotenv_path) +from src.cranecloud.commands.apps import apps_group +from src.cranecloud.commands.clusters import clusters_group +from pathlib import Path +from dotenv import set_key @click.group() def cli(): pass - cli = click.CommandCollection( sources=[user_group, projects_group, apps_group, clusters_group, config_group]) -def create_initial_config(): - create_config() + + diff --git a/src/cranecloud/commands/apps.py b/src/cranecloud/commands/apps.py index bded9ff..b2daae0 100644 --- a/src/cranecloud/commands/apps.py +++ b/src/cranecloud/commands/apps.py @@ -20,6 +20,14 @@ def apps(): pass +@apps.group(name='revisions') +def revisions(): + ''' + Revisions management commands. + ''' + pass + + @apps.command('list', help='List apps in project') @click.option('-p', '--project_id', type=click.UUID, help='Project ID') def get_apps(project_id): @@ -62,9 +70,12 @@ def get_app_details(app_id): click.echo('Getting app details...\n') try: token = get_token() + + # Getting details response = requests.get( f'{API_BASE_URL}/apps/{app_id}', headers={'Authorization': f'Bearer {token}'}) response.raise_for_status() + if response.status_code == 200: app = response.json()['data']['apps'] table_data = [ @@ -224,3 +235,84 @@ def update_app(app_id, name, image, command, replicas, port, env): click.echo(f'Failed to connect to the server: {e}') click.echo( 'Please check your internet connection or try again later.') + + +@revisions.command('list', help='List app revisions') +@click.argument('app_id', type=click.UUID) +@click.option('--page', type=int, help='Page' , required=False) +def get_revisions(app_id , page): + '''Get application revisions .''' + click.echo('Getting app revisions ... ') + try: + + token = get_token() + + + # Getting revisions + response = requests.get( + f'{API_BASE_URL}/apps/{app_id}/revisions', headers={'Authorization': f'Bearer {token}'} , + params={'page' : page} + ) + + response.raise_for_status() + + if response.status_code == 200: + revisions = response.json()['data']['revisions'] + table_data = [] + + for revision in revisions: + table_data.append( + [revision.get('revision') , revision.get('revision_id') , revision.get('replicas') , revision.get('created_at') , revision.get('image') , revision.get('port') , revision.get('current' , '') , revision.get('command')]) + headers = ['Revision' , 'Revision id' , 'Replicas' , 'Date created' , 'image' , 'Port' , 'Current' , 'Command'] + click.echo(tabulate(table_data, headers, tablefmt='simple')) + + click.echo(f"Page {response.json()['data']['pagination']['page']} of {response.json()['data']['pagination']['pages']} ....") + else: + click.echo('Failed to get app revisions list.') + except requests.RequestException as e: + if e.response or e.response.reason: + click.echo(f'Error: {e.response.reason}') + else: + click.echo(f'Failed to connect to the server: {e}') + click.echo( + 'Please check your internet connection or try again later.') + + + +@revisions.command('update', help='Update an application to a specific revision id') +@click.option('-r', '--revision', type=str, help='Revision id of the application' , required = True) +@click.argument('app_id', type=click.UUID) +def update_app(app_id , revision): + '''Make an app update.''' + click.echo(f'Updating application to revision {revision} ...') + try: + token = get_token() + + + response = requests.post( + f'{API_BASE_URL}/apps/{app_id}/revise/{revision}', + headers={'Authorization': f'Bearer {token}'} + ) + response.raise_for_status() + + if response.status_code == 200 : + click.echo('App revised successfully.') + + else : + click.echo('An error occured. Could not revise the application.') + + except requests.RequestException as e: + if e.response not in [None, '']: + click.echo( + click.style(f'Failed to revise the app\n', fg='red') + + e.response.json().get('message')) + else: + click.echo(f'Failed to connect to the server: {e}') + click.echo( + 'Please check your internet connection or try again later.') + + + + + + diff --git a/src/cranecloud/commands/config_management.py b/src/cranecloud/commands/config_management.py index 33a8305..9a15057 100644 --- a/src/cranecloud/commands/config_management.py +++ b/src/cranecloud/commands/config_management.py @@ -2,8 +2,9 @@ from tabulate import SEPARATING_LINE, tabulate from src.cranecloud.commands.projects import set_use_project from src.config import CURRENT_CLUSTER, CURRENT_PROJECT, CURRENT_USER -from src.cranecloud.utils.config import read_config +from src.cranecloud.utils.config import read_config , create_config +import os @click.group() def config_group(): @@ -43,3 +44,12 @@ def get_config(): table_data.append([key, value]) headers = ['Key', 'Value'] click.echo(tabulate(table_data, headers, tablefmt='simple')) + + +@config.command('use-config', help='Create CraneCloud configuration.') +@click.argument('config_path', type=click.STRING) +def change_config(config_path): + + os.makedirs(os.path.join(config_path, '.crane') , exist_ok=True) + create_config(os.path.join(config_path, '.crane')) + \ No newline at end of file diff --git a/src/cranecloud/utils/config.py b/src/cranecloud/utils/config.py index 55c58a5..f8a3d60 100644 --- a/src/cranecloud/utils/config.py +++ b/src/cranecloud/utils/config.py @@ -1,32 +1,61 @@ import os import configparser +from dotenv import set_key +from pathlib import Path +from os.path import join, dirname +from dotenv import load_dotenv + + CONFIG_FILE = 'config' +dotenv_path = join(dirname(__file__), '.env') +load_dotenv(dotenv_path) + + def get_base_dir(): - home_dir = os.path.expanduser("~") - crane_dir = os.path.join(home_dir, '.crane') + crane_dir = os.getenv('CRANE_CONFIG_DIR') + if not crane_dir: + config_dir = os.path.expanduser("~") + crane_dir = os.path.join(config_dir, '.crane') return crane_dir -def create_config(): +def create_config(dir= get_base_dir()): + env_file_path = Path(join(dirname(__file__), '.env')) + env_file_path.touch(mode=0o600, exist_ok=True) + + default_base_url = os.getenv('API_BASE_URL', "https://api.cranecloud.io") + set_key(dotenv_path=env_file_path, key_to_set="CRANE_CONFIG_DIR", value_to_set=dir , export=True) + write_config('base_url', default_base_url , crane_dir = dir) + write_config("dotenv_path" , dotenv_path , crane_dir=env_file_path) + + +def create_initial_config(): + env_file_path = Path(join(dirname(__file__), '.env')) + env_file_path.touch(mode=0o600, exist_ok=True) + + config_dir = os.path.expanduser("~") + crane_dir = os.path.join(config_dir, '.crane') + + set_key(dotenv_path=env_file_path, key_to_set="CRANE_CONFIG_DIR", value_to_set=crane_dir , export=True) + write_config("dotenv_path" , dotenv_path , crane_dir=crane_dir) + default_base_url = os.getenv('API_BASE_URL', "https://api.cranecloud.io") - write_config('base_url', default_base_url) + write_config('base_url', default_base_url , crane_dir=crane_dir) -def read_config(): +def read_config(crane_config = get_base_dir()): config = configparser.ConfigParser() - crane_dir = get_base_dir() - config_file = os.path.join(crane_dir, CONFIG_FILE) + config_file = os.path.join(crane_config, CONFIG_FILE) config.read(config_file) return config -def write_config(key, value, should_update=True): +def write_config(key, value, should_update=True , crane_dir = get_base_dir()): config = configparser.ConfigParser() - crane_dir = get_base_dir() config_file = os.path.join(crane_dir, CONFIG_FILE) os.makedirs(crane_dir, exist_ok=True)