From d9a10fe6801ae6838bca75951001c748a3af122f Mon Sep 17 00:00:00 2001 From: Chandan Kumar Date: Thu, 11 Jan 2018 14:34:45 +0530 Subject: [PATCH] Moved gnocchi tempest tests under telemetry tempest plugin * In order to achieve tempest plugin split goal, we have merged aodh, panko, ceilometer and gnocchi tempest plugin into telemetry tempest plugin * gnocchi/tempest -> telemetry_tempest_plugin/gnocchi * gnocchi/tests/functional_live -> telemetry_tempest_plugin/gnocchi Change-Id: Icf6789afc143db3206af409c62a36e56edefd142 --- telemetry_tempest_plugin/config.py | 18 + telemetry_tempest_plugin/gnocchi/__init_.py | 0 .../gnocchi/functional_live/__init__.py | 0 .../gnocchi/functional_live/gabbits/live.yaml | 739 ++++++++++++++++++ .../gabbits/search-resource.yaml | 275 +++++++ .../gnocchi/scenario/__init__.py | 110 +++ telemetry_tempest_plugin/plugin.py | 7 +- 7 files changed, 1148 insertions(+), 1 deletion(-) create mode 100644 telemetry_tempest_plugin/gnocchi/__init_.py create mode 100644 telemetry_tempest_plugin/gnocchi/functional_live/__init__.py create mode 100644 telemetry_tempest_plugin/gnocchi/functional_live/gabbits/live.yaml create mode 100644 telemetry_tempest_plugin/gnocchi/functional_live/gabbits/search-resource.yaml create mode 100644 telemetry_tempest_plugin/gnocchi/scenario/__init__.py diff --git a/telemetry_tempest_plugin/config.py b/telemetry_tempest_plugin/config.py index 87b50af..7fc17a8 100644 --- a/telemetry_tempest_plugin/config.py +++ b/telemetry_tempest_plugin/config.py @@ -27,6 +27,10 @@ service_option = [cfg.BoolOpt('ceilometer', cfg.BoolOpt("aodh_plugin", default=True, help="Whether or not Aodh is expected to be" + "available"), + cfg.BoolOpt('gnocchi', + default=True, + help="Whether or not Gnocchi is expected to be" "available")] telemetry_group = cfg.OptGroup(name='telemetry', @@ -38,6 +42,9 @@ event_group = cfg.OptGroup(name='event', alarming_group = cfg.OptGroup(name='alarming_plugin', title='Alarming Service Options') +metric_group = cfg.OptGroup(name='metric', + title='Metric Service Options') + TelemetryGroup = [ cfg.IntOpt('notification_wait', default=120, @@ -75,3 +82,14 @@ AlarmingGroup = [ 'publicURL', 'adminURL', 'internalURL'], help="The endpoint type to use for the alarming service."), ] + +metric_opts = [ + cfg.StrOpt('catalog_type', + default='metric', + help="Catalog type of the Metric service."), + cfg.StrOpt('endpoint_type', + default='publicURL', + choices=['public', 'admin', 'internal', + 'publicURL', 'adminURL', 'internalURL'], + help="The endpoint type to use for the metric service."), +] diff --git a/telemetry_tempest_plugin/gnocchi/__init_.py b/telemetry_tempest_plugin/gnocchi/__init_.py new file mode 100644 index 0000000..e69de29 diff --git a/telemetry_tempest_plugin/gnocchi/functional_live/__init__.py b/telemetry_tempest_plugin/gnocchi/functional_live/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/telemetry_tempest_plugin/gnocchi/functional_live/gabbits/live.yaml b/telemetry_tempest_plugin/gnocchi/functional_live/gabbits/live.yaml new file mode 100644 index 0000000..d63cb09 --- /dev/null +++ b/telemetry_tempest_plugin/gnocchi/functional_live/gabbits/live.yaml @@ -0,0 +1,739 @@ +# +# Confirmation tests to run against a live web server. +# +# These act as a very basic sanity check. + +defaults: + request_headers: + x-auth-token: $ENVIRON['GNOCCHI_SERVICE_TOKEN'] + authorization: $ENVIRON['GNOCCHI_AUTHORIZATION'] + +tests: + - name: check / + GET: / + + # Fail to create archive policy + - name: wrong archive policy content type + desc: attempt to create archive policy with invalid content-type + POST: /v1/archive_policy + request_headers: + content-type: text/plain + status: 415 + response_strings: + - Unsupported Media Type + + - name: wrong method + desc: attempt to create archive policy with 'PUT' method + PUT: /v1/archive_policy + request_headers: + content-type: application/json + status: 405 + + - name: invalid authZ + desc: x-auth-token is invalid + POST: /v1/archive_policy + request_headers: + content-type: application/json + x-auth-token: 'hello' + authorization: 'basic hello:' + data: + name: medium + definition: + - granularity: 1 second + status: 401 + + - name: bad archive policy body + desc: archive policy contains invalid key 'cowsay' + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + cowsay: moo + status: 400 + response_strings: + - "Invalid input: extra keys not allowed" + + - name: missing definition + desc: archive policy is missing 'definition' keyword + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: medium + status: 400 + response_strings: + - "Invalid input: required key not provided" + + - name: empty definition + desc: empty definition for archive policy + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: medium + definition: [] + status: 400 + response_strings: + - "Invalid input: length of value must be at least 1" + + - name: wrong value definition + desc: invalid type of 'definition' key + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: somename + definition: foobar + status: 400 + response_strings: + - "Invalid input: expected a list" + + - name: useless definition + desc: invalid archive policy definition + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: medium + definition: + - cowsay: moo + status: 400 + response_strings: + - "Invalid input: extra keys not allowed" + + # + # Create archive policy + # + + - name: create archive policy + desc: create archve policy 'gabbilive' for live tests + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: gabbilive + back_window: 0 + definition: + - granularity: 1 second + points: 60 + - granularity: 2 second + timespan: 1 minute + - points: 5 + timespan: 5 minute + aggregation_methods: + - mean + - min + - max + response_headers: + location: $SCHEME://$NETLOC/v1/archive_policy/gabbilive + status: 201 + + # Retrieve it correctly and then poorly + + - name: get archive policy + desc: retrieve archive policy 'gabbilive' and asster its values + GET: $LOCATION + response_headers: + content-type: /application/json/ + response_json_paths: + $.name: gabbilive + $.back_window: 0 + $.definition[0].granularity: "0:00:01" + $.definition[0].points: 60 + $.definition[0].timespan: "0:01:00" + $.definition[1].granularity: "0:00:02" + $.definition[1].points: 30 + $.definition[1].timespan: "0:01:00" + $.definition[2].granularity: "0:01:00" + $.definition[2].points: 5 + $.definition[2].timespan: "0:05:00" + response_json_paths: + $.aggregation_methods.`sorted`: ["max", "mean", "min"] + + - name: get wrong accept + desc: invalid 'accept' header + GET: /v1/archive_policy/medium + request_headers: + accept: text/plain + status: 406 + + # Unexpected methods + + - name: post single archive + desc: unexpected 'POST' request to archive policy + POST: /v1/archive_policy/gabbilive + status: 405 + + - name: put single archive + desc: unexpected 'PUT' request to archive policy + PUT: /v1/archive_policy/gabbilive + status: 405 + + # Duplicated archive policy names ain't allowed + + - name: create duplicate archive policy + desc: create archve policy 'gabbilive' for live tests + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: gabbilive + definition: + - granularity: 30 second + points: 60 + status: 409 + response_strings: + - Archive policy gabbilive already exists + + # Create a unicode named policy + + - name: post unicode policy name + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: ✔éñ☃ + definition: + - granularity: 1 minute + points: 20 + status: 201 + response_headers: + location: $SCHEME://$NETLOC/v1/archive_policy/%E2%9C%94%C3%A9%C3%B1%E2%98%83 + response_json_paths: + name: ✔éñ☃ + + - name: retrieve unicode policy name + GET: $LOCATION + response_json_paths: + name: ✔éñ☃ + + - name: delete unicode archive policy + DELETE: /v1/archive_policy/%E2%9C%94%C3%A9%C3%B1%E2%98%83 + status: 204 + + # It really is gone + + - name: confirm delete + desc: assert deleted unicode policy is not available + GET: /v1/archive_policy/%E2%9C%94%C3%A9%C3%B1%E2%98%83 + status: 404 + + # Fail to delete one that does not exist + + - name: delete missing archive + desc: delete non-existent archive policy + DELETE: /v1/archive_policy/grandiose + status: 404 + response_strings: + - Archive policy grandiose does not exist + + # Attempt to create illogical policies + + - name: create illogical policy + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: complex + definition: + - granularity: 1 second + points: 60 + timespan: "0:01:01" + status: 400 + response_strings: + - timespan ≠ granularity × points + + - name: create identical granularities policy + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: complex + definition: + - granularity: 1 second + points: 60 + - granularity: 1 second + points: 120 + status: 400 + response_strings: + - "More than one archive policy uses granularity `1.0'" + + - name: policy invalid unit + desc: invalid unit for archive policy 'timespan' key + POST: /v1/archive_policy + request_headers: + content-type: application/json + data: + name: 227d0e1f-4295-4e4b-8515-c296c47d71d3 + definition: + - granularity: 1 second + timespan: "1 shenanigan" + status: 400 + + # + # Archive policy rules + # + + - name: create archive policy rule1 + POST: /v1/archive_policy_rule + request_headers: + content-type: application/json + data: + name: gabbilive_rule + metric_pattern: "live.*" + archive_policy_name: gabbilive + status: 201 + response_json_paths: + $.metric_pattern: "live.*" + $.archive_policy_name: gabbilive + $.name: gabbilive_rule + + - name: create invalid archive policy rule + POST: /v1/archive_policy_rule + request_headers: + content-type: application/json + data: + name: test_rule + metric_pattern: "disk.foo.*" + status: 400 + + - name: missing auth archive policy rule + POST: /v1/archive_policy_rule + request_headers: + content-type: application/json + x-auth-token: 'hello' + authorization: 'basic hello:' + data: + name: test_rule + metric_pattern: "disk.foo.*" + archive_policy_name: low + status: 401 + + - name: wrong archive policy rule content type + POST: /v1/archive_policy_rule + request_headers: + content-type: text/plain + status: 415 + response_strings: + - Unsupported Media Type + + - name: bad archive policy rule body + POST: /v1/archive_policy_rule + request_headers: + content-type: application/json + data: + whaa: foobar + status: 400 + response_strings: + - "Invalid input: extra keys not allowed" + + # get an archive policy rules + + - name: get all archive policy rules + GET: /v1/archive_policy_rule + status: 200 + response_json_paths: + $[\name][0].name: "gabbilive_rule" + $[\name][0].metric_pattern: "live.*" + $[\name][0].archive_policy_name: "gabbilive" + + - name: get unknown archive policy rule + GET: /v1/archive_policy_rule/foo + status: 404 + + + - name: get archive policy rule + GET: /v1/archive_policy_rule/gabbilive_rule + status: 200 + response_json_paths: + $.metric_pattern: "live.*" + $.archive_policy_name: "gabbilive" + $.name: "gabbilive_rule" + + - name: delete archive policy in use + desc: fails due to https://bugs.launchpad.net/gnocchi/+bug/1569781 + DELETE: /v1/archive_policy/gabbilive + status: 400 + + # + # Metrics + # + + + - name: get all metrics + GET: /v1/metric + status: 200 + + - name: create metric with name and rule + POST: /v1/metric + request_headers: + content-type: application/json + data: + name: "live.io.rate" + status: 201 + response_json_paths: + $.archive_policy_name: gabbilive + $.name: live.io.rate + + - name: assert metric is present in listing + GET: /v1/metric?id=$HISTORY['create metric with name and rule'].$RESPONSE['$.id'] + response_json_paths: + $.`len`: 1 + + - name: assert metric is the only one with this policy + GET: /v1/metric?archive_policy_name=gabbilive + response_json_paths: + $.`len`: 1 + + - name: delete metric + DELETE: /v1/metric/$HISTORY['create metric with name and rule'].$RESPONSE['$.id'] + status: 204 + + - name: assert metric is expunged + GET: $HISTORY['assert metric is present in listing'].$URL&status=delete + poll: + count: 360 + delay: 1 + response_json_paths: + $.`len`: 0 + + - name: create metric with name and policy + POST: /v1/metric + request_headers: + content-type: application/json + data: + name: "aagabbi.live.metric" + archive_policy_name: "gabbilive" + status: 201 + response_json_paths: + $.archive_policy_name: gabbilive + $.name: "aagabbi.live.metric" + + - name: get valid metric id + GET: $LOCATION + status: 200 + response_json_paths: + $.archive_policy.name: gabbilive + + - name: delete the metric + DELETE: /v1/metric/$RESPONSE['$.id'] + status: 204 + + - name: ensure the metric is delete + GET: /v1/metric/$HISTORY['get valid metric id'].$RESPONSE['$.id'] + status: 404 + + - name: create metric bad archive policy + POST: /v1/metric + request_headers: + content-type: application/json + data: + archive_policy_name: 2e2675aa-105e-4664-a30d-c407e6a0ea7f + status: 400 + response_strings: + - Archive policy 2e2675aa-105e-4664-a30d-c407e6a0ea7f does not exist + + - name: create metric bad content-type + POST: /v1/metric + request_headers: + content-type: plain/text + data: '{"archive_policy_name": "cookies"}' + status: 415 + + + # + # Cleanup + # + + - name: delete archive policy rule + DELETE: /v1/archive_policy_rule/gabbilive_rule + status: 204 + + - name: confirm delete archive policy rule + DELETE: /v1/archive_policy_rule/gabbilive_rule + status: 404 + + + # + # Resources section + # + + - name: root of resource + GET: /v1/resource + response_json_paths: + $.generic: $SCHEME://$NETLOC/v1/resource/generic + + - name: typo of resource + GET: /v1/resoue + status: 404 + + - name: typo of resource extra + GET: /v1/resource/foobar + status: 404 + + - name: generic resource + GET: /v1/resource/generic + status: 200 + + - name: post resource type + POST: /v1/resource_type + request_headers: + content-type: application/json + data: + name: myresource + attributes: + display_name: + type: string + required: true + max_length: 5 + min_length: 2 + status: 201 + response_headers: + location: $SCHEME://$NETLOC/v1/resource_type/myresource + + - name: add an attribute + PATCH: /v1/resource_type/myresource + request_headers: + content-type: application/json-patch+json + data: + - op: "add" + path: "/attributes/awesome-stuff" + value: {"type": "bool", "required": false} + status: 200 + response_json_paths: + $.name: myresource + $.attributes."awesome-stuff".type: bool + $.attributes.[*].`len`: 2 + + - name: remove an attribute + PATCH: /v1/resource_type/myresource + request_headers: + content-type: application/json-patch+json + data: + - op: "remove" + path: "/attributes/awesome-stuff" + status: 200 + response_json_paths: + $.name: myresource + $.attributes.display_name.type: string + $.attributes.[*].`len`: 1 + + - name: myresource resource bad accept + desc: Expect 406 on bad accept type + request_headers: + accept: text/plain + GET: /v1/resource/myresource + status: 406 + response_strings: + - 406 Not Acceptable + + - name: myresource resource complex accept + desc: failover accept media type appropriately + request_headers: + accept: text/plain, application/json; q=0.8 + GET: /v1/resource/myresource + status: 200 + + - name: post myresource resource + POST: /v1/resource/myresource + request_headers: + content-type: application/json + data: + id: 2ae35573-7f9f-4bb1-aae8-dad8dff5706e + user_id: 126204ef-989a-46fd-999b-ee45c8108f31 + project_id: 98e785d7-9487-4159-8ab8-8230ec37537a + display_name: myvm + metrics: + vcpus: + archive_policy_name: gabbilive + status: 201 + response_json_paths: + $.id: 2ae35573-7f9f-4bb1-aae8-dad8dff5706e + $.user_id: 126204ef-989a-46fd-999b-ee45c8108f31 + $.project_id: 98e785d7-9487-4159-8ab8-8230ec37537a + $.display_name: "myvm" + + - name: get myresource resource + GET: $LOCATION + status: 200 + response_json_paths: + $.id: 2ae35573-7f9f-4bb1-aae8-dad8dff5706e + $.user_id: 126204ef-989a-46fd-999b-ee45c8108f31 + $.project_id: 98e785d7-9487-4159-8ab8-8230ec37537a + $.display_name: "myvm" + + - name: get vcpus metric + GET: /v1/metric/$HISTORY['get myresource resource'].$RESPONSE['$.metrics.vcpus'] + status: 200 + response_json_paths: + $.name: vcpus + $.resource.id: 2ae35573-7f9f-4bb1-aae8-dad8dff5706e + + - name: search for myresource resource via user_id + POST: /v1/search/resource/myresource + request_headers: + content-type: application/json + data: + =: + user_id: "126204ef-989a-46fd-999b-ee45c8108f31" + response_json_paths: + $..id: 2ae35573-7f9f-4bb1-aae8-dad8dff5706e + $..user_id: 126204ef-989a-46fd-999b-ee45c8108f31 + $..project_id: 98e785d7-9487-4159-8ab8-8230ec37537a + $..display_name: myvm + + - name: search for myresource resource via user_id and 'generic' type + POST: /v1/search/resource/generic + request_headers: + content-type: application/json + data: + =: + id: "2ae35573-7f9f-4bb1-aae8-dad8dff5706e" + response_strings: + - '"user_id": "126204ef-989a-46fd-999b-ee45c8108f31"' + + - name: search for myresource resource via user_id and project_id + POST: /v1/search/resource/generic + request_headers: + content-type: application/json + data: + and: + - =: + user_id: "126204ef-989a-46fd-999b-ee45c8108f31" + - =: + project_id: "98e785d7-9487-4159-8ab8-8230ec37537a" + response_strings: + - '"id": "2ae35573-7f9f-4bb1-aae8-dad8dff5706e"' + + - name: patch myresource resource + PATCH: /v1/resource/myresource/2ae35573-7f9f-4bb1-aae8-dad8dff5706e + request_headers: + content-type: application/json + data: + display_name: myvm2 + status: 200 + response_json_paths: + display_name: myvm2 + + - name: post some measures to the metric on myresource + POST: /v1/resource/myresource/2ae35573-7f9f-4bb1-aae8-dad8dff5706e/metric/vcpus/measures + request_headers: + content-type: application/json + data: + - timestamp: "2015-03-06T14:33:57" + value: 2 + - timestamp: "2015-03-06T14:34:12" + value: 2 + status: 202 + + - name: get myresource measures with poll + GET: /v1/resource/myresource/2ae35573-7f9f-4bb1-aae8-dad8dff5706e/metric/vcpus/measures + # wait up to 60 seconds before policy is deleted + poll: + count: 60 + delay: 1 + response_json_paths: + $[0][2]: 2 + $[1][2]: 2 + + - name: post some more measures to the metric on myresource + POST: /v1/resource/myresource/2ae35573-7f9f-4bb1-aae8-dad8dff5706e/metric/vcpus/measures + request_headers: + content-type: application/json + data: + - timestamp: "2015-03-06T14:34:15" + value: 5 + - timestamp: "2015-03-06T14:34:20" + value: 5 + status: 202 + + - name: get myresource measures with refresh + GET: /v1/resource/myresource/2ae35573-7f9f-4bb1-aae8-dad8dff5706e/metric/vcpus/measures?refresh=true + response_json_paths: + $[0][2]: 2 + $[1][2]: 4 + $[2][2]: 2 + $[3][2]: 2 + $[4][2]: 5 + $[5][2]: 5 + + # + # Search for resources + # + + - name: typo of search + POST: /v1/search/notexists + status: 404 + + - name: typo of search in resource + POST: /v1/search/resource/foobar + status: 404 + + - name: search with invalid uuid + POST: /v1/search/resource/generic + request_headers: + content-type: application/json + data: + =: + id: "cd9eef" + status: 200 + response_json_paths: + $.`len`: 0 + + - name: assert vcpus metric exists in listing + GET: /v1/metric?id=$HISTORY['get myresource resource'].$RESPONSE['$.metrics.vcpus'] + poll: + count: 360 + delay: 1 + response_json_paths: + $.`len`: 1 + + - name: delete myresource resource + DELETE: /v1/resource/myresource/2ae35573-7f9f-4bb1-aae8-dad8dff5706e + status: 204 + + # assert resource is really deleted + - name: assert resource resource is deleted + GET: /v1/resource/myresource/2ae35573-7f9f-4bb1-aae8-dad8dff5706e + status: 404 + + - name: assert vcpus metric is really expurged + GET: $HISTORY['assert vcpus metric exists in listing'].$URL&status=delete + poll: + count: 360 + delay: 1 + response_json_paths: + $.`len`: 0 + + - name: post myresource resource no data + POST: /v1/resource/myresource + request_headers: + content-type: application/json + status: 400 + + - name: assert no metrics have the gabbilive policy + GET: $HISTORY['assert metric is the only one with this policy'].$URL + response_json_paths: + $.`len`: 0 + + - name: assert no delete metrics have the gabbilive policy + GET: $HISTORY['assert metric is the only one with this policy'].$URL&status=delete + response_json_paths: + $.`len`: 0 + + - name: delete single archive policy cleanup + DELETE: /v1/archive_policy/gabbilive + poll: + count: 360 + delay: 1 + status: 204 + + # It really is gone + + - name: delete our resource type + DELETE: /v1/resource_type/myresource + status: 204 + + - name: confirm delete of cleanup + GET: /v1/archive_policy/gabbilive + status: 404 diff --git a/telemetry_tempest_plugin/gnocchi/functional_live/gabbits/search-resource.yaml b/telemetry_tempest_plugin/gnocchi/functional_live/gabbits/search-resource.yaml new file mode 100644 index 0000000..fe25478 --- /dev/null +++ b/telemetry_tempest_plugin/gnocchi/functional_live/gabbits/search-resource.yaml @@ -0,0 +1,275 @@ +# +# Tests to confirm resources are searchable. Run against a live setup. +# URL: http://gnocchi.xyz/rest.html#searching-for-resources +# +# Instance-ResourceID-1: a64ca14f-bc7c-45b0-aa85-42cd2179e1e2 +# Instance-ResourceID-2: 7ccccfa0-92ce-4225-80ca-3ac9cb122d6a +# Instance-ResourceID-3: c442a47c-eb33-46ce-9665-f3aa0bef54e7 +# +# UserID-1: 33ba83ca-2f12-4ad6-8fa2-bc8b55d36e07 +# UserID-2: 81d82ef3-4deb-499d-9270-9aeb5a3ec5fe +# +# ProjectID-1: c9a5f184-c0d0-4daa-83c3-af6fdc0879e6 +# ProjectID-2: 40eba01c-b348-49b8-803f-67123251a00a +# +# ImageID-1: 7ab2f7ae-7af5-4469-bdc8-3c0f6dfab75d +# ImageID-2: b01f2588-89dc-46b2-897b-fffae1e10975 +# + +defaults: + request_headers: + x-auth-token: $ENVIRON['GNOCCHI_SERVICE_TOKEN'] + authorization: $ENVIRON['GNOCCHI_AUTHORIZATION'] + +tests: + # + # Setup resource types if don't exist + # + + - name: create new resource type 'instance-like' + POST: /v1/resource_type + status: 201 + request_headers: + content-type: application/json + data: + name: instance-like + attributes: + display_name: + type: string + required: True + flavor_id: + type: string + required: True + host: + type: string + required: True + image_ref: + type: string + required: False + server_group: + type: string + required: False + + - name: create new resource type 'image-like' + POST: /v1/resource_type + status: 201 + request_headers: + content-type: application/json + data: + name: image-like + attributes: + name: + type: string + required: True + disk_format: + type: string + required: True + container_format: + type: string + required: True + + # + # Setup test resources + # + - name: helper. create instance-like resource-1 + POST: /v1/resource/instance-like + request_headers: + content-type: application/json + data: + display_name: vm-gabbi-1 + id: a64ca14f-bc7c-45b0-aa85-42cd2179e1e2 + user_id: 33ba83ca-2f12-4ad6-8fa2-bc8b55d36e07 + flavor_id: "1" + image_ref: 7ab2f7ae-7af5-4469-bdc8-3c0f6dfab75d + host: compute-0-gabbi.localdomain + project_id: c9a5f184-c0d0-4daa-83c3-af6fdc0879e6 + status: 201 + + - name: helper. create instance-like resource-2 + POST: /v1/resource/instance-like + request_headers: + content-type: application/json + data: + display_name: vm-gabbi-2 + id: 7ccccfa0-92ce-4225-80ca-3ac9cb122d6a + user_id: 33ba83ca-2f12-4ad6-8fa2-bc8b55d36e07 + flavor_id: "2" + image_ref: b01f2588-89dc-46b2-897b-fffae1e10975 + host: compute-1-gabbi.localdomain + project_id: c9a5f184-c0d0-4daa-83c3-af6fdc0879e6 + status: 201 + + - name: helper. create instance-like resource-3 + POST: /v1/resource/instance-like + request_headers: + content-type: application/json + data: + display_name: vm-gabbi-3 + id: c442a47c-eb33-46ce-9665-f3aa0bef54e7 + user_id: 81d82ef3-4deb-499d-9270-9aeb5a3ec5fe + flavor_id: "2" + image_ref: b01f2588-89dc-46b2-897b-fffae1e10975 + host: compute-1-gabbi.localdomain + project_id: 40eba01c-b348-49b8-803f-67123251a00a + status: 201 + + - name: helper. create image-like resource-1 + POST: /v1/resource/image-like + request_headers: + content-type: application/json + data: + id: 7ab2f7ae-7af5-4469-bdc8-3c0f6dfab75d + container_format: bare + disk_format: qcow2 + name: gabbi-image-1 + user_id: 81d82ef3-4deb-499d-9270-9aeb5a3ec5fe + project_id: 40eba01c-b348-49b8-803f-67123251a00a + status: 201 + + # + # Actual tests + # + + - name: search for all resources with a specific user_id + desc: search through all resource types + POST: /v1/search/resource/generic + request_headers: + content-type: application/json + data: + =: + user_id: 81d82ef3-4deb-499d-9270-9aeb5a3ec5fe + status: 200 + response_json_paths: + $.`len`: 2 + response_json_paths: + $.[0].type: instance-like + $.[1].type: image-like + $.[0].id: c442a47c-eb33-46ce-9665-f3aa0bef54e7 + $.[1].id: 7ab2f7ae-7af5-4469-bdc8-3c0f6dfab75d + + - name: search for all resources of instance-like type create by specific user_id + desc: all instances created by a specified user + POST: /v1/search/resource/generic + request_headers: + content-type: application/json + data: + and: + - =: + type: instance-like + - =: + user_id: 33ba83ca-2f12-4ad6-8fa2-bc8b55d36e07 + status: 200 + response_json_paths: + $.`len`: 2 + response_strings: + - '"id": "a64ca14f-bc7c-45b0-aa85-42cd2179e1e2"' + - '"id": "7ccccfa0-92ce-4225-80ca-3ac9cb122d6a"' + response_json_paths: + $.[0].id: a64ca14f-bc7c-45b0-aa85-42cd2179e1e2 + $.[1].id: 7ccccfa0-92ce-4225-80ca-3ac9cb122d6a + $.[0].type: instance-like + $.[1].type: instance-like + $.[0].metrics.`len`: 0 + $.[1].metrics.`len`: 0 + + - name: search for all resources with a specific project_id + desc: search for all resources in a specific project + POST: /v1/search/resource/generic + request_headers: + content-type: application/json + data: + =: + project_id: c9a5f184-c0d0-4daa-83c3-af6fdc0879e6 + status: 200 + response_json_paths: + $.`len`: 2 + + - name: search for intances on a specific compute using "like" keyword + desc: search for vms hosted on a specific compute node + POST: /v1/search/resource/instance-like + request_headers: + content-type: application/json + data: + like: + host: 'compute-1-gabbi%' + response_json_paths: + $.`len`: 2 + response_strings: + - '"project_id": "40eba01c-b348-49b8-803f-67123251a00a"' + - '"project_id": "c9a5f184-c0d0-4daa-83c3-af6fdc0879e6"' + - '"user_id": "33ba83ca-2f12-4ad6-8fa2-bc8b55d36e07"' + - '"user_id": "81d82ef3-4deb-499d-9270-9aeb5a3ec5fe"' + - '"display_name": "vm-gabbi-2"' + - '"display_name": "vm-gabbi-3"' + + - name: search for instances using complex search with "like" keyword and user_id + desc: search for vms of specified user hosted on a specific compute node + POST: /v1/search/resource/instance-like + request_headers: + content-type: application/json + data: + and: + - like: + host: 'compute-%-gabbi%' + - =: + user_id: 33ba83ca-2f12-4ad6-8fa2-bc8b55d36e07 + response_json_paths: + $.`len`: 2 + response_strings: + - '"display_name": "vm-gabbi-1"' + - '"display_name": "vm-gabbi-2"' + - '"project_id": "c9a5f184-c0d0-4daa-83c3-af6fdc0879e6"' + + - name: search for resources of instance-like or image-like type with specific user_id + desc: search for all image-like or instance-like resources created by a specific user + POST: /v1/search/resource/generic + request_headers: + content-type: application/json + data: + and: + - =: + user_id: 81d82ef3-4deb-499d-9270-9aeb5a3ec5fe + + - or: + - =: + type: instance-like + + - =: + type: image-like + status: 200 + response_json_paths: + $.`len`: 2 + response_strings: + - '"type": "image-like"' + - '"type": "instance-like"' + - '"id": "7ab2f7ae-7af5-4469-bdc8-3c0f6dfab75d"' + - '"id": "c442a47c-eb33-46ce-9665-f3aa0bef54e7"' + + # + # Tear down resources + # + + - name: helper. delete instance-like resource-1 + DELETE: /v1/resource/instance-like/a64ca14f-bc7c-45b0-aa85-42cd2179e1e2 + status: 204 + + - name: helper. delete instance-like resource-2 + DELETE: /v1/resource/instance-like/7ccccfa0-92ce-4225-80ca-3ac9cb122d6a + status: 204 + + - name: helper. delete instance-like resource-3 + DELETE: /v1/resource/instance-like/c442a47c-eb33-46ce-9665-f3aa0bef54e7 + status: 204 + + - name: helper. delete image-like resource + DELETE: /v1/resource/image-like/7ab2f7ae-7af5-4469-bdc8-3c0f6dfab75d + status: 204 + + - name: helper. delete resource-type instance-like + DELETE: /v1/resource_type/instance-like + status: 204 + + - name: helper. delete resource-type image-like + DELETE: /v1/resource_type/image-like + status: 204 + diff --git a/telemetry_tempest_plugin/gnocchi/scenario/__init__.py b/telemetry_tempest_plugin/gnocchi/scenario/__init__.py new file mode 100644 index 0000000..3ad1239 --- /dev/null +++ b/telemetry_tempest_plugin/gnocchi/scenario/__init__.py @@ -0,0 +1,110 @@ +# 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 __future__ import absolute_import + +import os +import unittest + +from gabbi import runner +from gabbi import suitemaker +from gabbi import utils +import six.moves.urllib.parse as urlparse +from tempest import config +import tempest.test + +CONF = config.CONF + +TEST_DIR = os.path.join(os.path.dirname(__file__), '..', + 'gnocchi', 'functional_live', 'gabbits') + + +class GnocchiGabbiTest(tempest.test.BaseTestCase): + credentials = ['admin'] + + TIMEOUT_SCALING_FACTOR = 5 + + @classmethod + def skip_checks(cls): + super(GnocchiGabbiTest, cls).skip_checks() + if not CONF.service_available.gnocchi: + raise cls.skipException("Gnocchi support is required") + + def _do_test(self, filename): + token = self.os_admin.auth_provider.get_token() + url = self.os_admin.auth_provider.base_url( + {'service': CONF.metric.catalog_type, + 'endpoint_type': CONF.metric.endpoint_type}) + + parsed_url = urlparse.urlsplit(url) + prefix = parsed_url.path.rstrip('/') # turn it into a prefix + if parsed_url.scheme == 'https': + port = 443 + require_ssl = True + else: + port = 80 + require_ssl = False + host = parsed_url.hostname + if parsed_url.port: + port = parsed_url.port + + os.environ["GNOCCHI_SERVICE_TOKEN"] = token + os.environ["GNOCCHI_AUTHORIZATION"] = "not used" + + with open(os.path.join(TEST_DIR, filename)) as f: + suite_dict = utils.load_yaml(f) + suite_dict.setdefault('defaults', {})['ssl'] = require_ssl + test_suite = suitemaker.test_suite_from_dict( + loader=unittest.defaultTestLoader, + test_base_name="gabbi", + suite_dict=suite_dict, + test_directory=TEST_DIR, + host=host, port=port, + fixture_module=None, + intercept=None, + prefix=prefix, + handlers=runner.initialize_handlers([]), + test_loader_name="tempest") + + # NOTE(sileht): We hide stdout/stderr and reraise the failure + # manually, tempest will print it itself. + with open(os.devnull, 'w') as stream: + result = unittest.TextTestRunner( + stream=stream, verbosity=0, failfast=True, + ).run(test_suite) + + if not result.wasSuccessful(): + failures = (result.errors + result.failures + + result.unexpectedSuccesses) + if failures: + test, bt = failures[0] + name = test.test_data.get('name', test.id()) + msg = 'From test "%s" :\n%s' % (name, bt) + self.fail(msg) + + self.assertTrue(result.wasSuccessful()) + + +def test_maker(name, filename): + def test(self): + self._do_test(filename) + test.__name__ = name + return test + + +# Create one scenario per yaml file +for filename in os.listdir(TEST_DIR): + if not filename.endswith('.yaml'): + continue + name = "test_%s" % filename[:-5].lower().replace("-", "_") + setattr(GnocchiGabbiTest, name, + test_maker(name, filename)) diff --git a/telemetry_tempest_plugin/plugin.py b/telemetry_tempest_plugin/plugin.py index 0d8fdfd..2f2861e 100644 --- a/telemetry_tempest_plugin/plugin.py +++ b/telemetry_tempest_plugin/plugin.py @@ -43,6 +43,9 @@ class TelemetryTempestPlugin(plugins.TempestPlugin): config.register_opt_group( conf, tempest_config.alarming_group, tempest_config.AlarmingGroup) + config.register_opt_group( + conf, tempest_config.metric_group, + tempest_config.metric_opts) def get_opt_lists(self): return [(tempest_config.telemetry_group.name, @@ -52,4 +55,6 @@ class TelemetryTempestPlugin(plugins.TempestPlugin): (config.service_available_group.name, tempest_config.service_option), (tempest_config.alarming_group.name, - tempest_config.AlarmingGroup)] + tempest_config.AlarmingGroup), + (tempest_config.metric_group.name, + tempest_config.metric_opts)]