Skip to content

Commit

Permalink
Merge pull request #11 from william-cass-wright/eighth
Browse files Browse the repository at this point in the history
logger fix and config endpoints
  • Loading branch information
will-wright-eng committed Jun 23, 2022
2 parents d330422 + 21a5205 commit 0fa3396
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 73 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,8 @@ To run the tests:
```bash
pytest
```

## References
- heavily based on [secretsmanager_basics.py][1]

[1]: https://docs.aws.amazon.com/code-samples/latest/catalog/python-secretsmanager-secretsmanager_basics.py.html
66 changes: 66 additions & 0 deletions scripts/scripts_for_config_write.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html
# aws = AwsSecretMgmt()
# secret_name = "test/test_secret"
# secret = aws.get_secret(secret_name)
# secret_name = 'test/test_secret_2'
# secret_string = json.dumps(secret)
# aws.create_secret(secret_string,secret_name)
## write aws secrets to local
"""

from .aws import AwsSecretMgmt
from .config import ConfigHandler


aws = AwsSecretMgmt()


def write_secret_to_local_config(project_name):
config = ConfigHandler(project_name)
secrets_prefix = "projects/dev"
secret = aws.get_secret(os.path.join(secrets_prefix, project_name))
config.write_config_file_from_dict(config_dict=secret)
return config.print_configs()


# for project_name in projects:
# write_secret_to_local_config(project_name)


def find_all(name, path):
result = []
for root, dirs, files in os.walk(path):
if name in files:
result.append(os.path.join(root, name))
return result


def create_res_dict_from_envrc():
files = find_all(".envrc", "../.")
projects = ["media_mgmt_cli", "twl_app"]
res = {}
for file_path, project_name in zip(files, projects):
tmp_res = {}
with open(file_path, "r") as file:
tmp_lines = file.readlines()
for pos, line in enumerate(tmp_lines):
tmp_var = line.replace("\n", "").replace("export ", "").split("=")
if "KEY" in tmp_var[0]:
pass
else:
tmp_res[tmp_var[0]] = tmp_var[1]
res[project_name] = tmp_res
return res


def create_secret_from_dict(project_name, secrets_dict):
secrets_prefix = "projects/dev"
secret_name = os.path.join(secrets_prefix, project_name)
secret_string = json.dumps(secrets_dict)
return aws.create_secret(secret_string, secret_name)
31 changes: 0 additions & 31 deletions scripts/write_secret_to_config.py

This file was deleted.

39 changes: 37 additions & 2 deletions secrets_mgmt_cli/aws.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import os
import json
import time
import base64
import pathlib
import logging
import configparser

import boto3
from botocore.exceptions import ClientError

import time
import logging
logger = logging.getLogger(__name__)


def get_default_region() -> str:
Expand Down Expand Up @@ -222,5 +223,39 @@ def list(self, max_results):
def get_secrets_list(self):
return self.client.list_secrets()

def get_secret(self, secret_name):
# See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
try:
get_secret_value_response = self.client.get_secret_value(SecretId=secret_name)
except ClientError as e:
if e.response["Error"]["Code"] == "DecryptionFailureException":
# Secrets Manager can't decrypt the protected secret text using the provided KMS key.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
elif e.response["Error"]["Code"] == "InternalServiceErrorException":
# An error occurred on the server side.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
elif e.response["Error"]["Code"] == "InvalidParameterException":
# You provided an invalid value for a parameter.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
elif e.response["Error"]["Code"] == "InvalidRequestException":
# You provided a parameter value that is not valid for the current state of the resource.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
elif e.response["Error"]["Code"] == "ResourceNotFoundException":
# We can't find the resource that you asked for.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
else:
# Decrypts secret using the associated KMS key.
# Depending on whether the secret is a string or binary, one of these fields will be populated.
if "SecretString" in get_secret_value_response:
secret = get_secret_value_response["SecretString"]
return json.loads(secret)
else:
decoded_binary_secret = base64.b64decode(get_secret_value_response["SecretBinary"])


aws = AwsSecretMgmt()
30 changes: 25 additions & 5 deletions secrets_mgmt_cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import os
import json
import datetime

import click

from .aws import aws
from .config import ConfigHandler, config_handler


class DateTimeEncoder(json.JSONEncoder):
Expand All @@ -27,12 +29,16 @@ def cli():


@cli.command()
def ls():
@click.option("--config", is_flag=True)
def ls(config):
"list secrets in AWS Secrets Manager"
resp = aws.get_secrets_list()
for secret in resp.get("SecretList"):
click.echo(f"\n-- {secret.get('Name')} --")
echo_dict(secret)
if config:
config_handler.list_config_dirs()
else:
resp = aws.get_secrets_list()
for secret in resp.get("SecretList"):
click.echo(f"\n-- {secret.get('Name')} --")
echo_dict(secret)


@cli.command()
Expand Down Expand Up @@ -82,9 +88,23 @@ def search(key_word):
echo_dict(secret)


@cli.command()
@click.option("-n", "--secret-name", "secret_name", required=False, default=None)
@click.option("-p", "--project-name", "project_name", required=True)
def transfer(secret_name, project_name):
config = ConfigHandler(project_name)
if secret_name is None:
secrets_prefix = "projects/dev"
secret_name = os.path.join(secrets_prefix, project_name)
secret = aws.get_secret(secret_name=secret_name)
config.write_config_file_from_dict(config_dict=secret)
return config.print_configs()


cli.add_command(ls)
cli.add_command(create)
cli.add_command(read)
cli.add_command(update)
cli.add_command(delete)
cli.add_command(search)
cli.add_command(transfer)
95 changes: 95 additions & 0 deletions secrets_mgmt_cli/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import os
import pathlib
import configparser


class ConfigHandler:
def __init__(self, project_name="tmp"):
p = pathlib.Path.home()
self.home_path = p
self.config_path = p / ".config" / project_name
self.config_file_path = self.config_path / "config"

self.config = configparser.ConfigParser()
if os.path.isfile(self.config_file_path):
self.config.read(self.config_file_path)
print("-- config file exists --")
print(self.print_configs())

def export_configs(self):
# export configs as environment variables
for key, val in self.config.defaults().items():
if key is not None:
os.environ[key.upper()] = val

def print_configs(self):
# print('print configs')
print(self.config.defaults())
# self.config.read_file(
for key, val in self.config.defaults().items():
# if key is not None:
# print(key.upper(),(20-int(len(key)))*' ', val)
self.formatted_print(key, val)

def write_config_file(self):
# rewrite config file
with open(self.config_file_path, "w") as configfile:
self.config.write(configfile)

def create_file_and_dir(self):
self.config_path.mkdir(parents=True, exist_ok=True)
self.config_file_path.touch()

def config_file_input(self, config_dict: dict, section: str = "DEFAULT"):
"""
example:
config['DEFAULT'] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '8',}
"""
self.config[section] = config_dict

def write_config_file_from_dict(self, config_dict: dict):
self.config_file_input(config_dict)
self.write_config_file()

def put_project(self, project_name):
self.project_name = project_name
self.config_path = self.home_path / ".config" / project_name
self.config_file_path = self.config_path / "config"
self.config = configparser.ConfigParser()
if os.path.isfile(self.config_file_path):
self.config.read(self.config_file_path)
print("-- config file exists --")
print(self.print_configs())

def list_config_dirs(self):
# list directories
p = self.home_path / ".config"
active = []
other = []
for x in p.iterdir():
if x.is_dir():
tmp = x / "config"
if os.path.isfile(tmp):
active.append(tmp.resolve())
resp = "config file exists"
else:
other.append(x.resolve())
resp = "no config file"
self.formatted_print(x, resp, n=45)

for file_path in active:
print("\n-- ", file_path, " --")
tmp = configparser.ConfigParser()
tmp.read(file_path)
for key, val in tmp.defaults().items():
self.formatted_print(key, val)

def formatted_print(self, key, val, n=20):
key = str(key)
val = str(val)
print(key, (n - int(len(key))) * ".", val)


config_handler = ConfigHandler()
11 changes: 3 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from setuptools import setup
import os

VERSION = "0.4.2"
VERSION = "0.4.3"


def get_long_description():
Expand Down Expand Up @@ -31,12 +31,7 @@ def get_long_description():
[console_scripts]
smgmt=secrets_mgmt_cli.cli:cli
""",
install_requires=[
"click",
"boto3"
],
extras_require={
"test": ["pytest"]
},
install_requires=["click", "boto3"],
extras_require={"test": ["pytest"]},
python_requires=">=3.7",
)
Loading

0 comments on commit 0fa3396

Please sign in to comment.