Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade karton cli #100

Merged
merged 17 commits into from
Jan 12, 2021
Merged
2 changes: 1 addition & 1 deletion karton/core/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(self, config):
decode_responses=True,
)
self.minio = Minio(
config["minio"]["address"],
endpoint=config["minio"]["address"],
access_key=config["minio"]["access_key"],
secret_key=config["minio"]["secret_key"],
secure=bool(int(config["minio"].get("secure", True))),
Expand Down
199 changes: 181 additions & 18 deletions karton/core/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,125 @@
import argparse
import logging
import os.path
from configparser import ConfigParser
from typing import Any, Dict, List

from minio import Minio
from redis import StrictRedis

from .__version__ import __version__
from .backend import KartonBackend
from .config import Config
from .karton import Consumer

log = logging.getLogger(__name__)


def get_user_option(prompt: str, default: str) -> str:
user_input = input(prompt + f"\n[{default}] ")
nazywam marked this conversation as resolved.
Show resolved Hide resolved
print("") # just for style
return user_input.strip() or default


def configuration_wizard(config_filename: str) -> None:
config = ConfigParser()

log.info("Configuring MinIO")
while True:
minio_access_key = get_user_option(
"Enter the MinIO access key", default="minioadmin"
)
minio_secret_key = get_user_option(
"Enter the MinIO secret key", default="minioadmin"
)
minio_address = get_user_option(
"Enter the MinIO address", default="localhost:9000"
)
minio_bucket = get_user_option(
"Enter the MinIO bucket to use", default="karton"
)
minio_secure = get_user_option('Use SSL ("0", "1")?', default="0")

log.info("Testing MinIO connection...")
minio = Minio(
endpoint=minio_address,
access_key=minio_access_key,
secret_key=minio_secret_key,
secure=bool(int(minio_secure)),
)
bucket_exists = False
try:
bucket_exists = minio.bucket_exists(minio_bucket)
except Exception as e:
log.info("Error while connecting to MinIO: %s", e)
nazywam marked this conversation as resolved.
Show resolved Hide resolved
retry = get_user_option(
'Do you want to try with different MinIO settings ("yes", "no")?',
default="yes",
)
if retry != "yes":
log.info("Quitting configuration")
return
else:
continue

log.info("Connected to MinIO successfully")
if not bucket_exists:
log.info(
(
"The required bucket %s does not exist. To create it automatically,"
" start karton-system with --setup-bucket flag"
),
minio_bucket,
)
break

config["minio"] = {
"access_key": minio_access_key,
"secret_key": minio_secret_key,
"address": minio_address,
"bucket": minio_bucket,
"secure": str(bool(int(minio_secure))),
}

log.info("Configuring Redis")

while True:
redis_host = get_user_option("Enter the Redis host", default="localhost")
redis_port = get_user_option("Enter the Redis port", default="6379")

log.info("Testing Redis connection...")
redis = StrictRedis(
host=redis_host,
port=int(redis_port),
decode_responses=True,
)
try:
redis.ping()
except Exception as e:
log.info("Error while connecting to Redis: %s", e)
nazywam marked this conversation as resolved.
Show resolved Hide resolved
retry = get_user_option(
'Do you want to try with different Redis settings ("yes", "no")?',
default="yes",
)
if retry != "yes":
log.info("Quitting configuration")
return
else:
continue

log.info("Connected to Redis successfully")
break

config["redis"] = {
"host": redis_host,
"port": str(int(redis_port)),
}

with open(config_filename, "w") as configfile:
config.write(configfile)

log.info("Saved the new configuration file in %s", os.path.abspath(config_filename))


def print_bind_list(config: Config) -> None:
backend = KartonBackend(config=config)
Expand All @@ -19,11 +133,11 @@ def delete_bind(config: Config, karton_name: str) -> None:
consumers = backend.get_online_consumers()

if karton_name not in binds:
print("Trying to delete a karton bind that doesn't exist")
log.error("Trying to delete a karton bind that doesn't exist")
return

if consumers.get(karton_name, []):
print(
log.error(
"This bind has active replicas that need to be downscaled "
"before it can be deleted"
)
Expand All @@ -42,30 +156,79 @@ def process(self, task):


def main() -> None:

parser = argparse.ArgumentParser(description="Your red pill to the karton-verse")
parser.add_argument("--list", action="store_true", help="List active karton binds")
parser.add_argument("--version", action="version", version=__version__)
parser.add_argument("-c", "--config-file", help="Alternative configuration path")
parser.add_argument(
"--delete", action="store", help="Delete persistent karton bind"
"-v", "--verbose", action="store_true", help="More verbose log output"
)
parser.add_argument("--version", action="version", version=__version__)
parser.add_argument("--config-file", help="Alternative configuration path")

subparsers = parser.add_subparsers(dest="command", help="sub-command help")
nazywam marked this conversation as resolved.
Show resolved Hide resolved

subparsers.add_parser("list", help="List active karton binds")

delete_parser = subparsers.add_parser("delete", help="Delete an unused karton bind")
delete_parser.add_argument("identity", help="Karton bind identity to remove")

configure_parser = subparsers.add_parser(
"configure", help="Create a new configuration file"
)
configure_parser.add_argument(
"-f",
"--force",
action="store_true",
help="Overwrite the existing configuration file",
)

args = parser.parse_args()

config = Config(args.config_file)
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)

if args.command == "configure":
config_filename = args.config_file or "./karton.ini"

log.debug("Creating a new configuration file in %s", config_filename)

if not args.force and os.path.exists(config_filename):
log.error(
(
"There's already a configuration file under %s. Please delete "
"it or specify a different filename using the -c argument"
),
config_filename,
)
return

configuration_wizard(config_filename)
return

if args.delete:
karton_name = args.delete
try:
config = Config(args.config_file)
except RuntimeError as e:
log.error("Error while initializing the karton config: %s", e)
log.error(
(
"Please correct the configuration file or run `karton configure` "
"to initialize it"
)
)
return

if args.command == "list":
print_bind_list(config)
elif args.command == "delete":
karton_name = args.identity
print(
"Are you sure you want to remove binds for karton {karton_name}?\n"
"Type in the karton name to confirm".format(karton_name=karton_name)
f"Are you sure you want to remove binds for karton {karton_name}?\n"
"Type in the karton name to confirm deletion."
)
if input().strip() == karton_name:
delete_bind(config, karton_name)
else:
nazywam marked this conversation as resolved.
Show resolved Hide resolved
print("abort")

return

if args.list:
print_bind_list(config)
return
log.info("abort")
nazywam marked this conversation as resolved.
Show resolved Hide resolved
else:
parser.print_help()