diff --git a/gnocchiclient/tests/functional/test_archive_policy.py b/gnocchiclient/tests/functional/test_archive_policy.py new file mode 100644 index 0000000..f2237f2 --- /dev/null +++ b/gnocchiclient/tests/functional/test_archive_policy.py @@ -0,0 +1,76 @@ +# 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 tempest_lib import exceptions + +from gnocchiclient.tests.functional import base + + +class ArchivePolicyClientTest(base.ClientTestBase): + + def details_multiple(self, output_lines, with_label=False): + """Return list of dicts with item details from cli output tables. + + If with_label is True, key '__label' is added to each items dict. + For more about 'label' see OutputParser.tables(). + + NOTE(sileht): come from tempest-lib just because cliff use + Field instead of Property as first columun header. + """ + items = [] + tables_ = self.parser.tables(output_lines) + for table_ in tables_: + if ('Field' not in table_['headers'] + or 'Value' not in table_['headers']): + raise exceptions.InvalidStructure() + item = {} + for value in table_['values']: + item[value[0]] = value[1] + if with_label: + item['__label'] = table_['label'] + items.append(item) + return items + + def test_archive_policy_scenario(self): + # CREATE + result = self.gnocchi( + u'archivepolicy', params=u"create -a name:low" + u" -a back_window:0" + u" -d granularity:1s" + u" -d points:86400 ") + policy = self.details_multiple(result)[0] + self.assertEqual('low', policy["name"]) + + # GET + result = self.gnocchi( + 'archivepolicy', params="show low") + policy = self.details_multiple(result)[0] + self.assertEqual("low", policy["name"]) + + # DELETE + result = self.gnocchi('archivepolicy', + params="delete low") + self.assertEqual("", result) + + # GET FAIL + result = self.gnocchi('archivepolicy', + params="show low", + fail_ok=True, merge_stderr=True) + self.assertFirstLineStartsWith(result.split('\n'), + "Not Found (HTTP 404)") + + # DELETE FAIL + result = self.gnocchi('archivepolicy', + params="delete low", + fail_ok=True, merge_stderr=True) + self.assertFirstLineStartsWith(result.split('\n'), + "Not Found (HTTP 404)") diff --git a/gnocchiclient/tests/functional/test_archive_policy_rule.py b/gnocchiclient/tests/functional/test_archive_policy_rule.py new file mode 100644 index 0000000..96af076 --- /dev/null +++ b/gnocchiclient/tests/functional/test_archive_policy_rule.py @@ -0,0 +1,75 @@ +# 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 tempest_lib import exceptions + +from gnocchiclient.tests.functional import base + + +class ArchivePolicyRuleClientTest(base.ClientTestBase): + + def details_multiple(self, output_lines, with_label=False): + """Return list of dicts with item details from cli output tables. + + If with_label is True, key '__label' is added to each items dict. + For more about 'label' see OutputParser.tables(). + + NOTE(sileht): come from tempest-lib just because cliff use + Field instead of Property as first columun header. + """ + items = [] + tables_ = self.parser.tables(output_lines) + for table_ in tables_: + if ('Field' not in table_['headers'] + or 'Value' not in table_['headers']): + raise exceptions.InvalidStructure() + item = {} + for value in table_['values']: + item[value[0]] = value[1] + if with_label: + item['__label'] = table_['label'] + items.append(item) + return items + + def test_archive_policy_rule_scenario(self): + # CREATE + result = self.gnocchi( + u'archivepolicyrule', params=u"create -a name:test" + u" -a archive_policy_name:high" + u" -a metric_pattern:disk.io.*") + policy_rule = self.details_multiple(result)[0] + self.assertEqual('test', policy_rule["name"]) + + # GET + result = self.gnocchi( + 'archivepolicyrule', params="show test") + policy_rule = self.details_multiple(result)[0] + self.assertEqual("test", policy_rule["name"]) + + # DELETE + result = self.gnocchi('archivepolicyrule', + params="delete test") + self.assertEqual("", result) + + # GET FAIL + result = self.gnocchi('archivepolicyrule', + params="show test", + fail_ok=True, merge_stderr=True) + self.assertFirstLineStartsWith(result.split('\n'), + "Not Found (HTTP 404)") + + # DELETE FAIL + result = self.gnocchi('archivepolicyrule', + params="delete test", + fail_ok=True, merge_stderr=True) + self.assertFirstLineStartsWith(result.split('\n'), + "Not Found (HTTP 404)") diff --git a/gnocchiclient/v1/archivepolicy.py b/gnocchiclient/v1/archivepolicy.py new file mode 100644 index 0000000..74f31ec --- /dev/null +++ b/gnocchiclient/v1/archivepolicy.py @@ -0,0 +1,53 @@ +# +# 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): + + def list(self): + """List archive policies + + """ + url = self.client._build_url("archive_policy") + return self.client.api.get(url).json() + + def get(self, policy_name): + """Get a archive_policy + + :param policy_name: Name of the archive_policy + :type policy_name: str + """ + url = self.client._build_url("archive_policy/%s" % policy_name) + return self.client.api.get(url).json() + + def create(self, data): + """Create a archive_policy + + """ + url = self.client._build_url("archive_policy/") + return self.client.api.post( + url, headers={'Content-Type': "application/json"}, + data=jsonutils.dumps(data)).json() + + def delete(self, policy_name): + """Delete a archive_policy + + :param policy_name: ID of the archive_policy + :type policy_name: str + """ + url = self.client._build_url("archive_policy/%s" % policy_name) + self.client.api.delete(url) diff --git a/gnocchiclient/v1/archivepolicycli.py b/gnocchiclient/v1/archivepolicycli.py new file mode 100644 index 0000000..7668b71 --- /dev/null +++ b/gnocchiclient/v1/archivepolicycli.py @@ -0,0 +1,85 @@ +# +# 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 + + +class CliArchivePolicyList(lister.Lister): + COLS = ('name', + 'back_window', 'definition', 'aggregation_methods') + + def get_parser(self, prog_name, history=True): + parser = super(CliArchivePolicyList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + policy = self.app.client.archivepolicy.list(parsed_args) + return self.COLS, [self._2tuple(r) for r in policy] + + @classmethod + def _2tuple(cls, field): + return tuple([field[k] for k in cls.COLS]) + + +class CliArchivePolicyShow(show.ShowOne): + 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): + res = self.app.client.archivepolicy.get( + policy_name=parsed_args.name) + return self.dict2columns(res) + + +class CliArchivePolicyCreate(show.ShowOne): + def get_parser(self, prog_name): + parser = super(CliArchivePolicyCreate, self).get_parser(prog_name) + parser.add_argument("-a", "--attribute", action='append', + help=("name and value of a attribute " + "separated with a ':'")) + parser.add_argument("-d", "--definition", action='append', + help=("name and value of a attribute " + "separated with a ':'")) + return parser + + def take_action(self, parsed_args): + data = {} + if parsed_args.attribute: + for attr in parsed_args.attribute: + attr, __, value = attr.partition(":") + data[attr] = value + if parsed_args.definition: + definition = {} + data["definition"] = [] + for attr in parsed_args.definition: + attr, __, value = attr.partition(":") + definition[attr] = value + data["definition"].append(definition) + policy = self.app.client.archivepolicy.create(data=data) + return self.dict2columns(policy) + + +class CliArchivePolicyDelete(command.Command): + 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.archivepolicy.delete(parsed_args.name) diff --git a/gnocchiclient/v1/archivepolicyrule.py b/gnocchiclient/v1/archivepolicyrule.py new file mode 100644 index 0000000..d26543f --- /dev/null +++ b/gnocchiclient/v1/archivepolicyrule.py @@ -0,0 +1,55 @@ +# +# 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): + + def list(self): + """List archive policies + + """ + url = self.client._build_url("archive_policy_rule") + return self.client.api.get(url).json() + + def get(self, policy_rule_name): + """Get a archive_policy + + :param policy_name: Name of the archive_policy + :type policy_name: str + """ + url = self.client._build_url("archive_policy_rule/%s" + % policy_rule_name) + return self.client.api.get(url).json() + + def create(self, data): + """Create a archive_policy + + """ + url = self.client._build_url("archive_policy_rule/") + return self.client.api.post( + url, headers={'Content-Type': "application/json"}, + data=jsonutils.dumps(data)).json() + + def delete(self, policy_rule_name): + """Delete a archive_policy + + :param policy_name: ID of the archive_policy + :type policy_name: str + """ + url = self.client._build_url("archive_policy_rule/%s" + % policy_rule_name) + self.client.api.delete(url) diff --git a/gnocchiclient/v1/archivepolicyrulecli.py b/gnocchiclient/v1/archivepolicyrulecli.py new file mode 100644 index 0000000..9e38f07 --- /dev/null +++ b/gnocchiclient/v1/archivepolicyrulecli.py @@ -0,0 +1,74 @@ +# +# 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 + + +class CliArchivePolicyRuleList(lister.Lister): + COLS = ('archive_policy_name', 'metric_pattern', 'name') + + def get_parser(self, prog_name, history=True): + parser = super(CliArchivePolicyRuleList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + policy = self.app.client.archivepolicyrule.list(parsed_args) + return self.COLS, [self._2tuple(r) for r in policy] + + @classmethod + def _2tuple(cls, field): + return tuple([field[k] for k in cls.COLS]) + + +class CliArchivePolicyRuleShow(show.ShowOne): + 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): + res = self.app.client.archivepolicyrule.get( + policy_rule_name=parsed_args.name) + return self.dict2columns(res) + + +class CliArchivePolicyRuleCreate(show.ShowOne): + def get_parser(self, prog_name): + parser = super(CliArchivePolicyRuleCreate, self).get_parser(prog_name) + parser.add_argument("-a", "--attribute", action='append', + help=("name and value of a attribute " + "separated with a ':'")) + return parser + + def take_action(self, parsed_args): + data = {} + if parsed_args.attribute: + for attr in parsed_args.attribute: + attr, __, value = attr.partition(":") + data[attr] = value + policy = self.app.client.archivepolicyrule.create(data=data) + return self.dict2columns(policy) + + +class CliArchivePolicyRuleDelete(command.Command): + 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.archivepolicyrule.delete(parsed_args.name) diff --git a/gnocchiclient/v1/client.py b/gnocchiclient/v1/client.py index 584e8b1..984bdbe 100644 --- a/gnocchiclient/v1/client.py +++ b/gnocchiclient/v1/client.py @@ -15,6 +15,8 @@ from keystoneclient import session as keystoneclient_session +from gnocchiclient.v1 import archivepolicy +from gnocchiclient.v1 import archivepolicyrule from gnocchiclient.v1 import resource @@ -42,6 +44,9 @@ class Client(object): """Initialize a new client for the Gnocchi v1 API.""" self.api = keystoneclient_session.Session(auth, **kwargs) self.resource = resource.ResourceManager(self) + self.archivepolicy = archivepolicy.ArchivePolicyManager(self) + self.archivepolicyrule = archivepolicyrule.ArchivePolicyRuleManager( + self) self.interface = interface self.region_name = region_name self._endpoint = endpoint diff --git a/setup.cfg b/setup.cfg index a099d57..6eddf8f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -35,6 +35,14 @@ gnocchi.cli.v1 = resource_create = gnocchiclient.v1.resourcecli:CliResourceCreate resource_update = gnocchiclient.v1.resourcecli:CliResourceUpdate resource_delete = gnocchiclient.v1.resourcecli:CliResourceDelete + archivepolicy_list = gnocchiclient.v1.archivepolicycli:CliArchivePolicyList + archivepolicy_show = gnocchiclient.v1.archivepolicycli:CliArchivePolicyShow + archivepolicy_create = gnocchiclient.v1.archivepolicycli:CliArchivePolicyCreate + archivepolicy_delete = gnocchiclient.v1.archivepolicycli:CliArchivePolicyDelete + archivepolicyrule_list = gnocchiclient.v1.archivepolicyrulecli:CliArchivePolicyRuleList + archivepolicyrule_show = gnocchiclient.v1.archivepolicyrulecli:CliArchivePolicyRuleShow + archivepolicyrule_create = gnocchiclient.v1.archivepolicyrulecli:CliArchivePolicyRuleCreate + archivepolicyrule_delete = gnocchiclient.v1.archivepolicyrulecli:CliArchivePolicyRuleDelete keystoneclient.auth.plugin = gnocchi-noauth = gnocchiclient.noauth:GnocchiNoAuthPlugin