Installation struct API call
* jsonschema and model for InstallationStruct added * post API call handled * DB migration fixed for adding new tables * .gitreview added * licence text added into files * test app and uwsgi conf for test app added * import cycles fixed (reproduced on CI only) * autocommit option removed from DB session Blueprint: send-anon-usage Change-Id: If83cb6f86fa96d609da4453ed7417cff996c2019
This commit is contained in:
parent
e5e4186bc3
commit
21c6679048
|
@ -0,0 +1,4 @@
|
|||
[gerrit]
|
||||
host=review.openstack.org
|
||||
port=29418
|
||||
project=stackforge/fuel-stats.git
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2014 Mirantis, 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.
|
|
@ -1 +1,13 @@
|
|||
|
||||
# Copyright 2014 Mirantis, 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.
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 flask import Flask
|
||||
from flask import jsonify
|
||||
from flask import make_response
|
||||
|
@ -14,13 +28,16 @@ app = Flask(__name__)
|
|||
app.config['JSONSCHEMA_DIR'] = os.path.join(app.root_path, 'schemas')
|
||||
flask_jsonschema.JsonSchema(app)
|
||||
|
||||
db = flask_sqlalchemy.SQLAlchemy(app, session_options={'autocommit': True})
|
||||
db = flask_sqlalchemy.SQLAlchemy(app)
|
||||
|
||||
|
||||
# Registering blueprints
|
||||
from collector.api.resources.action_logs import bp as action_logs_bp
|
||||
from collector.api.resources.installation_struct import \
|
||||
bp as installation_struct_bp
|
||||
from collector.api.resources.ping import bp as ping_bp
|
||||
|
||||
app.register_blueprint(installation_struct_bp)
|
||||
app.register_blueprint(action_logs_bp)
|
||||
app.register_blueprint(ping_bp)
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
from collector.api.app import app
|
||||
from collector.api import log
|
||||
|
||||
|
||||
app.config.from_object('collector.api.config.Testing')
|
||||
log.init_logger()
|
|
@ -1 +1,13 @@
|
|||
|
||||
# Copyright 2014 Mirantis, 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.
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 collections import namedtuple
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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.
|
||||
|
||||
import datetime
|
||||
from flask import current_app
|
||||
from flask import jsonify
|
||||
|
@ -65,7 +79,6 @@ def db_transaction(fn):
|
|||
"""
|
||||
@wraps(fn)
|
||||
def decorated(*args, **kwargs):
|
||||
db.session.begin()
|
||||
try:
|
||||
result = fn(*args, **kwargs)
|
||||
db.session.commit()
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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.
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2014 Mirantis, 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.
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 __future__ import with_statement
|
||||
from alembic import context
|
||||
from sqlalchemy import engine_from_config, pool
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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.
|
||||
|
||||
"""Collector DB schema
|
||||
|
||||
Revision ID: 558f628a238
|
||||
|
@ -24,10 +38,21 @@ def upgrade():
|
|||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('node_aid', 'external_id')
|
||||
)
|
||||
op.create_table(
|
||||
'installation_structs',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('aid', sa.String(), nullable=False),
|
||||
sa.Column('struct', sa.Text(), nullable=False),
|
||||
sa.Column('creation_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('modification_date', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('aid')
|
||||
)
|
||||
### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('action_logs')
|
||||
op.execute('DROP TABLE IF EXISTS installation_structs')
|
||||
op.execute('DROP TABLE IF EXISTS action_logs')
|
||||
### end Alembic commands ###
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 collector.api.app import db
|
||||
|
||||
|
||||
|
@ -10,3 +24,13 @@ class ActionLog(db.Model):
|
|||
id = db.Column(db.Integer, primary_key=True)
|
||||
node_aid = db.Column(db.String, nullable=False)
|
||||
external_id = db.Column(db.Integer, nullable=False)
|
||||
|
||||
|
||||
class InstallationStruct(db.Model):
|
||||
__tablename__ = 'installation_structs'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
aid = db.Column(db.String, nullable=False, unique=True)
|
||||
struct = db.Column(db.Text, nullable=False)
|
||||
creation_date = db.Column(db.DateTime)
|
||||
modification_date = db.Column(db.DateTime)
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 logging import FileHandler
|
||||
from logging import Formatter
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2014 Mirantis, 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.
|
|
@ -1,9 +1,26 @@
|
|||
# Copyright 2014 Mirantis, 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 flask import Blueprint
|
||||
from flask import request
|
||||
from flask_jsonschema import validate as validate_request
|
||||
import six
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import or_
|
||||
|
||||
bp = Blueprint('action_logs', __name__, url_prefix='/api/v1/action_logs')
|
||||
|
||||
from collector.api.app import app
|
||||
from collector.api.app import db
|
||||
from collector.api.common import consts
|
||||
|
@ -14,9 +31,6 @@ from collector.api.common.util import handle_response
|
|||
from collector.api.db.model import ActionLog
|
||||
|
||||
|
||||
bp = Blueprint('action_logs', __name__, url_prefix='/api/v1/action_logs')
|
||||
|
||||
|
||||
@bp.route('/', methods=['POST'])
|
||||
@validate_request('action_logs', 'request')
|
||||
@handle_response(201, 'action_logs', 'response')
|
||||
|
@ -30,51 +44,57 @@ def post():
|
|||
objects_info = []
|
||||
for chunk in util.split_collection(action_logs, chunk_size=1000):
|
||||
existed_objs, action_logs_to_add = _separate_action_logs(chunk)
|
||||
_handle_existed_objects(objects_info, existed_objs)
|
||||
_save_action_logs(objects_info, action_logs_to_add)
|
||||
objects_info.extend(_extract_objects_info(existed_objs))
|
||||
objects_info.extend(_save_action_logs(action_logs_to_add))
|
||||
return {'status': 'ok', 'action_logs': list(objects_info)}
|
||||
|
||||
|
||||
@db_transaction
|
||||
def _save_action_logs(objects_info, action_logs):
|
||||
def _save_action_logs(action_logs):
|
||||
result = []
|
||||
if not action_logs:
|
||||
return
|
||||
return result
|
||||
try:
|
||||
db.session.execute(ActionLog.__table__.insert(), action_logs)
|
||||
for action_log in action_logs:
|
||||
objects_info.append({
|
||||
result.append({
|
||||
'node_aid': action_log['node_aid'],
|
||||
'external_id': action_log['external_id'],
|
||||
'status': consts.ACTION_LOG_STATUSES.added
|
||||
})
|
||||
except Exception:
|
||||
app.logger.exception("Processing of action logs chunk failed")
|
||||
_handle_chunk_processing_error(objects_info, action_logs)
|
||||
result = _handle_chunk_processing_error(action_logs)
|
||||
return result
|
||||
|
||||
|
||||
def _handle_existed_objects(objects_info, existed_objects):
|
||||
def _extract_objects_info(existed_objects):
|
||||
result = []
|
||||
for obj in existed_objects:
|
||||
objects_info.append({
|
||||
result.append({
|
||||
'node_aid': obj.node_aid,
|
||||
'external_id': obj.external_id,
|
||||
'status': consts.ACTION_LOG_STATUSES.existed
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def _handle_chunk_processing_error(objects_info, chunk):
|
||||
def _handle_chunk_processing_error(chunk):
|
||||
result = []
|
||||
for action_log in chunk:
|
||||
objects_info.append({
|
||||
result.append({
|
||||
'node_aid': action_log['node_aid'],
|
||||
'external_id': action_log['external_id'],
|
||||
'status': consts.ACTION_LOG_STATUSES.failed
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def _separate_action_logs(action_logs):
|
||||
existed_objs = []
|
||||
action_logs_idx = util.build_index(action_logs, 'node_aid', 'external_id')
|
||||
clauses = []
|
||||
for aid, ext_id in action_logs_idx.keys():
|
||||
for aid, ext_id in six.iterkeys(action_logs_idx):
|
||||
clauses.append(and_(
|
||||
ActionLog.node_aid == aid,
|
||||
ActionLog.external_id == ext_id
|
||||
|
@ -85,4 +105,4 @@ def _separate_action_logs(action_logs):
|
|||
existed_objs.append(existed)
|
||||
idx = (existed.node_aid, existed.external_id)
|
||||
action_logs_idx.pop(idx)
|
||||
return existed_objs, action_logs_idx.values()
|
||||
return existed_objs, list(six.itervalues(action_logs_idx))
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# Copyright 2014 Mirantis, 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 datetime import datetime
|
||||
from flask import Blueprint
|
||||
from flask import json
|
||||
from flask import request
|
||||
from flask_jsonschema import validate as validate_request
|
||||
|
||||
bp = Blueprint('installation_struct', __name__,
|
||||
url_prefix='/api/v1/installation_struct')
|
||||
|
||||
from collector.api.app import app
|
||||
from collector.api.app import db
|
||||
from collector.api.common.util import db_transaction
|
||||
from collector.api.common.util import exec_time
|
||||
from collector.api.common.util import handle_response
|
||||
from collector.api.db.model import InstallationStruct
|
||||
|
||||
|
||||
@bp.route('/', methods=['POST'])
|
||||
@validate_request('installation_struct', 'request')
|
||||
@handle_response(201, 'installation_struct', 'response')
|
||||
@db_transaction
|
||||
@exec_time
|
||||
def post():
|
||||
app.logger.debug(
|
||||
"Handling installation_struct post request: {}".format(request.json)
|
||||
)
|
||||
struct = request.json['installation_struct']
|
||||
aid = struct['aid']
|
||||
obj = db.session.query(InstallationStruct).filter(
|
||||
InstallationStruct.aid == aid).first()
|
||||
if obj is None:
|
||||
app.logger.debug("Saving new struct")
|
||||
obj = InstallationStruct(aid=aid)
|
||||
obj.creation_date = datetime.utcnow()
|
||||
else:
|
||||
app.logger.debug("Updating struct {}".format(obj.id))
|
||||
obj.modification_date = datetime.utcnow()
|
||||
obj.struct = json.dumps(struct)
|
||||
db.session.add(obj)
|
||||
return {'status': 'ok'}
|
|
@ -1,15 +1,28 @@
|
|||
# Copyright 2014 Mirantis, 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 flask import Blueprint
|
||||
from flask import request
|
||||
from flask_jsonschema import validate as validate_request
|
||||
|
||||
bp = Blueprint('ping', __name__, url_prefix='/api/v1/ping')
|
||||
|
||||
from collector.api.app import app
|
||||
from collector.api.common.util import exec_time
|
||||
from collector.api.common.util import handle_response
|
||||
|
||||
|
||||
bp = Blueprint('ping', __name__, url_prefix='/api/v1/ping')
|
||||
|
||||
|
||||
@bp.route('/', methods=['GET'])
|
||||
@validate_request('ping', 'request')
|
||||
@handle_response(200, 'ping', 'response')
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
|
||||
"type": "object",
|
||||
|
||||
"request": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"installation_struct": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aid": {"type": "string"},
|
||||
"clusters_num": {"type": "integer"},
|
||||
"allocated_nodes_num": {"type": "integer"},
|
||||
"unallocated_nodes_num": {"type": "integer"},
|
||||
"fuel_release": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"release": {"type": "string"},
|
||||
"ostf_sha": {"type": "string"},
|
||||
"astute_sha": {"type": "string"},
|
||||
"nailgun_sha": {"type": "string"},
|
||||
"fuellib_sha": {"type": "string"},
|
||||
"feature_groups": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
},
|
||||
"api": {"type": "string"}
|
||||
},
|
||||
"required": ["release", "ostf_sha", "astute_sha",
|
||||
"nailgun_sha", "fuellib_sha", "api",
|
||||
"feature_groups"]
|
||||
},
|
||||
"clusters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "integer"},
|
||||
"mode": {"type": "string"},
|
||||
"release": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {"type": "string"},
|
||||
"os": {"type": "string"},
|
||||
"name": {"type": "string"}
|
||||
},
|
||||
"required": ["version", "os", "name"]
|
||||
},
|
||||
"nodes_num": {"type": "integer"},
|
||||
"nodes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "integer"},
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
},
|
||||
"status": {"type": "string"}
|
||||
},
|
||||
"required": ["id", "roles"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["id", "nodes_num", "nodes", "mode", "release"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["aid", "clusters_num", "allocated_nodes_num",
|
||||
"unallocated_nodes_num", "clusters"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["installation_struct"]
|
||||
},
|
||||
|
||||
"response": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"enum": ["ok"]},
|
||||
"exec_time": {"type": "number"}
|
||||
},
|
||||
"required": ["status"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"enum": ["error"]},
|
||||
"exec_time": {"type": "number"},
|
||||
"message": {"type": "string"}
|
||||
},
|
||||
"required": ["status", "message"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2014 Mirantis, 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.
|
|
@ -1,3 +1,18 @@
|
|||
# Copyright 2014 Mirantis, 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 alembic.util import CommandError
|
||||
from flask import json
|
||||
import flask_migrate
|
||||
import os
|
||||
|
@ -55,9 +70,16 @@ class DbTest(BaseTest):
|
|||
def setUp(self):
|
||||
super(DbTest, self).setUp()
|
||||
|
||||
# Connection must be closed before DB migration
|
||||
db.session.close()
|
||||
|
||||
# Cleaning DB. It useful in case of tests failure
|
||||
directory = os.path.join(os.path.dirname(__file__),
|
||||
'..', 'api', 'db', 'migrations')
|
||||
with app.app_context():
|
||||
flask_migrate.downgrade(directory=directory)
|
||||
try:
|
||||
flask_migrate.downgrade(directory=directory)
|
||||
except CommandError:
|
||||
# Workaround for the first migration
|
||||
pass
|
||||
flask_migrate.upgrade(directory=directory)
|
||||
|
|
|
@ -1 +1,13 @@
|
|||
|
||||
# Copyright 2014 Mirantis, 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.
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 collector.test.base import BaseTest
|
||||
|
||||
from collector.api.common.util import build_index
|
||||
|
|
|
@ -1 +1,13 @@
|
|||
|
||||
# Copyright 2014 Mirantis, 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.
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 collector.test.base import DbTest
|
||||
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
@ -16,6 +30,8 @@ class TestModelActionLog(DbTest):
|
|||
def test_non_nullable_fields(self):
|
||||
db.session.add(ActionLog())
|
||||
self.assertRaises(IntegrityError, db.session.flush)
|
||||
db.session.rollback()
|
||||
|
||||
db.session.add(ActionLog(node_aid='aid'))
|
||||
self.assertRaises(IntegrityError, db.session.flush)
|
||||
db.session.rollback()
|
||||
|
|
|
@ -1 +1,13 @@
|
|||
|
||||
# Copyright 2014 Mirantis, 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.
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 flask import json
|
||||
|
||||
from collector.test.base import DbTest
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 collector.test.base import BaseTest
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
# Copyright 2014 Mirantis, 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 flask import json
|
||||
|
||||
from collector.test.base import DbTest
|
||||
|
||||
from collector.api.app import db
|
||||
from collector.api.db.model import InstallationStruct
|
||||
|
||||
|
||||
class TestInstallationStruct(DbTest):
|
||||
|
||||
def test_not_allowed_methods(self):
|
||||
resp = self.get('/api/v1/installation_struct/', None)
|
||||
self.check_response_error(resp, 405)
|
||||
resp = self.delete('/api/v1/installation_struct/')
|
||||
self.check_response_error(resp, 405)
|
||||
resp = self.patch('/api/v1/installation_struct/', None)
|
||||
self.check_response_error(resp, 405)
|
||||
resp = self.put('/api/v1/installation_struct/', None)
|
||||
self.check_response_error(resp, 405)
|
||||
|
||||
def test_validation_error(self):
|
||||
wrong_data_sets = [
|
||||
{'installation_struct': {'aid': 'x'}},
|
||||
None,
|
||||
{}
|
||||
]
|
||||
for data in wrong_data_sets:
|
||||
resp = self.post(
|
||||
'/api/v1/installation_struct/',
|
||||
data
|
||||
)
|
||||
self.check_response_error(resp, code=400)
|
||||
|
||||
def test_post(self):
|
||||
aid = 'x'
|
||||
struct = {
|
||||
'aid': aid,
|
||||
'fuel_release': {
|
||||
'release': 'r',
|
||||
'ostf_sha': 'o_sha',
|
||||
'astute_sha': 'a_sha',
|
||||
'nailgun_sha': 'n_sha',
|
||||
'fuellib_sha': 'fl_sha',
|
||||
'feature_groups': ['experimental'],
|
||||
'api': 'v1'
|
||||
},
|
||||
'allocated_nodes_num': 4,
|
||||
'unallocated_nodes_num': 4,
|
||||
'clusters_num': 2,
|
||||
'clusters': [
|
||||
{
|
||||
'id': 29,
|
||||
'mode': 'ha_full',
|
||||
'release': {
|
||||
'version': '2014.2-6.0',
|
||||
'name': 'Juno on CentOS 6.5',
|
||||
'os': 'CentOS'
|
||||
},
|
||||
'nodes_num': 3,
|
||||
'nodes': [
|
||||
{'id': 33, 'roles': ['a', 'b', 'c'], 'status': 's'},
|
||||
{'id': 34, 'roles': ['b', 'c'], 'status': 's'},
|
||||
{'id': 35, 'roles': ['c'], 'status': 's'}
|
||||
]
|
||||
},
|
||||
{
|
||||
'id': 32,
|
||||
'mode': 'ha_compact',
|
||||
'release': {
|
||||
'version': '2014.2-6.0',
|
||||
'name': 'Juno on CentOS 6.5',
|
||||
'os': 'CentOS'
|
||||
},
|
||||
'nodes_num': 1,
|
||||
'nodes': [
|
||||
{'id': 42, 'roles': ['s'], 'status': 's'}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
resp = self.post(
|
||||
'/api/v1/installation_struct/',
|
||||
{'installation_struct': struct}
|
||||
)
|
||||
self.check_response_ok(resp, code=201)
|
||||
obj = db.session.query(InstallationStruct).filter(
|
||||
InstallationStruct.aid == aid).one()
|
||||
self.assertEquals(json.dumps(struct), obj.struct)
|
||||
self.assertIsNotNone(obj.creation_date)
|
||||
self.assertIsNone(obj.modification_date)
|
||||
|
||||
def test_post_update(self):
|
||||
aid = 'xx'
|
||||
struct = {
|
||||
'aid': aid,
|
||||
'allocated_nodes_num': 0,
|
||||
'unallocated_nodes_num': 0,
|
||||
'clusters_num': 0,
|
||||
'clusters': []
|
||||
}
|
||||
resp = self.post(
|
||||
'/api/v1/installation_struct/',
|
||||
{'installation_struct': struct}
|
||||
)
|
||||
self.check_response_ok(resp, code=201)
|
||||
obj_new = db.session.query(InstallationStruct).filter(
|
||||
InstallationStruct.aid == aid).one()
|
||||
self.assertEquals(json.dumps(struct), obj_new.struct)
|
||||
self.assertIsNotNone(obj_new.creation_date)
|
||||
self.assertIsNone(obj_new.modification_date)
|
||||
|
||||
struct['unallocated_nodes_num'] = 5
|
||||
resp = self.post(
|
||||
'/api/v1/installation_struct/',
|
||||
{'installation_struct': struct}
|
||||
)
|
||||
self.check_response_ok(resp, code=201)
|
||||
obj_upd = db.session.query(InstallationStruct).filter(
|
||||
InstallationStruct.aid == aid).one()
|
||||
self.assertEquals(json.dumps(struct), obj_upd.struct)
|
||||
self.assertIsNotNone(obj_upd.creation_date)
|
||||
self.assertIsNotNone(obj_upd.modification_date)
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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 collector.test.base import BaseTest
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2014 Mirantis, 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 flask_migrate import Migrate
|
||||
from flask_migrate import MigrateCommand
|
||||
from flask_script import Manager
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# Copyright 2014 Mirantis, 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.
|
||||
|
||||
import os
|
||||
|
||||
from setuptools import find_packages
|
||||
|
@ -37,9 +51,5 @@ setup(
|
|||
zip_safe=False,
|
||||
install_requires=parse_requirements_txt(),
|
||||
include_package_data=True,
|
||||
scripts=['manage_collector.py'],
|
||||
# entry_points={
|
||||
# 'console_scripts': [
|
||||
# 'upgrade_db = collector.cli:main']
|
||||
# }
|
||||
scripts=['manage_collector.py']
|
||||
)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
uwsgi:
|
||||
socket: :8081
|
||||
module: collector.api.app
|
||||
# for production app use collector.api.app as module
|
||||
module: collector.api.app_test
|
||||
callable: app
|
||||
protocol: http
|
||||
|
|
Loading…
Reference in New Issue