File: gcloud_setup.py

package info (click to toggle)
ipyparallel 9.0.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,388 kB
  • sloc: python: 22,769; javascript: 267; makefile: 29; sh: 28
file content (189 lines) | stat: -rwxr-xr-x 5,534 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#!/usr/bin/env python3
import multiprocessing as mp
import os
import sys
from subprocess import Popen, check_call
from time import sleep
from typing import List

import googleapiclient.discovery as gcd

from benchmarks.utils import get_time_stamp

CORE_NUMBERS_FOR_TEMPLATES = [64]

ZONE = "europe-west1-b"
PROJECT_NAME = "jupyter-simula"
INSTANCE_NAME_PREFIX = "asv-testing-"
MACHINE_CONFIGS_DIR = os.path.join(os.getcwd(), "machine_configs")
CONDA_PATH = 'miniconda3/bin/conda'

compute = gcd.build("compute", "v1")


def generate_template_name(number_of_cores_and_ram):
    return f"{INSTANCE_NAME_PREFIX}{number_of_cores_and_ram}"


def get_running_instance_names() -> List[str]:
    result = compute.instances().list(project=PROJECT_NAME, zone=ZONE).execute()
    return [item["name"] for item in result["items"]] if "items" in result else []


def delete_instance(instance_name) -> dict:
    print(f"Deleting instance: {instance_name}")
    return (
        compute.instances()
        .delete(project=PROJECT_NAME, zone=ZONE, instance=instance_name)
        .execute()
    )


def delete_all_instances():
    return [
        delete_instance(name)
        for name in get_running_instance_names()
        if INSTANCE_NAME_PREFIX in name
    ]


def gcloud_run(*args, block=True):
    cmd = ["gcloud", "compute"] + list(args)
    print(f'$ {" ".join(cmd)}')
    (
        check_call(
            cmd
            # stdout=open(get_gcloud_log_file_name(instance_name) + ".log", "a+"),
            # stderr=open(f"{get_gcloud_log_file_name(instance_name)}_error.out", "a+"),
        )
        if block
        else Popen(cmd)
    )


def copy_files_to_instance(instance_name, *file_names, directory="~"):
    for file_name in file_names:
        gcloud_run("scp", file_name, f"{instance_name}:{directory}", f"--zone={ZONE}")


def command_over_ssh(instance_name, *args, block=True):
    return gcloud_run("ssh", instance_name, f"--zone={ZONE}", "--", *args, block=block)


def run_on_instance(template_name):
    current_instance_name = f"{template_name}-{get_time_stamp()}"
    benchmark_name = sys.argv[1] if len(sys.argv) > 1 else ''

    print(f"Creating new instance with name: {current_instance_name}")

    gcloud_run(
        "instances",
        "create",
        current_instance_name,
        "--source-instance-template",
        template_name,
    )
    sleep(20)  # Waiting for ssh keys to propagate to instance
    command_over_ssh(current_instance_name, "sudo", "apt", "update")
    print("copying instance setup to instance")
    command_over_ssh(
        current_instance_name,
        'wget',
        '-q',
        'https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh',
    )
    print('installing miniconda')
    command_over_ssh(
        current_instance_name, 'bash', 'Miniconda3-latest-Linux-x86_64.sh', '-b'
    )
    command_over_ssh(
        current_instance_name,
        'echo',
        '"source  miniconda3/bin/activate"',
        '>>',
        '~/.bashrc',
    )
    command_over_ssh(current_instance_name, f'{CONDA_PATH}', 'init')
    print('installing asv and google api')
    command_over_ssh(
        current_instance_name,
        f'{CONDA_PATH}',
        'install',
        '-c',
        'conda-forge',
        'asv',
        'google-api-python-client',
        'google-auth-httplib2',
        'google-auth-oauthlib',
        'google-cloud-storage',
        'numpy',
        '-y',
    )

    copy_files_to_instance(current_instance_name, "instance_setup.py")

    for config_name in os.listdir(MACHINE_CONFIGS_DIR):
        if config_name == template_name + ".json":
            copy_files_to_instance(
                current_instance_name,
                os.path.join(MACHINE_CONFIGS_DIR, config_name),
                directory="~/.asv-machine.json",
            )
            break
    else:
        print(f"Found no valid machine config for template: {template_name}.")
        exit(1)
    print("starting instance setup")
    command_over_ssh(
        current_instance_name,
        "miniconda3/bin/python3",
        "instance_setup.py",
        current_instance_name,
        template_name,
        block=True,
    )

    command_over_ssh(
        current_instance_name,
        'cd',
        'ipyparallel_master_project',
        ';',
        "~/miniconda3/bin/python3",
        'asv_runner.py',
        benchmark_name,
        template_name,
        block=False,
    )


if __name__ == "__main__":
    running_instances = get_running_instance_names()
    number_of_running_instances = len(running_instances)
    # atexit.register(delete_all_instances)

    print(f"Currently there are {number_of_running_instances} running instances.")
    if number_of_running_instances:
        print("Running instances: ")
        for instance in running_instances:
            print(f"  {instance}")

    if "-d" in sys.argv:
        result = delete_instance(sys.argv[2])
    elif "-da" in sys.argv:
        result = delete_all_instances()
    if "-q" in sys.argv:
        exit(0)

    if len(CORE_NUMBERS_FOR_TEMPLATES) == 1:
        run_on_instance(generate_template_name(CORE_NUMBERS_FOR_TEMPLATES[0]))
    else:
        with mp.Pool(len(CORE_NUMBERS_FOR_TEMPLATES)) as pool:
            result = pool.map_async(
                run_on_instance,
                [
                    generate_template_name(core_number)
                    for core_number in CORE_NUMBERS_FOR_TEMPLATES
                ],
            )
        result.wait()
    print("gcloud setup finished.")