-
Notifications
You must be signed in to change notification settings - Fork 0
/
fabfile.py
219 lines (175 loc) · 6.5 KB
/
fabfile.py
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
from __future__ import print_function
import os
import sys
import time
from encryptedfiles.encryptedfile import EncryptedFile
from encryptedfiles.encryptedjson import EncryptedJson
from fabric.decorators import task
from fabric.colors import red, green, blue, yellow
from fabric.api import env, run, local, sudo, put
from fabric.context_managers import cd
import subprocess
import boto
import boto.ec2
import boto.rds
from config import Config
from jinja2 import Template
####
## AMAZON EC2
####
aws_cfg = Config(open("aws.cfg"))
@task
def localhost():
env.run = local
env.hosts = ["localhost"]
@task
def target(instance_name, user="ec2-user"):
"""
Sets the fab environment to the given instance_name.
This instance_name has to be the tag "Name" of the ec2 instance
we want to control.
Used like: fab target:django1 *some_other_command*.
"""
conn = connect_ec2()
reservations = conn.get_all_instances()
for res in reservations:
for inst in res.instances:
name = inst.tags["Name"]
if name == instance_name:
env.hosts = [inst.public_dns_name]
env.key_filename = os.path.expanduser(os.path.join(
aws_cfg["key_dir"], "{}.pem".format(inst.key_name)))
env.user = user
env.run = run
def connect_ec2():
return boto.ec2.connect_to_region(aws_cfg["region"],
aws_access_key_id=aws_cfg["aws_access_key_id"],
aws_secret_access_key=aws_cfg["aws_secret_access_key"])
## WEBAPP DEPLOYMENT
@task
def deploy_webapp_run(fresh=True):
deploy_webapp(fresh)
run_webapp_container()
@task
def deploy_webapp(fresh=True):
handle_prerequisites(fresh)
with cd("djagolb"):
put("src/djagolb/config/keys/*", "src/djagolb/config/keys/")
env.run("sudo docker build -t djagolb_appserver_deploy .")
print(green("Succesfully deployed the djagolb appserver. "
"Feel free to run 'fab run_webapp_container' ;)."))
def handle_prerequisites(fresh):
if fresh:
env.run("sudo yum install git")
env.run("sudo yum install -y docker ; sudo service docker start") # https://docs.docker.com/installation/amazon/
env.run("rm -rf djagolb")
env.run("git clone https://github.com/Skabed/djagolb djagolb")
@task
def run_webapp_container():
docker_ps = env.run("sudo docker ps -a")
if "djagolb_appserver_running" in docker_ps:
env.run("sudo docker rm -f djagolb_appserver_running")
env.run("sudo docker run --name djagolb_appserver_running -p 80:80 djagolb_appserver_deploy")
@task
def stop_webapp_container():
env.run("sudo docker stop djagolb_appserver_running")
## DATABASE DEPLOYMENT
@task
def deploy_db_run(fresh=True):
deploy_db(fresh)
run_db_container()
@task
def deploy_db(fresh=True):
handle_prerequisites(fresh)
with cd("djagolb"):
put("src/djagolb/config/keys/*", "src/djagolb/config/keys/")
env.run("bash init.sh")
env.run("bin/fab build_db_dockerfile")
print(green("Succesfully deployed the djagolb database. "
"Feel free to run 'fab run_db_container' ;)."))
@task
def build_db_dockerfile():
dockerfile_template = Template(open(".server_config/db/psql_dockerfile.template").read())
db_settings = get_enc_json("prod_db.json")
try:
with open(".server_config/db/psql_dockerfile", "w") as psql_dockerfile:
psql_dockerfile.write(dockerfile_template.render(
db_user = db_settings["database"]["USER"],
db_password = db_settings["database"]["PASSWORD"],
db_name = db_settings["database"]["NAME"]))
env.run("sudo docker build -t djagolb_db_deploy - < .server_config/db/psql_dockerfile")
finally:
os.remove(".server_config/db/psql_dockerfile")
@task
def run_db_container():
docker_ps = env.run("sudo docker ps -a")
if "djagolb_db_running" in docker_ps:
env.run("sudo docker rm -f djagolb_db_running")
env.run("sudo docker run --name djagolb_db_running -p 80:80 djagolb_db_deploy")
@task
def stop_db_container():
env.run("sudo docker stop djagolb_db_running")
####
## AMAZON RDS
####
@task
def create_rds_instance(database_id,
allocated_storage=5,
instance_class="db.t2.micro"):
db_settings = get_enc_json("prod_db.json")
conn = connect_rds()
db = conn.create_dbinstance(
id=database_id,
allocated_storage=allocated_storage,
instance_class=instance_class,
master_username=db_settings["database"]["USER"],
master_password=db_settings["database"]["PASSWORD"],
db_name=db_settings["database"]["NAME"],
engine="postgres",
port=5432,
)
print("Waiting for db to be available:", end="")
time_waited = 0
while db.status.lower().strip() != "available":
time.sleep(1)
time_waited += 1
print(".", end="")
if time_waited % 30 == 0:
print("\nDB status: {} (waited for {} seconds)."\
.format(db.status.lower(), time_waited), end="")
sys.stdout.flush()
db.update()
print(green("\nSuccessfully created db instance."))
print(green("DB Endpoint: {}".format(db.endpoint)))
print(yellow("Remember to manually set the security group."))
def connect_rds():
conn = boto.rds.connect_to_region(
aws_cfg["region"],
aws_access_key_id=aws_cfg["aws_access_key_id"],
aws_secret_access_key=aws_cfg["aws_secret_access_key"])
return conn
####
## Utils
####
BASE_CONFIG = os.path.join("src", "djagolb", "config")
CONFIG_DIRNAME = os.path.join(BASE_CONFIG, "plain")
ENCRYPTED_DIRNAME = os.path.join(BASE_CONFIG, "encrypted")
KEYS_DIR = os.path.join(BASE_CONFIG, "keys")
def get_enc_file(filename):
return EncryptedFile(os.path.join(ENCRYPTED_DIRNAME, filename), get_key())
def get_enc_json(filename):
return EncryptedJson(os.path.join(ENCRYPTED_DIRNAME, filename), get_key())
@task
def encrypt_config():
cfg_filenames = [f for f in os.listdir(CONFIG_DIRNAME)
if os.path.isfile(os.path.join(CONFIG_DIRNAME, f))]
for filename in cfg_filenames:
if ".gitignore" in filename:
continue
with open(os.path.join(CONFIG_DIRNAME, filename), "r") as cfg_file:
enc_file = EncryptedFile(os.path.join(ENCRYPTED_DIRNAME, filename),
get_key())
enc_file.write(cfg_file.read())
def get_key():
with open(os.path.join(KEYS_DIR, "cfg_key.key"), "r") as cfg_key_file:
return cfg_key_file.read()