add usage API

Change-Id: Id6a688192277f9a58b13ca45d2596d375c5c187d
This commit is contained in:
Mohammed Naser 2020-09-04 15:21:49 -04:00
parent d5f060ad09
commit 84bc653862
10 changed files with 145 additions and 19 deletions

View File

@ -7,6 +7,9 @@
- context: . - context: .
repository: vexxhost/atmosphere-ingress repository: vexxhost/atmosphere-ingress
target: atmosphere-ingress target: atmosphere-ingress
- context: .
repository: vexxhost/atmosphere-usage
target: atmosphere-usage
- job: - job:
name: atmosphere:image:upload name: atmosphere:image:upload

View File

@ -27,3 +27,6 @@ ENV FLASK_APP=atmosphere.app \
FROM atmosphere AS atmosphere-ingress FROM atmosphere AS atmosphere-ingress
ENV UWSGI_WSGI_FILE=/usr/local/bin/atmosphere-ingress-wsgi ENV UWSGI_WSGI_FILE=/usr/local/bin/atmosphere-ingress-wsgi
FROM atmosphere AS atmosphere-usage
ENV UWSGI_WSGI_FILE=/usr/local/bin/atmosphere-usage-wsgi

62
atmosphere/api/usage.py Normal file
View File

@ -0,0 +1,62 @@
# Copyright 2020 VEXXHOST, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Usage API."""
from datetime import datetime
from flask import abort
from flask import Blueprint
from flask import request
from flask import jsonify
from keystonemiddleware import auth_token
from oslo_config import cfg
from atmosphere.app import create_app
from atmosphere import models
CONF = cfg.CONF
blueprint = Blueprint('usage', __name__)
def init_application(config=None):
"""Create usage API application."""
app = create_app(config)
app.register_blueprint(blueprint)
cfg.CONF([])
authtoken_config = dict(CONF.keystone_authtoken)
authtoken_config['log_name'] = app.name
app.wsgi_app = auth_token.AuthProtocol(app.wsgi_app, authtoken_config)
return app
@blueprint.route('/v1/resources')
def list_resources():
"""List all resources for a specific project."""
# Project ID from request (or allow override if admin)
project_id = request.headers['X-Project-Id']
if 'admin' in request.headers['X-Roles'] and 'project_id' in request.args:
project_id = request.args['project_id']
try:
start = datetime.fromisoformat(request.args['start'])
end = datetime.fromisoformat(request.args['end'])
except (KeyError, ValueError):
abort(400)
resources = models.Resource.get_all_by_time_range(start, end, project_id)
return jsonify(resources)

View File

@ -15,8 +15,25 @@
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
import pytest import pytest
from atmosphere.api import ingress
from atmosphere.tests.unit import fake from atmosphere.tests.unit import fake
from atmosphere import models from atmosphere import models
from atmosphere.models import db
@pytest.fixture
def app():
app = ingress.init_application()
app.config['TESTING'] = True
app.config['SQLALCHEMY_ECHO'] = True
return app
@pytest.fixture
def _db(app):
db.init_app(app)
db.create_all()
return db
@pytest.mark.usefixtures("client", "db_session") @pytest.mark.usefixtures("client", "db_session")

View File

@ -0,0 +1,37 @@
# Copyright 2020 VEXXHOST, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from dateutil.relativedelta import relativedelta
import pytest
from atmosphere.api import usage
from atmosphere.tests.unit import fake
from atmosphere import models
from atmosphere.models import db
@pytest.fixture
def app():
app = usage.init_application()
app.config['TESTING'] = True
app.config['SQLALCHEMY_ECHO'] = True
return app
@pytest.mark.usefixtures("client")
class TestResourceNoAuth:
def test_get_resources(self, client):
response = client.get('/v1/resources')
assert response.status_code == 401

View File

@ -18,7 +18,6 @@ from flask_sqlalchemy import SQLAlchemy
from atmosphere.app import create_app from atmosphere.app import create_app
from atmosphere.api import ingress from atmosphere.api import ingress
from atmosphere.models import db
@pytest.fixture(params=[ @pytest.fixture(params=[
@ -36,19 +35,3 @@ from atmosphere.models import db
]) ])
def ignored_event(request): def ignored_event(request):
yield request.param yield request.param
@pytest.fixture
def app():
app = create_app()
app.config['TESTING'] = True
app.config['SQLALCHEMY_ECHO'] = True
app.register_blueprint(ingress.blueprint)
return app
@pytest.fixture
def _db(app):
db.init_app(app)
db.create_all()
return db

View File

@ -22,11 +22,28 @@ from dateutil.relativedelta import relativedelta
from freezegun import freeze_time from freezegun import freeze_time
import before_after import before_after
from atmosphere.api import ingress
from atmosphere import models from atmosphere import models
from atmosphere.models import db
from atmosphere import exceptions from atmosphere import exceptions
from atmosphere.tests.unit import fake from atmosphere.tests.unit import fake
@pytest.fixture
def app():
app = ingress.init_application()
app.config['TESTING'] = True
app.config['SQLALCHEMY_ECHO'] = True
return app
@pytest.fixture
def _db(app):
db.init_app(app)
db.create_all()
return db
class GetOrCreateTestMixin: class GetOrCreateTestMixin:
def test_with_existing_object(self): def test_with_existing_object(self):
event = fake.get_normalized_event() event = fake.get_normalized_event()

View File

@ -2,5 +2,6 @@ ceilometer
Flask Flask
Flask-Migrate Flask-Migrate
Flask-SQLAlchemy Flask-SQLAlchemy
keystonemiddleware
python-dateutil python-dateutil
PyMySQL PyMySQL

View File

@ -8,6 +8,7 @@ packages =
[entry_points] [entry_points]
wsgi_scripts = wsgi_scripts =
atmosphere-ingress-wsgi = atmosphere.api.ingress:init_application atmosphere-ingress-wsgi = atmosphere.api.ingress:init_application
atmosphere-usage-wsgi = atmosphere.api.usage:init_application
[tool:pytest] [tool:pytest]
mocked-sessions=atmosphere.models.db.session mocked-sessions=atmosphere.models.db.session

View File

@ -4,10 +4,12 @@ skipsdist = True
[testenv] [testenv]
envdir = {toxworkdir}/shared envdir = {toxworkdir}/shared
usedevelop = True usedevelop = True
setenv =
FLASK_APP=atmosphere.app
passenv = passenv =
OS_*
FLASK_APP
DATABASE_URI DATABASE_URI
setenv =
FLASK_ENV=development
deps = deps =
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt -r{toxinidir}/requirements.txt