diff --git a/.generator/schemas/v1/openapi.yaml b/.generator/schemas/v1/openapi.yaml index e4c949659000..c132893290dd 100644 --- a/.generator/schemas/v1/openapi.yaml +++ b/.generator/schemas/v1/openapi.yaml @@ -11409,6 +11409,60 @@ components: example: UTC type: string type: object + SLOCountCondition: + description: 'A count-based SLI specification, composed of three parts: the + good events formula, the total events formula, + + and the involved queries.' + example: + good_events_formula: query1 - query2 + queries: + - data_source: metrics + name: query1 + query: sum:trace.servlet.request.success{*} by {env}.as_count() + - data_source: metrics + name: query2 + query: sum:trace.servlet.request.hits{*} by {env}.as_count() + total_events_formula: query2 + properties: + good_events_formula: + $ref: '#/components/schemas/SLOFormula' + queries: + example: + - data_source: metrics + name: query1 + query: sum:trace.servlet.request.hits{*} by {env}.as_count() + items: + $ref: '#/components/schemas/SLODataSourceQueryDefinition' + minItems: 1 + type: array + total_events_formula: + $ref: '#/components/schemas/SLOFormula' + required: + - good_events_formula + - total_events_formula + - queries + type: object + SLOCountSpec: + additionalProperties: false + description: A count-based SLI specification. + example: + count: + good_events_formula: query1 - query2 + queries: + - data_source: metrics + name: query1 + query: sum:trace.servlet.request.success{*} by {env}.as_count() + - data_source: metrics + name: query2 + query: sum:trace.servlet.request.hits{*} by {env}.as_count() + total_events_formula: query2 + properties: + count: + $ref: '#/components/schemas/SLOCountCondition' + required: + - count + type: object SLOCreator: description: The creator of the SLO nullable: true @@ -12295,8 +12349,6 @@ components: type: array timeframe: $ref: '#/components/schemas/SLOTimeframe' - type: - $ref: '#/components/schemas/SLOType' warning_threshold: description: 'The optional warning threshold such that when the service level indicator is @@ -12314,9 +12366,10 @@ components: type: object SLOSliSpec: description: A generic SLI specification. This is currently used for time-slice - SLOs only. + and count-based SLOs only. oneOf: - $ref: '#/components/schemas/SLOTimeSliceSpec' + - $ref: '#/components/schemas/SLOCountSpec' SLOState: description: State of the SLO. enum: @@ -13468,8 +13521,7 @@ components: - type type: object ServiceLevelObjectiveQuery: - description: 'A metric-based SLO. **Required if type is `metric`**. Note that - Datadog only allows the sum by aggregator + description: 'A metric-based SLO. Note that Datadog only allows the sum by aggregator to be used because this will sum up all request counts instead of averaging them, or taking the max or diff --git a/examples/v1/service-level-objectives/CreateSLO_512760759.rb b/examples/v1/service-level-objectives/CreateSLO_512760759.rb new file mode 100644 index 000000000000..f47aa83a9143 --- /dev/null +++ b/examples/v1/service-level-objectives/CreateSLO_512760759.rb @@ -0,0 +1,49 @@ +# Create a new metric SLO object using sli_specification returns "OK" response + +require "datadog_api_client" +api_instance = DatadogAPIClient::V1::ServiceLevelObjectivesAPI.new + +body = DatadogAPIClient::V1::ServiceLevelObjectiveRequest.new({ + type: DatadogAPIClient::V1::SLOType::METRIC, + description: "Metric SLO using sli_specification", + name: "Example-Service-Level-Objective", + sli_specification: DatadogAPIClient::V1::SLOCountSpec.new({ + count: DatadogAPIClient::V1::SLOCountCondition.new({ + good_events_formula: DatadogAPIClient::V1::SLOFormula.new({ + formula: "query1", + }), + total_events_formula: DatadogAPIClient::V1::SLOFormula.new({ + formula: "query2", + }), + queries: [ + DatadogAPIClient::V1::FormulaAndFunctionMetricQueryDefinition.new({ + data_source: DatadogAPIClient::V1::FormulaAndFunctionMetricDataSource::METRICS, + name: "query1", + query: "sum:httpservice.success{*}.as_count()", + }), + DatadogAPIClient::V1::FormulaAndFunctionMetricQueryDefinition.new({ + data_source: DatadogAPIClient::V1::FormulaAndFunctionMetricDataSource::METRICS, + name: "query2", + query: "sum:httpservice.hits{*}.as_count()", + }), + ], + }), + }), + tags: [ + "env:prod", + "type:count", + ], + thresholds: [ + DatadogAPIClient::V1::SLOThreshold.new({ + target: 99.0, + target_display: "99.0", + timeframe: DatadogAPIClient::V1::SLOTimeframe::SEVEN_DAYS, + warning: 98, + warning_display: "98.0", + }), + ], + timeframe: DatadogAPIClient::V1::SLOTimeframe::SEVEN_DAYS, + target_threshold: 99.0, + warning_threshold: 98, +}) +p api_instance.create_slo(body) diff --git a/features/v1/service_level_objectives.feature b/features/v1/service_level_objectives.feature index c5534618a73e..3fba149b2d39 100644 --- a/features/v1/service_level_objectives.feature +++ b/features/v1/service_level_objectives.feature @@ -48,6 +48,30 @@ Feature: Service Level Objectives When the request is sent Then the response status is 200 OK + @team:DataDog/slo-app + Scenario: Create a metric SLO with both sli_specification and query returns "Bad Request" response + Given new "CreateSLO" request + And body with value {"type":"metric","description":"Invalid SLO with both sli_specification and query","name":"{{ unique }}","sli_specification":{"count":{"good_events_formula":{"formula":"query1"},"total_events_formula":{"formula":"query2"},"queries":[{"data_source":"metrics","name":"query1","query":"sum:httpservice.success{*}.as_count()"},{"data_source":"metrics","name":"query2","query":"sum:httpservice.hits{*}.as_count()"}]}},"query":{"numerator":"sum:httpservice.success{*}.as_count()","denominator":"sum:httpservice.hits{*}.as_count()"},"tags":["env:prod"],"thresholds":[{"target":99.0,"target_display":"99.0","timeframe":"7d","warning":98,"warning_display":"98.0"}],"timeframe":"7d","target_threshold":99.0,"warning_threshold":98} + When the request is sent + Then the response status is 400 Bad Request + + @team:DataDog/slo-app + Scenario: Create a new metric SLO object using sli_specification returns "OK" response + Given new "CreateSLO" request + And body with value {"type":"metric","description":"Metric SLO using sli_specification","name":"{{ unique }}","sli_specification":{"count":{"good_events_formula":{"formula":"query1"},"total_events_formula":{"formula":"query2"},"queries":[{"data_source":"metrics","name":"query1","query":"sum:httpservice.success{*}.as_count()"},{"data_source":"metrics","name":"query2","query":"sum:httpservice.hits{*}.as_count()"}]}},"tags":["env:prod","type:count"],"thresholds":[{"target":99.0,"target_display":"99.0","timeframe":"7d","warning":98,"warning_display":"98.0"}],"timeframe":"7d","target_threshold":99.0,"warning_threshold":98} + When the request is sent + Then the response status is 200 OK + And the response "data[0].timeframe" is equal to "7d" + And the response "data[0].target_threshold" is equal to 99.0 + And the response "data[0].warning_threshold" is equal to 98.0 + And the response "data[0]" has field "sli_specification" + And the response "data[0].sli_specification" has field "count" + And the response "data[0].sli_specification.count" has field "good_events_formula" + And the response "data[0].sli_specification.count" has field "total_events_formula" + And the response "data[0].sli_specification.count" has field "queries" + And the response "data[0].sli_specification.count.queries" has length 2 + And the response "data[0]" does not have field "query" + @team:DataDog/slo-app Scenario: Create a time-slice SLO object returns "OK" response Given new "CreateSLO" request @@ -74,6 +98,8 @@ Feature: Service Level Objectives And the response "data[0].timeframe" is equal to "7d" And the response "data[0].target_threshold" is equal to 97.0 And the response "data[0].warning_threshold" is equal to 98.0 + And the response "data[0]" has field "query" + And the response "data[0]" does not have field "sli_specification" @generated @skip @team:DataDog/slo-app Scenario: Delete an SLO returns "Conflict" response diff --git a/lib/datadog_api_client/inflector.rb b/lib/datadog_api_client/inflector.rb index bb8ef80c0422..ff9353dddd4d 100644 --- a/lib/datadog_api_client/inflector.rb +++ b/lib/datadog_api_client/inflector.rb @@ -518,6 +518,8 @@ def overrides "v1.slo_correction_update_data" => "SLOCorrectionUpdateData", "v1.slo_correction_update_request" => "SLOCorrectionUpdateRequest", "v1.slo_correction_update_request_attributes" => "SLOCorrectionUpdateRequestAttributes", + "v1.slo_count_condition" => "SLOCountCondition", + "v1.slo_count_spec" => "SLOCountSpec", "v1.slo_creator" => "SLOCreator", "v1.slo_data_source_query_definition" => "SLODataSourceQueryDefinition", "v1.slo_delete_response" => "SLODeleteResponse", diff --git a/lib/datadog_api_client/v1/models/service_level_objective.rb b/lib/datadog_api_client/v1/models/service_level_objective.rb index bf18b9ab7e4d..d3fc45ba71b6 100644 --- a/lib/datadog_api_client/v1/models/service_level_objective.rb +++ b/lib/datadog_api_client/v1/models/service_level_objective.rb @@ -68,12 +68,12 @@ class ServiceLevelObjective # The name of the service level objective object. attr_reader :name - # A metric-based SLO. **Required if type is `metric`**. Note that Datadog only allows the sum by aggregator + # A metric-based SLO. Note that Datadog only allows the sum by aggregator # to be used because this will sum up all request counts instead of averaging them, or taking the max or # min of all of those requests. attr_accessor :query - # A generic SLI specification. This is currently used for time-slice SLOs only. + # A generic SLI specification. This is currently used for time-slice and count-based SLOs only. attr_accessor :sli_specification # A list of tags associated with this service level objective. diff --git a/lib/datadog_api_client/v1/models/service_level_objective_query.rb b/lib/datadog_api_client/v1/models/service_level_objective_query.rb index 354cf44c6038..cdabb166c0fb 100644 --- a/lib/datadog_api_client/v1/models/service_level_objective_query.rb +++ b/lib/datadog_api_client/v1/models/service_level_objective_query.rb @@ -17,7 +17,7 @@ require 'time' module DatadogAPIClient::V1 - # A metric-based SLO. **Required if type is `metric`**. Note that Datadog only allows the sum by aggregator + # A metric-based SLO. Note that Datadog only allows the sum by aggregator # to be used because this will sum up all request counts instead of averaging them, or taking the max or # min of all of those requests. class ServiceLevelObjectiveQuery diff --git a/lib/datadog_api_client/v1/models/service_level_objective_request.rb b/lib/datadog_api_client/v1/models/service_level_objective_request.rb index c2415da8bd3f..1554cf4c32d2 100644 --- a/lib/datadog_api_client/v1/models/service_level_objective_request.rb +++ b/lib/datadog_api_client/v1/models/service_level_objective_request.rb @@ -42,12 +42,12 @@ class ServiceLevelObjectiveRequest # The name of the service level objective object. attr_reader :name - # A metric-based SLO. **Required if type is `metric`**. Note that Datadog only allows the sum by aggregator + # A metric-based SLO. Note that Datadog only allows the sum by aggregator # to be used because this will sum up all request counts instead of averaging them, or taking the max or # min of all of those requests. attr_accessor :query - # A generic SLI specification. This is currently used for time-slice SLOs only. + # A generic SLI specification. This is currently used for time-slice and count-based SLOs only. attr_accessor :sli_specification # A list of tags associated with this service level objective. diff --git a/lib/datadog_api_client/v1/models/slo_count_condition.rb b/lib/datadog_api_client/v1/models/slo_count_condition.rb new file mode 100644 index 000000000000..a7abb6bece70 --- /dev/null +++ b/lib/datadog_api_client/v1/models/slo_count_condition.rb @@ -0,0 +1,172 @@ +=begin +#Datadog API V1 Collection + +#Collection of all Datadog Public endpoints. + +The version of the OpenAPI document: 1.0 +Contact: support@datadoghq.com +Generated by: https://github.com/DataDog/datadog-api-client-ruby/tree/master/.generator + + Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. + This product includes software developed at Datadog (https://www.datadoghq.com/). + Copyright 2020-Present Datadog, Inc. + +=end + +require 'date' +require 'time' + +module DatadogAPIClient::V1 + # A count-based SLI specification, composed of three parts: the good events formula, the total events formula, + # and the involved queries. + class SLOCountCondition + include BaseGenericModel + + # A formula that specifies how to combine the results of multiple queries. + attr_reader :good_events_formula + + # + attr_reader :queries + + # A formula that specifies how to combine the results of multiple queries. + attr_reader :total_events_formula + + attr_accessor :additional_properties + + # Attribute mapping from ruby-style variable name to JSON key. + # @!visibility private + def self.attribute_map + { + :'good_events_formula' => :'good_events_formula', + :'queries' => :'queries', + :'total_events_formula' => :'total_events_formula' + } + end + + # Attribute type mapping. + # @!visibility private + def self.openapi_types + { + :'good_events_formula' => :'SLOFormula', + :'queries' => :'Array', + :'total_events_formula' => :'SLOFormula' + } + end + + # Initializes the object + # @param attributes [Hash] Model attributes in the form of hash + # @!visibility private + def initialize(attributes = {}) + if (!attributes.is_a?(Hash)) + fail ArgumentError, "The input argument (attributes) must be a hash in `DatadogAPIClient::V1::SLOCountCondition` initialize method" + end + + self.additional_properties = {} + # check to see if the attribute exists and convert string to symbol for hash key + attributes = attributes.each_with_object({}) { |(k, v), h| + if (!self.class.attribute_map.key?(k.to_sym)) + self.additional_properties[k.to_sym] = v + else + h[k.to_sym] = v + end + } + + if attributes.key?(:'good_events_formula') + self.good_events_formula = attributes[:'good_events_formula'] + end + + if attributes.key?(:'queries') + if (value = attributes[:'queries']).is_a?(Array) + self.queries = value + end + end + + if attributes.key?(:'total_events_formula') + self.total_events_formula = attributes[:'total_events_formula'] + end + end + + # Check to see if the all the properties in the model are valid + # @return true if the model is valid + # @!visibility private + def valid? + return false if @good_events_formula.nil? + return false if @queries.nil? + return false if @queries.length < 1 + return false if @total_events_formula.nil? + true + end + + # Custom attribute writer method with validation + # @param good_events_formula [Object] Object to be assigned + # @!visibility private + def good_events_formula=(good_events_formula) + if good_events_formula.nil? + fail ArgumentError, 'invalid value for "good_events_formula", good_events_formula cannot be nil.' + end + @good_events_formula = good_events_formula + end + + # Custom attribute writer method with validation + # @param queries [Object] Object to be assigned + # @!visibility private + def queries=(queries) + if queries.nil? + fail ArgumentError, 'invalid value for "queries", queries cannot be nil.' + end + if queries.length < 1 + fail ArgumentError, 'invalid value for "queries", number of items must be greater than or equal to 1.' + end + @queries = queries + end + + # Custom attribute writer method with validation + # @param total_events_formula [Object] Object to be assigned + # @!visibility private + def total_events_formula=(total_events_formula) + if total_events_formula.nil? + fail ArgumentError, 'invalid value for "total_events_formula", total_events_formula cannot be nil.' + end + @total_events_formula = total_events_formula + end + + # Returns the object in the form of hash, with additionalProperties support. + # @return [Hash] Returns the object in the form of hash + # @!visibility private + def to_hash + hash = {} + self.class.attribute_map.each_pair do |attr, param| + value = self.send(attr) + if value.nil? + is_nullable = self.class.openapi_nullable.include?(attr) + next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}")) + end + + hash[param] = _to_hash(value) + end + self.additional_properties.each_pair do |attr, value| + hash[attr] = value + end + hash + end + + # Checks equality by comparing each attribute. + # @param o [Object] Object to be compared + # @!visibility private + def ==(o) + return true if self.equal?(o) + self.class == o.class && + good_events_formula == o.good_events_formula && + queries == o.queries && + total_events_formula == o.total_events_formula && + additional_properties == o.additional_properties + end + + # Calculates hash code according to all attributes. + # @return [Integer] Hash code + # @!visibility private + def hash + [good_events_formula, queries, total_events_formula, additional_properties].hash + end + end +end diff --git a/lib/datadog_api_client/v1/models/slo_count_spec.rb b/lib/datadog_api_client/v1/models/slo_count_spec.rb new file mode 100644 index 000000000000..3c28f6a03bd3 --- /dev/null +++ b/lib/datadog_api_client/v1/models/slo_count_spec.rb @@ -0,0 +1,99 @@ +=begin +#Datadog API V1 Collection + +#Collection of all Datadog Public endpoints. + +The version of the OpenAPI document: 1.0 +Contact: support@datadoghq.com +Generated by: https://github.com/DataDog/datadog-api-client-ruby/tree/master/.generator + + Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. + This product includes software developed at Datadog (https://www.datadoghq.com/). + Copyright 2020-Present Datadog, Inc. + +=end + +require 'date' +require 'time' + +module DatadogAPIClient::V1 + # A count-based SLI specification. + class SLOCountSpec + include BaseGenericModel + + # A count-based SLI specification, composed of three parts: the good events formula, the total events formula, + # and the involved queries. + attr_reader :count + + # Attribute mapping from ruby-style variable name to JSON key. + # @!visibility private + def self.attribute_map + { + :'count' => :'count' + } + end + + # Attribute type mapping. + # @!visibility private + def self.openapi_types + { + :'count' => :'SLOCountCondition' + } + end + + # Initializes the object + # @param attributes [Hash] Model attributes in the form of hash + # @!visibility private + def initialize(attributes = {}) + if (!attributes.is_a?(Hash)) + fail ArgumentError, "The input argument (attributes) must be a hash in `DatadogAPIClient::V1::SLOCountSpec` initialize method" + end + + # check to see if the attribute exists and convert string to symbol for hash key + attributes = attributes.each_with_object({}) { |(k, v), h| + if (!self.class.attribute_map.key?(k.to_sym)) + fail ArgumentError, "`#{k}` is not a valid attribute in `DatadogAPIClient::V1::SLOCountSpec`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect + end + h[k.to_sym] = v + } + + if attributes.key?(:'count') + self.count = attributes[:'count'] + end + end + + # Check to see if the all the properties in the model are valid + # @return true if the model is valid + # @!visibility private + def valid? + return false if @count.nil? + true + end + + # Custom attribute writer method with validation + # @param count [Object] Object to be assigned + # @!visibility private + def count=(count) + if count.nil? + fail ArgumentError, 'invalid value for "count", count cannot be nil.' + end + @count = count + end + + # Checks equality by comparing each attribute. + # @param o [Object] Object to be compared + # @!visibility private + def ==(o) + return true if self.equal?(o) + self.class == o.class && + count == o.count + end + + # Calculates hash code according to all attributes. + # @return [Integer] Hash code + # @!visibility private + def hash + [count].hash + end + end +end diff --git a/lib/datadog_api_client/v1/models/slo_response_data.rb b/lib/datadog_api_client/v1/models/slo_response_data.rb index 5b010d33bbed..23d52baae736 100644 --- a/lib/datadog_api_client/v1/models/slo_response_data.rb +++ b/lib/datadog_api_client/v1/models/slo_response_data.rb @@ -71,12 +71,12 @@ class SLOResponseData # The name of the service level objective object. attr_accessor :name - # A metric-based SLO. **Required if type is `metric`**. Note that Datadog only allows the sum by aggregator + # A metric-based SLO. Note that Datadog only allows the sum by aggregator # to be used because this will sum up all request counts instead of averaging them, or taking the max or # min of all of those requests. attr_accessor :query - # A generic SLI specification. This is currently used for time-slice SLOs only. + # A generic SLI specification. This is currently used for time-slice and count-based SLOs only. attr_accessor :sli_specification # A list of tags associated with this service level objective. @@ -96,9 +96,6 @@ class SLOResponseData # or updating SLOs. It is only used when querying SLO history over custom timeframes. attr_accessor :timeframe - # The type of the service level objective. - attr_accessor :type - # The optional warning threshold such that when the service level indicator is # below this value for the given threshold, but above the target threshold, the # objective appears in a "warning" state. This value must be greater than the target @@ -127,7 +124,6 @@ def self.attribute_map :'target_threshold' => :'target_threshold', :'thresholds' => :'thresholds', :'timeframe' => :'timeframe', - :'type' => :'type', :'warning_threshold' => :'warning_threshold' } end @@ -152,7 +148,6 @@ def self.openapi_types :'target_threshold' => :'Float', :'thresholds' => :'Array', :'timeframe' => :'SLOTimeframe', - :'type' => :'SLOType', :'warning_threshold' => :'Float' } end @@ -259,10 +254,6 @@ def initialize(attributes = {}) self.timeframe = attributes[:'timeframe'] end - if attributes.key?(:'type') - self.type = attributes[:'type'] - end - if attributes.key?(:'warning_threshold') self.warning_threshold = attributes[:'warning_threshold'] end @@ -310,7 +301,6 @@ def ==(o) target_threshold == o.target_threshold && thresholds == o.thresholds && timeframe == o.timeframe && - type == o.type && warning_threshold == o.warning_threshold && additional_properties == o.additional_properties end @@ -319,7 +309,7 @@ def ==(o) # @return [Integer] Hash code # @!visibility private def hash - [configured_alert_ids, created_at, creator, description, groups, id, modified_at, monitor_ids, monitor_tags, name, query, sli_specification, tags, target_threshold, thresholds, timeframe, type, warning_threshold, additional_properties].hash + [configured_alert_ids, created_at, creator, description, groups, id, modified_at, monitor_ids, monitor_tags, name, query, sli_specification, tags, target_threshold, thresholds, timeframe, warning_threshold, additional_properties].hash end end end diff --git a/lib/datadog_api_client/v1/models/slo_sli_spec.rb b/lib/datadog_api_client/v1/models/slo_sli_spec.rb index 4c15c69a6ded..37b421358d67 100644 --- a/lib/datadog_api_client/v1/models/slo_sli_spec.rb +++ b/lib/datadog_api_client/v1/models/slo_sli_spec.rb @@ -17,7 +17,7 @@ require 'time' module DatadogAPIClient::V1 - # A generic SLI specification. This is currently used for time-slice SLOs only. + # A generic SLI specification. This is currently used for time-slice and count-based SLOs only. module SLOSliSpec class << self include BaseOneOfModel @@ -26,7 +26,8 @@ class << self # List of class defined in oneOf (OpenAPI v3) def openapi_one_of [ - :'SLOTimeSliceSpec' + :'SLOTimeSliceSpec', + :'SLOCountSpec' ] end # Builds the object