Allow CRUD measurements

This change allows to retreive and add measures to a metric.

It also rename --endpoint to --gnocchi-endpoint to avoid
argparse conflict between --endpoint and --end.

Change-Id: I5685e0c318a3b7d93bed24539d2cbe684d165285
This commit is contained in:
Mehdi Abaakouk
2015-09-18 14:37:11 +02:00
parent 1a4220378a
commit 65b05dcd1c
9 changed files with 177 additions and 6 deletions

View File

@@ -45,7 +45,7 @@ set these environment variables::
export OS_AUTH_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155
Also, if the server doesn't support authentification, you can provide
:option:`--os-auth-plugon` gnocchi-noauth, :option:`--endpoint`, :option:`--user-id`
:option:`--os-auth-plugon` gnocchi-noauth, :option:`--gnocchi-endpoint`, :option:`--user-id`
and :option:`--project-id`. You can alternatively set these environment variables::
export OS_AUTH_PLUGIN=gnocchi-noauth

View File

@@ -56,7 +56,8 @@ class GnocchiNoAuthPlugin(base.BaseAuthPlugin):
options.extend([
cfg.StrOpt('user-id', help='User ID', required=True),
cfg.StrOpt('project-id', help='Project ID', required=True),
cfg.StrOpt('endpoint', help='Gnocchi endpoint', required=True),
cfg.StrOpt('gnocchi-endpoint', help='Gnocchi endpoint',
dest="endpoint", required=True),
])
return options

View File

@@ -118,7 +118,7 @@ class GnocchiShell(app.App):
if plugin != noauth.GnocchiNoAuthPlugin:
parser.add_argument(
'--endpoint',
'--gnocchi-endpoint',
metavar='<endpoint>',
dest='endpoint',
default=os.environ.get('GNOCCHI_ENDPOINT'),

View File

@@ -14,6 +14,7 @@ import os
import shlex
import six
import subprocess
import time
import uuid
from tempest_lib.cli import base
@@ -36,9 +37,9 @@ class GnocchiClient(object):
fail_ok=False, merge_stderr=False):
creds = ("--os-auth-plugin gnocchi-noauth "
"--user-id %s --project-id %s "
"--endpoint %s") % (self.user_id,
self.project_id,
self.endpoint)
"--gnocchi-endpoint %s") % (self.user_id,
self.project_id,
self.endpoint)
flags = creds + ' ' + flags
@@ -82,6 +83,15 @@ class ClientTestBase(base.ClientTestBase):
def _get_clients(self):
return GnocchiClient()
def retry_gnocchi(self, retry, *args, **kwargs):
result = ""
while not result.strip() and retry > 0:
result = self.gnocchi(*args, **kwargs)
if not result:
time.sleep(1)
retry -= 1
return result
def gnocchi(self, *args, **kwargs):
return self.clients.gnocchi(*args, **kwargs)

View File

@@ -37,6 +37,29 @@ class MetricClientTest(base.ClientTestBase):
metric_get = self.details_multiple(result)[0]
self.assertEqual(metric, metric_get)
# MEASURES ADD
result = self.gnocchi('measures',
params=("add %s "
"-m '2015-03-06T14:33:57@43.11' "
"--measure '2015-03-06T14:34:12@12' "
) % metric["id"])
self.assertEqual("", result)
# MEASURES GET
result = self.retry_gnocchi(
5, 'measures', params=("get %s "
"--aggregation mean "
"--start 2015-03-06T14:32:00 "
"--end 2015-03-06T14:36:00"
) % metric["id"])
measures = self.parser.listing(result)
self.assertEqual([{'granularity': '1.0',
'timestamp': '2015-03-06T14:33:57+00:00',
'value': '43.11'},
{'granularity': '1.0',
'timestamp': '2015-03-06T14:34:12+00:00',
'value': '12.0'}], measures)
# LIST
result = self.gnocchi('metric', params="list")
metrics = self.parser.listing(result)
@@ -87,6 +110,28 @@ class MetricClientTest(base.ClientTestBase):
metric_get = self.details_multiple(result)[0]
self.assertEqual(metric, metric_get)
# MEASURES ADD
result = self.gnocchi('measures',
params=("add metric-name metric-res "
"-m '2015-03-06T14:33:57@43.11' "
"--measure '2015-03-06T14:34:12@12'"))
self.assertEqual("", result)
# MEASURES GET
result = self.retry_gnocchi(
5, 'measures', params=("get metric-name metric-res "
"--aggregation mean "
"--start 2015-03-06T14:32:00 "
"--end 2015-03-06T14:36:00"))
measures = self.parser.listing(result)
self.assertEqual([{'granularity': '1.0',
'timestamp': '2015-03-06T14:33:57+00:00',
'value': '43.11'},
{'granularity': '1.0',
'timestamp': '2015-03-06T14:34:12+00:00',
'value': '12.0'}], measures)
# LIST
result = self.gnocchi('metric', params="list")
metrics = self.parser.listing(result)

View File

@@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import uuid
from oslo_serialization import jsonutils
@@ -97,3 +98,61 @@ class MetricManager(base.Manager):
url = self.client._build_url("resource/generic/%s/metric/%s" % (
resource_id, metric))
self.client.api.delete(url)
def add_measures(self, metric, measures, resource_id=None):
"""Add measurements to a metric
:param metric: ID or Name of the metric
:type metric: str
:param resource_id: ID of the resource (required
to get a metric by name)
:type resource_id: str
:param measures: measurements
:type measures: list of dict(timestamp=timestamp, value=float)
"""
if resource_id is None:
self._ensure_metric_is_uuid(metric)
url = self.client._build_url("metric/%s/measures" % metric)
else:
url = self.client._build_url(
"resource/generic/%s/metric/%s/measures" % (
resource_id, metric))
return self.client.api.post(
url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(measures))
def get_measures(self, metric, start=None, end=None, aggregation=None,
resource_id=None, **kwargs):
"""Get measurements of a metric
:param metric: ID or Name of the metric
:type metric: str
:param start: begin of the period
:type start: timestamp
:param end: end of the period
:type end: timestamp
:param aggregation: aggregation to retrieve
:type aggregation: str
:param resource_id: ID of the resource (required
to get a metric by name)
:type resource_id: str
All other arguments are arguments are dedicated to custom aggregation
method passed as-is to the Gnocchi.
"""
if isinstance(start, datetime.datetime):
start = start.isoformat()
if isinstance(end, datetime.datetime):
end = end.isoformat()
params = dict(start=start, end=end, aggregation=aggregation)
params.update(kwargs)
if resource_id is None:
self._ensure_metric_is_uuid(metric)
url = self.client._build_url("metric/%s/measures" % metric)
else:
url = self.client._build_url(
"resource/generic/%s/metric/%s/measures" % (
resource_id, metric))
return self.client.api.get(url, params=params).json()

View File

@@ -85,3 +85,56 @@ class CliMetricDelete(command.Command):
def take_action(self, parsed_args):
self.app.client.metric.delete(metric=parsed_args.metric,
resource_id=parsed_args.resource_id)
class CliMeasuresGet(lister.Lister):
COLS = ('timestamp', 'granularity', 'value')
def get_parser(self, prog_name):
parser = super(CliMeasuresGet, self).get_parser(prog_name)
parser.add_argument("metric",
help="ID or name of the metric")
parser.add_argument("resource_id", nargs='?',
help="ID of the resource")
parser.add_argument("--aggregation",
help="aggregation to retrieve")
parser.add_argument("--start",
help="start of the period")
parser.add_argument("--end",
help="end of the period")
return parser
def take_action(self, parsed_args):
measures = self.app.client.metric.get_measures(
metric=parsed_args.metric,
resource_id=parsed_args.resource_id,
aggregation=parsed_args.aggregation,
start=parsed_args.start,
end=parsed_args.end,
)
return self.COLS, measures
class CliMeasuresAdd(command.Command):
def measure(self, measure):
timestamp, __, value = measure.rpartition("@")
return {'timestamp': timestamp, 'value': float(value)}
def get_parser(self, prog_name):
parser = super(CliMeasuresAdd, self).get_parser(prog_name)
parser.add_argument("metric",
help="ID or name of the metric")
parser.add_argument("resource_id", nargs='?',
help="ID of the resource")
parser.add_argument("-m", "--measure", action='append',
required=True, type=self.measure,
help=("timestamp and value of a measure "
"separated with a '@'"))
return parser
def take_action(self, parsed_args):
self.app.client.metric.add_measures(
metric=parsed_args.metric,
resource_id=parsed_args.resource_id,
measures=parsed_args.measure,
)

View File

@@ -39,6 +39,7 @@ policy_file = ${GNOCCHI_DATA}/policy.json
[api]
middlewares =
[storage]
metric_processing_delay = 1
file_basepath = ${GNOCCHI_DATA}
driver = file
coordination_url = file://${GNOCCHI_DATA}

View File

@@ -47,6 +47,8 @@ gnocchi.cli.v1 =
metric_show = gnocchiclient.v1.metric_cli:CliMetricShow
metric_create = gnocchiclient.v1.metric_cli:CliMetricCreate
metric_delete = gnocchiclient.v1.metric_cli:CliMetricDelete
measures_get = gnocchiclient.v1.metric_cli:CliMeasuresGet
measures_add = gnocchiclient.v1.metric_cli:CliMeasuresAdd
keystoneclient.auth.plugin =
gnocchi-noauth = gnocchiclient.noauth:GnocchiNoAuthPlugin