Skip to content

Commit

Permalink
Merge branch 'main' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
patricksanders committed Oct 7, 2024
2 parents 72657c5 + db8746b commit 2dad4aa
Show file tree
Hide file tree
Showing 13 changed files with 333 additions and 109 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Run tests

on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install \
-r requirements.txt \
flake8 \
pytest \
.
- name: Lint
run: |
flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test
run: |
pytest --capture=sys --ignore=test/test_docker.py
43 changes: 23 additions & 20 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
name: Publish

on:
release:
types:
- published
push:
tags:
- '*'
branches:
- main
- main # publish pre-release packages on every push to main

jobs:
package:
Expand All @@ -20,7 +21,7 @@ jobs:
# probably be removed.
fetch-depth: 0
fetch-tags: true
- name: Set up Python ${{ matrix.python-version }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
Expand All @@ -36,22 +37,24 @@ jobs:
name: python-package-distributions
path: dist/

# pypi-publish:
# name: Upload release to PyPI
# runs-on: ubuntu-latest
# environment:
# name: release
# url: https://pypi.org/p/aardvark
# permissions:
# id-token: write
# steps:
# - name: Download all the dists
# uses: actions/download-artifact@v4
# with:
# name: python-package-distributions
# path: dist/
# - name: Publish package distributions to PyPI
# uses: pypa/gh-action-pypi-publish@release/v1
pypi-publish:
name: Upload release to PyPI
runs-on: ubuntu-latest
needs:
- package
environment:
name: release
url: https://pypi.org/p/aardvark
permissions:
id-token: write
steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

pypi-test-publish:
name: Upload release to TestPyPI
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Aardvark
Aardvark - Multi-Account AWS IAM Access Advisor API
========
[![NetflixOSS Lifecycle](https://img.shields.io/osslifecycle/Netflix/osstracker.svg)]()
[![Discord chat](https://img.shields.io/discord/754080763070382130?logo=discord)](https://discord.gg/9kwMWa6)
Expand Down
88 changes: 0 additions & 88 deletions aardvark/__init__.py
Original file line number Diff line number Diff line change
@@ -1,88 +0,0 @@
import logging
import os.path
from logging.config import dictConfig

from dynaconf.contrib import FlaskDynaconf
from flasgger import Swagger
from flask import Flask

from aardvark.advisors import advisor_bp
from aardvark.persistence.sqlalchemy import SQLAlchemyPersistence

BLUEPRINTS = [advisor_bp]

API_VERSION = "1"

log = logging.getLogger("aardvark")


def create_app(**kwargs):
init_logging()
app = Flask(__name__, static_url_path="/static")
Swagger(app)
persistence = SQLAlchemyPersistence()

FlaskDynaconf(app, **kwargs)

# For ELB and/or Eureka
@app.route("/healthcheck")
def healthcheck():
"""Healthcheck
Simple healthcheck that indicates the services is up
---
responses:
200:
description: service is up
"""
return "ok"

# Blueprints
for bp in BLUEPRINTS:
app.register_blueprint(bp, url_prefix=f"/api/{API_VERSION}")

# Extensions:
persistence.init_db()

return app


def init_logging():
log_cfg = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"standard": {"format": "%(asctime)s %(levelname)s: %(message)s " "[in %(pathname)s:%(lineno)d]"}
},
"handlers": {
"file": {
"class": "logging.handlers.RotatingFileHandler",
"level": "DEBUG",
"formatter": "standard",
"filename": "aardvark.log",
"maxBytes": 10485760,
"backupCount": 100,
"encoding": "utf8",
},
"console": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "standard",
"stream": "ext://sys.stdout",
},
},
"loggers": {"aardvark": {"handlers": ["file", "console"], "level": "DEBUG"}},
}
dictConfig(log_cfg)


def _find_config():
"""Search for config.py in order of preference and return path if it exists, else None"""
config_paths = [
os.path.join(os.getcwd(), "config.py"),
"/etc/aardvark/config.py",
"/apps/aardvark/config.py",
]
for path in config_paths:
if os.path.exists(path):
return path
return None
89 changes: 89 additions & 0 deletions aardvark/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from __future__ import annotations

import os.path
import logging
import sys
from logging import DEBUG, Formatter, StreamHandler
from logging.config import dictConfig
from typing import TYPE_CHECKING

from flask_sqlalchemy import SQLAlchemy
from flask import Flask
from flasgger import Swagger

if TYPE_CHECKING:
from flask import Config

db = SQLAlchemy()

from aardvark.view import mod as advisor_bp # noqa

BLUEPRINTS = [
advisor_bp
]

API_VERSION = "1"


def create_app(config_override: Config = None):
app = Flask(__name__, static_url_path="/static")
Swagger(app)

if config_override:
app.config.from_mapping(config_override)
else:
path = _find_config()
if not path:
print("No config")
app.config.from_pyfile("_config.py")
else:
app.config.from_pyfile(path)

# For ELB and/or Eureka
@app.route("/healthcheck")
def healthcheck():
"""Healthcheck
Simple healthcheck that indicates the services is up
---
responses:
200:
description: service is up
"""
return "ok"

# Blueprints
for bp in BLUEPRINTS:
app.register_blueprint(bp, url_prefix=f"/api/{API_VERSION}")

# Extensions:
db.init_app(app)
setup_logging(app)

return app


def _find_config():
"""Search for config.py in order of preference and return path if it exists, else None"""
config_paths = [
os.path.join(os.getcwd(), "config.py"),
"/etc/aardvark/config.py",
"/apps/aardvark/config.py",
]
for path in config_paths:
if os.path.exists(path):
return path
return None


def setup_logging(app):
if not app.debug:
if app.config.get("LOG_CFG"):
# initialize the Flask logger (removes all handlers)
dictConfig(app.config.get("LOG_CFG"))
app.logger = logging.getLogger(__name__)
else:
handler = StreamHandler(stream=sys.stderr)

handler.setFormatter(Formatter("%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]"))
app.logger.setLevel(app.config.get("LOG_LEVEL", DEBUG))
app.logger.addHandler(handler)
Empty file added aardvark/model.py
Empty file.
Empty file added aardvark/updater/__init__.py
Empty file.
1 change: 1 addition & 0 deletions aardvark/utils/sqla_regex.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""

# courtesy of Xion: http://xion.io/post/code/sqlalchemy-regex-filters.html

import re
import sqlite3

Expand Down
Empty file added aardvark/view.py
Empty file.
Empty file added requirements.txt
Empty file.
Empty file added setup.py
Empty file.
34 changes: 34 additions & 0 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import pytest
from flask_sqlalchemy import SQLAlchemy


@pytest.fixture(scope="function")
def app_config():
"""Return a Flask configuration object for testing. The returned configuration is intended to be a good base for
testing and can be customized for specific testing needs.
"""
from flask import Config
c = Config('.')
c.from_mapping({
"SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:",
"SQLALCHEMY_TRACK_MODIFICATIONS": False,
"DEBUG": False,
"LOG_CFG": {'version': 1, 'handlers': []}, # silence logging
})
return c


@pytest.fixture(scope="function")
def mock_database(app_config):
"""Yield an instance of flask_sqlalchemy.SQLAlchemy associated with the base model class used in aardvark.model.
This is almost certainly not safe for parallel/multi-threaded use.
"""
from aardvark.app import db
mock_db = SQLAlchemy(model_class=db.Model)

from aardvark.app import create_app
app = create_app(config_override=app_config)
with app.app_context():
mock_db.create_all()
yield mock_db
mock_db.drop_all()
Loading

0 comments on commit 2dad4aa

Please sign in to comment.