diff --git a/artifice/billing/csv_invoice.py b/artifice/billing/csv_invoice.py index 6303e21..c1edca2 100644 --- a/artifice/billing/csv_invoice.py +++ b/artifice/billing/csv_invoice.py @@ -1,12 +1,12 @@ import os from csv import writer from artifice import invoice -from artifice import clerk_mixins +# from artifice import clerk_mixins import yaml from decimal import * -class Csv(clerk_mixins.ClerkRatesMixin, invoice.Invoice): +class Csv(invoice.RatesFileMixin, invoice.Invoice): def __init__(self, tenant, start, end, config): self.config = config diff --git a/artifice/database.py b/artifice/database.py index 7c99374..e4c3557 100644 --- a/artifice/database.py +++ b/artifice/database.py @@ -1,7 +1,5 @@ from sqlalchemy import func -from .models.db_models import Tenant as tenant_model -from .models.db_models import UsageEntry, Resource -from .models import billing, Base +from .models import billing, Base, Tenant, Resource, UsageEntry import collections import json @@ -61,12 +59,12 @@ class Database(object): """Returns a list of tenants based on the usage entries in the given range. start, end: define the range to query - teants: is a iterable of tenants, + tenants: is a iterable of tenants, if not given will default to whole tenant list.""" if tenants is None: - tenants = self.session.query(tenant_model.tenant_id).\ - filter(tenant_model.active) + tenants = self.session.query(Tenant.tenant_id).\ + filter(Tenant.active) elif not isinstance(tenants, collections.Iterable): raise AttributeError("tenants is not an iterable") @@ -103,8 +101,8 @@ class Database(object): resource.usage_strategies[entry.service] = usage_strat # build tenant: - name = self.session.query(tenant_model.name).\ - filter(tenant_model.tenant_id == entry.tenant_id) + name = self.session.query(Tenant.name).\ + filter(Tenant.tenant_id == entry.tenant_id) tenant = billing.Tenant(name[0].name, entry.tenant_id) # add resource to tenant: tenant.resources[entry.resource_id] = resource diff --git a/artifice/invoice.py b/artifice/invoice.py index baccbff..8704bcc 100644 --- a/artifice/invoice.py +++ b/artifice/invoice.py @@ -118,7 +118,7 @@ class RatesFileMixin(object): # Adds a rates file loader, expecting various things from the # configuration - def rate(self, name): + def rate(self, name, region=None): try: self.__rates except AttributeError: diff --git a/artifice/models/__init__.py b/artifice/models/__init__.py index 1545f9e..0bd598d 100644 --- a/artifice/models/__init__.py +++ b/artifice/models/__init__.py @@ -1,8 +1,48 @@ from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker +from sqlalchemy import Column, Text, DateTime, Boolean, DECIMAL Base = declarative_base() # -Session = sessionmaker() \ No newline at end of file +Session = sessionmaker() + + +class UsageEntry(Base): + """Simplified data store of usage information for a given service, + in a resource, in a tenant. Similar to ceilometer datastore, + but stores local transformed data.""" + __tablename__ = 'usage' + service = Column(Text, primary_key=True) + volume = Column(DECIMAL) + resource_id = Column(Text, primary_key=True) + tenant_id = Column(Text, primary_key=True) + start = Column(DateTime) + end = Column(DateTime, primary_key=True) + + +class Resource(Base): + """Database model for storing metadata associated with a resource.""" + __tablename__ = 'resources' + resource_id = Column(Text, primary_key=True) + info = Column(Text) + + +# this might not be a needed model? +class SalesOrder(Base): + """Historic billing periods so that tenants cannot be rebuild accidentally.""" + __tablename__ = 'sales_orders' + tenant_id = Column(Text, primary_key=True) + start = Column(DateTime) + end = Column(DateTime, primary_key=True) + + +class Tenant(Base): + """Model for storage of metadata related to a tenant.""" + __tablename__ = 'tenants' + # ID is a uuid + tenant_id = Column(Text, primary_key=True, nullable=False) + name = Column(Text) + info = Column(Text) + active = Column(Boolean, default=True) + # Some reference data to something else? diff --git a/artifice/models/db_models.py b/artifice/models/db_models.py deleted file mode 100644 index 1939312..0000000 --- a/artifice/models/db_models.py +++ /dev/null @@ -1,36 +0,0 @@ -from . import Base -from sqlalchemy import Column, Text, DateTime, Boolean, DECIMAL - - -class UsageEntry(Base): - __tablename__ = 'usage' - service = Column(Text, primary_key=True) - volume = Column(DECIMAL) - resource_id = Column(Text, primary_key=True) - tenant_id = Column(Text, primary_key=True) - start = Column(DateTime) - end = Column(DateTime, primary_key=True) - - -class Resource(Base): - __tablename__ = 'resources' - resource_id = Column(Text, primary_key=True) - info = Column(Text) - - -class SalesOrder(Base): - __tablename__ = 'sales_orders' - tenant_id = Column(Text, primary_key=True) - start = Column(DateTime) - end = Column(DateTime, primary_key=True) - - -class Tenant(Base): - - __tablename__ = 'tenants' - # ID is a uuid - tenant_id = Column(Text, primary_key=True, nullable=False) - name = Column(Text) - info = Column(Text) - active = Column(Boolean, default=True) - # Some reference data to something else? diff --git a/examples/csv_rates.csv b/examples/csv_rates.csv index cfd5356..027f2ce 100644 --- a/examples/csv_rates.csv +++ b/examples/csv_rates.csv @@ -1,8 +1,8 @@ -region | m1.nano | duration | 0.32 -region | m1.micro | duration | 0.42 -region | m1.tiny | duration | 0.62 -region | m1.small | duration | 0.82 -region | m1.medium | duration | 1.02 +region | m1_nano | duration | 0.32 +region | m1_micro | duration | 0.42 +region | m1_tiny | duration | 0.62 +region | m1_small | duration | 0.82 +region | m1_medium | duration | 1.02 region | incoming_megabytes | bytes | 0.004 region | outgoing_megabytes | bytes | 0.007 region | storage_size | bytes per hour | 0.000513 diff --git a/tests/test_DB_transform.py b/tests/test_DB_transform.py index 3244eea..fc6904b 100644 --- a/tests/test_DB_transform.py +++ b/tests/test_DB_transform.py @@ -1,7 +1,7 @@ from . import test_interface from decimal import Decimal from artifice import database -from artifice.models.db_models import Tenant +from artifice.models import Tenant from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() diff --git a/tests/test_csv_invoice.py b/tests/test_csv_invoice.py index 8344aa0..6ac809e 100644 --- a/tests/test_csv_invoice.py +++ b/tests/test_csv_invoice.py @@ -1,6 +1,6 @@ from . import test_interface from artifice import database -from artifice.models.db_models import Tenant +from artifice.models import Tenant from sqlalchemy.ext.declarative import declarative_base from artifice.billing import csv_invoice @@ -10,7 +10,7 @@ Base = declarative_base() config = { "output_file": '%(tenant)s-%(start)s-%(end)s.csv', - "output_path": "./invoices", + "output_path": "./tests/invoices", "rates": {"file": "/home/adriant/Projects/openstack-artifice/examples/csv_rates.csv"} } diff --git a/tests/test_interface.py b/tests/test_interface.py index 7d4b5fb..3561d91 100644 --- a/tests/test_interface.py +++ b/tests/test_interface.py @@ -4,8 +4,8 @@ from artifice.interface import Artifice import mock import random import json -from artifice.models.db_models import Tenant as tenant_model -from artifice.models.db_models import UsageEntry, Resource +from artifice.models import Tenant as tenant_model +from artifice.models import UsageEntry, Resource # import copy from sqlalchemy import create_engine