mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
160 lines
4.9 KiB
Python
160 lines
4.9 KiB
Python
import os
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
from typing import List
|
|
|
|
import digitalocean
|
|
import zulip
|
|
from requests.adapters import HTTPAdapter
|
|
from requests.packages.urllib3.util.retry import Retry
|
|
|
|
manager = digitalocean.Manager(token=os.environ["DIGITALOCEAN_API_KEY"])
|
|
zulip_client = zulip.Client()
|
|
TEST_DROPLET_SUBDOMAIN = "oneclicktest"
|
|
|
|
|
|
def generate_ssh_keys() -> None:
|
|
subprocess.call(
|
|
["ssh-keygen", "-f", str(Path.home()) + "/.ssh/id_ed25519", "-P", "", "-t", "ed25519"]
|
|
)
|
|
|
|
|
|
def get_public_ssh_key() -> str:
|
|
try:
|
|
with open(str(Path.home()) + "/.ssh/id_ed25519.pub") as f:
|
|
return f.read()
|
|
except FileNotFoundError:
|
|
return ""
|
|
|
|
|
|
def sleep_until_droplet_action_is_completed(
|
|
droplet: digitalocean.Droplet, action_type: str
|
|
) -> None:
|
|
incomplete = True
|
|
while incomplete:
|
|
for action in droplet.get_actions():
|
|
action.load()
|
|
print(f"...[{action.type}]: {action.status}")
|
|
if action.type == action_type and action.status == "completed":
|
|
incomplete = False
|
|
break
|
|
if incomplete:
|
|
time.sleep(5)
|
|
droplet.load()
|
|
|
|
|
|
def set_api_request_retry_limits(api_object: digitalocean.baseapi.BaseAPI) -> None:
|
|
retry = Retry(connect=5, read=5, backoff_factor=0.1)
|
|
adapter = HTTPAdapter(max_retries=retry)
|
|
api_object._session.mount("https://", adapter)
|
|
|
|
|
|
def create_droplet(
|
|
name: str, ssh_keys: List[str], image: str = "ubuntu-18-04-x64"
|
|
) -> digitalocean.Droplet:
|
|
droplet = digitalocean.Droplet(
|
|
token=manager.token,
|
|
name=name,
|
|
region="nyc3",
|
|
size_slug="s-1vcpu-2gb",
|
|
image=image,
|
|
backups=False,
|
|
ssh_keys=ssh_keys,
|
|
tags=["github-action", "temporary"],
|
|
)
|
|
set_api_request_retry_limits(droplet)
|
|
droplet.create()
|
|
sleep_until_droplet_action_is_completed(droplet, "create")
|
|
return droplet
|
|
|
|
|
|
def create_ssh_key(name: str, public_key: str) -> digitalocean.SSHKey:
|
|
action_public_ssh_key_object = digitalocean.SSHKey(
|
|
name=name, public_key=public_key, token=manager.token
|
|
)
|
|
set_api_request_retry_limits(action_public_ssh_key_object)
|
|
action_public_ssh_key_object.create()
|
|
return action_public_ssh_key_object
|
|
|
|
|
|
def create_snapshot(droplet: digitalocean.Droplet, snapshot_name: str) -> None:
|
|
droplet.take_snapshot(snapshot_name, power_off=True)
|
|
droplet.load()
|
|
sleep_until_droplet_action_is_completed(droplet, "snapshot")
|
|
|
|
|
|
def create_dns_records(droplet: digitalocean.Droplet) -> None:
|
|
domain = digitalocean.Domain(token=manager.token, name="zulipdev.org")
|
|
set_api_request_retry_limits(domain)
|
|
domain.load()
|
|
|
|
oneclick_test_app_record_names = [TEST_DROPLET_SUBDOMAIN, f"*.{TEST_DROPLET_SUBDOMAIN}"]
|
|
for record in domain.get_records():
|
|
if (
|
|
record.name in oneclick_test_app_record_names
|
|
and record.domain == "zulipdev.org"
|
|
and record.type == "A"
|
|
):
|
|
record.destroy()
|
|
|
|
domain.load()
|
|
for record_name in oneclick_test_app_record_names:
|
|
domain.create_new_domain_record(type="A", name=record_name, data=droplet.ip_address)
|
|
|
|
|
|
def setup_one_click_app_installer(droplet: digitalocean.Droplet) -> None:
|
|
subprocess.call(
|
|
[
|
|
"fab",
|
|
"build_image",
|
|
"-H",
|
|
droplet.ip_address,
|
|
"--keepalive",
|
|
"5",
|
|
"--connection-attempts",
|
|
"10",
|
|
],
|
|
cwd="marketplace-partners/marketplace_docs/templates/Fabric",
|
|
)
|
|
|
|
|
|
def send_message(content: str) -> None:
|
|
request = {
|
|
"type": "stream",
|
|
"to": os.environ["ONE_CLICK_ACTION_STREAM"],
|
|
"topic": "digitalocean installer",
|
|
"content": content,
|
|
}
|
|
zulip_client.send_message(request)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
release_version = os.environ["RELEASE_VERSION"]
|
|
|
|
generate_ssh_keys()
|
|
action_public_ssh_key_object = create_ssh_key(
|
|
f"oneclickapp-{release_version}-image-generator-public-key", get_public_ssh_key()
|
|
)
|
|
|
|
image_generator_droplet = create_droplet(
|
|
f"oneclickapp-{release_version}-image-generator", [action_public_ssh_key_object]
|
|
)
|
|
|
|
setup_one_click_app_installer(image_generator_droplet)
|
|
|
|
oneclick_image_name = f"oneclickapp-{release_version}"
|
|
create_snapshot(image_generator_droplet, oneclick_image_name)
|
|
snapshot = image_generator_droplet.get_snapshots()[0]
|
|
send_message(f"One click app image `{oneclick_image_name}` created.")
|
|
|
|
image_generator_droplet.destroy()
|
|
action_public_ssh_key_object.destroy()
|
|
|
|
test_droplet_name = f"oneclickapp-{release_version}-test"
|
|
test_droplet = create_droplet(test_droplet_name, manager.get_all_sshkeys(), image=snapshot.id)
|
|
create_dns_records(test_droplet)
|
|
send_message(
|
|
f"Test droplet `{test_droplet_name}` created. SSH as root to {TEST_DROPLET_SUBDOMAIN}.zulipdev.org for testing."
|
|
)
|