cleanup legacy changes
Change-Id: I5a29cee1ed9e3ea18d2e7e659d5e3143d122bf62
This commit is contained in:
parent
113e5618e9
commit
50de35d7e8
17
orm/common/client/audit/CONTRIBUTING.rst
Normal file
17
orm/common/client/audit/CONTRIBUTING.rst
Normal file
@ -0,0 +1,17 @@
|
||||
If you would like to contribute to the development of OpenStack, you must
|
||||
follow the steps in this page:
|
||||
|
||||
http://docs.openstack.org/infra/manual/developers.html
|
||||
|
||||
If you already have a good understanding of how the system works and your
|
||||
OpenStack accounts are set up, you can skip to the development workflow
|
||||
section of this documentation to learn how changes to OpenStack should be
|
||||
submitted for review via the Gerrit tool:
|
||||
|
||||
http://docs.openstack.org/infra/manual/developers.html#development-workflow
|
||||
|
||||
Pull requests submitted through GitHub will be ignored.
|
||||
|
||||
Bugs should be filed on Launchpad, not GitHub:
|
||||
|
||||
https://bugs.launchpad.net/audit_client
|
4
orm/common/client/audit/HACKING.rst
Normal file
4
orm/common/client/audit/HACKING.rst
Normal file
@ -0,0 +1,4 @@
|
||||
audit_client Style Commandments
|
||||
===============================================
|
||||
|
||||
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
|
6
orm/common/client/audit/MANIFEST.in
Normal file
6
orm/common/client/audit/MANIFEST.in
Normal file
@ -0,0 +1,6 @@
|
||||
include AUTHORS
|
||||
include ChangeLog
|
||||
exclude .gitignore
|
||||
exclude .gitreview
|
||||
|
||||
global-exclude *.pyc
|
19
orm/common/client/audit/README.rst
Normal file
19
orm/common/client/audit/README.rst
Normal file
@ -0,0 +1,19 @@
|
||||
===============================
|
||||
audit_client
|
||||
===============================
|
||||
|
||||
This is the Audit Client project
|
||||
|
||||
Please feel here a long description which must be at least 3 lines wrapped on
|
||||
80 cols, so that distribution package maintainers can use it in their packages.
|
||||
Note that this is a hard requirement.
|
||||
|
||||
* Free software: Apache license
|
||||
* Documentation: http://docs.openstack.org/developer/audit_client
|
||||
* Source: http://git.openstack.org/cgit/audit_client/audit_client
|
||||
* Bugs: http://bugs.launchpad.net/audit_client
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* TODO
|
1
orm/common/client/audit/audit_client/__init__.py
Normal file
1
orm/common/client/audit/audit_client/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""audit_client package."""
|
1
orm/common/client/audit/audit_client/api/__init__.py
Normal file
1
orm/common/client/audit/audit_client/api/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""api package."""
|
219
orm/common/client/audit/audit_client/api/audit.py
Executable file
219
orm/common/client/audit/audit_client/api/audit.py
Executable file
@ -0,0 +1,219 @@
|
||||
"""audit module."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
import urllib2
|
||||
|
||||
from audit_client.api.exceptions.audit_exception import AuditException
|
||||
from audit_client.api.model.get_audits_result import AuditsResult
|
||||
from audit_client.api.model.transaction import Transaction
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
config = {
|
||||
'AUDIT_SERVER_URL': None,
|
||||
'NUM_OF_SEND_RETRIES': None,
|
||||
'TIME_WAIT_BETWEEN_RETRIES': None,
|
||||
'SERVICE_NAME': None}
|
||||
|
||||
|
||||
def init(audit_server_url, num_of_send_retries, time_wait_between_retries,
|
||||
service_name=''):
|
||||
"""Initialize the audit client.
|
||||
|
||||
:param audit_server_url: audit server url
|
||||
:param num_of_send_retries: number of times to try and send the record
|
||||
in case of failures.
|
||||
:param time_wait_between_retries: how much time to wait (in seconds)
|
||||
between each retry.
|
||||
"""
|
||||
if not audit_server_url \
|
||||
or not num_of_send_retries \
|
||||
or not time_wait_between_retries:
|
||||
error_msg = "Error: Fail to initialize audit using following inputs " \
|
||||
"AUDIT_SERVER_URL={}, NUM_OF_SEND_RETRIES={}, " \
|
||||
"TIME_WAIT_BETWEEN_RETRIES={}. " \
|
||||
"One of them is possibly None" \
|
||||
.format(audit_server_url, num_of_send_retries,
|
||||
time_wait_between_retries)
|
||||
logger.error(error_msg)
|
||||
raise AuditException(error_msg)
|
||||
|
||||
config['AUDIT_SERVER_URL'] = audit_server_url
|
||||
config['NUM_OF_SEND_RETRIES'] = num_of_send_retries
|
||||
config['TIME_WAIT_BETWEEN_RETRIES'] = time_wait_between_retries
|
||||
config['SERVICE_NAME'] = service_name
|
||||
|
||||
|
||||
def _validate():
|
||||
"""# Validate proper initialization of the audit client."""
|
||||
# if not AUDIT_SERVER_URL or not NUM_OF_SEND_RETRIES
|
||||
# or not TIME_WAIT_BETWEEN_RETRIES:
|
||||
if not config['AUDIT_SERVER_URL'] \
|
||||
or not config['NUM_OF_SEND_RETRIES'] \
|
||||
or not config['TIME_WAIT_BETWEEN_RETRIES']:
|
||||
raise AuditException(
|
||||
"Error: Audit was not initialize correctly. You must first "
|
||||
"run audit.init(audit_server_url, num_of_send_retries, "
|
||||
"time_wait_between_retries)")
|
||||
|
||||
|
||||
def audit(timestamp, application_id, tracking_id, transaction_id,
|
||||
transaction_type, resource_id, service_name, user_id=None,
|
||||
external_id=None, event_details=None):
|
||||
"""The method is used to audit transactions.
|
||||
|
||||
:param timestamp:
|
||||
:param application_id:
|
||||
:param tracking_id:
|
||||
:param transaction_id:
|
||||
:param transaction_type:
|
||||
:param resource_id:
|
||||
:param service_name:
|
||||
:param user_id:
|
||||
:param external_id:
|
||||
:param event_details:
|
||||
:return:
|
||||
"""
|
||||
thread = threading.Thread(target=_audit_thread, args=(
|
||||
timestamp, application_id, tracking_id, transaction_id,
|
||||
transaction_type,
|
||||
resource_id, service_name, user_id, external_id, event_details))
|
||||
thread.start()
|
||||
|
||||
|
||||
def get_audits(timestamp_from=None, timestamp_to=None, application_id=None,
|
||||
tracking_id=None, transaction_id=None, transaction_type=None,
|
||||
resource_id=None, service_name=None, user_id=None,
|
||||
external_id=None, event_details=None, limit=None):
|
||||
"""The method is used to audit transactions.
|
||||
|
||||
:param timestamp_from:
|
||||
:param timestamp_to:
|
||||
:param application_id:
|
||||
:param tracking_id:
|
||||
:param transaction_id:
|
||||
:param transaction_type:
|
||||
:param resource_id:
|
||||
:param service_name:
|
||||
:param user_id:
|
||||
:param external_id:
|
||||
:param event_details:
|
||||
"""
|
||||
query = ""
|
||||
query = _build_query(query, "q.timestamp_from", timestamp_from)
|
||||
query = _build_query(query, "q.timestamp_to", timestamp_to)
|
||||
query = _build_query(query, "q.application_id", application_id)
|
||||
query = _build_query(query, "q.tracking_id", tracking_id)
|
||||
query = _build_query(query, "q.transaction_id", transaction_id)
|
||||
query = _build_query(query, "q.transaction_type", transaction_type)
|
||||
query = _build_query(query, "q.resource_id", resource_id)
|
||||
query = _build_query(query, "q.service_name", service_name)
|
||||
query = _build_query(query, "q.user_id", user_id)
|
||||
query = _build_query(query, "q.external_id", external_id)
|
||||
query = _build_query(query, "q.event_details", event_details)
|
||||
query = _build_query(query, "limit", limit)
|
||||
payload = _get_data(query)
|
||||
data = json.load(payload)
|
||||
transactions = []
|
||||
for transaction in data['transactions']:
|
||||
timestamp = transaction['timestamp']
|
||||
user_id = transaction['user_id']
|
||||
application_id = transaction['application_id']
|
||||
tracking_id = transaction['tracking_id']
|
||||
external_id = transaction['external_id']
|
||||
transaction_id = transaction['transaction_id']
|
||||
resource_id = transaction['resource_id']
|
||||
service_name = transaction['service_name']
|
||||
transaction_type = transaction['transaction_type']
|
||||
event_details = transaction['event_details']
|
||||
transactions.append(
|
||||
Transaction(timestamp, user_id, application_id, tracking_id,
|
||||
external_id, transaction_id, transaction_type,
|
||||
event_details, resource_id, service_name))
|
||||
return AuditsResult(transactions)
|
||||
|
||||
|
||||
def _build_query(query, arg_name, arg_value):
|
||||
if arg_value is not None:
|
||||
query = query + "%s=%s&" % (arg_name, arg_value)
|
||||
return query
|
||||
|
||||
|
||||
# A thread method for sending data to the audit server
|
||||
# This method is asynchronic in order to prevent blocking
|
||||
def _audit_thread(timestamp, application_id, tracking_id, transaction_id,
|
||||
transaction_type, resource_id, service_name, user_id,
|
||||
external_id, event_details):
|
||||
# Prepare the data for the audit server
|
||||
data = {
|
||||
"timestamp": timestamp,
|
||||
"application_id": application_id,
|
||||
"tracking_id": tracking_id,
|
||||
"transaction_id": transaction_id,
|
||||
"transaction_type": transaction_type,
|
||||
"resource_id": resource_id,
|
||||
"service_name": service_name,
|
||||
"user_id": user_id,
|
||||
"external_id": external_id,
|
||||
"event_details": event_details,
|
||||
"resource_id": resource_id,
|
||||
"service_name": service_name
|
||||
}
|
||||
_post_data(data)
|
||||
|
||||
|
||||
def _post_data(data):
|
||||
# Validate that the configuration was initialized
|
||||
_validate()
|
||||
# Send the data
|
||||
req = urllib2.Request(config['AUDIT_SERVER_URL'])
|
||||
req.add_header('Content-Type', 'application/json')
|
||||
# Retry to send the data to the audit server
|
||||
success = False
|
||||
for retry_number in range(config['NUM_OF_SEND_RETRIES']):
|
||||
try:
|
||||
urllib2.urlopen(req, json.dumps(data))
|
||||
success = True
|
||||
break
|
||||
except Exception as error:
|
||||
time.sleep(config['TIME_WAIT_BETWEEN_RETRIES'])
|
||||
|
||||
if not success:
|
||||
error_msg = "ERROR|CON{}AUDIT001|Fail to send data to [{}]. Tried " \
|
||||
"a couple of times with no success. Last attempt " \
|
||||
"error: [{}]".format(config['SERVICE_NAME'],
|
||||
config['AUDIT_SERVER_URL'],
|
||||
error.message)
|
||||
logger.error(error_msg)
|
||||
raise AuditException(error_msg)
|
||||
|
||||
|
||||
def _get_data(query):
|
||||
# Validate that the configuration was initialized
|
||||
_validate()
|
||||
# Send the data
|
||||
audit_server_url_with_query = "{}?{}".format(config['AUDIT_SERVER_URL'],
|
||||
query)
|
||||
req = urllib2.Request(audit_server_url_with_query)
|
||||
# Retry to get the data from the audit server
|
||||
success = False
|
||||
response = None
|
||||
for retry_number in range(config['NUM_OF_SEND_RETRIES']):
|
||||
try:
|
||||
response = urllib2.urlopen(req)
|
||||
success = True
|
||||
break
|
||||
except Exception as error:
|
||||
time.sleep(config['TIME_WAIT_BETWEEN_RETRIES'])
|
||||
|
||||
if not success:
|
||||
error_msg = "Fail to get data from [{}]. Tried a couple of times " \
|
||||
"with no success. Last attempt error: [{}]".\
|
||||
format(audit_server_url_with_query, error.message)
|
||||
logger.error(error_msg)
|
||||
raise AuditException(error_msg)
|
||||
else:
|
||||
return response
|
@ -0,0 +1 @@
|
||||
"""exceptions package."""
|
@ -0,0 +1,9 @@
|
||||
"""audit exception module."""
|
||||
|
||||
|
||||
class AuditException(Exception):
|
||||
"""AuditException class."""
|
||||
|
||||
def __init__(self, error_msg):
|
||||
"""init method."""
|
||||
Exception.__init__(self, error_msg)
|
@ -0,0 +1 @@
|
||||
"""model package."""
|
@ -0,0 +1,14 @@
|
||||
"""get_audit_result module."""
|
||||
|
||||
|
||||
class AuditsResult(object):
|
||||
"""AuditResult class."""
|
||||
|
||||
def __init__(self, transactions):
|
||||
"""init method."""
|
||||
self.transactions = transactions
|
||||
|
||||
def __str__(self):
|
||||
"""string representation of the object."""
|
||||
return "AuditsResult[ " \
|
||||
"transactions: {}]".format(self.transactions)
|
49
orm/common/client/audit/audit_client/api/model/transaction.py
Executable file
49
orm/common/client/audit/audit_client/api/model/transaction.py
Executable file
@ -0,0 +1,49 @@
|
||||
"""transaction module."""
|
||||
|
||||
|
||||
class Transaction(object):
|
||||
"""transaction class."""
|
||||
|
||||
def __init__(self, timestamp, user_id, application_id, tracking_id,
|
||||
external_id, transaction_id, transaction_type, event_details,
|
||||
resource_id, service_name):
|
||||
"""init method."""
|
||||
self.timestamp = timestamp
|
||||
self.user_id = user_id
|
||||
self.application_id = application_id
|
||||
self.tracking_id = tracking_id
|
||||
self.external_id = external_id
|
||||
self.transaction_id = transaction_id
|
||||
self.transaction_type = transaction_type
|
||||
self.event_details = event_details
|
||||
self.resource_id = resource_id
|
||||
self.service_name = service_name
|
||||
|
||||
def __str__(self):
|
||||
"""string representation of the object."""
|
||||
return "Transaction:[" \
|
||||
"timestamp={}, " \
|
||||
"user_id={}, " \
|
||||
"application_id={}, " \
|
||||
"tracking_id={}, " \
|
||||
"external_id={}, " \
|
||||
"transaction_id={}, " \
|
||||
"transaction_type={}, " \
|
||||
"event_details={}, " \
|
||||
"resource_id={}, " \
|
||||
"service_name={}]" \
|
||||
.format(
|
||||
self.timestamp,
|
||||
self.user_id,
|
||||
self.application_id,
|
||||
self.tracking_id,
|
||||
self.external_id,
|
||||
self.transaction_id,
|
||||
self.transaction_type,
|
||||
self.event_details,
|
||||
self.resource_id,
|
||||
self.service_name)
|
||||
|
||||
def __repr__(self):
|
||||
"""string representation of the object."""
|
||||
return str(self)
|
@ -0,0 +1 @@
|
||||
"""examples package."""
|
22
orm/common/client/audit/audit_client/examples/get_audits.py
Normal file
22
orm/common/client/audit/audit_client/examples/get_audits.py
Normal file
@ -0,0 +1,22 @@
|
||||
"""get_audits module."""
|
||||
|
||||
from audit_client.api import audit
|
||||
|
||||
audit_server_url = "http://127.0.0.1:8776/v1/audit/transaction"
|
||||
num_of_send_retries = 3
|
||||
time_wait_between_retries = 1
|
||||
audit.init(audit_server_url, num_of_send_retries, time_wait_between_retries)
|
||||
response = audit.get_audits(timestamp_from=1, timestamp_to=5,
|
||||
application_id="application_id_1",
|
||||
tracking_id="tracking_id_1",
|
||||
transaction_id="transaction_id_1",
|
||||
transaction_type="transaction_type_1",
|
||||
resource_id="resource_id_1",
|
||||
service_name="service_name_1", user_id="user_id_1",
|
||||
external_id="external_id_1",
|
||||
event_details="event_details_1", status="status_1",
|
||||
limit=10)
|
||||
print(response)
|
||||
|
||||
response = audit.get_audits(timestamp_from=1, timestamp_to=5, limit=10)
|
||||
print(response)
|
52
orm/common/client/audit/audit_client/examples/put_audit.py
Normal file
52
orm/common/client/audit/audit_client/examples/put_audit.py
Normal file
@ -0,0 +1,52 @@
|
||||
"""put_audit module."""
|
||||
|
||||
from audit_client.api import audit
|
||||
|
||||
audit_server_url = "http://127.0.0.1:8776/v1/audit/transaction"
|
||||
num_of_send_retries = 3
|
||||
time_wait_between_retries = 1
|
||||
audit.init(audit_server_url, num_of_send_retries, time_wait_between_retries)
|
||||
audit.audit(1, "application_id_1", "tracking_id_1", "transaction_id_1",
|
||||
"transaction_type_1", "resource_id_1", "service_name_1",
|
||||
"user_id_1", "external_id_1", "event_details_1", "status_1")
|
||||
print("audit1")
|
||||
audit.audit(2, "application_id_2", "tracking_id_2", "transaction_id_2",
|
||||
"transaction_type_2", "resource_id_2", "service_name_2",
|
||||
"user_id_2", "external_id_2", "event_details_2", "status_2")
|
||||
print("audit2")
|
||||
audit.audit(3, "application_id_3", "tracking_id_3", "transaction_id_3",
|
||||
"transaction_type_3", "resource_id_3", "service_name_3",
|
||||
"user_id_3", "external_id_3", "event_details_3", "status_3")
|
||||
print("audit3")
|
||||
audit.audit(4, "application_id_4", "tracking_id_4", "transaction_id_4",
|
||||
"transaction_type_4", "resource_id_4", "service_name_4",
|
||||
"user_id_4", "external_id_4", "event_details_4", "status_4")
|
||||
print("audit4")
|
||||
audit.audit(5, "application_id_5", "tracking_id_5", "transaction_id_5",
|
||||
"transaction_type_5", "resource_id_5", "service_name_5",
|
||||
"user_id_5", "external_id_5", "event_details_5", "status_5")
|
||||
print("audit5")
|
||||
audit.audit(6, "application_id_6", "tracking_id_6", "transaction_id_6",
|
||||
"transaction_type_6", "resource_id_6", "service_name_6",
|
||||
"user_id_6", "external_id_6", "event_details_6", "status_6")
|
||||
print("audit6")
|
||||
audit.audit(7, "application_id_7", "tracking_id_7", "transaction_id_7",
|
||||
"transaction_type_7", "resource_id_7", "service_name_7",
|
||||
"user_id_7", "external_id_7", "event_details_7", "status_7")
|
||||
print("audit7")
|
||||
audit.audit(8, "application_id_8", "tracking_id_8", "transaction_id_8",
|
||||
"transaction_type_8", "resource_id_8", "service_name_8",
|
||||
"user_id_8", "external_id_8", "event_details_8", "status_8")
|
||||
print("audit8")
|
||||
audit.audit(9, "application_id_9", "tracking_id_9", "transaction_id_9",
|
||||
"transaction_type_9", "resource_id_9", "service_name_9",
|
||||
"user_id_9", "external_id_9", "event_details_9", "status_9")
|
||||
print("audit9")
|
||||
audit.audit(10, "application_id_10", "tracking_id_10", "transaction_id_10",
|
||||
"transaction_type_10", "resource_id_10", "service_name_10",
|
||||
"user_id_10", "external_id_10", "event_details_10", "status_10")
|
||||
print("audit10")
|
||||
audit.audit(11, "application_id_11", "tracking_id_11", "transaction_id_11",
|
||||
"transaction_type_11", "resource_id_11", "service_name_11",
|
||||
"user_id_11", "external_id_11", "event_details_11", "status_11")
|
||||
print("audit11")
|
1
orm/common/client/audit/audit_client/tests/__init__.py
Normal file
1
orm/common/client/audit/audit_client/tests/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""test package."""
|
@ -0,0 +1 @@
|
||||
"""api package."""
|
@ -0,0 +1 @@
|
||||
"""model package."""
|
@ -0,0 +1,16 @@
|
||||
"""test_get_audits_result module."""
|
||||
|
||||
from audit_client.api.model.get_audits_result import AuditsResult
|
||||
import unittest
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test get audits result class."""
|
||||
|
||||
def test_init_AuditsResult(self):
|
||||
"""test init method."""
|
||||
transactions = []
|
||||
audit_result = AuditsResult(transactions)
|
||||
self.assertEqual(str(audit_result),
|
||||
"AuditsResult[ transactions: {}]".format(
|
||||
transactions))
|
69
orm/common/client/audit/audit_client/tests/api/model/test_transactions.py
Executable file
69
orm/common/client/audit/audit_client/tests/api/model/test_transactions.py
Executable file
@ -0,0 +1,69 @@
|
||||
"""test transactions module."""
|
||||
|
||||
import unittest
|
||||
|
||||
from audit_client.api.model.transaction import Transaction
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test transactions class."""
|
||||
|
||||
def test_init_AuditsResult(self):
|
||||
"""test init method."""
|
||||
timestamp = 111
|
||||
user_id = "user_id_1"
|
||||
application_id = "application_id_1"
|
||||
tracking_id = "tracking_id_1"
|
||||
external_id = "external_id_1"
|
||||
transaction_id = "transaction_id_1"
|
||||
transaction_type = "transaction_type_1"
|
||||
event_details = "event_details_1"
|
||||
resource_id = "resource_id_1"
|
||||
service_name = "service_name_1"
|
||||
transaction = Transaction(timestamp, user_id, application_id,
|
||||
tracking_id, external_id, transaction_id,
|
||||
transaction_type, event_details,
|
||||
resource_id, service_name)
|
||||
self.assertEqual(str(transaction), "Transaction:["
|
||||
"timestamp={}, "
|
||||
"user_id={}, "
|
||||
"application_id={}, "
|
||||
"tracking_id={}, "
|
||||
"external_id={}, "
|
||||
"transaction_id={}, "
|
||||
"transaction_type={}, "
|
||||
"event_details={}, "
|
||||
"resource_id={}, "
|
||||
"service_name={}]".format(
|
||||
timestamp,
|
||||
user_id,
|
||||
application_id,
|
||||
tracking_id,
|
||||
external_id,
|
||||
transaction_id,
|
||||
transaction_type,
|
||||
event_details,
|
||||
resource_id,
|
||||
service_name))
|
||||
|
||||
self.assertEqual(transaction.__repr__(), "Transaction:["
|
||||
"timestamp={}, "
|
||||
"user_id={}, "
|
||||
"application_id={}, "
|
||||
"tracking_id={}, "
|
||||
"external_id={}, "
|
||||
"transaction_id={}, "
|
||||
"transaction_type={}, "
|
||||
"event_details={}, "
|
||||
"resource_id={}, "
|
||||
"service_name={}]".format(
|
||||
timestamp,
|
||||
user_id,
|
||||
application_id,
|
||||
tracking_id,
|
||||
external_id,
|
||||
transaction_id,
|
||||
transaction_type,
|
||||
event_details,
|
||||
resource_id,
|
||||
service_name))
|
265
orm/common/client/audit/audit_client/tests/api/test_audit.py
Executable file
265
orm/common/client/audit/audit_client/tests/api/test_audit.py
Executable file
@ -0,0 +1,265 @@
|
||||
"""test_audit module."""
|
||||
|
||||
import json
|
||||
import threading
|
||||
import unittest
|
||||
import urllib2
|
||||
|
||||
from mock import patch
|
||||
|
||||
from audit_client.api import audit
|
||||
from audit_client.api.exceptions.audit_exception import AuditException
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test audit class."""
|
||||
|
||||
data = {
|
||||
'transactions': [
|
||||
{
|
||||
'timestamp': 111,
|
||||
'user_id': 'user_id_1',
|
||||
'application_id': 'application_id_1',
|
||||
'tracking_id': 'tracking_id_1',
|
||||
'external_id': 'external_id_1',
|
||||
'transaction_id': 'transaction_id_1',
|
||||
'transaction_type': 'transaction_type_1',
|
||||
'event_details': 'event_details_1',
|
||||
'resource_id': "resource_id_1",
|
||||
'service_name': "service_name_1"
|
||||
}, {
|
||||
'timestamp': 111,
|
||||
'user_id': 'user_id_2',
|
||||
'application_id': 'application_id_2',
|
||||
'tracking_id': 'tracking_id_2',
|
||||
'external_id': 'external_id_2',
|
||||
'transaction_id': 'transaction_id_2',
|
||||
'transaction_type': 'transaction_type_2',
|
||||
'event_details': 'event_details_2',
|
||||
'resource_id': "resource_id_2",
|
||||
'service_name': "service_name_3"
|
||||
}, {
|
||||
'timestamp': 111,
|
||||
'user_id': 'user_id_3',
|
||||
'application_id': 'application_id_3',
|
||||
'tracking_id': 'tracking_id_3',
|
||||
'external_id': 'external_id_3',
|
||||
'transaction_id': 'transaction_id_3',
|
||||
'transaction_type': 'transaction_type_3',
|
||||
'event_details': 'event_details_3',
|
||||
'resource_id': "resource_id_3",
|
||||
'service_name': "service_name_3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
def test_init(self):
|
||||
"""test init method.
|
||||
|
||||
test that init doesn't throw and exeception/error
|
||||
and that the gloabl variables are set correctly
|
||||
"""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = 5
|
||||
time_wait_between_retries = 10
|
||||
audit.init(audit_server_url, num_of_send_retries,
|
||||
time_wait_between_retries)
|
||||
self.assertEqual(audit.config['AUDIT_SERVER_URL'], audit_server_url)
|
||||
self.assertEqual(audit.config['NUM_OF_SEND_RETRIES'],
|
||||
num_of_send_retries)
|
||||
self.assertEqual(audit.config['TIME_WAIT_BETWEEN_RETRIES'],
|
||||
time_wait_between_retries)
|
||||
|
||||
#
|
||||
def test_init_with_audit_server_url_empty(self):
|
||||
"""test that init throws an exception when audit_server_url is None."""
|
||||
audit_server_url = None
|
||||
num_of_send_retries = 5
|
||||
time_wait_between_retries = 10
|
||||
self.assertRaises(AuditException, audit.init, audit_server_url,
|
||||
num_of_send_retries, time_wait_between_retries)
|
||||
|
||||
def test_init_with_num_of_send_retries_empty(self):
|
||||
"""test init method.
|
||||
|
||||
test that init throws an exception when num_of_send_retries is None
|
||||
"""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = None
|
||||
time_wait_between_retries = 10
|
||||
self.assertRaises(AuditException, audit.init, audit_server_url,
|
||||
num_of_send_retries, time_wait_between_retries)
|
||||
|
||||
def test_init_with_time_wait_between_retries_empty(self):
|
||||
"""test init method.
|
||||
|
||||
Test that init throws an exception when
|
||||
time_wait_between_retries is None.
|
||||
"""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = 5
|
||||
time_wait_between_retries = None
|
||||
self.assertRaises(AuditException, audit.init, audit_server_url,
|
||||
num_of_send_retries, time_wait_between_retries)
|
||||
|
||||
def test_validate(self):
|
||||
"""test validate method.
|
||||
|
||||
test that _validate doesn't throw and exception when all variables
|
||||
are populated
|
||||
"""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = 5
|
||||
time_wait_between_retries = 10
|
||||
audit.init(audit_server_url, num_of_send_retries,
|
||||
time_wait_between_retries)
|
||||
audit._validate()
|
||||
|
||||
def test_validate_with_audit_server_url_empty(self):
|
||||
"""test validate with audit_server_url.
|
||||
|
||||
test that _validate throw and exception when AUDIT_SERVER_URL
|
||||
is None.
|
||||
"""
|
||||
audit.config['AUDIT_SERVER_URL'] = None
|
||||
audit.config['NUM_OF_SEND_RETRIES'] = 5
|
||||
audit.config['TIME_WAIT_BETWEEN_RETRIES'] = 10
|
||||
self.assertRaises(AuditException, audit._validate)
|
||||
|
||||
def test_validate_with_num_of_send_retries_empty(self):
|
||||
"""test validate with num of send_retries_empty.
|
||||
|
||||
test that _validate throw and exception when NUM_OF_SEND_RETRIES
|
||||
is None
|
||||
"""
|
||||
audit.config['AUDIT_SERVER_URL'] = "audit_server_url_1"
|
||||
audit.config['NUM_OF_SEND_RETRIES'] = None
|
||||
audit.config['TIME_WAIT_BETWEEN_RETRIES'] = 10
|
||||
self.assertRaises(AuditException, audit._validate)
|
||||
|
||||
def test_validate_with_time_wait_between_retries_empty(self):
|
||||
"""test validate with ime_wait_between_retries_empty.
|
||||
|
||||
test that _validate throw and exception when
|
||||
TIME_WAIT_BETWEEN_RETRIES is None
|
||||
"""
|
||||
audit.config['AUDIT_SERVER_URL'] = "audit_server_url_1"
|
||||
audit.config['NUM_OF_SEND_RETRIES'] = 5
|
||||
audit.config['TIME_WAIT_BETWEEN_RETRIES'] = None
|
||||
self.assertRaises(AuditException, audit._validate)
|
||||
|
||||
@patch.object(urllib2, 'urlopen')
|
||||
@patch.object(json, 'load', return_value=data)
|
||||
def test_get_audits(self, mock_urlopen, mock_load):
|
||||
"""test get_audits."""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = 5
|
||||
time_wait_between_retries = 10
|
||||
audit.init(audit_server_url, num_of_send_retries,
|
||||
time_wait_between_retries)
|
||||
result = audit.get_audits()
|
||||
self.assertEqual(len(result.transactions), 3)
|
||||
|
||||
@patch.object(urllib2, 'urlopen')
|
||||
@patch.object(json, 'load')
|
||||
def test_audit_thread(self, mock_urlopen, mock_load):
|
||||
"""Test audit_thread is executed with no exceptions."""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = 5
|
||||
time_wait_between_retries = 10
|
||||
audit.init(audit_server_url, num_of_send_retries,
|
||||
time_wait_between_retries)
|
||||
timestamp = 111
|
||||
application_id = 'application_id_1'
|
||||
tracking_id = 'tracking_id_1'
|
||||
transaction_id = 'transaction_id_1'
|
||||
transaction_type = 'transaction_type_1'
|
||||
user_id = 'user_id_1'
|
||||
external_id = 'external_id_1'
|
||||
event_details = 'event_details_1'
|
||||
resource_id = 'resource_id_1'
|
||||
service_name = 'service_name_1'
|
||||
audit._audit_thread(timestamp, application_id, tracking_id,
|
||||
transaction_id, transaction_type,
|
||||
resource_id, service_name, user_id, external_id,
|
||||
event_details)
|
||||
|
||||
@patch.object(urllib2, 'urlopen')
|
||||
@patch.object(json, 'load')
|
||||
def test_post_data(self, mock_urlopen, mock_load):
|
||||
"""test that post_data is executed with no exceptions."""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = 5
|
||||
time_wait_between_retries = 10
|
||||
audit.init(audit_server_url, num_of_send_retries,
|
||||
time_wait_between_retries)
|
||||
audit._post_data(None)
|
||||
|
||||
@patch.object(urllib2, 'urlopen', side_effect=Exception)
|
||||
@patch.object(json, 'load')
|
||||
def test_post_data_with_retry_exception(self, mock_urlopen, mock_load):
|
||||
"""test post data with retry_exception.
|
||||
|
||||
test that post_data throws an exception when trying to send
|
||||
a data for num_of_send_retries
|
||||
"""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = 1
|
||||
time_wait_between_retries = 1
|
||||
audit.init(audit_server_url, num_of_send_retries,
|
||||
time_wait_between_retries)
|
||||
self.assertRaises(AuditException, audit._post_data, None)
|
||||
|
||||
def test_build_query(self):
|
||||
"""test that build_query is exceuted with no exception."""
|
||||
query = "query_1"
|
||||
arg_name = "arg_1"
|
||||
arg_value = "arg_value_1"
|
||||
expected_query = query + "%s=%s&" % (arg_name, arg_value)
|
||||
returned_query = audit._build_query(query, arg_name, arg_value)
|
||||
self.assertEqual(returned_query, expected_query)
|
||||
|
||||
def test_build_query_with_empty_arg_value(self):
|
||||
"""test build query with empty_arg_value.
|
||||
|
||||
test that build_query throws an exception when called
|
||||
with empty arg_value.
|
||||
"""
|
||||
query = "query_1"
|
||||
arg_name = "arg_1"
|
||||
arg_value = None
|
||||
expected_query = query
|
||||
returned_query = audit._build_query(query, arg_name, arg_value)
|
||||
self.assertEqual(returned_query, expected_query)
|
||||
|
||||
@patch.object(threading, 'Thread')
|
||||
def test_audit(self, mock_thread):
|
||||
"""test that audit is exceuted with no exception."""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = 1
|
||||
time_wait_between_retries = 1
|
||||
audit.init(audit_server_url, num_of_send_retries,
|
||||
time_wait_between_retries)
|
||||
timestamp = 111
|
||||
application_id = 'application_id_1'
|
||||
tracking_id = 'tracking_id_1'
|
||||
transaction_id = 'transaction_id_1'
|
||||
transaction_type = 'transaction_type_1'
|
||||
user_id = 'user_id_1'
|
||||
external_id = 'external_id_1'
|
||||
event_details = 'event_details_1'
|
||||
resource_id = 'resource_id_1'
|
||||
service_name = 'service_name_1'
|
||||
audit.audit(timestamp, application_id, tracking_id, transaction_id,
|
||||
transaction_type, resource_id, service_name, user_id,
|
||||
external_id, event_details)
|
||||
|
||||
def test_get_data(self):
|
||||
"""test get data."""
|
||||
audit_server_url = "audit_server_url_1"
|
||||
num_of_send_retries = 1
|
||||
time_wait_between_retries = 1
|
||||
audit.init(audit_server_url, num_of_send_retries,
|
||||
time_wait_between_retries)
|
||||
query = "query1"
|
||||
self.assertRaises(AuditException, audit._get_data, query)
|
2
orm/common/client/audit/babel.cfg
Normal file
2
orm/common/client/audit/babel.cfg
Normal file
@ -0,0 +1,2 @@
|
||||
[python: **.py]
|
||||
|
4
orm/common/client/audit/requirements.txt
Normal file
4
orm/common/client/audit/requirements.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
46
orm/common/client/audit/setup.cfg
Normal file
46
orm/common/client/audit/setup.cfg
Normal file
@ -0,0 +1,46 @@
|
||||
[metadata]
|
||||
name = audit_client
|
||||
summary = This is the Audit Client project
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
home-page = http://www.openstack.org/
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Information Technology
|
||||
Intended Audience :: System Administrators
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.3
|
||||
Programming Language :: Python :: 3.4
|
||||
|
||||
[files]
|
||||
packages =
|
||||
audit_client
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
all_files = 1
|
||||
|
||||
[upload_sphinx]
|
||||
upload-dir = doc/build/html
|
||||
|
||||
[compile_catalog]
|
||||
directory = audit_client/locale
|
||||
domain = audit_client
|
||||
|
||||
[update_catalog]
|
||||
domain = audit_client
|
||||
output_dir = audit_client/locale
|
||||
input_file = audit_client/locale/audit_client.pot
|
||||
|
||||
[extract_messages]
|
||||
keywords = _ gettext ngettext l_ lazy_gettext
|
||||
mapping_file = babel.cfg
|
||||
output_file = audit_client/locale/audit_client.pot
|
33
orm/common/client/audit/setup.py
Normal file
33
orm/common/client/audit/setup.py
Normal file
@ -0,0 +1,33 @@
|
||||
"""setup.py module."""
|
||||
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='audit_client',
|
||||
version='0.1',
|
||||
description='',
|
||||
author='',
|
||||
author_email='',
|
||||
zip_safe=False,
|
||||
include_package_data=True,
|
||||
packages=find_packages(),
|
||||
install_requires=[]
|
||||
)
|
9
orm/common/client/audit/test-requirements.txt
Normal file
9
orm/common/client/audit/test-requirements.txt
Normal file
@ -0,0 +1,9 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
# Hacking already pins down pep8, pyflakes and flake8
|
||||
hacking<0.11,>=0.10.0
|
||||
testrepository>=0.0.18
|
||||
mock<1.1.0,>=1.0
|
||||
coverage>=3.6
|
22
orm/common/client/audit/tox.ini
Normal file
22
orm/common/client/audit/tox.ini
Normal file
@ -0,0 +1,22 @@
|
||||
[tox]
|
||||
envlist = py27, cover, pep8
|
||||
|
||||
[testenv]
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
install_command = pip install -U {opts} {packages}
|
||||
|
||||
commands = python setup.py testr
|
||||
|
||||
[testenv:cover]
|
||||
#omitting rds/api/app.py and rds/examples/api/functional_test.py
|
||||
#since they have no need for unit test
|
||||
commands =
|
||||
python setup.py testr --slowest --coverage --omit=audit_client/examples/*
|
||||
coverage report --omit=audit_client/examples/*
|
||||
|
||||
[testenv:pep8]
|
||||
#cannot handle and 'H102 Apache 2.0 license header not found' and
|
||||
#'H202 assertRaises Exception too broad'
|
||||
#since it requires business code changes
|
||||
commands = flake8
|
@ -1 +0,0 @@
|
||||
aic-orm-keystone/* opt/app/orm/keystone_utils
|
@ -1,5 +0,0 @@
|
||||
aic-orm-keystone (3.5.0) stable; urgency=low
|
||||
|
||||
* this is release 3.5.0
|
||||
|
||||
-- Jenkins job <jenkins@unknown> Thu, 24 Jun 2016 14:48:02 +0000
|
@ -1 +0,0 @@
|
||||
9
|
@ -1,13 +0,0 @@
|
||||
Source: aic-orm-keystone
|
||||
Section: unknown
|
||||
Priority: optional
|
||||
Maintainer: orm <orm@intl.att.com>
|
||||
Build-Depends: debhelper (>= 8.0.0)
|
||||
Standards-Version: 3.9.4
|
||||
XS-Python-Version: >= 2.7
|
||||
Homepage: <insert the upstream URL, if relevant>
|
||||
|
||||
Package: aic-orm-keystone
|
||||
Architecture: any
|
||||
Depends: python-keystoneclient (>= 1.2.0), python-requests (>= 2.2.0)
|
||||
Description: aic-orm-keystone application for ORM
|
@ -1,34 +0,0 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: aic-orm-keystone
|
||||
Source: <url://example.com>
|
||||
|
||||
Files: *
|
||||
Copyright: <years> <put author's name and email here>
|
||||
<years> <likewise for another author>
|
||||
License: GPL-3.0+
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2016 root <root@unknown>
|
||||
License: GPL-3.0+
|
||||
|
||||
License: GPL-3.0+
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
||||
|
||||
# Please also look if there are files or directories which have a
|
||||
# different copyright/license attached and list them here.
|
||||
# Please avoid to pick license terms that are more restrictive than the
|
||||
# packaged work, as it may make Debian's contributions unacceptable upstream.
|
@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#rm -rf /opt/app/orm/keystone_utils
|
||||
#echo "Deleting /opt/app/orm/keystone_utils directory."
|
@ -1,8 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
%:
|
||||
dh $@ --buildsystem=python_distutils -D aic-orm-keystone
|
@ -1 +0,0 @@
|
||||
3.0 (native)
|
@ -1,21 +0,0 @@
|
||||
Metadata-Version: 1.1
|
||||
Name: keystone-utils
|
||||
Version: 0.1
|
||||
Summary: keyKeystone utils
|
||||
Home-page: http://www.openstack.org/
|
||||
Author: OpenStack
|
||||
Author-email: openstack-dev@lists.openstack.org
|
||||
License: UNKNOWN
|
||||
Description: UNKNOWN
|
||||
Platform: UNKNOWN
|
||||
Classifier: Environment :: OpenStack
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: License :: OSI Approved :: Apache Software License
|
||||
Classifier: Operating System :: POSIX :: Linux
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
@ -1,25 +0,0 @@
|
||||
MANIFEST.in
|
||||
README.rst
|
||||
setup.cfg
|
||||
setup.py
|
||||
keystone_utils/__init__.py
|
||||
keystone_utils/tokens.py
|
||||
keystone_utils.egg-info/PKG-INFO
|
||||
keystone_utils.egg-info/SOURCES.txt
|
||||
keystone_utils.egg-info/dependency_links.txt
|
||||
keystone_utils.egg-info/not-zip-safe
|
||||
keystone_utils.egg-info/pbr.json
|
||||
keystone_utils.egg-info/top_level.txt
|
||||
keystone_utils/tests/__init__.py
|
||||
keystone_utils/tests/unit/__init__.py
|
||||
keystone_utils/tests/unit/test_tokens.py
|
||||
mock_keystone/__init__.py
|
||||
mock_keystone/keystoneclient/__init__.py
|
||||
mock_keystone/keystoneclient/exceptions.py
|
||||
mock_keystone/keystoneclient/v2_0/__init__.py
|
||||
mock_keystone/keystoneclient/v2_0/client.py
|
||||
mock_keystone/keystoneclient/v3/__init__.py
|
||||
mock_keystone/keystoneclient/v3/client.py
|
||||
mock_keystone/orm_common/__init__.py
|
||||
mock_keystone/orm_common/utils/__init__.py
|
||||
mock_keystone/orm_common/utils/dictator.py
|
@ -1 +0,0 @@
|
||||
{"is_release": false, "git_version": ""}
|
@ -1,2 +0,0 @@
|
||||
keystone_utils
|
||||
mock_keystone
|
1
orm/services/audit_trail_manager/MANIFEST.in
Normal file
1
orm/services/audit_trail_manager/MANIFEST.in
Normal file
@ -0,0 +1 @@
|
||||
recursive-include public *
|
26
orm/services/audit_trail_manager/audit_server.conf
Normal file
26
orm/services/audit_trail_manager/audit_server.conf
Normal file
@ -0,0 +1,26 @@
|
||||
Listen 8776
|
||||
|
||||
<VirtualHost *:8776>
|
||||
|
||||
WSGIDaemonProcess audit_server user=orm group=orm threads=5
|
||||
WSGIScriptAlias / /opt/app/orm/audit_server/audit_server.wsgi
|
||||
|
||||
<Location /v1/audit/logs>
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
Allow from localhost
|
||||
</Location>
|
||||
|
||||
<Location /v1/audit/configuration>
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
Allow from localhost
|
||||
</Location>
|
||||
|
||||
<Directory /opt/app/orm/audit_server/>
|
||||
WSGIProcessGroup audit_server
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
Require all granted
|
||||
Allow from all
|
||||
</Directory>
|
||||
</VirtualHost>
|
2
orm/services/audit_trail_manager/audit_server.wsgi
Normal file
2
orm/services/audit_trail_manager/audit_server.wsgi
Normal file
@ -0,0 +1,2 @@
|
||||
from pecan.deploy import deploy
|
||||
application = deploy('/opt/app/orm/audit_server/config.py')
|
@ -0,0 +1 @@
|
||||
"""root package."""
|
34
orm/services/audit_trail_manager/audit_server/app.py
Normal file
34
orm/services/audit_trail_manager/audit_server/app.py
Normal file
@ -0,0 +1,34 @@
|
||||
"""app module."""
|
||||
import logging
|
||||
import os
|
||||
|
||||
from pecan import make_app
|
||||
from pecan.commands import CommandRunner
|
||||
from audit_server import model
|
||||
from audit_server.storage import factory
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_app(config):
|
||||
"""setup method."""
|
||||
model.init_model()
|
||||
app_conf = dict(config.app)
|
||||
factory.database_url = config.database.url
|
||||
factory.echo_statements = config.database.echo_statements
|
||||
|
||||
app = make_app(
|
||||
app_conf.pop('root'),
|
||||
logging=getattr(config, 'logging', {}),
|
||||
**app_conf
|
||||
)
|
||||
|
||||
logger.info('Starting Audit...')
|
||||
return app
|
||||
|
||||
def main():
|
||||
dir_name = os.path.dirname(__file__)
|
||||
drive, path_and_file = os.path.splitdrive(dir_name)
|
||||
path, filename = os.path.split(path_and_file)
|
||||
runner = CommandRunner()
|
||||
runner.run(['serve', path+'/config.py'])
|
@ -0,0 +1 @@
|
||||
"""controllers package."""
|
@ -0,0 +1,10 @@
|
||||
"""root controller module."""
|
||||
|
||||
|
||||
from audit_server.controllers.v1 import root as v1
|
||||
|
||||
|
||||
class RootController(object):
|
||||
"""root controller."""
|
||||
|
||||
v1 = v1.V1Controller()
|
@ -0,0 +1 @@
|
||||
"""v1 package."""
|
13
orm/services/audit_trail_manager/audit_server/controllers/v1/audit.py
Executable file
13
orm/services/audit_trail_manager/audit_server/controllers/v1/audit.py
Executable file
@ -0,0 +1,13 @@
|
||||
"""audit controller module."""
|
||||
|
||||
from audit_server.controllers.v1 import configuration
|
||||
from audit_server.controllers.v1 import logs
|
||||
from audit_server.controllers.v1 import transaction
|
||||
|
||||
|
||||
class AuditController(object):
|
||||
"""audit controller."""
|
||||
|
||||
transaction = transaction.TransactionController()
|
||||
logs = logs.LogsController()
|
||||
configuration = configuration.ConfigurationController()
|
@ -0,0 +1,49 @@
|
||||
"""base module for base wsme types and client side errors."""
|
||||
|
||||
|
||||
import wsme
|
||||
from wsme import types as wtypes
|
||||
|
||||
|
||||
class ClientSideError(wsme.exc.ClientSideError):
|
||||
"""base client side error."""
|
||||
|
||||
def __init__(self, error, status_code=400):
|
||||
"""init method..
|
||||
|
||||
:param error: error message to show to the client.
|
||||
:param status_code: status code to show to the client.
|
||||
"""
|
||||
super(ClientSideError, self).__init__(error, status_code)
|
||||
|
||||
|
||||
class InputValueError(ClientSideError):
|
||||
"""input value error."""
|
||||
|
||||
def __init__(self, name, value, status_code=400):
|
||||
"""init method..
|
||||
|
||||
:param name: the input name for which an error was raised.
|
||||
:param value: the input value for which an error was raised.
|
||||
:param status_code: status code to show to the client.
|
||||
"""
|
||||
super(InputValueError, self).__init__(
|
||||
"Invalid value for input {} : {}".format(name, value), status_code)
|
||||
|
||||
|
||||
class EntityNotFoundError(ClientSideError):
|
||||
"""entity not found error."""
|
||||
|
||||
def __init__(self, entity_id):
|
||||
"""init method..
|
||||
|
||||
:param entity_id: the id for which an entity was not found.
|
||||
"""
|
||||
super(EntityNotFoundError, self).__init__(
|
||||
"Entity not found for {}".format(entity_id), status_code=404)
|
||||
|
||||
|
||||
class Base(wtypes.DynamicBase):
|
||||
"""base class for wsme types."""
|
||||
|
||||
pass
|
@ -0,0 +1,28 @@
|
||||
"""Configuration rest API input module."""
|
||||
|
||||
import logging
|
||||
from orm_common.utils import utils
|
||||
from pecan import conf
|
||||
from pecan import rest
|
||||
from wsmeext.pecan import wsexpose
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ConfigurationController(rest.RestController):
|
||||
"""Configuration controller."""
|
||||
|
||||
@wsexpose(str, str, status_code=200)
|
||||
def get(self, dump_to_log='false'):
|
||||
"""get method.
|
||||
|
||||
:param dump_to_log: A boolean string that says whether the
|
||||
configuration should be written to log
|
||||
:return: A pretty string that contains the service's configuration
|
||||
"""
|
||||
logger.info("Get configuration...")
|
||||
|
||||
dump = dump_to_log.lower() == 'true'
|
||||
utils.set_utils_conf(conf)
|
||||
result = utils.report_config(conf, dump, logger)
|
||||
return result
|
@ -0,0 +1,65 @@
|
||||
import logging
|
||||
|
||||
from pecan import rest
|
||||
import wsme
|
||||
from wsmeext.pecan import wsexpose
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LogChangeResultWSME(wsme.types.DynamicBase):
|
||||
"""log change result wsme type."""
|
||||
|
||||
result = wsme.wsattr(str, mandatory=True, default=None)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
""""init method."""
|
||||
super(LogChangeResult, self).__init__(**kwargs)
|
||||
|
||||
|
||||
class LogChangeResult(object):
|
||||
"""log change result type."""
|
||||
|
||||
def __init__(self, result):
|
||||
""""init method."""
|
||||
self.result = result
|
||||
|
||||
|
||||
class LogsController(rest.RestController):
|
||||
"""Logs Audit controller."""
|
||||
|
||||
@wsexpose(LogChangeResultWSME, str, status_code=201,
|
||||
rest_content_types='json')
|
||||
def put(self, level):
|
||||
"""update log level.
|
||||
|
||||
:param level: the log level text name
|
||||
:return:
|
||||
"""
|
||||
|
||||
logger.info("Changing log level to [{}]".format(level))
|
||||
try:
|
||||
log_level = logging._levelNames.get(level.upper())
|
||||
if log_level is not None:
|
||||
self._change_log_level(log_level)
|
||||
result = "Log level changed to {}.".format(level)
|
||||
logger.info(result)
|
||||
else:
|
||||
raise Exception(
|
||||
"The given log level [{}] doesn't exist.".format(level))
|
||||
except Exception as e:
|
||||
result = "Fail to change log_level. Reason: {}".format(
|
||||
e.message)
|
||||
logger.error(result)
|
||||
return LogChangeResult(result)
|
||||
|
||||
@staticmethod
|
||||
def _change_log_level(log_level):
|
||||
path = __name__.split('.')
|
||||
if len(path) > 0:
|
||||
root = path[0]
|
||||
root_logger = logging.getLogger(root)
|
||||
root_logger.setLevel(log_level)
|
||||
else:
|
||||
logger.info("Fail to change log_level to [{}]. "
|
||||
"the given log level doesn't exist.".format(log_level))
|
@ -0,0 +1,10 @@
|
||||
"""v1 controller module."""
|
||||
|
||||
|
||||
from audit_server.controllers.v1 import audit
|
||||
|
||||
|
||||
class V1Controller(object):
|
||||
"""v1 controller."""
|
||||
|
||||
audit = audit.AuditController()
|
203
orm/services/audit_trail_manager/audit_server/controllers/v1/transaction.py
Executable file
203
orm/services/audit_trail_manager/audit_server/controllers/v1/transaction.py
Executable file
@ -0,0 +1,203 @@
|
||||
"""transaction controller module."""
|
||||
|
||||
from audit_server.model.transaction import Model as TransactionModel
|
||||
from audit_server.model.transaction_query import Model as QueryModel
|
||||
from audit_server.services import transaction as transaction_service
|
||||
import base
|
||||
import logging
|
||||
from pecan import rest
|
||||
import wsme
|
||||
from wsme import types as wtypes
|
||||
from wsmeext.pecan import wsexpose
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Transaction(base.Base):
|
||||
"""transaction type."""
|
||||
|
||||
timestamp = wsme.wsattr(long, mandatory=True)
|
||||
user_id = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
application_id = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
tracking_id = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
external_id = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
transaction_id = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
transaction_type = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
event_details = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
resource_id = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
service_name = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""init method."""
|
||||
super(Transaction, self).__init__(**kwargs)
|
||||
|
||||
def to_model(self):
|
||||
"""transform the Transaction to a TransactionModel."""
|
||||
return TransactionModel(self.timestamp,
|
||||
self.user_id,
|
||||
self.application_id,
|
||||
self.tracking_id,
|
||||
self.external_id,
|
||||
self.transaction_id,
|
||||
self.transaction_type,
|
||||
self.event_details,
|
||||
self.resource_id,
|
||||
self.service_name)
|
||||
|
||||
def __str__(self):
|
||||
"""return a string representation of the object."""
|
||||
return "Transaction:[ " \
|
||||
"timestamp={}, " \
|
||||
"user_id={}, " \
|
||||
"application_id={}, " \
|
||||
"tracking_id={}, " \
|
||||
"external_id={}, " \
|
||||
"transaction_id={}," \
|
||||
"transaction_type={}, " \
|
||||
"event_details={}, " \
|
||||
"resource_id={}," \
|
||||
"service_name={}]".format(self.timestamp,
|
||||
self.user_id,
|
||||
self.application_id,
|
||||
self.tracking_id,
|
||||
self.external_id,
|
||||
self.transaction_id,
|
||||
self.transaction_type,
|
||||
self.event_details,
|
||||
self.resource_id,
|
||||
self.service_name)
|
||||
|
||||
|
||||
class Query(base.Base):
|
||||
"""query type."""
|
||||
|
||||
timestamp_from = wsme.wsattr(long, mandatory=False, default=None)
|
||||
timestamp_to = wsme.wsattr(long, mandatory=False, default=None)
|
||||
user_id = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
application_id = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
tracking_id = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
external_id = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
transaction_id = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
transaction_type = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
event_details = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
resource_id = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
service_name = wsme.wsattr(wtypes.text, mandatory=False, default=None)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""init method."""
|
||||
super(Query, self).__init__(**kwargs)
|
||||
|
||||
def to_model(self):
|
||||
"""transform the Query to a QueryModel."""
|
||||
return QueryModel(self.timestamp_from,
|
||||
self.timestamp_to,
|
||||
self.user_id,
|
||||
self.application_id,
|
||||
self.tracking_id,
|
||||
self.external_id,
|
||||
self.transaction_id,
|
||||
self.transaction_type,
|
||||
self.event_details,
|
||||
self.resource_id,
|
||||
self.service_name)
|
||||
|
||||
def __str__(self):
|
||||
"""return a string representation of the object."""
|
||||
return "TransactionQuery:[ " \
|
||||
"timestamp_from={}, " \
|
||||
"timestamp_to={}, " \
|
||||
"user_id={}, " \
|
||||
"application_id={}, " \
|
||||
"tracking_id={}, " \
|
||||
"external_id={}, " \
|
||||
"transaction_id={}," \
|
||||
"transaction_type={}, " \
|
||||
"event_details={}, " \
|
||||
"resource_id={}," \
|
||||
"service_name={}]".format(self.timestamp_from,
|
||||
self.timestamp_to,
|
||||
self.user_id,
|
||||
self.application_id,
|
||||
self.tracking_id,
|
||||
self.external_id,
|
||||
self.transaction_id,
|
||||
self.transaction_type,
|
||||
self.event_details,
|
||||
self.resource_id,
|
||||
self.service_name)
|
||||
|
||||
|
||||
class QueryResult(base.Base):
|
||||
"""query result type."""
|
||||
|
||||
transactions = wsme.wsattr([Transaction], mandatory=False, default=None)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
""""init method."""
|
||||
super(QueryResult, self).__init__(**kwargs)
|
||||
|
||||
|
||||
class TransactionController(rest.RestController):
|
||||
"""Transaction Audit controller."""
|
||||
|
||||
@wsexpose(QueryResult, Query, int, str, rest_content_types='json')
|
||||
def get_all(self, q=None, limit=10, marker=None):
|
||||
"""get all transactions that meet the given query.
|
||||
|
||||
:param q: the query to use in order to search for relevant.
|
||||
transactions.
|
||||
:param limit: the maximun number of transactions to return.
|
||||
:param marker: a place order for pagination (not implemented yet).
|
||||
|
||||
Example of usage:
|
||||
http://127.0.0.1:8777/v1/audit/transaction?q.timestamp_from=1111&q.
|
||||
timestamp_to=5555&q.user_id=user1&q.application_id=SSP&limit=15&
|
||||
marker=1
|
||||
"""
|
||||
logger.debug("Getting audit records...start")
|
||||
logger.info(
|
||||
"Getting audit records for the query:[{}]...start".format(q))
|
||||
model = None
|
||||
if q is not None:
|
||||
model = q.to_model()
|
||||
# page or marker (the last row in the previous page)
|
||||
query_result = transaction_service.get_transactions(model, limit,
|
||||
marker)
|
||||
logger.debug("Getting audit records...end")
|
||||
return query_result
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
@wsexpose(None, body=Transaction, status_code=201,
|
||||
rest_content_types='json')
|
||||
def post(self, transaction_input):
|
||||
"""add a new transaction.
|
||||
|
||||
:param transaction_input: the new transaction values
|
||||
|
||||
Example of usage:
|
||||
http://127.0.0.1:8777/v1/audit/transaction
|
||||
Headers: Content-Type=application/json
|
||||
Body:{
|
||||
"timestamp":111,
|
||||
"user_id":"user1",
|
||||
"application_id":"application_id1",
|
||||
"tracking_id":"tracking_id1",
|
||||
"external_id":"external_id1",
|
||||
"transaction_id":"transaction_id1",
|
||||
"transaction_type":"transaction_type1",
|
||||
"event_details":"event_details1",
|
||||
"status":"status1",
|
||||
"resource_id":"resource_id1",
|
||||
"service_name":"service_name1"
|
||||
}
|
||||
"""
|
||||
logger.debug("Posting new audit record...start")
|
||||
logger.info("Posting new audit record: [{}]".format(
|
||||
transaction_input))
|
||||
model = transaction_input.to_model()
|
||||
transaction_service.add_transaction(model)
|
||||
logger.debug("Auditing record...end")
|
0
orm/common/client/keystone/debian/docs → orm/services/audit_trail_manager/audit_server/external_mock/__init__.py
Executable file → Normal file
0
orm/common/client/keystone/debian/docs → orm/services/audit_trail_manager/audit_server/external_mock/__init__.py
Executable file → Normal file
@ -0,0 +1,13 @@
|
||||
"""Utils module mock."""
|
||||
|
||||
|
||||
def report_config(conf, dump=False):
|
||||
"""Mock report_config function."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def set_utils_conf(conf):
|
||||
"""Mock set_utils_conf function."""
|
||||
|
||||
pass
|
@ -0,0 +1,16 @@
|
||||
"""model package."""
|
||||
|
||||
from pecan import conf # noqa
|
||||
|
||||
|
||||
def init_model():
|
||||
"""Thi is a stub method which is called at application startup time.
|
||||
|
||||
If you need to bind to a parsed database configuration, set up tables or
|
||||
ORM classes, or perform any database initialization, this is the
|
||||
recommended place to do it.
|
||||
|
||||
For more information working with databases, and some common recipes,
|
||||
see http://pecan.readthedocs.org/en/latest/databases.html
|
||||
"""
|
||||
pass
|
47
orm/services/audit_trail_manager/audit_server/model/transaction.py
Executable file
47
orm/services/audit_trail_manager/audit_server/model/transaction.py
Executable file
@ -0,0 +1,47 @@
|
||||
"""transaction model module."""
|
||||
|
||||
|
||||
class Model(object):
|
||||
"""transaction model."""
|
||||
|
||||
def __init__(self, timestamp, user_id, application_id, tracking_id,
|
||||
external_id, transaction_id, transaction_type, event_details,
|
||||
resource_id, service_name):
|
||||
"""init method."""
|
||||
self.timestamp = timestamp
|
||||
self.user_id = user_id
|
||||
self.application_id = application_id
|
||||
self.tracking_id = tracking_id
|
||||
self.external_id = external_id
|
||||
self.transaction_id = transaction_id
|
||||
self.transaction_type = transaction_type
|
||||
self.event_details = event_details
|
||||
self.resource_id = resource_id
|
||||
self.service_name = service_name
|
||||
|
||||
def __str__(self):
|
||||
"""return a string representation of the object."""
|
||||
return "Transaction:[ " \
|
||||
"timestamp={}, " \
|
||||
"user_id={}, " \
|
||||
"application_id={}, " \
|
||||
"tracking_id={}, " \
|
||||
"external_id={}, " \
|
||||
"transaction_id={}," \
|
||||
"transaction_type={}, " \
|
||||
"event_details={}, " \
|
||||
"resource_id={}," \
|
||||
"service_name={}]".format(self.timestamp,
|
||||
self.user_id,
|
||||
self.application_id,
|
||||
self.tracking_id,
|
||||
self.external_id,
|
||||
self.transaction_id,
|
||||
self.transaction_type,
|
||||
self.event_details,
|
||||
self.resource_id,
|
||||
self.service_name)
|
||||
|
||||
def __repr__(self):
|
||||
"""return a string representation of the transaction object."""
|
||||
return str(self)
|
46
orm/services/audit_trail_manager/audit_server/model/transaction_query.py
Executable file
46
orm/services/audit_trail_manager/audit_server/model/transaction_query.py
Executable file
@ -0,0 +1,46 @@
|
||||
"""transaction_query model module."""
|
||||
|
||||
|
||||
class Model(object):
|
||||
"""transaction query model."""
|
||||
|
||||
def __init__(self, timestamp_from, timestamp_to, user_id, application_id,
|
||||
tracking_id, external_id, transaction_id, transaction_type,
|
||||
event_details, resource_id, service_name):
|
||||
"""init method."""
|
||||
self.timestamp_from = timestamp_from
|
||||
self.timestamp_to = timestamp_to
|
||||
self.user_id = user_id
|
||||
self.application_id = application_id
|
||||
self.tracking_id = tracking_id
|
||||
self.external_id = external_id
|
||||
self.transaction_id = transaction_id
|
||||
self.transaction_type = transaction_type
|
||||
self.event_details = event_details
|
||||
self.resource_id = resource_id
|
||||
self.service_name = service_name
|
||||
|
||||
def __str__(self):
|
||||
"""return a string representation of the object."""
|
||||
return "Transaction:[ " \
|
||||
"timestamp_from={}, " \
|
||||
"timestamp_to={}" \
|
||||
"user_id={}, " \
|
||||
"application_id={}, " \
|
||||
"tracking_id={}, " \
|
||||
"external_id={}, " \
|
||||
"transaction_id={}," \
|
||||
"transaction_type={}, " \
|
||||
"event_details={}, " \
|
||||
"resource_id={}," \
|
||||
"service_name={}]".format(self.timestamp_from,
|
||||
self.timestamp_to,
|
||||
self.user_id,
|
||||
self.application_id,
|
||||
self.tracking_id,
|
||||
self.external_id,
|
||||
self.transaction_id,
|
||||
self.transaction_type,
|
||||
self.event_details,
|
||||
self.resource_id,
|
||||
self.service_name)
|
@ -0,0 +1,14 @@
|
||||
"""transaction_query_result model module."""
|
||||
|
||||
|
||||
class Model(object):
|
||||
"""transaction query result model."""
|
||||
|
||||
def __init__(self, transactions):
|
||||
"""init method."""
|
||||
self.transactions = transactions
|
||||
|
||||
def __str__(self):
|
||||
"""return a string representation of the object."""
|
||||
return "TransactionQueryResult:[ " \
|
||||
"transactions={}]".format(self.transactions)
|
@ -0,0 +1 @@
|
||||
"""services package."""
|
@ -0,0 +1,7 @@
|
||||
"""base module for all services, holds errors."""
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""base error class."""
|
||||
|
||||
pass
|
@ -0,0 +1,35 @@
|
||||
"""transaction service module."""
|
||||
|
||||
import logging
|
||||
|
||||
from audit_server.model.transaction_query_result import \
|
||||
Model as QueryResultModel
|
||||
from audit_server.storage import factory
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def add_transaction(transaction):
|
||||
"""add a new transaction.
|
||||
|
||||
:param transaction: the new transaction object.
|
||||
"""
|
||||
logger.debug("Auditing record: [{}] ...start".format(transaction))
|
||||
conn = factory.get_transaction_connection()
|
||||
conn.add_record(transaction)
|
||||
logger.debug("Auditing record...end")
|
||||
|
||||
|
||||
def get_transactions(query, limit, marker):
|
||||
"""get all transactions that meet the given query.
|
||||
|
||||
:param q: the query to use in order to search for relevant.
|
||||
transactions.
|
||||
:param limit: the maximun number of transactions to return.
|
||||
:param marker: a place order for pagination (not implemented yet).
|
||||
"""
|
||||
logger.debug("Getting records for query:{}...start".format(query))
|
||||
conn = factory.get_transaction_connection()
|
||||
transactions = conn.get_records(query, limit, marker)
|
||||
logger.debug("Getting records for query...end")
|
||||
return QueryResultModel(transactions)
|
@ -0,0 +1 @@
|
||||
"""storage package."""
|
@ -0,0 +1,12 @@
|
||||
"""factory module."""
|
||||
|
||||
|
||||
from audit_server.storage.mysql.transaction import Connection as Transaction
|
||||
|
||||
database_url = 'NA'
|
||||
echo_statements = False
|
||||
|
||||
|
||||
def get_transaction_connection():
|
||||
"""return a transaction orm implementation."""
|
||||
return Transaction(database_url, echo_statements)
|
@ -0,0 +1 @@
|
||||
"""mysql package."""
|
168
orm/services/audit_trail_manager/audit_server/storage/mysql/transaction.py
Executable file
168
orm/services/audit_trail_manager/audit_server/storage/mysql/transaction.py
Executable file
@ -0,0 +1,168 @@
|
||||
"""mysql transaction module."""
|
||||
|
||||
import logging
|
||||
|
||||
from sqlalchemy import Column, Integer, Text, BigInteger, asc
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.ext.declarative.api import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from audit_server.model.transaction import Model
|
||||
from audit_server.storage import transaction
|
||||
|
||||
Base = declarative_base()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Record(Base):
|
||||
"""record base class."""
|
||||
|
||||
__tablename__ = 'transactions'
|
||||
|
||||
id = Column(Integer, autoincrement=True, primary_key=True)
|
||||
timestamp = Column(BigInteger)
|
||||
user_id = Column(Text)
|
||||
application_id = Column(Text)
|
||||
tracking_id = Column(Text)
|
||||
external_id = Column(Text)
|
||||
transaction_id = Column(Text)
|
||||
transaction_type = Column(Text)
|
||||
event_details = Column(Text)
|
||||
resource_id = Column(Text)
|
||||
service_name = Column(Text)
|
||||
|
||||
|
||||
class Connection(transaction.Base):
|
||||
"""Implements mysql DB."""
|
||||
|
||||
def __init__(self, url, echo_statements):
|
||||
"""init method."""
|
||||
self._engine = create_engine(url, echo=echo_statements)
|
||||
self._session_maker = sessionmaker(bind=self._engine)
|
||||
pass
|
||||
|
||||
def add_record(self, transaction_record):
|
||||
"""add a new transaction record.
|
||||
|
||||
:param transaction_record: the new transaction record.
|
||||
"""
|
||||
logger.debug(
|
||||
"Auditing record: [{}] ...start".format(transaction_record))
|
||||
try:
|
||||
session = self._session_maker()
|
||||
session.add(Record(timestamp=transaction_record.timestamp,
|
||||
user_id=transaction_record.user_id,
|
||||
application_id=transaction_record.
|
||||
application_id,
|
||||
tracking_id=transaction_record.tracking_id,
|
||||
external_id=transaction_record.external_id,
|
||||
transaction_id=transaction_record.
|
||||
transaction_id,
|
||||
transaction_type=transaction_record.
|
||||
transaction_type,
|
||||
event_details=transaction_record.event_details,
|
||||
resource_id=transaction_record.resource_id,
|
||||
service_name=transaction_record.service_name))
|
||||
session.commit()
|
||||
# All other exceptions will be raised
|
||||
except IntegrityError as e:
|
||||
# Except Exception as e:
|
||||
session.rollback()
|
||||
# Raise the exception only if it's not a duplicate entry exception
|
||||
if 'duplicate entry' in e.message.lower():
|
||||
logger.warning(
|
||||
"Fail to audit record - Duplicate entry: {}".format(
|
||||
e))
|
||||
else:
|
||||
logger.warning("Fail to audit record: {}".format(e))
|
||||
raise e
|
||||
|
||||
finally:
|
||||
session.close()
|
||||
logger.debug("Auditing record...end")
|
||||
|
||||
def get_records(self, query, limit=10, marker=None):
|
||||
"""get all records records that meet the given query.
|
||||
|
||||
:param q: the query to use in order to search for relevant.
|
||||
records.
|
||||
:param limit: the maximun number of records to return.
|
||||
:param marker: a place order for pagination (not implemented yet).
|
||||
"""
|
||||
logger.debug("Getting records using query:[{}]...start".format(query))
|
||||
try:
|
||||
session = self._session_maker()
|
||||
records = session.query(Record)
|
||||
if query is not None:
|
||||
records = Connection._add_filter(records, query, marker)
|
||||
records = records.order_by(asc(Record.timestamp))
|
||||
records = records.limit(limit)
|
||||
records_result = records.all()
|
||||
transactions = []
|
||||
for record in records_result:
|
||||
timestamp = record.timestamp
|
||||
user_id = record.user_id
|
||||
application_id = record.application_id
|
||||
tracking_id = record.tracking_id
|
||||
external_id = record.external_id
|
||||
transaction_id = record.transaction_id
|
||||
transaction_type = record.transaction_type
|
||||
event_details = record.event_details
|
||||
resource_id = record.resource_id
|
||||
service_name = record.service_name
|
||||
model = Model(timestamp, user_id, application_id, tracking_id,
|
||||
external_id, transaction_id, transaction_type,
|
||||
event_details, resource_id, service_name)
|
||||
transactions.append(model)
|
||||
logger.debug(
|
||||
"Getting records using query:[{}] "
|
||||
"return the result :[{}]...start".format(
|
||||
query, transactions))
|
||||
logger.debug("Getting records using query...end")
|
||||
return transactions
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
@staticmethod
|
||||
def _add_filter(records, query, marker):
|
||||
"""add filter to the select based on the given query.
|
||||
|
||||
:param records: the records created so far.
|
||||
:param query: the query to use in order to search for relevant.
|
||||
records.
|
||||
:param marker: a place order for pagination (not implemented yet).
|
||||
"""
|
||||
logger.debug("add_filter for query: [{}] ...start".format(query))
|
||||
if marker is not None:
|
||||
records = records.filter(Record.timestamp > marker)
|
||||
if query.timestamp_from is not None:
|
||||
records = records.filter(Record.timestamp >= query.timestamp_from)
|
||||
if query.timestamp_to is not None:
|
||||
records = records.filter(Record.timestamp <= query.timestamp_to)
|
||||
records = Connection._add_filter_eq(records, Record.user_id,
|
||||
query.user_id)
|
||||
records = Connection._add_filter_eq(records, Record.application_id,
|
||||
query.application_id)
|
||||
records = Connection._add_filter_eq(records, Record.tracking_id,
|
||||
query.tracking_id)
|
||||
records = Connection._add_filter_eq(records, Record.external_id,
|
||||
query.external_id)
|
||||
records = Connection._add_filter_eq(records, Record.transaction_id,
|
||||
query.transaction_id)
|
||||
records = Connection._add_filter_eq(records, Record.transaction_type,
|
||||
query.transaction_type)
|
||||
records = Connection._add_filter_eq(records, Record.event_details,
|
||||
query.event_details)
|
||||
records = Connection._add_filter_eq(records, Record.resource_id,
|
||||
query.resource_id)
|
||||
records = Connection._add_filter_eq(records, Record.service_name,
|
||||
query.service_name)
|
||||
logger.debug("add_filter for query: [{}] ...end".format(query))
|
||||
return records
|
||||
|
||||
@staticmethod
|
||||
def _add_filter_eq(records, key, value):
|
||||
if value is not None:
|
||||
records = records.filter(key == value)
|
||||
return records
|
@ -0,0 +1,17 @@
|
||||
"""transaction interface module."""
|
||||
|
||||
|
||||
class Base(object):
|
||||
"""transaction base class."""
|
||||
|
||||
def __init__(self, url):
|
||||
"""init method."""
|
||||
pass
|
||||
|
||||
def add_record(self, transaction):
|
||||
"""add new transaction record to the db."""
|
||||
raise NotImplementedError("Please Implement this method")
|
||||
|
||||
def get_records(self, query):
|
||||
"""get transactions that meet the given query from the db."""
|
||||
raise NotImplementedError("Please Implement this method")
|
@ -0,0 +1,12 @@
|
||||
<%inherit file="layout.html" />
|
||||
|
||||
## provide definitions for blocks we want to redefine
|
||||
<%def name="title()">
|
||||
Server Error ${status}
|
||||
</%def>
|
||||
|
||||
## now define the body of the template
|
||||
<header>
|
||||
<h1>Server Error ${status}</h1>
|
||||
</header>
|
||||
<p>${message}</p>
|
@ -0,0 +1,34 @@
|
||||
<%inherit file="layout.html" />
|
||||
|
||||
## provide definitions for blocks we want to redefine
|
||||
<%def name="title()">
|
||||
Welcome to Pecan!
|
||||
</%def>
|
||||
|
||||
## now define the body of the template
|
||||
<header>
|
||||
<h1><img src="/images/logo.png" /></h1>
|
||||
</header>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<p>This is a sample Pecan project.</p>
|
||||
|
||||
<p>
|
||||
Instructions for getting started can be found online at <a
|
||||
href="http://pecanpy.org" target="window">pecanpy.org</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
...or you can search the documentation here:
|
||||
</p>
|
||||
|
||||
<form method="POST" action="/">
|
||||
<fieldset>
|
||||
<input name="q" />
|
||||
<input type="submit" value="Search" />
|
||||
</fieldset>
|
||||
<small>Enter search terms or a module, class or function name.</small>
|
||||
</form>
|
||||
|
||||
</div>
|
@ -0,0 +1,22 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>${self.title()}</title>
|
||||
${self.style()}
|
||||
${self.javascript()}
|
||||
</head>
|
||||
<body>
|
||||
${self.body()}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<%def name="title()">
|
||||
Default Title
|
||||
</%def>
|
||||
|
||||
<%def name="style()">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/style.css" />
|
||||
</%def>
|
||||
|
||||
<%def name="javascript()">
|
||||
<script language="text/javascript" src="/javascript/shared.js"></script>
|
||||
</%def>
|
@ -0,0 +1 @@
|
||||
"""test package."""
|
@ -0,0 +1 @@
|
||||
"""controllers package."""
|
@ -0,0 +1,154 @@
|
||||
"""Base classes for API tests."""
|
||||
|
||||
import pecan
|
||||
import pecan.testing
|
||||
import unittest
|
||||
|
||||
|
||||
class FunctionalTest(unittest.TestCase):
|
||||
"""Used for functional tests of Pecan controllers.
|
||||
|
||||
Used in case when you need to test your literal application and its
|
||||
integration with the framework.
|
||||
"""
|
||||
|
||||
PATH_PREFIX = ''
|
||||
|
||||
def setUp(self):
|
||||
"""set up method."""
|
||||
self.app = self._make_app()
|
||||
|
||||
def _make_app(self, enable_acl=False):
|
||||
"""make app method."""
|
||||
self.config = {
|
||||
'app': {
|
||||
'root': 'audit_server.controllers.root.RootController',
|
||||
'modules': ['audit_server']
|
||||
},
|
||||
'wsme': {
|
||||
'debug': True,
|
||||
},
|
||||
'database': {
|
||||
'url': 'mysql://dummy:dummy@1.1.1.1/orm_audit?charset=utf8',
|
||||
'echo_statements': False
|
||||
}
|
||||
}
|
||||
|
||||
return pecan.testing.load_test_app(self.config)
|
||||
|
||||
def tearDown(self):
|
||||
"""tear down method."""
|
||||
super(FunctionalTest, self).tearDown()
|
||||
pecan.set_config({}, overwrite=True)
|
||||
|
||||
def put_json(self, path, params, expect_errors=False, headers=None,
|
||||
extra_environ=None, status=None):
|
||||
"""Send simulated HTTP PUT request to Pecan test app.
|
||||
|
||||
:param path: url path of target service
|
||||
:param params: content for wsgi.input of request
|
||||
:param expect_errors: boolean value whether an error is expected based
|
||||
on request
|
||||
:param headers: A dictionary of headers to send along with the request
|
||||
:param extra_environ: A dictionary of environ variables to send along
|
||||
with the request
|
||||
:param status: Expected status code of response
|
||||
"""
|
||||
return self.post_json(path=path, params=params,
|
||||
expect_errors=expect_errors,
|
||||
headers=headers, extra_environ=extra_environ,
|
||||
status=status, method="put")
|
||||
|
||||
def post_json(self, path, params, expect_errors=False, headers=None,
|
||||
method="post", extra_environ=None, status=None):
|
||||
"""Send simulated HTTP POST request to Pecan test app.
|
||||
|
||||
:param path: url path of target service
|
||||
:param params: content for wsgi.input of request
|
||||
:param expect_errors: boolean value whether an error is expected based
|
||||
on request
|
||||
:param headers: A dictionary of headers to send along with the request
|
||||
:param method: Request method type. Appropriate method function call
|
||||
should be used rather than passing attribute in.
|
||||
:param extra_environ: A dictionary of environ variables to send along
|
||||
with the request
|
||||
:param status: Expected status code of response
|
||||
"""
|
||||
full_path = self.PATH_PREFIX + path
|
||||
response = getattr(self.app, "%s_json" % method)(
|
||||
str(full_path),
|
||||
params=params,
|
||||
headers=headers,
|
||||
status=status,
|
||||
extra_environ=extra_environ,
|
||||
expect_errors=expect_errors
|
||||
)
|
||||
return response
|
||||
|
||||
def delete(self, path, expect_errors=False, headers=None,
|
||||
extra_environ=None, status=None):
|
||||
"""Send simulated HTTP DELETE request to Pecan test app.
|
||||
|
||||
:param path: url path of target service
|
||||
:param expect_errors: boolean value whether an error is expected based
|
||||
on request
|
||||
:param headers: A dictionary of headers to send along with the request
|
||||
:param extra_environ: A dictionary of environ variables to send along
|
||||
with the request
|
||||
:param status: Expected status code of response
|
||||
"""
|
||||
full_path = self.PATH_PREFIX + path
|
||||
response = self.app.delete(str(full_path),
|
||||
headers=headers,
|
||||
status=status,
|
||||
extra_environ=extra_environ,
|
||||
expect_errors=expect_errors)
|
||||
return response
|
||||
|
||||
def get_json(self, path, expect_errors=False, headers=None,
|
||||
extra_environ=None, q=None, groupby=None, status=None,
|
||||
override_params=None, **params):
|
||||
"""Send simulated HTTP GET request to Pecan test app.
|
||||
|
||||
:param path: url path of target service
|
||||
:param expect_errors: boolean value whether an error is expected based
|
||||
on request
|
||||
:param headers: A dictionary of headers to send along with the request
|
||||
:param extra_environ: A dictionary of environ variables to send along
|
||||
with the request
|
||||
:param q: list of queries consisting of: field, value, op, and type
|
||||
keys
|
||||
:param groupby: list of fields to group by
|
||||
:param status: Expected status code of response
|
||||
:param override_params: literally encoded query param string
|
||||
:param params: content for wsgi.input of request
|
||||
"""
|
||||
q = q or []
|
||||
groupby = groupby or []
|
||||
full_path = self.PATH_PREFIX + path
|
||||
if override_params:
|
||||
all_params = override_params
|
||||
else:
|
||||
query_params = {'q.field': [],
|
||||
'q.value': [],
|
||||
'q.op': [],
|
||||
'q.type': [],
|
||||
}
|
||||
for query in q:
|
||||
for name in ['field', 'op', 'value', 'type']:
|
||||
query_params['q.%s' % name].append(query.get(name, ''))
|
||||
all_params = {}
|
||||
all_params.update(params)
|
||||
if q:
|
||||
all_params.update(query_params)
|
||||
if groupby:
|
||||
all_params.update({'groupby': groupby})
|
||||
response = self.app.get(full_path,
|
||||
params=all_params,
|
||||
headers=headers,
|
||||
extra_environ=extra_environ,
|
||||
expect_errors=expect_errors,
|
||||
status=status)
|
||||
if not expect_errors:
|
||||
response = response.json
|
||||
return response
|
@ -0,0 +1 @@
|
||||
"""v1 package."""
|
@ -0,0 +1,10 @@
|
||||
"""functional_test module."""
|
||||
|
||||
|
||||
from audit_server.tests.controllers.functional_test import FunctionalTest
|
||||
|
||||
|
||||
class FunctionalTest(FunctionalTest):
|
||||
"""base functional test class."""
|
||||
|
||||
PATH_PREFIX = '/v1'
|
@ -0,0 +1,38 @@
|
||||
"""test_base module."""
|
||||
|
||||
|
||||
from audit_server.controllers.v1.base import ClientSideError
|
||||
from audit_server.controllers.v1.base import EntityNotFoundError
|
||||
from audit_server.controllers.v1.base import InputValueError
|
||||
import unittest
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test case class."""
|
||||
|
||||
def test_init_ClientSideError(self):
|
||||
"""test the init method."""
|
||||
expected_msg = "This is an error"
|
||||
expected_code = 400
|
||||
error = ClientSideError(expected_msg)
|
||||
self.assertEqual(error.msg, expected_msg)
|
||||
self.assertEqual(error.code, expected_code)
|
||||
|
||||
def test_init_InputValueError(self):
|
||||
"""test the init method."""
|
||||
name = "name1"
|
||||
value = "value1"
|
||||
expected_msg = "Invalid value for input {} : {}".format(name, value)
|
||||
expected_code = 400
|
||||
error = InputValueError(name, value)
|
||||
self.assertEqual(error.msg, expected_msg)
|
||||
self.assertEqual(error.code, expected_code)
|
||||
|
||||
def test_init_EntityNotFoundError(self):
|
||||
"""test the init method."""
|
||||
id = "id1"
|
||||
expected_msg = "Entity not found for {}".format(id)
|
||||
expected_code = 404
|
||||
error = EntityNotFoundError(id)
|
||||
self.assertEqual(error.msg, expected_msg)
|
||||
self.assertEqual(error.code, expected_code)
|
@ -0,0 +1,14 @@
|
||||
"""Get configuration module unittests."""
|
||||
from audit_server.controllers.v1 import configuration as root
|
||||
from audit_server.tests.controllers.v1.functional_test import FunctionalTest
|
||||
from mock import patch
|
||||
|
||||
|
||||
class TestGetConfiguration(FunctionalTest):
|
||||
"""Main get configuration test case."""
|
||||
|
||||
@patch.object(root.utils, 'report_config', return_value='12345')
|
||||
def test_get_configuration_success(self, input):
|
||||
"""Test get_configuration returns the expected value on success."""
|
||||
response = self.app.get('/v1/audit/configuration')
|
||||
self.assertEqual(response.json, '12345')
|
@ -0,0 +1,25 @@
|
||||
"""Logs module unittests."""
|
||||
from audit_server.tests.controllers.v1.functional_test import FunctionalTest
|
||||
|
||||
|
||||
class TestLogs(FunctionalTest):
|
||||
"""logs tests."""
|
||||
|
||||
def test_change_log_level_fail(self):
|
||||
response = self.app.put('/v1/audit/logs/1')
|
||||
expected_result = {
|
||||
"result": "Fail to change log_level. Reason: "
|
||||
"The given log level [1] doesn't exist."}
|
||||
self.assertEqual(expected_result, response.json)
|
||||
|
||||
def test_change_log_level_none(self):
|
||||
response = self.app.put('/v1/audit/logs', expect_errors=True)
|
||||
expected_result = 'Missing argument: "level"'
|
||||
self.assertEqual(response.json["faultstring"], expected_result)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def test_change_log_level_success(self):
|
||||
response = self.app.put('/v1/audit/logs/debug')
|
||||
expected_result = {'result': 'Log level changed to debug.'}
|
||||
self.assertEqual(response.json, expected_result)
|
||||
self.assertEqual(response.status_code, 201)
|
@ -0,0 +1,97 @@
|
||||
"""test_transaction module."""
|
||||
|
||||
|
||||
from mock import patch
|
||||
|
||||
from audit_server.controllers.v1.transaction import QueryResult
|
||||
from audit_server.model.transaction import Model as TransactionModel
|
||||
from audit_server.model.transaction_query_result import \
|
||||
Model as TransactionQueryResultModel
|
||||
from audit_server.services import transaction as transaction_service
|
||||
from audit_server.tests.controllers.v1.functional_test import FunctionalTest
|
||||
|
||||
|
||||
class Test(FunctionalTest):
|
||||
"""test transaction class."""
|
||||
|
||||
transaction_model = TransactionModel(timestamp=111, user_id="user_id_1",
|
||||
application_id="application_id_1",
|
||||
tracking_id="tracking_id_1",
|
||||
external_id="external_id_1",
|
||||
transaction_id="transaction_id_1",
|
||||
transaction_type="transaction_type_1",
|
||||
event_details="event_details_1",
|
||||
resource_id="resource_id_1",
|
||||
service_name="service_name_1")
|
||||
|
||||
@patch.object(transaction_service, 'get_transactions',
|
||||
return_value=TransactionQueryResultModel(
|
||||
[transaction_model]))
|
||||
def test_get_all(self, mock_get_transactions):
|
||||
"""test that get_one returns an appropriate json result."""
|
||||
url = "/audit/transaction?q.timestamp_from=1111&q.timestamp_to=5555&" \
|
||||
"q.user_id=user1&q.application_id=SSP&limit=15&marker=1"
|
||||
output = self.get_json(url)
|
||||
returned_transactions = output['transactions']
|
||||
self.assertIsNotNone(returned_transactions)
|
||||
self.assertEqual(len(returned_transactions), 1)
|
||||
transaction = returned_transactions[0]
|
||||
self._assert_returned_transaction(transaction)
|
||||
|
||||
@patch.object(transaction_service, 'get_transactions',
|
||||
return_value=TransactionQueryResultModel(
|
||||
[transaction_model]))
|
||||
def test_get_all_with_empty_query(self, mock_get_transactions):
|
||||
"""Test that get_one accepts an empty query and returns a response."""
|
||||
url = "/audit/transaction?limit=15&marker=1"
|
||||
output = self.get_json(url)
|
||||
returned_transactions = output['transactions']
|
||||
self.assertIsNotNone(returned_transactions)
|
||||
self.assertEqual(len(returned_transactions), 1)
|
||||
transaction = returned_transactions[0]
|
||||
self._assert_returned_transaction(transaction)
|
||||
|
||||
@patch.object(transaction_service, 'add_transaction')
|
||||
def test_post(self, mock_transaction_service):
|
||||
"""Test that post is executed with no exceptions."""
|
||||
url = "/audit/transaction"
|
||||
body = {
|
||||
"timestamp": 111,
|
||||
"user_id": "user_1",
|
||||
"application_id": "application_id_1",
|
||||
"tracking_id": "tracking_id_1",
|
||||
"external_id": "external_id_1",
|
||||
"transaction_id": "transaction_id_1",
|
||||
"transaction_type": "transaction_type_1",
|
||||
"event_details": "event_details_1",
|
||||
"resource_id": "resource_id_1",
|
||||
"service_name": "service_name_1"
|
||||
}
|
||||
self.post_json(url, body)
|
||||
|
||||
def test_init_QueryResult(self):
|
||||
"""test the init method."""
|
||||
QueryResult(**{"prop1": "value1", "prop2": "value2"})
|
||||
|
||||
def _assert_returned_transaction(self, transaction):
|
||||
"""Check the returned trasaction."""
|
||||
self.assertEqual(transaction['timestamp'],
|
||||
self.transaction_model.timestamp)
|
||||
self.assertEqual(transaction['user_id'],
|
||||
self.transaction_model.user_id)
|
||||
self.assertEqual(transaction['application_id'],
|
||||
self.transaction_model.application_id)
|
||||
self.assertEqual(transaction['tracking_id'],
|
||||
self.transaction_model.tracking_id)
|
||||
self.assertEqual(transaction['external_id'],
|
||||
self.transaction_model.external_id)
|
||||
self.assertEqual(transaction['transaction_id'],
|
||||
self.transaction_model.transaction_id)
|
||||
self.assertEqual(transaction['transaction_type'],
|
||||
self.transaction_model.transaction_type)
|
||||
self.assertEqual(transaction['event_details'],
|
||||
self.transaction_model.event_details)
|
||||
self.assertEqual(transaction['resource_id'],
|
||||
self.transaction_model.resource_id)
|
||||
self.assertEqual(transaction['service_name'],
|
||||
self.transaction_model.service_name)
|
@ -0,0 +1 @@
|
||||
"""model package."""
|
@ -0,0 +1,19 @@
|
||||
"""test_transaction_query_result module."""
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
from audit_server.model.transaction_query_result import \
|
||||
Model as TransactionQueryResultModel
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test transaction query result class."""
|
||||
|
||||
def test_str(self):
|
||||
"""test str method."""
|
||||
transactions = []
|
||||
model = TransactionQueryResultModel(transactions)
|
||||
self.assertEqual(str(model),
|
||||
"TransactionQueryResult:[ transactions={}]".format(
|
||||
transactions))
|
@ -0,0 +1 @@
|
||||
"""services package."""
|
@ -0,0 +1,14 @@
|
||||
"""test_base module."""
|
||||
|
||||
|
||||
from audit_server.services.base import Error
|
||||
import unittest
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test base class."""
|
||||
|
||||
def test_init_Error(self):
|
||||
"""Test that init of Error succeeded."""
|
||||
Error("test")
|
||||
pass
|
@ -0,0 +1,56 @@
|
||||
"""test_transaction module."""
|
||||
|
||||
import unittest
|
||||
|
||||
from mock import patch
|
||||
|
||||
from audit_server.model.transaction import Model as TransactionModel
|
||||
from audit_server.model.transaction_query import Model as TransactionQuery
|
||||
from audit_server.services import transaction as TransactionService
|
||||
from audit_server.storage import factory
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test transaction class."""
|
||||
|
||||
@patch.object(factory, 'get_transaction_connection')
|
||||
def test_add_transaction(self, mock_factory):
|
||||
"""test that add_transaction doesn't throws any exception."""
|
||||
timestamp = 111
|
||||
user_id = "user_id_1"
|
||||
application_id = "application_id_1"
|
||||
tracking_id = "tracking_id_1"
|
||||
external_id = "external_id_1"
|
||||
transaction_id = "transaction_id_1"
|
||||
transaction_type = "transaction_type_1"
|
||||
event_details = "event_details_1"
|
||||
resource_id = "resource_id_1"
|
||||
service_name = "service_name_1"
|
||||
transaction = TransactionModel(timestamp, user_id, application_id,
|
||||
tracking_id, external_id,
|
||||
transaction_id, transaction_type,
|
||||
event_details, resource_id,
|
||||
service_name)
|
||||
TransactionService.add_transaction(transaction)
|
||||
|
||||
@patch.object(factory, 'get_transaction_connection')
|
||||
def test_get_transaction(query, mock_factory):
|
||||
"""test that get_transaction doesn't throws any exception."""
|
||||
timestamp_from = 111
|
||||
timestamp_to = 555
|
||||
user_id = "user_id_1"
|
||||
application_id = "application_id_1"
|
||||
tracking_id = "tracking_id_1"
|
||||
external_id = "external_id_1"
|
||||
transaction_id = "transaction_id_1"
|
||||
transaction_type = "transaction_type_1"
|
||||
event_details = "event_details_1"
|
||||
resource_id = "resource_id_1"
|
||||
service_name = "service_name_1"
|
||||
query = TransactionQuery(timestamp_from, timestamp_to, user_id,
|
||||
application_id, tracking_id, external_id,
|
||||
transaction_id, transaction_type,
|
||||
event_details, resource_id, service_name)
|
||||
limit = 10
|
||||
marker = 1
|
||||
TransactionService.get_transactions(query, limit, marker)
|
@ -0,0 +1 @@
|
||||
"""storage package."""
|
@ -0,0 +1 @@
|
||||
"""mysql package."""
|
@ -0,0 +1,226 @@
|
||||
"""test_transaction module."""
|
||||
|
||||
import unittest
|
||||
|
||||
from mock import patch
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
|
||||
from audit_server.model.transaction import Model as TransactionModel
|
||||
from audit_server.model.transaction_query import Model as TransactionQueryModel
|
||||
from audit_server.storage.mysql.transaction import Connection
|
||||
from audit_server.storage.mysql.transaction import Record
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test transaction class."""
|
||||
|
||||
transaction = TransactionModel(timestamp=111, user_id="user_id_1",
|
||||
application_id="application_id_1",
|
||||
tracking_id="tracking_id_1",
|
||||
external_id="external_id_1",
|
||||
transaction_id="transaction_id_1",
|
||||
transaction_type="transaction_type_1",
|
||||
event_details="event_details_1",
|
||||
resource_id="resource_id_1",
|
||||
service_name="service_name_1")
|
||||
|
||||
transaction_query = TransactionQueryModel(111, 222, "user_id1",
|
||||
"application_id1",
|
||||
"tracking_id1",
|
||||
"external_id1",
|
||||
"transaction_id1",
|
||||
"transaction_type1",
|
||||
"event_details1",
|
||||
"resource_id_1",
|
||||
"service_name_1")
|
||||
|
||||
@patch.object(create_engine, '__init__')
|
||||
@patch.object(sessionmaker, '__init__')
|
||||
def setUp(self, mock_engine, mock_sessionmaker):
|
||||
"""setup method."""
|
||||
self.mock_engine = mock_engine
|
||||
self.mock_sessionmaker = mock_sessionmaker
|
||||
self.conn = object.__new__(Connection)
|
||||
self.conn._engine = self.mock_engine
|
||||
self.conn._session_maker = self.mock_sessionmaker
|
||||
|
||||
def test_add_record(self):
|
||||
"""test add record.
|
||||
|
||||
test that no exception/error is thrown when calling the
|
||||
add_record execution.
|
||||
"""
|
||||
self.conn.add_record(self.transaction)
|
||||
|
||||
def test_add_record_duplicate_entry(self):
|
||||
"""test duplicate entries to add record.
|
||||
|
||||
test that when session.add throws Duplicate Entry exception,
|
||||
no expcetion is thrown back.
|
||||
"""
|
||||
side_effect = IntegrityError(None, None, None, None)
|
||||
side_effect.message = "Duplicate entry"
|
||||
mock_session = self.mock_sessionmaker.return_value.__call__
|
||||
mock_add = mock_session.im_self.add
|
||||
mock_add.side_effect = side_effect
|
||||
self.conn.add_record(self.transaction)
|
||||
|
||||
def test_add_record_integrity_entry(self):
|
||||
"""test add record that throws integrity error.
|
||||
|
||||
test that when session.add throws a different exception
|
||||
than Duplicate Entry it will be rasied up.
|
||||
"""
|
||||
side_effect = IntegrityError(None, None, None, None)
|
||||
side_effect.message = "Some other integrity error"
|
||||
mock_session = self.mock_sessionmaker.return_value.__call__
|
||||
mock_add = mock_session.im_self.add
|
||||
mock_add.side_effect = IntegrityError("Some other integrity error",
|
||||
None, None, None)
|
||||
self.assertRaises(IntegrityError, self.conn.add_record,
|
||||
self.transaction)
|
||||
|
||||
def test_get_records(self):
|
||||
"""test get records.
|
||||
|
||||
test that get_records returns a list and that
|
||||
no exception/error is thrown.
|
||||
"""
|
||||
# mock record
|
||||
record = Record()
|
||||
record.id = 1
|
||||
record.timestamp = 111
|
||||
record.user_id = "user_id1"
|
||||
record.application_id = "application_id1"
|
||||
record.tracking_id = "tracking_id1"
|
||||
record.external_id = "external_id1"
|
||||
record.transaction_id = "transaction_id1"
|
||||
record.transaction_type = "transaction_type1"
|
||||
record.event_details = "event_details1"
|
||||
|
||||
mock_returned_records = [record]
|
||||
|
||||
# The transaction query above will result in the following method call:
|
||||
# EngineFacade().get_session().query().filter().filter().filter().
|
||||
# filter().filter().filter().filter().filter().filter().filter().
|
||||
# order_by().limit() Therefore we will need to mock the entire
|
||||
# call tree in order to set the required returned value
|
||||
mock_session = self.mock_sessionmaker.return_value.__call__
|
||||
mock_query = mock_session.im_self.query
|
||||
mock_filter = mock_query.return_value.filter
|
||||
for key in range(len(self.transaction_query.__dict__.keys()) - 1):
|
||||
mock_filter = mock_filter.return_value.filter
|
||||
mock_order_by = mock_filter.return_value.order_by
|
||||
mock_limit = mock_order_by.return_value.limit
|
||||
mock_all = mock_limit.return_value.all
|
||||
mock_all.return_value = mock_returned_records
|
||||
|
||||
returned_records = self.conn.get_records(self.transaction_query)
|
||||
|
||||
self.assertIsNotNone(returned_records)
|
||||
self.assertIsInstance(returned_records, list)
|
||||
# Check that the list is not empty
|
||||
self.assertTrue(returned_records)
|
||||
# Compare the return record value with the expected value
|
||||
self.assertTrue(len(returned_records), len(mock_returned_records))
|
||||
self.assertEqual(returned_records[0].timestamp,
|
||||
mock_returned_records[0].timestamp)
|
||||
self.assertEqual(returned_records[0].user_id,
|
||||
mock_returned_records[0].user_id)
|
||||
self.assertEqual(returned_records[0].application_id,
|
||||
mock_returned_records[0].application_id)
|
||||
self.assertEqual(returned_records[0].tracking_id,
|
||||
mock_returned_records[0].tracking_id)
|
||||
self.assertEqual(returned_records[0].external_id,
|
||||
mock_returned_records[0].external_id)
|
||||
self.assertEqual(returned_records[0].transaction_id,
|
||||
mock_returned_records[0].transaction_id)
|
||||
self.assertEqual(returned_records[0].transaction_type,
|
||||
mock_returned_records[0].transaction_type)
|
||||
self.assertEqual(returned_records[0].event_details,
|
||||
mock_returned_records[0].event_details)
|
||||
|
||||
def test_get_records_returns_none(self):
|
||||
"""test get records return none.
|
||||
|
||||
Test get_records will return empty list when session
|
||||
returns empty list.
|
||||
"""
|
||||
mock_session = self.mock_engine.return_value.get_session
|
||||
mock_query = mock_session.return_value.query
|
||||
mock_filter_by = mock_query.return_value.filter_by
|
||||
mock_order_by = mock_filter_by.return_value.order_by
|
||||
mock_first = mock_order_by.return_value.first
|
||||
mock_first.return_value = []
|
||||
returned_records = self.conn.get_records(self.transaction_query)
|
||||
self.assertIsNotNone(returned_records)
|
||||
self.assertIsInstance(returned_records, list)
|
||||
# Check that the list is empty
|
||||
self.assertTrue(not returned_records)
|
||||
|
||||
def test_get_records_with_empty_query(self):
|
||||
"""test get record with empty query.
|
||||
|
||||
test get_records with empty query will not throw an exception
|
||||
and will returns a result.
|
||||
"""
|
||||
transaction_query = None
|
||||
self.conn.get_records(transaction_query)
|
||||
|
||||
def test_add_filter(self):
|
||||
"""test that add_filter is executed with no exceptions/error."""
|
||||
marker = 5
|
||||
session = self.mock_engine.get_session()
|
||||
records = session.query(Record)
|
||||
records = self.conn._add_filter(records, self.transaction_query,
|
||||
marker)
|
||||
|
||||
def test_add_filter_with_timestamp_empty(self):
|
||||
"""test add filter with empty timestamp.
|
||||
|
||||
test that add_filter is executed with no exceptions/error
|
||||
when timestamp_from and timestamp_to are empty.
|
||||
"""
|
||||
timestamp_from = None
|
||||
timestamp_to = None
|
||||
user_id = "user_id_1"
|
||||
application_id = "application_id_1"
|
||||
tracking_id = "tracking_id_1"
|
||||
external_id = "external_id_1"
|
||||
transaction_id = "transaction_id_1"
|
||||
transaction_type = "transaction_type_1"
|
||||
event_details = "event_details_1"
|
||||
resource_id = "resource_id_1"
|
||||
service_name = "service_name_1"
|
||||
query = TransactionQueryModel(timestamp_from, timestamp_to, user_id,
|
||||
application_id, tracking_id,
|
||||
external_id, transaction_id,
|
||||
transaction_type, event_details,
|
||||
resource_id, service_name)
|
||||
marker = 5
|
||||
session = self.mock_engine.get_session()
|
||||
records = session.query(Record)
|
||||
records = self.conn._add_filter(records, query, marker)
|
||||
|
||||
def test_add_filter_eq(self):
|
||||
"""test that add_filter_eq will not throw an exception."""
|
||||
session = self.mock_engine.get_session()
|
||||
records = session.query(Record)
|
||||
key = "key1"
|
||||
value = "value1"
|
||||
records = self.conn._add_filter_eq(records, key, value)
|
||||
|
||||
def test_add_filter_eq_with_empty_value(self):
|
||||
"""test add filter with empty value.
|
||||
|
||||
test that add_filter_eq will not throw an exception
|
||||
when value is None.
|
||||
"""
|
||||
session = self.mock_engine.get_session()
|
||||
records = session.query(Record)
|
||||
key = "key1"
|
||||
value = None
|
||||
records = self.conn._add_filter_eq(records, key, value)
|
@ -0,0 +1,25 @@
|
||||
"""test_factory module."""
|
||||
|
||||
from audit_server.storage import factory
|
||||
from audit_server.storage.mysql.transaction import Connection
|
||||
from mock import patch
|
||||
from sqlalchemy import create_engine
|
||||
import unittest
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test factory class."""
|
||||
|
||||
@patch.object(create_engine, '__init__')
|
||||
def test_get_get_transaction_connection(self, mock_engine):
|
||||
"""test get_zone_resource_type_status.
|
||||
|
||||
test that get_zone_resource_type_status_connection returns
|
||||
an instance of type ZoneResourceTypeStatusConnection.
|
||||
"""
|
||||
factory.database_url = 'mysql://root:stack@127.0.0.1/orm_audit?' \
|
||||
'charset=utf8'
|
||||
factory.echo_statements = False
|
||||
mock_engine.get_session.return_value = None
|
||||
conn = factory.get_transaction_connection()
|
||||
self.assertIsInstance(conn, Connection)
|
@ -0,0 +1,21 @@
|
||||
"""test_transaction module."""
|
||||
|
||||
|
||||
from audit_server.storage.transaction import Base
|
||||
import unittest
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"""test transaction class."""
|
||||
|
||||
def test_add_record(self):
|
||||
"""test that add_record throws an NotImplementedError exception."""
|
||||
baseConn = Base("test_url")
|
||||
self.assertRaises(NotImplementedError, baseConn.add_record,
|
||||
transaction=None)
|
||||
|
||||
def test_get_latest_record(self):
|
||||
"""test that add_record throws an NotImplementedError exception."""
|
||||
baseConn = Base("test_url")
|
||||
self.assertRaises(NotImplementedError, baseConn.get_records,
|
||||
query=None)
|
175
orm/services/audit_trail_manager/audit_server_docs/audit_server_swagger.yaml
Executable file
175
orm/services/audit_trail_manager/audit_server_docs/audit_server_swagger.yaml
Executable file
@ -0,0 +1,175 @@
|
||||
# This is the Audit Server API
|
||||
swagger: '2.0'
|
||||
info:
|
||||
title: Audit Server API
|
||||
description: Audit Server service
|
||||
version: "1.0.0"
|
||||
# the domain of the service
|
||||
host: server
|
||||
# array of all schemes that your API supports
|
||||
schemes:
|
||||
- http
|
||||
# will be prefixed to all paths
|
||||
basePath: /v1
|
||||
produces:
|
||||
- application/json
|
||||
paths:
|
||||
/audit/transaction:
|
||||
get:
|
||||
summary: get audit transactions
|
||||
description: |
|
||||
Returns transactions that meet the query.
|
||||
parameters:
|
||||
- name: q.timestamp_from
|
||||
in: query
|
||||
description: Transaction from timestamp.
|
||||
required: false
|
||||
type: number
|
||||
format: long
|
||||
- name: q.timestamp_to
|
||||
in: query
|
||||
description: Transaction to timestamp.
|
||||
required: false
|
||||
type: number
|
||||
format: long
|
||||
- name: q.user_id
|
||||
in: query
|
||||
description: Transaction user id.
|
||||
required: false
|
||||
type: string
|
||||
- name: q.application_id
|
||||
in: query
|
||||
description: Transaction application id.
|
||||
required: false
|
||||
type: string
|
||||
- name: q.tracking_id
|
||||
in: query
|
||||
description: Transaction tracking id.
|
||||
required: false
|
||||
type: string
|
||||
- name: q.external_id
|
||||
in: query
|
||||
description: Transaction external id.
|
||||
required: false
|
||||
type: string
|
||||
- name: q.transaction_id
|
||||
in: query
|
||||
description: Transaction transaction id.
|
||||
required: false
|
||||
type: string
|
||||
- name: q.transaction_type
|
||||
in: query
|
||||
description: Transaction transaction type.
|
||||
required: false
|
||||
type: string
|
||||
- name: q.event_details
|
||||
in: query
|
||||
description: Transaction event details.
|
||||
required: false
|
||||
type: string
|
||||
- name: q.status
|
||||
in: query
|
||||
description: Transaction status.
|
||||
required: false
|
||||
type: string
|
||||
- name: q.resource_id
|
||||
in: query
|
||||
description: Transaction resource id.
|
||||
required: false
|
||||
type: string
|
||||
- name: q.service_name
|
||||
in: query
|
||||
description: Transaction service name.
|
||||
required: false
|
||||
type: string
|
||||
- name: limit
|
||||
in: query
|
||||
description: Max number of records to return
|
||||
required: false
|
||||
type: string
|
||||
#tags:
|
||||
# - Transactions
|
||||
responses:
|
||||
200:
|
||||
description: An array of transactions
|
||||
schema:
|
||||
$ref: '#/definitions/Transactions'
|
||||
default:
|
||||
description: Unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
post:
|
||||
summary: put audit transactions
|
||||
description: |
|
||||
Insert audit transactions
|
||||
parameters:
|
||||
- name: transaction
|
||||
in: body
|
||||
description: The audit transaction to add
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/Transaction"
|
||||
#tags:
|
||||
# - Transactions
|
||||
responses:
|
||||
"201":
|
||||
description: Null response
|
||||
default:
|
||||
description: unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
definitions:
|
||||
Transactions:
|
||||
type: object
|
||||
properties:
|
||||
transactions:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Transaction'
|
||||
Transaction:
|
||||
type: object
|
||||
properties:
|
||||
timestamp:
|
||||
type: number
|
||||
format: long
|
||||
description: Time of audit record in milliseconds since 1/1/1970.
|
||||
user_id:
|
||||
type: string
|
||||
description: The concrete user which initiated this transaction (i.e the SSP user for which a create action was initiated).
|
||||
application_id:
|
||||
type: string
|
||||
description: (SSP, eCOMP, etc).
|
||||
tracking_id:
|
||||
type: string
|
||||
description: The “session” identifier for a set of transactions, and will be the same all through the flow. So if SSP calls CMS with its own transaction id, it should also be used as the tracking id. If it does not include some identifier, the CMS generated transaction id can serve as the tracking id. Either way, that tracking id will be preserved and identify all actions along the flow – on RDS, by the ORD, etc.
|
||||
external_id:
|
||||
type: string
|
||||
description: Anything we get from outside the ORM. For example, if the SSP has its own transaction ID, it may forward it to us.
|
||||
transaction_id:
|
||||
type: string
|
||||
description: The transaction ID of the component creating the current record.
|
||||
transaction_type:
|
||||
type: string
|
||||
description: The type of transaction (depends on the application business logic).
|
||||
event_details:
|
||||
type: string
|
||||
description: Free description, may be transaction type specific data.
|
||||
status:
|
||||
type: string
|
||||
description: The transaction status (depends on the application business logic).
|
||||
resource_id:
|
||||
type: string
|
||||
description: The UUID of the resource on which this action is operating.
|
||||
service_name:
|
||||
type: string
|
||||
description: The service which initiated the log ie- CMS, RDS, RMS....
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
faultcode:
|
||||
type: string
|
||||
faultstring:
|
||||
type: string
|
||||
debuginfo:
|
||||
type: string
|
||||
|
@ -0,0 +1,24 @@
|
||||
# Swagger generated server
|
||||
|
||||
## Overview
|
||||
This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. This is an example of building a node.js server.
|
||||
|
||||
This example uses the [expressjs](http://expressjs.com/) framework. To see how to make this your own, look here:
|
||||
|
||||
[README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md)
|
||||
|
||||
### Running the server
|
||||
To run the server, follow these simple steps:
|
||||
|
||||
```
|
||||
npm install
|
||||
node .
|
||||
```
|
||||
|
||||
To view the Swagger UI interface:
|
||||
|
||||
```
|
||||
open http://localhost:8080/docs
|
||||
```
|
||||
|
||||
This project leverages the mega-awesome [swagger-tools](https://github.com/apigee-127/swagger-tools) middleware which does most all the work.
|
@ -0,0 +1,178 @@
|
||||
---
|
||||
swagger: "2.0"
|
||||
info:
|
||||
description: "Audit Server service"
|
||||
version: "1.0.0"
|
||||
title: "Audit Server API"
|
||||
host: "server"
|
||||
basePath: "/v1"
|
||||
schemes:
|
||||
- "http"
|
||||
produces:
|
||||
- "application/json"
|
||||
paths:
|
||||
/audit/transaction:
|
||||
get:
|
||||
summary: "get audit transactions"
|
||||
description: "Returns transactions that meet the query.\n"
|
||||
operationId: "auditTransactionGET"
|
||||
parameters:
|
||||
- name: "q.timestamp_from"
|
||||
in: "query"
|
||||
description: "Transaction from timestamp."
|
||||
required: false
|
||||
type: "number"
|
||||
format: "long"
|
||||
- name: "q.timestamp_to"
|
||||
in: "query"
|
||||
description: "Transaction to timestamp."
|
||||
required: false
|
||||
type: "number"
|
||||
format: "long"
|
||||
- name: "q.user_id"
|
||||
in: "query"
|
||||
description: "Transaction user id."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "q.application_id"
|
||||
in: "query"
|
||||
description: "Transaction application id."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "q.tracking_id"
|
||||
in: "query"
|
||||
description: "Transaction tracking id."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "q.external_id"
|
||||
in: "query"
|
||||
description: "Transaction external id."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "q.transaction_id"
|
||||
in: "query"
|
||||
description: "Transaction transaction id."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "q.transaction_type"
|
||||
in: "query"
|
||||
description: "Transaction transaction type."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "q.event_details"
|
||||
in: "query"
|
||||
description: "Transaction event details."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "q.status"
|
||||
in: "query"
|
||||
description: "Transaction status."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "q.resource_id"
|
||||
in: "query"
|
||||
description: "Transaction resource id."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "q.service_name"
|
||||
in: "query"
|
||||
description: "Transaction service name."
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "limit"
|
||||
in: "query"
|
||||
description: "Max number of records to return"
|
||||
required: false
|
||||
type: "string"
|
||||
responses:
|
||||
200:
|
||||
description: "An array of transactions"
|
||||
schema:
|
||||
$ref: "#/definitions/Transactions"
|
||||
default:
|
||||
description: "Unexpected error"
|
||||
schema:
|
||||
$ref: "#/definitions/Error"
|
||||
x-swagger-router-controller: "Default"
|
||||
post:
|
||||
summary: "put audit transactions"
|
||||
description: "Insert audit transactions\n"
|
||||
operationId: "auditTransactionPOST"
|
||||
parameters:
|
||||
- in: "body"
|
||||
name: "transaction"
|
||||
description: "The audit transaction to add"
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/Transaction"
|
||||
responses:
|
||||
201:
|
||||
description: "Null response"
|
||||
default:
|
||||
description: "unexpected error"
|
||||
schema:
|
||||
$ref: "#/definitions/Error"
|
||||
x-swagger-router-controller: "Default"
|
||||
definitions:
|
||||
Transactions:
|
||||
type: "object"
|
||||
properties:
|
||||
transactions:
|
||||
type: "array"
|
||||
items:
|
||||
$ref: "#/definitions/Transaction"
|
||||
Transaction:
|
||||
type: "object"
|
||||
properties:
|
||||
timestamp:
|
||||
type: "number"
|
||||
format: "long"
|
||||
description: "Time of audit record in milliseconds since 1/1/1970."
|
||||
user_id:
|
||||
type: "string"
|
||||
description: "The concrete user which initiated this transaction (i.e the\
|
||||
\ SSP user for which a create action was initiated)."
|
||||
application_id:
|
||||
type: "string"
|
||||
description: "(SSP, eCOMP, etc)."
|
||||
tracking_id:
|
||||
type: "string"
|
||||
description: "The “session” identifier for a set of transactions, and will\
|
||||
\ be the same all through the flow. So if SSP calls CMS with its own transaction\
|
||||
\ id, it should also be used as the tracking id. If it does not include\
|
||||
\ some identifier, the CMS generated transaction id can serve as the tracking\
|
||||
\ id. Either way, that tracking id will be preserved and identify all actions\
|
||||
\ along the flow – on RDS, by the ORD, etc."
|
||||
external_id:
|
||||
type: "string"
|
||||
description: "Anything we get from outside the ORM. For example, if the SSP\
|
||||
\ has its own transaction ID, it may forward it to us."
|
||||
transaction_id:
|
||||
type: "string"
|
||||
description: "The transaction ID of the component creating the current record."
|
||||
transaction_type:
|
||||
type: "string"
|
||||
description: "The type of transaction (depends on the application business\
|
||||
\ logic)."
|
||||
event_details:
|
||||
type: "string"
|
||||
description: "Free description, may be transaction type specific data."
|
||||
status:
|
||||
type: "string"
|
||||
description: "The transaction status (depends on the application business\
|
||||
\ logic)."
|
||||
resource_id:
|
||||
type: "string"
|
||||
description: "The UUID of the resource on which this action is operating."
|
||||
service_name:
|
||||
type: "string"
|
||||
description: "The service which initiated the log ie- CMS, RDS, RMS...."
|
||||
Error:
|
||||
type: "object"
|
||||
properties:
|
||||
faultcode:
|
||||
type: "string"
|
||||
faultstring:
|
||||
type: "string"
|
||||
debuginfo:
|
||||
type: "string"
|
@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var url = require('url');
|
||||
|
||||
|
||||
var Default = require('./DefaultService');
|
||||
|
||||
|
||||
module.exports.auditTransactionGET = function auditTransactionGET (req, res, next) {
|
||||
Default.auditTransactionGET(req.swagger.params, res, next);
|
||||
};
|
||||
|
||||
module.exports.auditTransactionPOST = function auditTransactionPOST (req, res, next) {
|
||||
Default.auditTransactionPOST(req.swagger.params, res, next);
|
||||
};
|
@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
exports.auditTransactionGET = function(args, res, next) {
|
||||
/**
|
||||
* parameters expected in the args:
|
||||
* q.timestampFrom (BigDecimal)
|
||||
* q.timestampTo (BigDecimal)
|
||||
* q.userId (String)
|
||||
* q.applicationId (String)
|
||||
* q.trackingId (String)
|
||||
* q.externalId (String)
|
||||
* q.transactionId (String)
|
||||
* q.transactionType (String)
|
||||
* q.eventDetails (String)
|
||||
* q.status (String)
|
||||
* q.resourceId (String)
|
||||
* q.serviceName (String)
|
||||
* limit (String)
|
||||
**/
|
||||
|
||||
|
||||
var examples = {};
|
||||
examples['application/json'] = {
|
||||
"transactions" : [ {
|
||||
"transaction_id" : "aeiou",
|
||||
"user_id" : "aeiou",
|
||||
"service_name" : "aeiou",
|
||||
"resource_id" : "aeiou",
|
||||
"external_id" : "aeiou",
|
||||
"event_details" : "aeiou",
|
||||
"transaction_type" : "aeiou",
|
||||
"application_id" : "aeiou",
|
||||
"tracking_id" : "aeiou",
|
||||
"timestamp" : 1.3579000000000001069366817318950779736042022705078125,
|
||||
"status" : "aeiou"
|
||||
} ]
|
||||
};
|
||||
|
||||
if(Object.keys(examples).length > 0) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2));
|
||||
}
|
||||
else {
|
||||
res.end();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
exports.auditTransactionPOST = function(args, res, next) {
|
||||
/**
|
||||
* parameters expected in the args:
|
||||
* transaction (Transaction)
|
||||
**/
|
||||
// no response value expected for this operation
|
||||
|
||||
|
||||
res.end();
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
var app = require('connect')();
|
||||
var http = require('http');
|
||||
var swaggerTools = require('swagger-tools');
|
||||
var jsyaml = require('js-yaml');
|
||||
var fs = require('fs');
|
||||
var serverPort = 8080;
|
||||
|
||||
// swaggerRouter configuration
|
||||
var options = {
|
||||
swaggerUi: '/swagger.json',
|
||||
controllers: './controllers',
|
||||
useStubs: process.env.NODE_ENV === 'development' ? true : false // Conditionally turn on stubs (mock mode)
|
||||
};
|
||||
|
||||
// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
|
||||
var spec = fs.readFileSync('./api/swagger.yaml', 'utf8');
|
||||
var swaggerDoc = jsyaml.safeLoad(spec);
|
||||
|
||||
// Initialize the Swagger middleware
|
||||
swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {
|
||||
// Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
|
||||
app.use(middleware.swaggerMetadata());
|
||||
|
||||
// Validate Swagger requests
|
||||
app.use(middleware.swaggerValidator());
|
||||
|
||||
// Route validated requests to appropriate controller
|
||||
app.use(middleware.swaggerRouter(options));
|
||||
|
||||
// Serve the Swagger documents and Swagger UI
|
||||
app.use(middleware.swaggerUi());
|
||||
|
||||
// Start the server
|
||||
http.createServer(app).listen(serverPort, function () {
|
||||
console.log('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort);
|
||||
console.log('Swagger-ui is available on http://localhost:%d/docs', serverPort);
|
||||
});
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "audit-server-api",
|
||||
"version": "1.0.0",
|
||||
"description": "Audit Server service",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
"swagger"
|
||||
],
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"connect": "^3.2.0",
|
||||
"js-yaml": "^3.3.0",
|
||||
"swagger-tools": "0.9.*"
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user