testing/vcttesting/deploy.py (121 lines of code) (raw):
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import, unicode_literals
import io
import json
import logging
import os
from pipes import quote
import shutil
import subprocess
import tempfile
import zipfile
import boto3
from .vctutil import (
decrypt_sops_files,
get_and_write_vct_node,
)
HERE = os.path.abspath(os.path.dirname(__file__))
ROOT = os.path.normpath(os.path.join(HERE, "..", ".."))
ANSIBLE = os.path.join(ROOT, "ansible")
logger = logging.getLogger(__name__)
def run_playbook(name, extra_vars=None, verbosity=0):
get_and_write_vct_node()
extra_vars = extra_vars or {}
args = [
"ansible-playbook",
"-i",
os.path.join(ANSIBLE, "hosts"),
"-f",
"20",
"%s.yml" % name,
"--extra-vars",
json.dumps(extra_vars),
]
if verbosity:
args.append("-%s" % ("v" * verbosity))
logger.info("$ %s" % " ".join([quote(a) for a in args]))
return subprocess.call(args, cwd=ANSIBLE)
def deploy_hgmo(
skip_hgssh=False,
skip_hgweb=False,
skip_mirrors=False,
skip_kafka=False,
clean_wdir=False,
verbosity=0,
):
"""Deploy to hg.mozilla.org."""
decrypt_sops_files()
extra = {
"skip_kafka": skip_kafka,
"skip_mirrors": skip_mirrors,
"skip_hgssh": skip_hgssh,
"skip_hgweb": skip_hgweb,
"vct": ROOT,
}
res = run_playbook("deploy-hgmo", extra_vars=extra, verbosity=verbosity)
if clean_wdir:
# Wipe away encrypted secrets
subprocess.check_output(["hg", "-R", ROOT, "update", "--clean", "-r", "."])
return res
def hgmo_strip(repo, rev, verbosity=0):
extra = {
"repo": repo,
"rev": rev,
}
return run_playbook("hgmo-strip-repo", extra_vars=extra, verbosity=verbosity)
def hgmo_reclone_repos(repos, verbosity=0):
extra = {"repos": repos}
return run_playbook("hgmo-reclone-repos", extra_vars=extra, verbosity=verbosity)
def github_lambda_deploy_package():
"""Obtain a .zip file for a deployment package for GitHub Lambda foo."""
d = tempfile.mkdtemp()
PIP = os.path.join(ROOT, "venv", "bin", "pip")
try:
# Install Python packages.
subprocess.check_call(
[
PIP,
"install",
"-t",
d,
"-r",
os.path.join(ROOT, "github-webhooks", "lambda-requirements.txt"),
"--require-hashes",
]
)
# Copy relevant files from the source directory.
for p in os.listdir(os.path.join(ROOT, "github-webhooks")):
if not p.endswith(".py"):
continue
shutil.copyfile(
os.path.join(ROOT, "github-webhooks", p), os.path.join(d, p)
)
# Now make a zip file.
zf = io.BytesIO()
with zipfile.ZipFile(zf, "w") as z:
for root, dirs, files in os.walk(d):
for f in sorted(files):
full = os.path.join(root, f)
rel = os.path.relpath(full, d)
z.write(full, rel)
return zf.getvalue()
finally:
shutil.rmtree(d)
def github_webhook_lambda():
"""Deploys code for GitHub WebHook processing in AWS Lambda."""
zip_content = github_lambda_deploy_package()
S3_BUCKET = "moz-github-webhooks"
S3_KEY = "github_lambda.zip"
# The code package is shared. So upload to S3 and reference it there.
s3 = boto3.client("s3")
s3.put_object(
Bucket=S3_BUCKET,
Key=S3_KEY,
Body=zip_content,
ContentType="application/zip",
)
client = boto3.client("lambda", region_name="us-west-2")
for fn in ("github-webhooks-receive", "github-webhooks-pulse"):
res = client.update_function_code(
FunctionName=fn,
S3Bucket=S3_BUCKET,
S3Key=S3_KEY,
Publish=True,
)
# Lambda versions code/functions by default. So delete old versions
# as part of upload so old versions don't pile up.
for v in client.list_versions_by_function(FunctionName=fn)["Versions"]:
if v["Version"] in (res["Version"], "$LATEST"):
continue
client.delete_function(
FunctionName=v["FunctionArn"], Qualifier=v["Version"]
)