Test cases for usages indicated an incomplete representation of the various datatypes, based on our own necessary modelling for billable information. Moving instead to specific types of constructs, similar to ceilometer's own internal data structures/divisons. New tests to follow that line.
This commit is contained in:
parent
f0eff01084
commit
908ca359c1
@ -1,5 +1,5 @@
|
||||
import yaml
|
||||
from models import session
|
||||
from models import Session
|
||||
from interface import Artifice
|
||||
default_config = "/etc/artifice/config.yaml"
|
||||
|
||||
|
@ -5,18 +5,29 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
from copy import copy
|
||||
from collections import defaultdict
|
||||
|
||||
#
|
||||
import datetime
|
||||
|
||||
# Provides authentication against Openstack
|
||||
from keystoneclient.v2_0 import client as keystone
|
||||
from keystoneclient.v2_0 import client as KeystoneClient
|
||||
|
||||
# Provides hooks to ceilometer, which we need for data.
|
||||
from ceilometerclient.v2.client import Client as ceilometer
|
||||
|
||||
#
|
||||
# from .models import usage
|
||||
from .models import Session, usage
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from .models.usage import Usage
|
||||
from .models import resources, tenants
|
||||
|
||||
# from .models.tenants import Tenant
|
||||
|
||||
# Date format Ceilometer uses
|
||||
# 2013-07-03T13:34:17
|
||||
# which is, as an strftime:
|
||||
@ -29,8 +40,52 @@ date_format = "%Y-%m-%dT%H:%M:%S"
|
||||
# Sometimes things also have milliseconds, so we look for that too.
|
||||
other_date_format = "%Y-%m-%dT%H:%M:%S.%f"
|
||||
|
||||
def get_meter(meter, start, end, auth):
|
||||
date_fields = [{
|
||||
"field": "timestamp",
|
||||
"op": "ge",
|
||||
"value": start.strftime(date_format)
|
||||
},
|
||||
{
|
||||
"field": "timestamp",
|
||||
"op": "lt",
|
||||
"value": end.strftime(date_format)
|
||||
}
|
||||
]
|
||||
# I dislike directly calling requests here.
|
||||
r = requests.get(
|
||||
meter.link,
|
||||
headers={
|
||||
"X-Auth-Token": auth,
|
||||
"Content-Type":"application/json"},
|
||||
data=json.dumps({"q": date_fields})
|
||||
)
|
||||
return json.loads(r)
|
||||
|
||||
|
||||
class NotFound(BaseException): pass
|
||||
|
||||
class keystone(KeystoneClient.Client):
|
||||
|
||||
def tenant_by_name(self, name):
|
||||
authenticator = self.auth_url
|
||||
url = "%(url)s/tenants?%(query)s" % {
|
||||
"url": authenticator,
|
||||
"query": urllib.urlencode({"name":name})
|
||||
}
|
||||
r = requests.get(url, headers={
|
||||
"X-Auth-Token": self.auth_token,
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
if r.ok:
|
||||
data = json.loads(r.text)
|
||||
assert data
|
||||
return data
|
||||
else:
|
||||
if r.status_code == 404:
|
||||
# couldn't find it
|
||||
raise NotFound
|
||||
|
||||
class Artifice(object):
|
||||
"""Produces billable artifacts"""
|
||||
def __init__(self, config):
|
||||
@ -39,7 +94,7 @@ class Artifice(object):
|
||||
|
||||
# This is the Keystone client connection, which provides our
|
||||
# OpenStack authentication
|
||||
self.auth = keystone.Client(
|
||||
self.auth = keystone(
|
||||
username= config["openstack"]["username"],
|
||||
password= config["openstack"]["password"],
|
||||
tenant_name= config["openstack"]["default_tenant"],
|
||||
@ -55,9 +110,16 @@ class Artifice(object):
|
||||
}
|
||||
engine = create_engine(conn_string)
|
||||
Session.configure(bind=engine)
|
||||
session = Session()
|
||||
self.session = Session()
|
||||
self.artifice = None
|
||||
|
||||
self.ceilometer = ceilometer(
|
||||
self.config["ceilometer"]["host"],
|
||||
token=self.auth.auth_token
|
||||
)
|
||||
self._tenancy = None
|
||||
|
||||
|
||||
def tenant(self, name):
|
||||
"""
|
||||
Returns a Tenant object describing the specified Tenant by name, or raises a NotFound error.
|
||||
@ -65,32 +127,21 @@ class Artifice(object):
|
||||
# Returns a Tenant object for the given name.
|
||||
# Uses Keystone API to perform a direct name lookup,
|
||||
# as this is expected to work via name.
|
||||
authenticator = config["openstack"]["authentication_url"]
|
||||
url = "%(url)s/tenants?%(query)s" % {
|
||||
"url": authenticator,
|
||||
"query": urllib.urlencode({"name":name})
|
||||
}
|
||||
r = requests.get(url, headers={"X-Auth-Token": self.auth.auth_token, "Content-Type": "application/json"})
|
||||
if r.ok:
|
||||
data = json.loads(r.text)
|
||||
assert data
|
||||
t = Tenant(data["tenant"], self)
|
||||
return t
|
||||
else:
|
||||
if r.status_code == 404:
|
||||
# couldn't find it
|
||||
raise NotFound
|
||||
|
||||
data = self.auth.tenant_by_name(name)
|
||||
t = Tenant(data["tenant"], self)
|
||||
return t
|
||||
|
||||
@property
|
||||
def tenants(self):
|
||||
"""All the tenants in our system"""
|
||||
# print "tenant list is %s" % self.auth.tenants.list()
|
||||
if not self._tenancy:
|
||||
self._tenancy = {}
|
||||
invoice_type = __import__(self.config["invoices"]["plugin"])
|
||||
for tenant in self.auth.tenants.list():
|
||||
t = Tenant(tenant, self)
|
||||
|
||||
dict( [(t.name, Tenant(t, self)) for t in self.auth.tenants.list() ] )
|
||||
self._tenancy[t.name] = t
|
||||
return self._tenancy
|
||||
|
||||
class Tenant(object):
|
||||
@ -109,8 +160,9 @@ class Tenant(object):
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr not in self.tenant:
|
||||
return super(self, Tenant).__getattr__(attr)
|
||||
return self.tenant["attr"]
|
||||
return object.__getattribute__(self, attr)
|
||||
# return super(Tenant, self).__getattr__(attr)
|
||||
return self.tenant[attr]
|
||||
|
||||
|
||||
def invoice(self):
|
||||
@ -137,24 +189,32 @@ class Tenant(object):
|
||||
invoice = self.invoice_type(self, config)
|
||||
return invoice
|
||||
|
||||
@property
|
||||
def resources(self):
|
||||
def resources(self, start, end):
|
||||
if not self._resources:
|
||||
r = requests.get(
|
||||
os.path.join(self.config["ceilometer"]["host"], "v2/resources"),
|
||||
headers={"X-Auth-Token": self.auth.auth_token, "Content-Type":"application/json"},
|
||||
data=json.dumps( { "q": resourcing_fields } )
|
||||
)
|
||||
if not r.ok:
|
||||
return None
|
||||
|
||||
self._resources = json.loads(r.text)
|
||||
date_fields = [{
|
||||
"field": "timestamp",
|
||||
"op": "ge",
|
||||
"value": start.strftime(date_format)
|
||||
},
|
||||
{
|
||||
"field": "timestamp",
|
||||
"op": "lt",
|
||||
"value": end.strftime(date_format)
|
||||
},
|
||||
{ "field": "project_id",
|
||||
"op": "eq",
|
||||
"value": self.tenant["id"]
|
||||
},
|
||||
]
|
||||
self._resources = self.ceilometer.resources.list(date_fields)
|
||||
return self._resources
|
||||
|
||||
|
||||
|
||||
# def usage(self, start, end, section=None):
|
||||
def contents(self, start, end):
|
||||
def usage(self, start, end):
|
||||
"""
|
||||
Contents is the meat of Artifice, returning a dict of location to
|
||||
sub-information
|
||||
"""
|
||||
# Returns a usage dict, based on regions.
|
||||
vms = {}
|
||||
vm_to_region = {}
|
||||
@ -162,69 +222,63 @@ class Tenant(object):
|
||||
|
||||
usage_by_dc = {}
|
||||
|
||||
date_fields = [{
|
||||
"field": "timestamp",
|
||||
"op": "ge",
|
||||
"value": start.strftime(date_format)
|
||||
},
|
||||
{
|
||||
"field": "timestamp",
|
||||
"op": "lt",
|
||||
"value": end.strftime(date_format)
|
||||
},
|
||||
]
|
||||
writing_to = None
|
||||
|
||||
vms = []
|
||||
networks = []
|
||||
storage = []
|
||||
images = []
|
||||
volumes = []
|
||||
|
||||
for resource in self.resources:
|
||||
for resource in self.resources(start, end):
|
||||
rels = [link["rel"] for link in resource["links"] if link["rel"] != 'self' ]
|
||||
if "image" in rels:
|
||||
# Images don't have location data - we don't know where they are.
|
||||
# It may not matter where they are.
|
||||
resource["_type"] = "image"
|
||||
images.append(resource)
|
||||
images.append(Resource(resource, self.conn))
|
||||
pass
|
||||
elif "storage" in rels:
|
||||
elif "storage.objects" in rels:
|
||||
# Unknown how this data layout happens yet.
|
||||
resource["_type"] = "storage"
|
||||
storage.append(resource)
|
||||
resource["_type"] = "object"
|
||||
storage.append(Resource(resource, self.conn))
|
||||
pass
|
||||
elif "network" in rels:
|
||||
# Have we seen the VM that owns this yet?
|
||||
resource["_type"] = "network"
|
||||
networks.append(resource)
|
||||
else:
|
||||
networks.append(Resource(resource , self.conn))
|
||||
elif "volumne" in rels:
|
||||
volumes.append( Resource(resource, self.conn) )
|
||||
elif 'instance' in rels:
|
||||
resource["_type"] = "vm"
|
||||
vms.append(resource)
|
||||
vms.append(Resource(resource, self.conn ))
|
||||
|
||||
datacenters = {}
|
||||
region_tmpl = { "vms": [],
|
||||
"network": [],
|
||||
"storage": []
|
||||
region_tmpl = { "vms": vms,
|
||||
"network": networks,
|
||||
"objects": storage,
|
||||
"volumes": volumes
|
||||
|
||||
}
|
||||
vm_to_region = {}
|
||||
for vm in vms:
|
||||
id_ = vm["resource_id"]
|
||||
# vm_to_region = {}
|
||||
# for vm in vms:
|
||||
# id_ = vm["resource_id"]
|
||||
|
||||
datacenter = self.host_to_dc( vm["metadata"]["host"] )
|
||||
# datacenter = self.conn.host_to_dc( vm["metadata"]["host"] )
|
||||
|
||||
if datacenter not in datacenters:
|
||||
dict_ = copy(region_tmpl)
|
||||
datacenters[datacenter] = dict_
|
||||
# if datacenter not in datacenters:
|
||||
# dict_ = copy(region_tmpl)
|
||||
# datacenters[datacenter] = dict_
|
||||
|
||||
datacenters[datacenter]["vms"].append(vm)
|
||||
# datacenters[datacenter]["vms"].append(vm)
|
||||
|
||||
vm_to_region[id_] = datacenter
|
||||
# vm_to_region[id_] = datacenter
|
||||
|
||||
for network in networks:
|
||||
vm_id = network["metadata"]["instance_id"]
|
||||
datacenter = vm_to_region[ vm_id ]
|
||||
# for network in networks:
|
||||
# vm_id = network["metadata"]["instance_id"]
|
||||
# datacenter = self.host_to_dc( network["metadata"]["host"] )
|
||||
|
||||
datacenters[datacenter]["network"].append(network)
|
||||
# datacenters[datacenter]["network"].append(network)
|
||||
|
||||
# for resource in storage:
|
||||
# pass
|
||||
@ -240,42 +294,62 @@ class Tenant(object):
|
||||
# So we can now start to collect stats and construct what we consider to be
|
||||
# usage information for this tenant for this timerange
|
||||
|
||||
return Contents(datacenters, start, end)
|
||||
|
||||
@property
|
||||
def meters(self):
|
||||
if not self.meters:
|
||||
resourcing_fields = [{"field": "project_id", "op": "eq", "value": self.tenant.id }]
|
||||
r = requests.get(
|
||||
os.path.join(self.config["ceilometer"]["host"], "v2/resources"),
|
||||
headers={"X-Auth-Token": self.auth.auth_token, "Content-Type":"application/json"},
|
||||
data=json.dumps( { "q": resourcing_fields } )
|
||||
)
|
||||
# meters = set()
|
||||
resources = json.loads(r.text)
|
||||
for resource in resources:
|
||||
for link in resource["links"]:
|
||||
if link["rel"] == "self":
|
||||
continue
|
||||
self._meters.add(link["rel"])
|
||||
# sections.append(Section(self, link))
|
||||
return self._meters()
|
||||
return Usage(region_tmpl, start, end, self.conn)
|
||||
|
||||
|
||||
class Contents(object):
|
||||
class Usage(object):
|
||||
"""
|
||||
This is a dict-like object containing all the datacenters and
|
||||
meters available in those datacenters.
|
||||
"""
|
||||
|
||||
def __init__(self, contents, start, end):
|
||||
def __init__(self, contents, start, end, conn):
|
||||
self.contents = contents
|
||||
self.start = start
|
||||
self.end = end
|
||||
self.conn = conn
|
||||
|
||||
self._vms = []
|
||||
self._objects = []
|
||||
self._volumes = []
|
||||
|
||||
|
||||
# Replaces all the internal references with better references to
|
||||
# actual metered values.
|
||||
self._replace()
|
||||
# self._replace()
|
||||
|
||||
def __getitem__(self, item):
|
||||
@property
|
||||
def vms(self):
|
||||
|
||||
return self.contents[item]
|
||||
if not self._vms:
|
||||
vms = []
|
||||
|
||||
for vm in self.contents["vms"]:
|
||||
VM = resources.VM(vm)
|
||||
VM.location = self.conn.host_to_dc( vm["metadata"]["host"] )
|
||||
vms.append(VM)
|
||||
self._vms = vms
|
||||
return self._vms
|
||||
|
||||
@property
|
||||
def objects(self):
|
||||
if not self._objects:
|
||||
vms = []
|
||||
|
||||
for object_ in self.contents["objects"]:
|
||||
obj = resources.Object(object_)
|
||||
obj.location = self.conn.host_to_dc( vm["metadata"]["host"] )
|
||||
vms.append(VM)
|
||||
self._vms = vms
|
||||
return self._vms
|
||||
|
||||
@property
|
||||
def volumes(self):
|
||||
return []
|
||||
|
||||
# def __getitem__(self, item):
|
||||
|
||||
# return self.contents[item]
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
@ -290,19 +364,21 @@ class Contents(object):
|
||||
def _replace(self):
|
||||
# Turns individual metering objects into
|
||||
# Usage objects that this expects.
|
||||
for dc in contents.iterkeys():
|
||||
for section in contents[dc].iterkeys():
|
||||
for dc in self.contents.iterkeys():
|
||||
for section in self.contents[dc].iterkeys():
|
||||
meters = []
|
||||
for meter in contents[dc][section]:
|
||||
|
||||
for resource in self.contents[dc][section]:
|
||||
meters.extend(resource.meters)
|
||||
usages = []
|
||||
for meter in meters:
|
||||
usage = meter.usage(self.start, self.end)
|
||||
usage.db = self.db # catch the DB context?
|
||||
usage.db = self.conn # catch the DB context?
|
||||
|
||||
meters.append(usage)
|
||||
usages.append(usage)
|
||||
# Overwrite the original metering objects
|
||||
# with the core usage objects.
|
||||
# This is because we're not storing metering.
|
||||
contents[dc][section] = meters
|
||||
self.contents[dc][section] = usages
|
||||
|
||||
def save(self):
|
||||
|
||||
@ -310,78 +386,79 @@ class Contents(object):
|
||||
Iterate the list of things; save them to DB.
|
||||
"""
|
||||
# self.db.begin()
|
||||
for dc in contents.iterkeys():
|
||||
for section in contents[dc].iterkeys():
|
||||
for meter in contents[dc][section]:
|
||||
meter.save()
|
||||
self.db.commit()
|
||||
# for
|
||||
# for dc in self.contents.iterkeys():
|
||||
# for section in self.contents[dc].iterkeys():
|
||||
# for meter in self.contents[dc][section]:
|
||||
# meter.save()
|
||||
# self.conn.session.commit()
|
||||
raise NotImplementedError("Not implemented")
|
||||
|
||||
class Resource(object):
|
||||
|
||||
def __init__(self, resource):
|
||||
def __init__(self, resource, conn):
|
||||
self.resource = resource
|
||||
self.conn = conn
|
||||
self._meters = {}
|
||||
|
||||
def meter(self, name):
|
||||
pass # Return a named meter
|
||||
|
||||
|
||||
def __getitem__(self, name):
|
||||
return self.resource[name]
|
||||
|
||||
@property
|
||||
def meters(self):
|
||||
meters = []
|
||||
for link in self.resource["links"]:
|
||||
if link["rel"] == "self":
|
||||
continue
|
||||
meter = Meter(self.resource, link)
|
||||
meters.append(meter)
|
||||
return meters
|
||||
if not self._meters:
|
||||
meters = []
|
||||
for link in self.resource["links"]:
|
||||
if link["rel"] == "self":
|
||||
continue
|
||||
meter = Meter(self, link, self.conn)
|
||||
meters.append(meter)
|
||||
self._meters = meters
|
||||
return self._meters
|
||||
|
||||
class Meter(object):
|
||||
|
||||
def __init__(self, resource, link):
|
||||
def __init__(self, resource, link, conn):
|
||||
self.resource = resource
|
||||
self.link = link
|
||||
self.conn = conn
|
||||
# self.meter = meter
|
||||
|
||||
def __getitem__(self, x):
|
||||
if isintance(x, slice):
|
||||
if isinstance(x, slice):
|
||||
# Woo
|
||||
pass
|
||||
pass
|
||||
|
||||
@property
|
||||
def usage(self, start, end):
|
||||
"""
|
||||
Usage condenses the entirety of a meter into a single datapoint:
|
||||
A volume value that we can plot as a single number against previous
|
||||
usage for a given range.
|
||||
"""
|
||||
date_fields = [{
|
||||
"field": "timestamp",
|
||||
"op": "ge",
|
||||
"value": start.strftime(date_format)
|
||||
},
|
||||
{
|
||||
"field": "timestamp",
|
||||
"op": "lt",
|
||||
"value": end.strftime(date_format)
|
||||
}
|
||||
]
|
||||
r = requests.get(
|
||||
self.link,
|
||||
headers={
|
||||
"X-Auth-Token": self.auth.auth_token,
|
||||
"Content-Type":"application/json"},
|
||||
data=json.dumps({"q": date_fields})
|
||||
)
|
||||
measurements = json.loads(r)
|
||||
measurements = get_meter(self, start, end, self.conn.auth.auth_token)
|
||||
|
||||
self.measurements = defaultdict(list)
|
||||
self.type = set([a["counter_type"] for a in measurements])
|
||||
if len(self.type) > 1:
|
||||
# That's a big problem
|
||||
raise RuntimeError("Too many types for measurement!")
|
||||
elif len(self.type) == 0:
|
||||
raise RuntimeError("No types!")
|
||||
else:
|
||||
self.type = self.type.pop()
|
||||
type_ = None
|
||||
if self.type == "cumulative":
|
||||
# The usage is the last one, which is the highest value.
|
||||
#
|
||||
# Base it just on the resource ID.
|
||||
|
||||
# Is this a reasonable thing to do?
|
||||
# Composition style: resource.meter("cpu_util").usage(start, end) == artifact
|
||||
type_ = Cumulative
|
||||
|
||||
elif self.type == "gauge":
|
||||
type_ = Gauge
|
||||
# return Gauge(self.Resource, )
|
||||
@ -392,6 +469,11 @@ class Meter(object):
|
||||
|
||||
class Artifact(object):
|
||||
|
||||
"""
|
||||
Provides base artifact controls; generic typing information
|
||||
for the artifact structures.
|
||||
"""
|
||||
|
||||
def __init__(self, resource, usage, start, end):
|
||||
|
||||
self.resource = resource
|
||||
@ -409,13 +491,41 @@ class Artifact(object):
|
||||
Persists to our database backend. Opinionatedly this is a sql datastore.
|
||||
"""
|
||||
value = self.volume()
|
||||
session = self.resource.conn.session
|
||||
# self.artifice.
|
||||
tenant_id = self.resource["tenant"]
|
||||
try:
|
||||
tenant_id = self.resource["tenant_id"]
|
||||
except KeyError:
|
||||
tenant_id = self.resource["project_id"]
|
||||
resource_id = self.resource["resource_id"]
|
||||
|
||||
usage = models.Usage(
|
||||
resource_id,
|
||||
tenant_id,
|
||||
tenant = session.query(tenants.Tenant).get(tenant_id)
|
||||
|
||||
if tenant is None:
|
||||
res = resources.Resource()
|
||||
tenant = tenants.Tenant()
|
||||
tenant.id = tenant_id
|
||||
|
||||
res.id = resource_id
|
||||
res.tenant = tenant
|
||||
session.add(res)
|
||||
session.add(tenant)
|
||||
else:
|
||||
try:
|
||||
res = session.query(resources.Resource).filter(resources.Resource.id == resource_id)[0]
|
||||
tenant = res.tenant
|
||||
except IndexError:
|
||||
res = resources.Resource()
|
||||
tenant = tenants.Tenant()
|
||||
tenant.id = tenant_id
|
||||
res.id = resource_id
|
||||
res.tenant = tenant
|
||||
session.add(res)
|
||||
session.add(tenant)
|
||||
|
||||
usage = Usage(
|
||||
res,
|
||||
tenant,
|
||||
value,
|
||||
self.start,
|
||||
self.end,
|
||||
@ -424,7 +534,6 @@ class Artifact(object):
|
||||
session.commit() # Persist to our backend
|
||||
|
||||
|
||||
|
||||
def volume(self):
|
||||
"""
|
||||
Default billable number for this volume
|
||||
|
@ -10,4 +10,53 @@ class Resource(Base):
|
||||
id = Column(String, primary_key=True)
|
||||
type_ = Column(String)
|
||||
tenant_id = Column(String, ForeignKey("tenants.id"), primary_key=True)
|
||||
tenant = relationship("Tenant", backref=backref("tenants"))
|
||||
tenant = relationship("Tenant", backref=backref("tenants"))
|
||||
|
||||
|
||||
class VM(object):
|
||||
|
||||
def __init__(self, raw):
|
||||
# raw is the raw data for this
|
||||
self._raw = raw
|
||||
|
||||
self._location = None
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._raw["metadata"]["instance_type"]
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return self.type
|
||||
|
||||
@property
|
||||
def memory(self):
|
||||
return self._raw["metadata"]["memory"]
|
||||
|
||||
@property
|
||||
def cpus(self):
|
||||
return self._raw["metadata"]["memory"]
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
return self._raw["metadata"]["state"]
|
||||
|
||||
@property
|
||||
def bandwidth(self):
|
||||
# This is a metered value
|
||||
return 0
|
||||
|
||||
@property
|
||||
def ips(self):
|
||||
"""floating IPs; this is a metered value"""
|
||||
return 0
|
||||
|
||||
|
||||
class Object(object):
|
||||
pass
|
||||
|
||||
class Volume(object):
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
pass
|
||||
|
1
tests/data/index.json
Normal file
1
tests/data/index.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_0.json
Normal file
1
tests/data/map_fixture_0.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_1.json
Normal file
1
tests/data/map_fixture_1.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/port?q.field=resource_id&q.value=07771c9c-f10e-4b08-9702-78c8618f5a48": [{"counter_name": "port", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "07771c9c-f10e-4b08-9702-78c8618f5a48", "timestamp": "2013-08-05T05:17:40.283000", "message_id": "5981ec68-fd8e-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:nova", "mac_address": "fa:16:3e:b3:f6:db", "event_type": "port.create.end", "id": "07771c9c-f10e-4b08-9702-78c8618f5a48", "device_id": "c01c63fe-7a29-4426-bab1-34d088e92415"}, "counter_type": "gauge"}, {"counter_name": "port", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "07771c9c-f10e-4b08-9702-78c8618f5a48", "timestamp": "2013-08-05T05:17:40.283000", "message_id": "5981ec68-fd8e-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:nova", "mac_address": "fa:16:3e:b3:f6:db", "event_type": "port.create.end", "id": "07771c9c-f10e-4b08-9702-78c8618f5a48", "device_id": "c01c63fe-7a29-4426-bab1-34d088e92415"}, "counter_type": "gauge"}], "http://localhost:8777/v2/meters/port.create?q.field=resource_id&q.value=07771c9c-f10e-4b08-9702-78c8618f5a48": [{"counter_name": "port.create", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "07771c9c-f10e-4b08-9702-78c8618f5a48", "timestamp": "2013-08-05T05:17:40.283000", "message_id": "5988a0e4-fd8e-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:nova", "mac_address": "fa:16:3e:b3:f6:db", "event_type": "port.create.end", "id": "07771c9c-f10e-4b08-9702-78c8618f5a48", "device_id": "c01c63fe-7a29-4426-bab1-34d088e92415"}, "counter_type": "delta"}]}
|
1
tests/data/map_fixture_10.json
Normal file
1
tests/data/map_fixture_10.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_11.json
Normal file
1
tests/data/map_fixture_11.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/port.create?q.field=resource_id&q.value=5561589b-c1fa-46eb-b9d4-5998daceaee4": [{"counter_name": "port.create", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "5561589b-c1fa-46eb-b9d4-5998daceaee4", "timestamp": "2013-08-05T21:56:25.971000", "message_id": "dff93784-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "name": "", "admin_state_up": "True", "network_id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "device_owner": "", "mac_address": "fa:16:3e:4a:5d:9a", "event_type": "port.create.end", "id": "5561589b-c1fa-46eb-b9d4-5998daceaee4", "device_id": ""}, "counter_type": "delta"}], "http://localhost:8777/v2/meters/port?q.field=resource_id&q.value=5561589b-c1fa-46eb-b9d4-5998daceaee4": [{"counter_name": "port", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "5561589b-c1fa-46eb-b9d4-5998daceaee4", "timestamp": "2013-08-05T21:56:25.971000", "message_id": "dff84b8a-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "name": "", "admin_state_up": "True", "network_id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "device_owner": "", "mac_address": "fa:16:3e:4a:5d:9a", "event_type": "port.create.end", "id": "5561589b-c1fa-46eb-b9d4-5998daceaee4", "device_id": ""}, "counter_type": "gauge"}]}
|
1
tests/data/map_fixture_12.json
Normal file
1
tests/data/map_fixture_12.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/volume?q.field=resource_id&q.value=5d658ace-2535-48c5-a05f-85d651c0d0ac": [{"counter_name": "volume", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "5d658ace-2535-48c5-a05f-85d651c0d0ac", "timestamp": "2013-08-05T03:52:24.800000", "message_id": "7069d14a-fd82-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "volume", "counter_volume": 1.0, "project_id": "7ec5ec9750414a4c8e767e16e1b6c9cf", "resource_metadata": {"status": "available", "display_name": "asdf", "event_type": "volume.create.end", "availability_zone": "nova", "tenant_id": "7ec5ec9750414a4c8e767e16e1b6c9cf", "created_at": "2013-08-05 03:52:23", "volume_id": "5d658ace-2535-48c5-a05f-85d651c0d0ac", "volume_type": "None", "host": "volume.openstack", "snapshot_id": "None", "user_id": "2b8fbe55863d4dfab5310796202b2019", "launched_at": "", "size": "2"}, "counter_type": "gauge"}], "http://localhost:8777/v2/meters/volume.size?q.field=resource_id&q.value=5d658ace-2535-48c5-a05f-85d651c0d0ac": [{"counter_name": "volume.size", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "5d658ace-2535-48c5-a05f-85d651c0d0ac", "timestamp": "2013-08-05T03:52:24.800000", "message_id": "706bcc3e-fd82-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "GB", "counter_volume": 2.0, "project_id": "7ec5ec9750414a4c8e767e16e1b6c9cf", "resource_metadata": {"status": "available", "display_name": "asdf", "event_type": "volume.create.end", "availability_zone": "nova", "tenant_id": "7ec5ec9750414a4c8e767e16e1b6c9cf", "created_at": "2013-08-05 03:52:23", "volume_id": "5d658ace-2535-48c5-a05f-85d651c0d0ac", "volume_type": "None", "host": "volume.openstack", "snapshot_id": "None", "user_id": "2b8fbe55863d4dfab5310796202b2019", "launched_at": "", "size": "2"}, "counter_type": "gauge"}]}
|
1
tests/data/map_fixture_13.json
Normal file
1
tests/data/map_fixture_13.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/port.create?q.field=resource_id&q.value=615a397c-fca2-4233-9f42-b769a8d6ea59": [{"counter_name": "port.create", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "615a397c-fca2-4233-9f42-b769a8d6ea59", "timestamp": "2013-08-04T23:58:49.296000", "message_id": "ce871c4a-fd61-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:None", "mac_address": "fa:16:3e:4d:0f:e5", "event_type": "port.create.end", "id": "615a397c-fca2-4233-9f42-b769a8d6ea59", "device_id": "03bd0d4c-99da-4ccf-b308-2721f33e84ef"}, "counter_type": "delta"}], "http://localhost:8777/v2/meters/port?q.field=resource_id&q.value=615a397c-fca2-4233-9f42-b769a8d6ea59": [{"counter_name": "port", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "615a397c-fca2-4233-9f42-b769a8d6ea59", "timestamp": "2013-08-04T23:58:49.296000", "message_id": "ce863870-fd61-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:None", "mac_address": "fa:16:3e:4d:0f:e5", "event_type": "port.create.end", "id": "615a397c-fca2-4233-9f42-b769a8d6ea59", "device_id": "03bd0d4c-99da-4ccf-b308-2721f33e84ef"}, "counter_type": "gauge"}]}
|
1
tests/data/map_fixture_14.json
Normal file
1
tests/data/map_fixture_14.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/port?q.field=resource_id&q.value=6b9765e2-9138-4468-a60c-4e9f63044d9d": [{"counter_name": "port", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "6b9765e2-9138-4468-a60c-4e9f63044d9d", "timestamp": "2013-08-05T05:17:40.286000", "message_id": "5982294e-fd8e-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:nova", "mac_address": "fa:16:3e:19:28:00", "event_type": "port.create.end", "id": "6b9765e2-9138-4468-a60c-4e9f63044d9d", "device_id": "1bd5a017-2777-4601-8c48-fd7569a4e485"}, "counter_type": "gauge"}], "http://localhost:8777/v2/meters/port.create?q.field=resource_id&q.value=6b9765e2-9138-4468-a60c-4e9f63044d9d": [{"counter_name": "port.create", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "6b9765e2-9138-4468-a60c-4e9f63044d9d", "timestamp": "2013-08-05T05:17:40.286000", "message_id": "5983bcb4-fd8e-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:nova", "mac_address": "fa:16:3e:19:28:00", "event_type": "port.create.end", "id": "6b9765e2-9138-4468-a60c-4e9f63044d9d", "device_id": "1bd5a017-2777-4601-8c48-fd7569a4e485"}, "counter_type": "delta"}]}
|
1
tests/data/map_fixture_15.json
Normal file
1
tests/data/map_fixture_15.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_16.json
Normal file
1
tests/data/map_fixture_16.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/network?q.field=resource_id&q.value=79b5e163-496c-4ab6-9c21-3b597ed632dc": [{"counter_name": "network", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "timestamp": "2013-08-05T21:56:01.044000", "message_id": "d11cd69e-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "network", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "ACTIVE", "name": "two", "admin_state_up": "True", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "shared": "False", "id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "event_type": "network.create.end"}, "counter_type": "gauge"}], "http://localhost:8777/v2/meters/network.create?q.field=resource_id&q.value=79b5e163-496c-4ab6-9c21-3b597ed632dc": [{"counter_name": "network.create", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "timestamp": "2013-08-05T21:56:01.044000", "message_id": "d11dd012-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "network", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "ACTIVE", "name": "two", "admin_state_up": "True", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "shared": "False", "id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "event_type": "network.create.end"}, "counter_type": "delta"}]}
|
1
tests/data/map_fixture_17.json
Normal file
1
tests/data/map_fixture_17.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_18.json
Normal file
1
tests/data/map_fixture_18.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_19.json
Normal file
1
tests/data/map_fixture_19.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_2.json
Normal file
1
tests/data/map_fixture_2.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_20.json
Normal file
1
tests/data/map_fixture_20.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/subnet.create?q.field=resource_id&q.value=a2777ed6-7442-42b8-bb86-5b554aad7f08": [{"counter_name": "subnet.create", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "a2777ed6-7442-42b8-bb86-5b554aad7f08", "timestamp": "2013-08-05T21:56:01.107000", "message_id": "d126f9da-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "subnet", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"name": "two", "enable_dhcp": "True", "network_id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "gateway_ip": "192.168.0.1", "ip_version": "4", "cidr": "192.168.0.0/24", "id": "a2777ed6-7442-42b8-bb86-5b554aad7f08", "event_type": "subnet.create.end"}, "counter_type": "delta"}], "http://localhost:8777/v2/meters/subnet?q.field=resource_id&q.value=a2777ed6-7442-42b8-bb86-5b554aad7f08": [{"counter_name": "subnet", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "a2777ed6-7442-42b8-bb86-5b554aad7f08", "timestamp": "2013-08-05T21:56:01.107000", "message_id": "d1264c1a-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "subnet", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"name": "two", "enable_dhcp": "True", "network_id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "gateway_ip": "192.168.0.1", "ip_version": "4", "cidr": "192.168.0.0/24", "id": "a2777ed6-7442-42b8-bb86-5b554aad7f08", "event_type": "subnet.create.end"}, "counter_type": "gauge"}]}
|
1
tests/data/map_fixture_21.json
Normal file
1
tests/data/map_fixture_21.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/volume?q.field=resource_id&q.value=a5696083-56d2-4e25-a0cb-2b51bd2ca90d": [{"counter_name": "volume", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "a5696083-56d2-4e25-a0cb-2b51bd2ca90d", "timestamp": "2013-08-05T03:50:05.084000", "message_id": "1d224d8c-fd82-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "volume", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "available", "display_name": "tests", "event_type": "volume.create.end", "availability_zone": "nova", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "created_at": "2013-08-05 03:50:03", "volume_id": "a5696083-56d2-4e25-a0cb-2b51bd2ca90d", "volume_type": "2fbf14d8-e544-487e-aba7-98c1ebba8fcd", "host": "volume.openstack", "snapshot_id": "None", "user_id": "2b8fbe55863d4dfab5310796202b2019", "launched_at": "", "size": "1"}, "counter_type": "gauge"}], "http://localhost:8777/v2/meters/volume.size?q.field=resource_id&q.value=a5696083-56d2-4e25-a0cb-2b51bd2ca90d": [{"counter_name": "volume.size", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "a5696083-56d2-4e25-a0cb-2b51bd2ca90d", "timestamp": "2013-08-05T03:50:05.084000", "message_id": "1d244fd8-fd82-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "GB", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "available", "display_name": "tests", "event_type": "volume.create.end", "availability_zone": "nova", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "created_at": "2013-08-05 03:50:03", "volume_id": "a5696083-56d2-4e25-a0cb-2b51bd2ca90d", "volume_type": "2fbf14d8-e544-487e-aba7-98c1ebba8fcd", "host": "volume.openstack", "snapshot_id": "None", "user_id": "2b8fbe55863d4dfab5310796202b2019", "launched_at": "", "size": "1"}, "counter_type": "gauge"}]}
|
1
tests/data/map_fixture_22.json
Normal file
1
tests/data/map_fixture_22.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_23.json
Normal file
1
tests/data/map_fixture_23.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/port?q.field=resource_id&q.value=b35709ef-6b3a-42d7-bd57-ef4cd673ec9b": [{"counter_name": "port", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "b35709ef-6b3a-42d7-bd57-ef4cd673ec9b", "timestamp": "2013-08-05T22:04:18.505000", "message_id": "f99f7c38-fe1a-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:None", "mac_address": "fa:16:3e:a6:d8:57", "event_type": "port.create.end", "id": "b35709ef-6b3a-42d7-bd57-ef4cd673ec9b", "device_id": "0a16330b-d457-425d-8249-a275fab9adea"}, "counter_type": "gauge"}], "http://localhost:8777/v2/meters/port.create?q.field=resource_id&q.value=b35709ef-6b3a-42d7-bd57-ef4cd673ec9b": [{"counter_name": "port.create", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "b35709ef-6b3a-42d7-bd57-ef4cd673ec9b", "timestamp": "2013-08-05T22:04:18.505000", "message_id": "f9a15652-fe1a-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "79b5e163-496c-4ab6-9c21-3b597ed632dc", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:None", "mac_address": "fa:16:3e:a6:d8:57", "event_type": "port.create.end", "id": "b35709ef-6b3a-42d7-bd57-ef4cd673ec9b", "device_id": "0a16330b-d457-425d-8249-a275fab9adea"}, "counter_type": "delta"}]}
|
1
tests/data/map_fixture_24.json
Normal file
1
tests/data/map_fixture_24.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_25.json
Normal file
1
tests/data/map_fixture_25.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_26.json
Normal file
1
tests/data/map_fixture_26.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_3.json
Normal file
1
tests/data/map_fixture_3.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_4.json
Normal file
1
tests/data/map_fixture_4.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_5.json
Normal file
1
tests/data/map_fixture_5.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_6.json
Normal file
1
tests/data/map_fixture_6.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/port?q.field=resource_id&q.value=24916b40-f8d8-49ad-be4a-4edbf6c9a370": [{"counter_name": "port", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "24916b40-f8d8-49ad-be4a-4edbf6c9a370", "timestamp": "2013-08-05T22:04:19.030000", "message_id": "f9f4e18c-fe1a-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:None", "mac_address": "fa:16:3e:de:89:e7", "event_type": "port.create.end", "id": "24916b40-f8d8-49ad-be4a-4edbf6c9a370", "device_id": "0a16330b-d457-425d-8249-a275fab9adea"}, "counter_type": "gauge"}], "http://localhost:8777/v2/meters/port.create?q.field=resource_id&q.value=24916b40-f8d8-49ad-be4a-4edbf6c9a370": [{"counter_name": "port.create", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "24916b40-f8d8-49ad-be4a-4edbf6c9a370", "timestamp": "2013-08-05T22:04:19.030000", "message_id": "f9f5a234-fe1a-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:None", "mac_address": "fa:16:3e:de:89:e7", "event_type": "port.create.end", "id": "24916b40-f8d8-49ad-be4a-4edbf6c9a370", "device_id": "0a16330b-d457-425d-8249-a275fab9adea"}, "counter_type": "delta"}]}
|
1
tests/data/map_fixture_7.json
Normal file
1
tests/data/map_fixture_7.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/data/map_fixture_8.json
Normal file
1
tests/data/map_fixture_8.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/port?q.field=resource_id&q.value=375d1c5d-e732-4082-857b-ca133f08006b": [{"counter_name": "port", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "375d1c5d-e732-4082-857b-ca133f08006b", "timestamp": "2013-08-05T05:17:39.866000", "message_id": "593b506e-fd8e-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:nova", "mac_address": "fa:16:3e:20:df:2e", "event_type": "port.create.end", "id": "375d1c5d-e732-4082-857b-ca133f08006b", "device_id": "6d254988-1431-49d7-9491-e7c27d0bd6cb"}, "counter_type": "gauge"}], "http://localhost:8777/v2/meters/port.create?q.field=resource_id&q.value=375d1c5d-e732-4082-857b-ca133f08006b": [{"counter_name": "port.create", "user_id": "9692a61b44f246259af534f0b1d95942", "resource_id": "375d1c5d-e732-4082-857b-ca133f08006b", "timestamp": "2013-08-05T05:17:39.866000", "message_id": "593d6552-fd8e-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "port", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "DOWN", "binding:host_id": "openstack", "name": "", "admin_state_up": "True", "network_id": "0e5f3762-a8a9-4051-ad35-49ad879ebfc3", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "binding:vif_type": "ovs", "device_owner": "compute:nova", "mac_address": "fa:16:3e:20:df:2e", "event_type": "port.create.end", "id": "375d1c5d-e732-4082-857b-ca133f08006b", "device_id": "6d254988-1431-49d7-9491-e7c27d0bd6cb"}, "counter_type": "delta"}]}
|
1
tests/data/map_fixture_9.json
Normal file
1
tests/data/map_fixture_9.json
Normal file
@ -0,0 +1 @@
|
||||
{"http://localhost:8777/v2/meters/router.create?q.field=resource_id&q.value=4392aff1-d6a8-4106-9e75-818eb91a3d45": [{"counter_name": "router.create", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "timestamp": "2013-08-05T21:55:26.292000", "message_id": "bc685070-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "router", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "ACTIVE", "external_gateway_info": "None", "name": "router2", "admin_state_up": "True", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "event_type": "router.create.end"}, "counter_type": "delta"}], "http://localhost:8777/v2/meters/router?q.field=resource_id&q.value=4392aff1-d6a8-4106-9e75-818eb91a3d45": [{"counter_name": "router", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "timestamp": "2013-08-05T22:07:15.284000", "message_id": "62fe6586-fe1b-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "router", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "ACTIVE", "external_gateway_info": "None", "name": "router2", "admin_state_up": "True", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "event_type": "router.update.end"}, "counter_type": "gauge"}, {"counter_name": "router", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "timestamp": "2013-08-05T21:55:33.751000", "message_id": "c0d80f10-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "router", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "ACTIVE", "name": "router2", "admin_state_up": "True", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "event_type": "router.update.end"}, "counter_type": "gauge"}, {"counter_name": "router", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "timestamp": "2013-08-05T21:55:26.292000", "message_id": "bc6726c8-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "router", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "ACTIVE", "external_gateway_info": "None", "name": "router2", "admin_state_up": "True", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "event_type": "router.create.end"}, "counter_type": "gauge"}], "http://localhost:8777/v2/meters/router.update?q.field=resource_id&q.value=4392aff1-d6a8-4106-9e75-818eb91a3d45": [{"counter_name": "router.update", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "timestamp": "2013-08-05T22:07:15.284000", "message_id": "62ff4c80-fe1b-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "router", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "ACTIVE", "external_gateway_info": "None", "name": "router2", "admin_state_up": "True", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "event_type": "router.update.end"}, "counter_type": "delta"}, {"counter_name": "router.update", "user_id": "2b8fbe55863d4dfab5310796202b2019", "resource_id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "timestamp": "2013-08-05T21:55:33.751000", "message_id": "c0d8dc74-fe19-11e2-a072-080027880ca6", "source": "openstack", "counter_unit": "router", "counter_volume": 1.0, "project_id": "931dc699f9934021bb4a2b1088ba4d3b", "resource_metadata": {"status": "ACTIVE", "name": "router2", "admin_state_up": "True", "tenant_id": "931dc699f9934021bb4a2b1088ba4d3b", "host": "network.openstack", "id": "4392aff1-d6a8-4106-9e75-818eb91a3d45", "event_type": "router.update.end"}, "counter_type": "delta"}]}
|
1
tests/data/resources.json
Normal file
1
tests/data/resources.json
Normal file
File diff suppressed because one or more lines are too long
3
tests/test_import.py
Normal file
3
tests/test_import.py
Normal file
@ -0,0 +1,3 @@
|
||||
print __file__
|
||||
import os
|
||||
print os.path.abspath(__file__)
|
320
tests/test_interface.py
Normal file
320
tests/test_interface.py
Normal file
@ -0,0 +1,320 @@
|
||||
import unittest
|
||||
from artifice import interface
|
||||
from artifice.interface import Artifice
|
||||
import mock
|
||||
import random
|
||||
import json
|
||||
import copy
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from artifice.models import Session
|
||||
from artifice.models import usage, tenants
|
||||
from artifice.models.resources import Resource
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
"""
|
||||
This module tests interacting with the Ceilometer web service.
|
||||
This will require an active Ceilometer with data in it, or,
|
||||
|
||||
"""
|
||||
|
||||
# @mock.patch("artifice.models.Session")
|
||||
# @mock.patch("keystoneclient.v2_0.client.Client")
|
||||
# @mock.patch("sqlalchemy.create_engine")
|
||||
# def test_instance_artifice(self, sqlmock, keystone, session):
|
||||
|
||||
# """Tests that artifice correctly instances."""
|
||||
# from artifice.interface import Artifice
|
||||
# # from artifice.models import usage
|
||||
|
||||
config = {
|
||||
"main": {},
|
||||
"database": {
|
||||
"username": "aurynn",
|
||||
"password": "aurynn",
|
||||
"host": "localhost",
|
||||
"port": "5433",
|
||||
"database": "artifice"
|
||||
},
|
||||
"openstack": {
|
||||
"username": "foo",
|
||||
"password": "bar",
|
||||
"default_tenant":"asdf",
|
||||
"authentication_url": "http://foo"
|
||||
},
|
||||
"ceilometer": {
|
||||
"host": 'http://whee'
|
||||
},
|
||||
"invoices": {
|
||||
"plugin": "json"
|
||||
}
|
||||
}
|
||||
|
||||
# Enter in a whoooooole bunch of mock data.
|
||||
|
||||
TENANTS = [
|
||||
{u'enabled': True,
|
||||
u'description': None,
|
||||
u'name': u'demo',
|
||||
u'id': u'931dc699f9934021bb4a2b1088ba4d3b'}
|
||||
]
|
||||
|
||||
DATACENTRE = "testcenter"
|
||||
|
||||
|
||||
# I think three is good
|
||||
import os
|
||||
try:
|
||||
fn = os.path.abspath(__file__)
|
||||
path, f = os.path.split(fn)
|
||||
except NameError:
|
||||
path = os.getcwd()
|
||||
|
||||
|
||||
fh = open( os.path.join( path, "data/resources.json") )
|
||||
resources = json.loads(fh.read () )
|
||||
fh.close()
|
||||
|
||||
i = 0
|
||||
|
||||
mappings = {}
|
||||
|
||||
hosts = set([resource["metadata"]["host"] for resource in resources if resource["metadata"].get("host")])
|
||||
|
||||
while True:
|
||||
try:
|
||||
fh = open( os.path.join( path, "data/map_fixture_%s.json" % i ) )
|
||||
d = json.loads(fh.read())
|
||||
fh.close()
|
||||
mappings.update(d)
|
||||
i += 1
|
||||
except IOError:
|
||||
break
|
||||
|
||||
# Mappings should now be a set of resources.
|
||||
|
||||
AUTH_TOKEN = "ASDFTOKEN"
|
||||
|
||||
storages = []
|
||||
vms = []
|
||||
networks = []
|
||||
|
||||
# res = {"vms": [], "net": [], 'storage': [], "ports":[], "ips": []}
|
||||
# res = {"vms": [], "network": [], 'storage': [], "ports":[]}
|
||||
res = {"vms": [], "volumes": [], 'objects': [], "network": []}
|
||||
|
||||
for resource in resources:
|
||||
rels = [link["rel"] for link in resource["links"] if link["rel"] != 'self' ]
|
||||
if "image" in rels:
|
||||
continue
|
||||
elif "storage.objects" in rels:
|
||||
# Unknown how this data layout happens yet.
|
||||
# resource["_type"] = "storage"
|
||||
res["objects"].append(resource)
|
||||
elif "volume" in rels:
|
||||
res["volumes"].append(resource)
|
||||
elif "network" in rels:
|
||||
res["network"].append(resource)
|
||||
elif "instance" in rels:
|
||||
res["vms"].append(resource)
|
||||
# elif "port" in rels:
|
||||
# res["ports"].append(resource)
|
||||
# elif "ip.floating" in rels:
|
||||
# res["ips"].append(resource)
|
||||
|
||||
|
||||
def resources_replacement(tester):
|
||||
#
|
||||
def repl(self, start, end):
|
||||
tester.called_replacement_resources = True
|
||||
return resources
|
||||
|
||||
class TestInterface(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
engine = create_engine(os.environ["DATABASE_URL"])
|
||||
Session.configure(bind=engine)
|
||||
self.session = Session()
|
||||
self.objects = []
|
||||
self.session.rollback()
|
||||
self.called_replacement_resources = False
|
||||
|
||||
num = random.randrange(len(res["vms"]))
|
||||
# Only one vm for this
|
||||
self.resources = [ res["vms"][ num ] ]
|
||||
|
||||
self.start = datetime.now() - timedelta(days=30)
|
||||
self.end = datetime.now()
|
||||
|
||||
def tearDown(self):
|
||||
|
||||
self.session.query(usage.Usage).delete()
|
||||
self.session.query(Resource).delete()
|
||||
self.session.query(tenants.Tenant).delete()
|
||||
|
||||
|
||||
self.session.commit()
|
||||
self.contents = None
|
||||
self.resources = []
|
||||
|
||||
|
||||
@mock.patch("artifice.models.Session")
|
||||
# @mock.patch("artifice.interface.get_meter") # I don't think this will work
|
||||
@mock.patch("artifice.interface.keystone")
|
||||
@mock.patch("sqlalchemy.create_engine")
|
||||
def test_get_usage(self, sqlmock, keystone, session):
|
||||
|
||||
# At this point, we prime the ceilometer/requests response
|
||||
# system, so that what we return to usage is what we expect
|
||||
# to get in the usage system.
|
||||
|
||||
keystone.auth_token = AUTH_TOKEN
|
||||
# keystone.
|
||||
self.assertTrue(TENANTS is not None)
|
||||
|
||||
def get_meter(self, start, end, auth):
|
||||
# Returns meter data from our data up above
|
||||
global mappings
|
||||
# print self.link
|
||||
data = mappings[self.link["href"]]
|
||||
return data
|
||||
|
||||
interface.get_meter = get_meter
|
||||
|
||||
artifice = Artifice(config)
|
||||
# Needed because this
|
||||
artifice.auth.tenants.list.return_value = TENANTS
|
||||
# this_config = copy.deepcopy(config["openstack"])
|
||||
# this_config["tenant_name"] = this_config["default_tenant"]
|
||||
# del this_config["default_tenant"]
|
||||
|
||||
keystone.assert_called_with(
|
||||
username= config["openstack"]["username"],
|
||||
password= config["openstack"]["password"],
|
||||
tenant_name= config["openstack"]["default_tenant"],
|
||||
auth_url= config["openstack"]["authentication_url"]
|
||||
)
|
||||
tenants = None
|
||||
try:
|
||||
tenants = artifice.tenants
|
||||
except Exception as e:
|
||||
self.fail(e)
|
||||
|
||||
# self.assertEqual ( len(tenants.vms), 1 )
|
||||
|
||||
self.assertEqual( len(tenants), 1 )
|
||||
k = tenants.keys()[0]
|
||||
t = tenants[k]
|
||||
self.assertTrue( isinstance( t, interface.Tenant ) )
|
||||
|
||||
contents = None
|
||||
|
||||
# t.resources = resources_replacement(self)
|
||||
t.resources = mock.Mock()
|
||||
t.resources.return_value = self.resources
|
||||
|
||||
artifice.host_to_dc = mock.Mock()
|
||||
|
||||
artifice.host_to_dc.return_value = DATACENTRE
|
||||
|
||||
usage = t.usage(self.start, self.end)
|
||||
# try:
|
||||
|
||||
# except Exception as e:
|
||||
# self.fail(e)
|
||||
|
||||
# self.assertTrue( self.called_replacement_resources )
|
||||
t.resources.assert_called_with(self.start, self.end)
|
||||
|
||||
# So, we should be able to assert a couple of things here
|
||||
# What got called, when, and how.
|
||||
|
||||
for call in artifice.host_to_dc.call_args_list:
|
||||
self.assertTrue ( len(call[0]) == 1 )
|
||||
self.assertTrue ( call[0][0] in hosts )
|
||||
|
||||
self.assertTrue ( isinstance(usage, interface.Usage) )
|
||||
|
||||
# self.assertEqual( len(usage.vms), 1 )
|
||||
# self.assertEqual( len(usage.objects), 0)
|
||||
# self.assertEqual( len(usage.volumes), 0)
|
||||
|
||||
self.usage = usage
|
||||
|
||||
# @mock.patch("artifice.models.Session")
|
||||
# @mock.patch("artifice.interface.get_meter") # I don't think this will work
|
||||
# @mock.patch("artifice.interface.keystone")
|
||||
# @mock.patch("sqlalchemy.create_engine")
|
||||
# def test_save_smaller_range_no_overlap(self, sqlmock, keystone, meters, session):
|
||||
|
||||
# self.test_get_usage()
|
||||
|
||||
# first_contents = self.usage
|
||||
|
||||
# # self.resources = [
|
||||
# # res["vms"][random.randrange(len[res["vms"]])],
|
||||
# # ]
|
||||
|
||||
|
||||
def add_element(self, from_):
|
||||
|
||||
self.resources.append( res[from_][random.randrange(len(res[from_]))] )
|
||||
print len(self.resources)
|
||||
|
||||
self.test_get_usage()
|
||||
usage = self.usage
|
||||
|
||||
# key = contents.keys()[0] # Key is the datacenter
|
||||
print from_
|
||||
self.assertTrue( hasattr(usage, from_) )
|
||||
self.assertTrue( hasattr(usage, "vms") )
|
||||
|
||||
lens = { "vms": 1}
|
||||
|
||||
if from_ == "vms":
|
||||
lens["vms"] = 2
|
||||
else:
|
||||
lens[from_] = 1
|
||||
|
||||
self.assertEqual(len(usage.vms), lens["vms"])
|
||||
self.assertEqual(len( getattr(usage, from_) ), lens[from_])
|
||||
|
||||
self.assertEqual( usage.vms[0].location, DATACENTRE )
|
||||
|
||||
def test_add_instance(self):
|
||||
"""
|
||||
Adds a new instance, tests that the returned data has both
|
||||
|
||||
Tests that if we create a new instance in the data,
|
||||
we should get another instance in the returned contents.
|
||||
"""
|
||||
|
||||
self.add_element("vms")
|
||||
|
||||
def test_add_storage(self):
|
||||
|
||||
self.add_element("objects")
|
||||
|
||||
# def test_add_ip(self):
|
||||
# self.add_element("ips")
|
||||
|
||||
def test_save_contents(self):
|
||||
|
||||
self.test_get_usage()
|
||||
|
||||
usage = self.usage
|
||||
# try:
|
||||
usage.save()
|
||||
# except Exception as e:
|
||||
self.fail(e)
|
||||
|
||||
# Now examine the database
|
||||
|
||||
def test_correct_usage_values(self):
|
||||
pass
|
||||
|
||||
def test_use_a_bunch_of_data(self):
|
||||
pass
|
@ -11,12 +11,10 @@ class TestInvoicing(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
|
||||
def test_replace_invoice_object(self):
|
||||
pass
|
||||
|
||||
def test_add_usage_to_invoice(self):
|
||||
|
||||
pass
|
||||
|
||||
def test_save_invoice(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user