Add metrics/dimensions/names into monasca-api
This endpoint will return all the dimension names for a given metric name. Added dimension-names for influx in python api and java api Added dimension-names for vertica in java api Depends-On: Id981dafd00778a6d4a376b9ceab011231e94c0c6 Change-Id: I0192ccb9276ea94103a477bd2ad7d10f21e64d31 Implements: blueprint dimensions-api
This commit is contained in:
parent
e7a7732446
commit
f26c427b4b
|
@ -22,6 +22,7 @@ alarms_count = monasca_api.v2.reference.alarms:AlarmsCount
|
|||
alarms_state_history = monasca_api.v2.reference.alarms:AlarmsStateHistory
|
||||
notification_methods = monasca_api.v2.reference.notifications:Notifications
|
||||
dimension_values = monasca_api.v2.reference.metrics:DimensionValues
|
||||
dimension_names = monasca_api.v2.reference.metrics:DimensionNames
|
||||
notification_method_types = monasca_api.v2.reference.notificationstype:NotificationsType
|
||||
|
||||
[security]
|
||||
|
|
|
@ -94,9 +94,8 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-2)
|
||||
- [Response Body](#response-body-4)
|
||||
- [Response Examples](#response-examples-3)
|
||||
- [Measurements](#measurements)
|
||||
- [List measurements](#list-measurements)
|
||||
- [GET /v2.0/metrics/measurements](#get-v20metricsmeasurements)
|
||||
- [List dimension names](#list-dimension-names)
|
||||
- [GET /v2.0/metrics/dimensions/names](#get-v20metricsdimensionsnames)
|
||||
- [Headers](#headers-5)
|
||||
- [Path Parameters](#path-parameters-5)
|
||||
- [Query Parameters](#query-parameters-5)
|
||||
|
@ -106,9 +105,9 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-3)
|
||||
- [Response Body](#response-body-5)
|
||||
- [Response Examples](#response-examples-4)
|
||||
- [Metric Names](#metric-names)
|
||||
- [List names](#list-names)
|
||||
- [GET /v2.0/metrics/names](#get-v20metricsnames)
|
||||
- [Measurements](#measurements)
|
||||
- [List measurements](#list-measurements)
|
||||
- [GET /v2.0/metrics/measurements](#get-v20metricsmeasurements)
|
||||
- [Headers](#headers-6)
|
||||
- [Path Parameters](#path-parameters-6)
|
||||
- [Query Parameters](#query-parameters-6)
|
||||
|
@ -118,9 +117,9 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-4)
|
||||
- [Response Body](#response-body-6)
|
||||
- [Response Examples](#response-examples-5)
|
||||
- [Statistics](#statistics)
|
||||
- [List statistics](#list-statistics)
|
||||
- [GET /v2.0/metrics/statistics](#get-v20metricsstatistics)
|
||||
- [Metric Names](#metric-names)
|
||||
- [List names](#list-names)
|
||||
- [GET /v2.0/metrics/names](#get-v20metricsnames)
|
||||
- [Headers](#headers-7)
|
||||
- [Path Parameters](#path-parameters-7)
|
||||
- [Query Parameters](#query-parameters-7)
|
||||
|
@ -130,9 +129,9 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-5)
|
||||
- [Response Body](#response-body-7)
|
||||
- [Response Examples](#response-examples-6)
|
||||
- [Notification Methods](#notification-methods-1)
|
||||
- [Create Notification Method](#create-notification-method)
|
||||
- [POST /v2.0/notification-methods](#post-v20notification-methods)
|
||||
- [Statistics](#statistics)
|
||||
- [List statistics](#list-statistics)
|
||||
- [GET /v2.0/metrics/statistics](#get-v20metricsstatistics)
|
||||
- [Headers](#headers-8)
|
||||
- [Path Parameters](#path-parameters-8)
|
||||
- [Query Parameters](#query-parameters-8)
|
||||
|
@ -142,8 +141,9 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-6)
|
||||
- [Response Body](#response-body-8)
|
||||
- [Response Examples](#response-examples-7)
|
||||
- [List Notification Methods](#list-notification-methods)
|
||||
- [GET /v2.0/notification-methods](#get-v20notification-methods)
|
||||
- [Notification Methods](#notification-methods-1)
|
||||
- [Create Notification Method](#create-notification-method)
|
||||
- [POST /v2.0/notification-methods](#post-v20notification-methods)
|
||||
- [Headers](#headers-9)
|
||||
- [Path Parameters](#path-parameters-9)
|
||||
- [Query Parameters](#query-parameters-9)
|
||||
|
@ -153,8 +153,8 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-7)
|
||||
- [Response Body](#response-body-9)
|
||||
- [Response Examples](#response-examples-8)
|
||||
- [Get Notification Method](#get-notification-method)
|
||||
- [GET /v2.0/notification-methods/{notification_method_id}](#get-v20notification-methodsnotification_method_id)
|
||||
- [List Notification Methods](#list-notification-methods)
|
||||
- [GET /v2.0/notification-methods](#get-v20notification-methods)
|
||||
- [Headers](#headers-10)
|
||||
- [Path Parameters](#path-parameters-10)
|
||||
- [Query Parameters](#query-parameters-10)
|
||||
|
@ -164,8 +164,8 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-8)
|
||||
- [Response Body](#response-body-10)
|
||||
- [Response Examples](#response-examples-9)
|
||||
- [Update Notification Method](#update-notification-method)
|
||||
- [PUT /v2.0/notification-methods/{notification_method_id}](#put-v20notification-methodsnotification_method_id)
|
||||
- [Get Notification Method](#get-notification-method)
|
||||
- [GET /v2.0/notification-methods/{notification_method_id}](#get-v20notification-methodsnotification_method_id)
|
||||
- [Headers](#headers-11)
|
||||
- [Path Parameters](#path-parameters-11)
|
||||
- [Query Parameters](#query-parameters-11)
|
||||
|
@ -175,8 +175,8 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-9)
|
||||
- [Response Body](#response-body-11)
|
||||
- [Response Examples](#response-examples-10)
|
||||
- [Patch Notification Method](#patch-notification-method)
|
||||
- [PATCH /v2.0/notification-methods/{notification_method_id}](#patch-v20notification-methodsnotification_method_id)
|
||||
- [Update Notification Method](#update-notification-method)
|
||||
- [PUT /v2.0/notification-methods/{notification_method_id}](#put-v20notification-methodsnotification_method_id)
|
||||
- [Headers](#headers-12)
|
||||
- [Path Parameters](#path-parameters-12)
|
||||
- [Query Parameters](#query-parameters-12)
|
||||
|
@ -186,8 +186,8 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-10)
|
||||
- [Response Body](#response-body-12)
|
||||
- [Response Examples](#response-examples-11)
|
||||
- [Delete Notification Method](#delete-notification-method)
|
||||
- [DELETE /v2.0/notification-methods/{notification_method_id}](#delete-v20notification-methodsnotification_method_id)
|
||||
- [Patch Notification Method](#patch-notification-method)
|
||||
- [PATCH /v2.0/notification-methods/{notification_method_id}](#patch-v20notification-methodsnotification_method_id)
|
||||
- [Headers](#headers-13)
|
||||
- [Path Parameters](#path-parameters-13)
|
||||
- [Query Parameters](#query-parameters-13)
|
||||
|
@ -196,21 +196,20 @@ Document Version: v2.0
|
|||
- [Response](#response-13)
|
||||
- [Status Code](#status-code-11)
|
||||
- [Response Body](#response-body-13)
|
||||
- [List supported Notification Method Types](#list-supported-notification-method-types)
|
||||
- [GET /v2.0/notification-methods/types/](#get-v20notification-methodstypes)
|
||||
- [Response Examples](#response-examples-12)
|
||||
- [Delete Notification Method](#delete-notification-method)
|
||||
- [DELETE /v2.0/notification-methods/{notification_method_id}](#delete-v20notification-methodsnotification_method_id)
|
||||
- [Headers](#headers-14)
|
||||
- [Path Parameters](#path-parameters-14)
|
||||
- [Query Parameters](#query-parameters-14)
|
||||
- [Request Body](#request-body-14)
|
||||
- [Request Examples](#request-examples-14)
|
||||
- [Response](#response-14)
|
||||
- [Status Code](#status-code-12)
|
||||
- [Response Body](#response-body-14)
|
||||
- [Response Examples](#response-examples-12)
|
||||
- [Alarm Definitions](#alarm-definitions)
|
||||
- [Create Alarm Definition](#create-alarm-definition)
|
||||
- [POST /v2.0/alarm-definitions](#post-v20alarm-definitions)
|
||||
- [List supported Notification Method Types](#list-supported-notification-method-types)
|
||||
- [GET /v2.0/notification-methods/types/](#get-v20notification-methodstypes)
|
||||
- [Headers](#headers-15)
|
||||
- [Path Parameters](#path-parameters-14)
|
||||
- [Query Parameters](#query-parameters-15)
|
||||
- [Request Body](#request-body-15)
|
||||
- [Request Examples](#request-examples-15)
|
||||
|
@ -218,8 +217,9 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-13)
|
||||
- [Response Body](#response-body-15)
|
||||
- [Response Examples](#response-examples-13)
|
||||
- [List Alarm Definitions](#list-alarm-definitions)
|
||||
- [GET /v2.0/alarm-definitions](#get-v20alarm-definitions)
|
||||
- [Alarm Definitions](#alarm-definitions)
|
||||
- [Create Alarm Definition](#create-alarm-definition)
|
||||
- [POST /v2.0/alarm-definitions](#post-v20alarm-definitions)
|
||||
- [Headers](#headers-16)
|
||||
- [Path Parameters](#path-parameters-15)
|
||||
- [Query Parameters](#query-parameters-16)
|
||||
|
@ -229,29 +229,29 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-14)
|
||||
- [Response Body](#response-body-16)
|
||||
- [Response Examples](#response-examples-14)
|
||||
- [Get Alarm Definition](#get-alarm-definition)
|
||||
- [GET /v2.0/alarm-definitions/{alarm_definition_id}](#get-v20alarm-definitionsalarm_definition_id)
|
||||
- [List Alarm Definitions](#list-alarm-definitions)
|
||||
- [GET /v2.0/alarm-definitions](#get-v20alarm-definitions)
|
||||
- [Headers](#headers-17)
|
||||
- [Path Parameters](#path-parameters-16)
|
||||
- [Query Parameters](#query-parameters-17)
|
||||
- [Request Body](#request-body-17)
|
||||
- [Request Examples](#request-examples-17)
|
||||
- [Response](#response-17)
|
||||
- [Status Code](#status-code-15)
|
||||
- [Response Body](#response-body-17)
|
||||
- [Response Examples](#response-examples-15)
|
||||
- [Update Alarm Definition](#update-alarm-definition)
|
||||
- [PUT /v2.0/alarm-definitions/{alarm_definition_id}](#put-v20alarm-definitionsalarm_definition_id)
|
||||
- [Get Alarm Definition](#get-alarm-definition)
|
||||
- [GET /v2.0/alarm-definitions/{alarm_definition_id}](#get-v20alarm-definitionsalarm_definition_id)
|
||||
- [Headers](#headers-18)
|
||||
- [Path Parameters](#path-parameters-17)
|
||||
- [Query Parameters](#query-parameters-18)
|
||||
- [Request Body](#request-body-18)
|
||||
- [Request Examples](#request-examples-17)
|
||||
- [Response](#response-18)
|
||||
- [Status Code](#status-code-16)
|
||||
- [Response Body](#response-body-18)
|
||||
- [Response Examples](#response-examples-16)
|
||||
- [Patch Alarm Definition](#patch-alarm-definition)
|
||||
- [PATCH /v2.0/alarm-definitions/{alarm_definition_id}](#patch-v20alarm-definitionsalarm_definition_id)
|
||||
- [Update Alarm Definition](#update-alarm-definition)
|
||||
- [PUT /v2.0/alarm-definitions/{alarm_definition_id}](#put-v20alarm-definitionsalarm_definition_id)
|
||||
- [Headers](#headers-19)
|
||||
- [Path Parameters](#path-parameters-18)
|
||||
- [Query Parameters](#query-parameters-19)
|
||||
|
@ -261,8 +261,8 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-17)
|
||||
- [Response Body](#response-body-19)
|
||||
- [Response Examples](#response-examples-17)
|
||||
- [Delete Alarm Definition](#delete-alarm-definition)
|
||||
- [DELETE /v2.0/alarm-definitions/{alarm_definition_id}](#delete-v20alarm-definitionsalarm_definition_id)
|
||||
- [Patch Alarm Definition](#patch-alarm-definition)
|
||||
- [PATCH /v2.0/alarm-definitions/{alarm_definition_id}](#patch-v20alarm-definitionsalarm_definition_id)
|
||||
- [Headers](#headers-20)
|
||||
- [Path Parameters](#path-parameters-19)
|
||||
- [Query Parameters](#query-parameters-20)
|
||||
|
@ -271,9 +271,9 @@ Document Version: v2.0
|
|||
- [Response](#response-20)
|
||||
- [Status Code](#status-code-18)
|
||||
- [Response Body](#response-body-20)
|
||||
- [Alarms](#alarms)
|
||||
- [List Alarms](#list-alarms)
|
||||
- [GET /v2.0/alarms](#get-v20alarms)
|
||||
- [Response Examples](#response-examples-18)
|
||||
- [Delete Alarm Definition](#delete-alarm-definition)
|
||||
- [DELETE /v2.0/alarm-definitions/{alarm_definition_id}](#delete-v20alarm-definitionsalarm_definition_id)
|
||||
- [Headers](#headers-21)
|
||||
- [Path Parameters](#path-parameters-20)
|
||||
- [Query Parameters](#query-parameters-21)
|
||||
|
@ -282,19 +282,20 @@ Document Version: v2.0
|
|||
- [Response](#response-21)
|
||||
- [Status Code](#status-code-19)
|
||||
- [Response Body](#response-body-21)
|
||||
- [Response Examples](#response-examples-18)
|
||||
- [List Alarms State History](#list-alarms-state-history)
|
||||
- [GET /v2.0/alarms/state-history](#get-v20alarmsstate-history)
|
||||
- [Alarms](#alarms)
|
||||
- [List Alarms](#list-alarms)
|
||||
- [GET /v2.0/alarms](#get-v20alarms)
|
||||
- [Headers](#headers-22)
|
||||
- [Path Parameters](#path-parameters-21)
|
||||
- [Query Parameters](#query-parameters-22)
|
||||
- [Request Body](#request-body-22)
|
||||
- [Request Examples](#request-examples-21)
|
||||
- [Response](#response-22)
|
||||
- [Status Code](#status-code-20)
|
||||
- [Response Body](#response-body-22)
|
||||
- [Response Examples](#response-examples-19)
|
||||
- [Get Alarm](#get-alarm)
|
||||
- [GET /v2.0/alarms/{alarm_id}](#get-v20alarmsalarm_id)
|
||||
- [List Alarms State History](#list-alarms-state-history)
|
||||
- [GET /v2.0/alarms/state-history](#get-v20alarmsstate-history)
|
||||
- [Headers](#headers-23)
|
||||
- [Path Parameters](#path-parameters-22)
|
||||
- [Query Parameters](#query-parameters-23)
|
||||
|
@ -303,19 +304,18 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-21)
|
||||
- [Response Body](#response-body-23)
|
||||
- [Response Examples](#response-examples-20)
|
||||
- [Update Alarm](#update-alarm)
|
||||
- [PUT /v2.0/alarms/{alarm_id}](#put-v20alarmsalarm_id)
|
||||
- [Get Alarm](#get-alarm)
|
||||
- [GET /v2.0/alarms/{alarm_id}](#get-v20alarmsalarm_id)
|
||||
- [Headers](#headers-24)
|
||||
- [Path Parameters](#path-parameters-23)
|
||||
- [Query Parameters](#query-parameters-24)
|
||||
- [Request Body](#request-body-24)
|
||||
- [Request Examples](#request-examples-21)
|
||||
- [Response](#response-24)
|
||||
- [Status Code](#status-code-22)
|
||||
- [Response Body](#response-body-24)
|
||||
- [Response Examples](#response-examples-21)
|
||||
- [Patch Alarm](#patch-alarm)
|
||||
- [PATCH /v2.0/alarms/{alarm_id}](#patch-v20alarmsalarm_id)
|
||||
- [Update Alarm](#update-alarm)
|
||||
- [PUT /v2.0/alarms/{alarm_id}](#put-v20alarmsalarm_id)
|
||||
- [Headers](#headers-25)
|
||||
- [Path Parameters](#path-parameters-24)
|
||||
- [Query Parameters](#query-parameters-25)
|
||||
|
@ -325,8 +325,8 @@ Document Version: v2.0
|
|||
- [Status Code](#status-code-23)
|
||||
- [Response Body](#response-body-25)
|
||||
- [Response Examples](#response-examples-22)
|
||||
- [Delete Alarm](#delete-alarm)
|
||||
- [DELETE /v2.0/alarms/{alarm_id}](#delete-v20alarmsalarm_id)
|
||||
- [Patch Alarm](#patch-alarm)
|
||||
- [PATCH /v2.0/alarms/{alarm_id}](#patch-v20alarmsalarm_id)
|
||||
- [Headers](#headers-26)
|
||||
- [Path Parameters](#path-parameters-25)
|
||||
- [Query Parameters](#query-parameters-26)
|
||||
|
@ -335,17 +335,28 @@ Document Version: v2.0
|
|||
- [Response](#response-26)
|
||||
- [Status Code](#status-code-24)
|
||||
- [Response Body](#response-body-26)
|
||||
- [List Alarm State History](#list-alarm-state-history)
|
||||
- [GET /v2.0/alarms/{alarm_id}/state-history](#get-v20alarmsalarm_idstate-history)
|
||||
- [Response Examples](#response-examples-23)
|
||||
- [Delete Alarm](#delete-alarm)
|
||||
- [DELETE /v2.0/alarms/{alarm_id}](#delete-v20alarmsalarm_id)
|
||||
- [Headers](#headers-27)
|
||||
- [Path Parameters](#path-parameters-26)
|
||||
- [Query Parameters](#query-parameters-27)
|
||||
- [Request Body](#request-body-27)
|
||||
- [Request Data](#request-data)
|
||||
- [Request Examples](#request-examples-24)
|
||||
- [Response](#response-27)
|
||||
- [Status Code](#status-code-25)
|
||||
- [Response Body](#response-body-27)
|
||||
- [Response Examples](#response-examples-23)
|
||||
- [List Alarm State History](#list-alarm-state-history)
|
||||
- [GET /v2.0/alarms/{alarm_id}/state-history](#get-v20alarmsalarm_idstate-history)
|
||||
- [Headers](#headers-28)
|
||||
- [Path Parameters](#path-parameters-27)
|
||||
- [Query Parameters](#query-parameters-28)
|
||||
- [Request Body](#request-body-28)
|
||||
- [Request Data](#request-data)
|
||||
- [Response](#response-28)
|
||||
- [Status Code](#status-code-26)
|
||||
- [Response Body](#response-body-28)
|
||||
- [Response Examples](#response-examples-24)
|
||||
- [License](#license)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
@ -1194,40 +1205,93 @@ Cache-Control: no-cache
|
|||
* 200 - OK
|
||||
|
||||
#### Response Body
|
||||
Returns a JSON object with a 'links' array of links and an 'elements' array of metric definition objects with the following fields:
|
||||
|
||||
* dimension_name (string)
|
||||
* metric_name (string)
|
||||
* values (list of strings)
|
||||
Returns a JSON object with a 'links' array of links and an 'elements' array of dimension values.
|
||||
|
||||
#### Response Examples
|
||||
````
|
||||
{
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://192.168.10.4:8080/v2.0/metrics/dimensions/names/values?dimension_name=dimension_name"
|
||||
},
|
||||
{
|
||||
"rel": "next",
|
||||
"href": "http://192.168.10.4:8080/v2.0/metrics/dimensions/names/values?dimension_name=dimension_name&offset=dimensionValue2"
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": "b63d9bc1e16582d0ca039616ce3c870556b3095b",
|
||||
"metric_name": "metric_name",
|
||||
"dimension_name": "dimension_name",
|
||||
"values": [
|
||||
"dimensonValue1",
|
||||
"dimensonValue2"
|
||||
]
|
||||
}
|
||||
]
|
||||
"elements": [
|
||||
{
|
||||
"dimension_value": "value2"
|
||||
},
|
||||
{
|
||||
"dimension_value": "value3"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"href": "http://192.168.10.6:8070/v2.0/metrics/dimensions/names/values?dimension_name=dim_name&offset=value1&limit=2",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://192.168.10.6:8070/v2.0/metrics/dimensions/names/values?offset=value3&dimension_name=dim_name&limit=2",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
||||
````
|
||||
___
|
||||
|
||||
## List dimension names
|
||||
Get dimension names
|
||||
|
||||
#### GET /v2.0/metrics/dimensions/names
|
||||
|
||||
#### Headers
|
||||
* X-Auth-Token (string, required) - Keystone auth token
|
||||
* Accept (string) - application/json
|
||||
|
||||
#### Path Parameters
|
||||
None.
|
||||
|
||||
#### Query Parameters
|
||||
* tenant_id (string, optional, restricted) - Tenant ID from which to get dimension names. This parameter can be used to get dimension names from a tenant other than the tenant the request auth token is scoped to. Usage of this query parameter is restricted to users with the monasca admin role, as defined in the monasca api configuration file, which defaults to `monasca-admin`.
|
||||
* metric_name (string(255), optional) - A metric name to filter dimension names by.
|
||||
* offset (string(255), optional) - The dimension names are returned in alphabetic order, and the offset is the dimension name after which will return in the next pagination request.
|
||||
* limit (integer, optional)
|
||||
|
||||
#### Request Body
|
||||
None.
|
||||
|
||||
#### Request Examples
|
||||
```
|
||||
GET /v2.0/metrics/dimensions/names HTTP/1.1
|
||||
Host: 192.168.10.6:8070
|
||||
Content-Type: application/json
|
||||
X-Auth-Token: 818d3d8f10bd4987adb3f84bc94a801d
|
||||
Cache-Control: no-cache
|
||||
```
|
||||
|
||||
### Response
|
||||
#### Status Code
|
||||
* 200 - OK
|
||||
|
||||
#### Response Body
|
||||
Returns a JSON object with a 'links' array of links and an 'elements' array of dimension names.
|
||||
#### Response Examples
|
||||
````
|
||||
{
|
||||
"elements": [
|
||||
{
|
||||
"dimension_name": "name2"
|
||||
},
|
||||
{
|
||||
"dimension_name": "name3"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"href": "http://192.168.10.6:8070/v2.0/metrics/dimensions/names?offset=name1&limit=2",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://192.168.10.6:8070/v2.0/metrics/dimensions/names?offset=name3&limit=2",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
||||
````
|
||||
|
||||
# Measurements
|
||||
Operations for accessing measurements of metrics.
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ alarms_count = monasca_api.v2.reference.alarms:AlarmsCount
|
|||
alarms_state_history = monasca_api.v2.reference.alarms:AlarmsStateHistory
|
||||
notification_methods = monasca_api.v2.reference.notifications:Notifications
|
||||
dimension_values = monasca_api.v2.reference.metrics:DimensionValues
|
||||
dimension_names = monasca_api.v2.reference.metrics:DimensionNames
|
||||
notification_method_types = monasca_api.v2.reference.notificationstype:NotificationsType
|
||||
|
||||
[security]
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.dimension;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
|
||||
/**
|
||||
* Base class for DimensionNames and DimensionValues.
|
||||
*/
|
||||
public abstract class DimensionBase extends AbstractEntity {
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
final private String metricName;
|
||||
final private String id;
|
||||
|
||||
public DimensionBase(String metricName, String id) {
|
||||
this.metricName = metricName;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getMetricName() {
|
||||
return metricName;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
DimensionBase other = (DimensionBase) obj;
|
||||
if (metricName == null) {
|
||||
if (other.getMetricName() != null)
|
||||
return false;
|
||||
} else if (!metricName.equals(other.getMetricName()))
|
||||
return false;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 17;
|
||||
result = prime * result + ((metricName == null) ? 0 : metricName.hashCode());
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.dimension;
|
||||
|
||||
/**
|
||||
* Encapsulates dimension name for an optional metric name.
|
||||
*/
|
||||
public class DimensionName extends DimensionBase {
|
||||
final private String dimensionName;
|
||||
|
||||
public DimensionName(String metricName, String dimensionName) {
|
||||
super(metricName, dimensionName);
|
||||
this.dimensionName = dimensionName;
|
||||
}
|
||||
|
||||
public String getDimensionName() {
|
||||
return dimensionName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
DimensionName other = (DimensionName) obj;
|
||||
if (dimensionName == null) {
|
||||
if (other.dimensionName != null)
|
||||
return false;
|
||||
} else if (!dimensionName.equals(other.dimensionName))
|
||||
return false;
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((dimensionName == null) ? 0 : dimensionName.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("DimensionName: MetricName=%s DimensionName [names=%s]",
|
||||
getMetricName(), dimensionName);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Hewlett-Packard Development Company, L.P.
|
||||
* (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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
|
||||
|
@ -13,10 +13,10 @@
|
|||
*/
|
||||
package monasca.api.domain.model.dimension;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository for dimensions.
|
||||
*/
|
||||
|
@ -25,10 +25,19 @@ public interface DimensionRepo {
|
|||
* Finds dimension values given a dimension name and
|
||||
* optional metric name.
|
||||
*/
|
||||
DimensionValues find(String metricName,
|
||||
String tenantId,
|
||||
String dimensionName,
|
||||
@Nullable String offset,
|
||||
int limit)
|
||||
List<DimensionValue> findValues(String metricName,
|
||||
String tenantId,
|
||||
String dimensionName,
|
||||
@Nullable String offset,
|
||||
int limit)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Finds dimension names given an optional metric name.
|
||||
*/
|
||||
List<DimensionName> findNames(String metricName,
|
||||
String tenantId,
|
||||
@Nullable String offset,
|
||||
int limit)
|
||||
throws Exception;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.dimension;
|
||||
|
||||
/**
|
||||
* Encapsulates dimension value for a given dimension name
|
||||
* (and optional metric-name).
|
||||
*/
|
||||
public class DimensionValue extends DimensionBase {
|
||||
|
||||
final private String dimensionName;
|
||||
final private String dimensionValue;
|
||||
|
||||
public DimensionValue(String metricName, String dimensionName, String dimensionValue) {
|
||||
super(metricName, dimensionValue);
|
||||
this.dimensionName = dimensionName;
|
||||
this.dimensionValue = dimensionValue;
|
||||
}
|
||||
|
||||
public String getDimensionValue() {
|
||||
return dimensionValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
DimensionValue other = (DimensionValue) obj;
|
||||
if (dimensionName == null) {
|
||||
if (other.dimensionName != null)
|
||||
return false;
|
||||
} else if (!dimensionName.equals(other.dimensionName))
|
||||
return false;
|
||||
if (dimensionValue == null) {
|
||||
if (other.dimensionValue != null)
|
||||
return false;
|
||||
} else if (!dimensionValue.equals(other.dimensionValue))
|
||||
return false;
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((dimensionName == null) ? 0 : dimensionName.hashCode());
|
||||
result = prime * result + ((dimensionValue == null) ? 0 : dimensionValue.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("DimensionValue: MetricName=%s DimensionValue [name=%s, values=%s]",
|
||||
getMetricName(), dimensionName, dimensionValue);
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.dimension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
/**
|
||||
* Encapsulates the list of dimension values for a given dimension name
|
||||
* (and optional metric-name).
|
||||
*/
|
||||
public class DimensionValues extends AbstractEntity {
|
||||
|
||||
protected String id = null;
|
||||
protected String dimensionName;
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
protected String metricName;
|
||||
protected List<String> values;
|
||||
protected Map<String, List<String>> dimensionValues;
|
||||
|
||||
public DimensionValues() {
|
||||
this.values = new ArrayList<String>();
|
||||
this.dimensionValues = new HashMap<String, List<String>>();
|
||||
}
|
||||
|
||||
public DimensionValues(String metricName, String dimensionName, List<String> values) {
|
||||
this.metricName = metricName;
|
||||
this.dimensionName = dimensionName;
|
||||
this.values = values;
|
||||
this.dimensionValues = new HashMap<String, List<String>>();
|
||||
this.dimensionValues.put(dimensionName, values);
|
||||
this.id = generateId();
|
||||
}
|
||||
|
||||
public List<String> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
public String getDimensionName() {
|
||||
return dimensionName;
|
||||
}
|
||||
|
||||
public String getMetricName() {
|
||||
return metricName;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
if (null == this.id) {
|
||||
this.id = generateId();
|
||||
}
|
||||
return this.id;
|
||||
}
|
||||
|
||||
private String generateId() {
|
||||
String hashstr = "metricName=" + metricName + "dimensionName=" + dimensionName;
|
||||
byte[] sha1Hash = DigestUtils.sha(hashstr);
|
||||
return Hex.encodeHexString(sha1Hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
DimensionValues other = (DimensionValues) obj;
|
||||
if (dimensionName == null) {
|
||||
if (other.dimensionName != null)
|
||||
return false;
|
||||
} else if (!dimensionName.equals(other.dimensionName))
|
||||
return false;
|
||||
if (metricName == null) {
|
||||
if (other.metricName != null)
|
||||
return false;
|
||||
} else if (!metricName.equals(other.metricName))
|
||||
return false;
|
||||
if (values == null) {
|
||||
if (other.values != null)
|
||||
return false;
|
||||
} else if (!values.equals(other.values))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((dimensionName == null) ? 0 : dimensionName.hashCode());
|
||||
result = prime * result + ((metricName == null) ? 0 : metricName.hashCode());
|
||||
result = prime * result + ((values == null) ? 0 : values.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("MetricName=%s DimensionValues [name=%s, values=%s]",
|
||||
metricName, dimensionName, values);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Hewlett-Packard Development Company, L.P.
|
||||
* (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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
|
||||
|
@ -14,21 +14,21 @@
|
|||
package monasca.api.infrastructure.persistence.influxdb;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Set;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.domain.model.dimension.DimensionValues;
|
||||
import monasca.api.domain.model.dimension.DimensionName;
|
||||
import monasca.api.domain.model.dimension.DimensionValue;
|
||||
import monasca.api.domain.model.dimension.DimensionRepo;
|
||||
|
||||
|
||||
|
@ -54,7 +54,7 @@ public class InfluxV9DimensionRepo implements DimensionRepo {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DimensionValues find(
|
||||
public List<DimensionValue> findValues(
|
||||
String metricName,
|
||||
String tenantId,
|
||||
String dimensionName,
|
||||
|
@ -65,6 +65,7 @@ public class InfluxV9DimensionRepo implements DimensionRepo {
|
|||
// Use treeset to keep list in alphabetic/predictable order
|
||||
// for string based offset.
|
||||
//
|
||||
List<DimensionValue> dimensionValueList = new ArrayList<>();
|
||||
Set<String> matchingValues = new TreeSet<String>();
|
||||
String dimNamePart = "and \""
|
||||
+ this.influxV9Utils.sanitize(dimensionName)
|
||||
|
@ -93,19 +94,22 @@ public class InfluxV9DimensionRepo implements DimensionRepo {
|
|||
}
|
||||
|
||||
List<String> filteredValues = filterDimensionValues(matchingValues,
|
||||
dimensionName,
|
||||
limit,
|
||||
offset);
|
||||
|
||||
return new DimensionValues(metricName, dimensionName, filteredValues);
|
||||
for (String filteredValue : filteredValues) {
|
||||
DimensionValue dimValue = new DimensionValue(metricName, dimensionName, filteredValue);
|
||||
dimensionValueList.add(dimValue);
|
||||
}
|
||||
|
||||
return dimensionValueList;
|
||||
}
|
||||
|
||||
private List<String> filterDimensionValues(Set<String> matchingValues,
|
||||
String dimensionName,
|
||||
int limit,
|
||||
String offset)
|
||||
{
|
||||
Boolean haveOffset = (null != offset && !"".equals(offset));
|
||||
Boolean haveOffset = !Strings.isNullOrEmpty(offset);
|
||||
List<String> filteredValues = new ArrayList<String>();
|
||||
int remaining_limit = limit + 1;
|
||||
|
||||
|
@ -122,4 +126,68 @@ public class InfluxV9DimensionRepo implements DimensionRepo {
|
|||
|
||||
return filteredValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DimensionName> findNames(
|
||||
String metricName,
|
||||
String tenantId,
|
||||
String offset,
|
||||
int limit) throws Exception
|
||||
{
|
||||
//
|
||||
// Use treeset to keep list in alphabetic/predictable order
|
||||
// for string based offset.
|
||||
//
|
||||
List<DimensionName> dimensionNameList = new ArrayList<>();
|
||||
Set<String> matchingNames = new TreeSet<String>();
|
||||
|
||||
String q = String.format("show series %1$s where %2$s",
|
||||
this.influxV9Utils.namePart(metricName, false),
|
||||
this.influxV9Utils.privateTenantIdPart(tenantId));
|
||||
|
||||
logger.debug("Dimension names query: {}", q);
|
||||
String r = this.influxV9RepoReader.read(q);
|
||||
Series series = this.objectMapper.readValue(r, Series.class);
|
||||
|
||||
if (!series.isEmpty()) {
|
||||
for (Serie serie : series.getSeries()) {
|
||||
for (String[] names : serie.getValues()) {
|
||||
Map<String, String> dimensions = this.influxV9Utils.getDimensions(names, serie.getColumns());
|
||||
for (Map.Entry<String, String> entry : dimensions.entrySet()) {
|
||||
matchingNames.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> filteredNames = filterDimensionNames(matchingNames, limit, offset);
|
||||
|
||||
for (String filteredName : filteredNames) {
|
||||
DimensionName dimName = new DimensionName(metricName, filteredName);
|
||||
dimensionNameList.add(dimName);
|
||||
}
|
||||
|
||||
return dimensionNameList;
|
||||
}
|
||||
|
||||
private List<String> filterDimensionNames(Set<String> matchingNames,
|
||||
int limit,
|
||||
String offset) {
|
||||
Boolean haveOffset = !Strings.isNullOrEmpty(offset);
|
||||
List<String> filteredNames = new ArrayList<String>();
|
||||
int remaining_limit = limit + 1;
|
||||
|
||||
for (String dimName : matchingNames) {
|
||||
if (remaining_limit <= 0) {
|
||||
break;
|
||||
}
|
||||
if (haveOffset && dimName.compareTo(offset) <= 0) {
|
||||
continue;
|
||||
}
|
||||
filteredNames.add(dimName);
|
||||
remaining_limit--;
|
||||
}
|
||||
|
||||
return filteredNames;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2016 Hewlett-Packard Development Company, L.P.
|
||||
/* (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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
|
||||
|
@ -13,16 +13,17 @@
|
|||
package monasca.api.infrastructure.persistence.vertica;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.domain.model.dimension.DimensionName;
|
||||
import monasca.api.domain.model.dimension.DimensionRepo;
|
||||
import monasca.api.domain.model.dimension.DimensionValues;
|
||||
import monasca.api.domain.model.dimension.DimensionValue;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
|
@ -53,6 +54,23 @@ public class DimensionVerticaRepoImpl implements DimensionRepo {
|
|||
+ "ORDER BY dims.value ASC "
|
||||
+ "%s "; // limit goes here
|
||||
|
||||
private static final String FIND_DIMENSION_NAMES_SQL =
|
||||
"SELECT %s" // dbHint goes here
|
||||
+ " DISTINCT dims.name as dName "
|
||||
+ "FROM "
|
||||
+ " MonMetrics.Definitions def,"
|
||||
+ " MonMetrics.DefinitionDimensions defdims "
|
||||
+ "LEFT OUTER JOIN"
|
||||
+ " MonMetrics.Dimensions dims"
|
||||
+ " ON dims.dimension_set_id = defdims.dimension_set_id "
|
||||
+ "WHERE "
|
||||
+ " def.id = defdims.definition_id"
|
||||
+ " %s " // optional offset goes here
|
||||
+ " %s " // metric name goes here
|
||||
+ " and def.tenant_id = '%s' " // tenant_id goes here
|
||||
+ "ORDER BY dims.name ASC "
|
||||
+ "%s "; // limit goes here
|
||||
|
||||
private final DBI db;
|
||||
private final String dbHint;
|
||||
|
||||
|
@ -65,25 +83,24 @@ public class DimensionVerticaRepoImpl implements DimensionRepo {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DimensionValues find(
|
||||
public List<DimensionValue> findValues(
|
||||
String metricName,
|
||||
String tenantId,
|
||||
String dimensionName,
|
||||
String offset,
|
||||
int limit) throws Exception
|
||||
{
|
||||
List<String> values = new ArrayList<String>();
|
||||
String offsetPart = "";
|
||||
String metricNamePart = "";
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
|
||||
if (offset != null && !offset.isEmpty()) {
|
||||
offsetPart = " and dims.value > '" + offset + "' ";
|
||||
offsetPart = " and dims.value > :offset";
|
||||
}
|
||||
|
||||
if (metricName != null && !metricName.isEmpty()) {
|
||||
metricNamePart = " and def.name = '" + metricName + "' ";
|
||||
metricNamePart = " and def.name = :metricName";
|
||||
}
|
||||
|
||||
String limitPart = " limit " + Integer.toString(limit + 1);
|
||||
|
@ -98,12 +115,82 @@ public class DimensionVerticaRepoImpl implements DimensionRepo {
|
|||
|
||||
Query<Map<String, Object>> query = h.createQuery(sql);
|
||||
|
||||
List<Map<String, Object>> rows = query.list();
|
||||
for (Map<String, Object> row : rows) {
|
||||
String dimValue = (String) row.get("dValue");
|
||||
values.add(dimValue);
|
||||
|
||||
if (!Strings.isNullOrEmpty(offset)) {
|
||||
logger.debug("binding offset: {}", offset);
|
||||
query.bind("offset", offset);
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(metricName)) {
|
||||
logger.debug("binding metricName: {}", metricName);
|
||||
query.bind("metricName", metricName);
|
||||
}
|
||||
|
||||
List<Map<String, Object>> rows = query.list();
|
||||
|
||||
List<DimensionValue> dimensionValuesList = new ArrayList<>(rows.size());
|
||||
|
||||
for (Map<String, Object> row : rows) {
|
||||
String dimensionValue = (String) row.get("dValue");
|
||||
DimensionValue dimValue = new DimensionValue(metricName, dimensionName, dimensionValue);
|
||||
dimensionValuesList.add(dimValue);
|
||||
}
|
||||
return dimensionValuesList;
|
||||
}
|
||||
return new DimensionValues(metricName, dimensionName, values);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DimensionName> findNames(
|
||||
String metricName,
|
||||
String tenantId,
|
||||
String offset,
|
||||
int limit) throws Exception
|
||||
{
|
||||
String offsetPart = "";
|
||||
String metricNamePart = "";
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
|
||||
if (!Strings.isNullOrEmpty(offset)) {
|
||||
offsetPart = " and dims.name > :offset";
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(metricName)) {
|
||||
metricNamePart = " and def.name = :metricName";
|
||||
}
|
||||
|
||||
String limitPart = " limit " + Integer.toString(limit + 1);
|
||||
|
||||
String sql = String.format(FIND_DIMENSION_NAMES_SQL,
|
||||
this.dbHint,
|
||||
offsetPart,
|
||||
metricNamePart,
|
||||
tenantId,
|
||||
limitPart);
|
||||
|
||||
Query<Map<String, Object>> query = h.createQuery(sql);
|
||||
|
||||
if (!Strings.isNullOrEmpty(offset)) {
|
||||
logger.debug("binding offset: {}", offset);
|
||||
query.bind("offset", offset);
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(metricName)) {
|
||||
logger.debug("binding metricName: {}", metricName);
|
||||
query.bind("metricName", metricName);
|
||||
}
|
||||
|
||||
List<Map<String, Object>> rows = query.list();
|
||||
List<DimensionName> dimensionNamesList = new ArrayList<>(rows.size());
|
||||
|
||||
for (Map<String, Object> row : rows) {
|
||||
String dimensionName = (String) row.get("dName");
|
||||
DimensionName dimName = new DimensionName(metricName, dimensionName);
|
||||
dimensionNamesList.add(dimName);
|
||||
}
|
||||
return dimensionNamesList;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Hewlett-Packard Development Company, L.P.
|
||||
* (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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
|
||||
|
@ -15,12 +15,10 @@ package monasca.api.resource;
|
|||
|
||||
import static monasca.api.app.validation.Validation.DEFAULT_ADMIN_ROLE;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
|
@ -32,35 +30,36 @@ import javax.ws.rs.core.Context;
|
|||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import monasca.api.app.validation.MetricNameValidation;
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.app.validation.Validation;
|
||||
import monasca.api.domain.model.dimension.DimensionName;
|
||||
import monasca.api.domain.model.dimension.DimensionRepo;
|
||||
import monasca.api.domain.model.dimension.DimensionValues;
|
||||
import monasca.api.domain.model.dimension.DimensionValue;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
|
||||
/**
|
||||
* Dimension resource implementation.
|
||||
*/
|
||||
@Path("/v2.0/metrics/dimensions/names/values")
|
||||
@Path("/v2.0/metrics/dimensions")
|
||||
public class DimensionResource {
|
||||
|
||||
private final DimensionRepo repo;
|
||||
private final PersistUtils persistUtils;
|
||||
private final String admin_role;
|
||||
private final String adminRole;
|
||||
|
||||
@Inject
|
||||
public DimensionResource(ApiConfig config, DimensionRepo repo, PersistUtils persistUtils) {
|
||||
this.admin_role = (config.middleware == null || config.middleware.adminRole == null)
|
||||
this.adminRole = (config.middleware == null || config.middleware.adminRole == null)
|
||||
? DEFAULT_ADMIN_ROLE : config.middleware.adminRole;
|
||||
this.repo = repo;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/names/values")
|
||||
@Timed
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object get(
|
||||
public Object getDimensionValues(
|
||||
@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@HeaderParam("X-Roles") String roles,
|
||||
|
@ -71,9 +70,28 @@ public class DimensionResource {
|
|||
@QueryParam("tenant_id") String crossTenantId) throws Exception
|
||||
{
|
||||
Validation.validateNotNullOrEmpty(dimensionName, "dimension_name");
|
||||
final int pagingLimit = this.persistUtils.getLimit(limit);
|
||||
String queryTenantId = Validation.getQueryProject(roles, crossTenantId, tenantId, adminRole);
|
||||
List<DimensionValue> dimValues = repo.findValues(metricName, queryTenantId, dimensionName, offset, pagingLimit);
|
||||
return Links.paginate(pagingLimit, dimValues, uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/names")
|
||||
@Timed
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object getDimensionNames(
|
||||
@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@HeaderParam("X-Roles") String roles,
|
||||
@QueryParam("limit") String limit,
|
||||
@QueryParam("metric_name") String metricName,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("tenant_id") String crossTenantId) throws Exception
|
||||
{
|
||||
final int paging_limit = this.persistUtils.getLimit(limit);
|
||||
String queryTenantId = Validation.getQueryProject(roles, crossTenantId, tenantId, admin_role);
|
||||
DimensionValues dimVals = repo.find(metricName, queryTenantId, dimensionName, offset, paging_limit);
|
||||
return Links.paginateDimensionValues(dimVals, paging_limit, uriInfo);
|
||||
String queryTenantId = Validation.getQueryProject(roles, crossTenantId, tenantId, adminRole);
|
||||
List<DimensionName> dimNames = repo.findNames(metricName, queryTenantId, offset, paging_limit);
|
||||
return Links.paginate(paging_limit, dimNames, uriInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* (C) Copyright 2014-2016 Hewlett Packard Enterprise Development Company LP
|
||||
* (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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
|
||||
|
@ -26,7 +26,7 @@ import com.google.common.base.Preconditions;
|
|||
import monasca.api.ApiConfig;
|
||||
import monasca.api.domain.model.alarm.AlarmCount;
|
||||
import monasca.api.domain.model.common.Paged;
|
||||
import monasca.api.domain.model.dimension.DimensionValues;
|
||||
import monasca.api.domain.model.dimension.DimensionBase;
|
||||
import monasca.api.domain.model.measurement.Measurements;
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
import monasca.api.domain.model.common.Link;
|
||||
|
@ -360,21 +360,4 @@ public final class Links {
|
|||
alarmCount.setLinks(links);
|
||||
}
|
||||
|
||||
public static Paged paginateDimensionValues(DimensionValues dimVals, int limit, UriInfo uriInfo)
|
||||
throws UnsupportedEncodingException {
|
||||
Paged paged = new Paged();
|
||||
List<DimensionValues> elements = new ArrayList<DimensionValues>();
|
||||
paged.links.add(getSelfLink(uriInfo));
|
||||
|
||||
if ((null != dimVals) && (dimVals.getValues().size() > limit)) {
|
||||
dimVals.getValues().remove(dimVals.getValues().size()-1);
|
||||
String offset = dimVals.getValues().get(dimVals.getValues().size()-1);
|
||||
paged.links.add(getNextLink(offset, uriInfo));
|
||||
}
|
||||
|
||||
elements.add(dimVals);
|
||||
paged.elements = elements;
|
||||
return paged;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Hewlett-Packard Development Company, L.P.
|
||||
* (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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
|
||||
|
@ -14,18 +14,11 @@
|
|||
|
||||
package monasca.api.resource;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
|
@ -49,23 +42,32 @@ public class DimensionResourceTest extends AbstractMonApiResourceTest {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldQueryWithDefaultParams() throws Exception {
|
||||
public void shouldQueryDimensionValuesWithDefaultParams() throws Exception {
|
||||
|
||||
client()
|
||||
.resource(
|
||||
"/v2.0/metrics/dimensions/names/values?dimension_name=hpcs.compute")
|
||||
.header("X-Tenant-Id", "abc").get(ClientResponse.class);
|
||||
verify(dimensionRepo).find(anyString(), anyString(), anyString(), anyString(),
|
||||
verify(dimensionRepo).findValues(anyString(), anyString(), anyString(), anyString(),
|
||||
anyInt());
|
||||
}
|
||||
|
||||
public void shouldQueryWithOptionalMetricName() throws Exception {
|
||||
public void shouldQueryDimensionValuesWithOptionalMetricName() throws Exception {
|
||||
|
||||
client()
|
||||
.resource(
|
||||
"/v2.0/metrics/dimensions/names/values?dimension_name=hpcs.compute&metric_name=cpu_utilization")
|
||||
.header("X-Tenant-Id", "abc").get(ClientResponse.class);
|
||||
verify(dimensionRepo).find(anyString(), anyString(), anyString(), anyString(),
|
||||
verify(dimensionRepo).findValues(anyString(), anyString(), anyString(), anyString(),
|
||||
anyInt());
|
||||
}
|
||||
|
||||
public void shouldQueryDimensionNamesWithDefaultParams() throws Exception {
|
||||
|
||||
client()
|
||||
.resource(
|
||||
"/v2.0/metrics/dimensions/names")
|
||||
.header("X-Tenant-Id", "abc").get(ClientResponse.class);
|
||||
verify(dimensionRepo).findNames(anyString(), anyString(), anyString(), anyInt());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* (C) Copyright 2015-2016 Hewlett Packard Enterprise Development Company LP
|
||||
* (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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
|
||||
|
@ -18,7 +18,6 @@ import monasca.api.domain.model.alarm.Alarm;
|
|||
import monasca.api.domain.model.common.Link;
|
||||
import monasca.api.domain.model.common.Paged;
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
import monasca.api.domain.model.dimension.DimensionValues;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
@ -135,49 +134,4 @@ public class LinksTest {
|
|||
+ ALARM_DEF_ID));
|
||||
}
|
||||
|
||||
public void verifyPaginateDimensionValues() throws UnsupportedEncodingException, URISyntaxException{
|
||||
final String base = "http://TheVip:8070/v2.0/metrics/dimensions/names/values";
|
||||
final String limitParam = "limit=1";
|
||||
final String url = base + "?" + limitParam;
|
||||
final UriInfo uriInfo = mock(UriInfo.class);
|
||||
when(uriInfo.getRequestUri()).thenReturn(new URI(url));
|
||||
when(uriInfo.getAbsolutePath()).thenReturn(new URI(base));
|
||||
|
||||
final Map<String, String> params = new HashMap<>();
|
||||
params.put("limit", "1");
|
||||
@SuppressWarnings("unchecked")
|
||||
final MultivaluedMap<String, String> mockParams = mock(MultivaluedMap.class);
|
||||
when(uriInfo.getQueryParameters()).thenReturn(mockParams);
|
||||
when(mockParams.keySet()).thenReturn(params.keySet());
|
||||
when(mockParams.get("limit")).thenReturn(Arrays.asList("1"));
|
||||
|
||||
List<String> values = new ArrayList<String>();
|
||||
values.add("value1");
|
||||
values.add("value2");
|
||||
List<String> oneValue = Arrays.asList("value1");
|
||||
|
||||
DimensionValues dimVals = new DimensionValues("custom_metric",
|
||||
"dimension_name",
|
||||
values);
|
||||
|
||||
DimensionValues expectedDimVal = new DimensionValues("custom_metric",
|
||||
"dimension_name",
|
||||
oneValue);
|
||||
final int limit = 1;
|
||||
final Paged expected = new Paged();
|
||||
final List<Link> links = new ArrayList<>();
|
||||
String expectedSelf = url;
|
||||
String expectedNext = base + "?offset=value1&" + limitParam;
|
||||
links.add(new Link("self", expectedSelf));
|
||||
links.add(new Link("next", expectedNext));
|
||||
expected.links = links;
|
||||
|
||||
final ArrayList<DimensionValues> expectedElements = new ArrayList<DimensionValues>();
|
||||
// Since limit is one, only the first element is returned
|
||||
expectedElements.add(expectedDimVal);
|
||||
expected.elements = expectedElements;
|
||||
|
||||
final Paged actual = Links.paginateDimensionValues(dimVals, 1, uriInfo);
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Copyright 2014 IBM Corp
|
||||
# Copyright 2014 Hewlett-Packard
|
||||
# (C) Copyright 2014,2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
|
@ -64,3 +64,12 @@ class DimensionValuesV2API(object):
|
|||
|
||||
def on_get(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
|
||||
class DimensionNamesV2API(object):
|
||||
def __init__(self):
|
||||
super(DimensionNamesV2API, self).__init__()
|
||||
LOG.info('Initializing DimensionNamesV2API!')
|
||||
|
||||
def on_get(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Copyright 2014 IBM Corp
|
||||
# Copyright 2015-2016 Hewlett Packard Enterprise Development LP
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
|
@ -46,6 +46,8 @@ dispatcher_opts = [cfg.StrOpt('versions', default=None,
|
|||
help='Notification methods'),
|
||||
cfg.StrOpt('dimension_values', default=None,
|
||||
help='Dimension values'),
|
||||
cfg.StrOpt('dimension_names', default=None,
|
||||
help='Dimension names'),
|
||||
cfg.StrOpt('notification_method_types', default=None,
|
||||
help='notification_method_types methods')]
|
||||
|
||||
|
@ -115,6 +117,9 @@ def launch(conf, config_file="/etc/monasca/api-config.conf"):
|
|||
dimension_values = simport.load(cfg.CONF.dispatcher.dimension_values)()
|
||||
app.add_route("/v2.0/metrics/dimensions/names/values", dimension_values)
|
||||
|
||||
dimension_names = simport.load(cfg.CONF.dispatcher.dimension_names)()
|
||||
app.add_route("/v2.0/metrics/dimensions/names", dimension_names)
|
||||
|
||||
notification_method_types = simport.load(
|
||||
cfg.CONF.dispatcher.notification_method_types)()
|
||||
app.add_route("/v2.0/notification-methods/types", notification_method_types)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
# under the License.
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
from influxdb import client
|
||||
|
@ -207,28 +206,11 @@ class MetricsRepository(metrics_repository.AbstractMetricsRepository):
|
|||
LOG.exception(ex)
|
||||
raise exceptions.RepositoryException(ex)
|
||||
|
||||
def _generate_dimension_values_id(self, metric_name, dimension_name):
|
||||
sha1 = hashlib.sha1()
|
||||
hashstr = "metricName=" + (metric_name or "") + "dimensionName=" + dimension_name
|
||||
sha1.update(hashstr)
|
||||
return sha1.hexdigest()
|
||||
|
||||
def _build_serie_dimension_values(self, series_names, metric_name, dimension_name,
|
||||
tenant_id, region, offset):
|
||||
dim_vals = []
|
||||
sha1_id = self._generate_dimension_values_id(metric_name, dimension_name)
|
||||
json_dim_vals = {u'id': sha1_id,
|
||||
u'dimension_name': dimension_name,
|
||||
u'values': dim_vals}
|
||||
|
||||
#
|
||||
# Only return metric name if one was provided
|
||||
#
|
||||
if metric_name:
|
||||
json_dim_vals[u'metric_name'] = metric_name
|
||||
|
||||
def _build_serie_dimension_values(self, series_names, dimension_name):
|
||||
dim_values = []
|
||||
json_dim_value_list = []
|
||||
if not series_names:
|
||||
return json_dim_vals
|
||||
return json_dim_value_list
|
||||
|
||||
if 'series' in series_names.raw:
|
||||
for series in series_names.raw['series']:
|
||||
|
@ -240,12 +222,29 @@ class MetricsRepository(metrics_repository.AbstractMetricsRepository):
|
|||
if value and not name.startswith(u'_')
|
||||
}
|
||||
|
||||
if dimension_name in dims and dims[dimension_name] not in dim_vals:
|
||||
dim_vals.append(dims[dimension_name])
|
||||
if dimension_name in dims and dims[dimension_name] not in\
|
||||
dim_values:
|
||||
dim_values.append(dims[dimension_name])
|
||||
json_dim_value_list.append({u'dimension_value':
|
||||
dims[dimension_name]})
|
||||
|
||||
dim_vals = sorted(dim_vals)
|
||||
json_dim_vals[u'values'] = dim_vals
|
||||
return json_dim_vals
|
||||
json_dim_value_list = sorted(json_dim_value_list)
|
||||
return json_dim_value_list
|
||||
|
||||
def _build_serie_dimension_names(self, series_names):
|
||||
dim_names = []
|
||||
json_dim_name_list = []
|
||||
if not series_names:
|
||||
return json_dim_name_list
|
||||
|
||||
if 'series' in series_names.raw:
|
||||
for series in series_names.raw['series']:
|
||||
for name in series[u'columns']:
|
||||
if name not in dim_names and not name.startswith(u'_'):
|
||||
dim_names.append(name)
|
||||
json_dim_name_list.append({u'dimension_name': name})
|
||||
json_dim_name_list = sorted(json_dim_name_list)
|
||||
return json_dim_name_list
|
||||
|
||||
def _build_serie_metric_list(self, series_names, tenant_id, region,
|
||||
start_timestamp, end_timestamp,
|
||||
|
@ -619,21 +618,25 @@ class MetricsRepository(metrics_repository.AbstractMetricsRepository):
|
|||
return int((dt - datetime(1970, 1, 1)).total_seconds() * 1000)
|
||||
|
||||
def list_dimension_values(self, tenant_id, region, metric_name,
|
||||
dimension_name, offset, limit):
|
||||
|
||||
dimension_name):
|
||||
try:
|
||||
query = self._build_show_series_query(None, metric_name, tenant_id, region)
|
||||
query = self._build_show_series_query(None, metric_name,
|
||||
tenant_id, region)
|
||||
result = self.influxdb_client.query(query)
|
||||
|
||||
json_dim_vals = self._build_serie_dimension_values(result,
|
||||
metric_name,
|
||||
dimension_name,
|
||||
tenant_id,
|
||||
region,
|
||||
offset)
|
||||
|
||||
return json_dim_vals
|
||||
|
||||
json_dim_name_list = self._build_serie_dimension_values(
|
||||
result, dimension_name)
|
||||
return json_dim_name_list
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise exceptions.RepositoryException(ex)
|
||||
|
||||
def list_dimension_names(self, tenant_id, region, metric_name):
|
||||
try:
|
||||
query = self._build_show_series_query(None, metric_name,
|
||||
tenant_id, region)
|
||||
result = self.influxdb_client.query(query)
|
||||
json_dim_name_list = self._build_serie_dimension_names(result)
|
||||
return json_dim_name_list
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise exceptions.RepositoryException(ex)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright 2015 Cray Inc. All Rights Reserved.
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
|
@ -152,18 +153,40 @@ class TestRepoMetricsInfluxDB(unittest.TestCase):
|
|||
"38dc2a2549f94d2e9a4fa1cc45a4970c",
|
||||
"useast",
|
||||
"custom_metric",
|
||||
"hostname",
|
||||
offset=None,
|
||||
limit=1)
|
||||
"hostname")
|
||||
|
||||
self.assertEqual(result, {
|
||||
u'dimension_name': 'hostname',
|
||||
u'values': [
|
||||
u'custom_host'
|
||||
],
|
||||
u'id': 'bea9565d854a16a3366164de213694c190f27675',
|
||||
u'metric_name': 'custom_metric'
|
||||
})
|
||||
self.assertEqual(result, [{u'dimension_value': u'custom_host'}])
|
||||
|
||||
@patch("monasca_api.common.repositories.influxdb.metrics_repository.client.InfluxDBClient")
|
||||
def test_list_dimension_names(self, influxdb_client_mock):
|
||||
mock_client = influxdb_client_mock.return_value
|
||||
mock_client.query.return_value.raw = {
|
||||
u'series': [{
|
||||
u'values': [[
|
||||
u'custom_metric,_region=useast,_tenant_id=38dc2a2549f94d2e9a4fa1cc45a4970c,'
|
||||
u'hostname=custom_host,service=custom_service',
|
||||
u'useast',
|
||||
u'38dc2a2549f94d2e9a4fa1cc45a4970c',
|
||||
u'custom_host',
|
||||
u'custom_service'
|
||||
]],
|
||||
u'name': u'custom_metric',
|
||||
u'columns': [u'_key', u'_region', u'_tenant_id', u'hostname', u'service']
|
||||
}]
|
||||
}
|
||||
|
||||
repo = influxdb_repo.MetricsRepository()
|
||||
|
||||
result = repo.list_dimension_names(
|
||||
"38dc2a2549f94d2e9a4fa1cc45a4970c",
|
||||
"useast",
|
||||
"custom_metric")
|
||||
|
||||
self.assertEqual(result,
|
||||
[
|
||||
{u'dimension_name': u'hostname'},
|
||||
{u'dimension_name': u'service'}
|
||||
])
|
||||
|
||||
|
||||
class TestRepoMetricsCassandra(testtools.TestCase):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Copyright 2015 Cray Inc. All Rights Reserved.
|
||||
# Copyright 2014, 2016 Hewlett Packard Enterprise Development LP
|
||||
# Copyright 2014,2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
|
@ -463,61 +463,6 @@ def paginate_alarming(resource, uri, limit):
|
|||
return resource
|
||||
|
||||
|
||||
def paginate_dimension_values(dimvals, uri, offset, limit):
|
||||
|
||||
parsed_uri = urlparse.urlparse(uri)
|
||||
self_link = build_base_uri(parsed_uri)
|
||||
old_query_params = _get_old_query_params(parsed_uri)
|
||||
|
||||
if old_query_params:
|
||||
self_link += '?' + '&'.join(old_query_params)
|
||||
|
||||
if (dimvals and dimvals[u'values']):
|
||||
have_more, truncated_values = _truncate_dimension_values(dimvals[u'values'],
|
||||
limit,
|
||||
offset)
|
||||
|
||||
links = [{u'rel': u'self', u'href': self_link.decode('utf8')}]
|
||||
if have_more:
|
||||
new_offset = truncated_values[limit - 1]
|
||||
next_link = build_base_uri(parsed_uri)
|
||||
new_query_params = [u'offset' + '=' + urlparse.quote(
|
||||
new_offset.encode('utf8'), safe='')]
|
||||
|
||||
_get_old_query_params_except_offset(new_query_params, parsed_uri)
|
||||
|
||||
if new_query_params:
|
||||
next_link += '?' + '&'.join(new_query_params)
|
||||
|
||||
links.append({u'rel': u'next', u'href': next_link.decode('utf8')})
|
||||
|
||||
truncated_dimvals = {u'id': dimvals[u'id'],
|
||||
u'dimension_name': dimvals[u'dimension_name'],
|
||||
u'values': truncated_values}
|
||||
#
|
||||
# Only return metric name if one was provided
|
||||
#
|
||||
if u'metric_name' in dimvals:
|
||||
truncated_dimvals[u'metric_name'] = dimvals[u'metric_name']
|
||||
|
||||
resource = {u'links': links,
|
||||
u'elements': [truncated_dimvals]}
|
||||
else:
|
||||
resource = {u'links': ([{u'rel': u'self',
|
||||
u'href': self_link.decode('utf8')}]),
|
||||
u'elements': [dimvals]}
|
||||
|
||||
return resource
|
||||
|
||||
|
||||
def _truncate_dimension_values(values, limit, offset):
|
||||
if offset and offset in values:
|
||||
next_value_pos = values.index(offset) + 1
|
||||
values = values[next_value_pos:]
|
||||
have_more = len(values) > limit
|
||||
return have_more, values[:limit]
|
||||
|
||||
|
||||
def paginate_measurement(measurement, uri, limit):
|
||||
parsed_uri = urlparse.urlparse(uri)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# (C) Copyright 2014, 2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2014, 2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
|
@ -327,7 +327,8 @@ class DimensionValues(metrics_api_v2.DimensionValuesV2API):
|
|||
helpers.validate_authorization(req, self._get_metrics_authorized_roles)
|
||||
tenant_id = helpers.get_tenant_id(req)
|
||||
metric_name = helpers.get_query_param(req, 'metric_name')
|
||||
dimension_name = helpers.get_query_param(req, 'dimension_name', required=True)
|
||||
dimension_name = helpers.get_query_param(req, 'dimension_name',
|
||||
required=True)
|
||||
offset = helpers.get_query_param(req, 'offset')
|
||||
limit = helpers.get_limit(req)
|
||||
result = self._dimension_values(tenant_id, req.uri, metric_name,
|
||||
|
@ -342,8 +343,43 @@ class DimensionValues(metrics_api_v2.DimensionValuesV2API):
|
|||
result = self._metrics_repo.list_dimension_values(tenant_id,
|
||||
self._region,
|
||||
metric_name,
|
||||
dimension_name,
|
||||
offset,
|
||||
limit)
|
||||
dimension_name)
|
||||
|
||||
return helpers.paginate_dimension_values(result, req_uri, offset, limit)
|
||||
return helpers.paginate_with_no_id(result, req_uri, offset, limit)
|
||||
|
||||
|
||||
class DimensionNames(metrics_api_v2.DimensionNamesV2API):
|
||||
def __init__(self):
|
||||
try:
|
||||
super(DimensionNames, self).__init__()
|
||||
self._region = cfg.CONF.region
|
||||
self._get_metrics_authorized_roles = (
|
||||
cfg.CONF.security.default_authorized_roles +
|
||||
cfg.CONF.security.read_only_authorized_roles)
|
||||
self._metrics_repo = simport.load(
|
||||
cfg.CONF.repositories.metrics_driver)()
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def on_get(self, req, res):
|
||||
helpers.validate_authorization(req, self._get_metrics_authorized_roles)
|
||||
tenant_id = helpers.get_tenant_id(req)
|
||||
metric_name = helpers.get_query_param(req, 'metric_name')
|
||||
offset = helpers.get_query_param(req, 'offset')
|
||||
limit = helpers.get_limit(req)
|
||||
result = self._dimension_names(tenant_id, req.uri, metric_name,
|
||||
offset, limit)
|
||||
res.body = helpers.dumpit_utf8(result)
|
||||
res.status = falcon.HTTP_200
|
||||
|
||||
@resource.resource_try_catch_block
|
||||
def _dimension_names(self, tenant_id, req_uri, metric_name, offset, limit):
|
||||
|
||||
result = self._metrics_repo.list_dimension_names(tenant_id,
|
||||
self._region,
|
||||
metric_name)
|
||||
|
||||
return helpers.paginate_with_no_id(result, req_uri, offset, limit)
|
||||
|
|
|
@ -52,6 +52,13 @@ class MonascaClient(rest_client.RestClient):
|
|||
resp, response_body = self.get(uri)
|
||||
return resp, json.loads(response_body)
|
||||
|
||||
def list_dimension_names(self, query_params=None):
|
||||
uri = 'metrics/dimensions/names'
|
||||
if query_params is not None:
|
||||
uri = uri + query_params
|
||||
resp, response_body = self.get(uri)
|
||||
return resp, json.loads(response_body)
|
||||
|
||||
def list_dimension_values(self, query_params=None):
|
||||
uri = 'metrics/dimensions/names/values'
|
||||
if query_params is not None:
|
||||
|
|
|
@ -93,5 +93,4 @@ class BaseMonascaTest(tempest.test.BaseTestCase):
|
|||
query_params = urlparse.parse_qs(urlparse.urlparse(next_link).query)
|
||||
if 'offset' not in query_params:
|
||||
self.fail("No offset in next link: {}".format(next_link))
|
||||
|
||||
return query_params['offset'][0]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# (C) Copyright 2016 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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
|
||||
|
@ -14,14 +14,13 @@
|
|||
|
||||
import time
|
||||
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from monasca_tempest_tests.tests.api import base
|
||||
from monasca_tempest_tests.tests.api import constants
|
||||
from monasca_tempest_tests.tests.api import helpers
|
||||
from tempest.common.utils import data_utils
|
||||
from tempest import test
|
||||
from tempest.lib import exceptions
|
||||
from urllib import urlencode
|
||||
|
||||
|
||||
class TestDimensions(base.BaseMonascaTest):
|
||||
|
@ -29,34 +28,56 @@ class TestDimensions(base.BaseMonascaTest):
|
|||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(TestDimensions, cls).resource_setup()
|
||||
name = data_utils.rand_name()
|
||||
key = data_utils.rand_name()
|
||||
metric_name1 = data_utils.rand_name()
|
||||
name1 = "name_1"
|
||||
name2 = "name_2"
|
||||
value1 = "value_1"
|
||||
value2 = "value_2"
|
||||
cls._param = key + ':' + value1
|
||||
cls._dimension_name = key
|
||||
cls._dim_val_1 = value1
|
||||
cls._dim_val_2 = value2
|
||||
metric = helpers.create_metric(name=name,
|
||||
dimensions={key: value1})
|
||||
cls.monasca_client.create_metrics(metric)
|
||||
metric = helpers.create_metric(name=name,
|
||||
dimensions={key: value2})
|
||||
cls.monasca_client.create_metrics(metric)
|
||||
cls._test_metric = metric
|
||||
|
||||
start_time = str(timeutils.iso8601_from_timestamp(
|
||||
metric['timestamp'] / 1000.0))
|
||||
parms = '?name=' + str(cls._test_metric['name']) + \
|
||||
'&start_time=' + start_time
|
||||
timestamp = int(round(time.time() * 1000))
|
||||
time_iso = helpers.timestamp_to_iso(timestamp)
|
||||
|
||||
metric1 = helpers.create_metric(name=metric_name1,
|
||||
dimensions={name1: value1,
|
||||
name2: value2
|
||||
})
|
||||
cls.monasca_client.create_metrics(metric1)
|
||||
metric1 = helpers.create_metric(name=metric_name1,
|
||||
dimensions={name1: value2})
|
||||
cls.monasca_client.create_metrics(metric1)
|
||||
|
||||
metric_name2 = data_utils.rand_name()
|
||||
name3 = "name_3"
|
||||
value3 = "value_3"
|
||||
metric2 = helpers.create_metric(name=metric_name2,
|
||||
dimensions={name3: value3})
|
||||
cls.monasca_client.create_metrics(metric2)
|
||||
|
||||
metric_name3 = data_utils.rand_name()
|
||||
metric3 = helpers.create_metric(name=metric_name3,
|
||||
dimensions={name1: value3})
|
||||
|
||||
cls.monasca_client.create_metrics(metric3)
|
||||
|
||||
cls._test_metric1 = metric1
|
||||
cls._test_metric2 = metric2
|
||||
cls._test_metric_names = {metric_name1, metric_name2, metric_name3}
|
||||
cls._dim_names_metric1 = [name1, name2]
|
||||
cls._dim_names_metric2 = [name3]
|
||||
cls._dim_names = cls._dim_names_metric1 + cls._dim_names_metric2
|
||||
cls._dim_values_for_metric1 = [value1, value2]
|
||||
cls._dim_values = [value1, value2, value3]
|
||||
|
||||
param = '?start_time=' + time_iso
|
||||
returned_name_set = set()
|
||||
for i in xrange(constants.MAX_RETRIES):
|
||||
resp, response_body = cls.monasca_client.list_metrics(
|
||||
parms)
|
||||
param)
|
||||
elements = response_body['elements']
|
||||
for element in elements:
|
||||
if str(element['name']) == cls._test_metric['name']:
|
||||
return
|
||||
returned_name_set.add(str(element['name']))
|
||||
if cls._test_metric_names.issubset(returned_name_set):
|
||||
return
|
||||
time.sleep(constants.RETRY_WAIT_SECS)
|
||||
|
||||
assert False, 'Unable to initialize metrics'
|
||||
|
@ -67,46 +88,73 @@ class TestDimensions(base.BaseMonascaTest):
|
|||
|
||||
@test.attr(type='gate')
|
||||
def test_list_dimension_values_without_metric_name(self):
|
||||
parms = '?dimension_name=' + self._dimension_name
|
||||
resp, response_body = self.monasca_client.list_dimension_values(parms)
|
||||
param = '?dimension_name=' + self._dim_names[0]
|
||||
resp, response_body = self.monasca_client.list_dimension_values(param)
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertTrue(set(['links', 'elements']) == set(response_body))
|
||||
if not self._is_dimension_name_in_list(response_body):
|
||||
self.fail('Dimension name not found in response')
|
||||
if self._is_metric_name_in_list(response_body):
|
||||
self.fail('Metric name was in response and should not be')
|
||||
if not self._are_dim_vals_in_list(response_body):
|
||||
self.fail('Dimension value not found in response')
|
||||
self.assertTrue({'links', 'elements'} == set(response_body))
|
||||
response_values_length = len(response_body['elements'])
|
||||
values = [str(response_body['elements'][i]['dimension_value'])
|
||||
for i in xrange(response_values_length)]
|
||||
self.assertEqual(values, self._dim_values)
|
||||
|
||||
@test.attr(type='gate')
|
||||
def test_list_dimension_values_with_metric_name(self):
|
||||
parms = '?metric_name=' + self._test_metric['name']
|
||||
parms += '&dimension_name=' + self._dimension_name
|
||||
parms = '?metric_name=' + self._test_metric1['name']
|
||||
parms += '&dimension_name=' + self._dim_names[0]
|
||||
resp, response_body = self.monasca_client.list_dimension_values(parms)
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertTrue(set(['links', 'elements']) == set(response_body))
|
||||
if not self._is_metric_name_in_list(response_body):
|
||||
self.fail('Metric name not found in response')
|
||||
if not self._is_dimension_name_in_list(response_body):
|
||||
self.fail('Dimension name not found in response')
|
||||
if not self._are_dim_vals_in_list(response_body):
|
||||
self.fail('Dimension value not found in response')
|
||||
self.assertTrue({'links', 'elements'} == set(response_body))
|
||||
response_values_length = len(response_body['elements'])
|
||||
values = [str(response_body['elements'][i]['dimension_value'])
|
||||
for i in xrange(response_values_length)]
|
||||
self.assertEqual(values, self._dim_values_for_metric1)
|
||||
|
||||
@test.attr(type='gate')
|
||||
def test_list_dimension_values_limit_and_offset(self):
|
||||
parms = '?dimension_name=' + self._dimension_name
|
||||
parms += '&limit=1'
|
||||
resp, response_body = self.monasca_client.list_dimension_values(parms)
|
||||
param = '?dimension_name=' + self._dim_names[0]
|
||||
resp, response_body = self.monasca_client.list_dimension_values(param)
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertTrue(set(['links', 'elements']) == set(response_body))
|
||||
if not self._is_dimension_name_in_list(response_body):
|
||||
self.fail('Dimension name not found in response')
|
||||
if not self._is_dim_val_in_list(response_body, self._dim_val_1):
|
||||
self.fail('First dimension value not found in response')
|
||||
if not self._is_offset_in_links(response_body, self._dim_val_1):
|
||||
self.fail('Offset not found in response')
|
||||
if not self._is_limit_in_links(response_body):
|
||||
self.fail('Limit not found in response')
|
||||
elements = response_body['elements']
|
||||
num_dim_values = len(elements)
|
||||
for limit in xrange(1, num_dim_values):
|
||||
start_index = 0
|
||||
params = [('limit', limit)]
|
||||
offset = None
|
||||
while True:
|
||||
num_expected_elements = limit
|
||||
if (num_expected_elements + start_index) > num_dim_values:
|
||||
num_expected_elements = num_dim_values - start_index
|
||||
|
||||
these_params = list(params)
|
||||
# If not the first call, use the offset returned by the last
|
||||
# call
|
||||
if offset:
|
||||
these_params.extend([('offset', str(offset))])
|
||||
query_parms = '?dimension_name=' + self._dim_names[0] + '&' + \
|
||||
urlencode(these_params)
|
||||
resp, response_body = \
|
||||
self.monasca_client.list_dimension_values(query_parms)
|
||||
self.assertEqual(200, resp.status)
|
||||
if not response_body['elements']:
|
||||
self.fail("No metrics returned")
|
||||
response_values_length = len(response_body['elements'])
|
||||
if response_values_length == 0:
|
||||
self.fail("No dimension names returned")
|
||||
new_elements = [str(response_body['elements'][i]
|
||||
['dimension_value']) for i in
|
||||
xrange(response_values_length)]
|
||||
self.assertEqual(num_expected_elements, len(new_elements))
|
||||
|
||||
expected_elements = elements[start_index:start_index+limit]
|
||||
expected_dimension_values = \
|
||||
[expected_elements[i]['dimension_value'] for i in xrange(
|
||||
len(expected_elements))]
|
||||
self.assertEqual(expected_dimension_values, new_elements)
|
||||
start_index += num_expected_elements
|
||||
if start_index >= num_dim_values:
|
||||
break
|
||||
# Get the next set
|
||||
offset = self._get_offset(response_body)
|
||||
|
||||
@test.attr(type='gate')
|
||||
@test.attr(type=['negative'])
|
||||
|
@ -114,46 +162,81 @@ class TestDimensions(base.BaseMonascaTest):
|
|||
self.assertRaises(exceptions.UnprocessableEntity,
|
||||
self.monasca_client.list_dimension_values)
|
||||
|
||||
def _is_metric_name_in_list(self, response_body):
|
||||
elements = response_body['elements'][0]
|
||||
if 'metric_name' not in elements:
|
||||
return False
|
||||
if str(elements['metric_name']) == self._test_metric['name']:
|
||||
return True
|
||||
return False
|
||||
@test.attr(type='gate')
|
||||
def test_list_dimension_names(self):
|
||||
resp, response_body = self.monasca_client.list_dimension_names()
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertTrue({'links', 'elements'} == set(response_body))
|
||||
response_names_length = len(response_body['elements'])
|
||||
names = [str(response_body['elements'][i]['dimension_name']) for i
|
||||
in xrange(response_names_length)]
|
||||
self.assertEqual(names, self._dim_names)
|
||||
|
||||
def _is_dimension_name_in_list(self, response_body):
|
||||
elements = response_body['elements'][0]
|
||||
if str(elements['dimension_name']) == self._dimension_name:
|
||||
return True
|
||||
return False
|
||||
@test.attr(type='gate')
|
||||
def test_list_dimension_names_with_metric_name(self):
|
||||
self._test_list_dimension_names_with_metric_name(
|
||||
self._test_metric1['name'], self._dim_names_metric1)
|
||||
self._test_list_dimension_names_with_metric_name(
|
||||
self._test_metric2['name'], self._dim_names_metric2)
|
||||
|
||||
def _are_dim_vals_in_list(self, response_body):
|
||||
elements = response_body['elements'][0]
|
||||
have_dim_1 = self._is_dim_val_in_list(response_body, self._dim_val_1)
|
||||
have_dim_2 = self._is_dim_val_in_list(response_body, self._dim_val_2)
|
||||
if have_dim_1 and have_dim_1:
|
||||
return True
|
||||
return False
|
||||
@test.attr(type='gate')
|
||||
def test_list_dimension_names_limit_and_offset(self):
|
||||
resp, response_body = self.monasca_client.list_dimension_names()
|
||||
self.assertEqual(200, resp.status)
|
||||
elements = response_body['elements']
|
||||
num_dim_names = len(elements)
|
||||
for limit in xrange(1, num_dim_names):
|
||||
start_index = 0
|
||||
params = [('limit', limit)]
|
||||
offset = None
|
||||
while True:
|
||||
num_expected_elements = limit
|
||||
if (num_expected_elements + start_index) > num_dim_names:
|
||||
num_expected_elements = num_dim_names - start_index
|
||||
|
||||
def _is_dim_val_in_list(self, response_body, dim_val):
|
||||
elements = response_body['elements'][0]
|
||||
if dim_val in elements['values']:
|
||||
return True
|
||||
return False
|
||||
these_params = list(params)
|
||||
# If not the first call, use the offset returned by the last
|
||||
# call
|
||||
if offset:
|
||||
these_params.extend([('offset', str(offset))])
|
||||
query_parms = '?' + urlencode(these_params)
|
||||
resp, response_body = self.monasca_client.list_dimension_names(
|
||||
query_parms)
|
||||
self.assertEqual(200, resp.status)
|
||||
if not response_body['elements']:
|
||||
self.fail("No metrics returned")
|
||||
response_names_length = len(response_body['elements'])
|
||||
if response_names_length == 0:
|
||||
self.fail("No dimension names returned")
|
||||
new_elements = [str(response_body['elements'][i]
|
||||
['dimension_name']) for i in
|
||||
xrange(response_names_length)]
|
||||
self.assertEqual(num_expected_elements, len(new_elements))
|
||||
|
||||
def _is_offset_in_links(self, response_body, dim_val):
|
||||
links = response_body['links']
|
||||
offset = "offset=" + dim_val
|
||||
for link in links:
|
||||
if offset in link['href']:
|
||||
return True
|
||||
return False
|
||||
expected_elements = elements[start_index:start_index+limit]
|
||||
expected_dimension_names = \
|
||||
[expected_elements[i]['dimension_name'] for i in xrange(
|
||||
len(expected_elements))]
|
||||
self.assertEqual(expected_dimension_names, new_elements)
|
||||
start_index += num_expected_elements
|
||||
if start_index >= num_dim_names:
|
||||
break
|
||||
# Get the next set
|
||||
offset = self._get_offset(response_body)
|
||||
|
||||
def _is_limit_in_links(self, response_body):
|
||||
links = response_body['links']
|
||||
limit = "limit=1"
|
||||
for link in links:
|
||||
if limit in link['href']:
|
||||
return True
|
||||
return False
|
||||
@test.attr(type='gate')
|
||||
@test.attr(type=['negative'])
|
||||
def test_list_dimension_names_with_wrong_metric_name(self):
|
||||
self._test_list_dimension_names_with_metric_name(
|
||||
'wrong_metric_name', [])
|
||||
|
||||
def _test_list_dimension_names_with_metric_name(self, metric_name,
|
||||
dimension_names):
|
||||
param = '?metric_name=' + metric_name
|
||||
resp, response_body = self.monasca_client.list_dimension_names(param)
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertTrue(set(['links', 'elements']) == set(response_body))
|
||||
response_names_length = len(response_body['elements'])
|
||||
names = [str(response_body['elements'][i]['dimension_name']) for i
|
||||
in xrange(response_names_length)]
|
||||
self.assertEqual(names, dimension_names)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#
|
||||
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
# 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
|
||||
|
@ -13,8 +13,6 @@
|
|||
|
||||
import time
|
||||
|
||||
import six.moves.urllib.parse as urlparse
|
||||
|
||||
from monasca_tempest_tests.tests.api import base
|
||||
from monasca_tempest_tests.tests.api import helpers
|
||||
from tempest import test
|
||||
|
@ -22,6 +20,7 @@ from tempest.lib import exceptions
|
|||
|
||||
from monasca_tempest_tests import clients
|
||||
|
||||
|
||||
class TestReadOnlyRole(base.BaseMonascaTest):
|
||||
|
||||
@classmethod
|
||||
|
@ -112,7 +111,19 @@ class TestReadOnlyRole(base.BaseMonascaTest):
|
|||
#
|
||||
url = '/v2.0/metrics/dimensions/names/values?dimension_name=foo'
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertEqual(0, len(response_body['elements'][0]['values']))
|
||||
self.assertEqual(0, len(response_body['elements']))
|
||||
self.assertTrue(response_body['links'][0]['href'].endswith(url))
|
||||
|
||||
@test.attr(type="gate")
|
||||
def test_list_dimension_names_success(self):
|
||||
resp, response_body = self.monasca_client.list_dimension_names()
|
||||
#
|
||||
# Validate the call succeeds with empty result (we didn't
|
||||
# create any metrics/dimensions)
|
||||
#
|
||||
url = '/v2.0/metrics/dimensions/names'
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertEqual(0, len(response_body['elements']))
|
||||
self.assertTrue(response_body['links'][0]['href'].endswith(url))
|
||||
|
||||
@test.attr(type="gate")
|
||||
|
@ -129,7 +140,6 @@ class TestReadOnlyRole(base.BaseMonascaTest):
|
|||
self.assertEqual(0, len(response_body['elements']))
|
||||
self.assertTrue('/v2.0/metrics/measurements' in response_body['links'][0]['href'])
|
||||
|
||||
|
||||
@test.attr(type="gate")
|
||||
def test_list_statistics_success(self):
|
||||
start_timestamp = int(time.time() * 1000)
|
||||
|
|
Loading…
Reference in New Issue