diff --git a/ceo/cli/database.py b/ceo/cli/database.py deleted file mode 100644 index b36e3a6..0000000 --- a/ceo/cli/database.py +++ /dev/null @@ -1,161 +0,0 @@ -import click -import os - -from zope import component -from ceo_common.interfaces import IConfig - -from ..utils import http_post, http_get -from .utils import handle_sync_response, Abort - - -def check_file_path(file): - if os.path.isfile(file): - click.echo(f"{file} will be overwritten") - click.confirm('Do you want to continue?', abort=True) - elif os.path.isdir(file): - click.echo(f"Error: there exists a directory at {file}") - raise Abort() - - -@click.group(short_help='Perform operations on MySQL') -def mysql(): - pass - - -def mysql_create_info_file(file, username, password): - cfg_srv = component.getUtility(IConfig) - mysql_host = cfg_srv.get('mysql_host') - info = f"""MySQL Database Information for {username} - - Your new MySQL database was created. To connect, use the following options: - - Database: {username} - Username: {username} - Password: {password} - Host: {mysql_host} - - On {mysql_host} to connect using the MySQL command-line client use - - mysql {username} -u {username} -p - - From other CSC machines you can connect using - - mysql {username} -h {mysql_host} -u {username} -p - - """ - with click.open_file(file, "w") as f: - f.write(info) - os.chown(file, username, username) - os.chmod(file, 0o640) - - -@mysql.command(short_help='Create a MySQL database for a user') -@click.argument('username') -def create(username): - resp = http_get(f'/api/members/{username}') - result = handle_sync_response(resp) - info_file_path = os.path.join(result['home_directory'], "ceo-mysql-info") - - check_file_path(info_file_path) - - resp = http_post(f'/api/db/mysql/{username}') - result = handle_sync_response(resp) - password = result['password'] - - mysql_create_info_file(info_file_path, username, password) - - click.echo(f""" - MySQL database {username} with password {password} has been created - This password and more details have been written to {info_file_path}""") - - -@mysql.command(short_help='Reset the password of a MySQL user') -@click.argument('username') -def pwreset(username): - resp = http_get(f'/api/members/{username}') - result = handle_sync_response(resp) - info_file_path = os.path.join(result['home_directory'], "ceo-mysql-info") - - check_file_path(info_file_path) - - resp = http_post(f'/api/db/mysql/{username}/pwreset') - result = handle_sync_response(resp) - password = result['password'] - - mysql_create_info_file(info_file_path, username, password) - - click.echo(f""" - MySQL database {username} now has the password {password} - This password and more details have been written to {info_file_path}""") - - -@click.group(short_help='Perform operations on PostgreSQL') -def postgresql(): - pass - - -def psql_create_info_file(file, username, password): - cfg_srv = component.getUtility(IConfig) - psql_host = cfg_srv.get('postgresql_host') - info = f"""PostgreSQL Database Information for {username} - - Your new PostgreSQL database was created. To connect, use the following options: - - Database: {username} - Username: {username} - Password: {password} - Host: {psql_host} - - On {psql_host} to connect using the PostgreSQL command-line client use - - psql -d {username} -U {username} -W - - From other CSC machines you can connect using - - psql -d {username} -h {psql_host} -U {username} -W - - """ - with click.open_file(file, "w") as f: - f.write(info) - os.chown(file, username, username) - os.chmod(file, 0o640) - - -@postgresql.command(short_help='Create a PostgreSQL database for a user') -@click.argument('username') -def create(username): - resp = http_get(f'/api/members/{username}') - result = handle_sync_response(resp) - info_file_path = os.path.join(result['home_directory'], "ceo-psql-info") - - check_file_path(info_file_path) - - resp = http_post(f'/api/db/postgresql/{username}') - result = handle_sync_response(resp) - password = result['password'] - - psql_create_info_file(info_file_path, username, password) - - click.echo(f""" - PostgreSQL database {username} with password {password} has been created - This password and more details have been written to {info_file_path}""") - - -@postgresql.command(short_help='Reset the password of a PostgreSQL user') -@click.argument('username') -def pwreset(username): - resp = http_get(f'/api/members/{username}') - result = handle_sync_response(resp) - info_file_path = os.path.join(result['home_directory'], "ceo-psql-info") - - check_file_path(info_file_path) - - resp = http_post(f'/api/db/postgresql/{username}/pwreset') - result = handle_sync_response(resp) - password = result['password'] - - psql_create_info_file(info_file_path, username, password) - - click.echo(f""" - PostgreSQL database {username} now has the password {password} - This password and more details have been written to {info_file_path}""") diff --git a/ceo/cli/entrypoint.py b/ceo/cli/entrypoint.py index 8993952..bf11edd 100644 --- a/ceo/cli/entrypoint.py +++ b/ceo/cli/entrypoint.py @@ -9,7 +9,8 @@ from ..krb_check import krb_check from .members import members from .groups import groups from .updateprograms import updateprograms -from .database import mysql, postgresql +from .mysql import mysql +from .postgresql import postgresql from ceo_common.interfaces import IConfig, IHTTPClient from ceo_common.model import Config, HTTPClient diff --git a/ceo/cli/mysql.py b/ceo/cli/mysql.py new file mode 100644 index 0000000..30786c3 --- /dev/null +++ b/ceo/cli/mysql.py @@ -0,0 +1,80 @@ +import click +import os + +from zope import component +from ceo_common.interfaces import IConfig + +from ..utils import http_post, http_get +from .utils import handle_sync_response, check_file_path + + +def mysql_create_info_file(file, username, password): + cfg_srv = component.getUtility(IConfig) + mysql_host = cfg_srv.get('mysql_host') + info = f"""MySQL Database Information for {username} + + Your new MySQL database was created. To connect, use the following options: + + Database: {username} + Username: {username} + Password: {password} + Host: {mysql_host} + + On {mysql_host} to connect using the MySQL command-line client use + + mysql {username} -u {username} -p + + From other CSC machines you can connect using + + mysql {username} -h {mysql_host} -u {username} -p + + """ + with click.open_file(file, "w") as f: + f.write(info) + os.chown(file, username, username) + os.chmod(file, 0o640) + + +@click.group(short_help='Perform operations on MySQL') +def mysql(): + pass + + +@mysql.command(short_help='Create a MySQL database for a user') +@click.argument('username') +def create(username): + resp = http_get(f'/api/members/{username}') + result = handle_sync_response(resp) + info_file_path = os.path.join(result['home_directory'], "ceo-mysql-info") + + check_file_path(info_file_path) + + resp = http_post(f'/api/db/mysql/{username}') + result = handle_sync_response(resp) + password = result['password'] + + mysql_create_info_file(info_file_path, username, password) + + click.echo(f""" + MySQL database {username} with password {password} has been created + This password and more details have been written to {info_file_path}""") + + +@mysql.command(short_help='Reset the password of a MySQL user') +@click.argument('username') +def pwreset(username): + resp = http_get(f'/api/members/{username}') + result = handle_sync_response(resp) + info_file_path = os.path.join(result['home_directory'], "ceo-mysql-info") + + check_file_path(info_file_path) + + resp = http_post(f'/api/db/mysql/{username}/pwreset') + result = handle_sync_response(resp) + password = result['password'] + + mysql_create_info_file(info_file_path, username, password) + + click.echo(f""" + MySQL database {username} now has the password {password} + This password and more details have been written to {info_file_path}""") diff --git a/ceo/cli/postgresql.py b/ceo/cli/postgresql.py new file mode 100644 index 0000000..7127ac8 --- /dev/null +++ b/ceo/cli/postgresql.py @@ -0,0 +1,80 @@ +import click +import os + +from zope import component +from ceo_common.interfaces import IConfig + +from ..utils import http_post, http_get +from .utils import handle_sync_response, check_file_path + + +def psql_create_info_file(file, username, password): + cfg_srv = component.getUtility(IConfig) + psql_host = cfg_srv.get('postgresql_host') + info = f"""PostgreSQL Database Information for {username} + + Your new PostgreSQL database was created. To connect, use the following options: + + Database: {username} + Username: {username} + Password: {password} + Host: {psql_host} + + On {psql_host} to connect using the PostgreSQL command-line client use + + psql -d {username} -U {username} -W + + From other CSC machines you can connect using + + psql -d {username} -h {psql_host} -U {username} -W + + """ + with click.open_file(file, "w") as f: + f.write(info) + os.chown(file, username, username) + os.chmod(file, 0o640) + + +@click.group(short_help='Perform operations on PostgreSQL') +def postgresql(): + pass + + +@postgresql.command(short_help='Create a PostgreSQL database for a user') +@click.argument('username') +def create(username): + resp = http_get(f'/api/members/{username}') + result = handle_sync_response(resp) + info_file_path = os.path.join(result['home_directory'], "ceo-psql-info") + + check_file_path(info_file_path) + + resp = http_post(f'/api/db/postgresql/{username}') + result = handle_sync_response(resp) + password = result['password'] + + psql_create_info_file(info_file_path, username, password) + + click.echo(f""" + PostgreSQL database {username} with password {password} has been created + This password and more details have been written to {info_file_path}""") + + +@postgresql.command(short_help='Reset the password of a PostgreSQL user') +@click.argument('username') +def pwreset(username): + resp = http_get(f'/api/members/{username}') + result = handle_sync_response(resp) + info_file_path = os.path.join(result['home_directory'], "ceo-psql-info") + + check_file_path(info_file_path) + + resp = http_post(f'/api/db/postgresql/{username}/pwreset') + result = handle_sync_response(resp) + password = result['password'] + + psql_create_info_file(info_file_path, username, password) + + click.echo(f""" + PostgreSQL database {username} now has the password {password} + This password and more details have been written to {info_file_path}""") diff --git a/ceo/cli/utils.py b/ceo/cli/utils.py index 98aa23f..5443c35 100644 --- a/ceo/cli/utils.py +++ b/ceo/cli/utils.py @@ -1,6 +1,7 @@ import json import socket import sys +import os from typing import List, Tuple, Dict import click @@ -114,6 +115,15 @@ def handle_sync_response(resp: requests.Response): return resp.json() +def check_file_path(file): + if os.path.isfile(file): + click.echo(f"{file} will be overwritten") + click.confirm('Do you want to continue?', abort=True) + elif os.path.isdir(file): + click.echo(f"Error: there exists a directory at {file}") + raise Abort() + + def check_if_in_development() -> bool: """Aborts if we are not currently in the dev environment.""" if not socket.getfqdn().endswith('.csclub.internal'):