summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Chung <chungg@ca.ibm.com>2013-08-19 15:03:01 -0400
committerGordon Chung <chungg@ca.ibm.com>2013-08-20 18:55:53 -0400
commit02aaa468ce2b20f00e298cf6118cc50890c462ca (patch)
tree34e4244ee4cb9de9655d72122d2d276224a7edbc
parent081382ad627e2b7167db65cbb3a7f4cc20f41b8e (diff)
downloadpycadf-0.1.5.tar.gz
update cadf spec to support new data model0.1.5
- add Credential type and move token into it - add Host type and move client_addr, agent into it - add Endpoint type and move adminUrl, privateUrl into it - add credential, host, addresses as optional attr of Resource - add observer attr to event Change-Id: I663eaf0b2f239300e035f084b8574e615c40a182 Fixes: Bug #1214097
-rw-r--r--pycadf/audit/__init__.py28
-rw-r--r--pycadf/audit/api.py115
-rw-r--r--pycadf/credential.py49
-rw-r--r--pycadf/endpoint.py52
-rw-r--r--pycadf/event.py24
-rw-r--r--pycadf/host.py65
-rw-r--r--pycadf/reporterstep.py2
-rw-r--r--pycadf/resource.py40
-rw-r--r--pycadf/tests/audit/test_api.py43
-rw-r--r--pycadf/tests/test_cadf_spec.py37
10 files changed, 340 insertions, 115 deletions
diff --git a/pycadf/audit/__init__.py b/pycadf/audit/__init__.py
index 3a143f2..e69de29 100644
--- a/pycadf/audit/__init__.py
+++ b/pycadf/audit/__init__.py
@@ -1,28 +0,0 @@
-# -*- encoding: utf-8 -*-
-#
-# Copyright 2013 IBM Corp.
-#
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from oslo.config import cfg
-
-CONF = cfg.CONF
-
-opts = [
- cfg.StrOpt('api_audit_map',
- default='/etc/pycadf/api_audit_map.conf',
- help='File containing mapping for api paths and '
- 'service endpoints'),
-]
-CONF.register_opts(opts, group='audit')
diff --git a/pycadf/audit/api.py b/pycadf/audit/api.py
index 8a0859c..b34debb 100644
--- a/pycadf/audit/api.py
+++ b/pycadf/audit/api.py
@@ -23,7 +23,10 @@ import urlparse
from pycadf import cadftaxonomy as taxonomy
from pycadf import cadftype
+from pycadf import credential
+from pycadf import endpoint
from pycadf import eventfactory as factory
+from pycadf import host
from pycadf import identifier
from pycadf import reason
from pycadf import reporterstep
@@ -31,36 +34,28 @@ from pycadf import resource
from pycadf import tag
from pycadf import timestamp
-cfg.CONF.import_opt('api_audit_map', 'pycadf.audit', group='audit')
CONF = cfg.CONF
-
-
-class ServiceResource(resource.Resource):
- def __init__(self, admin_url=None, private_url=None,
- public_url=None, **kwargs):
- super(ServiceResource, self).__init__(**kwargs)
- if admin_url is not None:
- self.adminURL = admin_url
- if private_url is not None:
- self.privateURL = private_url
- if public_url is not None:
- self.publicURL = public_url
+opts = [
+ cfg.StrOpt('api_audit_map',
+ default='api_audit_map.conf',
+ help='File containing mapping for api paths and '
+ 'service endpoints'),
+]
+CONF.register_opts(opts, group='audit')
class ClientResource(resource.Resource):
- def __init__(self, client_addr=None, user_agent=None,
- token=None, tenant=None, status=None, **kwargs):
+ def __init__(self, project_id=None, **kwargs):
super(ClientResource, self).__init__(**kwargs)
- if client_addr is not None:
- self.client_addr = client_addr
- if user_agent is not None:
- self.user_agent = user_agent
- if token is not None:
- self.token = token
- if tenant is not None:
- self.tenant = tenant
- if status is not None:
- self.status = status
+ if project_id is not None:
+ self.project_id = project_id
+
+
+class KeystoneCredential(credential.Credential):
+ def __init__(self, identity_status=None, **kwargs):
+ super(KeystoneCredential, self).__init__(**kwargs)
+ if identity_status is not None:
+ self.identity_status = identity_status
class PycadfAuditApiConfigError(Exception):
@@ -156,46 +151,60 @@ class OpenStackAuditApi(object):
def create_event(self, req, correlation_id):
action = self._get_action(req)
+ initiator_host = host.Host(address=req.client_addr,
+ agent=req.user_agent)
catalog = ast.literal_eval(req.environ['HTTP_X_SERVICE_CATALOG'])
- for endpoint in catalog:
+ for endp in catalog:
admin_urlparse = urlparse.urlparse(
- endpoint['endpoints'][0]['adminURL'])
+ endp['endpoints'][0]['adminURL'])
public_urlparse = urlparse.urlparse(
- endpoint['endpoints'][0]['publicURL'])
+ endp['endpoints'][0]['publicURL'])
req_url = urlparse.urlparse(req.host_url)
if (req_url.netloc == admin_urlparse.netloc
or req_url.netloc == public_urlparse.netloc):
- service_type = self._SERVICE_ENDPOINTS.get(endpoint['type'],
+ service_type = self._SERVICE_ENDPOINTS.get(endp['type'],
taxonomy.UNKNOWN)
- service_name = endpoint['name']
- admin_url = endpoint['endpoints'][0]['adminURL']
- private_url = endpoint['endpoints'][0]['internalURL']
- public_url = endpoint['endpoints'][0]['publicURL']
- service_id = endpoint['endpoints'][0]['id']
+ service_name = endp['name']
+ admin_end = endpoint.Endpoint(
+ name='admin',
+ url=endp['endpoints'][0]['adminURL'])
+ private_end = endpoint.Endpoint(
+ name='private',
+ url=endp['endpoints'][0]['internalURL'])
+ public_end = endpoint.Endpoint(
+ name='public',
+ url=endp['endpoints'][0]['publicURL'])
+ service_id = endp['endpoints'][0]['id']
break
else:
service_type = service_id = service_name = taxonomy.UNKNOWN
- admin_url = private_url = public_url = None
-
+ admin_end = private_end = public_end = None
+
+ initiator = ClientResource(
+ typeURI=taxonomy.ACCOUNT_USER,
+ id=str(req.environ['HTTP_X_USER_ID']),
+ name=req.environ['HTTP_X_USER_NAME'],
+ host=initiator_host,
+ credential=KeystoneCredential(
+ token=req.environ['HTTP_X_AUTH_TOKEN'],
+ identity_status=req.environ['HTTP_X_IDENTITY_STATUS']),
+ project_id=req.environ['HTTP_X_PROJECT_ID'])
+ target = resource.Resource(typeURI=service_type,
+ id=service_id,
+ name=service_name)
+ if admin_end:
+ target.add_address(admin_end)
+ if private_end:
+ target.add_address(private_end)
+ if public_end:
+ target.add_address(public_end)
event = factory.EventFactory().new_event(
eventType=cadftype.EVENTTYPE_ACTIVITY,
outcome=taxonomy.OUTCOME_PENDING,
action=action,
- initiator=ClientResource(
- typeURI=taxonomy.ACCOUNT_USER,
- id=str(req.environ['HTTP_X_USER_ID']),
- name=req.environ['HTTP_X_USER_NAME'],
- client_addr=req.client_addr,
- user_agent=req.user_agent,
- token=req.environ['HTTP_X_AUTH_TOKEN'],
- tenant=req.environ['HTTP_X_PROJECT_ID'],
- status=req.environ['HTTP_X_IDENTITY_STATUS']),
- target=ServiceResource(typeURI=service_type,
- id=service_id,
- name=service_name,
- private_url=private_url,
- public_url=public_url,
- admin_url=admin_url))
+ initiator=initiator,
+ target=target,
+ observer='target')
event.add_tag(tag.generate_name_value_tag('correlation_id',
correlation_id))
return event
@@ -208,10 +217,6 @@ class OpenStackAuditApi(object):
correlation_id = identifier.generate_uuid()
req.environ['CADF_EVENT_CORRELATION_ID'] = correlation_id
event = self.create_event(req, correlation_id)
- event.add_reporterstep(
- reporterstep.Reporterstep(
- role=cadftype.REPORTER_ROLE_OBSERVER,
- reporter='target'))
setattr(req, 'cadf_model', event)
req.environ['CADF_EVENT'] = event.as_dict()
diff --git a/pycadf/credential.py b/pycadf/credential.py
new file mode 100644
index 0000000..f58f6b6
--- /dev/null
+++ b/pycadf/credential.py
@@ -0,0 +1,49 @@
+# -*- encoding: utf-8 -*-
+#
+# Copyright © 2013 IBM Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from pycadf import cadftype
+
+TYPE_URI_CRED = cadftype.CADF_VERSION_1_0_0 + 'credential'
+
+CRED_KEYNAME_TYPE = "type"
+CRED_KEYNAME_TOKEN = "token"
+
+CRED_KEYNAMES = [CRED_KEYNAME_TYPE,
+ CRED_KEYNAME_TOKEN]
+
+
+class Credential(cadftype.CADFAbstractType):
+
+ type = cadftype.ValidatorDescriptor(
+ CRED_KEYNAME_TYPE,
+ lambda x: isinstance(x, basestring))
+ token = cadftype.ValidatorDescriptor(
+ CRED_KEYNAME_TOKEN,
+ lambda x: isinstance(x, basestring))
+
+ def __init__(self, token, type=None):
+
+ # Credential.token
+ setattr(self, CRED_KEYNAME_TOKEN, token)
+
+ # Credential.type
+ if type is not None:
+ setattr(self, CRED_KEYNAME_TYPE, type)
+
+ # TODO(mrutkows): validate this cadf:Credential type against schema
+ def is_valid(self):
+ # TODO(mrutkows): validate specific attribute type/format
+ return hasattr(self, CRED_KEYNAME_TOKEN)
diff --git a/pycadf/endpoint.py b/pycadf/endpoint.py
new file mode 100644
index 0000000..046d7cd
--- /dev/null
+++ b/pycadf/endpoint.py
@@ -0,0 +1,52 @@
+# -*- encoding: utf-8 -*-
+#
+# Copyright © 2013 IBM Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from pycadf import cadftype
+
+TYPE_URI_ENDPOINT = cadftype.CADF_VERSION_1_0_0 + 'endpoint'
+
+ENDPOINT_KEYNAME_URL = "url"
+ENDPOINT_KEYNAME_NAME = "name"
+ENDPOINT_KEYNAME_PORT = "port"
+
+ENDPOINT_KEYNAMES = [ENDPOINT_KEYNAME_URL,
+ ENDPOINT_KEYNAME_NAME,
+ ENDPOINT_KEYNAME_PORT]
+
+
+class Endpoint(cadftype.CADFAbstractType):
+
+ url = cadftype.ValidatorDescriptor(
+ ENDPOINT_KEYNAME_URL, lambda x: isinstance(x, basestring))
+ name = cadftype.ValidatorDescriptor(
+ ENDPOINT_KEYNAME_NAME, lambda x: isinstance(x, basestring))
+ port = cadftype.ValidatorDescriptor(
+ ENDPOINT_KEYNAME_PORT, lambda x: isinstance(x, basestring))
+
+ def __init__(self, url, name=None, port=None):
+
+ # ENDPOINT.url
+ setattr(self, ENDPOINT_KEYNAME_URL, url)
+ # ENDPOINT.name
+ if name is not None:
+ setattr(self, ENDPOINT_KEYNAME_NAME, name)
+ # ENDPOINT.port
+ if port is not None:
+ setattr(self, ENDPOINT_KEYNAME_PORT, port)
+
+ # TODO(mrutkows): validate this cadf:ENDPOINT type against schema
+ def is_valid(self):
+ return hasattr(self, ENDPOINT_KEYNAME_URL)
diff --git a/pycadf/event.py b/pycadf/event.py
index 916b4c3..70972f6 100644
--- a/pycadf/event.py
+++ b/pycadf/event.py
@@ -45,6 +45,7 @@ EVENT_KEYNAME_SEVERITY = "severity"
EVENT_KEYNAME_MEASUREMENTS = "measurements"
EVENT_KEYNAME_TAGS = "tags"
EVENT_KEYNAME_ATTACHMENTS = "attachments"
+EVENT_KEYNAME_OBSERVER = "observer"
EVENT_KEYNAME_REPORTERCHAIN = "reporterchain"
EVENT_KEYNAMES = [EVENT_KEYNAME_TYPEURI,
@@ -62,6 +63,7 @@ EVENT_KEYNAMES = [EVENT_KEYNAME_TYPEURI,
EVENT_KEYNAME_MEASUREMENTS,
EVENT_KEYNAME_TAGS,
EVENT_KEYNAME_ATTACHMENTS,
+ EVENT_KEYNAME_OBSERVER,
EVENT_KEYNAME_REPORTERCHAIN]
@@ -94,13 +96,18 @@ class Event(cadftype.CADFAbstractType):
severity = cadftype.ValidatorDescriptor(EVENT_KEYNAME_SEVERITY,
lambda x: isinstance(x,
basestring))
+ observer = cadftype.ValidatorDescriptor(
+ EVENT_KEYNAME_OBSERVER,
+ (lambda x: isinstance(x, resource.Resource) or
+ (isinstance(x, basestring) and
+ (x == 'initiator' or x == 'target'))))
def __init__(self, eventType=cadftype.EVENTTYPE_ACTIVITY,
id=identifier.generate_uuid(),
eventTime=timestamp.get_utc_now(),
action=cadftaxonomy.UNKNOWN, outcome=cadftaxonomy.UNKNOWN,
initiator=None, initiatorId=None, target=None, targetId=None,
- severity=None, reason=None):
+ severity=None, reason=None, observer=None):
# Establish typeURI for the CADF Event data type
# TODO(mrutkows): support extended typeURIs for Event subtypes
@@ -121,6 +128,9 @@ class Event(cadftype.CADFAbstractType):
# Event.outcome (Mandatory)
setattr(self, EVENT_KEYNAME_OUTCOME, outcome)
+ # Event.observer (Mandatory)
+ setattr(self, EVENT_KEYNAME_OBSERVER, observer)
+
# Event.initiator (Mandatory if no initiatorId)
if initiator is not None:
setattr(self, EVENT_KEYNAME_INITIATOR, initiator)
@@ -145,15 +155,14 @@ class Event(cadftype.CADFAbstractType):
if reason is not None:
setattr(self, EVENT_KEYNAME_REASON, reason)
- # Event.reporterchain (Mandatory)
- # Prepare the Event.reporterchain (list of cadf:Reporterstep) since
- # at least one cadf:Reporterstep entry is required
- setattr(self, EVENT_KEYNAME_REPORTERCHAIN, list())
-
# Event.reporterchain
def add_reporterstep(self, step):
if step is not None and isinstance(step, reporterstep.Reporterstep):
if step.is_valid():
+ # Create the list of Reportersteps if needed
+ if not hasattr(self, EVENT_KEYNAME_REPORTERCHAIN):
+ setattr(self, EVENT_KEYNAME_REPORTERCHAIN, list())
+
reporterchain = getattr(self,
EVENT_KEYNAME_REPORTERCHAIN)
reporterchain.append(step)
@@ -224,6 +233,5 @@ class Event(cadftype.CADFAbstractType):
hasattr(self, EVENT_KEYNAME_ACTION) and
hasattr(self, EVENT_KEYNAME_OUTCOME) and
hasattr(self, EVENT_KEYNAME_INITIATOR) and
- hasattr(self, EVENT_KEYNAME_TARGET) and
- hasattr(self, EVENT_KEYNAME_REPORTERCHAIN)
+ hasattr(self, EVENT_KEYNAME_TARGET)
)
diff --git a/pycadf/host.py b/pycadf/host.py
new file mode 100644
index 0000000..565f00e
--- /dev/null
+++ b/pycadf/host.py
@@ -0,0 +1,65 @@
+# -*- encoding: utf-8 -*-
+#
+# Copyright © 2013 IBM Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from pycadf import cadftype
+from pycadf import identifier
+
+TYPE_URI_HOST = cadftype.CADF_VERSION_1_0_0 + 'host'
+
+HOST_KEYNAME_ID = "id"
+HOST_KEYNAME_ADDR = "address"
+HOST_KEYNAME_AGENT = "agent"
+HOST_KEYNAME_PLATFORM = "platform"
+
+HOST_KEYNAMES = [HOST_KEYNAME_ID,
+ HOST_KEYNAME_ADDR,
+ HOST_KEYNAME_AGENT,
+ HOST_KEYNAME_PLATFORM]
+
+
+class Host(cadftype.CADFAbstractType):
+
+ id = cadftype.ValidatorDescriptor(
+ HOST_KEYNAME_ID, lambda x: identifier.is_valid(x))
+ address = cadftype.ValidatorDescriptor(
+ HOST_KEYNAME_ADDR, lambda x: isinstance(x, basestring))
+ agent = cadftype.ValidatorDescriptor(
+ HOST_KEYNAME_AGENT, lambda x: isinstance(x, basestring))
+ platform = cadftype.ValidatorDescriptor(
+ HOST_KEYNAME_PLATFORM, lambda x: isinstance(x, basestring))
+
+ def __init__(self, id=None, address=None, agent=None,
+ platform=None):
+
+ # Host.id
+ if id is not None:
+ setattr(self, HOST_KEYNAME_ID, id)
+ # Host.address
+ if address is not None:
+ setattr(self, HOST_KEYNAME_ADDR, address)
+ # Host.agent
+ if agent is not None:
+ setattr(self, HOST_KEYNAME_AGENT, agent)
+ # Host.platform
+ if platform is not None:
+ setattr(self, HOST_KEYNAME_PLATFORM, platform)
+
+ # TODO(mrutkows): validate this cadf:Host type against schema
+ def is_valid(self):
+ return (hasattr(self, HOST_KEYNAME_ID) or
+ hasattr(self, HOST_KEYNAME_ADDR) or
+ hasattr(self, HOST_KEYNAME_AGENT) or
+ hasattr(self, HOST_KEYNAME_PLATFORM))
diff --git a/pycadf/reporterstep.py b/pycadf/reporterstep.py
index 29cab96..1f620b8 100644
--- a/pycadf/reporterstep.py
+++ b/pycadf/reporterstep.py
@@ -50,7 +50,7 @@ class Reporterstep(cadftype.CADFAbstractType):
reporterTime = cadftype.ValidatorDescriptor(
REPORTERSTEP_KEYNAME_REPORTERTIME, lambda x: timestamp.is_valid(x))
- def __init__(self, role=cadftype.REPORTER_ROLE_OBSERVER,
+ def __init__(self, role=cadftype.REPORTER_ROLE_MODIFIER,
reporterTime=None, reporter=None, reporterId=None):
# Reporterstep.role
setattr(self, REPORTERSTEP_KEYNAME_ROLE, role)
diff --git a/pycadf/resource.py b/pycadf/resource.py
index 0d30a42..9c447e6 100644
--- a/pycadf/resource.py
+++ b/pycadf/resource.py
@@ -19,7 +19,10 @@
from pycadf import attachment
from pycadf import cadftaxonomy
from pycadf import cadftype
+from pycadf import credential
+from pycadf import endpoint
from pycadf import geolocation
+from pycadf import host
from pycadf import identifier
TYPE_URI_RESOURCE = cadftype.CADF_VERSION_1_0_0 + 'resource'
@@ -28,18 +31,24 @@ RESOURCE_KEYNAME_TYPEURI = "typeURI"
RESOURCE_KEYNAME_ID = "id"
RESOURCE_KEYNAME_NAME = "name"
RESOURCE_KEYNAME_DOMAIN = "domain"
+RESOURCE_KEYNAME_CRED = "credential"
RESOURCE_KEYNAME_REF = "ref"
RESOURCE_KEYNAME_GEO = "geolocation"
RESOURCE_KEYNAME_GEOID = "geolocationId"
+RESOURCE_KEYNAME_HOST = "host"
+RESOURCE_KEYNAME_ADDRS = "addresses"
RESOURCE_KEYNAME_ATTACHMENTS = "attachments"
RESOURCE_KEYNAMES = [RESOURCE_KEYNAME_TYPEURI,
RESOURCE_KEYNAME_ID,
RESOURCE_KEYNAME_NAME,
RESOURCE_KEYNAME_DOMAIN,
+ RESOURCE_KEYNAME_CRED,
RESOURCE_KEYNAME_REF,
RESOURCE_KEYNAME_GEO,
RESOURCE_KEYNAME_GEOID,
+ RESOURCE_KEYNAME_HOST,
+ RESOURCE_KEYNAME_ADDRS,
RESOURCE_KEYNAME_ATTACHMENTS]
@@ -53,6 +62,11 @@ class Resource(cadftype.CADFAbstractType):
lambda x: isinstance(x, basestring))
domain = cadftype.ValidatorDescriptor(RESOURCE_KEYNAME_DOMAIN,
lambda x: isinstance(x, basestring))
+ credential = cadftype.ValidatorDescriptor(
+ RESOURCE_KEYNAME_CRED, (lambda x: isinstance(x, credential.Credential)
+ and x.is_valid()))
+ host = cadftype.ValidatorDescriptor(
+ RESOURCE_KEYNAME_HOST, lambda x: isinstance(x, host.Host))
# TODO(mrutkows): validate the "ref" attribute is indeed a URI (format),
# If it is a URL, we do not need to validate it is accessible/working,
# for audit purposes this could have been a valid URL at some point
@@ -68,7 +82,8 @@ class Resource(cadftype.CADFAbstractType):
def __init__(self, id=identifier.generate_uuid(),
typeURI=cadftaxonomy.UNKNOWN, name=None, ref=None,
- domain=None, geolocation=None, geolocationId=None):
+ domain=None, credential=None, host=None,
+ geolocation=None, geolocationId=None):
# Resource.id
setattr(self, RESOURCE_KEYNAME_ID, id)
@@ -88,6 +103,14 @@ class Resource(cadftype.CADFAbstractType):
if domain is not None:
setattr(self, RESOURCE_KEYNAME_DOMAIN, domain)
+ # Resource.credential
+ if credential is not None:
+ setattr(self, RESOURCE_KEYNAME_CRED, credential)
+
+ # Resource.host
+ if host is not None:
+ setattr(self, RESOURCE_KEYNAME_HOST, host)
+
# Resource.geolocation
if geolocation is not None:
setattr(self, RESOURCE_KEYNAME_GEO, geolocation)
@@ -96,6 +119,21 @@ class Resource(cadftype.CADFAbstractType):
if geolocationId:
setattr(self, RESOURCE_KEYNAME_GEOID, geolocationId)
+ # Resource.address
+ def add_address(self, addr):
+ if (addr is not None and isinstance(addr, endpoint.Endpoint)):
+ if addr.is_valid():
+ # Create the list of Endpoints if needed
+ if not hasattr(self, RESOURCE_KEYNAME_ADDRS):
+ setattr(self, RESOURCE_KEYNAME_ADDRS, list())
+
+ addrs = getattr(self, RESOURCE_KEYNAME_ADDRS)
+ addrs.append(addr)
+ else:
+ raise ValueError('Invalid endpoint')
+ else:
+ raise ValueError('Invalid endpoint. Value must be an Endpoint')
+
# Resource.attachments
def add_attachment(self, attach_val):
if (attach_val is not None
diff --git a/pycadf/tests/audit/test_api.py b/pycadf/tests/audit/test_api.py
index 7d2fbde..20fb275 100644
--- a/pycadf/tests/audit/test_api.py
+++ b/pycadf/tests/audit/test_api.py
@@ -54,7 +54,8 @@ class TestAuditApi(base.TestCase):
def api_request(self, method, url):
self.ENV_HEADERS['REQUEST_METHOD'] = method
- req = webob.Request.blank(url, environ=self.ENV_HEADERS)
+ req = webob.Request.blank(url, environ=self.ENV_HEADERS,
+ remote_addr='192.168.0.1')
self.audit_api.append_audit_event(req)
self.assertIn('CADF_EVENT_CORRELATION_ID', req.environ)
return req
@@ -67,25 +68,26 @@ class TestAuditApi(base.TestCase):
'http://schemas.dmtf.org/cloud/audit/1.0/event')
self.assertEqual(payload['outcome'], 'pending')
self.assertEqual(payload['eventType'], 'activity')
- self.assertEqual(payload['target']['publicURL'],
- 'http://host:8774/v2/public')
- self.assertEqual(payload['target']['privateURL'],
- 'http://host:8774/v2/internal')
- self.assertEqual(payload['target']['adminURL'],
- 'http://host:8774/v2/admin')
self.assertEqual(payload['target']['name'], 'nova')
self.assertEqual(payload['target']['id'], 'resource_id')
self.assertEqual(payload['target']['typeURI'], 'service/compute')
+ self.assertEqual(len(payload['target']['addresses']), 3)
+ self.assertEqual(payload['target']['addresses'][0]['name'], 'admin')
+ self.assertEqual(payload['target']['addresses'][0]['url'],
+ 'http://host:8774/v2/admin')
self.assertEqual(payload['initiator']['id'], 'user_id')
self.assertEqual(payload['initiator']['name'], 'user_name')
- self.assertEqual(payload['initiator']['token'], 'token')
- self.assertEqual(payload['initiator']['tenant'], 'tenant_id')
+ self.assertEqual(payload['initiator']['project_id'], 'tenant_id')
+ self.assertEqual(payload['initiator']['host']['address'],
+ '192.168.0.1')
self.assertEqual(payload['initiator']['typeURI'],
'service/security/account/user')
+ self.assertEqual(payload['initiator']['credential']['token'], 'token')
+ self.assertEqual(payload['initiator']['credential']['identity_status'],
+ 'Confirmed')
self.assertNotIn('reason', payload)
- self.assertEqual(len(payload['reporterchain']), 1)
- self.assertEqual(payload['reporterchain'][0]['role'], 'observer')
- self.assertEqual(payload['reporterchain'][0]['reporter'], 'target')
+ self.assertNotIn('reporterchain', payload)
+ self.assertEqual(payload['observer'], 'target')
def test_get_read(self):
req = self.api_request('GET',
@@ -158,9 +160,9 @@ class TestAuditApi(base.TestCase):
self.assertEqual(payload2['outcome'], 'success')
self.assertEqual(payload2['reason']['reasonType'], 'HTTP')
self.assertEqual(payload2['reason']['reasonCode'], '200')
- self.assertEqual(len(payload2['reporterchain']), 2)
- self.assertEqual(payload2['reporterchain'][1]['role'], 'modifier')
- self.assertEqual(payload2['reporterchain'][1]['reporter'], 'target')
+ self.assertEqual(len(payload2['reporterchain']), 1)
+ self.assertEqual(payload2['reporterchain'][0]['role'], 'modifier')
+ self.assertEqual(payload2['reporterchain'][0]['reporter'], 'target')
def test_no_response(self):
req = self.api_request('GET', 'http://host:8774/v2/public/servers')
@@ -171,9 +173,9 @@ class TestAuditApi(base.TestCase):
self.assertEqual(payload['tags'], payload2['tags'])
self.assertEqual(payload2['outcome'], 'unknown')
self.assertNotIn('reason', payload2)
- self.assertEqual(len(payload2['reporterchain']), 2)
- self.assertEqual(payload2['reporterchain'][1]['role'], 'modifier')
- self.assertEqual(payload2['reporterchain'][1]['reporter'], 'target')
+ self.assertEqual(len(payload2['reporterchain']), 1)
+ self.assertEqual(payload2['reporterchain'][0]['role'], 'modifier')
+ self.assertEqual(payload2['reporterchain'][0]['reporter'], 'target')
def test_missing_req(self):
self.ENV_HEADERS['REQUEST_METHOD'] = 'GET'
@@ -187,6 +189,5 @@ class TestAuditApi(base.TestCase):
self.assertEqual(payload['outcome'], 'success')
self.assertEqual(payload['reason']['reasonType'], 'HTTP')
self.assertEqual(payload['reason']['reasonCode'], '200')
- self.assertEqual(len(payload['reporterchain']), 1)
- self.assertEqual(payload['reporterchain'][0]['role'], 'observer')
- self.assertEqual(payload['reporterchain'][0]['reporter'], 'target')
+ self.assertEqual(payload['observer'], 'target')
+ self.assertNotIn('reporterchain', payload)
diff --git a/pycadf/tests/test_cadf_spec.py b/pycadf/tests/test_cadf_spec.py
index 6ab6ac9..869d34d 100644
--- a/pycadf/tests/test_cadf_spec.py
+++ b/pycadf/tests/test_cadf_spec.py
@@ -16,8 +16,11 @@
import testtools
from pycadf import attachment
+from pycadf import credential
+from pycadf import endpoint
from pycadf import event
from pycadf import geolocation
+from pycadf import host
from pycadf import identifier
from pycadf import measurement
from pycadf import metric
@@ -29,6 +32,30 @@ from pycadf import timestamp
class TestCADFSpec(testtools.TestCase):
+ def test_endpoint(self):
+ endp = endpoint.Endpoint(url='http://192.168.0.1',
+ name='endpoint name',
+ port='8080')
+ dict_endp = endp.as_dict()
+ for key in endpoint.ENDPOINT_KEYNAMES:
+ self.assertIn(key, dict_endp)
+
+ def test_host(self):
+ h = host.Host(id=identifier.generate_uuid(),
+ address='192.168.0.1',
+ agent='client',
+ platform='AIX')
+ dict_host = h.as_dict()
+ for key in host.HOST_KEYNAMES:
+ self.assertIn(key, dict_host)
+
+ def test_credential(self):
+ cred = credential.Credential(type='auth token',
+ token=identifier.generate_uuid())
+ dict_cred = cred.as_dict()
+ for key in credential.CRED_KEYNAMES:
+ self.assertIn(key, dict_cred)
+
def test_geolocation(self):
geo = geolocation.Geolocation(id=identifier.generate_uuid(),
latitude='43.6481 N',
@@ -75,7 +102,7 @@ class TestCADFSpec(testtools.TestCase):
def test_reporterstep(self):
step = reporterstep.Reporterstep(
- role='observer',
+ role='modifier',
reporter=resource.Resource(typeURI='storage'),
reporterId=identifier.generate_uuid(),
reporterTime=timestamp.get_utc_now())
@@ -98,12 +125,16 @@ class TestCADFSpec(testtools.TestCase):
name='res_name',
domain='res_domain',
ref='res_ref',
+ credential=credential.Credential(
+ token=identifier.generate_uuid()),
+ host=host.Host(address='192.168.0.1'),
geolocation=geolocation.Geolocation(),
geolocationId=identifier.generate_uuid())
res.add_attachment(attachment.Attachment(typeURI='attachURI',
content='content',
name='attachment_name'))
+ res.add_address(endpoint.Endpoint(url='http://192.168.0.1'))
dict_res = res.as_dict()
for key in resource.RESOURCE_KEYNAMES:
self.assertIn(key, dict_res)
@@ -117,6 +148,7 @@ class TestCADFSpec(testtools.TestCase):
action='read',
target=resource.Resource(typeURI='storage'),
targetId=identifier.generate_uuid(),
+ observer='target',
outcome='success',
reason=reason.Reason(reasonType='HTTP',
reasonCode='200'),
@@ -126,8 +158,11 @@ class TestCADFSpec(testtools.TestCase):
ev.add_attachment(attachment.Attachment(typeURI='attachURI',
content='content',
name='attachment_name'))
+ ev.observer = resource.Resource(typeURI='service/security')
ev.add_reporterstep(reporterstep.Reporterstep(
role='observer',
+ reporter=resource.Resource(typeURI='service/security')))
+ ev.add_reporterstep(reporterstep.Reporterstep(
reporterId=identifier.generate_uuid()))
dict_ev = ev.as_dict()