From 200449ab01453836d2d2db1cd7f57ddeb95b371b Mon Sep 17 00:00:00 2001 From: Micah Hausler Date: Fri, 24 Jul 2026 14:32:31 -0700 Subject: [PATCH] Update CloudWatch SDK to v1.65.0 Bump cloudwatch service models and adds support for evaluationCriteria and evaluationInterval for MetricAlarms --- ATTRIBUTION.md | 13 +- apis/v1alpha1/ack-generate-metadata.yaml | 10 +- apis/v1alpha1/dashboard.go | 2 +- apis/v1alpha1/enums.go | 28 +- apis/v1alpha1/generator.yaml | 6 +- apis/v1alpha1/metric_alarm.go | 69 ++- apis/v1alpha1/types.go | 209 ++++++- apis/v1alpha1/zz_generated.deepcopy.go | 435 +++++++++++++++ ...loudwatch.services.k8s.aws_dashboards.yaml | 2 +- ...udwatch.services.k8s.aws_metricalarms.yaml | 121 +++- generator.yaml | 6 +- go.mod | 10 +- go.sum | 20 +- ...loudwatch.services.k8s.aws_dashboards.yaml | 2 +- ...udwatch.services.k8s.aws_metricalarms.yaml | 121 +++- pkg/resource/metric_alarm/delta.go | 55 ++ pkg/resource/metric_alarm/sdk.go | 516 ++++++++++++------ test/e2e/requirements.txt | 2 +- .../metric_alarm_evaluation_window.yaml | 21 + test/e2e/resources/metric_alarm_promql.yaml | 19 + test/e2e/tests/test_metric_alarm.py | 186 ++++++- 21 files changed, 1570 insertions(+), 283 deletions(-) create mode 100644 test/e2e/resources/metric_alarm_evaluation_window.yaml create mode 100644 test/e2e/resources/metric_alarm_promql.yaml diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 479c3df..7786565 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -2041,7 +2041,16 @@ SOFTWARE. +### github.com/aws/aws-sdk-go-v2 +License Identifier: Apache-2.0 + +Subdependencies: +* `github.com/aws/smithy-go` + +#### github.com/aws/smithy-go + +License Identifier: Apache-2.0 ### github.com/aws/aws-sdk-go-v2/service/cloudwatch @@ -2053,10 +2062,6 @@ Subdependencies: * `github.com/aws/aws-sdk-go-v2/internal/endpoints/v2` * `github.com/aws/smithy-go` -#### github.com/aws/aws-sdk-go-v2 - -License Identifier: Apache-2.0 - diff --git a/apis/v1alpha1/ack-generate-metadata.yaml b/apis/v1alpha1/ack-generate-metadata.yaml index 35b3066..b91c0c1 100755 --- a/apis/v1alpha1/ack-generate-metadata.yaml +++ b/apis/v1alpha1/ack-generate-metadata.yaml @@ -1,13 +1,13 @@ ack_generate_info: - build_date: "2026-07-07T21:52:17Z" + build_date: "2026-07-24T23:28:35Z" build_hash: 0a6b791fa10a6140d862be334a6891868ee588eb - go_version: go1.26.4 + go_version: go1.26.5 version: v0.61.0 -api_directory_checksum: 8be9cea150aec461063eba17920438bc9b400a83 +api_directory_checksum: fc4c89800fb4263204f37a5b291222112d4150cb api_version: v1alpha1 -aws_sdk_go_version: v1.36.0 +aws_service_sdk_version: v1.65.0 generator_config_info: - file_checksum: 50f08f2e82558a3da16e8a4193b357021f29fb38 + file_checksum: 08fbc160443372732f33f8d6a185682c03c3e68d original_file_name: generator.yaml last_modification: reason: API generation diff --git a/apis/v1alpha1/dashboard.go b/apis/v1alpha1/dashboard.go index 079ad3d..5af26af 100644 --- a/apis/v1alpha1/dashboard.go +++ b/apis/v1alpha1/dashboard.go @@ -28,7 +28,7 @@ type DashboardSpec struct { // required. // // For more information about the syntax, see Dashboard Body Structure and Syntax - // (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/CloudWatch-Dashboard-Body-Structure.html). + // (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Dashboard-Body-Structure.html). // +kubebuilder:validation:Required DashboardBody *string `json:"dashboardBody"` // The name of the dashboard. If a dashboard with this name already exists, diff --git a/apis/v1alpha1/enums.go b/apis/v1alpha1/enums.go index bd9791e..b32c2a0 100644 --- a/apis/v1alpha1/enums.go +++ b/apis/v1alpha1/enums.go @@ -23,10 +23,19 @@ const ( ActionsSuppressedBy_WaitPeriod ActionsSuppressedBy = "WaitPeriod" ) +type AlarmMuteRuleStatus string + +const ( + AlarmMuteRuleStatus_ACTIVE AlarmMuteRuleStatus = "ACTIVE" + AlarmMuteRuleStatus_EXPIRED AlarmMuteRuleStatus = "EXPIRED" + AlarmMuteRuleStatus_SCHEDULED AlarmMuteRuleStatus = "SCHEDULED" +) + type AlarmType string const ( AlarmType_CompositeAlarm AlarmType = "CompositeAlarm" + AlarmType_LogAlarm AlarmType = "LogAlarm" AlarmType_MetricAlarm AlarmType = "MetricAlarm" ) @@ -60,15 +69,19 @@ const ( type EvaluationState string const ( - EvaluationState_PARTIAL_DATA EvaluationState = "PARTIAL_DATA" + EvaluationState_EVALUATION_ERROR EvaluationState = "EVALUATION_ERROR" + EvaluationState_EVALUATION_FAILURE EvaluationState = "EVALUATION_FAILURE" + EvaluationState_PARTIAL_DATA EvaluationState = "PARTIAL_DATA" ) type HistoryItemType string const ( - HistoryItemType_Action HistoryItemType = "Action" - HistoryItemType_ConfigurationUpdate HistoryItemType = "ConfigurationUpdate" - HistoryItemType_StateUpdate HistoryItemType = "StateUpdate" + HistoryItemType_Action HistoryItemType = "Action" + HistoryItemType_AlarmContributorAction HistoryItemType = "AlarmContributorAction" + HistoryItemType_AlarmContributorStateUpdate HistoryItemType = "AlarmContributorStateUpdate" + HistoryItemType_ConfigurationUpdate HistoryItemType = "ConfigurationUpdate" + HistoryItemType_StateUpdate HistoryItemType = "StateUpdate" ) type MetricStreamOutputFormat string @@ -79,6 +92,13 @@ const ( MetricStreamOutputFormat_opentelemetry1_0 MetricStreamOutputFormat = "opentelemetry1.0" ) +type OTelEnrichmentStatus string + +const ( + OTelEnrichmentStatus_Running OTelEnrichmentStatus = "Running" + OTelEnrichmentStatus_Stopped OTelEnrichmentStatus = "Stopped" +) + type RecentlyActive string const ( diff --git a/apis/v1alpha1/generator.yaml b/apis/v1alpha1/generator.yaml index 7d4ef90..c3974a1 100644 --- a/apis/v1alpha1/generator.yaml +++ b/apis/v1alpha1/generator.yaml @@ -1,3 +1,5 @@ +empty_shapes: + - SlidingWindow ignore: resource_names: - AnomalyDetector @@ -5,6 +7,8 @@ ignore: - InsightRule - ManagedInsightRule # - MetricStream + field_paths: + - PutDashboardInput.Tags operations: DeleteAlarms: operation_type: @@ -92,4 +96,4 @@ resources: - InvalidParameterValueException - InvalidParameterInput tags: - ignore: true \ No newline at end of file + ignore: true diff --git a/apis/v1alpha1/metric_alarm.go b/apis/v1alpha1/metric_alarm.go index b3caa5d..640bafd 100644 --- a/apis/v1alpha1/metric_alarm.go +++ b/apis/v1alpha1/metric_alarm.go @@ -74,7 +74,7 @@ type MetricAlarmSpec struct { // // # Start a Amazon Q Developer operational investigation // - // arn:aws:aiops:region:account-id:investigation-group:ingestigation-group-id + // arn:aws:aiops:region:account-id:investigation-group:investigation-group-id AlarmActions []*string `json:"alarmActions,omitempty"` // The description for the alarm. AlarmDescription *string `json:"alarmDescription,omitempty"` @@ -84,8 +84,7 @@ type MetricAlarmSpec struct { // The values LessThanLowerOrGreaterThanUpperThreshold, LessThanLowerThreshold, // and GreaterThanUpperThreshold are used only for alarms based on anomaly detection // models. - // +kubebuilder:validation:Required - ComparisonOperator *string `json:"comparisonOperator"` + ComparisonOperator *string `json:"comparisonOperator,omitempty"` // The number of data points that must be breaching to trigger the alarm. This // is used only if you are setting an "M out of N" alarm. In that case, this // value is the M. For more information, see Evaluating an Alarm (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarm-evaluation) @@ -102,15 +101,43 @@ type MetricAlarmSpec struct { // // Valid Values: evaluate | ignore EvaluateLowSampleCountPercentile *string `json:"evaluateLowSampleCountPercentile,omitempty"` + // The evaluation criteria for the alarm. For each PutMetricAlarm operation, + // you must specify either MetricName, a Metrics array, or an EvaluationCriteria. + // + // If you use the EvaluationCriteria parameter, you cannot include the Namespace, + // MetricName, Dimensions, Period, Unit, Statistic, ExtendedStatistic, Metrics, + // Threshold, ComparisonOperator, ThresholdMetricId, EvaluationPeriods, or DatapointsToAlarm + // parameters of PutMetricAlarm in the same operation. Instead, all evaluation + // parameters are defined within this structure. + // + // For an example of how to use this parameter, see the PromQL alarm example + // on this page. + EvaluationCriteria *EvaluationCriteria `json:"evaluationCriteria,omitempty"` + // The frequency, in seconds, at which the alarm is evaluated. Valid values + // are 10, 20, 30, and any multiple of 60. + // + // This parameter is required for alarms that use EvaluationCriteria, and cannot + // be specified for alarms configured with MetricName or Metrics. + EvaluationInterval *int64 `json:"evaluationInterval,omitempty"` // The number of periods over which data is compared to the specified threshold. // If you are setting an alarm that requires that a number of consecutive data // points be breaching to trigger the alarm, this value specifies that number. // If you are setting an "M out of N" alarm, this value is the N. + EvaluationPeriods *int64 `json:"evaluationPeriods,omitempty"` + // The evaluation window that the alarm uses to select the range of metric data + // that it evaluates. Specify either a sliding window or a wall clock window. + // If you omit this parameter, the alarm uses a sliding window. // - // An alarm's total current evaluation period can be no longer than one day, - // so this number multiplied by Period cannot be more than 86,400 seconds. - // +kubebuilder:validation:Required - EvaluationPeriods *int64 `json:"evaluationPeriods"` + // A sliding window advances each time the alarm is evaluated, forming a rolling + // time window. A wall clock window aligns the evaluated range to fixed clock + // boundaries, such as the top of the hour or the start of the day. + // + // You can use EvaluationWindow with any type of metric alarm except alarms + // that are based on a PromQL query. + // + // For more information, see Alarm evaluation windows (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/alarm-evaluation-window.html) + // in the CloudWatch User Guide. + EvaluationWindow *EvaluationWindow `json:"evaluationWindow,omitempty"` // The extended statistic for the metric specified in MetricName. When you call // PutMetricAlarm and specify a MetricName, you must specify either Statistic // or ExtendedStatistic but not both. @@ -187,7 +214,7 @@ type MetricAlarmSpec struct { // - arn:aws:ssm-incidents::account-id:responseplan/response-plan-name InsufficientDataActions []*string `json:"insufficientDataActions,omitempty"` // The name for the metric associated with the alarm. For each PutMetricAlarm - // operation, you must specify either MetricName or a Metrics array. + // operation, you must specify either MetricName, a Metrics array, or an EvaluationCriteria. // // If you are creating an alarm based on a math expression, you cannot specify // this parameter, or any of the Namespace, Dimensions, Period, Unit, Statistic, @@ -196,7 +223,7 @@ type MetricAlarmSpec struct { MetricName *string `json:"metricName,omitempty"` // An array of MetricDataQuery structures that enable you to create an alarm // based on the result of a metric math expression. For each PutMetricAlarm - // operation, you must specify either MetricName or a Metrics array. + // operation, you must specify either MetricName, a Metrics array, or an EvaluationCriteria. // // Each item in the Metrics array either retrieves a metric or performs a math // expression. @@ -265,24 +292,26 @@ type MetricAlarmSpec struct { // - arn:aws:ssm-incidents::account-id:responseplan/response-plan-name OKActions []*string `json:"oKActions,omitempty"` // The length, in seconds, used each time the metric specified in MetricName - // is evaluated. Valid values are 10, 30, and any multiple of 60. + // is evaluated. Valid values are 10, 20, 30, and any multiple of 60. // // Period is required for alarms based on static thresholds. If you are creating // an alarm based on a metric math expression, you specify the period for each // metric within the objects in the Metrics array. // - // Be sure to specify 10 or 30 only for metrics that are stored by a PutMetricData - // call with a StorageResolution of 1. If you specify a period of 10 or 30 for - // a metric that does not have sub-minute resolution, the alarm still attempts - // to gather data at the period rate that you specify. In this case, it does - // not receive data for the attempts that do not correspond to a one-minute + // Be sure to specify 10, 20, or 30 only for metrics that are stored by a PutMetricData + // call with a StorageResolution of 1. If you specify a period of 10, 20, or + // 30 for a metric that does not have sub-minute resolution, the alarm still + // attempts to gather data at the period rate that you specify. In this case, + // it does not receive data for the attempts that do not correspond to a one-minute // data resolution, and the alarm might often lapse into INSUFFICENT_DATA status. - // Specifying 10 or 30 also sets this alarm as a high-resolution alarm, which - // has a higher charge than other alarms. For more information about pricing, + // Specifying 10, 20, or 30 also sets this alarm as a high-resolution alarm, + // which has a higher charge than other alarms. For more information about pricing, // see Amazon CloudWatch Pricing (https://aws.amazon.com/cloudwatch/pricing/). // - // An alarm's total current evaluation period can be no longer than one day, - // so Period multiplied by EvaluationPeriods cannot be more than 86,400 seconds. + // An alarm's total current evaluation period can be no longer than seven days, + // so Period multiplied by EvaluationPeriods can't be more than 604,800 seconds. + // For alarms with a period of less than one hour (3,600 seconds), the total + // evaluation period can't be longer than one day (86,400 seconds). Period *int64 `json:"period,omitempty"` // The statistic for the metric specified in MetricName, other than percentile. // For percentile statistics, use ExtendedStatistic. When you call PutMetricAlarm @@ -329,6 +358,8 @@ type MetricAlarmSpec struct { // missing data even if you choose a different option for TreatMissingData. // When an AWS/DynamoDB metric has missing data, alarms that evaluate that metric // remain in their current state. + // + // This parameter is not applicable to PromQL alarms. TreatMissingData *string `json:"treatMissingData,omitempty"` // The unit of measure for the statistic. For example, the units for the Amazon // EC2 NetworkIn metric are Bytes because NetworkIn tracks the number of bytes diff --git a/apis/v1alpha1/types.go b/apis/v1alpha1/types.go index 9d0a07f..d1e1076 100644 --- a/apis/v1alpha1/types.go +++ b/apis/v1alpha1/types.go @@ -28,6 +28,14 @@ var ( _ = ackv1alpha1.AWSAccountID("") ) +// Represents an individual contributor to a multi-timeseries alarm, containing +// information about a specific time series and its contribution to the alarm's +// state. +type AlarmContributor struct { + StateReason *string `json:"stateReason,omitempty"` + StateTransitionedTimestamp *metav1.Time `json:"stateTransitionedTimestamp,omitempty"` +} + // Represents the history of a specific alarm. type AlarmHistoryItem struct { AlarmName *string `json:"alarmName,omitempty"` @@ -35,6 +43,22 @@ type AlarmHistoryItem struct { Timestamp *metav1.Time `json:"timestamp,omitempty"` } +// Summary information about an alarm mute rule, including its name, status, +// and configuration details. +type AlarmMuteRuleSummary struct { + ExpireDate *metav1.Time `json:"expireDate,omitempty"` + LastUpdatedTimestamp *metav1.Time `json:"lastUpdatedTimestamp,omitempty"` +} + +// Contains the configuration that determines how a PromQL alarm evaluates its +// contributors, including the query to run and the durations that define when +// contributors transition between states. +type AlarmPromQLCriteria struct { + PendingPeriod *int64 `json:"pendingPeriod,omitempty"` + Query *string `json:"query,omitempty"` + RecoveryPeriod *int64 `json:"recoveryPeriod,omitempty"` +} + // An anomaly detection model associated with a particular CloudWatch metric, // statistic, or metric math expression. You can use the model to display a // band of expected, normal values when the metric is graphed. @@ -110,6 +134,46 @@ type DimensionFilter struct { Value *string `json:"value,omitempty"` } +// The evaluation criteria for an alarm. This is a union type that currently +// supports PromQLCriteria. +type EvaluationCriteria struct { + // Contains the configuration that determines how a PromQL alarm evaluates its + // contributors, including the query to run and the durations that define when + // contributors transition between states. + PromQLCriteria *AlarmPromQLCriteria `json:"promQLCriteria,omitempty"` +} + +// The evaluation window that an alarm uses to select the range of metric data +// that it evaluates each time it runs. This is a union type. Set exactly one +// of its members, SlidingWindow or WallClockWindow. If you don't set EvaluationWindow, +// the alarm uses a SlidingWindow by default. +// +// For more information, see Alarm evaluation windows (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/alarm-evaluation-window.html) +// in the CloudWatch User Guide. +type EvaluationWindow struct { + // An evaluation window that advances each time the alarm is evaluated, forming + // a rolling time window. This is the default evaluation window. A sliding window + // has no additional configuration options. + // + // Choose a sliding window when you need the fastest detection and the calendar + // boundaries of the data don't matter, such as for continuous performance, + // latency, or resource-exhaustion monitoring. + SlidingWindow map[string]*string `json:"slidingWindow,omitempty"` + // An evaluation window that aligns the evaluated range to fixed clock boundaries + // that match the alarm's period, such as the top of the hour, midnight, or + // the start of the calendar week, optionally in a specific time zone. + // + // When you use a wall clock window, the alarm's period must be 1 minute (60 + // seconds), 5 minutes (300 seconds), 1 hour (3,600 seconds), 1 day (86,400 + // seconds), or 1 week (604,800 seconds). Other period values aren't supported + // with a wall clock window. + // + // Choose a wall clock window when your monitoring is tied to a business or + // calendar period, such as daily reports, batch jobs, or backups, or when you + // want alarm evaluations to match the periods shown on a metric dashboard. + WallClockWindow *WallClockWindow `json:"wallClockWindow,omitempty"` +} + // One data point related to one contributor. // // For more information, see GetInsightRuleReport (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetInsightRuleReport.html) @@ -126,6 +190,34 @@ type InsightRuleMetricDatapoint struct { Timestamp *metav1.Time `json:"timestamp,omitempty"` } +// The details about a log alarm. +type LogAlarm struct { + ActionLogLineCount *int64 `json:"actionLogLineCount,omitempty"` + ActionLogLineRoleARN *string `json:"actionLogLineRoleARN,omitempty"` + ActionsEnabled *bool `json:"actionsEnabled,omitempty"` + AlarmActions []*string `json:"alarmActions,omitempty"` + AlarmARN *string `json:"alarmARN,omitempty"` + AlarmConfigurationUpdatedTimestamp *metav1.Time `json:"alarmConfigurationUpdatedTimestamp,omitempty"` + AlarmDescription *string `json:"alarmDescription,omitempty"` + AlarmName *string `json:"alarmName,omitempty"` + ComparisonOperator *string `json:"comparisonOperator,omitempty"` + EvaluationState *string `json:"evaluationState,omitempty"` + InsufficientDataActions []*string `json:"insufficientDataActions,omitempty"` + OKActions []*string `json:"oKActions,omitempty"` + QueryResultsToAlarm *int64 `json:"queryResultsToAlarm,omitempty"` + QueryResultsToEvaluate *int64 `json:"queryResultsToEvaluate,omitempty"` + // The configuration of the CloudWatch Logs scheduled query that backs a log + // alarm. + ScheduledQueryConfiguration *ScheduledQueryConfiguration `json:"scheduledQueryConfiguration,omitempty"` + StateReason *string `json:"stateReason,omitempty"` + StateReasonData *string `json:"stateReasonData,omitempty"` + StateTransitionedTimestamp *metav1.Time `json:"stateTransitionedTimestamp,omitempty"` + StateUpdatedTimestamp *metav1.Time `json:"stateUpdatedTimestamp,omitempty"` + StateValue *string `json:"stateValue,omitempty"` + Threshold *float64 `json:"threshold,omitempty"` + TreatMissingData *string `json:"treatMissingData,omitempty"` +} + // Contains the information that's required to enable a managed Contributor // Insights rule for an Amazon Web Services resource. type ManagedRule struct { @@ -148,35 +240,47 @@ type Metric struct { // The details about a metric alarm. type MetricAlarm_SDK struct { - ActionsEnabled *bool `json:"actionsEnabled,omitempty"` - AlarmActions []*string `json:"alarmActions,omitempty"` - AlarmARN *string `json:"alarmARN,omitempty"` - AlarmConfigurationUpdatedTimestamp *metav1.Time `json:"alarmConfigurationUpdatedTimestamp,omitempty"` - AlarmDescription *string `json:"alarmDescription,omitempty"` - AlarmName *string `json:"alarmName,omitempty"` - ComparisonOperator *string `json:"comparisonOperator,omitempty"` - DatapointsToAlarm *int64 `json:"datapointsToAlarm,omitempty"` - Dimensions []*Dimension `json:"dimensions,omitempty"` - EvaluateLowSampleCountPercentile *string `json:"evaluateLowSampleCountPercentile,omitempty"` - EvaluationPeriods *int64 `json:"evaluationPeriods,omitempty"` - EvaluationState *string `json:"evaluationState,omitempty"` - ExtendedStatistic *string `json:"extendedStatistic,omitempty"` - InsufficientDataActions []*string `json:"insufficientDataActions,omitempty"` - MetricName *string `json:"metricName,omitempty"` - Metrics []*MetricDataQuery `json:"metrics,omitempty"` - Namespace *string `json:"namespace,omitempty"` - OKActions []*string `json:"oKActions,omitempty"` - Period *int64 `json:"period,omitempty"` - StateReason *string `json:"stateReason,omitempty"` - StateReasonData *string `json:"stateReasonData,omitempty"` - StateTransitionedTimestamp *metav1.Time `json:"stateTransitionedTimestamp,omitempty"` - StateUpdatedTimestamp *metav1.Time `json:"stateUpdatedTimestamp,omitempty"` - StateValue *string `json:"stateValue,omitempty"` - Statistic *string `json:"statistic,omitempty"` - Threshold *float64 `json:"threshold,omitempty"` - ThresholdMetricID *string `json:"thresholdMetricID,omitempty"` - TreatMissingData *string `json:"treatMissingData,omitempty"` - Unit *string `json:"unit,omitempty"` + ActionsEnabled *bool `json:"actionsEnabled,omitempty"` + AlarmActions []*string `json:"alarmActions,omitempty"` + AlarmARN *string `json:"alarmARN,omitempty"` + AlarmConfigurationUpdatedTimestamp *metav1.Time `json:"alarmConfigurationUpdatedTimestamp,omitempty"` + AlarmDescription *string `json:"alarmDescription,omitempty"` + AlarmName *string `json:"alarmName,omitempty"` + ComparisonOperator *string `json:"comparisonOperator,omitempty"` + DatapointsToAlarm *int64 `json:"datapointsToAlarm,omitempty"` + Dimensions []*Dimension `json:"dimensions,omitempty"` + EvaluateLowSampleCountPercentile *string `json:"evaluateLowSampleCountPercentile,omitempty"` + // The evaluation criteria for an alarm. This is a union type that currently + // supports PromQLCriteria. + EvaluationCriteria *EvaluationCriteria `json:"evaluationCriteria,omitempty"` + EvaluationInterval *int64 `json:"evaluationInterval,omitempty"` + EvaluationPeriods *int64 `json:"evaluationPeriods,omitempty"` + EvaluationState *string `json:"evaluationState,omitempty"` + // The evaluation window that an alarm uses to select the range of metric data + // that it evaluates each time it runs. This is a union type. Set exactly one + // of its members, SlidingWindow or WallClockWindow. If you don't set EvaluationWindow, + // the alarm uses a SlidingWindow by default. + // + // For more information, see Alarm evaluation windows (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/alarm-evaluation-window.html) + // in the CloudWatch User Guide. + EvaluationWindow *EvaluationWindow `json:"evaluationWindow,omitempty"` + ExtendedStatistic *string `json:"extendedStatistic,omitempty"` + InsufficientDataActions []*string `json:"insufficientDataActions,omitempty"` + MetricName *string `json:"metricName,omitempty"` + Metrics []*MetricDataQuery `json:"metrics,omitempty"` + Namespace *string `json:"namespace,omitempty"` + OKActions []*string `json:"oKActions,omitempty"` + Period *int64 `json:"period,omitempty"` + StateReason *string `json:"stateReason,omitempty"` + StateReasonData *string `json:"stateReasonData,omitempty"` + StateTransitionedTimestamp *metav1.Time `json:"stateTransitionedTimestamp,omitempty"` + StateUpdatedTimestamp *metav1.Time `json:"stateUpdatedTimestamp,omitempty"` + StateValue *string `json:"stateValue,omitempty"` + Statistic *string `json:"statistic,omitempty"` + Threshold *float64 `json:"threshold,omitempty"` + ThresholdMetricID *string `json:"thresholdMetricID,omitempty"` + TreatMissingData *string `json:"treatMissingData,omitempty"` + Unit *string `json:"unit,omitempty"` } // This structure is used in both GetMetricData and PutMetricAlarm. The supported @@ -297,6 +401,37 @@ type Range struct { StartTime *metav1.Time `json:"startTime,omitempty"` } +// Specifies when and how long an alarm mute rule is active. +// +// The schedule uses either a cron expression for recurring mute windows or +// an at expression for one-time mute windows. When the schedule activates, +// the mute rule mutes alarm actions for the specified duration. +type Schedule struct { + Timezone *string `json:"timezone,omitempty"` +} + +// Contains the schedule expression and time-range offsets that define when +// a scheduled query runs and what time range each execution covers. +type ScheduleConfiguration struct { + EndTimeOffset *int64 `json:"endTimeOffset,omitempty"` + ScheduleExpression *string `json:"scheduleExpression,omitempty"` + StartTimeOffset *int64 `json:"startTimeOffset,omitempty"` +} + +// The configuration of the CloudWatch Logs scheduled query that backs a log +// alarm. +type ScheduledQueryConfiguration struct { + AggregationExpression *string `json:"aggregationExpression,omitempty"` + LogGroupIdentifiers []*string `json:"logGroupIdentifiers,omitempty"` + QueryARN *string `json:"queryARN,omitempty"` + QueryString *string `json:"queryString,omitempty"` + // Contains the schedule expression and time-range offsets that define when + // a scheduled query runs and what time range each execution covers. + ScheduleConfiguration *ScheduleConfiguration `json:"scheduleConfiguration,omitempty"` + ScheduledQueryRoleARN *string `json:"scheduledQueryRoleARN,omitempty"` + Tags []*Tag `json:"tags,omitempty"` +} + // Designates the CloudWatch metric and statistic that provides the time series // the anomaly detector uses as input. If you have enabled unified cross-account // observability, and this account is a monitoring account, the metric can be @@ -313,3 +448,19 @@ type Tag struct { Key *string `json:"key,omitempty"` Value *string `json:"value,omitempty"` } + +// An evaluation window that aligns the evaluated range to fixed clock boundaries +// that match the alarm's period, such as the top of the hour, midnight, or +// the start of the calendar week, optionally in a specific time zone. +// +// When you use a wall clock window, the alarm's period must be 1 minute (60 +// seconds), 5 minutes (300 seconds), 1 hour (3,600 seconds), 1 day (86,400 +// seconds), or 1 week (604,800 seconds). Other period values aren't supported +// with a wall clock window. +// +// Choose a wall clock window when your monitoring is tied to a business or +// calendar period, such as daily reports, batch jobs, or backups, or when you +// want alarm evaluations to match the periods shown on a metric dashboard. +type WallClockWindow struct { + Timezone *string `json:"timezone,omitempty"` +} diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index 2d81057..847ab28 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -24,6 +24,30 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AlarmContributor) DeepCopyInto(out *AlarmContributor) { + *out = *in + if in.StateReason != nil { + in, out := &in.StateReason, &out.StateReason + *out = new(string) + **out = **in + } + if in.StateTransitionedTimestamp != nil { + in, out := &in.StateTransitionedTimestamp, &out.StateTransitionedTimestamp + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlarmContributor. +func (in *AlarmContributor) DeepCopy() *AlarmContributor { + if in == nil { + return nil + } + out := new(AlarmContributor) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AlarmHistoryItem) DeepCopyInto(out *AlarmHistoryItem) { *out = *in @@ -53,6 +77,59 @@ func (in *AlarmHistoryItem) DeepCopy() *AlarmHistoryItem { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AlarmMuteRuleSummary) DeepCopyInto(out *AlarmMuteRuleSummary) { + *out = *in + if in.ExpireDate != nil { + in, out := &in.ExpireDate, &out.ExpireDate + *out = (*in).DeepCopy() + } + if in.LastUpdatedTimestamp != nil { + in, out := &in.LastUpdatedTimestamp, &out.LastUpdatedTimestamp + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlarmMuteRuleSummary. +func (in *AlarmMuteRuleSummary) DeepCopy() *AlarmMuteRuleSummary { + if in == nil { + return nil + } + out := new(AlarmMuteRuleSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AlarmPromQLCriteria) DeepCopyInto(out *AlarmPromQLCriteria) { + *out = *in + if in.PendingPeriod != nil { + in, out := &in.PendingPeriod, &out.PendingPeriod + *out = new(int64) + **out = **in + } + if in.Query != nil { + in, out := &in.Query, &out.Query + *out = new(string) + **out = **in + } + if in.RecoveryPeriod != nil { + in, out := &in.RecoveryPeriod, &out.RecoveryPeriod + *out = new(int64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlarmPromQLCriteria. +func (in *AlarmPromQLCriteria) DeepCopy() *AlarmPromQLCriteria { + if in == nil { + return nil + } + out := new(AlarmPromQLCriteria) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AnomalyDetector) DeepCopyInto(out *AnomalyDetector) { *out = *in @@ -473,6 +550,62 @@ func (in *DimensionFilter) DeepCopy() *DimensionFilter { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EvaluationCriteria) DeepCopyInto(out *EvaluationCriteria) { + *out = *in + if in.PromQLCriteria != nil { + in, out := &in.PromQLCriteria, &out.PromQLCriteria + *out = new(AlarmPromQLCriteria) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EvaluationCriteria. +func (in *EvaluationCriteria) DeepCopy() *EvaluationCriteria { + if in == nil { + return nil + } + out := new(EvaluationCriteria) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EvaluationWindow) DeepCopyInto(out *EvaluationWindow) { + *out = *in + if in.SlidingWindow != nil { + in, out := &in.SlidingWindow, &out.SlidingWindow + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } + if in.WallClockWindow != nil { + in, out := &in.WallClockWindow, &out.WallClockWindow + *out = new(WallClockWindow) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EvaluationWindow. +func (in *EvaluationWindow) DeepCopy() *EvaluationWindow { + if in == nil { + return nil + } + out := new(EvaluationWindow) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InsightRuleContributorDatapoint) DeepCopyInto(out *InsightRuleContributorDatapoint) { *out = *in @@ -511,6 +644,146 @@ func (in *InsightRuleMetricDatapoint) DeepCopy() *InsightRuleMetricDatapoint { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LogAlarm) DeepCopyInto(out *LogAlarm) { + *out = *in + if in.ActionLogLineCount != nil { + in, out := &in.ActionLogLineCount, &out.ActionLogLineCount + *out = new(int64) + **out = **in + } + if in.ActionLogLineRoleARN != nil { + in, out := &in.ActionLogLineRoleARN, &out.ActionLogLineRoleARN + *out = new(string) + **out = **in + } + if in.ActionsEnabled != nil { + in, out := &in.ActionsEnabled, &out.ActionsEnabled + *out = new(bool) + **out = **in + } + if in.AlarmActions != nil { + in, out := &in.AlarmActions, &out.AlarmActions + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.AlarmARN != nil { + in, out := &in.AlarmARN, &out.AlarmARN + *out = new(string) + **out = **in + } + if in.AlarmConfigurationUpdatedTimestamp != nil { + in, out := &in.AlarmConfigurationUpdatedTimestamp, &out.AlarmConfigurationUpdatedTimestamp + *out = (*in).DeepCopy() + } + if in.AlarmDescription != nil { + in, out := &in.AlarmDescription, &out.AlarmDescription + *out = new(string) + **out = **in + } + if in.AlarmName != nil { + in, out := &in.AlarmName, &out.AlarmName + *out = new(string) + **out = **in + } + if in.ComparisonOperator != nil { + in, out := &in.ComparisonOperator, &out.ComparisonOperator + *out = new(string) + **out = **in + } + if in.EvaluationState != nil { + in, out := &in.EvaluationState, &out.EvaluationState + *out = new(string) + **out = **in + } + if in.InsufficientDataActions != nil { + in, out := &in.InsufficientDataActions, &out.InsufficientDataActions + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.OKActions != nil { + in, out := &in.OKActions, &out.OKActions + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.QueryResultsToAlarm != nil { + in, out := &in.QueryResultsToAlarm, &out.QueryResultsToAlarm + *out = new(int64) + **out = **in + } + if in.QueryResultsToEvaluate != nil { + in, out := &in.QueryResultsToEvaluate, &out.QueryResultsToEvaluate + *out = new(int64) + **out = **in + } + if in.ScheduledQueryConfiguration != nil { + in, out := &in.ScheduledQueryConfiguration, &out.ScheduledQueryConfiguration + *out = new(ScheduledQueryConfiguration) + (*in).DeepCopyInto(*out) + } + if in.StateReason != nil { + in, out := &in.StateReason, &out.StateReason + *out = new(string) + **out = **in + } + if in.StateReasonData != nil { + in, out := &in.StateReasonData, &out.StateReasonData + *out = new(string) + **out = **in + } + if in.StateTransitionedTimestamp != nil { + in, out := &in.StateTransitionedTimestamp, &out.StateTransitionedTimestamp + *out = (*in).DeepCopy() + } + if in.StateUpdatedTimestamp != nil { + in, out := &in.StateUpdatedTimestamp, &out.StateUpdatedTimestamp + *out = (*in).DeepCopy() + } + if in.StateValue != nil { + in, out := &in.StateValue, &out.StateValue + *out = new(string) + **out = **in + } + if in.Threshold != nil { + in, out := &in.Threshold, &out.Threshold + *out = new(float64) + **out = **in + } + if in.TreatMissingData != nil { + in, out := &in.TreatMissingData, &out.TreatMissingData + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogAlarm. +func (in *LogAlarm) DeepCopy() *LogAlarm { + if in == nil { + return nil + } + out := new(LogAlarm) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ManagedRule) DeepCopyInto(out *ManagedRule) { *out = *in @@ -707,11 +980,26 @@ func (in *MetricAlarmSpec) DeepCopyInto(out *MetricAlarmSpec) { *out = new(string) **out = **in } + if in.EvaluationCriteria != nil { + in, out := &in.EvaluationCriteria, &out.EvaluationCriteria + *out = new(EvaluationCriteria) + (*in).DeepCopyInto(*out) + } + if in.EvaluationInterval != nil { + in, out := &in.EvaluationInterval, &out.EvaluationInterval + *out = new(int64) + **out = **in + } if in.EvaluationPeriods != nil { in, out := &in.EvaluationPeriods, &out.EvaluationPeriods *out = new(int64) **out = **in } + if in.EvaluationWindow != nil { + in, out := &in.EvaluationWindow, &out.EvaluationWindow + *out = new(EvaluationWindow) + (*in).DeepCopyInto(*out) + } if in.ExtendedStatistic != nil { in, out := &in.ExtendedStatistic, &out.ExtendedStatistic *out = new(string) @@ -913,6 +1201,16 @@ func (in *MetricAlarm_SDK) DeepCopyInto(out *MetricAlarm_SDK) { *out = new(string) **out = **in } + if in.EvaluationCriteria != nil { + in, out := &in.EvaluationCriteria, &out.EvaluationCriteria + *out = new(EvaluationCriteria) + (*in).DeepCopyInto(*out) + } + if in.EvaluationInterval != nil { + in, out := &in.EvaluationInterval, &out.EvaluationInterval + *out = new(int64) + **out = **in + } if in.EvaluationPeriods != nil { in, out := &in.EvaluationPeriods, &out.EvaluationPeriods *out = new(int64) @@ -923,6 +1221,11 @@ func (in *MetricAlarm_SDK) DeepCopyInto(out *MetricAlarm_SDK) { *out = new(string) **out = **in } + if in.EvaluationWindow != nil { + in, out := &in.EvaluationWindow, &out.EvaluationWindow + *out = new(EvaluationWindow) + (*in).DeepCopyInto(*out) + } if in.ExtendedStatistic != nil { in, out := &in.ExtendedStatistic, &out.ExtendedStatistic *out = new(string) @@ -1560,6 +1863,118 @@ func (in *Range) DeepCopy() *Range { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Schedule) DeepCopyInto(out *Schedule) { + *out = *in + if in.Timezone != nil { + in, out := &in.Timezone, &out.Timezone + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Schedule. +func (in *Schedule) DeepCopy() *Schedule { + if in == nil { + return nil + } + out := new(Schedule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScheduleConfiguration) DeepCopyInto(out *ScheduleConfiguration) { + *out = *in + if in.EndTimeOffset != nil { + in, out := &in.EndTimeOffset, &out.EndTimeOffset + *out = new(int64) + **out = **in + } + if in.ScheduleExpression != nil { + in, out := &in.ScheduleExpression, &out.ScheduleExpression + *out = new(string) + **out = **in + } + if in.StartTimeOffset != nil { + in, out := &in.StartTimeOffset, &out.StartTimeOffset + *out = new(int64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduleConfiguration. +func (in *ScheduleConfiguration) DeepCopy() *ScheduleConfiguration { + if in == nil { + return nil + } + out := new(ScheduleConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScheduledQueryConfiguration) DeepCopyInto(out *ScheduledQueryConfiguration) { + *out = *in + if in.AggregationExpression != nil { + in, out := &in.AggregationExpression, &out.AggregationExpression + *out = new(string) + **out = **in + } + if in.LogGroupIdentifiers != nil { + in, out := &in.LogGroupIdentifiers, &out.LogGroupIdentifiers + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.QueryARN != nil { + in, out := &in.QueryARN, &out.QueryARN + *out = new(string) + **out = **in + } + if in.QueryString != nil { + in, out := &in.QueryString, &out.QueryString + *out = new(string) + **out = **in + } + if in.ScheduleConfiguration != nil { + in, out := &in.ScheduleConfiguration, &out.ScheduleConfiguration + *out = new(ScheduleConfiguration) + (*in).DeepCopyInto(*out) + } + if in.ScheduledQueryRoleARN != nil { + in, out := &in.ScheduledQueryRoleARN, &out.ScheduledQueryRoleARN + *out = new(string) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]*Tag, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Tag) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduledQueryConfiguration. +func (in *ScheduledQueryConfiguration) DeepCopy() *ScheduledQueryConfiguration { + if in == nil { + return nil + } + out := new(ScheduledQueryConfiguration) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SingleMetricAnomalyDetector) DeepCopyInto(out *SingleMetricAnomalyDetector) { *out = *in @@ -1625,3 +2040,23 @@ func (in *Tag) DeepCopy() *Tag { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WallClockWindow) DeepCopyInto(out *WallClockWindow) { + *out = *in + if in.Timezone != nil { + in, out := &in.Timezone, &out.Timezone + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WallClockWindow. +func (in *WallClockWindow) DeepCopy() *WallClockWindow { + if in == nil { + return nil + } + out := new(WallClockWindow) + in.DeepCopyInto(out) + return out +} diff --git a/config/crd/bases/cloudwatch.services.k8s.aws_dashboards.yaml b/config/crd/bases/cloudwatch.services.k8s.aws_dashboards.yaml index e0b64f0..5e2e99c 100644 --- a/config/crd/bases/cloudwatch.services.k8s.aws_dashboards.yaml +++ b/config/crd/bases/cloudwatch.services.k8s.aws_dashboards.yaml @@ -46,7 +46,7 @@ spec: required. For more information about the syntax, see Dashboard Body Structure and Syntax - (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/CloudWatch-Dashboard-Body-Structure.html). + (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Dashboard-Body-Structure.html). type: string dashboardName: description: |- diff --git a/config/crd/bases/cloudwatch.services.k8s.aws_metricalarms.yaml b/config/crd/bases/cloudwatch.services.k8s.aws_metricalarms.yaml index 585b296..34ad608 100644 --- a/config/crd/bases/cloudwatch.services.k8s.aws_metricalarms.yaml +++ b/config/crd/bases/cloudwatch.services.k8s.aws_metricalarms.yaml @@ -95,7 +95,7 @@ spec: Start a Amazon Q Developer operational investigation - arn:aws:aiops:region:account-id:investigation-group:ingestigation-group-id + arn:aws:aiops:region:account-id:investigation-group:investigation-group-id items: type: string type: array @@ -149,17 +149,100 @@ spec: Valid Values: evaluate | ignore type: string + evaluationCriteria: + description: |- + The evaluation criteria for the alarm. For each PutMetricAlarm operation, + you must specify either MetricName, a Metrics array, or an EvaluationCriteria. + + If you use the EvaluationCriteria parameter, you cannot include the Namespace, + MetricName, Dimensions, Period, Unit, Statistic, ExtendedStatistic, Metrics, + Threshold, ComparisonOperator, ThresholdMetricId, EvaluationPeriods, or DatapointsToAlarm + parameters of PutMetricAlarm in the same operation. Instead, all evaluation + parameters are defined within this structure. + + For an example of how to use this parameter, see the PromQL alarm example + on this page. + properties: + promQLCriteria: + description: |- + Contains the configuration that determines how a PromQL alarm evaluates its + contributors, including the query to run and the durations that define when + contributors transition between states. + properties: + pendingPeriod: + format: int64 + type: integer + query: + type: string + recoveryPeriod: + format: int64 + type: integer + type: object + type: object + evaluationInterval: + description: |- + The frequency, in seconds, at which the alarm is evaluated. Valid values + are 10, 20, 30, and any multiple of 60. + + This parameter is required for alarms that use EvaluationCriteria, and cannot + be specified for alarms configured with MetricName or Metrics. + format: int64 + type: integer evaluationPeriods: description: |- The number of periods over which data is compared to the specified threshold. If you are setting an alarm that requires that a number of consecutive data points be breaching to trigger the alarm, this value specifies that number. If you are setting an "M out of N" alarm, this value is the N. - - An alarm's total current evaluation period can be no longer than one day, - so this number multiplied by Period cannot be more than 86,400 seconds. format: int64 type: integer + evaluationWindow: + description: |- + The evaluation window that the alarm uses to select the range of metric data + that it evaluates. Specify either a sliding window or a wall clock window. + If you omit this parameter, the alarm uses a sliding window. + + A sliding window advances each time the alarm is evaluated, forming a rolling + time window. A wall clock window aligns the evaluated range to fixed clock + boundaries, such as the top of the hour or the start of the day. + + You can use EvaluationWindow with any type of metric alarm except alarms + that are based on a PromQL query. + + For more information, see Alarm evaluation windows (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/alarm-evaluation-window.html) + in the CloudWatch User Guide. + properties: + slidingWindow: + additionalProperties: + type: string + description: |- + An evaluation window that advances each time the alarm is evaluated, forming + a rolling time window. This is the default evaluation window. A sliding window + has no additional configuration options. + + Choose a sliding window when you need the fastest detection and the calendar + boundaries of the data don't matter, such as for continuous performance, + latency, or resource-exhaustion monitoring. + type: object + wallClockWindow: + description: |- + An evaluation window that aligns the evaluated range to fixed clock boundaries + that match the alarm's period, such as the top of the hour, midnight, or + the start of the calendar week, optionally in a specific time zone. + + When you use a wall clock window, the alarm's period must be 1 minute (60 + seconds), 5 minutes (300 seconds), 1 hour (3,600 seconds), 1 day (86,400 + seconds), or 1 week (604,800 seconds). Other period values aren't supported + with a wall clock window. + + Choose a wall clock window when your monitoring is tied to a business or + calendar period, such as daily reports, batch jobs, or backups, or when you + want alarm evaluations to match the periods shown on a metric dashboard. + properties: + timezone: + type: string + type: object + type: object extendedStatistic: description: |- The extended statistic for the metric specified in MetricName. When you call @@ -244,7 +327,7 @@ spec: metricName: description: |- The name for the metric associated with the alarm. For each PutMetricAlarm - operation, you must specify either MetricName or a Metrics array. + operation, you must specify either MetricName, a Metrics array, or an EvaluationCriteria. If you are creating an alarm based on a math expression, you cannot specify this parameter, or any of the Namespace, Dimensions, Period, Unit, Statistic, @@ -255,7 +338,7 @@ spec: description: |- An array of MetricDataQuery structures that enable you to create an alarm based on the result of a metric math expression. For each PutMetricAlarm - operation, you must specify either MetricName or a Metrics array. + operation, you must specify either MetricName, a Metrics array, or an EvaluationCriteria. Each item in the Metrics array either retrieves a metric or performs a math expression. @@ -414,24 +497,26 @@ spec: period: description: |- The length, in seconds, used each time the metric specified in MetricName - is evaluated. Valid values are 10, 30, and any multiple of 60. + is evaluated. Valid values are 10, 20, 30, and any multiple of 60. Period is required for alarms based on static thresholds. If you are creating an alarm based on a metric math expression, you specify the period for each metric within the objects in the Metrics array. - Be sure to specify 10 or 30 only for metrics that are stored by a PutMetricData - call with a StorageResolution of 1. If you specify a period of 10 or 30 for - a metric that does not have sub-minute resolution, the alarm still attempts - to gather data at the period rate that you specify. In this case, it does - not receive data for the attempts that do not correspond to a one-minute + Be sure to specify 10, 20, or 30 only for metrics that are stored by a PutMetricData + call with a StorageResolution of 1. If you specify a period of 10, 20, or + 30 for a metric that does not have sub-minute resolution, the alarm still + attempts to gather data at the period rate that you specify. In this case, + it does not receive data for the attempts that do not correspond to a one-minute data resolution, and the alarm might often lapse into INSUFFICENT_DATA status. - Specifying 10 or 30 also sets this alarm as a high-resolution alarm, which - has a higher charge than other alarms. For more information about pricing, + Specifying 10, 20, or 30 also sets this alarm as a high-resolution alarm, + which has a higher charge than other alarms. For more information about pricing, see Amazon CloudWatch Pricing (https://aws.amazon.com/cloudwatch/pricing/). - An alarm's total current evaluation period can be no longer than one day, - so Period multiplied by EvaluationPeriods cannot be more than 86,400 seconds. + An alarm's total current evaluation period can be no longer than seven days, + so Period multiplied by EvaluationPeriods can't be more than 604,800 seconds. + For alarms with a period of less than one hour (3,600 seconds), the total + evaluation period can't be longer than one day (86,400 seconds). format: int64 type: integer statistic: @@ -497,6 +582,8 @@ spec: missing data even if you choose a different option for TreatMissingData. When an AWS/DynamoDB metric has missing data, alarms that evaluate that metric remain in their current state. + + This parameter is not applicable to PromQL alarms. type: string unit: description: |- @@ -522,8 +609,6 @@ spec: be stuck in the INSUFFICIENT DATA state. type: string required: - - comparisonOperator - - evaluationPeriods - name type: object status: diff --git a/generator.yaml b/generator.yaml index 7d4ef90..c3974a1 100644 --- a/generator.yaml +++ b/generator.yaml @@ -1,3 +1,5 @@ +empty_shapes: + - SlidingWindow ignore: resource_names: - AnomalyDetector @@ -5,6 +7,8 @@ ignore: - InsightRule - ManagedInsightRule # - MetricStream + field_paths: + - PutDashboardInput.Tags operations: DeleteAlarms: operation_type: @@ -92,4 +96,4 @@ resources: - InvalidParameterValueException - InvalidParameterInput tags: - ignore: true \ No newline at end of file + ignore: true diff --git a/go.mod b/go.mod index e81eeca..b8b4502 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ require ( github.com/aws-controllers-k8s/iam-controller v1.7.2 github.com/aws-controllers-k8s/runtime v0.61.0 github.com/aws/aws-sdk-go v1.49.0 - github.com/aws/aws-sdk-go-v2 v1.39.0 - github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.43.12 - github.com/aws/smithy-go v1.23.0 + github.com/aws/aws-sdk-go-v2 v1.43.0 + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.65.0 + github.com/aws/smithy-go v1.27.3 github.com/go-logr/logr v1.4.3 github.com/spf13/pflag v1.0.9 k8s.io/api v0.35.0 @@ -22,8 +22,8 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.28.6 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.47 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.7 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.7 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.31 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.31 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.10 // indirect diff --git a/go.sum b/go.sum index 3624619..18159c4 100644 --- a/go.sum +++ b/go.sum @@ -8,22 +8,22 @@ github.com/aws-controllers-k8s/runtime v0.61.0 h1:46ksj9nvW5gx86aB44/zfrZOvJj4G7 github.com/aws-controllers-k8s/runtime v0.61.0/go.mod h1:Ovpk9GCCc/3hekVN6CL0cZhsG41JqSvIb8DXwaEwL34= github.com/aws/aws-sdk-go v1.49.0 h1:g9BkW1fo9GqKfwg2+zCD+TW/D36Ux+vtfJ8guF4AYmY= github.com/aws/aws-sdk-go v1.49.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.39.0 h1:xm5WV/2L4emMRmMjHFykqiA4M/ra0DJVSWUkDyBjbg4= -github.com/aws/aws-sdk-go-v2 v1.39.0/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= +github.com/aws/aws-sdk-go-v2 v1.43.0 h1:fharf/WhbRAVZ1du0QL7roNFxZ6T/sWr+4Ni617bwSI= +github.com/aws/aws-sdk-go-v2 v1.43.0/go.mod h1:5pKeft2eJj+gElQ38Jqg4ibCqh+/AK33/0X3hip7IjM= github.com/aws/aws-sdk-go-v2/config v1.28.6 h1:D89IKtGrs/I3QXOLNTH93NJYtDhm8SYa9Q5CsPShmyo= github.com/aws/aws-sdk-go-v2/config v1.28.6/go.mod h1:GDzxJ5wyyFSCoLkS+UhGB0dArhb9mI+Co4dHtoTxbko= github.com/aws/aws-sdk-go-v2/credentials v1.17.47 h1:48bA+3/fCdi2yAwVt+3COvmatZ6jUDNkDTIsqDiMUdw= github.com/aws/aws-sdk-go-v2/credentials v1.17.47/go.mod h1:+KdckOejLW3Ks3b0E3b5rHsr2f9yuORBum0WPnE5o5w= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 h1:AmoU1pziydclFT/xRV+xXE/Vb8fttJCLRPv8oAkprc0= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21/go.mod h1:AjUdLYe4Tgs6kpH4Bv7uMZo7pottoyHMn4eTcIcneaY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.7 h1:UCxq0X9O3xrlENdKf1r9eRJoKz/b0AfGkpp3a7FPlhg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.7/go.mod h1:rHRoJUNUASj5Z/0eqI4w32vKvC7atoWR0jC+IkmVH8k= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.7 h1:Y6DTZUn7ZUC4th9FMBbo8LVE+1fyq3ofw+tRwkUd3PY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.7/go.mod h1:x3XE6vMnU9QvHN/Wrx2s44kwzV2o2g5x/siw4ZUJ9g8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.31 h1:Z8F3hfCY33IGpJjFAnv0wvtv1FIKj1GHmRDEYqy64tw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.31/go.mod h1:aVyUoytEyOViR6jhq6jula0xkc5NfBE2hgeF6BvOrao= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.31 h1:hyOxUyXdh3AyjE93gBgsfziJag9ACwcs+ZpDBLzi8mw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.31/go.mod h1:OERqI9k0draSLB8O8woxY3q25ZWTELRK4RRoLMuMZFo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.43.12 h1:SZE/PDYBlP0+SoSVMQUHq5KFTkUccurn99yr1LiLroQ= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.43.12/go.mod h1:LZrHBC9LwAoFniu+0g8csH9Jz20Es0AoeIxF6bNh6tQ= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.65.0 h1:mthzbb+JegG3ij6kCilO/tPPVT+ohq0dA/mc3kHFHDo= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.65.0/go.mod h1:t3drm8DC/zlLUm3MvhkgD4Me6U6EJjzO+ZhcBzWxkcc= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.10 h1:hN4yJBGswmFTOVYqmbz1GBs9ZMtQe8SrYxPwrkrlRv8= @@ -34,8 +34,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 h1:JnhTZR3PiYDNKlXy50/pNeix github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6/go.mod h1:URronUEGfXZN1VpdktPSD1EkAL9mfrV+2F4sjH38qOY= github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 h1:s4074ZO1Hk8qv65GqNXqDjmkf4HSQqJukaLuuW0TpDA= github.com/aws/aws-sdk-go-v2/service/sts v1.33.2/go.mod h1:mVggCnIWoM09jP71Wh+ea7+5gAp53q+49wDFs1SW5z8= -github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE= -github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/smithy-go v1.27.3 h1:F3Zb497UhhskkfpJmfkXswyo+t0sh9OTBnIHjogWbVY= +github.com/aws/smithy-go v1.27.3/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= diff --git a/helm/crds/cloudwatch.services.k8s.aws_dashboards.yaml b/helm/crds/cloudwatch.services.k8s.aws_dashboards.yaml index e0b64f0..5e2e99c 100644 --- a/helm/crds/cloudwatch.services.k8s.aws_dashboards.yaml +++ b/helm/crds/cloudwatch.services.k8s.aws_dashboards.yaml @@ -46,7 +46,7 @@ spec: required. For more information about the syntax, see Dashboard Body Structure and Syntax - (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/CloudWatch-Dashboard-Body-Structure.html). + (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Dashboard-Body-Structure.html). type: string dashboardName: description: |- diff --git a/helm/crds/cloudwatch.services.k8s.aws_metricalarms.yaml b/helm/crds/cloudwatch.services.k8s.aws_metricalarms.yaml index 8f53dd4..ebc730a 100644 --- a/helm/crds/cloudwatch.services.k8s.aws_metricalarms.yaml +++ b/helm/crds/cloudwatch.services.k8s.aws_metricalarms.yaml @@ -95,7 +95,7 @@ spec: # Start a Amazon Q Developer operational investigation - arn:aws:aiops:region:account-id:investigation-group:ingestigation-group-id + arn:aws:aiops:region:account-id:investigation-group:investigation-group-id items: type: string type: array @@ -149,17 +149,100 @@ spec: Valid Values: evaluate | ignore type: string + evaluationCriteria: + description: |- + The evaluation criteria for the alarm. For each PutMetricAlarm operation, + you must specify either MetricName, a Metrics array, or an EvaluationCriteria. + + If you use the EvaluationCriteria parameter, you cannot include the Namespace, + MetricName, Dimensions, Period, Unit, Statistic, ExtendedStatistic, Metrics, + Threshold, ComparisonOperator, ThresholdMetricId, EvaluationPeriods, or DatapointsToAlarm + parameters of PutMetricAlarm in the same operation. Instead, all evaluation + parameters are defined within this structure. + + For an example of how to use this parameter, see the PromQL alarm example + on this page. + properties: + promQLCriteria: + description: |- + Contains the configuration that determines how a PromQL alarm evaluates its + contributors, including the query to run and the durations that define when + contributors transition between states. + properties: + pendingPeriod: + format: int64 + type: integer + query: + type: string + recoveryPeriod: + format: int64 + type: integer + type: object + type: object + evaluationInterval: + description: |- + The frequency, in seconds, at which the alarm is evaluated. Valid values + are 10, 20, 30, and any multiple of 60. + + This parameter is required for alarms that use EvaluationCriteria, and cannot + be specified for alarms configured with MetricName or Metrics. + format: int64 + type: integer evaluationPeriods: description: |- The number of periods over which data is compared to the specified threshold. If you are setting an alarm that requires that a number of consecutive data points be breaching to trigger the alarm, this value specifies that number. If you are setting an "M out of N" alarm, this value is the N. - - An alarm's total current evaluation period can be no longer than one day, - so this number multiplied by Period cannot be more than 86,400 seconds. format: int64 type: integer + evaluationWindow: + description: |- + The evaluation window that the alarm uses to select the range of metric data + that it evaluates. Specify either a sliding window or a wall clock window. + If you omit this parameter, the alarm uses a sliding window. + + A sliding window advances each time the alarm is evaluated, forming a rolling + time window. A wall clock window aligns the evaluated range to fixed clock + boundaries, such as the top of the hour or the start of the day. + + You can use EvaluationWindow with any type of metric alarm except alarms + that are based on a PromQL query. + + For more information, see Alarm evaluation windows (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/alarm-evaluation-window.html) + in the CloudWatch User Guide. + properties: + slidingWindow: + additionalProperties: + type: string + description: |- + An evaluation window that advances each time the alarm is evaluated, forming + a rolling time window. This is the default evaluation window. A sliding window + has no additional configuration options. + + Choose a sliding window when you need the fastest detection and the calendar + boundaries of the data don't matter, such as for continuous performance, + latency, or resource-exhaustion monitoring. + type: object + wallClockWindow: + description: |- + An evaluation window that aligns the evaluated range to fixed clock boundaries + that match the alarm's period, such as the top of the hour, midnight, or + the start of the calendar week, optionally in a specific time zone. + + When you use a wall clock window, the alarm's period must be 1 minute (60 + seconds), 5 minutes (300 seconds), 1 hour (3,600 seconds), 1 day (86,400 + seconds), or 1 week (604,800 seconds). Other period values aren't supported + with a wall clock window. + + Choose a wall clock window when your monitoring is tied to a business or + calendar period, such as daily reports, batch jobs, or backups, or when you + want alarm evaluations to match the periods shown on a metric dashboard. + properties: + timezone: + type: string + type: object + type: object extendedStatistic: description: |- The extended statistic for the metric specified in MetricName. When you call @@ -244,7 +327,7 @@ spec: metricName: description: |- The name for the metric associated with the alarm. For each PutMetricAlarm - operation, you must specify either MetricName or a Metrics array. + operation, you must specify either MetricName, a Metrics array, or an EvaluationCriteria. If you are creating an alarm based on a math expression, you cannot specify this parameter, or any of the Namespace, Dimensions, Period, Unit, Statistic, @@ -255,7 +338,7 @@ spec: description: |- An array of MetricDataQuery structures that enable you to create an alarm based on the result of a metric math expression. For each PutMetricAlarm - operation, you must specify either MetricName or a Metrics array. + operation, you must specify either MetricName, a Metrics array, or an EvaluationCriteria. Each item in the Metrics array either retrieves a metric or performs a math expression. @@ -414,24 +497,26 @@ spec: period: description: |- The length, in seconds, used each time the metric specified in MetricName - is evaluated. Valid values are 10, 30, and any multiple of 60. + is evaluated. Valid values are 10, 20, 30, and any multiple of 60. Period is required for alarms based on static thresholds. If you are creating an alarm based on a metric math expression, you specify the period for each metric within the objects in the Metrics array. - Be sure to specify 10 or 30 only for metrics that are stored by a PutMetricData - call with a StorageResolution of 1. If you specify a period of 10 or 30 for - a metric that does not have sub-minute resolution, the alarm still attempts - to gather data at the period rate that you specify. In this case, it does - not receive data for the attempts that do not correspond to a one-minute + Be sure to specify 10, 20, or 30 only for metrics that are stored by a PutMetricData + call with a StorageResolution of 1. If you specify a period of 10, 20, or + 30 for a metric that does not have sub-minute resolution, the alarm still + attempts to gather data at the period rate that you specify. In this case, + it does not receive data for the attempts that do not correspond to a one-minute data resolution, and the alarm might often lapse into INSUFFICENT_DATA status. - Specifying 10 or 30 also sets this alarm as a high-resolution alarm, which - has a higher charge than other alarms. For more information about pricing, + Specifying 10, 20, or 30 also sets this alarm as a high-resolution alarm, + which has a higher charge than other alarms. For more information about pricing, see Amazon CloudWatch Pricing (https://aws.amazon.com/cloudwatch/pricing/). - An alarm's total current evaluation period can be no longer than one day, - so Period multiplied by EvaluationPeriods cannot be more than 86,400 seconds. + An alarm's total current evaluation period can be no longer than seven days, + so Period multiplied by EvaluationPeriods can't be more than 604,800 seconds. + For alarms with a period of less than one hour (3,600 seconds), the total + evaluation period can't be longer than one day (86,400 seconds). format: int64 type: integer statistic: @@ -497,6 +582,8 @@ spec: missing data even if you choose a different option for TreatMissingData. When an AWS/DynamoDB metric has missing data, alarms that evaluate that metric remain in their current state. + + This parameter is not applicable to PromQL alarms. type: string unit: description: |- @@ -522,8 +609,6 @@ spec: be stuck in the INSUFFICIENT DATA state. type: string required: - - comparisonOperator - - evaluationPeriods - name type: object status: diff --git a/pkg/resource/metric_alarm/delta.go b/pkg/resource/metric_alarm/delta.go index 91699ba..19557f5 100644 --- a/pkg/resource/metric_alarm/delta.go +++ b/pkg/resource/metric_alarm/delta.go @@ -91,6 +91,42 @@ func newResourceDelta( delta.Add("Spec.EvaluateLowSampleCountPercentile", a.ko.Spec.EvaluateLowSampleCountPercentile, b.ko.Spec.EvaluateLowSampleCountPercentile) } } + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationCriteria, b.ko.Spec.EvaluationCriteria) { + delta.Add("Spec.EvaluationCriteria", a.ko.Spec.EvaluationCriteria, b.ko.Spec.EvaluationCriteria) + } else if a.ko.Spec.EvaluationCriteria != nil && b.ko.Spec.EvaluationCriteria != nil { + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationCriteria.PromQLCriteria, b.ko.Spec.EvaluationCriteria.PromQLCriteria) { + delta.Add("Spec.EvaluationCriteria.PromQLCriteria", a.ko.Spec.EvaluationCriteria.PromQLCriteria, b.ko.Spec.EvaluationCriteria.PromQLCriteria) + } else if a.ko.Spec.EvaluationCriteria.PromQLCriteria != nil && b.ko.Spec.EvaluationCriteria.PromQLCriteria != nil { + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod, b.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod) { + delta.Add("Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod", a.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod, b.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod) + } else if a.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod != nil && b.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod != nil { + if *a.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod != *b.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod { + delta.Add("Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod", a.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod, b.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationCriteria.PromQLCriteria.Query, b.ko.Spec.EvaluationCriteria.PromQLCriteria.Query) { + delta.Add("Spec.EvaluationCriteria.PromQLCriteria.Query", a.ko.Spec.EvaluationCriteria.PromQLCriteria.Query, b.ko.Spec.EvaluationCriteria.PromQLCriteria.Query) + } else if a.ko.Spec.EvaluationCriteria.PromQLCriteria.Query != nil && b.ko.Spec.EvaluationCriteria.PromQLCriteria.Query != nil { + if *a.ko.Spec.EvaluationCriteria.PromQLCriteria.Query != *b.ko.Spec.EvaluationCriteria.PromQLCriteria.Query { + delta.Add("Spec.EvaluationCriteria.PromQLCriteria.Query", a.ko.Spec.EvaluationCriteria.PromQLCriteria.Query, b.ko.Spec.EvaluationCriteria.PromQLCriteria.Query) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod, b.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod) { + delta.Add("Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod", a.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod, b.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod) + } else if a.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod != nil && b.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod != nil { + if *a.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod != *b.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod { + delta.Add("Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod", a.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod, b.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod) + } + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationInterval, b.ko.Spec.EvaluationInterval) { + delta.Add("Spec.EvaluationInterval", a.ko.Spec.EvaluationInterval, b.ko.Spec.EvaluationInterval) + } else if a.ko.Spec.EvaluationInterval != nil && b.ko.Spec.EvaluationInterval != nil { + if *a.ko.Spec.EvaluationInterval != *b.ko.Spec.EvaluationInterval { + delta.Add("Spec.EvaluationInterval", a.ko.Spec.EvaluationInterval, b.ko.Spec.EvaluationInterval) + } + } if ackcompare.HasNilDifference(a.ko.Spec.EvaluationPeriods, b.ko.Spec.EvaluationPeriods) { delta.Add("Spec.EvaluationPeriods", a.ko.Spec.EvaluationPeriods, b.ko.Spec.EvaluationPeriods) } else if a.ko.Spec.EvaluationPeriods != nil && b.ko.Spec.EvaluationPeriods != nil { @@ -98,6 +134,25 @@ func newResourceDelta( delta.Add("Spec.EvaluationPeriods", a.ko.Spec.EvaluationPeriods, b.ko.Spec.EvaluationPeriods) } } + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationWindow, b.ko.Spec.EvaluationWindow) { + delta.Add("Spec.EvaluationWindow", a.ko.Spec.EvaluationWindow, b.ko.Spec.EvaluationWindow) + } else if a.ko.Spec.EvaluationWindow != nil && b.ko.Spec.EvaluationWindow != nil { + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationWindow.SlidingWindow, b.ko.Spec.EvaluationWindow.SlidingWindow) { + delta.Add("Spec.EvaluationWindow.SlidingWindow", a.ko.Spec.EvaluationWindow.SlidingWindow, b.ko.Spec.EvaluationWindow.SlidingWindow) + } else if a.ko.Spec.EvaluationWindow.SlidingWindow != nil && b.ko.Spec.EvaluationWindow.SlidingWindow != nil { + } + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationWindow.WallClockWindow, b.ko.Spec.EvaluationWindow.WallClockWindow) { + delta.Add("Spec.EvaluationWindow.WallClockWindow", a.ko.Spec.EvaluationWindow.WallClockWindow, b.ko.Spec.EvaluationWindow.WallClockWindow) + } else if a.ko.Spec.EvaluationWindow.WallClockWindow != nil && b.ko.Spec.EvaluationWindow.WallClockWindow != nil { + if ackcompare.HasNilDifference(a.ko.Spec.EvaluationWindow.WallClockWindow.Timezone, b.ko.Spec.EvaluationWindow.WallClockWindow.Timezone) { + delta.Add("Spec.EvaluationWindow.WallClockWindow.Timezone", a.ko.Spec.EvaluationWindow.WallClockWindow.Timezone, b.ko.Spec.EvaluationWindow.WallClockWindow.Timezone) + } else if a.ko.Spec.EvaluationWindow.WallClockWindow.Timezone != nil && b.ko.Spec.EvaluationWindow.WallClockWindow.Timezone != nil { + if *a.ko.Spec.EvaluationWindow.WallClockWindow.Timezone != *b.ko.Spec.EvaluationWindow.WallClockWindow.Timezone { + delta.Add("Spec.EvaluationWindow.WallClockWindow.Timezone", a.ko.Spec.EvaluationWindow.WallClockWindow.Timezone, b.ko.Spec.EvaluationWindow.WallClockWindow.Timezone) + } + } + } + } if ackcompare.HasNilDifference(a.ko.Spec.ExtendedStatistic, b.ko.Spec.ExtendedStatistic) { delta.Add("Spec.ExtendedStatistic", a.ko.Spec.ExtendedStatistic, b.ko.Spec.ExtendedStatistic) } else if a.ko.Spec.ExtendedStatistic != nil && b.ko.Spec.ExtendedStatistic != nil { diff --git a/pkg/resource/metric_alarm/sdk.go b/pkg/resource/metric_alarm/sdk.go index 1b83373..230f133 100644 --- a/pkg/resource/metric_alarm/sdk.go +++ b/pkg/resource/metric_alarm/sdk.go @@ -141,12 +141,66 @@ func (rm *resourceManager) sdkFind( } else { ko.Spec.EvaluateLowSampleCountPercentile = nil } + if elem.EvaluationCriteria != nil { + f10 := &svcapitypes.EvaluationCriteria{} + switch elem.EvaluationCriteria.(type) { + case *svcsdktypes.EvaluationCriteriaMemberPromQLCriteria: + f10f0 := elem.EvaluationCriteria.(*svcsdktypes.EvaluationCriteriaMemberPromQLCriteria) + if f10f0 != nil { + f10f0f0 := &svcapitypes.AlarmPromQLCriteria{} + if f10f0.Value.PendingPeriod != nil { + pendingPeriodCopy := int64(*f10f0.Value.PendingPeriod) + f10f0f0.PendingPeriod = &pendingPeriodCopy + } + if f10f0.Value.Query != nil { + f10f0f0.Query = f10f0.Value.Query + } + if f10f0.Value.RecoveryPeriod != nil { + recoveryPeriodCopy := int64(*f10f0.Value.RecoveryPeriod) + f10f0f0.RecoveryPeriod = &recoveryPeriodCopy + } + f10.PromQLCriteria = f10f0f0 + } + } + ko.Spec.EvaluationCriteria = f10 + } else { + ko.Spec.EvaluationCriteria = nil + } + if elem.EvaluationInterval != nil { + evaluationIntervalCopy := int64(*elem.EvaluationInterval) + ko.Spec.EvaluationInterval = &evaluationIntervalCopy + } else { + ko.Spec.EvaluationInterval = nil + } if elem.EvaluationPeriods != nil { evaluationPeriodsCopy := int64(*elem.EvaluationPeriods) ko.Spec.EvaluationPeriods = &evaluationPeriodsCopy } else { ko.Spec.EvaluationPeriods = nil } + if elem.EvaluationWindow != nil { + f14 := &svcapitypes.EvaluationWindow{} + switch elem.EvaluationWindow.(type) { + case *svcsdktypes.EvaluationWindowMemberSlidingWindow: + f14f0 := elem.EvaluationWindow.(*svcsdktypes.EvaluationWindowMemberSlidingWindow) + if f14f0 != nil { + f14f0f0 := map[string]*string{} + f14.SlidingWindow = f14f0f0 + } + case *svcsdktypes.EvaluationWindowMemberWallClockWindow: + f14f1 := elem.EvaluationWindow.(*svcsdktypes.EvaluationWindowMemberWallClockWindow) + if f14f1 != nil { + f14f1f1 := &svcapitypes.WallClockWindow{} + if f14f1.Value.Timezone != nil { + f14f1f1.Timezone = f14f1.Value.Timezone + } + f14.WallClockWindow = f14f1f1 + } + } + ko.Spec.EvaluationWindow = f14 + } else { + ko.Spec.EvaluationWindow = nil + } if elem.ExtendedStatistic != nil { ko.Spec.ExtendedStatistic = elem.ExtendedStatistic } else { @@ -163,69 +217,69 @@ func (rm *resourceManager) sdkFind( ko.Spec.MetricName = nil } if elem.Metrics != nil { - f15 := []*svcapitypes.MetricDataQuery{} - for _, f15iter := range elem.Metrics { - f15elem := &svcapitypes.MetricDataQuery{} - if f15iter.AccountId != nil { - f15elem.AccountID = f15iter.AccountId + f18 := []*svcapitypes.MetricDataQuery{} + for _, f18iter := range elem.Metrics { + f18elem := &svcapitypes.MetricDataQuery{} + if f18iter.AccountId != nil { + f18elem.AccountID = f18iter.AccountId } - if f15iter.Expression != nil { - f15elem.Expression = f15iter.Expression + if f18iter.Expression != nil { + f18elem.Expression = f18iter.Expression } - if f15iter.Id != nil { - f15elem.ID = f15iter.Id + if f18iter.Id != nil { + f18elem.ID = f18iter.Id } - if f15iter.Label != nil { - f15elem.Label = f15iter.Label + if f18iter.Label != nil { + f18elem.Label = f18iter.Label } - if f15iter.MetricStat != nil { - f15elemf4 := &svcapitypes.MetricStat{} - if f15iter.MetricStat.Metric != nil { - f15elemf4f0 := &svcapitypes.Metric{} - if f15iter.MetricStat.Metric.Dimensions != nil { - f15elemf4f0f0 := []*svcapitypes.Dimension{} - for _, f15elemf4f0f0iter := range f15iter.MetricStat.Metric.Dimensions { - f15elemf4f0f0elem := &svcapitypes.Dimension{} - if f15elemf4f0f0iter.Name != nil { - f15elemf4f0f0elem.Name = f15elemf4f0f0iter.Name + if f18iter.MetricStat != nil { + f18elemf4 := &svcapitypes.MetricStat{} + if f18iter.MetricStat.Metric != nil { + f18elemf4f0 := &svcapitypes.Metric{} + if f18iter.MetricStat.Metric.Dimensions != nil { + f18elemf4f0f0 := []*svcapitypes.Dimension{} + for _, f18elemf4f0f0iter := range f18iter.MetricStat.Metric.Dimensions { + f18elemf4f0f0elem := &svcapitypes.Dimension{} + if f18elemf4f0f0iter.Name != nil { + f18elemf4f0f0elem.Name = f18elemf4f0f0iter.Name } - if f15elemf4f0f0iter.Value != nil { - f15elemf4f0f0elem.Value = f15elemf4f0f0iter.Value + if f18elemf4f0f0iter.Value != nil { + f18elemf4f0f0elem.Value = f18elemf4f0f0iter.Value } - f15elemf4f0f0 = append(f15elemf4f0f0, f15elemf4f0f0elem) + f18elemf4f0f0 = append(f18elemf4f0f0, f18elemf4f0f0elem) } - f15elemf4f0.Dimensions = f15elemf4f0f0 + f18elemf4f0.Dimensions = f18elemf4f0f0 } - if f15iter.MetricStat.Metric.MetricName != nil { - f15elemf4f0.MetricName = f15iter.MetricStat.Metric.MetricName + if f18iter.MetricStat.Metric.MetricName != nil { + f18elemf4f0.MetricName = f18iter.MetricStat.Metric.MetricName } - if f15iter.MetricStat.Metric.Namespace != nil { - f15elemf4f0.Namespace = f15iter.MetricStat.Metric.Namespace + if f18iter.MetricStat.Metric.Namespace != nil { + f18elemf4f0.Namespace = f18iter.MetricStat.Metric.Namespace } - f15elemf4.Metric = f15elemf4f0 + f18elemf4.Metric = f18elemf4f0 } - if f15iter.MetricStat.Period != nil { - periodCopy := int64(*f15iter.MetricStat.Period) - f15elemf4.Period = &periodCopy + if f18iter.MetricStat.Period != nil { + periodCopy := int64(*f18iter.MetricStat.Period) + f18elemf4.Period = &periodCopy } - if f15iter.MetricStat.Stat != nil { - f15elemf4.Stat = f15iter.MetricStat.Stat + if f18iter.MetricStat.Stat != nil { + f18elemf4.Stat = f18iter.MetricStat.Stat } - if f15iter.MetricStat.Unit != "" { - f15elemf4.Unit = aws.String(string(f15iter.MetricStat.Unit)) + if f18iter.MetricStat.Unit != "" { + f18elemf4.Unit = aws.String(string(f18iter.MetricStat.Unit)) } - f15elem.MetricStat = f15elemf4 + f18elem.MetricStat = f18elemf4 } - if f15iter.Period != nil { - periodCopy := int64(*f15iter.Period) - f15elem.Period = &periodCopy + if f18iter.Period != nil { + periodCopy := int64(*f18iter.Period) + f18elem.Period = &periodCopy } - if f15iter.ReturnData != nil { - f15elem.ReturnData = f15iter.ReturnData + if f18iter.ReturnData != nil { + f18elem.ReturnData = f18iter.ReturnData } - f15 = append(f15, f15elem) + f18 = append(f18, f18elem) } - ko.Spec.Metrics = f15 + ko.Spec.Metrics = f18 } else { ko.Spec.Metrics = nil } @@ -380,6 +434,48 @@ func (rm *resourceManager) newCreateRequestPayload( if r.ko.Spec.EvaluateLowSampleCountPercentile != nil { res.EvaluateLowSampleCountPercentile = r.ko.Spec.EvaluateLowSampleCountPercentile } + if r.ko.Spec.EvaluationCriteria != nil { + var f8 svcsdktypes.EvaluationCriteria + isInterfaceSet := false + if r.ko.Spec.EvaluationCriteria.PromQLCriteria != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for PromQLCriteria")) + } + f8f0Parent := &svcsdktypes.EvaluationCriteriaMemberPromQLCriteria{} + f8f0 := &svcsdktypes.AlarmPromQLCriteria{} + if r.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod != nil { + pendingPeriodCopy0 := *r.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod + if pendingPeriodCopy0 > math.MaxInt32 || pendingPeriodCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field PendingPeriod is of type int32") + } + pendingPeriodCopy := int32(pendingPeriodCopy0) + f8f0.PendingPeriod = &pendingPeriodCopy + } + if r.ko.Spec.EvaluationCriteria.PromQLCriteria.Query != nil { + f8f0.Query = r.ko.Spec.EvaluationCriteria.PromQLCriteria.Query + } + if r.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod != nil { + recoveryPeriodCopy0 := *r.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod + if recoveryPeriodCopy0 > math.MaxInt32 || recoveryPeriodCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field RecoveryPeriod is of type int32") + } + recoveryPeriodCopy := int32(recoveryPeriodCopy0) + f8f0.RecoveryPeriod = &recoveryPeriodCopy + } + f8f0Parent.Value = *f8f0 + f8 = f8f0Parent + isInterfaceSet = true + } + res.EvaluationCriteria = f8 + } + if r.ko.Spec.EvaluationInterval != nil { + evaluationIntervalCopy0 := *r.ko.Spec.EvaluationInterval + if evaluationIntervalCopy0 > math.MaxInt32 || evaluationIntervalCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field EvaluationInterval is of type int32") + } + evaluationIntervalCopy := int32(evaluationIntervalCopy0) + res.EvaluationInterval = &evaluationIntervalCopy + } if r.ko.Spec.EvaluationPeriods != nil { evaluationPeriodsCopy0 := *r.ko.Spec.EvaluationPeriods if evaluationPeriodsCopy0 > math.MaxInt32 || evaluationPeriodsCopy0 < math.MinInt32 { @@ -388,6 +484,34 @@ func (rm *resourceManager) newCreateRequestPayload( evaluationPeriodsCopy := int32(evaluationPeriodsCopy0) res.EvaluationPeriods = &evaluationPeriodsCopy } + if r.ko.Spec.EvaluationWindow != nil { + var f11 svcsdktypes.EvaluationWindow + isInterfaceSet := false + if r.ko.Spec.EvaluationWindow.SlidingWindow != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for SlidingWindow")) + } + f11f0Parent := &svcsdktypes.EvaluationWindowMemberSlidingWindow{} + f11f0 := &svcsdktypes.SlidingWindow{} + f11f0Parent.Value = *f11f0 + f11 = f11f0Parent + isInterfaceSet = true + } + if r.ko.Spec.EvaluationWindow.WallClockWindow != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for WallClockWindow")) + } + f11f1Parent := &svcsdktypes.EvaluationWindowMemberWallClockWindow{} + f11f1 := &svcsdktypes.WallClockWindow{} + if r.ko.Spec.EvaluationWindow.WallClockWindow.Timezone != nil { + f11f1.Timezone = r.ko.Spec.EvaluationWindow.WallClockWindow.Timezone + } + f11f1Parent.Value = *f11f1 + f11 = f11f1Parent + isInterfaceSet = true + } + res.EvaluationWindow = f11 + } if r.ko.Spec.ExtendedStatistic != nil { res.ExtendedStatistic = r.ko.Spec.ExtendedStatistic } @@ -398,77 +522,77 @@ func (rm *resourceManager) newCreateRequestPayload( res.MetricName = r.ko.Spec.MetricName } if r.ko.Spec.Metrics != nil { - f12 := []svcsdktypes.MetricDataQuery{} - for _, f12iter := range r.ko.Spec.Metrics { - f12elem := &svcsdktypes.MetricDataQuery{} - if f12iter.AccountID != nil { - f12elem.AccountId = f12iter.AccountID - } - if f12iter.Expression != nil { - f12elem.Expression = f12iter.Expression - } - if f12iter.ID != nil { - f12elem.Id = f12iter.ID - } - if f12iter.Label != nil { - f12elem.Label = f12iter.Label - } - if f12iter.MetricStat != nil { - f12elemf4 := &svcsdktypes.MetricStat{} - if f12iter.MetricStat.Metric != nil { - f12elemf4f0 := &svcsdktypes.Metric{} - if f12iter.MetricStat.Metric.Dimensions != nil { - f12elemf4f0f0 := []svcsdktypes.Dimension{} - for _, f12elemf4f0f0iter := range f12iter.MetricStat.Metric.Dimensions { - f12elemf4f0f0elem := &svcsdktypes.Dimension{} - if f12elemf4f0f0iter.Name != nil { - f12elemf4f0f0elem.Name = f12elemf4f0f0iter.Name + f15 := []svcsdktypes.MetricDataQuery{} + for _, f15iter := range r.ko.Spec.Metrics { + f15elem := &svcsdktypes.MetricDataQuery{} + if f15iter.AccountID != nil { + f15elem.AccountId = f15iter.AccountID + } + if f15iter.Expression != nil { + f15elem.Expression = f15iter.Expression + } + if f15iter.ID != nil { + f15elem.Id = f15iter.ID + } + if f15iter.Label != nil { + f15elem.Label = f15iter.Label + } + if f15iter.MetricStat != nil { + f15elemf4 := &svcsdktypes.MetricStat{} + if f15iter.MetricStat.Metric != nil { + f15elemf4f0 := &svcsdktypes.Metric{} + if f15iter.MetricStat.Metric.Dimensions != nil { + f15elemf4f0f0 := []svcsdktypes.Dimension{} + for _, f15elemf4f0f0iter := range f15iter.MetricStat.Metric.Dimensions { + f15elemf4f0f0elem := &svcsdktypes.Dimension{} + if f15elemf4f0f0iter.Name != nil { + f15elemf4f0f0elem.Name = f15elemf4f0f0iter.Name } - if f12elemf4f0f0iter.Value != nil { - f12elemf4f0f0elem.Value = f12elemf4f0f0iter.Value + if f15elemf4f0f0iter.Value != nil { + f15elemf4f0f0elem.Value = f15elemf4f0f0iter.Value } - f12elemf4f0f0 = append(f12elemf4f0f0, *f12elemf4f0f0elem) + f15elemf4f0f0 = append(f15elemf4f0f0, *f15elemf4f0f0elem) } - f12elemf4f0.Dimensions = f12elemf4f0f0 + f15elemf4f0.Dimensions = f15elemf4f0f0 } - if f12iter.MetricStat.Metric.MetricName != nil { - f12elemf4f0.MetricName = f12iter.MetricStat.Metric.MetricName + if f15iter.MetricStat.Metric.MetricName != nil { + f15elemf4f0.MetricName = f15iter.MetricStat.Metric.MetricName } - if f12iter.MetricStat.Metric.Namespace != nil { - f12elemf4f0.Namespace = f12iter.MetricStat.Metric.Namespace + if f15iter.MetricStat.Metric.Namespace != nil { + f15elemf4f0.Namespace = f15iter.MetricStat.Metric.Namespace } - f12elemf4.Metric = f12elemf4f0 + f15elemf4.Metric = f15elemf4f0 } - if f12iter.MetricStat.Period != nil { - periodCopy0 := *f12iter.MetricStat.Period + if f15iter.MetricStat.Period != nil { + periodCopy0 := *f15iter.MetricStat.Period if periodCopy0 > math.MaxInt32 || periodCopy0 < math.MinInt32 { return nil, fmt.Errorf("error: field Period is of type int32") } periodCopy := int32(periodCopy0) - f12elemf4.Period = &periodCopy + f15elemf4.Period = &periodCopy } - if f12iter.MetricStat.Stat != nil { - f12elemf4.Stat = f12iter.MetricStat.Stat + if f15iter.MetricStat.Stat != nil { + f15elemf4.Stat = f15iter.MetricStat.Stat } - if f12iter.MetricStat.Unit != nil { - f12elemf4.Unit = svcsdktypes.StandardUnit(*f12iter.MetricStat.Unit) + if f15iter.MetricStat.Unit != nil { + f15elemf4.Unit = svcsdktypes.StandardUnit(*f15iter.MetricStat.Unit) } - f12elem.MetricStat = f12elemf4 + f15elem.MetricStat = f15elemf4 } - if f12iter.Period != nil { - periodCopy0 := *f12iter.Period + if f15iter.Period != nil { + periodCopy0 := *f15iter.Period if periodCopy0 > math.MaxInt32 || periodCopy0 < math.MinInt32 { return nil, fmt.Errorf("error: field Period is of type int32") } periodCopy := int32(periodCopy0) - f12elem.Period = &periodCopy + f15elem.Period = &periodCopy } - if f12iter.ReturnData != nil { - f12elem.ReturnData = f12iter.ReturnData + if f15iter.ReturnData != nil { + f15elem.ReturnData = f15iter.ReturnData } - f12 = append(f12, *f12elem) + f15 = append(f15, *f15elem) } - res.Metrics = f12 + res.Metrics = f15 } if r.ko.Spec.Namespace != nil { res.Namespace = r.ko.Spec.Namespace @@ -488,18 +612,18 @@ func (rm *resourceManager) newCreateRequestPayload( res.Statistic = svcsdktypes.Statistic(*r.ko.Spec.Statistic) } if r.ko.Spec.Tags != nil { - f17 := []svcsdktypes.Tag{} - for _, f17iter := range r.ko.Spec.Tags { - f17elem := &svcsdktypes.Tag{} - if f17iter.Key != nil { - f17elem.Key = f17iter.Key + f20 := []svcsdktypes.Tag{} + for _, f20iter := range r.ko.Spec.Tags { + f20elem := &svcsdktypes.Tag{} + if f20iter.Key != nil { + f20elem.Key = f20iter.Key } - if f17iter.Value != nil { - f17elem.Value = f17iter.Value + if f20iter.Value != nil { + f20elem.Value = f20iter.Value } - f17 = append(f17, *f17elem) + f20 = append(f20, *f20elem) } - res.Tags = f17 + res.Tags = f20 } if r.ko.Spec.Threshold != nil { res.Threshold = r.ko.Spec.Threshold @@ -599,6 +723,48 @@ func (rm *resourceManager) newUpdateRequestPayload( if r.ko.Spec.EvaluateLowSampleCountPercentile != nil { res.EvaluateLowSampleCountPercentile = r.ko.Spec.EvaluateLowSampleCountPercentile } + if r.ko.Spec.EvaluationCriteria != nil { + var f8 svcsdktypes.EvaluationCriteria + isInterfaceSet := false + if r.ko.Spec.EvaluationCriteria.PromQLCriteria != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for PromQLCriteria")) + } + f8f0Parent := &svcsdktypes.EvaluationCriteriaMemberPromQLCriteria{} + f8f0 := &svcsdktypes.AlarmPromQLCriteria{} + if r.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod != nil { + pendingPeriodCopy0 := *r.ko.Spec.EvaluationCriteria.PromQLCriteria.PendingPeriod + if pendingPeriodCopy0 > math.MaxInt32 || pendingPeriodCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field PendingPeriod is of type int32") + } + pendingPeriodCopy := int32(pendingPeriodCopy0) + f8f0.PendingPeriod = &pendingPeriodCopy + } + if r.ko.Spec.EvaluationCriteria.PromQLCriteria.Query != nil { + f8f0.Query = r.ko.Spec.EvaluationCriteria.PromQLCriteria.Query + } + if r.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod != nil { + recoveryPeriodCopy0 := *r.ko.Spec.EvaluationCriteria.PromQLCriteria.RecoveryPeriod + if recoveryPeriodCopy0 > math.MaxInt32 || recoveryPeriodCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field RecoveryPeriod is of type int32") + } + recoveryPeriodCopy := int32(recoveryPeriodCopy0) + f8f0.RecoveryPeriod = &recoveryPeriodCopy + } + f8f0Parent.Value = *f8f0 + f8 = f8f0Parent + isInterfaceSet = true + } + res.EvaluationCriteria = f8 + } + if r.ko.Spec.EvaluationInterval != nil { + evaluationIntervalCopy0 := *r.ko.Spec.EvaluationInterval + if evaluationIntervalCopy0 > math.MaxInt32 || evaluationIntervalCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field EvaluationInterval is of type int32") + } + evaluationIntervalCopy := int32(evaluationIntervalCopy0) + res.EvaluationInterval = &evaluationIntervalCopy + } if r.ko.Spec.EvaluationPeriods != nil { evaluationPeriodsCopy0 := *r.ko.Spec.EvaluationPeriods if evaluationPeriodsCopy0 > math.MaxInt32 || evaluationPeriodsCopy0 < math.MinInt32 { @@ -607,6 +773,34 @@ func (rm *resourceManager) newUpdateRequestPayload( evaluationPeriodsCopy := int32(evaluationPeriodsCopy0) res.EvaluationPeriods = &evaluationPeriodsCopy } + if r.ko.Spec.EvaluationWindow != nil { + var f11 svcsdktypes.EvaluationWindow + isInterfaceSet := false + if r.ko.Spec.EvaluationWindow.SlidingWindow != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for SlidingWindow")) + } + f11f0Parent := &svcsdktypes.EvaluationWindowMemberSlidingWindow{} + f11f0 := &svcsdktypes.SlidingWindow{} + f11f0Parent.Value = *f11f0 + f11 = f11f0Parent + isInterfaceSet = true + } + if r.ko.Spec.EvaluationWindow.WallClockWindow != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for WallClockWindow")) + } + f11f1Parent := &svcsdktypes.EvaluationWindowMemberWallClockWindow{} + f11f1 := &svcsdktypes.WallClockWindow{} + if r.ko.Spec.EvaluationWindow.WallClockWindow.Timezone != nil { + f11f1.Timezone = r.ko.Spec.EvaluationWindow.WallClockWindow.Timezone + } + f11f1Parent.Value = *f11f1 + f11 = f11f1Parent + isInterfaceSet = true + } + res.EvaluationWindow = f11 + } if r.ko.Spec.ExtendedStatistic != nil { res.ExtendedStatistic = r.ko.Spec.ExtendedStatistic } @@ -617,77 +811,77 @@ func (rm *resourceManager) newUpdateRequestPayload( res.MetricName = r.ko.Spec.MetricName } if r.ko.Spec.Metrics != nil { - f12 := []svcsdktypes.MetricDataQuery{} - for _, f12iter := range r.ko.Spec.Metrics { - f12elem := &svcsdktypes.MetricDataQuery{} - if f12iter.AccountID != nil { - f12elem.AccountId = f12iter.AccountID - } - if f12iter.Expression != nil { - f12elem.Expression = f12iter.Expression - } - if f12iter.ID != nil { - f12elem.Id = f12iter.ID - } - if f12iter.Label != nil { - f12elem.Label = f12iter.Label - } - if f12iter.MetricStat != nil { - f12elemf4 := &svcsdktypes.MetricStat{} - if f12iter.MetricStat.Metric != nil { - f12elemf4f0 := &svcsdktypes.Metric{} - if f12iter.MetricStat.Metric.Dimensions != nil { - f12elemf4f0f0 := []svcsdktypes.Dimension{} - for _, f12elemf4f0f0iter := range f12iter.MetricStat.Metric.Dimensions { - f12elemf4f0f0elem := &svcsdktypes.Dimension{} - if f12elemf4f0f0iter.Name != nil { - f12elemf4f0f0elem.Name = f12elemf4f0f0iter.Name + f15 := []svcsdktypes.MetricDataQuery{} + for _, f15iter := range r.ko.Spec.Metrics { + f15elem := &svcsdktypes.MetricDataQuery{} + if f15iter.AccountID != nil { + f15elem.AccountId = f15iter.AccountID + } + if f15iter.Expression != nil { + f15elem.Expression = f15iter.Expression + } + if f15iter.ID != nil { + f15elem.Id = f15iter.ID + } + if f15iter.Label != nil { + f15elem.Label = f15iter.Label + } + if f15iter.MetricStat != nil { + f15elemf4 := &svcsdktypes.MetricStat{} + if f15iter.MetricStat.Metric != nil { + f15elemf4f0 := &svcsdktypes.Metric{} + if f15iter.MetricStat.Metric.Dimensions != nil { + f15elemf4f0f0 := []svcsdktypes.Dimension{} + for _, f15elemf4f0f0iter := range f15iter.MetricStat.Metric.Dimensions { + f15elemf4f0f0elem := &svcsdktypes.Dimension{} + if f15elemf4f0f0iter.Name != nil { + f15elemf4f0f0elem.Name = f15elemf4f0f0iter.Name } - if f12elemf4f0f0iter.Value != nil { - f12elemf4f0f0elem.Value = f12elemf4f0f0iter.Value + if f15elemf4f0f0iter.Value != nil { + f15elemf4f0f0elem.Value = f15elemf4f0f0iter.Value } - f12elemf4f0f0 = append(f12elemf4f0f0, *f12elemf4f0f0elem) + f15elemf4f0f0 = append(f15elemf4f0f0, *f15elemf4f0f0elem) } - f12elemf4f0.Dimensions = f12elemf4f0f0 + f15elemf4f0.Dimensions = f15elemf4f0f0 } - if f12iter.MetricStat.Metric.MetricName != nil { - f12elemf4f0.MetricName = f12iter.MetricStat.Metric.MetricName + if f15iter.MetricStat.Metric.MetricName != nil { + f15elemf4f0.MetricName = f15iter.MetricStat.Metric.MetricName } - if f12iter.MetricStat.Metric.Namespace != nil { - f12elemf4f0.Namespace = f12iter.MetricStat.Metric.Namespace + if f15iter.MetricStat.Metric.Namespace != nil { + f15elemf4f0.Namespace = f15iter.MetricStat.Metric.Namespace } - f12elemf4.Metric = f12elemf4f0 + f15elemf4.Metric = f15elemf4f0 } - if f12iter.MetricStat.Period != nil { - periodCopy0 := *f12iter.MetricStat.Period + if f15iter.MetricStat.Period != nil { + periodCopy0 := *f15iter.MetricStat.Period if periodCopy0 > math.MaxInt32 || periodCopy0 < math.MinInt32 { return nil, fmt.Errorf("error: field Period is of type int32") } periodCopy := int32(periodCopy0) - f12elemf4.Period = &periodCopy + f15elemf4.Period = &periodCopy } - if f12iter.MetricStat.Stat != nil { - f12elemf4.Stat = f12iter.MetricStat.Stat + if f15iter.MetricStat.Stat != nil { + f15elemf4.Stat = f15iter.MetricStat.Stat } - if f12iter.MetricStat.Unit != nil { - f12elemf4.Unit = svcsdktypes.StandardUnit(*f12iter.MetricStat.Unit) + if f15iter.MetricStat.Unit != nil { + f15elemf4.Unit = svcsdktypes.StandardUnit(*f15iter.MetricStat.Unit) } - f12elem.MetricStat = f12elemf4 + f15elem.MetricStat = f15elemf4 } - if f12iter.Period != nil { - periodCopy0 := *f12iter.Period + if f15iter.Period != nil { + periodCopy0 := *f15iter.Period if periodCopy0 > math.MaxInt32 || periodCopy0 < math.MinInt32 { return nil, fmt.Errorf("error: field Period is of type int32") } periodCopy := int32(periodCopy0) - f12elem.Period = &periodCopy + f15elem.Period = &periodCopy } - if f12iter.ReturnData != nil { - f12elem.ReturnData = f12iter.ReturnData + if f15iter.ReturnData != nil { + f15elem.ReturnData = f15iter.ReturnData } - f12 = append(f12, *f12elem) + f15 = append(f15, *f15elem) } - res.Metrics = f12 + res.Metrics = f15 } if r.ko.Spec.Namespace != nil { res.Namespace = r.ko.Spec.Namespace @@ -707,18 +901,18 @@ func (rm *resourceManager) newUpdateRequestPayload( res.Statistic = svcsdktypes.Statistic(*r.ko.Spec.Statistic) } if r.ko.Spec.Tags != nil { - f17 := []svcsdktypes.Tag{} - for _, f17iter := range r.ko.Spec.Tags { - f17elem := &svcsdktypes.Tag{} - if f17iter.Key != nil { - f17elem.Key = f17iter.Key + f20 := []svcsdktypes.Tag{} + for _, f20iter := range r.ko.Spec.Tags { + f20elem := &svcsdktypes.Tag{} + if f20iter.Key != nil { + f20elem.Key = f20iter.Key } - if f17iter.Value != nil { - f17elem.Value = f17iter.Value + if f20iter.Value != nil { + f20elem.Value = f20iter.Value } - f17 = append(f17, *f17elem) + f20 = append(f20, *f20elem) } - res.Tags = f17 + res.Tags = f20 } if r.ko.Spec.Threshold != nil { res.Threshold = r.ko.Spec.Threshold diff --git a/test/e2e/requirements.txt b/test/e2e/requirements.txt index 4e87452..c5a6c9c 100644 --- a/test/e2e/requirements.txt +++ b/test/e2e/requirements.txt @@ -1 +1 @@ -acktest @ git+https://github.com/aws-controllers-k8s/test-infra.git@01a753c63b44af5f745c64d02d5f5b0ce7fef360 +acktest @ git+https://github.com/aws-controllers-k8s/test-infra.git@2efd6c7a98a1e99346f1de6c94f50f6bd5c329d8 diff --git a/test/e2e/resources/metric_alarm_evaluation_window.yaml b/test/e2e/resources/metric_alarm_evaluation_window.yaml new file mode 100644 index 0000000..5cfd684 --- /dev/null +++ b/test/e2e/resources/metric_alarm_evaluation_window.yaml @@ -0,0 +1,21 @@ +apiVersion: cloudwatch.services.k8s.aws/v1alpha1 +kind: MetricAlarm +metadata: + name: $METRIC_ALARM_NAME +spec: + alarmDescription: CPU Utilization greater than or equal to 90% for 5 minutes + name: $METRIC_ALARM_NAME + comparisonOperator: GreaterThanOrEqualToThreshold + evaluationPeriods: 5 + metricName: CPUUtilization + namespace: AWS/EC2 + period: 60 + statistic: Maximum + threshold: 90 + # evaluationWindow is a union: exactly one of slidingWindow or + # wallClockWindow. A wall clock window aligns evaluation to fixed clock + # boundaries and requires period to be 60, 300, 3600, 86400 or 604800. + # It is not supported on PromQL alarms. + evaluationWindow: + wallClockWindow: + timezone: America/New_York diff --git a/test/e2e/resources/metric_alarm_promql.yaml b/test/e2e/resources/metric_alarm_promql.yaml new file mode 100644 index 0000000..c7f7557 --- /dev/null +++ b/test/e2e/resources/metric_alarm_promql.yaml @@ -0,0 +1,19 @@ +apiVersion: cloudwatch.services.k8s.aws/v1alpha1 +kind: MetricAlarm +metadata: + name: $METRIC_ALARM_NAME +spec: + name: $METRIC_ALARM_NAME + alarmDescription: PromQL alarm on container CPU utilization + # A PromQL alarm is configured entirely through evaluationCriteria. The + # metric-based fields (metricName, namespace, dimensions, period, unit, + # statistic, extendedStatistic, metrics, threshold, comparisonOperator, + # thresholdMetricID, evaluationPeriods, datapointsToAlarm) must not be set + # alongside it. evaluationInterval is required for these alarms and must not + # be set on metric-based alarms. + evaluationInterval: 60 + evaluationCriteria: + promQLCriteria: + query: max by (k8s_namespace_name) (container_cpu_utilization) > 90 + pendingPeriod: 120 + recoveryPeriod: 120 diff --git a/test/e2e/tests/test_metric_alarm.py b/test/e2e/tests/test_metric_alarm.py index b5181d6..817aee6 100644 --- a/test/e2e/tests/test_metric_alarm.py +++ b/test/e2e/tests/test_metric_alarm.py @@ -31,14 +31,17 @@ MODIFY_WAIT_AFTER_SECONDS = 10 DELETE_WAIT_AFTER_SECONDS = 5 -@pytest.fixture -def _metric_alarm(): - metric_alarm_name = random_suffix_name("ack-test-metric-alarm", 24) +def _make_metric_alarm(name_prefix: str, resource_name: str): + """Creates a MetricAlarm from a resource file and deletes it afterwards. + + Yields the (reference, custom resource) pair. + """ + metric_alarm_name = random_suffix_name(name_prefix, 24) replacements = REPLACEMENT_VALUES.copy() replacements["METRIC_ALARM_NAME"] = metric_alarm_name resource_data = load_cloudwatch_resource( - "metric_alarm", + resource_name, additional_replacements=replacements, ) @@ -65,6 +68,23 @@ def _metric_alarm(): metric_alarm.wait_until_deleted(metric_alarm_name) +@pytest.fixture +def _metric_alarm(): + yield from _make_metric_alarm("ack-test-metric-alarm", "metric_alarm") + + +@pytest.fixture +def _evaluation_window_metric_alarm(): + yield from _make_metric_alarm( + "ack-test-eval-window", "metric_alarm_evaluation_window") + + +@pytest.fixture +def _promql_metric_alarm(): + yield from _make_metric_alarm( + "ack-test-promql-alarm", "metric_alarm_promql") + + @service_marker @pytest.mark.canary class TestMetricAlarm: @@ -78,3 +98,161 @@ def test_crud(self, _metric_alarm): assert metric_alarm.exists(metric_alarm_name) assert k8s.get_resource_exists(ref) + + +@service_marker +class TestMetricAlarmEvaluationWindow: + """Covers the evaluationWindow union on a metric-based alarm. + + Kept on its own resource rather than added to TestMetricAlarm so that a + gap in regional availability for evaluation windows cannot break the + canary coverage for basic MetricAlarm CRUD. + """ + + def test_crud(self, _evaluation_window_metric_alarm): + (ref, cr) = _evaluation_window_metric_alarm + metric_alarm_name = ref.name + + time.sleep(CHECK_STATUS_WAIT_SECONDS) + + condition.assert_synced(ref) + + assert metric_alarm.exists(metric_alarm_name) + assert k8s.get_resource_exists(ref) + + # Verify via the CR + cr = k8s.get_resource(ref) + assert cr["spec"]["evaluationWindow"]["wallClockWindow"]["timezone"] == 'America/New_York', \ + f"Expected wallClockWindow timezone on CR, got {cr['spec'].get('evaluationWindow')}" + + # Verify via the AWS API + initial_alarm = metric_alarm.get(metric_alarm_name) + assert initial_alarm is not None, "MetricAlarm not found in AWS API" + + initial_window = initial_alarm.get('EvaluationWindow', {}) + assert 'WallClockWindow' in initial_window, \ + f"Expected WallClockWindow on create, got {initial_window}" + assert initial_window['WallClockWindow'].get('Timezone') == 'America/New_York', \ + f"Expected America/New_York on create, got {initial_window['WallClockWindow']}" + + # Update the timezone. This stays within the wallClockWindow member - + # a fixed UTC offset must be aligned to a multiple of 5 minutes. + updates = { + "spec": { + "evaluationWindow": { + "wallClockWindow": { + "timezone": "UTC+05:30" + } + } + } + } + + k8s.patch_custom_resource(ref, updates) + cr = k8s.wait_resource_consumed_by_controller(ref) + + assert cr is not None + assert k8s.get_resource_exists(ref) + + time.sleep(MODIFY_WAIT_AFTER_SECONDS) + condition.assert_synced(ref) + + updated_alarm = metric_alarm.get(metric_alarm_name) + assert updated_alarm is not None, "MetricAlarm not found in AWS API after update" + + updated_window = updated_alarm.get('EvaluationWindow', {}) + assert 'WallClockWindow' in updated_window, \ + f"Expected WallClockWindow after update, got {updated_window}" + assert updated_window['WallClockWindow'].get('Timezone') == 'UTC+05:30', \ + f"Expected UTC+05:30 after update, got {updated_window['WallClockWindow']}" + + +@service_marker +class TestMetricAlarmPromQL: + """Covers alarms configured with evaluationCriteria/evaluationInterval. + + These fields are mutually exclusive with the metric-based fields, so a + PromQL alarm cannot be produced by patching the alarm in TestMetricAlarm - + it needs its own resource. + """ + + def test_crud(self, _promql_metric_alarm): + (ref, cr) = _promql_metric_alarm + metric_alarm_name = ref.name + + time.sleep(CHECK_STATUS_WAIT_SECONDS) + + condition.assert_synced(ref) + + assert metric_alarm.exists(metric_alarm_name) + assert k8s.get_resource_exists(ref) + + initial_query = 'max by (k8s_namespace_name) (container_cpu_utilization) > 90' + + # Verify via the CR + cr = k8s.get_resource(ref) + assert cr["spec"]["evaluationInterval"] == 60, \ + f"Expected evaluationInterval 60 on CR, got {cr['spec'].get('evaluationInterval')}" + cr_promql = cr["spec"]["evaluationCriteria"]["promQLCriteria"] + assert cr_promql["query"] == initial_query, \ + f"Expected query on CR, got {cr_promql.get('query')}" + + # Verify via the AWS API + initial_alarm = metric_alarm.get(metric_alarm_name) + assert initial_alarm is not None, "MetricAlarm not found in AWS API" + + assert initial_alarm.get('EvaluationInterval') == 60, \ + f"Expected EvaluationInterval 60, got {initial_alarm.get('EvaluationInterval')}" + + initial_criteria = initial_alarm.get('EvaluationCriteria', {}) + assert 'PromQLCriteria' in initial_criteria, \ + f"Expected PromQLCriteria on create, got {initial_criteria}" + + initial_promql = initial_criteria['PromQLCriteria'] + assert initial_promql.get('Query') == initial_query, \ + f"Expected query on create, got {initial_promql.get('Query')}" + assert initial_promql.get('PendingPeriod') == 120, \ + f"Expected PendingPeriod 120 on create, got {initial_promql.get('PendingPeriod')}" + assert initial_promql.get('RecoveryPeriod') == 120, \ + f"Expected RecoveryPeriod 120 on create, got {initial_promql.get('RecoveryPeriod')}" + + # Update the PromQL criteria and the evaluation interval. These stay + # within the PromQL alarm shape - switching an alarm between the + # metric-based and PromQL forms is not a supported update. + updated_query = 'max by (k8s_namespace_name) (container_cpu_utilization) > 80' + updates = { + "spec": { + "evaluationInterval": 120, + "evaluationCriteria": { + "promQLCriteria": { + "query": updated_query, + "pendingPeriod": 300, + "recoveryPeriod": 120, + } + } + } + } + + k8s.patch_custom_resource(ref, updates) + cr = k8s.wait_resource_consumed_by_controller(ref) + + assert cr is not None + assert k8s.get_resource_exists(ref) + + time.sleep(MODIFY_WAIT_AFTER_SECONDS) + condition.assert_synced(ref) + + updated_alarm = metric_alarm.get(metric_alarm_name) + assert updated_alarm is not None, "MetricAlarm not found in AWS API after update" + + assert updated_alarm.get('EvaluationInterval') == 120, \ + f"Expected EvaluationInterval 120 after update, got {updated_alarm.get('EvaluationInterval')}" + + updated_criteria = updated_alarm.get('EvaluationCriteria', {}) + assert 'PromQLCriteria' in updated_criteria, \ + f"Expected PromQLCriteria after update, got {updated_criteria}" + + updated_promql = updated_criteria['PromQLCriteria'] + assert updated_promql.get('Query') == updated_query, \ + f"Expected updated query, got {updated_promql.get('Query')}" + assert updated_promql.get('PendingPeriod') == 300, \ + f"Expected PendingPeriod 300 after update, got {updated_promql.get('PendingPeriod')}"