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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user