-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
VENV_BIN = python3 -m venv | ||
VENV_DIR ?= .venv | ||
VENV_ACTIVATE = $(VENV_DIR)/bin/activate | ||
VENV_RUN = . $(VENV_ACTIVATE) | ||
|
||
venv: $(VENV_ACTIVATE) | ||
|
||
$(VENV_ACTIVATE): setup.py setup.cfg | ||
test -d .venv || $(VENV_BIN) .venv | ||
$(VENV_RUN); pip install --upgrade pip setuptools plux build | ||
$(VENV_RUN); pip install --upgrade black isort | ||
$(VENV_RUN); pip install -e . | ||
touch $(VENV_DIR)/bin/activate | ||
|
||
clean: | ||
rm -rf .venv/ | ||
rm -rf build/ | ||
rm -rf .eggs/ | ||
rm -rf *.egg-info/ | ||
|
||
install: venv | ||
$(VENV_RUN); python setup.py develop | ||
|
||
format: venv | ||
$(VENV_RUN); python -m isort .; python -m black . | ||
|
||
dist: venv | ||
$(VENV_RUN); python -m build | ||
|
||
publish: clean-dist venv dist | ||
$(VENV_RUN); pip install --upgrade twine; twine upload dist/* | ||
|
||
clean-dist: clean | ||
rm -rf dist/ | ||
|
||
.PHONY: clean clean-dist dist install publish |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
Use Terraform files in LocalStack init hooks | ||
============================================ | ||
|
||
LocalStack Extension for using Terraform files in [init hooks](https://docs.localstack.cloud/references/init-hooks/). | ||
|
||
> [!WARNING] | ||
> This extension is experimental and subject to change. | ||
> [!NOTE] | ||
> The extension is designed for simple self-contained terraform files, not complex projects or modules. | ||
> If you have larger projects, then we recommend running them from the host. | ||
## Usage | ||
|
||
* Start localstack with `EXTENSION_AUTO_INSTALL="localstack-extension-terraform-init"` | ||
* Mount a `main.tf` file into `/etc/localstack/init/ready.d` | ||
|
||
When LocalStack starts up, it will install the extension, which in turn install `terraform` and `tflocal` into the container. | ||
If one of the init stage directories contain a `main.tf`, the extension will run `tflocal init` and `tflocal apply` on that directory. | ||
|
||
> [!NOTE] | ||
> Terraform state files will be created in your host directory if you mounted an entire folder into `/etc/localstack/init/ready.d`. | ||
> These files are created from within the container using the container user, so you may need `sudo` to remove the files from your host. | ||
> If you only mount the `main.tf` file, not an entire directory, localstack will have to download the AWS terraform provider every time during `tflocal init`. | ||
> | ||
### Example | ||
|
||
Example `main.tf`: | ||
```hcl | ||
resource "aws_s3_bucket" "example" { | ||
bucket = "my-tf-test-bucket" | ||
tags = { | ||
Name = "My bucket" | ||
Environment = "Dev" | ||
} | ||
} | ||
``` | ||
|
||
Start LocalStack Pro with mounted `main.tf`: | ||
|
||
```console | ||
localstack start \ | ||
-e EXTENSION_AUTO_INSTALL="localstack-extension-terraform-init" \ | ||
-v ./main.tf:/etc/localstack/init/ready.d/main.tf | ||
``` | ||
|
||
Or, if you use a docker-compose file: | ||
|
||
```yaml | ||
services: | ||
localstack: | ||
container_name: "localstack-main" | ||
image: localstack/localstack-pro # required for Pro | ||
ports: | ||
- "127.0.0.1:4566:4566" # LocalStack Gateway | ||
environment: | ||
# Activate LocalStack Pro: https://docs.localstack.cloud/getting-started/auth-token/ | ||
- LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN:?} | ||
- EXTENSION_AUTO_LOAD=localstack-extension-terraform-init" | ||
volumes: | ||
# you could also place your main.tf in `./ready.d` and set "./ready.d:/etc/localstack/init/ready.d" | ||
- "./main.tf:/etc/localstack/init/ready.d/main.tf" | ||
- "./volume:/var/lib/localstack" | ||
- "/var/run/docker.sock:/var/run/docker.sock" | ||
``` | ||
In a new terminal window, you can wait for localstack to complete and then print the created s3 buckets. | ||
```console | ||
localstack wait && awslocal s3 ls | ||
``` | ||
|
||
The logs should show something like: | ||
|
||
``` | ||
2024-06-26T20:36:19.946 INFO --- [ady_monitor)] l.extension : Applying terraform project from file /etc/localstack/init/ready.d/main.tf | ||
2024-06-26T20:36:19.946 DEBUG --- [ady_monitor)] localstack.utils.run : Executing command: ['tflocal', '-chdir=/etc/localstack/init/ready.d', 'init', '-input=false'] | ||
2024-06-26T20:36:26.864 DEBUG --- [ady_monitor)] localstack.utils.run : Executing command: ['tflocal', '-chdir=/etc/localstack/init/ready.d', 'apply', '-auto-approve'] | ||
``` | ||
|
||
## Install local development version | ||
|
||
To install the extension into localstack in developer mode, you will need Python 3.10, and create a virtual environment in the extensions project. | ||
|
||
In the newly generated project, simply run | ||
|
||
```bash | ||
make install | ||
``` | ||
|
||
Then, to enable the extension for LocalStack, run | ||
|
||
```bash | ||
localstack extensions dev enable . | ||
``` | ||
|
||
You can then start LocalStack with `EXTENSION_DEV_MODE=1` to load all enabled extensions: | ||
|
||
```bash | ||
EXTENSION_DEV_MODE=1 localstack start | ||
``` | ||
|
||
## Install from GitHub repository | ||
|
||
To distribute your extension, simply upload it to your github account. Your extension can then be installed via: | ||
|
||
```bash | ||
localstack extensions install "git+https://github.com/localstack/localstack-extensions/#egg=localstack-extension-terraform-init&subdirectory=terraform-init" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
name = "localstack_terraform_init" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import logging | ||
import os | ||
from typing import List | ||
|
||
from localstack import config | ||
from localstack.extensions.api import Extension | ||
from localstack.packages import InstallTarget, Package, PackageInstaller | ||
from localstack.packages.core import PythonPackageInstaller | ||
from localstack.packages.terraform import terraform_package | ||
from localstack.runtime.init import ScriptRunner | ||
from localstack.utils.run import run | ||
|
||
LOG = logging.getLogger(__name__) | ||
|
||
|
||
class TflocalInitExtension(Extension): | ||
# the extension itself is just used for discoverability | ||
name = "localstack-terraform-init" | ||
|
||
def on_extension_load(self): | ||
logging.getLogger("localstack_terraform_init").setLevel( | ||
logging.DEBUG if config.DEBUG else logging.INFO | ||
) | ||
|
||
|
||
class TflocalPackage(Package): | ||
def __init__(self, default_version: str = "0.18.2"): | ||
super().__init__(name="terraform_local", default_version=default_version) | ||
|
||
def _get_installer(self, version: str) -> PackageInstaller: | ||
return TflocalPackageInstaller(version) | ||
|
||
def get_versions(self) -> List[str]: | ||
return [self.default_version] | ||
|
||
|
||
class TflocalPackageInstaller(PythonPackageInstaller): | ||
def __init__(self, version: str): | ||
super().__init__("terraform_local", version) | ||
|
||
|
||
tflocal_package = TflocalPackage() | ||
|
||
|
||
class TflocalScriptRunner(ScriptRunner): | ||
name = "tflocal" | ||
|
||
def load(self, *args, **kwargs): | ||
terraform_package.install() | ||
tflocal_package.install() | ||
|
||
def should_run(self, script_file: str) -> bool: | ||
if os.path.basename(script_file) == "main.tf": | ||
return True | ||
return False | ||
|
||
def run(self, path: str) -> None: | ||
# create path to find ``terraform`` and ``tflocal`` binaries | ||
# TODO: better way to define path | ||
tf_path = terraform_package.get_installed_dir() | ||
install_dir = tflocal_package.get_installer()._get_install_dir( | ||
InstallTarget.VAR_LIBS | ||
) | ||
tflocal_path = f"{install_dir}/bin" | ||
env_path = f"{tflocal_path}:{tf_path}:{os.getenv('PATH')}" | ||
|
||
LOG.info("Applying terraform project from file %s", path) | ||
# run tflocal | ||
workdir = os.path.dirname(path) | ||
LOG.debug("Initializing terraform provider in %s", workdir) | ||
run( | ||
["tflocal", f"-chdir={workdir}", "init", "-input=false"], | ||
env_vars={"PATH": env_path}, | ||
) | ||
LOG.debug("Applying terraform file %s", path) | ||
run( | ||
["tflocal", f"-chdir={workdir}", "apply", "-auto-approve"], | ||
env_vars={"PATH": env_path}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[metadata] | ||
name = localstack-extension-terraform-init | ||
version = 0.2.0 | ||
summary = LocalStack Extension: LocalStack Terraform Init | ||
url = https://github.com/localstack/localstack-extensions/tree/main/terraform-init | ||
author = Thomas Rausch | ||
author_email = thomas@localstack.cloud | ||
description = LocalStack Extension for using Terraform files in init hooks | ||
long_description = file: README.md | ||
long_description_content_type = text/markdown; charset=UTF-8 | ||
|
||
[options] | ||
zip_safe = False | ||
packages = find: | ||
install_requires = | ||
localstack-core>=3.4 | ||
plux | ||
|
||
[options.entry_points] | ||
localstack.extensions = | ||
localstack-terraform-init = localstack_terraform_init.extension:TflocalInitExtension | ||
localstack.init.runner= | ||
tflocal = localstack_terraform_init.extension:TflocalScriptRunner |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env python | ||
from setuptools import setup | ||
|
||
setup() |