Improved documentation (docstrings and sphinx)
Added docstrings to every controllers and types. Added samples for every types. Improved CloudKitty's developper documentation. Change-Id: Idcd25777f67c61c096fbc52962bc173a86d614ba
This commit is contained in:
@@ -28,50 +28,111 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class APILink(wtypes.Base):
|
class APILink(wtypes.Base):
|
||||||
|
"""API link description.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
type = wtypes.text
|
type = wtypes.text
|
||||||
|
"""Type of link."""
|
||||||
|
|
||||||
rel = wtypes.text
|
rel = wtypes.text
|
||||||
|
"""Relationship with this link."""
|
||||||
|
|
||||||
href = wtypes.text
|
href = wtypes.text
|
||||||
|
"""URL of the link."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
version = 'v1'
|
||||||
|
sample = cls(
|
||||||
|
rel='self',
|
||||||
|
type='text/html',
|
||||||
|
href='http://127.0.0.1:8888/{id}'.format(
|
||||||
|
id=version))
|
||||||
|
return sample
|
||||||
|
|
||||||
|
|
||||||
class APIMediaType(wtypes.Base):
|
class APIMediaType(wtypes.Base):
|
||||||
|
"""Media type description.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
base = wtypes.text
|
base = wtypes.text
|
||||||
|
"""Base type of this media type."""
|
||||||
|
|
||||||
type = wtypes.text
|
type = wtypes.text
|
||||||
|
"""Type of this media type."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
sample = cls(
|
||||||
|
base='application/json',
|
||||||
|
type='application/vnd.openstack.cloudkitty-v1+json')
|
||||||
|
return sample
|
||||||
|
|
||||||
|
|
||||||
|
VERSION_STATUS = wtypes.Enum(wtypes.text, 'EXPERIMENTAL', 'STABLE')
|
||||||
|
|
||||||
|
|
||||||
class APIVersion(wtypes.Base):
|
class APIVersion(wtypes.Base):
|
||||||
|
"""API Version description.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
id = wtypes.text
|
id = wtypes.text
|
||||||
|
"""ID of the version."""
|
||||||
|
|
||||||
status = wtypes.text
|
status = VERSION_STATUS
|
||||||
|
"""Status of the version."""
|
||||||
|
|
||||||
|
updated = wtypes.text
|
||||||
|
"Last update in iso8601 format."
|
||||||
|
|
||||||
links = [APILink]
|
links = [APILink]
|
||||||
|
"""List of links to API resources."""
|
||||||
|
|
||||||
media_types = [APIMediaType]
|
media_types = [APIMediaType]
|
||||||
|
"""Types accepted by this API."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
version = 'v1'
|
||||||
|
updated = '2014-08-11T16:00:00Z'
|
||||||
|
links = [APILink.sample()]
|
||||||
|
media_types = [APIMediaType.sample()]
|
||||||
|
sample = cls(id=version,
|
||||||
|
status='STABLE',
|
||||||
|
updated=updated,
|
||||||
|
links=links,
|
||||||
|
media_types=media_types)
|
||||||
|
return sample
|
||||||
|
|
||||||
|
|
||||||
class RootController(rest.RestController):
|
class RootController(rest.RestController):
|
||||||
|
"""Root REST Controller exposing versions of the API.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
v1 = v1.V1Controller()
|
v1 = v1.V1Controller()
|
||||||
|
|
||||||
@wsme_pecan.wsexpose([APIVersion])
|
@wsme_pecan.wsexpose([APIVersion])
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Return the version list
|
||||||
|
|
||||||
|
"""
|
||||||
# TODO(sheeprine): Maybe we should store all the API version
|
# TODO(sheeprine): Maybe we should store all the API version
|
||||||
# informations in every API modules
|
# informations in every API modules
|
||||||
ver1 = APIVersion(
|
ver1 = APIVersion(
|
||||||
id='v1',
|
id='v1',
|
||||||
status='EXPERIMENTAL',
|
status='EXPERIMENTAL',
|
||||||
updated='2014-06-02T00:00:00Z',
|
updated='2014-08-11T16:00:00Z',
|
||||||
links=[
|
links=[
|
||||||
APILink(
|
APILink(
|
||||||
rel='self',
|
rel='self',
|
||||||
href='{scheme}://{host}/v1'.format(
|
href='{scheme}://{host}:{port}/v1'.format(
|
||||||
scheme=pecan.request.scheme,
|
scheme=pecan.request.scheme,
|
||||||
host=pecan.request.host
|
host=pecan.request.host,
|
||||||
|
port=pecan.request.port
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -33,14 +33,20 @@ CLOUDKITTY_SERVICES = wtypes.Enum(wtypes.text,
|
|||||||
|
|
||||||
|
|
||||||
class ResourceDescriptor(wtypes.Base):
|
class ResourceDescriptor(wtypes.Base):
|
||||||
|
"""Type describing a resource in CloudKitty.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
service = CLOUDKITTY_SERVICES
|
service = CLOUDKITTY_SERVICES
|
||||||
|
"""Name of the service."""
|
||||||
|
|
||||||
# FIXME(sheeprine): values should be dynamic
|
# FIXME(sheeprine): values should be dynamic
|
||||||
# Testing with ironic dynamic type
|
# Testing with ironic dynamic type
|
||||||
desc = {wtypes.text: cktypes.MultiType(wtypes.text, int, float, dict)}
|
desc = {wtypes.text: cktypes.MultiType(wtypes.text, int, float, dict)}
|
||||||
|
"""Description of the resources parameters."""
|
||||||
|
|
||||||
volume = int
|
volume = int
|
||||||
|
"""Number of resources."""
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
res_dict = {}
|
res_dict = {}
|
||||||
@@ -50,8 +56,20 @@ class ResourceDescriptor(wtypes.Base):
|
|||||||
}]
|
}]
|
||||||
return res_dict
|
return res_dict
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
sample = cls(service='compute',
|
||||||
|
desc={
|
||||||
|
'image_id': 'a41fba37-2429-4f15-aa00-b5bc4bf557bf'
|
||||||
|
},
|
||||||
|
volume=1)
|
||||||
|
return sample
|
||||||
|
|
||||||
|
|
||||||
class ModulesController(rest.RestController):
|
class ModulesController(rest.RestController):
|
||||||
|
"""REST Controller managing billing modules.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.extensions = extension.ExtensionManager(
|
self.extensions = extension.ExtensionManager(
|
||||||
@@ -72,6 +90,10 @@ class ModulesController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose([wtypes.text])
|
@wsme_pecan.wsexpose([wtypes.text])
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Return the list of loaded modules.
|
||||||
|
|
||||||
|
:return: Name of every loaded modules.
|
||||||
|
"""
|
||||||
return [ext for ext in self.extensions.names()]
|
return [ext for ext in self.extensions.names()]
|
||||||
|
|
||||||
|
|
||||||
@@ -85,6 +107,12 @@ class BillingController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(float, body=[ResourceDescriptor])
|
@wsme_pecan.wsexpose(float, body=[ResourceDescriptor])
|
||||||
def quote(self, res_data):
|
def quote(self, res_data):
|
||||||
|
"""Get an instant quote based on multiple resource descriptions.
|
||||||
|
|
||||||
|
:param res_data: List of resource descriptions.
|
||||||
|
:return: Total price for these descriptions.
|
||||||
|
"""
|
||||||
|
|
||||||
# TODO(sheeprine): Send RPC request for quote
|
# TODO(sheeprine): Send RPC request for quote
|
||||||
from cloudkitty import extension_manager
|
from cloudkitty import extension_manager
|
||||||
b_processors = {}
|
b_processors = {}
|
||||||
@@ -115,6 +143,9 @@ class BillingController(rest.RestController):
|
|||||||
|
|
||||||
|
|
||||||
class ReportController(rest.RestController):
|
class ReportController(rest.RestController):
|
||||||
|
"""REST Controller managing the reporting.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
_custom_actions = {
|
_custom_actions = {
|
||||||
'total': ['GET']
|
'total': ['GET']
|
||||||
@@ -122,11 +153,17 @@ class ReportController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(float)
|
@wsme_pecan.wsexpose(float)
|
||||||
def total(self):
|
def total(self):
|
||||||
|
"""Return the amount to pay for the current month.
|
||||||
|
|
||||||
|
"""
|
||||||
# TODO(sheeprine): Get current total from DB
|
# TODO(sheeprine): Get current total from DB
|
||||||
return 10.0
|
return 10.0
|
||||||
|
|
||||||
|
|
||||||
class V1Controller(rest.RestController):
|
class V1Controller(rest.RestController):
|
||||||
|
"""API version 1 controller.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
billing = BillingController()
|
billing = BillingController()
|
||||||
report = ReportController()
|
report = ReportController()
|
||||||
|
|||||||
@@ -39,19 +39,37 @@ class ExtensionSummary(wtypes.Base):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
name = wtypes.wsattr(wtypes.text, mandatory=True)
|
name = wtypes.wsattr(wtypes.text, mandatory=True)
|
||||||
|
"""Name of the extension."""
|
||||||
|
|
||||||
description = wtypes.text
|
description = wtypes.text
|
||||||
|
"""Short description of the extension."""
|
||||||
|
|
||||||
enabled = wtypes.wsattr(bool, default=False)
|
enabled = wtypes.wsattr(bool, default=False)
|
||||||
|
"""Extension status."""
|
||||||
|
|
||||||
hot_config = wtypes.wsattr(bool, default=False, name='hot-config')
|
hot_config = wtypes.wsattr(bool, default=False, name='hot-config')
|
||||||
|
"""On-the-fly configuration support."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
sample = cls(name='example',
|
||||||
|
description='Sample extension.',
|
||||||
|
enabled=True,
|
||||||
|
hot_config=False)
|
||||||
|
return sample
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class BillingEnableController(rest.RestController):
|
class BillingEnableController(rest.RestController):
|
||||||
|
"""REST Controller to enable or disable a billing module.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(bool)
|
@wsme_pecan.wsexpose(bool)
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Get module status
|
||||||
|
|
||||||
|
"""
|
||||||
api = db_api.get_instance()
|
api = db_api.get_instance()
|
||||||
module = pecan.request.path.rsplit('/', 2)[-2]
|
module = pecan.request.path.rsplit('/', 2)[-2]
|
||||||
module_db = api.get_module_enable_state()
|
module_db = api.get_module_enable_state()
|
||||||
@@ -59,6 +77,11 @@ class BillingEnableController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(bool, body=bool)
|
@wsme_pecan.wsexpose(bool, body=bool)
|
||||||
def put(self, state):
|
def put(self, state):
|
||||||
|
"""Set module status
|
||||||
|
|
||||||
|
:param state: State to set.
|
||||||
|
:return: New state set for the module.
|
||||||
|
"""
|
||||||
api = db_api.get_instance()
|
api = db_api.get_instance()
|
||||||
module = pecan.request.path.rsplit('/', 2)[-2]
|
module = pecan.request.path.rsplit('/', 2)[-2]
|
||||||
module_db = api.get_module_enable_state()
|
module_db = api.get_module_enable_state()
|
||||||
@@ -67,18 +90,37 @@ class BillingEnableController(rest.RestController):
|
|||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class BillingConfigController(rest.RestController):
|
class BillingConfigController(rest.RestController):
|
||||||
|
"""REST Controller managing internal configuration of billing modules.
|
||||||
|
|
||||||
@wsme_pecan.wsexpose()
|
"""
|
||||||
def get(self):
|
|
||||||
|
def _not_configurable(self):
|
||||||
try:
|
try:
|
||||||
module = pecan.request.path.rsplit('/', 1)[-1]
|
module = pecan.request.path.rsplit('/', 1)[-1]
|
||||||
raise BillingModuleNotConfigurable(module)
|
raise BillingModuleNotConfigurable(module)
|
||||||
except BillingModuleNotConfigurable as e:
|
except BillingModuleNotConfigurable as e:
|
||||||
pecan.abort(400, str(e))
|
pecan.abort(400, str(e))
|
||||||
|
|
||||||
|
@wsme_pecan.wsexpose()
|
||||||
|
def get(self):
|
||||||
|
"""Get current module configuration
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._not_configurable()
|
||||||
|
|
||||||
|
@wsme_pecan.wsexpose()
|
||||||
|
def put(self):
|
||||||
|
"""Set current module configuration
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._not_configurable()
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class BillingController(rest.RestController):
|
class BillingController(rest.RestController):
|
||||||
|
"""REST Controller used to manage billing system.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
config = BillingConfigController()
|
config = BillingConfigController()
|
||||||
enabled = BillingEnableController()
|
enabled = BillingEnableController()
|
||||||
|
|||||||
@@ -34,8 +34,15 @@ MAP_TYPE = wtypes.Enum(wtypes.text, 'flat', 'rate')
|
|||||||
class Mapping(wtypes.Base):
|
class Mapping(wtypes.Base):
|
||||||
|
|
||||||
map_type = wtypes.wsattr(MAP_TYPE, default='rate', name='type')
|
map_type = wtypes.wsattr(MAP_TYPE, default='rate', name='type')
|
||||||
|
"""Type of the mapping."""
|
||||||
|
|
||||||
value = wtypes.wsattr(float, mandatory=True)
|
value = wtypes.wsattr(float, mandatory=True)
|
||||||
|
"""Value of the mapping."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
sample = cls(value=4.2)
|
||||||
|
return sample
|
||||||
|
|
||||||
|
|
||||||
class BasicHashMapConfigController(billing.BillingConfigController):
|
class BasicHashMapConfigController(billing.BillingConfigController):
|
||||||
@@ -56,7 +63,7 @@ class BasicHashMapConfigController(billing.BillingConfigController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(Mapping, wtypes.text, wtypes.text, wtypes.text)
|
@wsme_pecan.wsexpose(Mapping, wtypes.text, wtypes.text, wtypes.text)
|
||||||
def get_mapping(self, service, field, key):
|
def get_mapping(self, service, field, key):
|
||||||
"""Return the list of every mappings.
|
"""Get a mapping from full path.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
hashmap = api.get_instance()
|
hashmap = api.get_instance()
|
||||||
@@ -67,6 +74,10 @@ class BasicHashMapConfigController(billing.BillingConfigController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose([wtypes.text])
|
@wsme_pecan.wsexpose([wtypes.text])
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Get the service list
|
||||||
|
|
||||||
|
:return: List of every services' name.
|
||||||
|
"""
|
||||||
hashmap = api.get_instance()
|
hashmap = api.get_instance()
|
||||||
return [service.name for service in hashmap.list_services()]
|
return [service.name for service in hashmap.list_services()]
|
||||||
|
|
||||||
@@ -74,6 +85,8 @@ class BasicHashMapConfigController(billing.BillingConfigController):
|
|||||||
def get_one(self, service=None, field=None):
|
def get_one(self, service=None, field=None):
|
||||||
"""Return the list of every sub keys.
|
"""Return the list of every sub keys.
|
||||||
|
|
||||||
|
:param service: (Optional) Filter on this service.
|
||||||
|
:param field: (Optional) Filter on this field.
|
||||||
"""
|
"""
|
||||||
hashmap = api.get_instance()
|
hashmap = api.get_instance()
|
||||||
if field:
|
if field:
|
||||||
@@ -95,6 +108,13 @@ class BasicHashMapConfigController(billing.BillingConfigController):
|
|||||||
@wsme_pecan.wsexpose(None, wtypes.text, wtypes.text, wtypes.text,
|
@wsme_pecan.wsexpose(None, wtypes.text, wtypes.text, wtypes.text,
|
||||||
body=Mapping)
|
body=Mapping)
|
||||||
def post(self, service, field=None, key=None, mapping=None):
|
def post(self, service, field=None, key=None, mapping=None):
|
||||||
|
"""Create hashmap fields.
|
||||||
|
|
||||||
|
:param service: Name of the service to create.
|
||||||
|
:param field: (Optional) Name of the field to create.
|
||||||
|
:param key: (Optional) Name of the key to create.
|
||||||
|
:param mapping: (Optional) Mapping object to create.
|
||||||
|
"""
|
||||||
hashmap = api.get_instance()
|
hashmap = api.get_instance()
|
||||||
if field:
|
if field:
|
||||||
if key:
|
if key:
|
||||||
@@ -131,6 +151,13 @@ class BasicHashMapConfigController(billing.BillingConfigController):
|
|||||||
@wsme_pecan.wsexpose(None, wtypes.text, wtypes.text, wtypes.text,
|
@wsme_pecan.wsexpose(None, wtypes.text, wtypes.text, wtypes.text,
|
||||||
body=Mapping)
|
body=Mapping)
|
||||||
def put(self, service, field, key, mapping):
|
def put(self, service, field, key, mapping):
|
||||||
|
"""Modify hashmap fields
|
||||||
|
|
||||||
|
:param service: Filter on this service.
|
||||||
|
:param field: Filter on this field.
|
||||||
|
:param key: Modify the content of this key.
|
||||||
|
:param mapping: Mapping object to update.
|
||||||
|
"""
|
||||||
hashmap = api.get_instance()
|
hashmap = api.get_instance()
|
||||||
try:
|
try:
|
||||||
hashmap.update_mapping(
|
hashmap.update_mapping(
|
||||||
@@ -149,6 +176,9 @@ class BasicHashMapConfigController(billing.BillingConfigController):
|
|||||||
def delete(self, service, field=None, key=None):
|
def delete(self, service, field=None, key=None):
|
||||||
"""Delete the parent and all the sub keys recursively.
|
"""Delete the parent and all the sub keys recursively.
|
||||||
|
|
||||||
|
:param service: Name of the service to delete.
|
||||||
|
:param field: (Optional) Name of the field to delete.
|
||||||
|
:param key: (Optional) Name of the key to delete.
|
||||||
"""
|
"""
|
||||||
hashmap = api.get_instance()
|
hashmap = api.get_instance()
|
||||||
try:
|
try:
|
||||||
|
|||||||
47
doc/source/arch.rst
Normal file
47
doc/source/arch.rst
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
=========================
|
||||||
|
CloudKitty's Architecture
|
||||||
|
=========================
|
||||||
|
|
||||||
|
CloudKitty can be cut in four big parts:
|
||||||
|
|
||||||
|
* API
|
||||||
|
* collector
|
||||||
|
* billing processor
|
||||||
|
* writer pipeline
|
||||||
|
|
||||||
|
|
||||||
|
Module loading and extensions
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Nearly every part of CloudKitty makes use of stevedore to load extensions
|
||||||
|
dynamically.
|
||||||
|
|
||||||
|
Every billing module is loaded at runtime and can be enabled/disabled directly
|
||||||
|
via CloudKitty's API. The billing module is responsible of its own API to ease
|
||||||
|
the management of its configuration.
|
||||||
|
|
||||||
|
Collectors and writers are loaded with stevedore but configured in CloudKitty's
|
||||||
|
configuration file.
|
||||||
|
|
||||||
|
|
||||||
|
Collector
|
||||||
|
=========
|
||||||
|
|
||||||
|
This part is responsible of the information gathering. It consists of a python
|
||||||
|
module that load data from a backend and return them in a format that
|
||||||
|
CloudKitty can handle.
|
||||||
|
|
||||||
|
Processor
|
||||||
|
=========
|
||||||
|
|
||||||
|
This is where every pricing calculations is done. The data gathered by
|
||||||
|
the collector is pushed in a pipeline of billing processors. Every
|
||||||
|
processor does its calculations and updates the data.
|
||||||
|
|
||||||
|
|
||||||
|
Writer
|
||||||
|
======
|
||||||
|
|
||||||
|
In the same way as the processor pipeline, the writing is handled with a
|
||||||
|
pipeline. The data is pushed to every writer in the pipeline which is
|
||||||
|
responsible of the writing.
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
# All configuration values have a default; values that are commented out
|
# All configuration values have a default; values that are commented out
|
||||||
# serve to show the default.
|
# serve to show the default.
|
||||||
|
|
||||||
import sys
|
#import sys
|
||||||
import os
|
#import os
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
@@ -28,7 +28,18 @@ import os
|
|||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = []
|
extensions = [
|
||||||
|
'sphinx.ext.autodoc',
|
||||||
|
'sphinx.ext.intersphinx',
|
||||||
|
'sphinx.ext.viewcode',
|
||||||
|
'wsmeext.sphinxext',
|
||||||
|
'sphinxcontrib.docbookrestapi.setup',
|
||||||
|
'sphinxcontrib.pecanwsme.rest',
|
||||||
|
'sphinxcontrib.httpdomain',
|
||||||
|
'oslosphinx',
|
||||||
|
]
|
||||||
|
|
||||||
|
wsme_protocols = ['restjson', 'restxml']
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
@@ -74,11 +85,11 @@ exclude_patterns = []
|
|||||||
#default_role = None
|
#default_role = None
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
#add_function_parentheses = True
|
add_function_parentheses = True
|
||||||
|
|
||||||
# If true, the current module name will be prepended to all description
|
# If true, the current module name will be prepended to all description
|
||||||
# unit titles (such as .. function::).
|
# unit titles (such as .. function::).
|
||||||
#add_module_names = True
|
add_module_names = True
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
# output. They are ignored by default.
|
# output. They are ignored by default.
|
||||||
@@ -88,7 +99,7 @@ exclude_patterns = []
|
|||||||
pygments_style = 'sphinx'
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
# A list of ignored prefixes for module index sorting.
|
# A list of ignored prefixes for module index sorting.
|
||||||
#modindex_common_prefix = []
|
modindex_common_prefix = ['cloudkitty.']
|
||||||
|
|
||||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||||
#keep_warnings = False
|
#keep_warnings = False
|
||||||
|
|||||||
@@ -3,14 +3,44 @@
|
|||||||
You can adapt this file completely to your liking, but it should at least
|
You can adapt this file completely to your liking, but it should at least
|
||||||
contain the root `toctree` directive.
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
Welcome to cloudkitty's documentation!
|
=================================================
|
||||||
======================================
|
Welcome to CloudKitty's developper documentation!
|
||||||
|
=================================================
|
||||||
|
|
||||||
Contents:
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
CloudKitty is a PricingAsAService project aimed at translating Ceilometer
|
||||||
|
metrics to prices.
|
||||||
|
|
||||||
|
|
||||||
|
Architecture
|
||||||
|
============
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 1
|
||||||
|
|
||||||
|
arch
|
||||||
|
|
||||||
|
|
||||||
|
API References
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
webapi/root
|
||||||
|
webapi/v1
|
||||||
|
|
||||||
|
|
||||||
|
Modules
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:glob:
|
||||||
|
|
||||||
|
webapi/billing/*
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
@@ -19,4 +49,3 @@ Indices and tables
|
|||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
* :ref:`modindex`
|
* :ref:`modindex`
|
||||||
* :ref:`search`
|
* :ref:`search`
|
||||||
|
|
||||||
|
|||||||
30
doc/source/webapi/billing/hashmap.rst
Normal file
30
doc/source/webapi/billing/hashmap.rst
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
=======================
|
||||||
|
HashMap Module REST API
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. rest-controller:: cloudkitty.billing.hash:BasicHashMapController
|
||||||
|
:webprefix: /v1/billing/modules/hashmap
|
||||||
|
|
||||||
|
.. rest-controller:: cloudkitty.billing.hash:BasicHashMapConfigController
|
||||||
|
:webprefix: /v1/billing/modules/hashmap/config
|
||||||
|
|
||||||
|
.. http:get:: /v1/billing/hashmap/modules/config/(service)/(field)/(key)
|
||||||
|
|
||||||
|
Get a mapping from full path
|
||||||
|
|
||||||
|
:param service: Filter on this service.
|
||||||
|
:param field: Filter on this field.
|
||||||
|
:param key: Filter on this key.
|
||||||
|
:type service: :class:`unicode`
|
||||||
|
:type field: :class:`unicode`
|
||||||
|
:type key: :class:`unicode`
|
||||||
|
:type mapping: :class:`Mapping`
|
||||||
|
:return: A mapping
|
||||||
|
|
||||||
|
:return type: :class:`Mapping`
|
||||||
|
|
||||||
|
|
||||||
|
.. autotype:: cloudkitty.billing.hash.Mapping
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
16
doc/source/webapi/root.rst
Normal file
16
doc/source/webapi/root.rst
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
==========================
|
||||||
|
CloudKitty REST API (root)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
.. rest-controller:: cloudkitty.api.controllers.root:RootController
|
||||||
|
:webprefix: / /
|
||||||
|
.. Dirty hack till the bug is fixed so we can specify root path
|
||||||
|
|
||||||
|
.. autotype:: cloudkitty.api.controllers.root.APILink
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autotype:: cloudkitty.api.controllers.root.APIMediaType
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autotype:: cloudkitty.api.controllers.root.APIVersion
|
||||||
|
:members:
|
||||||
31
doc/source/webapi/v1.rst
Normal file
31
doc/source/webapi/v1.rst
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
========================
|
||||||
|
CloudKitty REST API (v1)
|
||||||
|
========================
|
||||||
|
|
||||||
|
Billing
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. rest-controller:: cloudkitty.billing:BillingEnableController
|
||||||
|
:webprefix: /v1/billing/modules/(module)/enabled
|
||||||
|
|
||||||
|
.. rest-controller:: cloudkitty.billing:BillingConfigController
|
||||||
|
:webprefix: /v1/billing/modules/(module)/config
|
||||||
|
|
||||||
|
.. rest-controller:: cloudkitty.api.controllers.v1:ModulesController
|
||||||
|
:webprefix: /v1/billing/modules
|
||||||
|
|
||||||
|
.. rest-controller:: cloudkitty.api.controllers.v1:BillingController
|
||||||
|
:webprefix: /v1/billing
|
||||||
|
|
||||||
|
.. autotype:: cloudkitty.billing.ExtensionSummary
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autotype:: cloudkitty.api.controllers.v1.ResourceDescriptor
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
Report
|
||||||
|
======
|
||||||
|
|
||||||
|
.. rest-controller:: cloudkitty.api.controllers.v1:ReportController
|
||||||
|
:webprefix: /v1/report
|
||||||
@@ -6,7 +6,6 @@ mock>=1.0
|
|||||||
sphinx>=1.1.2,<1.2
|
sphinx>=1.1.2,<1.2
|
||||||
oslosphinx
|
oslosphinx
|
||||||
oslotest
|
oslotest
|
||||||
|
|
||||||
sphinxcontrib-docbookrestapi
|
sphinxcontrib-docbookrestapi
|
||||||
sphinxcontrib-httpdomain
|
sphinxcontrib-httpdomain
|
||||||
sphinxcontrib-pecanwsme>=0.8
|
sphinxcontrib-pecanwsme>=0.8
|
||||||
|
|||||||
Reference in New Issue
Block a user