remove gnocchi specific commands and set to v2

This commit is contained in:
gordon chung 2015-12-15 16:52:43 -05:00
parent 3c46e6b930
commit 026b43ba76
15 changed files with 2 additions and 1130 deletions

View File

@ -1,54 +0,0 @@
#
# 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.
from oslo_serialization import jsonutils
from gnocchiclient.v1 import base
class ArchivePolicyManager(base.Manager):
url = "v1/archive_policy/"
def list(self):
"""List archive policies
"""
return self._get(self.url).json()
def get(self, name):
"""Get an archive policy
:param name: Name of the archive policy
:type name: str
"""
return self._get(self.url + name).json()
def create(self, archive_policy):
"""Create an archive policy
:param archive_policy: the archive policy
:type archive_policy: dict
"""
return self._post(
self.url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(archive_policy)).json()
def delete(self, name):
"""Delete an archive policy
:param name: Name of the archive policy
:type name: str
"""
self._delete(self.url + name)

View File

@ -1,105 +0,0 @@
#
# 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.
from cliff import command
from cliff import lister
from cliff import show
from gnocchiclient import utils
class CliArchivePolicyList(lister.Lister):
"""List archive policies"""
COLS = ('name',
'back_window', 'definition', 'aggregation_methods')
def take_action(self, parsed_args):
policies = self.app.client.archive_policy.list()
for ap in policies:
utils.format_archive_policy(ap)
return utils.list2cols(self.COLS, policies)
class CliArchivePolicyShow(show.ShowOne):
"""Show an archive policy"""
def get_parser(self, prog_name):
parser = super(CliArchivePolicyShow, self).get_parser(prog_name)
parser.add_argument("name",
help="Name of the archive policy")
return parser
def take_action(self, parsed_args):
ap = self.app.client.archive_policy.get(
name=parsed_args.name)
utils.format_archive_policy(ap)
return self.dict2columns(ap)
def archive_policy_definition(string):
parts = string.split(",")
defs = {}
for part in parts:
attr, __, value = part.partition(":")
if (attr not in ['granularity', 'points', 'timespan']
or value is None):
raise ValueError
defs[attr] = value
if len(defs) < 2:
raise ValueError
return defs
class CliArchivePolicyCreate(show.ShowOne):
"""Create an archive policy"""
def get_parser(self, prog_name):
parser = super(CliArchivePolicyCreate, self).get_parser(prog_name)
parser.add_argument("name", help=("name of the archive policy"))
parser.add_argument("-b", "--back-window", dest="back_window",
type=int,
help=("back window of the archive policy"))
parser.add_argument("-m", "--aggregation-method",
action="append",
dest="aggregation_methods",
help=("aggregation method of the archive policy"))
parser.add_argument("-d", "--definition", action='append',
required=True, type=archive_policy_definition,
metavar="<DEFINITION>",
help=("two attributes (separated by ',') of an "
"archive policy definition with its name "
"and value separated with a ':'"))
return parser
def take_action(self, parsed_args):
archive_policy = utils.dict_from_parsed_args(
parsed_args, ['name', 'back_window', 'aggregation_methods',
'definition'])
ap = self.app.client.archive_policy.create(
archive_policy=archive_policy)
utils.format_archive_policy(ap)
return self.dict2columns(ap)
class CliArchivePolicyDelete(command.Command):
"""Delete an archive policy"""
def get_parser(self, prog_name):
parser = super(CliArchivePolicyDelete, self).get_parser(prog_name)
parser.add_argument("name",
help="Name of the archive policy")
return parser
def take_action(self, parsed_args):
self.app.client.archive_policy.delete(name=parsed_args.name)

View File

@ -1,50 +0,0 @@
#
# 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.
from oslo_serialization import jsonutils
from gnocchiclient.v1 import base
class ArchivePolicyRuleManager(base.Manager):
url = "v1/archive_policy_rule/"
def list(self):
"""List archive policy rules
"""
return self._get(self.url).json()
def get(self, name):
"""Get an archive policy rules
:param name: Name of the archive policy rule
:type name: str
"""
return self._get(self.url + name).json()
def create(self, archive_policy_rule):
"""Create an archive policy rule
"""
return self._post(
self.url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(archive_policy_rule)).json()
def delete(self, name):
"""Delete an archive policy rule
:param name: Name of the archive policy rule
:type name: str
"""
self._delete(self.url + name)

View File

@ -1,79 +0,0 @@
#
# 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.
from cliff import command
from cliff import lister
from cliff import show
from gnocchiclient import utils
class CliArchivePolicyRuleList(lister.Lister):
"""List archive policy rules"""
COLS = ('name', 'archive_policy_name', 'metric_pattern')
def take_action(self, parsed_args):
ap_rules = self.app.client.archive_policy_rule.list()
return utils.list2cols(self.COLS, ap_rules)
class CliArchivePolicyRuleShow(show.ShowOne):
"""Show an archive policy rule"""
def get_parser(self, prog_name):
parser = super(CliArchivePolicyRuleShow, self).get_parser(prog_name)
parser.add_argument("name",
help="Name of the archive policy rule")
return parser
def take_action(self, parsed_args):
ap_rule = self.app.client.archive_policy_rule.get(
name=parsed_args.name)
return self.dict2columns(ap_rule)
class CliArchivePolicyRuleCreate(show.ShowOne):
"""Create an archive policy rule"""
def get_parser(self, prog_name):
parser = super(CliArchivePolicyRuleCreate, self).get_parser(prog_name)
parser.add_argument("name",
help=("Rule name"))
parser.add_argument("-a", "--archive-policy-name",
dest="archive_policy_name",
required=True,
help=("Archive policy name"))
parser.add_argument("-m", "--metric-pattern",
dest="metric_pattern", required=True,
help=("Wildcard of metric name to match"))
return parser
def take_action(self, parsed_args):
rule = utils.dict_from_parsed_args(
parsed_args, ["name", "metric_pattern", "archive_policy_name"])
policy = self.app.client.archive_policy_rule.create(rule)
return self.dict2columns(policy)
class CliArchivePolicyRuleDelete(command.Command):
"""Delete an archive policy rule"""
def get_parser(self, prog_name):
parser = super(CliArchivePolicyRuleDelete, self).get_parser(prog_name)
parser.add_argument("name",
help="Name of the archive policy rule")
return parser
def take_action(self, parsed_args):
self.app.client.archive_policy_rule.delete(parsed_args.name)

View File

@ -1,201 +0,0 @@
#
# 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 datetime
import uuid
from oslo_serialization import jsonutils
from gnocchiclient import utils
from gnocchiclient.v1 import base
class MetricManager(base.Manager):
metric_url = "v1/metric/"
resource_url = "v1/resource/generic/%s/metric/"
def list(self):
"""List archive metrics
"""
return self._get(self.metric_url).json()
@staticmethod
def _ensure_metric_is_uuid(metric, attribute="resource_id"):
try:
uuid.UUID(metric)
except ValueError:
raise TypeError("%s is required to get a metric by name" %
attribute)
def get(self, metric, resource_id=None):
"""Get an 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
"""
if resource_id is None:
self._ensure_metric_is_uuid(metric)
url = self.metric_url + metric
else:
url = (self.resource_url % resource_id) + metric
return self._get(url).json()
# FIXME(jd): remove refetch_metric when LP#1497171 is fixed
def create(self, metric, refetch_metric=True):
"""Create an metric
:param metric: The metric
:type metric: str
"""
resource_id = metric.get('resource_id')
if resource_id is None:
metric = self._post(
self.metric_url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(metric)).json()
# FIXME(sileht): create and get have a
# different output: LP#1497171
if refetch_metric:
return self.get(metric["id"])
return metric
metric_name = metric.get('name')
if metric_name is None:
raise TypeError("metric_name is required if resource_id is set")
del metric['resource_id']
metric = {metric_name: metric}
metric = self._post(
self.resource_url % resource_id,
headers={'Content-Type': "application/json"},
data=jsonutils.dumps(metric))
return self.get(metric_name, resource_id)
def delete(self, metric, resource_id=None):
"""Delete an 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
"""
if resource_id is None:
self._ensure_metric_is_uuid(metric)
url = self.metric_url + metric
else:
url = self.resource_url % resource_id + metric
self._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.metric_url + metric + "/measures"
else:
url = self.resource_url % resource_id + metric + "/measures"
return self._post(
url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(measures))
def get_measures(self, metric, start=None, stop=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: beginning of the period
:type start: timestamp
:param stop: end of the period
:type stop: 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(stop, datetime.datetime):
stop = stop.isoformat()
params = dict(start=start, stop=stop, aggregation=aggregation)
params.update(kwargs)
if resource_id is None:
self._ensure_metric_is_uuid(metric)
url = self.metric_url + metric + "/measures"
else:
url = self.resource_url % resource_id + metric + "/measures"
return self._get(url, params=params).json()
def aggregation(self, metrics, query=None,
start=None, stop=None, aggregation=None,
needed_overlap=None, resource_type="generic"):
"""Get measurements of a aggregated metrics
:param metrics: IDs of metric or metric name
:type metric: list or str
:param query: The query dictionary
:type query: dict
:param start: beginning of the period
:type start: timestamp
:param stop: end of the period
:type stop: timestamp
:param aggregation: aggregation to retrieve
:type aggregation: str
:param resource_type: type of resource for the query
:type resource_type: str
See Gnocchi REST API documentation for the format
of *query dictionary*
http://docs.openstack.org/developer/gnocchi/rest.html#searching-for-resources
"""
if isinstance(start, datetime.datetime):
start = start.isoformat()
if isinstance(stop, datetime.datetime):
stop = stop.isoformat()
params = dict(start=start, stop=stop, aggregation=aggregation,
needed_overlap=needed_overlap)
if query is None:
for metric in metrics:
self._ensure_metric_is_uuid(metric)
params['metric'] = metrics
return self._get("v1/aggregation/metric",
params=params).json()
else:
return self._post(
"v1/aggregation/resource/%s/metric/%s?%s" % (
resource_type, metrics,
utils.dict_to_querystring(params)),
headers={'Content-Type': "application/json"},
data=jsonutils.dumps(query)).json()

View File

@ -1,207 +0,0 @@
#
# 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.
from cliff import command
from cliff import lister
from cliff import show
from gnocchiclient import utils
class CliMetricWithResourceID(command.Command):
def get_parser(self, prog_name):
parser = super(CliMetricWithResourceID, self).get_parser(prog_name)
parser.add_argument("--resource-id", "-r",
help="ID of the resource")
return parser
class CliMetricList(lister.Lister):
"""List metrics"""
COLS = ('id', 'archive_policy/name', 'name', 'resource_id')
def take_action(self, parsed_args):
metrics = self.app.client.metric.list()
for metric in metrics:
utils.format_archive_policy(metric["archive_policy"])
utils.format_move_dict_to_root(metric, "archive_policy")
return utils.list2cols(self.COLS, metrics)
class CliMetricShow(CliMetricWithResourceID, show.ShowOne):
"""Show a metric"""
def get_parser(self, prog_name):
parser = super(CliMetricShow, self).get_parser(prog_name)
parser.add_argument("metric",
help="ID or name of the metric")
return parser
def take_action(self, parsed_args):
metric = self.app.client.metric.get(
metric=parsed_args.metric,
resource_id=parsed_args.resource_id)
utils.format_archive_policy(metric["archive_policy"])
utils.format_move_dict_to_root(metric, "archive_policy")
return self.dict2columns(metric)
class CliMetricCreateBase(show.ShowOne, CliMetricWithResourceID):
def get_parser(self, prog_name):
parser = super(CliMetricCreateBase, self).get_parser(prog_name)
parser.add_argument("--archive-policy-name", "-a",
dest="archive_policy_name",
help=("name of the archive policy"))
return parser
def take_action(self, parsed_args):
metric = utils.dict_from_parsed_args(parsed_args,
["archive_policy_name",
"resource_id"])
return self._take_action(metric, parsed_args)
class CliMetricCreate(CliMetricCreateBase):
"""Create a metric"""
def get_parser(self, prog_name):
parser = super(CliMetricCreate, self).get_parser(prog_name)
parser.add_argument("name", nargs='?',
metavar="METRIC_NAME",
help="Name of the metric")
return parser
def _take_action(self, metric, parsed_args):
if parsed_args.name:
metric['name'] = parsed_args.name
metric = self.app.client.metric.create(metric)
utils.format_archive_policy(metric["archive_policy"])
utils.format_move_dict_to_root(metric, "archive_policy")
return self.dict2columns(metric)
class CliMetricDelete(CliMetricWithResourceID):
"""Delete a metric"""
def get_parser(self, prog_name):
parser = super(CliMetricDelete, self).get_parser(prog_name)
parser.add_argument("metric", nargs='+',
help="IDs or names of the metric")
return parser
def take_action(self, parsed_args):
for metric in parsed_args.metric:
self.app.client.metric.delete(metric=metric,
resource_id=parsed_args.resource_id)
class CliMeasuresShow(CliMetricWithResourceID, lister.Lister):
"""Get measurements of a metric"""
COLS = ('timestamp', 'granularity', 'value')
def get_parser(self, prog_name):
parser = super(CliMeasuresShow, self).get_parser(prog_name)
parser.add_argument("metric",
help="ID or name of the metric")
parser.add_argument("--aggregation",
help="aggregation to retrieve")
parser.add_argument("--start",
help="beginning of the period")
parser.add_argument("--stop",
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,
stop=parsed_args.stop,
)
return self.COLS, measures
class CliMeasuresAddBase(CliMetricWithResourceID):
def get_parser(self, prog_name):
parser = super(CliMeasuresAddBase, self).get_parser(prog_name)
parser.add_argument("metric", help="ID or name of the metric")
return parser
class CliMeasuresAdd(CliMeasuresAddBase):
"""Add measurements to a metric"""
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("-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,
)
class CliMeasuresAggregation(lister.Lister):
"""Get measurements of aggregated metrics"""
COLS = ('timestamp', 'granularity', 'value')
def get_parser(self, prog_name):
parser = super(CliMeasuresAggregation, self).get_parser(prog_name)
parser.add_argument("-m", "--metric", nargs='+', required=True,
help="metrics IDs or metric name")
parser.add_argument("--aggregation",
help="aggregation to retrieve")
parser.add_argument("--start",
help="beginning of the period")
parser.add_argument("--stop",
help="end of the period")
parser.add_argument("--needed-overlap", type=float,
help=("percent of datapoints in each "
"metrics required"))
parser.add_argument("--query", help="Query"),
parser.add_argument("--resource-type", default="generic",
help="Resource type to query"),
return parser
def take_action(self, parsed_args):
metrics = parsed_args.metric
query = None
if parsed_args.query:
query = utils.search_query_builder(parsed_args.query)
if len(parsed_args.metric) != 1:
raise ValueError("One metric is required if query is provied")
metrics = parsed_args.metric[0]
measures = self.app.client.metric.aggregation(
metrics=metrics,
query=query,
aggregation=parsed_args.aggregation,
start=parsed_args.start,
stop=parsed_args.stop,
needed_overlap=parsed_args.needed_overlap,
resource_type=parsed_args.resource_type,
)
return self.COLS, measures

View File

@ -1,167 +0,0 @@
#
# 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.
from oslo_serialization import jsonutils
from six.moves.urllib import parse as urllib_parse
from gnocchiclient.v1 import base
def _get_pagination_options(details=False, history=False,
limit=None, marker=None, sorts=None):
options = []
if details:
options.append("details=true")
if history:
options.append("history=true")
if limit:
options.append("limit=%d" % limit)
if marker:
options.append("marker=%s" % urllib_parse.quote(marker))
for sort in sorts or []:
options.append("sort=%s" % urllib_parse.quote(sort))
if options:
return "%s" % "&".join(options)
else:
return ""
class ResourceManager(base.Manager):
url = "v1/resource/"
def list(self, resource_type="generic", details=False, history=False,
limit=None, marker=None, sorts=None):
"""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
:param limit: maximum number of resources to return
:type limit: int
:param marker: the last item of the previous page; we returns the next
results after this value.
:param sorts: list of resource attributes to order by. (example
["user_id:desc-nullslast", "project_id:asc"]
:type sorts: list of str
"""
qs = _get_pagination_options(details, history, limit, marker, sorts)
url = "%s%s?%s" % (self.url, resource_type, qs)
return self._get(url).json()
def get(self, resource_type, resource_id, history=False):
"""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
:param history: Show the history of the resource
:type history: bool
"""
history = "/history" if history else ""
url = self.url + "%s/%s%s" % (resource_type, resource_id, history)
return self._get(url).json()
def history(self, resource_type, resource_id, details=False,
limit=None, marker=None, sorts=None):
"""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
:param details: Show all attributes of resources
:type details: bool
:param limit: maximum number of resources to return
:type limit: int
:param marker: the last item of the previous page; we returns the next
results after this value.
:param sorts: list of resource attributes to order by. (example
["user_id:desc-nullslast", "project_id:asc"]
:type sorts: list of str
"""
qs = _get_pagination_options(details, False, limit, marker, sorts)
url = "%s%s/%s/history?%s" % (self.url, resource_type, resource_id, qs)
return self._get(url).json()
def create(self, resource_type, resource):
"""Create a resource
:param resource_type: Type of the resource
:type resource_type: str
:param resource: Attribute of the resource
:type resource: dict
"""
return self._post(
self.url + resource_type,
headers={'Content-Type': "application/json"},
data=jsonutils.dumps(resource)).json()
def update(self, resource_type, resource_id, resource):
"""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
"""
return self._patch(
self.url + resource_type + "/" + resource_id,
headers={'Content-Type': "application/json"},
data=jsonutils.dumps(resource)).json()
def delete(self, resource_id):
"""Delete a resource
:param resource_id: ID of the resource
:type resource_id: str
"""
self._delete(self.url + "generic/" + resource_id)
def search(self, resource_type="generic", query=None, details=False,
history=False, limit=None, marker=None, sorts=None):
"""List resources
:param resource_type: Type of the resource
:param resource_type: str
:param query: The query dictionary
:type query: dict
:param details: Show all attributes of resources
:type details: bool
:param history: Show the history of resources
:type history: bool
:param limit: maximum number of resources to return
:type limit: int
:param marker: the last item of the previous page; we returns the next
results after this value.
:param sorts: list of resource attributes to order by. (example
["user_id:desc-nullslast", "project_id:asc"]
:type sorts: list of str
See Gnocchi REST API documentation for the format
of *query dictionary*
http://docs.openstack.org/developer/gnocchi/rest.html#searching-for-resources
"""
query = query or {}
qs = _get_pagination_options(details, history, limit, marker, sorts)
url = "v1/search/resource/%s?%s" % (resource_type, qs)
return self._post(
url, headers={'Content-Type': "application/json"},
data=jsonutils.dumps(query)).json()

View File

@ -1,213 +0,0 @@
#
# 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.
from cliff import command
from cliff import lister
from cliff import show
from gnocchiclient import utils
class CliResourceList(lister.Lister):
"""List resources"""
COLS = ('id', 'type',
'project_id', 'user_id',
'started_at', 'ended_at',
'revision_start', 'revision_end')
def get_parser(self, prog_name, history=True):
parser = super(CliResourceList, self).get_parser(prog_name)
parser.add_argument("--details", action='store_true',
help="Show all attributes of generic resources"),
if history:
parser.add_argument("--history", action='store_true',
help="Show history of the resources"),
parser.add_argument("--limit", type=int, metavar="<LIMIT>",
help="Number of resources to return "
"(Default is server default)")
parser.add_argument("--marker", metavar="<MARKER>",
help="Last item of the previous listing. "
"Return the next results after this value")
parser.add_argument("--sort", action="append", metavar="<SORT>",
help="Sort of resource attribute "
"(example: user_id:desc-nullslast")
parser.add_argument("--type", "-t", dest="resource_type",
default="generic", help="Type of resource")
return parser
def take_action(self, parsed_args):
resources = self.app.client.resource.list(
resource_type=parsed_args.resource_type,
**self._get_pagination_options(parsed_args))
return utils.list2cols(self.COLS, resources)
@staticmethod
def _get_pagination_options(parsed_args):
options = dict(
details=parsed_args.details,
sorts=parsed_args.sort,
limit=parsed_args.limit,
marker=parsed_args.marker)
if hasattr(parsed_args, 'history'):
options['history'] = parsed_args.history
return options
class CliResourceHistory(CliResourceList):
"""Show the history of a resource"""
def get_parser(self, prog_name):
parser = super(CliResourceHistory, self).get_parser(prog_name,
history=False)
parser.add_argument("resource_id",
help="ID of a resource")
return parser
def take_action(self, parsed_args):
resources = self.app.client.resource.history(
resource_type=parsed_args.resource_type,
resource_id=parsed_args.resource_id,
**self._get_pagination_options(parsed_args))
return utils.list2cols(self.COLS, resources)
class CliResourceSearch(CliResourceList):
"""Search resources with specified query rules"""
def get_parser(self, prog_name):
parser = super(CliResourceSearch, self).get_parser(prog_name)
parser.add_argument("--query", help="Query"),
return parser
def take_action(self, parsed_args):
resources = self.app.client.resource.search(
resource_type=parsed_args.resource_type,
query=utils.search_query_builder(parsed_args.query),
**self._get_pagination_options(parsed_args))
return utils.list2cols(self.COLS, 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):
"""Show a resource"""
def get_parser(self, prog_name):
parser = super(CliResourceShow, self).get_parser(prog_name)
parser.add_argument("--type", "-t", dest="resource_type",
default="generic", 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):
"""Create a resource"""
def get_parser(self, prog_name):
parser = super(CliResourceCreate, self).get_parser(prog_name)
parser.add_argument("--type", "-t", dest="resource_type",
default="generic", help="Type of resource")
parser.add_argument("resource_id",
help="ID of the resource")
parser.add_argument("-a", "--attribute", action='append',
default=[],
help=("name and value of a attribute "
"separated with a ':'"))
parser.add_argument("-m", "--add-metric", action='append',
default=[],
help="name:id of a metric to add"),
parser.add_argument(
"-n", "--create-metric", action='append',
help="name:archive_policy_name of a metric to create"),
parser.add_argument("-d", "--delete-metric", action='append',
default=[],
help="Name of a metric to delete"),
return parser
def _resource_from_args(self, parsed_args, update=False):
resource = {}
if not update:
resource['id'] = parsed_args.resource_id
if parsed_args.attribute:
for attr in parsed_args.attribute:
attr, __, value = attr.partition(":")
resource[attr] = value
if (parsed_args.add_metric
or parsed_args.create_metric
or parsed_args.delete_metric):
if update:
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.add_metric:
name, _, value = metric.partition(":")
resource['metrics'][name] = value
for metric in parsed_args.delete_metric:
resource['metrics'].pop(name, None)
for metric in parsed_args.create_metric:
name, _, value = metric.partition(":")
if value is "":
resource['metrics'][name] = {}
else:
resource['metrics'][name] = {'archive_policy_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):
"""Update a resource"""
def take_action(self, parsed_args):
resource = self._resource_from_args(parsed_args, update=True)
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):
"""Delete a resource"""
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

@ -1,21 +0,0 @@
#
# 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.
from gnocchiclient.v1 import base
class StatusManager(base.Manager):
url = "v1/status"
def get(self):
"""Get Gnocchi status."""
return self._get(self.url).json()

View File

@ -1,31 +0,0 @@
#
# 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.
from cliff import show
class CliStatusShow(show.ShowOne):
"""Show the status of measurements processing"""
def take_action(self, parsed_args):
status = self.app.client.status.get()
nb_metric = len(status['storage']['measures_to_process'])
nb_measures = (
sum(status['storage']['measures_to_process'].values())
)
return self.dict2columns({
"storage/total number of measures to process": nb_measures,
"storage/number of metric having measures to process": nb_metric,
})

View File

@ -11,11 +11,11 @@
# License for the specific language governing permissions and limitations
# under the License.
from gnocchiclient.v1 import base
from aodhclient.v2 import base
class CapabilitiesManager(base.Manager):
cap_url = "v1/capabilities/"
cap_url = "v2/capabilities/"
def list(self):
"""List capabilities