Skip to content

Commit

Permalink
Set new feature for deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
dbagan13 committed Oct 25, 2023
1 parent 647d4ad commit a7b1f00
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 7 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.3.0] - 2023-10-25
### Added
- Add support for interpolating environment variables to tentaclio secrets file.

## [1.2.2] - 2023-10-18
### Added
- Add support for connecting to SFTP via private key authentication. Replaces pysftp dependency with paramiko.
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,14 @@ And make it accessible to tentaclio by setting the environmental variable `TENTA
Alternatively you can run `curl https://raw.githubusercontent.com/octoenergy/tentaclio/master/extras/init_tentaclio.sh` to create a secrets file in `~/.tentaclio.yml` and
automatically configure your environment.

Environment variables can be included in the credentials file by using `${ENV_VARIABLE}` as it follows:
```
secrets:
db: postgresql://${DB_USER}:${DB_PASS}@myhost.com/database
```
Tentaclio will search `DB_USER` and `DB_PASS` in the environment and will interpolate their values with the secrets file content.


## Quick note on protocols structural subtyping.

In order to abstract concrete dependencies from the implementation of data related functions (or in any part of the system really) we use typed [protocols](https://mypy.readthedocs.io/en/latest/protocols.html#simple-user-defined-protocols). This allows a more flexible dependency injection than using subclassing or [more complex approches](http://code.activestate.com/recipes/413268/). This idea is heavily inspired by how this exact thing is done in [go](https://www.youtube.com/watch?v=ifBUfIb7kdo). Learn more about this principle in our [tech blog](https://tech.octopus.energy/news/2019/03/21/python-interfaces-a-la-go.html).
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from setuptools.command.install import install


VERSION = "1.2.2"
VERSION = "1.3.0"

REPO_ROOT = pathlib.Path(__file__).parent

Expand Down
12 changes: 6 additions & 6 deletions src/tentaclio/credentials/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

SECRETS = "secrets"
TENTACLIO_SECRETS_FILE = "TENTACLIO__SECRETS_FILE"
ENV_VARIABLE_PATTERN = r"\${[a-zA-Z_]+[a-zA-Z0-9_]*}"
ENV_VARIABLE_PATTERN = re.compile(r"\${[a-zA-Z_]+[a-zA-Z0-9_]*}")
NOT_VALID_ENV_VARIABLE_VALUES = "[${}]"


Expand Down Expand Up @@ -90,19 +90,19 @@ def _load_from_file(
raise TentaclioFileError("File not found") from e


def replace_env_variables(url: str) -> str:
def _replace_env_variables(url: str) -> str:
"""Replace the environment variables inside the url by its value in the environment.
Environment variables match the following format: ${ENV_VARIABLE_NAME}
"""
pattern = re.compile(ENV_VARIABLE_PATTERN)
env_variables = re.findall(pattern, url)
env_variables = re.findall(ENV_VARIABLE_PATTERN, url)
for env_variable in env_variables:
env_variable_name = re.sub(NOT_VALID_ENV_VARIABLE_VALUES, "", env_variable)
env_value = os.getenv(env_variable_name)
if not env_value:
raise EnvironmentError(
f"Error while reading variable '{env_variable_name}' from the environment. "
f"Error while reading variable '{env_variable_name}' from the environment "
f"when interpolating it from the secrets file. "
f"Check that the variable exists in your environment."
)
url = url.replace(env_variable, env_value)
Expand All @@ -123,7 +123,7 @@ def add_credentials_from_reader(
creds = _load_creds_from_yaml(yaml_reader)
for name, url in creds.items():
logger.info(f"Adding secret: {name}")
url = replace_env_variables(url)
url = _replace_env_variables(url)
try:
injector.register_credentials(urls.URL(url))
except Exception as e:
Expand Down

0 comments on commit a7b1f00

Please sign in to comment.