Beispiel #1
0
def configure_parser(parser: argparse.ArgumentParser) -> None:
    check_required_vars()
    parser.add_argument(
        "who",
        nargs="*",
        help="Whose instances to show (defaults to yourself)",
        default=[whoami()],
    )
    parser.add_argument("--all", help="Show all instances", action="store_true")
    parser.add_argument("--output-format", choices=["table", "csv"], default="table")
Beispiel #2
0
def run(args: argparse.Namespace) -> None:
    extra_tags = {}
    if args.extra_tags:
        extra_tags = json.loads(args.extra_tags)
        if not isinstance(extra_tags, dict) or not all(
                isinstance(k, str) and isinstance(v, str)
                for k, v in extra_tags.items()):
            raise RuntimeError(
                "extra-tags must be a JSON dictionary of strings to strings")

    check_required_vars()

    extra_tags["LaunchedBy"] = whoami()

    if args.machine:
        with open(ROOT / "misc" / "scratch" /
                  "{}.json".format(args.machine)) as f:

            print("Reading machine configs from {}".format(f.name))
            descs = [
                MachineDesc.parse_obj(obj) for obj in multi_json(f.read())
            ]
    else:
        print("Reading machine configs from stdin...")
        descs = [
            MachineDesc.parse_obj(obj) for obj in multi_json(sys.stdin.read())
        ]

    if args.ssh and len(descs) != 1:
        raise RuntimeError("Cannot use `--ssh` with {} instances".format(
            len(descs)))

    if args.max_age_days <= 0:
        raise RuntimeError(
            f"max_age_days must be positive, got {args.max_age_days}")
    max_age = datetime.timedelta(days=args.max_age_days)

    instances = launch_cluster(
        descs,
        subnet_id=args.subnet_id,
        key_name=args.key_name,
        security_group_id=args.security_group_id,
        instance_profile=args.instance_profile,
        extra_tags=extra_tags,
        delete_after=datetime.datetime.utcnow() + max_age,
        git_rev=args.git_rev,
        extra_env={},
    )

    print("Launched instances:")
    print_instances(instances, args.output_format)

    if args.ssh:
        print("ssh-ing into: {}".format(instances[0].instance_id))
        mssh(instances[0], "")
Beispiel #3
0
def run(args: argparse.Namespace) -> None:
    filters: List[FilterTypeDef] = []
    if not args.all:
        filters.append({
            "Name": "tag:LaunchedBy",
            "Values": args.who or [whoami()]
        })
    print_instances(
        list(boto3.resource("ec2").instances.filter(Filters=filters)),
        args.output_format,
    )
Beispiel #4
0
def run(args: argparse.Namespace) -> None:
    instance_profile = None if args.no_instance_profile else args.instance_profile
    extra_tags = {}
    if args.extra_tags:
        extra_tags = json.loads(args.extra_tags)
        if not isinstance(extra_tags, dict) or not all(
            isinstance(k, str) and isinstance(v, str) for k, v in extra_tags.items()
        ):
            raise RuntimeError(
                "extra-tags must be a JSON dictionary of strings to strings"
            )

    check_required_vars()

    extra_tags["LaunchedBy"] = whoami()

    descs = [
        MachineDesc(
            name=obj["name"],
            launch_script=obj.get("launch_script"),
            instance_type=obj["instance_type"],
            ami=obj["ami"],
            tags=obj.get("tags", dict()),
            size_gb=obj["size_gb"],
            checkout=obj.get("checkout", True),
        )
        for obj in multi_json(sys.stdin.read())
    ]

    nonce = util.nonce(8)

    delete_after = now_plus(MAX_AGE)
    instances = launch_cluster(
        descs,
        nonce,
        args.subnet_id,
        args.key_name,
        args.security_group_id,
        instance_profile,
        extra_tags,
        delete_after,
        args.git_rev,
        extra_env={},
    )

    print("Launched instances:")
    print_instances(instances, args.output_format)
Beispiel #5
0
def run(args: argparse.Namespace) -> None:
    check_required_vars()
    instance_ids = []
    filters: List[FilterTypeDef] = [{
        "Name":
        "instance-state-name",
        "Values": ["pending", "running", "stopping", "stopped"],
    }]
    if args.all_mine:
        if args.instances:
            print(
                "scratch: error: cannot specify --all-mine and instance IDs",
                file=sys.stderr,
            )
            sys.exit(1)
        filters.append({"Name": "tag:LaunchedBy", "Values": [whoami()]})
    elif not args.instances:
        print(
            "scratch: error: must supply at least one instance ID to destroy",
            file=sys.stderr,
        )
        sys.exit(1)
    else:
        instance_ids.extend(args.instances)

    instances = list(
        boto3.resource("ec2").instances.filter(Filters=filters,
                                               InstanceIds=instance_ids))

    print("Destroying instances:")
    print_instances(instances, args.output_format)

    if not args.yes and not ui.confirm("Would you like to continue?"):
        sys.exit(0)

    for instance in instances:
        instance.terminate()
    print("Instances destroyed.")
Beispiel #6
0
def start(ns: argparse.Namespace) -> None:
    check_required_vars()

    revs = ns.revs.split(",")

    clusters = list(
        itertools.product(range(ns.trials),
                          (git.rev_parse(rev) for rev in revs)))

    bench_script = ns.bench_script
    script_name = bench_script[0]
    script_args = " ".join((shlex.quote(arg) for arg in bench_script[1:]))

    # zip up the `misc` repository, for shipment to the remote machine
    os.chdir("misc/python")
    spawn.runv(["python3", "./setup.py", "sdist"])

    with open("./dist/materialize-0.0.0.tar.gz", "rb") as f:
        pkg_data = f.read()
    os.chdir(os.environ["MZ_ROOT"])

    if ns.append_metadata:
        munge_result = 'awk \'{ if (NR == 1) { print $0 ",Timestamp,BenchId,ClusterId,GitRef,S3Root" } else { print $0 ",\'$(date +%s)",$MZ_CB_BENCH_ID,$MZ_CB_CLUSTER_ID,$MZ_CB_GIT_REV,$MZ_CB_S3_ROOT"\'"}}\''
    else:
        munge_result = "cat"

    mz_launch_script = f"""echo {shlex.quote(base64.b64encode(pkg_data).decode('utf-8'))} | base64 -d > mz.tar.gz
python3 -m venv /tmp/mzenv >&2
. /tmp/mzenv/bin/activate >&2
python3 -m pip install --upgrade pip >&2
pip3 install ./mz.tar.gz[dev] >&2
MZ_ROOT=/home/ubuntu/materialize python3 -u -m {script_name} {script_args}
result=$?
echo $result > ~/bench_exit_code
if [ $result -eq 0 ]; then
    {munge_result} < ~/mzscratch-startup.out | aws s3 cp - s3://{ns.s3_root}/$MZ_CB_BENCH_ID/$MZ_CB_CLUSTER_ID.csv >&2
else
    aws s3 cp - s3://{ns.s3_root}/$MZ_CB_BENCH_ID/$MZ_CB_CLUSTER_ID-FAILURE.out < ~/mzscratch-startup.out >&2
    aws s3 cp - s3://{ns.s3_root}/$MZ_CB_BENCH_ID/$MZ_CB_CLUSTER_ID-FAILURE.err < ~/mzscratch-startup.err
fi
sudo shutdown -h now # save some money
"""

    if ns.profile == "basic":
        descs = [
            scratch.MachineDesc(
                name="materialized",
                launch_script=mz_launch_script,
                instance_type="r5a.4xlarge",
                ami="ami-0b29b6e62f2343b46",
                tags={},
                size_gb=64,
            ),
        ]
    elif ns.profile == "confluent":
        confluent_launch_script = f"""bin/mzcompose --mz-find load-tests up"""
        descs = [
            scratch.MachineDesc(
                name="materialized",
                launch_script=mz_launch_script,
                instance_type="r5a.4xlarge",
                ami="ami-0b29b6e62f2343b46",
                tags={},
                size_gb=64,
            ),
            scratch.MachineDesc(
                name="confluent",
                launch_script=confluent_launch_script,
                instance_type="r5a.4xlarge",
                ami="ami-0b29b6e62f2343b46",
                tags={},
                size_gb=1000,
                checkout=False,
            ),
        ]
    else:
        raise RuntimeError(f"Profile {ns.profile} is not implemented yet")

    bench_id = util.nonce(8)

    manifest_bytes = "".join(f"{i}-{rev}\n"
                             for i, rev in clusters).encode("utf-8")
    boto3.client("s3").put_object(Body=manifest_bytes,
                                  Bucket="mz-cloudbench",
                                  Key=f"{bench_id}/MANIFEST")

    # TODO - Do these in parallel
    launched = []
    for (i, rev) in clusters:
        launched += scratch.launch_cluster(
            descs=descs,
            nonce=f"{bench_id}-{i}-{rev}",
            subnet_id=DEFAULT_SUBNET_ID,
            security_group_id=DEFAULT_SG_ID,
            instance_profile=DEFAULT_INSTPROF_NAME,
            key_name=None,
            extra_tags={
                "bench_id": bench_id,
                "bench_rev": rev,
                "bench_i": str(i),
                "LaunchedBy": scratch.whoami(),
            },
            extra_env={
                "MZ_CB_BENCH_ID": bench_id,
                "MZ_CB_CLUSTER_ID": f"{i}-{rev}",
                "MZ_CB_GIT_REV": rev,
                "MZ_CB_S3_ROOT": ns.s3_root,
            },
            delete_after=scratch.now_plus(timedelta(days=1)),
            git_rev=rev,
        )

    print("Launched instances:")
    print_instances(launched, format="table")  # todo
    print(f"""Launched cloud bench with ID {bench_id}.
To wait for results, run: bin/cloudbench check {bench_id}""")