mirror of
https://github.com/zulip/zulip.git
synced 2025-11-13 02:17:19 +00:00
droplets: Add support for creating prod droplets.
This commit is contained in:
@@ -210,3 +210,12 @@ They can remove your SSH keys by running:
|
|||||||
```
|
```
|
||||||
$ python3 ~/zulip/tools/droplets/add_mentor.py <your username> --remove
|
$ python3 ~/zulip/tools/droplets/add_mentor.py <your username> --remove
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Creating a production droplet
|
||||||
|
|
||||||
|
`create.py` can also create a production droplet quickly for testing purposes.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ python3 create.py <username> --production
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# Creates a Droplet on DigitalOcean for remote Zulip development.
|
# Creates a Zulip remote development environment droplet or
|
||||||
|
# a production droplet in DigitalOcean.
|
||||||
|
#
|
||||||
# Particularly useful for sprints/hackathons, interns, and other
|
# Particularly useful for sprints/hackathons, interns, and other
|
||||||
# situation where one wants to quickly onboard new contributors.
|
# situation where one wants to quickly onboard new contributors.
|
||||||
#
|
#
|
||||||
@@ -25,6 +27,7 @@ import urllib.request
|
|||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
import digitalocean
|
import digitalocean
|
||||||
|
import requests
|
||||||
|
|
||||||
# initiation argument parser
|
# initiation argument parser
|
||||||
parser = argparse.ArgumentParser(description="Create a Zulip devopment VM DigitalOcean droplet.")
|
parser = argparse.ArgumentParser(description="Create a Zulip devopment VM DigitalOcean droplet.")
|
||||||
@@ -33,6 +36,7 @@ parser.add_argument(
|
|||||||
)
|
)
|
||||||
parser.add_argument("--tags", nargs="+", default=[])
|
parser.add_argument("--tags", nargs="+", default=[])
|
||||||
parser.add_argument("-f", "--recreate", action="store_true")
|
parser.add_argument("-f", "--recreate", action="store_true")
|
||||||
|
parser.add_argument("-p", "--production", action="store_true")
|
||||||
|
|
||||||
|
|
||||||
def get_config() -> configparser.ConfigParser:
|
def get_config() -> configparser.ConfigParser:
|
||||||
@@ -109,7 +113,7 @@ def get_ssh_keys_string_from_github_ssh_key_dicts(userkey_dicts: List[Dict[str,
|
|||||||
return "\n".join([userkey_dict["key"] for userkey_dict in userkey_dicts])
|
return "\n".join([userkey_dict["key"] for userkey_dict in userkey_dicts])
|
||||||
|
|
||||||
|
|
||||||
def set_user_data(username: str, userkey_dicts: List[Dict[str, Any]]) -> str:
|
def generate_dev_droplet_user_data(username: str, userkey_dicts: List[Dict[str, Any]]) -> str:
|
||||||
ssh_keys_string = get_ssh_keys_string_from_github_ssh_key_dicts(userkey_dicts)
|
ssh_keys_string = get_ssh_keys_string_from_github_ssh_key_dicts(userkey_dicts)
|
||||||
setup_root_ssh_keys = f"printf '{ssh_keys_string}' > /root/.ssh/authorized_keys"
|
setup_root_ssh_keys = f"printf '{ssh_keys_string}' > /root/.ssh/authorized_keys"
|
||||||
setup_zulipdev_ssh_keys = f"printf '{ssh_keys_string}' > /home/zulipdev/.ssh/authorized_keys"
|
setup_zulipdev_ssh_keys = f"printf '{ssh_keys_string}' > /home/zulipdev/.ssh/authorized_keys"
|
||||||
@@ -146,6 +150,22 @@ su -c 'git config --global pull.rebase true' zulipdev
|
|||||||
return cloudconf
|
return cloudconf
|
||||||
|
|
||||||
|
|
||||||
|
def generate_prod_droplet_user_data(username: str, userkey_dicts: List[Dict[str, Any]]) -> str:
|
||||||
|
ssh_keys_string = get_ssh_keys_string_from_github_ssh_key_dicts(userkey_dicts)
|
||||||
|
setup_root_ssh_keys = f"printf '{ssh_keys_string}' > /root/.ssh/authorized_keys"
|
||||||
|
|
||||||
|
cloudconf = f"""\
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
{setup_root_ssh_keys}
|
||||||
|
passwd -d root
|
||||||
|
sed -i "s/PasswordAuthentication yes/PasswordAuthentication no/g" /etc/ssh/sshd_config
|
||||||
|
service ssh restart
|
||||||
|
"""
|
||||||
|
print("...returning cloud-config data.")
|
||||||
|
return cloudconf
|
||||||
|
|
||||||
|
|
||||||
def create_droplet(
|
def create_droplet(
|
||||||
my_token: str, template_id: str, name: str, tags: List[str], user_data: str
|
my_token: str, template_id: str, name: str, tags: List[str], user_data: str
|
||||||
) -> str:
|
) -> str:
|
||||||
@@ -205,7 +225,7 @@ def create_dns_record(my_token: str, record_name: str, ip_address: str) -> None:
|
|||||||
domain.create_new_domain_record(type="A", name=wildcard_name, data=ip_address)
|
domain.create_new_domain_record(type="A", name=wildcard_name, data=ip_address)
|
||||||
|
|
||||||
|
|
||||||
def print_completion(droplet_domain_name: str) -> None:
|
def print_dev_droplet_instructions(droplet_domain_name: str) -> None:
|
||||||
print(
|
print(
|
||||||
"""
|
"""
|
||||||
COMPLETE! Droplet for GitHub user {0} is available at {0}.zulipdev.org.
|
COMPLETE! Droplet for GitHub user {0} is available at {0}.zulipdev.org.
|
||||||
@@ -242,41 +262,80 @@ Your remote Zulip dev server has been created!
|
|||||||
print("------")
|
print("------")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def print_production_droplet_instructions(droplet_domain_name: str) -> None:
|
||||||
# define id of image to create new droplets from
|
print(
|
||||||
# You can get this with something like the following. You may need to try other pages.
|
"""
|
||||||
# Broken in two to satisfy linter (line too long)
|
-----
|
||||||
# curl -X GET -H "Content-Type: application/json" -u <API_KEY>: "https://api.digitaloc
|
|
||||||
# ean.com/v2/images?page=5" | grep --color=always base.zulipdev.org
|
|
||||||
template_id = "63219191"
|
|
||||||
|
|
||||||
|
Production droplet created successfully!
|
||||||
|
|
||||||
|
Connect to the server by running
|
||||||
|
|
||||||
|
ssh root@{}
|
||||||
|
|
||||||
|
-----
|
||||||
|
""".format(
|
||||||
|
droplet_domain_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_zulip_oneclick_app_slug(api_token: str) -> str:
|
||||||
|
response = requests.get(
|
||||||
|
"https://api.digitalocean.com/v2/1-clicks", headers={"Authorization": f"Bearer {api_token}"}
|
||||||
|
).json()
|
||||||
|
one_clicks = response["1_clicks"]
|
||||||
|
|
||||||
|
for one_click in one_clicks:
|
||||||
|
if one_click["slug"].startswith("kandralabs"):
|
||||||
|
return one_click["slug"]
|
||||||
|
raise Exception("Unable to find Zulip One-click app slug")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
# get command line arguments
|
# get command line arguments
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
username = args.username.lower()
|
username = args.username.lower()
|
||||||
print(f"Creating Zulip developer environment for GitHub user {username}...")
|
|
||||||
|
|
||||||
subdomain = username
|
if args.production:
|
||||||
droplet_domain_name = f"{subdomain}.zulipdev.org"
|
print(f"Creating production droplet for GitHub user {username}...")
|
||||||
|
else:
|
||||||
|
print(f"Creating Zulip developer environment for GitHub user {username}...")
|
||||||
|
|
||||||
# get config details
|
# get config details
|
||||||
config = get_config()
|
config = get_config()
|
||||||
|
api_token = config["digitalocean"]["api_token"]
|
||||||
|
|
||||||
assert_github_user_exists(github_username=username)
|
assert_github_user_exists(github_username=username)
|
||||||
|
|
||||||
# grab user's public keys
|
# grab user's public keys
|
||||||
public_keys = get_keys(username=username)
|
public_keys = get_keys(username=username)
|
||||||
|
|
||||||
# now make sure the user has forked zulip/zulip
|
if args.production:
|
||||||
fork_exists(username=username)
|
subdomain = f"{username}-prod"
|
||||||
|
droplet_domain_name = f"{subdomain}.zulipdev.org"
|
||||||
|
template_id = get_zulip_oneclick_app_slug(api_token)
|
||||||
|
user_data = generate_prod_droplet_user_data(username=username, userkey_dicts=public_keys)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# now make sure the user has forked zulip/zulip
|
||||||
|
fork_exists(username=username)
|
||||||
|
|
||||||
|
subdomain = username
|
||||||
|
droplet_domain_name = f"{subdomain}.zulipdev.org"
|
||||||
|
user_data = generate_dev_droplet_user_data(username=username, userkey_dicts=public_keys)
|
||||||
|
|
||||||
|
# define id of image to create new droplets from
|
||||||
|
# You can get this with something like the following. You may need to try other pages.
|
||||||
|
# Broken in two to satisfy linter (line too long)
|
||||||
|
# curl -X GET -H "Content-Type: application/json" -u <API_KEY>: "https://api.digitaloc
|
||||||
|
# ean.com/v2/images?page=5" | grep --color=always base.zulipdev.org
|
||||||
|
template_id = "63219191"
|
||||||
|
|
||||||
api_token = config["digitalocean"]["api_token"]
|
|
||||||
assert_droplet_does_not_exist(
|
assert_droplet_does_not_exist(
|
||||||
my_token=api_token, droplet_name=droplet_domain_name, recreate=args.recreate
|
my_token=api_token, droplet_name=droplet_domain_name, recreate=args.recreate
|
||||||
)
|
)
|
||||||
|
|
||||||
# set user_data
|
|
||||||
user_data = set_user_data(username=username, userkey_dicts=public_keys)
|
|
||||||
|
|
||||||
# create droplet
|
# create droplet
|
||||||
ip_address = create_droplet(
|
ip_address = create_droplet(
|
||||||
my_token=api_token,
|
my_token=api_token,
|
||||||
@@ -288,6 +347,9 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
create_dns_record(my_token=api_token, record_name=subdomain, ip_address=ip_address)
|
create_dns_record(my_token=api_token, record_name=subdomain, ip_address=ip_address)
|
||||||
|
|
||||||
print_completion(droplet_domain_name=droplet_domain_name)
|
if args.production:
|
||||||
|
print_production_droplet_instructions(droplet_domain_name=droplet_domain_name)
|
||||||
|
else:
|
||||||
|
print_dev_droplet_instructions(droplet_domain_name=droplet_domain_name)
|
||||||
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user