Skip to content

Commit

Permalink
fix non-idempotent Auth@Edge function deploys (#464)
Browse files Browse the repository at this point in the history
pyrsa/pyjwt create scripts with a shebang specific to the build system.
Removing them, and setuptools remnants containing various hash values,
stops new functions from being built on different systems.

It's possible the `PYTHONDONTWRITEBYTECODE` option is safe to apply
unconditionally to all function builds by default, but I'm not 100%
certain of the implications of that so I've gated it to an explicit
option for now.

All of the new options have been intentionally left off the docs for
this first pass where we may revise the names.
  • Loading branch information
troyready committed Sep 25, 2020
1 parent ef66c37 commit b40fc97
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Fixed
- Static Site Auth@Edge: fix non-idempotent deploys when deploying from different systems

## [1.14.0] - 2020-09-23
### Changed
Expand Down
23 changes: 22 additions & 1 deletion runway/cfngin/hooks/aws_lambda.py
Expand Up @@ -3,6 +3,7 @@
import json
import logging
import os
import shutil
import stat
import subprocess
import sys
Expand Down Expand Up @@ -455,12 +456,17 @@ def dockerized_pip(

LOGGER.info('using docker image "%s" to build deployment package...', docker_image)

docker_run_args = {}
if _kwargs.get("python_dontwritebytecode"):
docker_run_args["environment"] = "1"

container = client.containers.run(
image=docker_image,
command=["/bin/sh", "-c", pip_cmd],
auto_remove=True,
detach=True,
mounts=[work_dir_mount],
**docker_run_args
)

# 'stream' creates a blocking generator that allows for real-time logs.
Expand Down Expand Up @@ -582,6 +588,10 @@ def _zip_package(
"--no-color",
]

subprocess_args = {}
if kwargs.get("python_dontwritebytecode"):
subprocess_args["env"] = dict(os.environ, PYTHONDONTWRITEBYTECODE="1")

# Pyinstaller build or explicit python path
if getattr(sys, "frozen", False) and not python_path:
script_contents = os.linesep.join(
Expand Down Expand Up @@ -612,13 +622,24 @@ def _zip_package(
)

try:
subprocess.check_call(cmd)
subprocess.check_call(cmd, **subprocess_args)
except subprocess.CalledProcessError:
raise PipError
finally:
if tmp_script.is_file():
tmp_script.unlink()

if kwargs.get("python_exclude_bin_dir") and os.path.isdir(
os.path.join(tmpdir, "bin")
):
LOGGER.debug("Removing python /bin directory from Lambda files")
shutil.rmtree(os.path.join(tmpdir, "bin"))
if kwargs.get("python_exclude_setuptools_dirs"):
for i in os.listdir(tmpdir):
if i.endswith(".egg-info") or i.endswith(".dist-info"):
LOGGER.debug("Removing directory %s from Lambda files", i)
shutil.rmtree(os.path.join(tmpdir, i))

req_files = _find_files(tmpdir, includes="**", follow_symlinks=False)
return _zip_files(req_files, tmpdir)

Expand Down
9 changes: 8 additions & 1 deletion runway/hooks/staticsite/auth_at_edge/lambda_config.py
Expand Up @@ -112,7 +112,14 @@ def write(
context,
provider,
bucket=kwargs["bucket"],
functions={handler: {"path": dirpath}},
functions={
handler: {
"path": dirpath,
"python_dontwritebytecode": True,
"python_exclude_bin_dir": True,
"python_exclude_setuptools_dirs": True,
}
},
)

# Add the lambda code reference to our context_dict
Expand Down

0 comments on commit b40fc97

Please sign in to comment.