diff --git a/.gitignore b/.gitignore index 5570995d3..478ebdbf9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ AUTHORS ChangeLog etc/gnocchi/gnocchi.conf +doc/build diff --git a/README.rst b/README.rst index 13001aa75..15e4ac1e2 100644 --- a/README.rst +++ b/README.rst @@ -2,110 +2,4 @@ Gnocchi ======== -REST API to store metrics in object storage. - -`Gnocchi `_ uses Pandas to analyze -metrics, with Swift as the canonical storage driver (other pluggable drivers -are expected to follow). - -Installation Instructions -========================= -Install Swift, either by enabling the required services in a full devstack -environment, or as a stand-alone installation. - -To enable Swift in Devstack, edit your localrc file to include:: - - enable_service s-proxy s-account s-container s-object - -and run `./stack.sh`. - -For directions on installing Swift all-in-one, see -`these instructions `_. - -Clone the gnocchi git repo (if you have a full Devstack environment, the -usual directory in which to install gnocchi would be /opt/stack/):: - - cd /opt/stack && git clone https://github.com/stackforge/gnocchi.git - -You may need to install the following libraries, depending on your system; -on Ubuntu the command would be:: - - sudo apt-get install build-essential libpq-dev libx11-dev libasound2-dev - -for Fedora users, type:: - - sudo yum install gcc-c++ libpq-devel libx11-devel alsa-lib-devel - -Run the installer:: - - cd gnocchi - sudo pip install -r requirements.txt - sudo pip install -r test-requirements.txt - sudo python setup.py install - - -Configuring Gnocchi -=================== - -If it doesn't exist, create a gnocchi.conf file in /etc/gnocchi/:: - - mkdir -p /etc/gnocchi - cd /etc/gnocchi && touch gnocchi.conf - -Edit `/etc/gnocchi/gnocchi.conf`. Shown below is a sample configuration file:: - - [api] - port = 8041 - host = 0.0.0.0 - - [storage] - swift_auth_version = 1 - swift_authurl = http://localhost:8080/auth/v1.0 - swift_user = admin:admin - swift_key = admin - - [indexer] - driver = sqlalchemy - - [database] - connection = mysql://username:password@host/gnocchi - -To use postgresql instead, set the database connection string accordingly:: - - connection = postgres://username:pasword@host/gnocchi - -Create a database. For mysql, from the command line type:: - - mysql -u root -pPASSWORD -e "create database gnocchi;" - -For postgresql:: - - createdb -U USERNAME -T template0 gnocchi - -Initialize the database by running:: - - gnocchi-dbsync - -Sending Requests to the API -=========================== - -Run the Gnocchi API service:: - - gnocchi-api - -You can now send requests to the API. Here's an example that creates an -entity with an archive that stores one point every second for an hour -(shown both with the curl command and using a Python script):: - - curl -i http://0.0.0.0:8041/v1/entity -X POST \ - -H "Content-Type: application/json" -H "Accept: application/json" \ - -d '{"archives": "high"}' - -Or:: - - import requests - import json - - r = requests.post('http://0.0.0.0:8041/v1/entity', data=json.dumps({"archives": "high"})) - print r.status_code - print r.text +HTTP API to store metrics and index resources. diff --git a/doc/source/basic.rst b/doc/source/basic.rst new file mode 100644 index 000000000..b7b1c1409 --- /dev/null +++ b/doc/source/basic.rst @@ -0,0 +1,45 @@ +================== + What is Gnocchi? +================== + +.. image:: gnocchi-logo.jpg + +Gnocchi is a service for managing a set of resources and storing metrics about +them. It allows its users to create resources (servers, images, volumes…) +with properties (name, URL, flavors…) and to associate those resources with +entities (CPU usage, bandwidth…) that are going to metered. + +The point of Gnocchi is to provide this service and its features in a scalable +and resilient way. Its functionalities are exposed over an HTTP REST API. + +============================ + A Brief History of Gnocchi +============================ + +The Gnocchi project was started in 2014 as a spin-off of the `OpenStack +Ceilometer`_ project to address the performance issues that Ceilometer +encountered while using standard databases as a storage backends for metrics. +More information are available on `Julien's blog post on Gnocchi +`_. + +.. _`OpenStack Ceilometer`: http://launchpad.net/ceilometer + +====================== + Project Architecture +====================== + +Gnocchi is built around 2 main components: a storage driver and an indexer +driver. The REST API exposed to the user manipulates both these drivers to +provide all the features that are needed to provide correct infrastructure +measurement. + +The *storage* is responsible for storing metrics of created entities. It +receives timestamps and values and computes aggregations according the the +defined +archive policies. + +The *indexer* is responsible for storing the index of all resources, along with +their types and their properties. Gnocchi only knows resource types from the +OpenStack project, but also provides a *generic* type so you can create basic +resources and handle the resource properties yourself. The indexer is also +responsible for linking resources with entities. diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 000000000..1abc1bce9 --- /dev/null +++ b/doc/source/conf.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- +# +# Gnocchi documentation build configuration file +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import datetime +import subprocess + +# 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 +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + 'sphinx.ext.autodoc', + 'oslosphinx', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'gnocchi' +copyright = u'%s, OpenStack Foundation' % datetime.date.today().year + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = subprocess.Popen(['sh', '-c', 'cd ../..; python setup.py --version'], + stdout=subprocess.PIPE).stdout.read() +version = version.strip() +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'gnocchidoc' diff --git a/doc/source/gnocchi-logo.jpg b/doc/source/gnocchi-logo.jpg new file mode 100644 index 000000000..a9eaca753 Binary files /dev/null and b/doc/source/gnocchi-logo.jpg differ diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 000000000..c7aceb97d --- /dev/null +++ b/doc/source/index.rst @@ -0,0 +1,20 @@ +=========================================== + Gnocchi -- Resource metering as a Service +=========================================== + +The Gnocchi project procdes a REST interface to catalog and measure resources. + +.. toctree:: + :glob: + + basic + install + rest + resource_types + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/doc/source/install.rst b/doc/source/install.rst new file mode 100644 index 000000000..7b0825c92 --- /dev/null +++ b/doc/source/install.rst @@ -0,0 +1,70 @@ +============== + Installation +============== + +To install Gnocchi, you just need to run the standard Python installation +procedure: + +:: + + python setup.py install + + +Configuration +============= + +Then configure Gnocchi by editing the `/etc/gnocchi/gnocchi.conf` sample. No +config file is provided with the source code, but one can be easily created by +running: + +:: + + tox -e genconfig + +The configuration file should be pretty explicit, but here are some of the base +options you want to change and configure: + + ++---------------------+--------------------------------------------------------+ +| Option name | Help | ++=====================+========================================================+ +| storage.driver | The storage driver for entities, Swift by default. | ++---------------------+--------------------------------------------------------+ +| indexer.driver | The indexer driver, SQLAlchemy by default. | ++---------------------+--------------------------------------------------------+ +| database.connection | URL to your database, used by the *sqlalchemy* driver. | ++---------------------+--------------------------------------------------------+ +| storage.swift_* | Configuration options to access Swift | +| | if you use the Swift storage driver. | ++---------------------+--------------------------------------------------------+ + + +Indexer Initialization +====================== + +Once you have configured Gnocchi properly, you need to initialize the indexer: + +:: + + gnocchi-dbsync + + +Running Gnocchi +=============== + +To run Gnocchi, simple run the HTTP server: + +:: + + gnocchi-api + + +Running As A WSGI Application +============================= + +It's possible – and advised – to run Gnocchi through a WSGI service such as +`mod_wsgi`_ or any other WSGI applications. The file `gnocchi/rest/app.wsgi` +provided with Gnocchi allows you to enable Gnocchi as a WSGI application. + +.. _`mod_wsgi`: https://modwsgi.readthedocs.org/en/master/ + diff --git a/doc/source/resource_types.rst b/doc/source/resource_types.rst new file mode 100644 index 000000000..a7057a685 --- /dev/null +++ b/doc/source/resource_types.rst @@ -0,0 +1,55 @@ +================ + Resource Types +================ + +Gnocchi offers different resource types to manage your resources. Each resource +type has its specific typed attributes. All resource types are subtype of the +`generic` type. + +Immutable attributes are attributes that cannot be modified after the resource +has been created. + + +generic +======= + ++------------+----------------+-----------+ +| Attribute | Type | Immutable | ++============+================+===========+ +| user_id | UUID | Yes | ++------------+----------------+-----------+ +| project_id | UUID | Yes | ++------------+----------------+-----------+ +| started_at | Timestamp | Yes | ++------------+----------------+-----------+ +| ended_at | Timestamp | No | ++------------+----------------+-----------+ +| type | Timestamp | Yes | ++------------+----------------+-----------+ +| entities | {String: UUID} | No | ++------------+----------------+-----------+ + + + +instance +======== + ++--------------+---------+-----------+ +| Attribute | Type | Immutable | ++==============+=========+===========+ +| flavor_id | Integer | No | ++--------------+---------+-----------+ +| image_ref | String | No | ++--------------+---------+-----------+ +| host | String | No | ++--------------+---------+-----------+ +| display_name | String | No | ++--------------+---------+-----------+ +| server_group | String | No | ++--------------+---------+-----------+ + + +swift_account +============= + +No specific attributes. diff --git a/doc/source/rest.rst b/doc/source/rest.rst new file mode 100644 index 000000000..43b25ce50 --- /dev/null +++ b/doc/source/rest.rst @@ -0,0 +1,623 @@ +================ + REST API Usage +================ + +Authentication +============== + +By default, the `api.middleware` configuration option is set to use the Keystone +middleware. Therefore you must authenticate using Keystone to use the API and +provide an `X-Auth-Token` header with a valid token for each request sent to +Gnocchi. + +Entities +======== + +Gnocchi provides a resource type that is called *entity*. An entity designates +any thing that can be measured: the CPU usage of a server, the temperature of a +room or the number of bytes sent by a network interface. + +An entity only has a few properties: a UUID to identify it, and the archive +policy that will be used to store and aggregate the measures. + +To create an entity, the following API request should be used: + +:: + + ▶ POST /v1/entity + Content-Type: application/json + + { + "archive_policy": "medium" + } + + ◀ HTTP/1.1 201 Created + Location: http://localhost:8080/v1/entity/125F6A9F-D8DB-424D-BFF2-A5F142E2DC03 + Content-Type: application/json + + { + "archive_policy": "medium" + } + +Once created, it is possible to send metrics to the entity: + +:: + + ▶ POST /v1/entity/125F6A9F-D8DB-424D-BFF2-A5F142E2DC03/measures + Content-Type: application/json + + [ + { + "timestamp": "2014-10-06T14:33:57", + "value": 43.1 + }, + { + "timestamp": "2014-10-06T14:34:12", + "value": 12 + } + { + "timestamp": "2014-10-06T14:34:20", + "value": 2 + } + ] + + ◀ HTTP/1.1 204 No Content + +If there are no errors, Gnocchi does not return a response body, only a simple +status code. It is possible to provide any number of measures. + +.. IMPORTANT:: + + While it is possible to send any number of (timestamp, value), it is still + needed to honor constraints defined by the archive policy used by the entity, + such as the maximum timespan. + + +Once measures are sent, it is possible to retrieve them using *GET* on the same +endpoint: + +:: + + ▶ GET /v1/entity/125F6A9F-D8DB-424D-BFF2-A5F142E2DC03/measures + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "timestamp": "2014-10-06T14:33:00", + "value": 43.1 + }, + { + "timestamp": "2014-10-06T14:34:00", + "value": 7 + } + ] + +It is possible to filter the measures over a time range by specifying the +*start* and/or *stop* parameters to the query with timestamp. The timestamp +format can be either a floating number (UNIX epoch) or an ISO8601 formated +timestamp: + +:: + + ▶ GET /v1/entity/125F6A9F-D8DB-424D-BFF2-A5F142E2DC03/measures?start=2014-10-06T14:34 + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "timestamp": "2014-10-06T14:34:00", + "value": 7 + } + ] + +By default, the aggregated values that are returned use the *mean* aggregation +method. It is possible to request for any other method by specifying the +*aggregation* query parameter: + +:: + + ▶ GET /v1/entity/125F6A9F-D8DB-424D-BFF2-A5F142E2DC03/measures?aggregation=max + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "timestamp": "2014-10-06T14:33:00", + "value": 43.1 + }, + { + "timestamp": "2014-10-06T14:34:00", + "value": 12 + } + ] + +The list of aggregation method available is: *mean*, *sum*, *last*, *max*, +*min*, *std*, *median* and *first*. + +Archive Policy +============== + +When sending measures for an entity to Gnocchi, the values are dynamically +aggregated. That means that Gnocchi does not store all sent measures, but +aggregates them over a certain period of time. Gnocchi provides several +aggregation method (mean, min, max, sum…) that are builtin. + +An archive policy is a list of item. Each item is composed of the timespan and +the level of precision that must be kept when aggregating data. For example, an +item might be defined of 12 points over an hour (one point every 5 minutes), or +a points every 1 hours over 1 day (24 points). An archive policy is defined by a +name and a definition composed of a list of at least one of the previously +described item. + +The REST API allows to create archive policies: + +:: + + ▶ POST /v1/archive_policy + Content-Type: application/json + + { + "name": "low", + "definition": [ + { + "granularity": "1s", + "timespan": "1 hour" + }, + { + "points": 1000, + "timespan": "1 day" + } + ] + } + + ◀ HTTP/1.1 201 Created + Location: http://localhost:8080/v1/archive_policy/low + Content-Type: application/json + + { + "name": "low", + "definition": [ + { + "granularity": "0:00:01", + "timespan": "0:01:00", + "points": 60, + }, + { + "granularity": 86.4, + "points": 1000, + "timespan": "1 day, 00:00:00" + } + ] + } + +Once the archive policy is created, the complete set of properties is computed +and returned, with the URL of the archive policy. This URL can be used to +retrieve the details of the archive policy later: + +:: + + ▶ GET /v1/archive_policy/low + + ◀ HTTP/1.1 200 OK + Location: http://localhost:8080/v1/archive_policy/low + Content-Type: application/json + + { + "name": "low", + "definition": [ + { + "granularity": "0:00:01", + "timespan": "0:01:00", + "points": 60, + }, + { + "granularity": 86.4, + "points": 1000, + "timespan": "1 day, 00:00:00" + } + ] + } + +It is also possible to list archive policies: + +:: + + ▶ GET /v1/archive_policy + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "name": "low", + "definition": [ + { + "granularity": "0:00:01", + "timespan": "0:01:00", + "points": 60, + }, + { + "granularity": 86.4, + "points": 1000, + "timespan": "1 day, 00:00:00" + } + ] + } + ] + +.. WARNING:: + + It is not yet possible to delete an archive policy. + +Resources +========= + +Gnocchi provides the ability to store and index resources. Each resource has a +type. The basic type of resources is *generic*, but more specialized subtypes +also exist, especially to describe OpenStack resources. + +The REST API allows to manipulate resources. To create a generic resource: + +:: + + ▶ POST /v1/resource/generic + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D" + } + + ◀ HTTP/1.1 201 Created + Location: http://localhost:8080/v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9 + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "started_at": "2014-10-06T14:34:00", + "ended_at": null + } + +The *id*, *user_id* and *project_id* attributes must be UUID and are mandatory. +The timestamp describing the lifespan of the resource are not, and *started_at* +is by default set to the current timestamp. + +It's possible to retrieve the resource by the URL provided in the `Location` +header. + +More specialized resources can be created. For example, the *instance* is used +to describe an OpenStack instance as managed by Nova_. + +:: + + ▶ POST /v1/resource/instance + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "entities": {} + } + + ◀ HTTP/1.1 201 Created + Location: http://localhost:8080/v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9 + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {} + } + + +All specialized types have their own optional and mandatory attributes, but they +all include attributes from the generic type as well. + +To retrieve a resource by its URL provided by the `Location` header at creation +time: + +:: + + ▶ GET /v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9 + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {} + } + + +It's possible to modify a resource by re-uploading it partially with the +modified fields: + +:: + + ▶ PATCH /v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9 + Content-Type: application/json + + { + "host": "compute2", + } + + + ◀ HTTP/1.1 201 Created + Location: http://localhost:8080/v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9 + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute2", + "display_name": "myvm", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {} + } + + +It possible to delete a resource altogether: + +:: + + ▶ DELETE /v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9 + + ◀ HTTP/1.1 204 No Content + + +All resources can be listed, either by using the `generic` type that will list +all types of resources, or by filtering on their resource type: + +:: + + ▶ GET /v1/resource/generic + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "type": "instance", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {} + }, + { + "id": "63F07754-F52D-4321-A422-138D019E0EF1", + "user_id": "763F8A05-16CF-42B0-B2C4-5E9A76D7781B", + "project_id": "439AC15D-23BC-4589-9033-A98AAD4D00EE", + "type": "swift_account", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {} + } + ] + + +No attributes specific to the resource type are retrieved when using the +`generic` endpoint. To retrieve the details, either list using the specific +resource type endpoint: + +:: + + ▶ GET /v1/resource/instance + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "type": "instance", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {} + } + ] + + +or using `details=true` in the query parameter: + +:: + + ▶ GET /v1/resource/generic?details=true + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "type": "instance", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {} + }, + { + "id": "63F07754-F52D-4321-A422-138D019E0EF1", + "user_id": "763F8A05-16CF-42B0-B2C4-5E9A76D7781B", + "project_id": "439AC15D-23BC-4589-9033-A98AAD4D00EE", + "type": "swift_account", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {} + } + ] + +When listing resources, it is possible to filter resource based on attributes +values: + +:: + + ▶ GET /v1/resource/instance?user_id=BD3A1E52-1C62-44CB-BF04-660BD88CD74D + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "type": "instance", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {} + } + ] + +Each resource can be linked to any number of entities. The `entities` attributes +is a key/value field where the key is the name of the relationship and the value +is an entity: + +:: + + ▶ POST /v1/resource/instance + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "entities": {"cpu.util": "73CFA91B-F868-4FC1-BA6B-9164570AEAA1"} + } + + ◀ HTTP/1.1 201 Created + Location: http://localhost:8080/v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9 + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {"cpu.util": "73CFA91B-F868-4FC1-BA6B-9164570AEAA1"} + } + +It's also possible to create entities dynamically while creating a resource: + +:: + + ▶ POST /v1/resource/instance + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "entities": {"cpu.util": {"archive_policy": "medium"}} + } + + ◀ HTTP/1.1 201 Created + Location: http://localhost:8080/v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9 + Content-Type: application/json + + { + "id": "75C44741-CC60-4033-804E-2D3098C7D2E9", + "user_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "project_id": "BD3A1E52-1C62-44CB-BF04-660BD88CD74D", + "flavor_id": 2, + "image_ref": "http://image", + "host": "compute1", + "display_name": "myvm", + "started_at": "2014-10-06T14:34:00", + "ended_at": null, + "entities": {"cpu.util": "2B9D2EAD-E14D-40C8-B50A-A94841F64D92"} + } + + +The entity associated with a resource an be accessed and manipulated using the +usual `/v1/entity` endpoint or using the named relationship with the resource: + +:: + + ▶ GET /v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9/entity/cpu.util/measures?start=2014-10-06T14:34 + + ◀ HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "timestamp": "2014-10-06T14:34:00", + "value": 7 + } + ] + +The same endpoint can be used to append entities to a resource: + +:: + + ▶ POST /v1/resource/generic/75C44741-CC60-4033-804E-2D3098C7D2E9/entity + Content-Type: application/json + + [ + {"memory": {"archive_policy": "low"}} + ] + + ◀ HTTP/1.1 204 No Content + + +.. _Nova: http://launchpad.net/nova diff --git a/test-requirements-py3.txt b/test-requirements-py3.txt index 855ec3351..852e4c00a 100644 --- a/test-requirements-py3.txt +++ b/test-requirements-py3.txt @@ -1,7 +1,9 @@ fixtures keystonemiddleware mock +oslosphinx>=2.2.0 # Apache-2.0 psycopg2 +sphinx testrepository testscenarios testtools>=0.9.38 diff --git a/test-requirements.txt b/test-requirements.txt index 7fa404589..fc36af5bb 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,6 +2,8 @@ fixtures keystonemiddleware mock MySQL-python +oslosphinx>=2.2.0 # Apache-2.0 +sphinx psycopg2 testrepository testscenarios diff --git a/tox.ini b/tox.ini index 44e5771cd..3e416d34b 100644 --- a/tox.ini +++ b/tox.ini @@ -56,6 +56,12 @@ commands = mkdir -p etc/gnocchi --namespace gnocchi \ --namespace oslo.db +[testenv:docs] +deps = {[testenv]deps} + doc8 +commands = doc8 doc/source + python setup.py build_sphinx + [hacking] import_exceptions = gnocchi.openstack.common.gettextutils