Write the base of the documentation

This commit is contained in:
Mehdi Abaakouk 2015-08-30 19:31:02 +02:00
parent 38bc513414
commit 0d180c360d
12 changed files with 415 additions and 194 deletions

3
.gitignore vendored
View File

@ -52,3 +52,6 @@ ChangeLog
*~
.*.swp
.*sw?
# generated docs
doc/source/ref/

View File

@ -2,11 +2,12 @@
python-gnocchiclient
===============================
Python client library for Gnocchi
Python bindings to the OpenStack Gnocchi API
Please feel here a long description which must be at least 3 lines wrapped on
80 cols, so that distribution package maintainers can use it in their packages.
Note that this is a hard requirement.
This is a client for OpenStack gnocchi API. There's :doc:`a Python API
<api>` (the :mod:`gnocchiclient` module), and a :doc:`command-line script
<shell>` (installed as :program:`gnocchi`). Each implements the entire
OpenStack Gnocchi API.
* Free software: Apache license
* Documentation: http://docs.openstack.org/developer/python-gnocchiclient

27
doc/source/api.rst Normal file
View File

@ -0,0 +1,27 @@
The :mod:`gnocchiclient` Python API
===================================
.. module:: gnocchiclient
:synopsis: A client for the Gnocchi API.
.. currentmodule:: gnocchiclient
Usage
-----
To use python-gnocchiclient in a project::
>>> from gnocchiclient.v1 import client
>>> gnocchi = client.Client(...)
>>> gnocchi.resource.list("instance")
Reference
---------
For more information, see the reference:
.. toctree::
:maxdepth: 2
ref/v1/index

View File

@ -15,7 +15,47 @@
import os
import sys
sys.path.insert(0, os.path.abspath('../..'))
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.abspath(os.path.join(BASE_DIR, "..", ".."))
sys.path.insert(0, ROOT)
sys.path.insert(0, BASE_DIR)
def gen_ref(ver, title, names):
refdir = os.path.join(BASE_DIR, "ref")
pkg = "gnocchiclient"
if ver:
pkg = "%s.%s" % (pkg, ver)
refdir = os.path.join(refdir, ver)
if not os.path.exists(refdir):
os.makedirs(refdir)
idxpath = os.path.join(refdir, "index.rst")
with open(idxpath, "w") as idx:
idx.write(("%(title)s\n"
"%(signs)s\n"
"\n"
".. toctree::\n"
" :maxdepth: 1\n"
"\n") % {"title": title, "signs": "=" * len(title)})
for name in names:
idx.write(" %s\n" % name)
rstpath = os.path.join(refdir, "%s.rst" % name)
with open(rstpath, "w") as rst:
rst.write(("%(title)s\n"
"%(signs)s\n"
"\n"
".. automodule:: %(pkg)s.%(name)s\n"
" :members:\n"
" :undoc-members:\n"
" :show-inheritance:\n"
" :noindex:\n")
% {"title": name.capitalize(),
"signs": "=" * len(name),
"pkg": pkg, "name": name})
gen_ref("v1", "Version 1 API", ["client", "resource"])
# -- General configuration ----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be

View File

@ -3,17 +3,31 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to python-gnocchiclient's documentation!
Python bindings to the Gnocchi API
========================================================
This is a client for gnocchi API. There's :doc:`a Python API
<api>` (the :mod:`gnocchiclient` module), and a :doc:`command-line script
<shell>` (installed as :program:`gnocchi`). Each implements the entire
Gnocchi API.
.. seealso::
You may want to read the `Gnocchi Developer Guide`__ -- the overview, at
least -- to get an idea of the concepts. By understanding the concepts
this library should make more sense.
__ http://docs.openstack.org/developer/gnocchi/
Contents:
.. toctree::
:maxdepth: 2
readme
installation
usage
shell
api
contributing
Indices and tables

View File

@ -1 +0,0 @@
.. include:: ../../README.rst

67
doc/source/shell.rst Normal file
View File

@ -0,0 +1,67 @@
The :program:`gnocchi` shell utility
=========================================
.. program:: gnocchi
.. highlight:: bash
The :program:`gnocchi` shell utility interacts with Gnocchi API
from the command line. It supports the entirety of the Gnocchi API.
You'll need to provide :program:`gnocchi` with your OpenStack credentials.
You can do this with the :option:`--os-username`, :option:`--os-password`,
:option:`--os-tenant-id` and :option:`--os-auth-url` options, but it's easier to
just set them as environment variables:
.. envvar:: OS_USERNAME
Your OpenStack username.
.. envvar:: OS_PASSWORD
Your password.
.. envvar:: OS_TENANT_NAME
Project to work on.
.. envvar:: OS_AUTH_URL
The OpenStack auth server URL (keystone).
For example, in Bash you would use::
export OS_USERNAME=user
export OS_PASSWORD=pass
export OS_TENANT_NAME=myproject
export OS_AUTH_URL=http://auth.example.com:5000/v2.0
The command line tool will attempt to reauthenticate using your provided credentials
for every request. You can override this behavior by manually supplying an auth
token using :option:`--os-gnocchi-url` and :option:`--os-auth-token`. You can alternatively
set these environment variables::
export GNOCCHI_ENDPOINT=http://gnocchi.example.org:8041
export OS_AUTH_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155
From there, all shell commands take the form::
gnocchi <command> [arguments...]
Run :program:`gnocchi help` to get a full list of all possible commands,
and run :program:`gnocchi help <command>` to get detailed help for that
command.
Examples
--------
Create a resource::
gnocch resource create instance --attribute id:5a301761-f78b-46e2-8900-8b4f6fe6675a --attribute project_id:eba5c38f-c3dd-4d9c-9235-32d430471f94 --metric temperature:high
List resources::
gnocchi resource list instance
Search of resources::
gnocchi resource search -q "project_id=5a301761-f78b-46e2-8900-8b4f6fe6675a and not (name like '%foobar%' or name='my_resource')"

View File

@ -1,7 +0,0 @@
========
Usage
========
To use python-gnocchiclient in a project::
import gnocchiclient

View File

@ -21,12 +21,21 @@ from gnocchiclient.v1 import resource
class Client(object):
"""Client for the Gnocchi v1 API.
:param string auth: An keystoneclient authentication plugin to
authenticate the session with
:param string auth: An optional keystoneclient authentication plugin
to authenticate the session with
:type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin`
:param endpoint: The optional Gnocchi API endpoint
:type endpoint: str
:param interface: The endpoint interface ('public', 'internal', 'admin')
:type interface: str
:param region_name: The keystone region name
:type region_name: str
:param \*\*kwargs: Any option supported by
:py:class:`keystoneclient.session.Session`
"""
VERSION = "v1"
_VERSION = "v1"
def __init__(self, auth=None, endpoint=None, interface=None,
region_name=None, **kwargs):
@ -45,7 +54,7 @@ class Client(object):
region_name=self.region_name)
return self._endpoint
def url(self, url_suffix):
def _build_url(self, url_suffix):
return "%s/%s/%s" % (self.endpoint.rstrip("/"),
self.VERSION,
self._VERSION,
url_suffix)

View File

@ -1,5 +1,3 @@
# Copyright 2012 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@ -13,203 +11,103 @@
# License for the specific language governing permissions and limitations
# under the License.
import uuid
from cliff import command
from cliff import lister
from cliff import show
from oslo_serialization import jsonutils
from gnocchiclient import utils
from gnocchiclient.v1 import base
class ResourceManager(base.Manager):
def list(self, resource_type="generic", details=False, history=False):
"""List resources
:param resource_type: Type of the resource
:type resource_type: str
:param details: Show all attributes of resources
:type details: bool
:param history: Show the history of resources
:type history: bool
"""
details = "true" if details else "false"
history = "true" if history else "false"
url = self.client.url("resource/%s?details=%s&history=%s" % (
url = self.client._build_url("resource/%s?details=%s&history=%s" % (
resource_type, details, history))
return self.client.api.get(url).json()
def get(self, resource_type, resource_id):
url = self.client.url("resource/%s/%s" % (
"""Get a resource
:param resource_type: Type of the resource
:type resource_type: str
:param resource_id: ID of the resource
:type resource_id: str
"""
url = self.client._build_url("resource/%s/%s" % (
resource_type, resource_id))
return self.client.api.get(url).json()
def create(self, resource_type, resource):
url = self.client.url("resource/%s" % resource_type)
"""Create a resource
:param resource_type: Type of the resource
:type resource_type: str
:param resource: Attribute of the resource
:type resource: dict
"""
url = self.client._build_url("resource/%s" % resource_type)
return self.client.api.post(
url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(resource)).json()
def update(self, resource_type, resource_id, resource):
url = self.client.url("resource/%s/%s" % (resource_type, resource_id))
"""Update a resource
:param resource_type: Type of the resource
:type resource_type: str
:param resource_id: ID of the resource
:type resource_id: str
:param resource: Attribute of the resource
:type resource: dict
"""
url = self.client._build_url("resource/%s/%s" % (resource_type,
resource_id))
return self.client.api.patch(
url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(resource)).json()
def delete(self, resource_id):
url = self.client.url("resource/generic/%s" % (resource_id))
"""Delete a resource
:param resource_id: ID of the resource
:type resource_id: str
"""
url = self.client._build_url("resource/generic/%s" % (resource_id))
self.client.api.delete(url)
def search(self, resource_type="generic", details=False, history=False,
request=None):
def search(self, resource_type="generic", request=None, details=False,
history=False):
"""List resources
:param resource_type: Type of the resource
:param resource_type: str
:param request: The search request dictionary
:type resource_type: dict
:param details: Show all attributes of resources
:type details: bool
:param history: Show the history of resources
:type history: bool
See Gnocchi REST API documentation for the format
of *request dictionary*
http://docs.openstack.org/developer/gnocchi/rest.html#searching-for-resources
"""
request = request or {}
details = "true" if details else "false"
history = "true" if history else "false"
url = self.client.url("/search/resource/%s?details=%s&history=%s" % (
resource_type, details, history))
url = self.client._build_url(
"/search/resource/%s?details=%s&history=%s" % (
resource_type, details, history))
return self.client.api.post(
url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(request)).json()
class CliResourceList(lister.Lister):
COLS = ('id', 'type',
'project_id', 'user_id',
'started_at', 'ended_at',
'revision_start', 'revision_end')
def get_parser(self, prog_name):
parser = super(CliResourceList, self).get_parser(prog_name)
parser.add_argument("--details", action='store_true',
help="Show all attributes of generic resources"),
parser.add_argument("--history", action='store_true',
help="Show history of the resources"),
parser.add_argument("resource_type",
default="generic",
nargs='?',
help="Type of resource")
return parser
def take_action(self, parsed_args):
resources = self.app.client.resource.list(
resource_type=parsed_args.resource_type,
details=parsed_args.details,
history=parsed_args.history)
return self.COLS, [self._resource2tuple(r) for r in resources]
@classmethod
def _resource2tuple(cls, resource):
return tuple([resource[k] for k in cls.COLS])
class CliResourceSearch(CliResourceList):
def get_parser(self, prog_name):
parser = super(CliResourceSearch, self).get_parser(prog_name)
parser.add_argument("-q", "--query",
help="Query"),
return parser
def take_action(self, parsed_args):
resources = self.app.client.resource.search(
resource_type=parsed_args.resource_type,
details=parsed_args.details,
history=parsed_args.history,
request=utils.search_query_builder(parsed_args.query))
return self.COLS, [self._resource2tuple(r) for r in resources]
def normalize_metrics(res):
res['metrics'] = "\n".join(sorted(
["%s: %s" % (name, _id)
for name, _id in res['metrics'].items()]))
class CliResourceShow(show.ShowOne):
def get_parser(self, prog_name):
parser = super(CliResourceShow, self).get_parser(prog_name)
parser.add_argument("resource_type",
default="generic",
nargs='?',
help="Type of resource")
parser.add_argument("resource_id",
help="ID of a resource")
return parser
def take_action(self, parsed_args):
res = self.app.client.resource.get(
resource_type=parsed_args.resource_type,
resource_id=parsed_args.resource_id)
normalize_metrics(res)
return self.dict2columns(res)
class CliResourceCreate(show.ShowOne):
def get_parser(self, prog_name):
parser = super(CliResourceCreate, self).get_parser(prog_name)
parser.add_argument("resource_type",
default="generic",
nargs='?',
help="Type of resource")
parser.add_argument("-a", "--attribute", action='append',
help=("name and value of a attribute "
"separated with a ':'"))
parser.add_argument("-m", "--metric", action='append',
help=("To add a metric use 'name:id' or "
"'name:archive_policy_name'. "
"To remove a metric use 'name:-'."))
return parser
def _resource_from_args(self, parsed_args):
resource = {}
if parsed_args.attribute:
for attr in parsed_args.attribute:
attr, __, value = attr.partition(":")
resource[attr] = value
if parsed_args.metric:
rid = getattr(parsed_args, 'resource_id', None)
if rid:
r = self.app.client.resource.get(parsed_args.resource_type,
parsed_args.resource_id)
default = r['metrics']
else:
default = {}
resource['metrics'] = default
for metric in parsed_args.metric:
name, __, value = metric.partition(":")
if value == '-' or not value:
resource['metrics'].pop(name, None)
else:
try:
value = uuid.UUID(value)
except ValueError:
value = {'archive_policy_name': value}
resource['metrics'][name] = value
return resource
def take_action(self, parsed_args):
resource = self._resource_from_args(parsed_args)
res = self.app.client.resource.create(
resource_type=parsed_args.resource_type, resource=resource)
normalize_metrics(res)
return self.dict2columns(res)
class CliResourceUpdate(CliResourceCreate):
def get_parser(self, prog_name):
parser = super(CliResourceUpdate, self).get_parser(prog_name)
parser.add_argument("resource_id",
help="ID of the resource")
return parser
def take_action(self, parsed_args):
resource = self._resource_from_args(parsed_args)
res = self.app.client.resource.update(
resource_type=parsed_args.resource_type,
resource_id=parsed_args.resource_id,
resource=resource)
normalize_metrics(res)
return self.dict2columns(res)
class CliResourceDelete(command.Command):
def get_parser(self, prog_name):
parser = super(CliResourceDelete, self).get_parser(prog_name)
parser.add_argument("resource_id",
help="ID of the resource")
return parser
def take_action(self, parsed_args):
self.app.client.resource.delete(parsed_args.resource_id)

View File

@ -0,0 +1,170 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import uuid
from cliff import command
from cliff import lister
from cliff import show
from gnocchiclient import utils
class CliResourceList(lister.Lister):
COLS = ('id', 'type',
'project_id', 'user_id',
'started_at', 'ended_at',
'revision_start', 'revision_end')
def get_parser(self, prog_name):
parser = super(CliResourceList, self).get_parser(prog_name)
parser.add_argument("--details", action='store_true',
help="Show all attributes of generic resources"),
parser.add_argument("--history", action='store_true',
help="Show history of the resources"),
parser.add_argument("resource_type",
default="generic",
nargs='?',
help="Type of resource")
return parser
def take_action(self, parsed_args):
resources = self.app.client.resource.list(
resource_type=parsed_args.resource_type,
details=parsed_args.details,
history=parsed_args.history)
return self.COLS, [self._resource2tuple(r) for r in resources]
@classmethod
def _resource2tuple(cls, resource):
return tuple([resource[k] for k in cls.COLS])
class CliResourceSearch(CliResourceList):
def get_parser(self, prog_name):
parser = super(CliResourceSearch, self).get_parser(prog_name)
parser.add_argument("-q", "--query",
help="Query"),
return parser
def take_action(self, parsed_args):
resources = self.app.client.resource.search(
resource_type=parsed_args.resource_type,
details=parsed_args.details,
history=parsed_args.history,
request=utils.search_query_builder(parsed_args.query))
return self.COLS, [self._resource2tuple(r) for r in resources]
def normalize_metrics(res):
res['metrics'] = "\n".join(sorted(
["%s: %s" % (name, _id)
for name, _id in res['metrics'].items()]))
class CliResourceShow(show.ShowOne):
def get_parser(self, prog_name):
parser = super(CliResourceShow, self).get_parser(prog_name)
parser.add_argument("resource_type",
default="generic",
nargs='?',
help="Type of resource")
parser.add_argument("resource_id",
help="ID of a resource")
return parser
def take_action(self, parsed_args):
res = self.app.client.resource.get(
resource_type=parsed_args.resource_type,
resource_id=parsed_args.resource_id)
normalize_metrics(res)
return self.dict2columns(res)
class CliResourceCreate(show.ShowOne):
def get_parser(self, prog_name):
parser = super(CliResourceCreate, self).get_parser(prog_name)
parser.add_argument("resource_type",
default="generic",
nargs='?',
help="Type of resource")
parser.add_argument("-a", "--attribute", action='append',
help=("name and value of a attribute "
"separated with a ':'"))
parser.add_argument("-m", "--metric", action='append',
help=("To add a metric use 'name:id' or "
"'name:archive_policy_name'. "
"To remove a metric use 'name:-'."))
return parser
def _resource_from_args(self, parsed_args):
resource = {}
if parsed_args.attribute:
for attr in parsed_args.attribute:
attr, __, value = attr.partition(":")
resource[attr] = value
if parsed_args.metric:
rid = getattr(parsed_args, 'resource_id', None)
if rid:
r = self.app.client.resource.get(parsed_args.resource_type,
parsed_args.resource_id)
default = r['metrics']
else:
default = {}
resource['metrics'] = default
for metric in parsed_args.metric:
name, __, value = metric.partition(":")
if value == '-' or not value:
resource['metrics'].pop(name, None)
else:
try:
value = uuid.UUID(value)
except ValueError:
value = {'archive_policy_name': value}
resource['metrics'][name] = value
return resource
def take_action(self, parsed_args):
resource = self._resource_from_args(parsed_args)
res = self.app.client.resource.create(
resource_type=parsed_args.resource_type, resource=resource)
normalize_metrics(res)
return self.dict2columns(res)
class CliResourceUpdate(CliResourceCreate):
def get_parser(self, prog_name):
parser = super(CliResourceUpdate, self).get_parser(prog_name)
parser.add_argument("resource_id",
help="ID of the resource")
return parser
def take_action(self, parsed_args):
resource = self._resource_from_args(parsed_args)
res = self.app.client.resource.update(
resource_type=parsed_args.resource_type,
resource_id=parsed_args.resource_id,
resource=resource)
normalize_metrics(res)
return self.dict2columns(res)
class CliResourceDelete(command.Command):
def get_parser(self, prog_name):
parser = super(CliResourceDelete, self).get_parser(prog_name)
parser.add_argument("resource_id",
help="ID of the resource")
return parser
def take_action(self, parsed_args):
self.app.client.resource.delete(parsed_args.resource_id)

View File

@ -28,12 +28,12 @@ console_scripts =
gnocchi = gnocchiclient.shell:main
gnocchi.cli.v1 =
resource_list = gnocchiclient.v1.resource:CliResourceList
resource_show = gnocchiclient.v1.resource:CliResourceShow
resource_search = gnocchiclient.v1.resource:CliResourceSearch
resource_create = gnocchiclient.v1.resource:CliResourceCreate
resource_update = gnocchiclient.v1.resource:CliResourceUpdate
resource_delete = gnocchiclient.v1.resource:CliResourceDelete
resource_list = gnocchiclient.v1.resourcecli:CliResourceList
resource_show = gnocchiclient.v1.resourcecli:CliResourceShow
resource_search = gnocchiclient.v1.resourcecli:CliResourceSearch
resource_create = gnocchiclient.v1.resourcecli:CliResourceCreate
resource_update = gnocchiclient.v1.resourcecli:CliResourceUpdate
resource_delete = gnocchiclient.v1.resourcecli:CliResourceDelete
[build_sphinx]
source-dir = doc/source