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

Refactor organization of CLI #347

Merged
merged 5 commits into from
May 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 62 additions & 16 deletions skylark/cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,44 @@
"""CLI for the Skylark object store"""

import subprocess
from functools import partial
from pathlib import Path
from shlex import split

import questionary
import typer
from halo import Halo

import skylark.cli.cli_aws
import skylark.cli.cli_azure
import skylark.cli.cli_gcp
import skylark.cli.cli_internal as cli_internal
import skylark.cli.cli_solver
import skylark.cli.experiments
from skylark import GB, config_path, exceptions, print_header, skylark_root
from skylark.cli.cli_helper import (
check_ulimit,
copy_azure_local,
from skylark.cli.cli_impl.cp_local import (
copy_local_local,
copy_local_gcs,
copy_gcs_local,
copy_local_azure,
copy_local_gcs,
copy_local_local,
copy_azure_local,
copy_local_s3,
copy_s3_local,
deprovision_skylark_instances,
load_aws_config,
load_azure_config,
load_gcp_config,
ls_local,
ls_objstore,
)
from skylark.cli.cli_impl.cp_replicate import replicate_helper
from skylark.cli.cli_impl.init import load_aws_config, load_azure_config, load_gcp_config
from skylark.cli.cli_impl.ls import ls_local, ls_objstore
from skylark.cli.util import (
check_ulimit,
parse_path,
replicate_helper,
query_instances,
)
from skylark.compute.aws.aws_auth import AWSAuthentication
from skylark.compute.aws.aws_cloud_provider import AWSCloudProvider
from skylark.config import SkylarkConfig
from skylark.obj_store.object_store_interface import ObjectStoreInterface
from skylark.replicate.replication_plan import ReplicationTopology
from skylark.replicate.solver import ThroughputProblem, ThroughputSolverILP
from skylark.utils import logger
from skylark.utils.utils import do_parallel

app = typer.Typer(name="skylark")
app.command()(cli_internal.replicate_random)
Expand All @@ -43,7 +47,6 @@
app.add_typer(skylark.cli.experiments.app, name="experiments")
app.add_typer(skylark.cli.cli_aws.app, name="aws")
app.add_typer(skylark.cli.cli_azure.app, name="azure")
app.add_typer(skylark.cli.cli_gcp.app, name="gcp")
app.add_typer(skylark.cli.cli_solver.app, name="solver")


Expand Down Expand Up @@ -109,6 +112,10 @@ def cp(
:type max_instances: int
:param reuse_gateways: If true, will leave provisioned instances running to be reused. You must run `skylark deprovision` to clean up.
:type reuse_gateways: bool
:param max_chunk_size_mb: If set, `cp` will subdivide objects into chunks at most this size.
:type max_chunk_size_mb: int
:param use_bbr: If set, will use BBR for transfers by default.
:type use_bbr: bool
:param solve: If true, will use solver to optimize transfer, else direct path is chosen
:type solve: bool
:param solver_required_throughput_gbits: The required throughput in Gbps when using the solver (default: 4)
Expand Down Expand Up @@ -214,7 +221,46 @@ def cp(
@app.command()
def deprovision():
"""Deprovision all resources created by skylark."""
deprovision_skylark_instances()
instances = query_instances()

if instances:
typer.secho(f"Deprovisioning {len(instances)} instances", fg="yellow", bold=True)
do_parallel(lambda instance: instance.terminate_instance(), instances, desc="Deprovisioning", spinner=True, spinner_persist=True)
else:
typer.secho("No instances to deprovision", fg="yellow", bold=True)

if AWSAuthentication().enabled():
aws = AWSCloudProvider()
# remove skylark vpc
vpcs = do_parallel(partial(aws.get_vpcs), aws.region_list(), desc="Querying VPCs", spinner=True)
args = [(x[0], vpc.id) for x in vpcs for vpc in x[1]]
do_parallel(lambda args: aws.remove_sg_ips(*args), args, desc="Removing IPs from VPCs", spinner=True, spinner_persist=True)
# remove all instance profiles
profiles = aws.list_instance_profiles(prefix="skylark-aws")
if profiles:
do_parallel(aws.delete_instance_profile, profiles, desc="Deleting instance profiles", spinner=True, spinner_persist=True, n=4)


@app.command()
def ssh():
"""SSH into a running gateway."""
instances = query_instances()
if len(instances) == 0:
typer.secho(f"No instances found", fg="red")
raise typer.Abort()

instance_map = {f"{i.region_tag}, {i.public_ip()} ({i.instance_state()})": i for i in instances}
choices = list(sorted(instance_map.keys()))
instance_name = questionary.select("Select an instance", choices=choices).ask()
if instance_name is not None and instance_name in instance_map:
instance = instance_map[instance_name]
cmd = instance.get_ssh_cmd()
logger.info(f"Running SSH command: {cmd}")
logger.info("It may ask for a private key password, try `skylark`.")
proc = subprocess.Popen(split(cmd))
proc.wait()
else:
typer.secho(f"No instance selected", fg="red")


@app.command()
Expand Down
26 changes: 0 additions & 26 deletions skylark/cli/cli_aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,13 @@
"""

import json
import subprocess
import time
from shlex import split
from typing import Optional

import questionary
import typer

from skylark import GB
from skylark.compute.aws.aws_auth import AWSAuthentication
from skylark.compute.aws.aws_cloud_provider import AWSCloudProvider
from skylark.compute.aws.aws_server import AWSServer
from skylark.obj_store.s3_interface import S3Interface
from skylark.utils import logger
from skylark.utils.utils import Timer, do_parallel
Expand Down Expand Up @@ -42,27 +37,6 @@ def get_service_quota(region):
typer.secho(f"{region}: {int(quota)}", fg="green")


@app.command()
def ssh(region: Optional[str] = None):
aws = AWSCloudProvider()
typer.secho("Querying AWS for instances", fg="green")
instances = aws.get_matching_instances(region=region)
if len(instances) == 0:
typer.secho(f"No instances found", fg="red")
raise typer.Abort()

instance_map = {f"{i.region()}, {i.public_ip()} ({i.instance_state()})": i for i in instances}
choices = list(sorted(instance_map.keys()))
instance_name: AWSServer = questionary.select("Select an instance", choices=choices).ask()
if instance_name is not None and instance_name in instance_map:
instance = instance_map[instance_name]
cmd = instance.get_ssh_cmd()
proc = subprocess.Popen(split(cmd))
proc.wait()
else:
typer.secho(f"No instance selected", fg="red")


@app.command()
def cp_datasync(src_bucket: str, dst_bucket: str, path: str):
aws_auth = AWSAuthentication()
Expand Down
31 changes: 1 addition & 30 deletions skylark/cli/cli_azure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,13 @@
AWS convenience interface
"""


import subprocess
from collections import defaultdict
from shlex import split
from typing import List, Optional
from typing import List

import questionary
import typer

from skylark.compute.azure.azure_auth import AzureAuthentication
from skylark.compute.azure.azure_cloud_provider import AzureCloudProvider
from skylark.compute.azure.azure_server import AzureServer
from skylark.utils import logger
from skylark.utils.utils import do_parallel

app = typer.Typer(name="skylark-azure")
Expand Down Expand Up @@ -49,26 +43,3 @@ def get_skus(region):
sorted_top_keys = sorted_top_keys[:top_k]
for sku in sorted_top_keys:
typer.secho(f"{sku} in {len(sku_regions[sku])} regions: {list(sorted(sku_regions[sku]))}")


@app.command()
def ssh(region: Optional[str] = None):
azure = AzureCloudProvider()
typer.secho("Querying Azure for instances", fg="green")
instances = azure.get_matching_instances(region=region)
if len(instances) == 0:
typer.secho(f"No instances found", fg="red")
raise typer.Abort()

instance_map = {f"{i.region()}, {i.public_ip()} ({i.instance_state()})": i for i in instances}
choices = list(sorted(instance_map.keys()))
instance_name: AzureServer = questionary.select("Select an instance", choices=choices).ask()
if instance_name is not None and instance_name in instance_map:
instance = instance_map[instance_name]
cmd = instance.get_ssh_cmd()
logger.info(f"Running SSH command: {cmd}")
logger.info("It may ask for a private key password, try `skylark`.")
proc = subprocess.Popen(split(cmd))
proc.wait()
else:
typer.secho(f"No instance selected", fg="red")
32 changes: 0 additions & 32 deletions skylark/cli/cli_gcp.py

This file was deleted.

Loading