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 .*.swp
.*sw? .*sw?
# generated docs
doc/source/ref/

View File

@ -2,11 +2,12 @@
python-gnocchiclient 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 This is a client for OpenStack gnocchi API. There's :doc:`a Python API
80 cols, so that distribution package maintainers can use it in their packages. <api>` (the :mod:`gnocchiclient` module), and a :doc:`command-line script
Note that this is a hard requirement. <shell>` (installed as :program:`gnocchi`). Each implements the entire
OpenStack Gnocchi API.
* Free software: Apache license * Free software: Apache license
* Documentation: http://docs.openstack.org/developer/python-gnocchiclient * 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 os
import sys 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 ---------------------------------------------------- # -- General configuration ----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be # 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 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 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: Contents:
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
readme
installation installation
usage shell
api
contributing contributing
Indices and tables 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): class Client(object):
"""Client for the Gnocchi v1 API. """Client for the Gnocchi v1 API.
:param string auth: An keystoneclient authentication plugin to :param string auth: An optional keystoneclient authentication plugin
authenticate the session with to authenticate the session with
:type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` :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, def __init__(self, auth=None, endpoint=None, interface=None,
region_name=None, **kwargs): region_name=None, **kwargs):
@ -45,7 +54,7 @@ class Client(object):
region_name=self.region_name) region_name=self.region_name)
return self._endpoint return self._endpoint
def url(self, url_suffix): def _build_url(self, url_suffix):
return "%s/%s/%s" % (self.endpoint.rstrip("/"), return "%s/%s/%s" % (self.endpoint.rstrip("/"),
self.VERSION, self._VERSION,
url_suffix) 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 # 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 # 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 # License for the specific language governing permissions and limitations
# under the License. # under the License.
import uuid
from cliff import command
from cliff import lister
from cliff import show
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from gnocchiclient import utils
from gnocchiclient.v1 import base from gnocchiclient.v1 import base
class ResourceManager(base.Manager): class ResourceManager(base.Manager):
def list(self, resource_type="generic", details=False, history=False): 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" details = "true" if details else "false"
history = "true" if history 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)) resource_type, details, history))
return self.client.api.get(url).json() return self.client.api.get(url).json()
def get(self, resource_type, resource_id): 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)) resource_type, resource_id))
return self.client.api.get(url).json() return self.client.api.get(url).json()
def create(self, resource_type, resource): 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( return self.client.api.post(
url, headers={'Content-Type': "application/json"}, url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(resource)).json() data=jsonutils.dumps(resource)).json()
def update(self, resource_type, resource_id, resource): 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( return self.client.api.patch(
url, headers={'Content-Type': "application/json"}, url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(resource)).json() data=jsonutils.dumps(resource)).json()
def delete(self, resource_id): 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) self.client.api.delete(url)
def search(self, resource_type="generic", details=False, history=False, def search(self, resource_type="generic", request=None, details=False,
request=None): 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 {} request = request or {}
details = "true" if details else "false" details = "true" if details else "false"
history = "true" if history else "false" history = "true" if history else "false"
url = self.client.url("/search/resource/%s?details=%s&history=%s" % ( url = self.client._build_url(
resource_type, details, history)) "/search/resource/%s?details=%s&history=%s" % (
resource_type, details, history))
return self.client.api.post( return self.client.api.post(
url, headers={'Content-Type': "application/json"}, url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(request)).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 = gnocchiclient.shell:main
gnocchi.cli.v1 = gnocchi.cli.v1 =
resource_list = gnocchiclient.v1.resource:CliResourceList resource_list = gnocchiclient.v1.resourcecli:CliResourceList
resource_show = gnocchiclient.v1.resource:CliResourceShow resource_show = gnocchiclient.v1.resourcecli:CliResourceShow
resource_search = gnocchiclient.v1.resource:CliResourceSearch resource_search = gnocchiclient.v1.resourcecli:CliResourceSearch
resource_create = gnocchiclient.v1.resource:CliResourceCreate resource_create = gnocchiclient.v1.resourcecli:CliResourceCreate
resource_update = gnocchiclient.v1.resource:CliResourceUpdate resource_update = gnocchiclient.v1.resourcecli:CliResourceUpdate
resource_delete = gnocchiclient.v1.resource:CliResourceDelete resource_delete = gnocchiclient.v1.resourcecli:CliResourceDelete
[build_sphinx] [build_sphinx]
source-dir = doc/source source-dir = doc/source