From f6a17d52315bf3cd40876c849ffcd3ba671e90e3 Mon Sep 17 00:00:00 2001 From: Jesse Bye <8467862+jessebye@users.noreply.github.com> Date: Mon, 24 Jul 2023 14:37:37 -0700 Subject: [PATCH 1/5] feat: add MetricAlarm resource type --- CONTRIBUTING.md | 74 +- GOVERNANCE.md | 20 +- NOTICE | 3 +- OWNERS_ALIASES | 4 +- apis/v1alpha1/ack-generate-metadata.yaml | 13 + apis/v1alpha1/doc.go | 4 + apis/v1alpha1/enums.go | 151 +++ apis/v1alpha1/generator.yaml | 37 + apis/v1alpha1/groupversion_info.go | 32 + apis/v1alpha1/metric_alarm.go | 328 +++++ apis/v1alpha1/types.go | 271 ++++ apis/v1alpha1/zz_generated.deepcopy.go | 1156 +++++++++++++++++ cmd/controller/main.go | 157 +++ config/controller/deployment.yaml | 83 ++ config/controller/kustomization.yaml | 9 + config/controller/service.yaml | 14 + ...udwatch.services.k8s.aws_metricalarms.yaml | 425 ++++++ .../services.k8s.aws_adoptedresources.yaml | 226 ++++ .../bases/services.k8s.aws_fieldexports.yaml | 134 ++ config/crd/common/kustomization.yaml | 7 + config/crd/kustomization.yaml | 5 + config/default/kustomization.yaml | 20 + config/overlays/namespaced/kustomization.yaml | 15 + config/overlays/namespaced/role-binding.json | 3 + config/overlays/namespaced/role.json | 2 + config/rbac/cluster-role-binding.yaml | 12 + config/rbac/cluster-role-controller.yaml | 93 ++ config/rbac/kustomization.yaml | 7 + config/rbac/role-reader.yaml | 16 + config/rbac/role-writer.yaml | 28 + config/rbac/service-account.yaml | 6 + generator.yaml | 34 + go.mod | 74 ++ go.sum | 651 ++++++++++ helm/Chart.yaml | 18 + ...udwatch.services.k8s.aws_metricalarms.yaml | 425 ++++++ .../services.k8s.aws_adoptedresources.yaml | 229 ++++ helm/crds/services.k8s.aws_fieldexports.yaml | 134 ++ helm/templates/NOTES.txt | 16 + helm/templates/_helpers.tpl | 48 + helm/templates/cluster-role-binding.yaml | 21 + helm/templates/cluster-role-controller.yaml | 108 ++ helm/templates/deployment.yaml | 154 +++ helm/templates/metrics-service.yaml | 29 + helm/templates/role-reader.yaml | 16 + helm/templates/role-writer.yaml | 29 + helm/templates/service-account.yaml | 18 + helm/values.schema.json | 262 ++++ helm/values.yaml | 123 ++ pkg/resource/metric_alarm/delta.go | 178 +++ pkg/resource/metric_alarm/descriptor.go | 155 +++ pkg/resource/metric_alarm/identifiers.go | 55 + pkg/resource/metric_alarm/manager.go | 360 +++++ pkg/resource/metric_alarm/manager_factory.go | 96 ++ pkg/resource/metric_alarm/references.go | 56 + pkg/resource/metric_alarm/resource.go | 100 ++ pkg/resource/metric_alarm/sdk.go | 866 ++++++++++++ pkg/resource/metric_alarm/tags.go | 63 + pkg/resource/registry.go | 45 + pkg/version/version.go | 22 + .../sdk_delete_post_build_request.go.tpl | 1 + 61 files changed, 7709 insertions(+), 32 deletions(-) create mode 100755 apis/v1alpha1/ack-generate-metadata.yaml create mode 100644 apis/v1alpha1/doc.go create mode 100644 apis/v1alpha1/enums.go create mode 100644 apis/v1alpha1/generator.yaml create mode 100644 apis/v1alpha1/groupversion_info.go create mode 100644 apis/v1alpha1/metric_alarm.go create mode 100644 apis/v1alpha1/types.go create mode 100644 apis/v1alpha1/zz_generated.deepcopy.go create mode 100644 cmd/controller/main.go create mode 100644 config/controller/deployment.yaml create mode 100644 config/controller/kustomization.yaml create mode 100644 config/controller/service.yaml create mode 100644 config/crd/bases/cloudwatch.services.k8s.aws_metricalarms.yaml create mode 100644 config/crd/common/bases/services.k8s.aws_adoptedresources.yaml create mode 100644 config/crd/common/bases/services.k8s.aws_fieldexports.yaml create mode 100644 config/crd/common/kustomization.yaml create mode 100644 config/crd/kustomization.yaml create mode 100644 config/default/kustomization.yaml create mode 100644 config/overlays/namespaced/kustomization.yaml create mode 100644 config/overlays/namespaced/role-binding.json create mode 100644 config/overlays/namespaced/role.json create mode 100644 config/rbac/cluster-role-binding.yaml create mode 100644 config/rbac/cluster-role-controller.yaml create mode 100644 config/rbac/kustomization.yaml create mode 100644 config/rbac/role-reader.yaml create mode 100644 config/rbac/role-writer.yaml create mode 100644 config/rbac/service-account.yaml create mode 100644 helm/Chart.yaml create mode 100644 helm/crds/cloudwatch.services.k8s.aws_metricalarms.yaml create mode 100644 helm/crds/services.k8s.aws_adoptedresources.yaml create mode 100644 helm/crds/services.k8s.aws_fieldexports.yaml create mode 100644 helm/templates/NOTES.txt create mode 100644 helm/templates/_helpers.tpl create mode 100644 helm/templates/cluster-role-binding.yaml create mode 100644 helm/templates/cluster-role-controller.yaml create mode 100644 helm/templates/deployment.yaml create mode 100644 helm/templates/metrics-service.yaml create mode 100644 helm/templates/role-reader.yaml create mode 100644 helm/templates/role-writer.yaml create mode 100644 helm/templates/service-account.yaml create mode 100644 helm/values.schema.json create mode 100644 helm/values.yaml create mode 100644 pkg/resource/metric_alarm/delta.go create mode 100644 pkg/resource/metric_alarm/descriptor.go create mode 100644 pkg/resource/metric_alarm/identifiers.go create mode 100644 pkg/resource/metric_alarm/manager.go create mode 100644 pkg/resource/metric_alarm/manager_factory.go create mode 100644 pkg/resource/metric_alarm/references.go create mode 100644 pkg/resource/metric_alarm/resource.go create mode 100644 pkg/resource/metric_alarm/sdk.go create mode 100644 pkg/resource/metric_alarm/tags.go create mode 100644 pkg/resource/registry.go create mode 100644 pkg/version/version.go create mode 100644 templates/hooks/metricalarm/sdk_delete_post_build_request.go.tpl diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 99fd57d..9da1461 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,59 +1,85 @@ # Contributing Guidelines -Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional -documentation, we greatly value feedback and contributions from our community. - -Please read through this document before submitting any issues or pull requests to ensure we have all the necessary -information to effectively respond to your bug report or contribution. +Thank you for your interest in contributing to our project. Whether it's a bug +report, new feature, correction, or additional documentation, we greatly value +feedback and contributions from our community. +Please read through this document before submitting any issues or pull requests +to ensure we have all the necessary information to effectively respond to your +bug report or contribution. ## Reporting Bugs/Feature Requests -We welcome you to use the GitHub issue tracker to report bugs or suggest features. +We welcome you to use the GitHub issue tracker to report bugs or suggest +features. -When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already -reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: +When filing an issue, please check existing open, or recently closed, issues to +make sure somebody else hasn't already reported the issue. Please try to +include as much information as you can. Details like these are incredibly +useful: * A reproducible test case or series of steps * The version of our code being used * Any modifications you've made relevant to the bug * Anything unusual about your environment or deployment - ## Contributing via Pull Requests -Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: + +Contributions via pull requests are much appreciated. Before sending us a pull +request, please ensure that: 1. You are working against the latest source on the *main* branch. -2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. -3. You open an issue to discuss any significant work - we would hate for your time to be wasted. +2. You check existing open, and recently merged, pull requests to make sure + someone else hasn't addressed the problem already. +3. You open an issue to discuss any significant work - we would hate for your + time to be wasted. To send us a pull request, please: 1. Fork the repository. -2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. +2. Modify the source; please focus on the specific change you are contributing. + If you also reformat all the code, it will be hard for us to focus on your + change. 3. Ensure local tests pass. 4. Commit to your fork using clear commit messages. -5. Send us a pull request, answering any default questions in the pull request interface. -6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. +5. Send us a pull request, answering any default questions in the pull request + interface. +6. Pay attention to any automated CI failures reported in the pull request, and + stay involved in the conversation. -GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and -[creating a pull request](https://help.github.com/articles/creating-a-pull-request/). +GitHub provides additional document on [forking a repository][fork] and +[creating a pull request][pr]. +[fork]: https://help.github.com/articles/fork-a-repo/ +[pr]: https://help.github.com/articles/creating-a-pull-request/ ## Finding contributions to work on -Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. +Looking at the existing issues is a great way to find something to contribute +on. As our projects, by default, use the default GitHub issue labels +(enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at +any 'help wanted' issues is a great place to start. + +## Developer documentation + +[See the documentation][dev-docs] for detailed development information. + +[dev-docs]: https://aws-controllers-k8s.github.io/community/docs/contributor-docs/overview/ ## Code of Conduct -This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). -For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact -opensource-codeofconduct@amazon.com with any additional questions or comments. +We adhere to the [Amazon Open Source Code of Conduct][coc]. + +[coc]: https://aws.github.io/code-of-conduct ## Security issue notifications -If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. +If you discover a potential security issue in this project we ask that you +notify AWS/Amazon Security via our [vulnerability reporting page][vuln]. Please +do **not** create a public Github issue. + +[vuln]: http://aws.amazon.com/security/vulnerability-reporting/ -## Licensing +## License -See the [LICENSE](/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. +This project is [licensed][./LICENSE] under the Apache-2.0 License. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index b883940..c37b88a 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -1,18 +1,30 @@ # Project governance -This document lays out the guidelines under which the AWS Controllers for Kubernetes (ACK) project will be governed. +This document lays out the guidelines under which the AWS Controllers for Kubernetes (ACK) project will be governed. The goal is to make sure that the roles and responsibilities are well defined and clarify on how decisions are made. +## Roles + +In the context of ACK, we consider the following roles: + +* __Users__ ... everyone using ACK, typically willing to provide feedback on ACK by proposing features and/or filing issues. +* __Contributors__ ... everyone contributing code, documentation, examples, testing infra, and participating in feature proposals as well as design discussions. Code contributions will require a Developer Certificate of Origin (DCO). +* __Maintainers__ ... are responsible for engaging with and assisting contributors to iterate on the contributions until it reaches acceptable quality. Maintainers can decide whether the contributions can be accepted into the project or rejected. Any active contributor meeting the project quality can be made a Maintainer by the Advisory Board. +* __Advisory Board__ ... is responsible for defining the guidelines and processes that the project operates under. + +The initial members of the Advisory Board are `@jaypipes` and `@mhausenblas`. + + ## Communication -The primary mechanism for communication will be via the `#provider-aws` channel on the Kubernetes Slack community. +The primary mechanism for communication will be via the `#provider-aws` channel on the Kubernetes Slack community. All features and bug fixes will be tracked as issues in GitHub. All decisions will be documented in GitHub issues. -In the future, we may consider using a public mailing list, which can be better archived. +In the future, we may consider using a public mailing list, which can be better archived. ## Roadmap Planning -Maintainers will share roadmap and release versions as milestones in GitHub. +Maintainers will share roadmap and release versions as milestones in GitHub. ## Release Management diff --git a/NOTICE b/NOTICE index cbf924b..b8d0d46 100644 --- a/NOTICE +++ b/NOTICE @@ -1,2 +1 @@ -Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - +Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 993d39f..12c74d9 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -5,5 +5,5 @@ aliases: - a-hilaly - RedbackThomson - jljaco - # TODO: Add your team members' GitHub aliases to the team alias - service-team: [] + service-team: + - jessebye diff --git a/apis/v1alpha1/ack-generate-metadata.yaml b/apis/v1alpha1/ack-generate-metadata.yaml new file mode 100755 index 0000000..44593d0 --- /dev/null +++ b/apis/v1alpha1/ack-generate-metadata.yaml @@ -0,0 +1,13 @@ +ack_generate_info: + build_date: "2023-07-24T21:35:44Z" + build_hash: e9b68590da73ce9143ba1e4361cebdc1d876c81e + go_version: go1.20.6 + version: v0.26.1-7-ge9b6859-dirty +api_directory_checksum: e21bfad36ac581912d611c9c390ab4bd2c2fb46d +api_version: v1alpha1 +aws_sdk_go_version: v1.44.303 +generator_config_info: + file_checksum: bfca77347e9ccada9ee0c53136c169cdca88443b + original_file_name: generator.yaml +last_modification: + reason: API generation diff --git a/apis/v1alpha1/doc.go b/apis/v1alpha1/doc.go new file mode 100644 index 0000000..f00be95 --- /dev/null +++ b/apis/v1alpha1/doc.go @@ -0,0 +1,4 @@ +// +k8s:deepcopy-gen=package +// Package v1alpha1 is the v1alpha1 version of the cloudwatch.services.k8s.aws API. +// +groupName=cloudwatch.services.k8s.aws +package v1alpha1 diff --git a/apis/v1alpha1/enums.go b/apis/v1alpha1/enums.go new file mode 100644 index 0000000..1504d03 --- /dev/null +++ b/apis/v1alpha1/enums.go @@ -0,0 +1,151 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +type ActionsSuppressedBy string + +const ( + ActionsSuppressedBy_WaitPeriod ActionsSuppressedBy = "WaitPeriod" + ActionsSuppressedBy_ExtensionPeriod ActionsSuppressedBy = "ExtensionPeriod" + ActionsSuppressedBy_Alarm ActionsSuppressedBy = "Alarm" +) + +type AlarmType string + +const ( + AlarmType_CompositeAlarm AlarmType = "CompositeAlarm" + AlarmType_MetricAlarm AlarmType = "MetricAlarm" +) + +type AnomalyDetectorStateValue string + +const ( + AnomalyDetectorStateValue_PENDING_TRAINING AnomalyDetectorStateValue = "PENDING_TRAINING" + AnomalyDetectorStateValue_TRAINED_INSUFFICIENT_DATA AnomalyDetectorStateValue = "TRAINED_INSUFFICIENT_DATA" + AnomalyDetectorStateValue_TRAINED AnomalyDetectorStateValue = "TRAINED" +) + +type AnomalyDetectorType string + +const ( + AnomalyDetectorType_SINGLE_METRIC AnomalyDetectorType = "SINGLE_METRIC" + AnomalyDetectorType_METRIC_MATH AnomalyDetectorType = "METRIC_MATH" +) + +type ComparisonOperator string + +const ( + ComparisonOperator_GreaterThanOrEqualToThreshold ComparisonOperator = "GreaterThanOrEqualToThreshold" + ComparisonOperator_GreaterThanThreshold ComparisonOperator = "GreaterThanThreshold" + ComparisonOperator_LessThanThreshold ComparisonOperator = "LessThanThreshold" + ComparisonOperator_LessThanOrEqualToThreshold ComparisonOperator = "LessThanOrEqualToThreshold" + ComparisonOperator_LessThanLowerOrGreaterThanUpperThreshold ComparisonOperator = "LessThanLowerOrGreaterThanUpperThreshold" + ComparisonOperator_LessThanLowerThreshold ComparisonOperator = "LessThanLowerThreshold" + ComparisonOperator_GreaterThanUpperThreshold ComparisonOperator = "GreaterThanUpperThreshold" +) + +type EvaluationState string + +const ( + EvaluationState_PARTIAL_DATA EvaluationState = "PARTIAL_DATA" +) + +type HistoryItemType string + +const ( + HistoryItemType_ConfigurationUpdate HistoryItemType = "ConfigurationUpdate" + HistoryItemType_StateUpdate HistoryItemType = "StateUpdate" + HistoryItemType_Action HistoryItemType = "Action" +) + +type MetricStreamOutputFormat string + +const ( + MetricStreamOutputFormat_json MetricStreamOutputFormat = "json" + MetricStreamOutputFormat_opentelemetry0_7 MetricStreamOutputFormat = "opentelemetry0.7" +) + +type RecentlyActive string + +const ( + RecentlyActive_PT3H RecentlyActive = "PT3H" +) + +type ScanBy string + +const ( + ScanBy_TimestampDescending ScanBy = "TimestampDescending" + ScanBy_TimestampAscending ScanBy = "TimestampAscending" +) + +type StandardUnit string + +const ( + StandardUnit_Seconds StandardUnit = "Seconds" + StandardUnit_Microseconds StandardUnit = "Microseconds" + StandardUnit_Milliseconds StandardUnit = "Milliseconds" + StandardUnit_Bytes StandardUnit = "Bytes" + StandardUnit_Kilobytes StandardUnit = "Kilobytes" + StandardUnit_Megabytes StandardUnit = "Megabytes" + StandardUnit_Gigabytes StandardUnit = "Gigabytes" + StandardUnit_Terabytes StandardUnit = "Terabytes" + StandardUnit_Bits StandardUnit = "Bits" + StandardUnit_Kilobits StandardUnit = "Kilobits" + StandardUnit_Megabits StandardUnit = "Megabits" + StandardUnit_Gigabits StandardUnit = "Gigabits" + StandardUnit_Terabits StandardUnit = "Terabits" + StandardUnit_Percent StandardUnit = "Percent" + StandardUnit_Count StandardUnit = "Count" + StandardUnit_Bytes_Second StandardUnit = "Bytes/Second" + StandardUnit_Kilobytes_Second StandardUnit = "Kilobytes/Second" + StandardUnit_Megabytes_Second StandardUnit = "Megabytes/Second" + StandardUnit_Gigabytes_Second StandardUnit = "Gigabytes/Second" + StandardUnit_Terabytes_Second StandardUnit = "Terabytes/Second" + StandardUnit_Bits_Second StandardUnit = "Bits/Second" + StandardUnit_Kilobits_Second StandardUnit = "Kilobits/Second" + StandardUnit_Megabits_Second StandardUnit = "Megabits/Second" + StandardUnit_Gigabits_Second StandardUnit = "Gigabits/Second" + StandardUnit_Terabits_Second StandardUnit = "Terabits/Second" + StandardUnit_Count_Second StandardUnit = "Count/Second" + StandardUnit_None StandardUnit = "None" +) + +type StateValue string + +const ( + StateValue_OK StateValue = "OK" + StateValue_ALARM StateValue = "ALARM" + StateValue_INSUFFICIENT_DATA StateValue = "INSUFFICIENT_DATA" +) + +type Statistic string + +const ( + Statistic_SampleCount Statistic = "SampleCount" + Statistic_Average Statistic = "Average" + Statistic_Sum Statistic = "Sum" + Statistic_Minimum Statistic = "Minimum" + Statistic_Maximum Statistic = "Maximum" +) + +type StatusCode string + +const ( + StatusCode_Complete StatusCode = "Complete" + StatusCode_InternalError StatusCode = "InternalError" + StatusCode_PartialData StatusCode = "PartialData" + StatusCode_Forbidden StatusCode = "Forbidden" +) diff --git a/apis/v1alpha1/generator.yaml b/apis/v1alpha1/generator.yaml new file mode 100644 index 0000000..796a3b9 --- /dev/null +++ b/apis/v1alpha1/generator.yaml @@ -0,0 +1,37 @@ +ignore: + resource_names: + - AnomalyDetector + - CompositeAlarm + - InsightRule + - ManagedInsightRule + - MetricStream +model_name: monitoring +operations: + DeleteAlarms: + operation_type: + - Delete + resource_name: MetricAlarm + DescribeAlarms: + output_wrapper_field_path: MetricAlarms + operation_type: + - List + resource_name: MetricAlarm + PutMetricAlarm: + operation_type: + - Create + - Update + resource_name: MetricAlarm +resources: + MetricAlarm: + fields: + Name: + is_primary_key: true + is_required: true + renames: + operations: + PutMetricAlarm: + input_fields: + AlarmName: Name + hooks: + sdk_delete_post_build_request: + template_path: hooks/metricalarm/sdk_delete_post_build_request.go.tpl diff --git a/apis/v1alpha1/groupversion_info.go b/apis/v1alpha1/groupversion_info.go new file mode 100644 index 0000000..e7d290a --- /dev/null +++ b/apis/v1alpha1/groupversion_info.go @@ -0,0 +1,32 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is the API Group Version used to register the objects + GroupVersion = schema.GroupVersion{Group: "cloudwatch.services.k8s.aws", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/apis/v1alpha1/metric_alarm.go b/apis/v1alpha1/metric_alarm.go new file mode 100644 index 0000000..255c0a4 --- /dev/null +++ b/apis/v1alpha1/metric_alarm.go @@ -0,0 +1,328 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// MetricAlarmSpec defines the desired state of MetricAlarm. +// +// The details about a metric alarm. +type MetricAlarmSpec struct { + + // Indicates whether actions should be executed during any changes to the alarm + // state. The default is TRUE. + ActionsEnabled *bool `json:"actionsEnabled,omitempty"` + // The actions to execute when this alarm transitions to the ALARM state from + // any other state. Each action is specified as an Amazon Resource Name (ARN). + // Valid values: + // + // EC2 actions: + // + // - arn:aws:automate:region:ec2:stop + // + // - arn:aws:automate:region:ec2:terminate + // + // - arn:aws:automate:region:ec2:reboot + // + // - arn:aws:automate:region:ec2:recover + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Stop/1.0 + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Recover/1.0 + // + // Autoscaling action: + // + // - arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + // + // SNS notification action: + // + // - arn:aws:sns:region:account-id:sns-topic-name:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + // + // SSM integration actions: + // + // - arn:aws:ssm:region:account-id:opsitem:severity#CATEGORY=category-name + // + // - arn:aws:ssm-incidents::account-id:responseplan/response-plan-name + AlarmActions []*string `json:"alarmActions,omitempty"` + // The description for the alarm. + AlarmDescription *string `json:"alarmDescription,omitempty"` + // The arithmetic operation to use when comparing the specified statistic and + // threshold. The specified statistic value is used as the first operand. + // + // The values LessThanLowerOrGreaterThanUpperThreshold, LessThanLowerThreshold, + // and GreaterThanUpperThreshold are used only for alarms based on anomaly detection + // models. + // +kubebuilder:validation:Required + ComparisonOperator *string `json:"comparisonOperator"` + // 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) + // in the Amazon CloudWatch User Guide. + DatapointsToAlarm *int64 `json:"datapointsToAlarm,omitempty"` + // The dimensions for the metric specified in MetricName. + Dimensions []*Dimension `json:"dimensions,omitempty"` + // Used only for alarms based on percentiles. If you specify ignore, the alarm + // state does not change during periods with too few data points to be statistically + // significant. If you specify evaluate or omit this parameter, the alarm is + // always evaluated and possibly changes state no matter how many data points + // are available. For more information, see Percentile-Based CloudWatch Alarms + // and Low Data Samples (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#percentiles-with-low-samples). + // + // Valid Values: evaluate | ignore + EvaluateLowSampleCountPercentile *string `json:"evaluateLowSampleCountPercentile,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. + // + // 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"` + // The percentile statistic for the metric specified in MetricName. Specify + // a value between p0.0 and p100. When you call PutMetricAlarm and specify a + // MetricName, you must specify either Statistic or ExtendedStatistic, but not + // both. + ExtendedStatistic *string `json:"extendedStatistic,omitempty"` + // The actions to execute when this alarm transitions to the INSUFFICIENT_DATA + // state from any other state. Each action is specified as an Amazon Resource + // Name (ARN). Valid values: + // + // EC2 actions: + // + // - arn:aws:automate:region:ec2:stop + // + // - arn:aws:automate:region:ec2:terminate + // + // - arn:aws:automate:region:ec2:reboot + // + // - arn:aws:automate:region:ec2:recover + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Stop/1.0 + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Recover/1.0 + // + // Autoscaling action: + // + // - arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + // + // SNS notification action: + // + // - arn:aws:sns:region:account-id:sns-topic-name:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + // + // SSM integration actions: + // + // - arn:aws:ssm:region:account-id:opsitem:severity#CATEGORY=category-name + // + // - 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. + // + // If you are creating an alarm based on a math expression, you cannot specify + // this parameter, or any of the Dimensions, Period, Namespace, Statistic, or + // ExtendedStatistic parameters. Instead, you specify all this information in + // the Metrics array. + 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. + // + // Each item in the Metrics array either retrieves a metric or performs a math + // expression. + // + // One item in the Metrics array is the expression that the alarm watches. You + // designate this expression by setting ReturnData to true for this object in + // the array. For more information, see MetricDataQuery (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDataQuery.html). + // + // If you use the Metrics parameter, you cannot include the MetricName, Dimensions, + // Period, Namespace, Statistic, or ExtendedStatistic parameters of PutMetricAlarm + // in the same operation. Instead, you retrieve the metrics you are using in + // your math expression as part of the Metrics array. + Metrics []*MetricDataQuery `json:"metrics,omitempty"` + // The name for the alarm. This name must be unique within the Region. + // + // The name must contain only UTF-8 characters, and can't contain ASCII control + // characters + // +kubebuilder:validation:Required + Name *string `json:"name"` + // The namespace for the metric associated specified in MetricName. + Namespace *string `json:"namespace,omitempty"` + // The actions to execute when this alarm transitions to an OK state from any + // other state. Each action is specified as an Amazon Resource Name (ARN). Valid + // values: + // + // EC2 actions: + // + // - arn:aws:automate:region:ec2:stop + // + // - arn:aws:automate:region:ec2:terminate + // + // - arn:aws:automate:region:ec2:reboot + // + // - arn:aws:automate:region:ec2:recover + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Stop/1.0 + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + // + // - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Recover/1.0 + // + // Autoscaling action: + // + // - arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + // + // SNS notification action: + // + // - arn:aws:sns:region:account-id:sns-topic-name:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + // + // SSM integration actions: + // + // - arn:aws:ssm:region:account-id:opsitem:severity#CATEGORY=category-name + // + // - 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. + // + // 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 + // 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, + // 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. + 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 + // and specify a MetricName, you must specify either Statistic or ExtendedStatistic, + // but not both. + Statistic *string `json:"statistic,omitempty"` + // A list of key-value pairs to associate with the alarm. You can associate + // as many as 50 tags with an alarm. + // + // Tags can help you organize and categorize your resources. You can also use + // them to scope user permissions by granting a user permission to access or + // change only resources with certain tag values. + // + // If you are using this operation to update an existing alarm, any tags you + // specify in this parameter are ignored. To change the tags of an existing + // alarm, use TagResource (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_TagResource.html) + // or UntagResource (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_UntagResource.html). + Tags []*Tag `json:"tags,omitempty"` + // The value against which the specified statistic is compared. + // + // This parameter is required for alarms based on static thresholds, but should + // not be used for alarms based on anomaly detection models. + Threshold *float64 `json:"threshold,omitempty"` + // If this is an alarm based on an anomaly detection model, make this value + // match the ID of the ANOMALY_DETECTION_BAND function. + // + // For an example of how to use this parameter, see the Anomaly Detection Model + // Alarm example on this page. + // + // If your alarm uses this parameter, it cannot have Auto Scaling actions. + ThresholdMetricID *string `json:"thresholdMetricID,omitempty"` + // Sets how this alarm is to handle missing data points. If TreatMissingData + // is omitted, the default behavior of missing is used. For more information, + // see Configuring How CloudWatch Alarms Treats Missing Data (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-missing-data). + // + // Valid Values: breaching | notBreaching | ignore | missing + // + // Alarms that evaluate metrics in the AWS/DynamoDB namespace always ignore + // 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. + 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 + // that an instance receives on all network interfaces. You can also specify + // a unit when you create a custom metric. Units help provide conceptual meaning + // to your data. Metric data points that specify a unit of measure, such as + // Percent, are aggregated separately. + // + // If you don't specify Unit, CloudWatch retrieves all unit types that have + // been published for the metric and attempts to evaluate the alarm. Usually, + // metrics are published with only one unit, so the alarm works as intended. + // + // However, if the metric is published with multiple types of units and you + // don't specify a unit, the alarm's behavior is not defined and it behaves + // unpredictably. + // + // We recommend omitting Unit so that you don't inadvertently specify an incorrect + // unit that is not published for this metric. Doing so causes the alarm to + // be stuck in the INSUFFICIENT DATA state. + Unit *string `json:"unit,omitempty"` +} + +// MetricAlarmStatus defines the observed state of MetricAlarm +type MetricAlarmStatus struct { + // All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + // that is used to contain resource sync state, account ownership, + // constructed ARN for the resource + // +kubebuilder:validation:Optional + ACKResourceMetadata *ackv1alpha1.ResourceMetadata `json:"ackResourceMetadata"` + // All CRS managed by ACK have a common `Status.Conditions` member that + // contains a collection of `ackv1alpha1.Condition` objects that describe + // the various terminal states of the CR and its backend AWS service API + // resource + // +kubebuilder:validation:Optional + Conditions []*ackv1alpha1.Condition `json:"conditions"` +} + +// MetricAlarm is the Schema for the MetricAlarms API +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +type MetricAlarm struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec MetricAlarmSpec `json:"spec,omitempty"` + Status MetricAlarmStatus `json:"status,omitempty"` +} + +// MetricAlarmList contains a list of MetricAlarm +// +kubebuilder:object:root=true +type MetricAlarmList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []MetricAlarm `json:"items"` +} + +func init() { + SchemeBuilder.Register(&MetricAlarm{}, &MetricAlarmList{}) +} diff --git a/apis/v1alpha1/types.go b/apis/v1alpha1/types.go new file mode 100644 index 0000000..97d9512 --- /dev/null +++ b/apis/v1alpha1/types.go @@ -0,0 +1,271 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + "github.com/aws/aws-sdk-go/aws" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Hack to avoid import errors during build... +var ( + _ = &metav1.Time{} + _ = &aws.JSONValue{} + _ = ackv1alpha1.AWSAccountID("") +) + +// Represents the history of a specific alarm. +type AlarmHistoryItem struct { + AlarmName *string `json:"alarmName,omitempty"` + AlarmType *string `json:"alarmType,omitempty"` + Timestamp *metav1.Time `json:"timestamp,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. +type AnomalyDetector struct { + Dimensions []*Dimension `json:"dimensions,omitempty"` + MetricName *string `json:"metricName,omitempty"` + Namespace *string `json:"namespace,omitempty"` +} + +// The details about a composite alarm. +type CompositeAlarm struct { + ActionsEnabled *bool `json:"actionsEnabled,omitempty"` + ActionsSuppressedBy *string `json:"actionsSuppressedBy,omitempty"` + ActionsSuppressedReason *string `json:"actionsSuppressedReason,omitempty"` + ActionsSuppressor *string `json:"actionsSuppressor,omitempty"` + ActionsSuppressorExtensionPeriod *int64 `json:"actionsSuppressorExtensionPeriod,omitempty"` + ActionsSuppressorWaitPeriod *int64 `json:"actionsSuppressorWaitPeriod,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"` + AlarmRule *string `json:"alarmRule,omitempty"` + InsufficientDataActions []*string `json:"insufficientDataActions,omitempty"` + OKActions []*string `json:"oKActions,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"` +} + +// Encapsulates the statistical data that CloudWatch computes from metric data. +type Datapoint struct { + Timestamp *metav1.Time `json:"timestamp,omitempty"` + Unit *string `json:"unit,omitempty"` +} + +// A dimension is a name/value pair that is part of the identity of a metric. +// Because dimensions are part of the unique identifier for a metric, whenever +// you add a unique name/value pair to one of your metrics, you are creating +// a new variation of that metric. For example, many Amazon EC2 metrics publish +// InstanceId as a dimension name, and the actual instance ID as the value for +// that dimension. +// +// You can assign up to 30 dimensions to a metric. +type Dimension struct { + Name *string `json:"name,omitempty"` + Value *string `json:"value,omitempty"` +} + +// Represents filters for a dimension. +type DimensionFilter struct { + Name *string `json:"name,omitempty"` + Value *string `json:"value,omitempty"` +} + +// One data point related to one contributor. +// +// For more information, see GetInsightRuleReport (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetInsightRuleReport.html) +// and InsightRuleContributor (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_InsightRuleContributor.html). +type InsightRuleContributorDatapoint struct { + Timestamp *metav1.Time `json:"timestamp,omitempty"` +} + +// One data point from the metric time series returned in a Contributor Insights +// rule report. +// +// For more information, see GetInsightRuleReport (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetInsightRuleReport.html). +type InsightRuleMetricDatapoint struct { + Timestamp *metav1.Time `json:"timestamp,omitempty"` +} + +// Contains the information that's required to enable a managed Contributor +// Insights rule for an Amazon Web Services resource. +type ManagedRule struct { + Tags []*Tag `json:"tags,omitempty"` +} + +// Represents a specific metric. +type Metric struct { + Dimensions []*Dimension `json:"dimensions,omitempty"` + MetricName *string `json:"metricName,omitempty"` + Namespace *string `json:"namespace,omitempty"` +} + +// 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"` +} + +// This structure is used in both GetMetricData and PutMetricAlarm. The supported +// use of this structure is different for those two operations. +// +// When used in GetMetricData, it indicates the metric data to return, and whether +// this call is just retrieving a batch set of data for one metric, or is performing +// a Metrics Insights query or a math expression. A single GetMetricData call +// can include up to 500 MetricDataQuery structures. +// +// When used in PutMetricAlarm, it enables you to create an alarm based on a +// metric math expression. Each MetricDataQuery in the array specifies either +// a metric to retrieve, or a math expression to be performed on retrieved metrics. +// A single PutMetricAlarm call can include up to 20 MetricDataQuery structures +// in the array. The 20 structures can include as many as 10 structures that +// contain a MetricStat parameter to retrieve a metric, and as many as 10 structures +// that contain the Expression parameter to perform a math expression. Of those +// Expression structures, one must have true as the value for ReturnData. The +// result of this expression is the value the alarm watches. +// +// Any expression used in a PutMetricAlarm operation must return a single time +// series. For more information, see Metric Math Syntax and Functions (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/using-metric-math.html#metric-math-syntax) +// in the Amazon CloudWatch User Guide. +// +// Some of the parameters of this structure also have different uses whether +// you are using this structure in a GetMetricData operation or a PutMetricAlarm +// operation. These differences are explained in the following parameter list. +type MetricDataQuery struct { + AccountID *string `json:"accountID,omitempty"` + Expression *string `json:"expression,omitempty"` + ID *string `json:"id,omitempty"` + Label *string `json:"label,omitempty"` + // This structure defines the metric to be returned, along with the statistics, + // period, and units. + MetricStat *MetricStat `json:"metricStat,omitempty"` + Period *int64 `json:"period,omitempty"` + ReturnData *bool `json:"returnData,omitempty"` +} + +// A GetMetricData call returns an array of MetricDataResult structures. Each +// of these structures includes the data points for that metric, along with +// the timestamps of those data points and other identifying information. +type MetricDataResult struct { + ID *string `json:"id,omitempty"` + Label *string `json:"label,omitempty"` +} + +// Encapsulates the information sent to either create a metric or add new values +// to be aggregated into an existing metric. +type MetricDatum struct { + Dimensions []*Dimension `json:"dimensions,omitempty"` + MetricName *string `json:"metricName,omitempty"` + Timestamp *metav1.Time `json:"timestamp,omitempty"` + Unit *string `json:"unit,omitempty"` +} + +// Indicates the CloudWatch math expression that provides the time series the +// anomaly detector uses as input. The designated math expression must return +// a single time series. +type MetricMathAnomalyDetector struct { + MetricDataQueries []*MetricDataQuery `json:"metricDataQueries,omitempty"` +} + +// This structure defines the metric to be returned, along with the statistics, +// period, and units. +type MetricStat struct { + // Represents a specific metric. + Metric *Metric `json:"metric,omitempty"` + Period *int64 `json:"period,omitempty"` + Stat *string `json:"stat,omitempty"` + Unit *string `json:"unit,omitempty"` +} + +// This structure contains the configuration information about one metric stream. +type MetricStreamEntry struct { + CreationDate *metav1.Time `json:"creationDate,omitempty"` + LastUpdateDate *metav1.Time `json:"lastUpdateDate,omitempty"` +} + +// This structure contains a metric namespace and optionally, a list of metric +// names, to either include in a metric stream or exclude from a metric stream. +// +// A metric stream's filters can include up to 1000 total names. This limit +// applies to the sum of namespace names and metric names in the filters. For +// example, this could include 10 metric namespace filters with 99 metrics each, +// or 20 namespace filters with 49 metrics specified in each filter. +type MetricStreamFilter struct { + Namespace *string `json:"namespace,omitempty"` +} + +// This object contains the information for one metric that is to be streamed +// with additional statistics. +type MetricStreamStatisticsMetric struct { + MetricName *string `json:"metricName,omitempty"` + Namespace *string `json:"namespace,omitempty"` +} + +// Specifies one range of days or times to exclude from use for training an +// anomaly detection model. +type Range struct { + EndTime *metav1.Time `json:"endTime,omitempty"` + StartTime *metav1.Time `json:"startTime,omitempty"` +} + +// Designates the CloudWatch metric and statistic that provides the time series +// the anomaly detector uses as input. +type SingleMetricAnomalyDetector struct { + Dimensions []*Dimension `json:"dimensions,omitempty"` + MetricName *string `json:"metricName,omitempty"` + Namespace *string `json:"namespace,omitempty"` +} + +// A key-value pair associated with a CloudWatch resource. +type Tag struct { + Key *string `json:"key,omitempty"` + Value *string `json:"value,omitempty"` +} diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..8c9189c --- /dev/null +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,1156 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + corev1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + 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 *AlarmHistoryItem) DeepCopyInto(out *AlarmHistoryItem) { + *out = *in + if in.AlarmName != nil { + in, out := &in.AlarmName, &out.AlarmName + *out = new(string) + **out = **in + } + if in.AlarmType != nil { + in, out := &in.AlarmType, &out.AlarmType + *out = new(string) + **out = **in + } + if in.Timestamp != nil { + in, out := &in.Timestamp, &out.Timestamp + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlarmHistoryItem. +func (in *AlarmHistoryItem) DeepCopy() *AlarmHistoryItem { + if in == nil { + return nil + } + out := new(AlarmHistoryItem) + 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 + if in.Dimensions != nil { + in, out := &in.Dimensions, &out.Dimensions + *out = make([]*Dimension, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Dimension) + (*in).DeepCopyInto(*out) + } + } + } + if in.MetricName != nil { + in, out := &in.MetricName, &out.MetricName + *out = new(string) + **out = **in + } + if in.Namespace != nil { + in, out := &in.Namespace, &out.Namespace + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnomalyDetector. +func (in *AnomalyDetector) DeepCopy() *AnomalyDetector { + if in == nil { + return nil + } + out := new(AnomalyDetector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompositeAlarm) DeepCopyInto(out *CompositeAlarm) { + *out = *in + if in.ActionsEnabled != nil { + in, out := &in.ActionsEnabled, &out.ActionsEnabled + *out = new(bool) + **out = **in + } + if in.ActionsSuppressedBy != nil { + in, out := &in.ActionsSuppressedBy, &out.ActionsSuppressedBy + *out = new(string) + **out = **in + } + if in.ActionsSuppressedReason != nil { + in, out := &in.ActionsSuppressedReason, &out.ActionsSuppressedReason + *out = new(string) + **out = **in + } + if in.ActionsSuppressor != nil { + in, out := &in.ActionsSuppressor, &out.ActionsSuppressor + *out = new(string) + **out = **in + } + if in.ActionsSuppressorExtensionPeriod != nil { + in, out := &in.ActionsSuppressorExtensionPeriod, &out.ActionsSuppressorExtensionPeriod + *out = new(int64) + **out = **in + } + if in.ActionsSuppressorWaitPeriod != nil { + in, out := &in.ActionsSuppressorWaitPeriod, &out.ActionsSuppressorWaitPeriod + *out = new(int64) + **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.AlarmRule != nil { + in, out := &in.AlarmRule, &out.AlarmRule + *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.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 + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompositeAlarm. +func (in *CompositeAlarm) DeepCopy() *CompositeAlarm { + if in == nil { + return nil + } + out := new(CompositeAlarm) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Datapoint) DeepCopyInto(out *Datapoint) { + *out = *in + if in.Timestamp != nil { + in, out := &in.Timestamp, &out.Timestamp + *out = (*in).DeepCopy() + } + if in.Unit != nil { + in, out := &in.Unit, &out.Unit + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Datapoint. +func (in *Datapoint) DeepCopy() *Datapoint { + if in == nil { + return nil + } + out := new(Datapoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Dimension) DeepCopyInto(out *Dimension) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Dimension. +func (in *Dimension) DeepCopy() *Dimension { + if in == nil { + return nil + } + out := new(Dimension) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DimensionFilter) DeepCopyInto(out *DimensionFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DimensionFilter. +func (in *DimensionFilter) DeepCopy() *DimensionFilter { + if in == nil { + return nil + } + out := new(DimensionFilter) + 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 + if in.Timestamp != nil { + in, out := &in.Timestamp, &out.Timestamp + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InsightRuleContributorDatapoint. +func (in *InsightRuleContributorDatapoint) DeepCopy() *InsightRuleContributorDatapoint { + if in == nil { + return nil + } + out := new(InsightRuleContributorDatapoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InsightRuleMetricDatapoint) DeepCopyInto(out *InsightRuleMetricDatapoint) { + *out = *in + if in.Timestamp != nil { + in, out := &in.Timestamp, &out.Timestamp + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InsightRuleMetricDatapoint. +func (in *InsightRuleMetricDatapoint) DeepCopy() *InsightRuleMetricDatapoint { + if in == nil { + return nil + } + out := new(InsightRuleMetricDatapoint) + 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 + 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 ManagedRule. +func (in *ManagedRule) DeepCopy() *ManagedRule { + if in == nil { + return nil + } + out := new(ManagedRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Metric) DeepCopyInto(out *Metric) { + *out = *in + if in.Dimensions != nil { + in, out := &in.Dimensions, &out.Dimensions + *out = make([]*Dimension, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Dimension) + (*in).DeepCopyInto(*out) + } + } + } + if in.MetricName != nil { + in, out := &in.MetricName, &out.MetricName + *out = new(string) + **out = **in + } + if in.Namespace != nil { + in, out := &in.Namespace, &out.Namespace + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Metric. +func (in *Metric) DeepCopy() *Metric { + if in == nil { + return nil + } + out := new(Metric) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricAlarm) DeepCopyInto(out *MetricAlarm) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricAlarm. +func (in *MetricAlarm) DeepCopy() *MetricAlarm { + if in == nil { + return nil + } + out := new(MetricAlarm) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MetricAlarm) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricAlarmList) DeepCopyInto(out *MetricAlarmList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MetricAlarm, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricAlarmList. +func (in *MetricAlarmList) DeepCopy() *MetricAlarmList { + if in == nil { + return nil + } + out := new(MetricAlarmList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MetricAlarmList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricAlarmSpec) DeepCopyInto(out *MetricAlarmSpec) { + *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.AlarmDescription != nil { + in, out := &in.AlarmDescription, &out.AlarmDescription + *out = new(string) + **out = **in + } + if in.ComparisonOperator != nil { + in, out := &in.ComparisonOperator, &out.ComparisonOperator + *out = new(string) + **out = **in + } + if in.DatapointsToAlarm != nil { + in, out := &in.DatapointsToAlarm, &out.DatapointsToAlarm + *out = new(int64) + **out = **in + } + if in.Dimensions != nil { + in, out := &in.Dimensions, &out.Dimensions + *out = make([]*Dimension, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Dimension) + (*in).DeepCopyInto(*out) + } + } + } + if in.EvaluateLowSampleCountPercentile != nil { + in, out := &in.EvaluateLowSampleCountPercentile, &out.EvaluateLowSampleCountPercentile + *out = new(string) + **out = **in + } + if in.EvaluationPeriods != nil { + in, out := &in.EvaluationPeriods, &out.EvaluationPeriods + *out = new(int64) + **out = **in + } + if in.ExtendedStatistic != nil { + in, out := &in.ExtendedStatistic, &out.ExtendedStatistic + *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.MetricName != nil { + in, out := &in.MetricName, &out.MetricName + *out = new(string) + **out = **in + } + if in.Metrics != nil { + in, out := &in.Metrics, &out.Metrics + *out = make([]*MetricDataQuery, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MetricDataQuery) + (*in).DeepCopyInto(*out) + } + } + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.Namespace != nil { + in, out := &in.Namespace, &out.Namespace + *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.Period != nil { + in, out := &in.Period, &out.Period + *out = new(int64) + **out = **in + } + if in.Statistic != nil { + in, out := &in.Statistic, &out.Statistic + *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) + } + } + } + if in.Threshold != nil { + in, out := &in.Threshold, &out.Threshold + *out = new(float64) + **out = **in + } + if in.ThresholdMetricID != nil { + in, out := &in.ThresholdMetricID, &out.ThresholdMetricID + *out = new(string) + **out = **in + } + if in.TreatMissingData != nil { + in, out := &in.TreatMissingData, &out.TreatMissingData + *out = new(string) + **out = **in + } + if in.Unit != nil { + in, out := &in.Unit, &out.Unit + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricAlarmSpec. +func (in *MetricAlarmSpec) DeepCopy() *MetricAlarmSpec { + if in == nil { + return nil + } + out := new(MetricAlarmSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricAlarmStatus) DeepCopyInto(out *MetricAlarmStatus) { + *out = *in + if in.ACKResourceMetadata != nil { + in, out := &in.ACKResourceMetadata, &out.ACKResourceMetadata + *out = new(corev1alpha1.ResourceMetadata) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]*corev1alpha1.Condition, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(corev1alpha1.Condition) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricAlarmStatus. +func (in *MetricAlarmStatus) DeepCopy() *MetricAlarmStatus { + if in == nil { + return nil + } + out := new(MetricAlarmStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricAlarm_SDK) DeepCopyInto(out *MetricAlarm_SDK) { + *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.DatapointsToAlarm != nil { + in, out := &in.DatapointsToAlarm, &out.DatapointsToAlarm + *out = new(int64) + **out = **in + } + if in.Dimensions != nil { + in, out := &in.Dimensions, &out.Dimensions + *out = make([]*Dimension, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Dimension) + (*in).DeepCopyInto(*out) + } + } + } + if in.EvaluateLowSampleCountPercentile != nil { + in, out := &in.EvaluateLowSampleCountPercentile, &out.EvaluateLowSampleCountPercentile + *out = new(string) + **out = **in + } + if in.EvaluationPeriods != nil { + in, out := &in.EvaluationPeriods, &out.EvaluationPeriods + *out = new(int64) + **out = **in + } + if in.EvaluationState != nil { + in, out := &in.EvaluationState, &out.EvaluationState + *out = new(string) + **out = **in + } + if in.ExtendedStatistic != nil { + in, out := &in.ExtendedStatistic, &out.ExtendedStatistic + *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.MetricName != nil { + in, out := &in.MetricName, &out.MetricName + *out = new(string) + **out = **in + } + if in.Metrics != nil { + in, out := &in.Metrics, &out.Metrics + *out = make([]*MetricDataQuery, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MetricDataQuery) + (*in).DeepCopyInto(*out) + } + } + } + if in.Namespace != nil { + in, out := &in.Namespace, &out.Namespace + *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.Period != nil { + in, out := &in.Period, &out.Period + *out = new(int64) + **out = **in + } + 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.Statistic != nil { + in, out := &in.Statistic, &out.Statistic + *out = new(string) + **out = **in + } + if in.Threshold != nil { + in, out := &in.Threshold, &out.Threshold + *out = new(float64) + **out = **in + } + if in.ThresholdMetricID != nil { + in, out := &in.ThresholdMetricID, &out.ThresholdMetricID + *out = new(string) + **out = **in + } + if in.TreatMissingData != nil { + in, out := &in.TreatMissingData, &out.TreatMissingData + *out = new(string) + **out = **in + } + if in.Unit != nil { + in, out := &in.Unit, &out.Unit + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricAlarm_SDK. +func (in *MetricAlarm_SDK) DeepCopy() *MetricAlarm_SDK { + if in == nil { + return nil + } + out := new(MetricAlarm_SDK) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricDataQuery) DeepCopyInto(out *MetricDataQuery) { + *out = *in + if in.AccountID != nil { + in, out := &in.AccountID, &out.AccountID + *out = new(string) + **out = **in + } + if in.Expression != nil { + in, out := &in.Expression, &out.Expression + *out = new(string) + **out = **in + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Label != nil { + in, out := &in.Label, &out.Label + *out = new(string) + **out = **in + } + if in.MetricStat != nil { + in, out := &in.MetricStat, &out.MetricStat + *out = new(MetricStat) + (*in).DeepCopyInto(*out) + } + if in.Period != nil { + in, out := &in.Period, &out.Period + *out = new(int64) + **out = **in + } + if in.ReturnData != nil { + in, out := &in.ReturnData, &out.ReturnData + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricDataQuery. +func (in *MetricDataQuery) DeepCopy() *MetricDataQuery { + if in == nil { + return nil + } + out := new(MetricDataQuery) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricDataResult) DeepCopyInto(out *MetricDataResult) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Label != nil { + in, out := &in.Label, &out.Label + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricDataResult. +func (in *MetricDataResult) DeepCopy() *MetricDataResult { + if in == nil { + return nil + } + out := new(MetricDataResult) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricDatum) DeepCopyInto(out *MetricDatum) { + *out = *in + if in.Dimensions != nil { + in, out := &in.Dimensions, &out.Dimensions + *out = make([]*Dimension, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Dimension) + (*in).DeepCopyInto(*out) + } + } + } + if in.MetricName != nil { + in, out := &in.MetricName, &out.MetricName + *out = new(string) + **out = **in + } + if in.Timestamp != nil { + in, out := &in.Timestamp, &out.Timestamp + *out = (*in).DeepCopy() + } + if in.Unit != nil { + in, out := &in.Unit, &out.Unit + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricDatum. +func (in *MetricDatum) DeepCopy() *MetricDatum { + if in == nil { + return nil + } + out := new(MetricDatum) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricMathAnomalyDetector) DeepCopyInto(out *MetricMathAnomalyDetector) { + *out = *in + if in.MetricDataQueries != nil { + in, out := &in.MetricDataQueries, &out.MetricDataQueries + *out = make([]*MetricDataQuery, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MetricDataQuery) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricMathAnomalyDetector. +func (in *MetricMathAnomalyDetector) DeepCopy() *MetricMathAnomalyDetector { + if in == nil { + return nil + } + out := new(MetricMathAnomalyDetector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricStat) DeepCopyInto(out *MetricStat) { + *out = *in + if in.Metric != nil { + in, out := &in.Metric, &out.Metric + *out = new(Metric) + (*in).DeepCopyInto(*out) + } + if in.Period != nil { + in, out := &in.Period, &out.Period + *out = new(int64) + **out = **in + } + if in.Stat != nil { + in, out := &in.Stat, &out.Stat + *out = new(string) + **out = **in + } + if in.Unit != nil { + in, out := &in.Unit, &out.Unit + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricStat. +func (in *MetricStat) DeepCopy() *MetricStat { + if in == nil { + return nil + } + out := new(MetricStat) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricStreamEntry) DeepCopyInto(out *MetricStreamEntry) { + *out = *in + if in.CreationDate != nil { + in, out := &in.CreationDate, &out.CreationDate + *out = (*in).DeepCopy() + } + if in.LastUpdateDate != nil { + in, out := &in.LastUpdateDate, &out.LastUpdateDate + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricStreamEntry. +func (in *MetricStreamEntry) DeepCopy() *MetricStreamEntry { + if in == nil { + return nil + } + out := new(MetricStreamEntry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricStreamFilter) DeepCopyInto(out *MetricStreamFilter) { + *out = *in + if in.Namespace != nil { + in, out := &in.Namespace, &out.Namespace + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricStreamFilter. +func (in *MetricStreamFilter) DeepCopy() *MetricStreamFilter { + if in == nil { + return nil + } + out := new(MetricStreamFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricStreamStatisticsMetric) DeepCopyInto(out *MetricStreamStatisticsMetric) { + *out = *in + if in.MetricName != nil { + in, out := &in.MetricName, &out.MetricName + *out = new(string) + **out = **in + } + if in.Namespace != nil { + in, out := &in.Namespace, &out.Namespace + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricStreamStatisticsMetric. +func (in *MetricStreamStatisticsMetric) DeepCopy() *MetricStreamStatisticsMetric { + if in == nil { + return nil + } + out := new(MetricStreamStatisticsMetric) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Range) DeepCopyInto(out *Range) { + *out = *in + if in.EndTime != nil { + in, out := &in.EndTime, &out.EndTime + *out = (*in).DeepCopy() + } + if in.StartTime != nil { + in, out := &in.StartTime, &out.StartTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Range. +func (in *Range) DeepCopy() *Range { + if in == nil { + return nil + } + out := new(Range) + 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 + if in.Dimensions != nil { + in, out := &in.Dimensions, &out.Dimensions + *out = make([]*Dimension, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Dimension) + (*in).DeepCopyInto(*out) + } + } + } + if in.MetricName != nil { + in, out := &in.MetricName, &out.MetricName + *out = new(string) + **out = **in + } + if in.Namespace != nil { + in, out := &in.Namespace, &out.Namespace + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SingleMetricAnomalyDetector. +func (in *SingleMetricAnomalyDetector) DeepCopy() *SingleMetricAnomalyDetector { + if in == nil { + return nil + } + out := new(SingleMetricAnomalyDetector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Tag) DeepCopyInto(out *Tag) { + *out = *in + if in.Key != nil { + in, out := &in.Key, &out.Key + *out = new(string) + **out = **in + } + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Tag. +func (in *Tag) DeepCopy() *Tag { + if in == nil { + return nil + } + out := new(Tag) + in.DeepCopyInto(out) + return out +} diff --git a/cmd/controller/main.go b/cmd/controller/main.go new file mode 100644 index 0000000..bb48898 --- /dev/null +++ b/cmd/controller/main.go @@ -0,0 +1,157 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package main + +import ( + "os" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" + ackrt "github.com/aws-controllers-k8s/runtime/pkg/runtime" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + ackrtutil "github.com/aws-controllers-k8s/runtime/pkg/util" + ackrtwebhook "github.com/aws-controllers-k8s/runtime/pkg/webhook" + svcsdk "github.com/aws/aws-sdk-go/service/cloudwatch" + flag "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrlrt "sigs.k8s.io/controller-runtime" + ctrlrtmetrics "sigs.k8s.io/controller-runtime/pkg/metrics" + + svctypes "github.com/aws-controllers-k8s/cloudwatch-controller/apis/v1alpha1" + svcresource "github.com/aws-controllers-k8s/cloudwatch-controller/pkg/resource" + + _ "github.com/aws-controllers-k8s/cloudwatch-controller/pkg/resource/metric_alarm" + + "github.com/aws-controllers-k8s/cloudwatch-controller/pkg/version" +) + +var ( + awsServiceAPIGroup = "cloudwatch.services.k8s.aws" + awsServiceAlias = "cloudwatch" + awsServiceEndpointsID = svcsdk.EndpointsID + scheme = runtime.NewScheme() + setupLog = ctrlrt.Log.WithName("setup") +) + +func init() { + _ = clientgoscheme.AddToScheme(scheme) + + _ = svctypes.AddToScheme(scheme) + _ = ackv1alpha1.AddToScheme(scheme) +} + +func main() { + var ackCfg ackcfg.Config + ackCfg.BindFlags() + flag.Parse() + ackCfg.SetupLogger() + + managerFactories := svcresource.GetManagerFactories() + resourceGVKs := make([]schema.GroupVersionKind, 0, len(managerFactories)) + for _, mf := range managerFactories { + resourceGVKs = append(resourceGVKs, mf.ResourceDescriptor().GroupVersionKind()) + } + + if err := ackCfg.Validate(ackcfg.WithGVKs(resourceGVKs)); err != nil { + setupLog.Error( + err, "Unable to create controller manager", + "aws.service", awsServiceAlias, + ) + os.Exit(1) + } + + host, port, err := ackrtutil.GetHostPort(ackCfg.WebhookServerAddr) + if err != nil { + setupLog.Error( + err, "Unable to parse webhook server address.", + "aws.service", awsServiceAlias, + ) + os.Exit(1) + } + + mgr, err := ctrlrt.NewManager(ctrlrt.GetConfigOrDie(), ctrlrt.Options{ + Scheme: scheme, + Port: port, + Host: host, + MetricsBindAddress: ackCfg.MetricsAddr, + LeaderElection: ackCfg.EnableLeaderElection, + LeaderElectionID: awsServiceAPIGroup, + Namespace: ackCfg.WatchNamespace, + }) + if err != nil { + setupLog.Error( + err, "unable to create controller manager", + "aws.service", awsServiceAlias, + ) + os.Exit(1) + } + + stopChan := ctrlrt.SetupSignalHandler() + + setupLog.Info( + "initializing service controller", + "aws.service", awsServiceAlias, + ) + sc := ackrt.NewServiceController( + awsServiceAlias, awsServiceAPIGroup, awsServiceEndpointsID, + acktypes.VersionInfo{ + version.GitCommit, + version.GitVersion, + version.BuildDate, + }, + ).WithLogger( + ctrlrt.Log, + ).WithResourceManagerFactories( + svcresource.GetManagerFactories(), + ).WithPrometheusRegistry( + ctrlrtmetrics.Registry, + ) + + if ackCfg.EnableWebhookServer { + webhooks := ackrtwebhook.GetWebhooks() + for _, webhook := range webhooks { + if err := webhook.Setup(mgr); err != nil { + setupLog.Error( + err, "unable to register webhook "+webhook.UID(), + "aws.service", awsServiceAlias, + ) + + } + } + } + + if err = sc.BindControllerManager(mgr, ackCfg); err != nil { + setupLog.Error( + err, "unable bind to controller manager to service controller", + "aws.service", awsServiceAlias, + ) + os.Exit(1) + } + + setupLog.Info( + "starting manager", + "aws.service", awsServiceAlias, + ) + if err := mgr.Start(stopChan); err != nil { + setupLog.Error( + err, "unable to start controller manager", + "aws.service", awsServiceAlias, + ) + os.Exit(1) + } +} diff --git a/config/controller/deployment.yaml b/config/controller/deployment.yaml new file mode 100644 index 0000000..53a9c2c --- /dev/null +++ b/config/controller/deployment.yaml @@ -0,0 +1,83 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: ack-system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ack-cloudwatch-controller + namespace: ack-system + labels: + app.kubernetes.io/name: ack-cloudwatch-controller + app.kubernetes.io/part-of: ack-system +spec: + selector: + matchLabels: + app.kubernetes.io/name: ack-cloudwatch-controller + replicas: 1 + template: + metadata: + labels: + app.kubernetes.io/name: ack-cloudwatch-controller + spec: + containers: + - command: + - ./bin/controller + args: + - --aws-region + - "$(AWS_REGION)" + - --aws-endpoint-url + - "$(AWS_ENDPOINT_URL)" + - --enable-development-logging + - "$(ACK_ENABLE_DEVELOPMENT_LOGGING)" + - --log-level + - "$(ACK_LOG_LEVEL)" + - --resource-tags + - "$(ACK_RESOURCE_TAGS)" + - --watch-namespace + - "$(ACK_WATCH_NAMESPACE)" + image: controller:latest + name: controller + ports: + - name: http + containerPort: 8080 + resources: + limits: + cpu: 100m + memory: 300Mi + requests: + cpu: 100m + memory: 200Mi + env: + - name: ACK_SYSTEM_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: AWS_REGION + value: "" + - name: AWS_ENDPOINT_URL + value: "" + - name: ACK_WATCH_NAMESPACE + value: "" + - name: ACK_ENABLE_DEVELOPMENT_LOGGING + value: "false" + - name: ACK_LOG_LEVEL + value: "info" + - name: ACK_RESOURCE_TAGS + value: "services.k8s.aws/controller-version=%CONTROLLER_SERVICE%-%CONTROLLER_VERSION%,services.k8s.aws/namespace=%K8S_NAMESPACE%" + securityContext: + allowPrivilegeEscalation: false + privileged: false + runAsNonRoot: true + capabilities: + drop: + - ALL + securityContext: + seccompProfile: + type: RuntimeDefault + terminationGracePeriodSeconds: 10 + serviceAccountName: ack-cloudwatch-controller + hostIPC: false + hostNetwork: false + hostPID: false diff --git a/config/controller/kustomization.yaml b/config/controller/kustomization.yaml new file mode 100644 index 0000000..84b9fed --- /dev/null +++ b/config/controller/kustomization.yaml @@ -0,0 +1,9 @@ +resources: +- deployment.yaml +- service.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: controller + newName: public.ecr.aws/aws-controllers-k8s/cloudwatch-controller + newTag: 0.0.0-non-release-version diff --git a/config/controller/service.yaml b/config/controller/service.yaml new file mode 100644 index 0000000..69acefd --- /dev/null +++ b/config/controller/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: ack-cloudwatch-metrics-service + namespace: ack-system +spec: + selector: + app.kubernetes.io/name: ack-cloudwatch-controller + ports: + - name: metricsport + port: 8080 + targetPort: http + protocol: TCP + type: NodePort diff --git a/config/crd/bases/cloudwatch.services.k8s.aws_metricalarms.yaml b/config/crd/bases/cloudwatch.services.k8s.aws_metricalarms.yaml new file mode 100644 index 0000000..e03e82b --- /dev/null +++ b/config/crd/bases/cloudwatch.services.k8s.aws_metricalarms.yaml @@ -0,0 +1,425 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: metricalarms.cloudwatch.services.k8s.aws +spec: + group: cloudwatch.services.k8s.aws + names: + kind: MetricAlarm + listKind: MetricAlarmList + plural: metricalarms + singular: metricalarm + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: MetricAlarm is the Schema for the MetricAlarms API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: "MetricAlarmSpec defines the desired state of MetricAlarm. + \n The details about a metric alarm." + properties: + actionsEnabled: + description: Indicates whether actions should be executed during any + changes to the alarm state. The default is TRUE. + type: boolean + alarmActions: + description: "The actions to execute when this alarm transitions to + the ALARM state from any other state. Each action is specified as + an Amazon Resource Name (ARN). Valid values: \n EC2 actions: \n + * arn:aws:automate:region:ec2:stop \n * arn:aws:automate:region:ec2:terminate + \n * arn:aws:automate:region:ec2:reboot \n * arn:aws:automate:region:ec2:recover + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Stop/1.0 + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Recover/1.0 + \n Autoscaling action: \n * arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SNS notification action: \n * arn:aws:sns:region:account-id:sns-topic-name:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SSM integration actions: \n * arn:aws:ssm:region:account-id:opsitem:severity#CATEGORY=category-name + \n * arn:aws:ssm-incidents::account-id:responseplan/response-plan-name" + items: + type: string + type: array + alarmDescription: + description: The description for the alarm. + type: string + comparisonOperator: + description: "The arithmetic operation to use when comparing the specified + statistic and threshold. The specified statistic value is used as + the first operand. \n The values LessThanLowerOrGreaterThanUpperThreshold, + LessThanLowerThreshold, and GreaterThanUpperThreshold are used only + for alarms based on anomaly detection models." + type: string + datapointsToAlarm: + description: 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) + in the Amazon CloudWatch User Guide. + format: int64 + type: integer + dimensions: + description: The dimensions for the metric specified in MetricName. + items: + description: "A dimension is a name/value pair that is part of the + identity of a metric. Because dimensions are part of the unique + identifier for a metric, whenever you add a unique name/value + pair to one of your metrics, you are creating a new variation + of that metric. For example, many Amazon EC2 metrics publish InstanceId + as a dimension name, and the actual instance ID as the value for + that dimension. \n You can assign up to 30 dimensions to a metric." + properties: + name: + type: string + value: + type: string + type: object + type: array + evaluateLowSampleCountPercentile: + description: "Used only for alarms based on percentiles. If you specify + ignore, the alarm state does not change during periods with too + few data points to be statistically significant. If you specify + evaluate or omit this parameter, the alarm is always evaluated and + possibly changes state no matter how many data points are available. + For more information, see Percentile-Based CloudWatch Alarms and + Low Data Samples (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#percentiles-with-low-samples). + \n Valid Values: evaluate | ignore" + type: string + 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. \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 + extendedStatistic: + description: The percentile statistic for the metric specified in + MetricName. Specify a value between p0.0 and p100. When you call + PutMetricAlarm and specify a MetricName, you must specify either + Statistic or ExtendedStatistic, but not both. + type: string + insufficientDataActions: + description: "The actions to execute when this alarm transitions to + the INSUFFICIENT_DATA state from any other state. Each action is + specified as an Amazon Resource Name (ARN). Valid values: \n EC2 + actions: \n * arn:aws:automate:region:ec2:stop \n * arn:aws:automate:region:ec2:terminate + \n * arn:aws:automate:region:ec2:reboot \n * arn:aws:automate:region:ec2:recover + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Stop/1.0 + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Recover/1.0 + \n Autoscaling action: \n * arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SNS notification action: \n * arn:aws:sns:region:account-id:sns-topic-name:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SSM integration actions: \n * arn:aws:ssm:region:account-id:opsitem:severity#CATEGORY=category-name + \n * arn:aws:ssm-incidents::account-id:responseplan/response-plan-name" + items: + type: string + type: array + metricName: + description: "The name for the metric associated with the alarm. For + each PutMetricAlarm operation, you must specify either MetricName + or a Metrics array. \n If you are creating an alarm based on a math + expression, you cannot specify this parameter, or any of the Dimensions, + Period, Namespace, Statistic, or ExtendedStatistic parameters. Instead, + you specify all this information in the Metrics array." + type: string + metrics: + 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. \n Each item in the Metrics array either retrieves + a metric or performs a math expression. \n One item in the Metrics + array is the expression that the alarm watches. You designate this + expression by setting ReturnData to true for this object in the + array. For more information, see MetricDataQuery (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDataQuery.html). + \n If you use the Metrics parameter, you cannot include the MetricName, + Dimensions, Period, Namespace, Statistic, or ExtendedStatistic parameters + of PutMetricAlarm in the same operation. Instead, you retrieve the + metrics you are using in your math expression as part of the Metrics + array." + items: + description: "This structure is used in both GetMetricData and PutMetricAlarm. + The supported use of this structure is different for those two + operations. \n When used in GetMetricData, it indicates the metric + data to return, and whether this call is just retrieving a batch + set of data for one metric, or is performing a Metrics Insights + query or a math expression. A single GetMetricData call can include + up to 500 MetricDataQuery structures. \n When used in PutMetricAlarm, + it enables you to create an alarm based on a metric math expression. + Each MetricDataQuery in the array specifies either a metric to + retrieve, or a math expression to be performed on retrieved metrics. + A single PutMetricAlarm call can include up to 20 MetricDataQuery + structures in the array. The 20 structures can include as many + as 10 structures that contain a MetricStat parameter to retrieve + a metric, and as many as 10 structures that contain the Expression + parameter to perform a math expression. Of those Expression structures, + one must have true as the value for ReturnData. The result of + this expression is the value the alarm watches. \n Any expression + used in a PutMetricAlarm operation must return a single time series. + For more information, see Metric Math Syntax and Functions (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/using-metric-math.html#metric-math-syntax) + in the Amazon CloudWatch User Guide. \n Some of the parameters + of this structure also have different uses whether you are using + this structure in a GetMetricData operation or a PutMetricAlarm + operation. These differences are explained in the following parameter + list." + properties: + accountID: + type: string + expression: + type: string + id: + type: string + label: + type: string + metricStat: + description: This structure defines the metric to be returned, + along with the statistics, period, and units. + properties: + metric: + description: Represents a specific metric. + properties: + dimensions: + items: + description: "A dimension is a name/value pair that + is part of the identity of a metric. Because dimensions + are part of the unique identifier for a metric, + whenever you add a unique name/value pair to one + of your metrics, you are creating a new variation + of that metric. For example, many Amazon EC2 metrics + publish InstanceId as a dimension name, and the + actual instance ID as the value for that dimension. + \n You can assign up to 30 dimensions to a metric." + properties: + name: + type: string + value: + type: string + type: object + type: array + metricName: + type: string + namespace: + type: string + type: object + period: + format: int64 + type: integer + stat: + type: string + unit: + type: string + type: object + period: + format: int64 + type: integer + returnData: + type: boolean + type: object + type: array + name: + description: "The name for the alarm. This name must be unique within + the Region. \n The name must contain only UTF-8 characters, and + can't contain ASCII control characters" + type: string + namespace: + description: The namespace for the metric associated specified in + MetricName. + type: string + oKActions: + description: "The actions to execute when this alarm transitions to + an OK state from any other state. Each action is specified as an + Amazon Resource Name (ARN). Valid values: \n EC2 actions: \n * arn:aws:automate:region:ec2:stop + \n * arn:aws:automate:region:ec2:terminate \n * arn:aws:automate:region:ec2:reboot + \n * arn:aws:automate:region:ec2:recover \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Stop/1.0 + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + \n * arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Recover/1.0 + \n Autoscaling action: \n * arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SNS notification action: \n * arn:aws:sns:region:account-id:sns-topic-name:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SSM integration actions: \n * arn:aws:ssm:region:account-id:opsitem:severity#CATEGORY=category-name + \n * arn:aws:ssm-incidents::account-id:responseplan/response-plan-name" + items: + type: string + type: array + 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. \n 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. \n 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 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, see Amazon CloudWatch Pricing (https://aws.amazon.com/cloudwatch/pricing/). + \n 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." + format: int64 + type: integer + statistic: + description: The statistic for the metric specified in MetricName, + other than percentile. For percentile statistics, use ExtendedStatistic. + When you call PutMetricAlarm and specify a MetricName, you must + specify either Statistic or ExtendedStatistic, but not both. + type: string + tags: + description: "A list of key-value pairs to associate with the alarm. + You can associate as many as 50 tags with an alarm. \n Tags can + help you organize and categorize your resources. You can also use + them to scope user permissions by granting a user permission to + access or change only resources with certain tag values. \n If you + are using this operation to update an existing alarm, any tags you + specify in this parameter are ignored. To change the tags of an + existing alarm, use TagResource (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_TagResource.html) + or UntagResource (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_UntagResource.html)." + items: + description: A key-value pair associated with a CloudWatch resource. + properties: + key: + type: string + value: + type: string + type: object + type: array + threshold: + description: "The value against which the specified statistic is compared. + \n This parameter is required for alarms based on static thresholds, + but should not be used for alarms based on anomaly detection models." + type: number + thresholdMetricID: + description: "If this is an alarm based on an anomaly detection model, + make this value match the ID of the ANOMALY_DETECTION_BAND function. + \n For an example of how to use this parameter, see the Anomaly + Detection Model Alarm example on this page. \n If your alarm uses + this parameter, it cannot have Auto Scaling actions." + type: string + treatMissingData: + description: "Sets how this alarm is to handle missing data points. + If TreatMissingData is omitted, the default behavior of missing + is used. For more information, see Configuring How CloudWatch Alarms + Treats Missing Data (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-missing-data). + \n Valid Values: breaching | notBreaching | ignore | missing \n + Alarms that evaluate metrics in the AWS/DynamoDB namespace always + ignore 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." + type: string + unit: + description: "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 that an instance receives on + all network interfaces. You can also specify a unit when you create + a custom metric. Units help provide conceptual meaning to your data. + Metric data points that specify a unit of measure, such as Percent, + are aggregated separately. \n If you don't specify Unit, CloudWatch + retrieves all unit types that have been published for the metric + and attempts to evaluate the alarm. Usually, metrics are published + with only one unit, so the alarm works as intended. \n However, + if the metric is published with multiple types of units and you + don't specify a unit, the alarm's behavior is not defined and it + behaves unpredictably. \n We recommend omitting Unit so that you + don't inadvertently specify an incorrect unit that is not published + for this metric. Doing so causes the alarm to be stuck in the INSUFFICIENT + DATA state." + type: string + required: + - comparisonOperator + - evaluationPeriods + - name + type: object + status: + description: MetricAlarmStatus defines the observed state of MetricAlarm + properties: + ackResourceMetadata: + description: All CRs managed by ACK have a common `Status.ACKResourceMetadata` + member that is used to contain resource sync state, account ownership, + constructed ARN for the resource + properties: + arn: + description: 'ARN is the Amazon Resource Name for the resource. + This is a globally-unique identifier and is set only by the + ACK service controller once the controller has orchestrated + the creation of the resource OR when it has verified that an + "adopted" resource (a resource where the ARN annotation was + set by the Kubernetes user on the CR) exists and matches the + supplied CR''s Spec field values. TODO(vijat@): Find a better + strategy for resources that do not have ARN in CreateOutputResponse + https://github.com/aws/aws-controllers-k8s/issues/270' + type: string + ownerAccountID: + description: OwnerAccountID is the AWS Account ID of the account + that owns the backend AWS service API resource. + type: string + region: + description: Region is the AWS region in which the resource exists + or will exist. + type: string + required: + - ownerAccountID + - region + type: object + conditions: + description: All CRS managed by ACK have a common `Status.Conditions` + member that contains a collection of `ackv1alpha1.Condition` objects + that describe the various terminal states of the CR and its backend + AWS service API resource + items: + description: Condition is the common struct used by all CRDs managed + by ACK service controllers to indicate terminal states of the + CR and its backend AWS service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/common/bases/services.k8s.aws_adoptedresources.yaml b/config/crd/common/bases/services.k8s.aws_adoptedresources.yaml new file mode 100644 index 0000000..7dca541 --- /dev/null +++ b/config/crd/common/bases/services.k8s.aws_adoptedresources.yaml @@ -0,0 +1,226 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: adoptedresources.services.k8s.aws +spec: + group: services.k8s.aws + names: + kind: AdoptedResource + listKind: AdoptedResourceList + plural: adoptedresources + singular: adoptedresource + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AdoptedResource is the schema for the AdoptedResource API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AdoptedResourceSpec defines the desired state of the AdoptedResource. + properties: + aws: + description: AWSIdentifiers provide all unique ways to reference an + AWS resource. + properties: + additionalKeys: + additionalProperties: + type: string + description: AdditionalKeys represents any additional arbitrary + identifiers used when describing the target resource. + type: object + arn: + description: ARN is the AWS Resource Name for the resource. It + is a globally unique identifier. + type: string + nameOrID: + description: NameOrId is a user-supplied string identifier for + the resource. It may or may not be globally unique, depending + on the type of resource. + type: string + type: object + kubernetes: + description: ResourceWithMetadata provides the values necessary to + create a Kubernetes resource and override any of its metadata values. + properties: + group: + type: string + kind: + type: string + metadata: + description: "ObjectMeta is metadata that all persisted resources + must have, which includes all objects users must create. It + is not possible to use `metav1.ObjectMeta` inside spec, as the + controller-gen automatically converts this to an arbitrary string-string + map. https://github.com/kubernetes-sigs/controller-tools/issues/385 + \n Active discussion about inclusion of this field in the spec + is happening in this PR: https://github.com/kubernetes-sigs/controller-tools/pull/395 + \n Until this is allowed, or if it never is, we will produce + a subset of the object meta that contains only the fields which + the user is allowed to modify in the metadata." + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value map + stored with a resource that may be set by external tools + to store and retrieve arbitrary metadata. They are not queryable + and should be preserved when modifying objects. More info: + http://kubernetes.io/docs/user-guide/annotations' + type: object + generateName: + description: "GenerateName is an optional prefix, used by + the server, to generate a unique name ONLY IF the Name field + has not been provided. If this field is used, the name returned + to the client will be different than the name passed. This + value will also be combined with a unique suffix. The provided + value has the same validation rules as the Name field, and + may be truncated by the length of the suffix required to + make the value unique on the server. \n If this field is + specified and the generated name exists, the server will + NOT return a 409 - instead, it will either return 201 Created + or 500 with Reason ServerTimeout indicating a unique name + could not be found in the time allotted, and the client + should retry (optionally after the time indicated in the + Retry-After header). \n Applied only if Name is not specified. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency" + type: string + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be used + to organize and categorize (scope and select) objects. May + match selectors of replication controllers and services. + More info: http://kubernetes.io/docs/user-guide/labels' + type: object + name: + description: 'Name must be unique within a namespace. Is required + when creating resources, although some resources may allow + a client to request the generation of an appropriate name + automatically. Name is primarily intended for creation idempotence + and configuration definition. Cannot be updated. More info: + http://kubernetes.io/docs/user-guide/identifiers#names' + type: string + namespace: + description: "Namespace defines the space within each name + must be unique. An empty namespace is equivalent to the + \"default\" namespace, but \"default\" is the canonical + representation. Not all objects are required to be scoped + to a namespace - the value of this field for those objects + will be empty. \n Must be a DNS_LABEL. Cannot be updated. + More info: http://kubernetes.io/docs/user-guide/namespaces" + type: string + ownerReferences: + description: List of objects depended by this object. If ALL + objects in the list have been deleted, this object will + be garbage collected. If this object is managed by a controller, + then an entry in this list will point to this controller, + with the controller field set to true. There cannot be more + than one managing controller. + items: + description: OwnerReference contains enough information + to let you identify an owning object. An owning object + must be in the same namespace as the dependent, or be + cluster-scoped, so there is no namespace field. + properties: + apiVersion: + description: API version of the referent. + type: string + blockOwnerDeletion: + description: If true, AND if the owner has the "foregroundDeletion" + finalizer, then the owner cannot be deleted from the + key-value store until this reference is removed. Defaults + to false. To set this field, a user needs "delete" + permission of the owner, otherwise 422 (Unprocessable + Entity) will be returned. + type: boolean + controller: + description: If true, this reference points to the managing + controller. + type: boolean + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names' + type: string + uid: + description: 'UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids' + type: string + required: + - apiVersion + - kind + - name + - uid + type: object + x-kubernetes-map-type: atomic + type: array + type: object + required: + - group + - kind + type: object + required: + - aws + - kubernetes + type: object + status: + description: AdoptedResourceStatus defines the observed status of the + AdoptedResource. + properties: + conditions: + description: A collection of `ackv1alpha1.Condition` objects that + describe the various terminal states of the adopted resource CR + and its target custom resource + items: + description: Condition is the common struct used by all CRDs managed + by ACK service controllers to indicate terminal states of the + CR and its backend AWS service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + required: + - conditions + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/common/bases/services.k8s.aws_fieldexports.yaml b/config/crd/common/bases/services.k8s.aws_fieldexports.yaml new file mode 100644 index 0000000..4a7ab61 --- /dev/null +++ b/config/crd/common/bases/services.k8s.aws_fieldexports.yaml @@ -0,0 +1,134 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: fieldexports.services.k8s.aws +spec: + group: services.k8s.aws + names: + kind: FieldExport + listKind: FieldExportList + plural: fieldexports + singular: fieldexport + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: FieldExport is the schema for the FieldExport API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: FieldExportSpec defines the desired state of the FieldExport. + properties: + from: + description: ResourceFieldSelector provides the values necessary to + identify an individual field on an individual K8s resource. + properties: + path: + type: string + resource: + description: NamespacedResource provides all the values necessary + to identify an ACK resource of a given type (within the same + namespace as the custom resource containing this type). + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - group + - kind + - name + type: object + required: + - path + - resource + type: object + to: + description: FieldExportTarget provides the values necessary to identify + the output path for a field export. + properties: + key: + description: Key overrides the default value (`.`) + for the FieldExport target + type: string + kind: + description: FieldExportOutputType represents all types that can + be produced by a field export operation + enum: + - configmap + - secret + type: string + name: + type: string + namespace: + description: Namespace is marked as optional, so we cannot compose + `NamespacedName` + type: string + required: + - kind + - name + type: object + required: + - from + - to + type: object + status: + description: FieldExportStatus defines the observed status of the FieldExport. + properties: + conditions: + description: A collection of `ackv1alpha1.Condition` objects that + describe the various recoverable states of the field CR + items: + description: Condition is the common struct used by all CRDs managed + by ACK service controllers to indicate terminal states of the + CR and its backend AWS service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + required: + - conditions + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/common/kustomization.yaml b/config/crd/common/kustomization.yaml new file mode 100644 index 0000000..96349f6 --- /dev/null +++ b/config/crd/common/kustomization.yaml @@ -0,0 +1,7 @@ +# Code generated in runtime. DO NOT EDIT. + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - bases/services.k8s.aws_adoptedresources.yaml + - bases/services.k8s.aws_fieldexports.yaml diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml new file mode 100644 index 0000000..7787da9 --- /dev/null +++ b/config/crd/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - common + - bases/cloudwatch.services.k8s.aws_metricalarms.yaml diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml new file mode 100644 index 0000000..c89f8ed --- /dev/null +++ b/config/default/kustomization.yaml @@ -0,0 +1,20 @@ +# Adds namespace to all resources. +# namespace: + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +# namePrefix: + +# Labels to add to all resources and selectors. +#commonLabels: +# someName: someValue + +resources: +- ../crd +- ../rbac +- ../controller + +patchesStrategicMerge: diff --git a/config/overlays/namespaced/kustomization.yaml b/config/overlays/namespaced/kustomization.yaml new file mode 100644 index 0000000..b1d2585 --- /dev/null +++ b/config/overlays/namespaced/kustomization.yaml @@ -0,0 +1,15 @@ +resources: +- ../../default +patches: +- path: role.json + target: + group: rbac.authorization.k8s.io + version: v1 + kind: ClusterRole + name: ack-cloudwatch-controller +- path: role-binding.json + target: + group: rbac.authorization.k8s.io + version: v1 + kind: ClusterRoleBinding + name: ack-cloudwatch-controller-rolebinding \ No newline at end of file diff --git a/config/overlays/namespaced/role-binding.json b/config/overlays/namespaced/role-binding.json new file mode 100644 index 0000000..83e46c5 --- /dev/null +++ b/config/overlays/namespaced/role-binding.json @@ -0,0 +1,3 @@ +[{"op": "replace", "path": "/kind", "value": "RoleBinding"}, +{"op": "add", "path": "/metadata/namespace", "value": "ack-system"}, +{"op": "replace", "path": "/roleRef/kind", "value": "Role"}] \ No newline at end of file diff --git a/config/overlays/namespaced/role.json b/config/overlays/namespaced/role.json new file mode 100644 index 0000000..deddee7 --- /dev/null +++ b/config/overlays/namespaced/role.json @@ -0,0 +1,2 @@ +[{"op": "replace", "path": "/kind", "value": "Role"}, +{"op": "add", "path": "/metadata/namespace", "value": "ack-system"}] \ No newline at end of file diff --git a/config/rbac/cluster-role-binding.yaml b/config/rbac/cluster-role-binding.yaml new file mode 100644 index 0000000..729b0b3 --- /dev/null +++ b/config/rbac/cluster-role-binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ack-cloudwatch-controller-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: ack-cloudwatch-controller +subjects: +- kind: ServiceAccount + name: ack-cloudwatch-controller + namespace: ack-system diff --git a/config/rbac/cluster-role-controller.yaml b/config/rbac/cluster-role-controller.yaml new file mode 100644 index 0000000..8fc14d6 --- /dev/null +++ b/config/rbac/cluster-role-controller.yaml @@ -0,0 +1,93 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: ack-cloudwatch-controller +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - patch + - watch +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms/status + verbs: + - get + - patch + - update +- apiGroups: + - services.k8s.aws + resources: + - adoptedresources + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - services.k8s.aws + resources: + - adoptedresources/status + verbs: + - get + - patch + - update +- apiGroups: + - services.k8s.aws + resources: + - fieldexports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - services.k8s.aws + resources: + - fieldexports/status + verbs: + - get + - patch + - update diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml new file mode 100644 index 0000000..eb7df60 --- /dev/null +++ b/config/rbac/kustomization.yaml @@ -0,0 +1,7 @@ +resources: +- cluster-role-binding.yaml +- cluster-role-controller.yaml +- role-reader.yaml +- role-writer.yaml +- service-account.yaml + diff --git a/config/rbac/role-reader.yaml b/config/rbac/role-reader.yaml new file mode 100644 index 0000000..224243a --- /dev/null +++ b/config/rbac/role-reader.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + creationTimestamp: null + name: ack-cloudwatch-reader + namespace: default +rules: +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms + verbs: + - get + - list + - watch diff --git a/config/rbac/role-writer.yaml b/config/rbac/role-writer.yaml new file mode 100644 index 0000000..639f349 --- /dev/null +++ b/config/rbac/role-writer.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + creationTimestamp: null + name: ack-cloudwatch-writer + namespace: default +rules: +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms + verbs: + - get + - patch + - update diff --git a/config/rbac/service-account.yaml b/config/rbac/service-account.yaml new file mode 100644 index 0000000..4c4e7c6 --- /dev/null +++ b/config/rbac/service-account.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ack-cloudwatch-controller + namespace: ack-system diff --git a/generator.yaml b/generator.yaml index f770e6d..796a3b9 100644 --- a/generator.yaml +++ b/generator.yaml @@ -1,3 +1,37 @@ ignore: resource_names: + - AnomalyDetector + - CompositeAlarm + - InsightRule + - ManagedInsightRule + - MetricStream model_name: monitoring +operations: + DeleteAlarms: + operation_type: + - Delete + resource_name: MetricAlarm + DescribeAlarms: + output_wrapper_field_path: MetricAlarms + operation_type: + - List + resource_name: MetricAlarm + PutMetricAlarm: + operation_type: + - Create + - Update + resource_name: MetricAlarm +resources: + MetricAlarm: + fields: + Name: + is_primary_key: true + is_required: true + renames: + operations: + PutMetricAlarm: + input_fields: + AlarmName: Name + hooks: + sdk_delete_post_build_request: + template_path: hooks/metricalarm/sdk_delete_post_build_request.go.tpl diff --git a/go.mod b/go.mod index b32d44a..87251f6 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,77 @@ module github.com/aws-controllers-k8s/cloudwatch-controller go 1.19 + +require ( + github.com/aws-controllers-k8s/runtime v0.26.0 + github.com/aws/aws-sdk-go v1.44.303 + github.com/go-logr/logr v1.2.3 + github.com/spf13/pflag v1.0.5 + k8s.io/api v0.26.1 + k8s.io/apimachinery v0.26.1 + k8s.io/client-go v0.26.1 + sigs.k8s.io/controller-runtime v0.14.5 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/zapr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/swag v0.19.14 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/itchyny/gojq v0.12.6 // indirect + github.com/itchyny/timefmt-go v0.1.3 // indirect + github.com/jaypipes/envutil v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect + github.com/samber/lo v1.37.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/term v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + golang.org/x/time v0.3.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.26.1 // indirect + k8s.io/component-base v0.26.1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) diff --git a/go.sum b/go.sum index e69de29..13a9cb7 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,651 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/aws-controllers-k8s/runtime v0.26.0 h1:XKqygFzHSBtM74Ov9IroZbyCVeYei9Eskp4aKbJ2SFw= +github.com/aws-controllers-k8s/runtime v0.26.0/go.mod h1:jizDzKikL09cueIuA9ZxoZ+4pfn5U7oKW5s/ZAqOA6E= +github.com/aws/aws-sdk-go v1.44.303 h1:GybJmj22u3KVMghsqYZoicS3NpiWiNaPE1+5bhvkxIs= +github.com/aws/aws-sdk-go v1.44.303/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +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.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/itchyny/gojq v0.12.6 h1:VjaFn59Em2wTxDNGcrRkDK9ZHMNa8IksOgL13sLL4d0= +github.com/itchyny/gojq v0.12.6/go.mod h1:ZHrkfu7A+RbZLy5J1/JKpS4poEqrzItSTGDItqsfP0A= +github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU= +github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= +github.com/jaypipes/envutil v1.0.0 h1:u6Vwy9HwruFihoZrL0bxDLCa/YNadGVwKyPElNmZWow= +github.com/jaypipes/envutil v1.0.0/go.mod h1:vgIRDly+xgBq0eeZRcflOHMMobMwgC6MkMbxo/Nw65M= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= +github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc= +github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= +github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ= +k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg= +k8s.io/apiextensions-apiserver v0.26.1 h1:cB8h1SRk6e/+i3NOrQgSFij1B2S0Y0wDoNl66bn8RMI= +k8s.io/apiextensions-apiserver v0.26.1/go.mod h1:AptjOSXDGuE0JICx/Em15PaoO7buLwTs0dGleIHixSM= +k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ= +k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= +k8s.io/client-go v0.26.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU= +k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE= +k8s.io/component-base v0.26.1 h1:4ahudpeQXHZL5kko+iDHqLj/FSGAEUnSVO0EBbgDd+4= +k8s.io/component-base v0.26.1/go.mod h1:VHrLR0b58oC035w6YQiBSbtsf0ThuSwXP+p5dD/kAWU= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y= +k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.14.5 h1:6xaWFqzT5KuAQ9ufgUaj1G/+C4Y1GRkhrxl+BJ9i+5s= +sigs.k8s.io/controller-runtime v0.14.5/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 0000000..9ec42f8 --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +name: cloudwatch-chart +description: A Helm chart for the ACK service controller for Amazon CloudWatch (CloudWatch) +version: 0.0.0-non-release-version +appVersion: 0.0.0-non-release-version +home: https://github.com/aws-controllers-k8s/cloudwatch-controller +icon: https://raw.githubusercontent.com/aws/eks-charts/master/docs/logo/aws.png +sources: + - https://github.com/aws-controllers-k8s/cloudwatch-controller +maintainers: + - name: ACK Admins + url: https://github.com/orgs/aws-controllers-k8s/teams/ack-admin + - name: CloudWatch Admins + url: https://github.com/orgs/aws-controllers-k8s/teams/cloudwatch-maintainer +keywords: + - aws + - kubernetes + - cloudwatch diff --git a/helm/crds/cloudwatch.services.k8s.aws_metricalarms.yaml b/helm/crds/cloudwatch.services.k8s.aws_metricalarms.yaml new file mode 100644 index 0000000..17c1ede --- /dev/null +++ b/helm/crds/cloudwatch.services.k8s.aws_metricalarms.yaml @@ -0,0 +1,425 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: metricalarms.cloudwatch.services.k8s.aws +spec: + group: cloudwatch.services.k8s.aws + names: + kind: MetricAlarm + listKind: MetricAlarmList + plural: metricalarms + singular: metricalarm + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: MetricAlarm is the Schema for the MetricAlarms API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: "MetricAlarmSpec defines the desired state of MetricAlarm. + \n The details about a metric alarm." + properties: + actionsEnabled: + description: Indicates whether actions should be executed during any + changes to the alarm state. The default is TRUE. + type: boolean + alarmActions: + description: "The actions to execute when this alarm transitions to + the ALARM state from any other state. Each action is specified as + an Amazon Resource Name (ARN). Valid values: \n EC2 actions: \n + - arn:aws:automate:region:ec2:stop \n - arn:aws:automate:region:ec2:terminate + \n - arn:aws:automate:region:ec2:reboot \n - arn:aws:automate:region:ec2:recover + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Stop/1.0 + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Recover/1.0 + \n Autoscaling action: \n - arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SNS notification action: \n - arn:aws:sns:region:account-id:sns-topic-name:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SSM integration actions: \n - arn:aws:ssm:region:account-id:opsitem:severity#CATEGORY=category-name + \n - arn:aws:ssm-incidents::account-id:responseplan/response-plan-name" + items: + type: string + type: array + alarmDescription: + description: The description for the alarm. + type: string + comparisonOperator: + description: "The arithmetic operation to use when comparing the specified + statistic and threshold. The specified statistic value is used as + the first operand. \n The values LessThanLowerOrGreaterThanUpperThreshold, + LessThanLowerThreshold, and GreaterThanUpperThreshold are used only + for alarms based on anomaly detection models." + type: string + datapointsToAlarm: + description: 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) + in the Amazon CloudWatch User Guide. + format: int64 + type: integer + dimensions: + description: The dimensions for the metric specified in MetricName. + items: + description: "A dimension is a name/value pair that is part of the + identity of a metric. Because dimensions are part of the unique + identifier for a metric, whenever you add a unique name/value + pair to one of your metrics, you are creating a new variation + of that metric. For example, many Amazon EC2 metrics publish InstanceId + as a dimension name, and the actual instance ID as the value for + that dimension. \n You can assign up to 30 dimensions to a metric." + properties: + name: + type: string + value: + type: string + type: object + type: array + evaluateLowSampleCountPercentile: + description: "Used only for alarms based on percentiles. If you specify + ignore, the alarm state does not change during periods with too + few data points to be statistically significant. If you specify + evaluate or omit this parameter, the alarm is always evaluated and + possibly changes state no matter how many data points are available. + For more information, see Percentile-Based CloudWatch Alarms and + Low Data Samples (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#percentiles-with-low-samples). + \n Valid Values: evaluate | ignore" + type: string + 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. \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 + extendedStatistic: + description: The percentile statistic for the metric specified in + MetricName. Specify a value between p0.0 and p100. When you call + PutMetricAlarm and specify a MetricName, you must specify either + Statistic or ExtendedStatistic, but not both. + type: string + insufficientDataActions: + description: "The actions to execute when this alarm transitions to + the INSUFFICIENT_DATA state from any other state. Each action is + specified as an Amazon Resource Name (ARN). Valid values: \n EC2 + actions: \n - arn:aws:automate:region:ec2:stop \n - arn:aws:automate:region:ec2:terminate + \n - arn:aws:automate:region:ec2:reboot \n - arn:aws:automate:region:ec2:recover + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Stop/1.0 + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Recover/1.0 + \n Autoscaling action: \n - arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SNS notification action: \n - arn:aws:sns:region:account-id:sns-topic-name:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SSM integration actions: \n - arn:aws:ssm:region:account-id:opsitem:severity#CATEGORY=category-name + \n - arn:aws:ssm-incidents::account-id:responseplan/response-plan-name" + items: + type: string + type: array + metricName: + description: "The name for the metric associated with the alarm. For + each PutMetricAlarm operation, you must specify either MetricName + or a Metrics array. \n If you are creating an alarm based on a math + expression, you cannot specify this parameter, or any of the Dimensions, + Period, Namespace, Statistic, or ExtendedStatistic parameters. Instead, + you specify all this information in the Metrics array." + type: string + metrics: + 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. \n Each item in the Metrics array either retrieves + a metric or performs a math expression. \n One item in the Metrics + array is the expression that the alarm watches. You designate this + expression by setting ReturnData to true for this object in the + array. For more information, see MetricDataQuery (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDataQuery.html). + \n If you use the Metrics parameter, you cannot include the MetricName, + Dimensions, Period, Namespace, Statistic, or ExtendedStatistic parameters + of PutMetricAlarm in the same operation. Instead, you retrieve the + metrics you are using in your math expression as part of the Metrics + array." + items: + description: "This structure is used in both GetMetricData and PutMetricAlarm. + The supported use of this structure is different for those two + operations. \n When used in GetMetricData, it indicates the metric + data to return, and whether this call is just retrieving a batch + set of data for one metric, or is performing a Metrics Insights + query or a math expression. A single GetMetricData call can include + up to 500 MetricDataQuery structures. \n When used in PutMetricAlarm, + it enables you to create an alarm based on a metric math expression. + Each MetricDataQuery in the array specifies either a metric to + retrieve, or a math expression to be performed on retrieved metrics. + A single PutMetricAlarm call can include up to 20 MetricDataQuery + structures in the array. The 20 structures can include as many + as 10 structures that contain a MetricStat parameter to retrieve + a metric, and as many as 10 structures that contain the Expression + parameter to perform a math expression. Of those Expression structures, + one must have true as the value for ReturnData. The result of + this expression is the value the alarm watches. \n Any expression + used in a PutMetricAlarm operation must return a single time series. + For more information, see Metric Math Syntax and Functions (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/using-metric-math.html#metric-math-syntax) + in the Amazon CloudWatch User Guide. \n Some of the parameters + of this structure also have different uses whether you are using + this structure in a GetMetricData operation or a PutMetricAlarm + operation. These differences are explained in the following parameter + list." + properties: + accountID: + type: string + expression: + type: string + id: + type: string + label: + type: string + metricStat: + description: This structure defines the metric to be returned, + along with the statistics, period, and units. + properties: + metric: + description: Represents a specific metric. + properties: + dimensions: + items: + description: "A dimension is a name/value pair that + is part of the identity of a metric. Because dimensions + are part of the unique identifier for a metric, + whenever you add a unique name/value pair to one + of your metrics, you are creating a new variation + of that metric. For example, many Amazon EC2 metrics + publish InstanceId as a dimension name, and the + actual instance ID as the value for that dimension. + \n You can assign up to 30 dimensions to a metric." + properties: + name: + type: string + value: + type: string + type: object + type: array + metricName: + type: string + namespace: + type: string + type: object + period: + format: int64 + type: integer + stat: + type: string + unit: + type: string + type: object + period: + format: int64 + type: integer + returnData: + type: boolean + type: object + type: array + name: + description: "The name for the alarm. This name must be unique within + the Region. \n The name must contain only UTF-8 characters, and + can't contain ASCII control characters" + type: string + namespace: + description: The namespace for the metric associated specified in + MetricName. + type: string + oKActions: + description: "The actions to execute when this alarm transitions to + an OK state from any other state. Each action is specified as an + Amazon Resource Name (ARN). Valid values: \n EC2 actions: \n - arn:aws:automate:region:ec2:stop + \n - arn:aws:automate:region:ec2:terminate \n - arn:aws:automate:region:ec2:reboot + \n - arn:aws:automate:region:ec2:recover \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Stop/1.0 + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + \n - arn:aws:swf:region:account-id:action/actions/AWS_EC2.InstanceId.Recover/1.0 + \n Autoscaling action: \n - arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SNS notification action: \n - arn:aws:sns:region:account-id:sns-topic-name:autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name + \n SSM integration actions: \n - arn:aws:ssm:region:account-id:opsitem:severity#CATEGORY=category-name + \n - arn:aws:ssm-incidents::account-id:responseplan/response-plan-name" + items: + type: string + type: array + 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. \n 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. \n 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 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, see Amazon CloudWatch Pricing (https://aws.amazon.com/cloudwatch/pricing/). + \n 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." + format: int64 + type: integer + statistic: + description: The statistic for the metric specified in MetricName, + other than percentile. For percentile statistics, use ExtendedStatistic. + When you call PutMetricAlarm and specify a MetricName, you must + specify either Statistic or ExtendedStatistic, but not both. + type: string + tags: + description: "A list of key-value pairs to associate with the alarm. + You can associate as many as 50 tags with an alarm. \n Tags can + help you organize and categorize your resources. You can also use + them to scope user permissions by granting a user permission to + access or change only resources with certain tag values. \n If you + are using this operation to update an existing alarm, any tags you + specify in this parameter are ignored. To change the tags of an + existing alarm, use TagResource (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_TagResource.html) + or UntagResource (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_UntagResource.html)." + items: + description: A key-value pair associated with a CloudWatch resource. + properties: + key: + type: string + value: + type: string + type: object + type: array + threshold: + description: "The value against which the specified statistic is compared. + \n This parameter is required for alarms based on static thresholds, + but should not be used for alarms based on anomaly detection models." + type: number + thresholdMetricID: + description: "If this is an alarm based on an anomaly detection model, + make this value match the ID of the ANOMALY_DETECTION_BAND function. + \n For an example of how to use this parameter, see the Anomaly + Detection Model Alarm example on this page. \n If your alarm uses + this parameter, it cannot have Auto Scaling actions." + type: string + treatMissingData: + description: "Sets how this alarm is to handle missing data points. + If TreatMissingData is omitted, the default behavior of missing + is used. For more information, see Configuring How CloudWatch Alarms + Treats Missing Data (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-missing-data). + \n Valid Values: breaching | notBreaching | ignore | missing \n + Alarms that evaluate metrics in the AWS/DynamoDB namespace always + ignore 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." + type: string + unit: + description: "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 that an instance receives on + all network interfaces. You can also specify a unit when you create + a custom metric. Units help provide conceptual meaning to your data. + Metric data points that specify a unit of measure, such as Percent, + are aggregated separately. \n If you don't specify Unit, CloudWatch + retrieves all unit types that have been published for the metric + and attempts to evaluate the alarm. Usually, metrics are published + with only one unit, so the alarm works as intended. \n However, + if the metric is published with multiple types of units and you + don't specify a unit, the alarm's behavior is not defined and it + behaves unpredictably. \n We recommend omitting Unit so that you + don't inadvertently specify an incorrect unit that is not published + for this metric. Doing so causes the alarm to be stuck in the INSUFFICIENT + DATA state." + type: string + required: + - comparisonOperator + - evaluationPeriods + - name + type: object + status: + description: MetricAlarmStatus defines the observed state of MetricAlarm + properties: + ackResourceMetadata: + description: All CRs managed by ACK have a common `Status.ACKResourceMetadata` + member that is used to contain resource sync state, account ownership, + constructed ARN for the resource + properties: + arn: + description: 'ARN is the Amazon Resource Name for the resource. + This is a globally-unique identifier and is set only by the + ACK service controller once the controller has orchestrated + the creation of the resource OR when it has verified that an + "adopted" resource (a resource where the ARN annotation was + set by the Kubernetes user on the CR) exists and matches the + supplied CR''s Spec field values. TODO(vijat@): Find a better + strategy for resources that do not have ARN in CreateOutputResponse + https://github.com/aws/aws-controllers-k8s/issues/270' + type: string + ownerAccountID: + description: OwnerAccountID is the AWS Account ID of the account + that owns the backend AWS service API resource. + type: string + region: + description: Region is the AWS region in which the resource exists + or will exist. + type: string + required: + - ownerAccountID + - region + type: object + conditions: + description: All CRS managed by ACK have a common `Status.Conditions` + member that contains a collection of `ackv1alpha1.Condition` objects + that describe the various terminal states of the CR and its backend + AWS service API resource + items: + description: Condition is the common struct used by all CRDs managed + by ACK service controllers to indicate terminal states of the + CR and its backend AWS service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm/crds/services.k8s.aws_adoptedresources.yaml b/helm/crds/services.k8s.aws_adoptedresources.yaml new file mode 100644 index 0000000..d8d5126 --- /dev/null +++ b/helm/crds/services.k8s.aws_adoptedresources.yaml @@ -0,0 +1,229 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: adoptedresources.services.k8s.aws +spec: + group: services.k8s.aws + names: + kind: AdoptedResource + listKind: AdoptedResourceList + plural: adoptedresources + singular: adoptedresource + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AdoptedResource is the schema for the AdoptedResource API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AdoptedResourceSpec defines the desired state of the AdoptedResource. + properties: + aws: + description: AWSIdentifiers provide all unique ways to reference an + AWS resource. + properties: + additionalKeys: + additionalProperties: + type: string + description: AdditionalKeys represents any additional arbitrary + identifiers used when describing the target resource. + type: object + arn: + description: ARN is the AWS Resource Name for the resource. It + is a globally unique identifier. + type: string + nameOrID: + description: NameOrId is a user-supplied string identifier for + the resource. It may or may not be globally unique, depending + on the type of resource. + type: string + type: object + kubernetes: + description: ResourceWithMetadata provides the values necessary to + create a Kubernetes resource and override any of its metadata values. + properties: + group: + type: string + kind: + type: string + metadata: + description: "ObjectMeta is metadata that all persisted resources + must have, which includes all objects users must create. It + is not possible to use `metav1.ObjectMeta` inside spec, as the + controller-gen automatically converts this to an arbitrary string-string + map. https://github.com/kubernetes-sigs/controller-tools/issues/385 + \n Active discussion about inclusion of this field in the spec + is happening in this PR: https://github.com/kubernetes-sigs/controller-tools/pull/395 + \n Until this is allowed, or if it never is, we will produce + a subset of the object meta that contains only the fields which + the user is allowed to modify in the metadata." + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value map + stored with a resource that may be set by external tools + to store and retrieve arbitrary metadata. They are not queryable + and should be preserved when modifying objects. More info: + http://kubernetes.io/docs/user-guide/annotations' + type: object + generateName: + description: "GenerateName is an optional prefix, used by + the server, to generate a unique name ONLY IF the Name field + has not been provided. If this field is used, the name returned + to the client will be different than the name passed. This + value will also be combined with a unique suffix. The provided + value has the same validation rules as the Name field, and + may be truncated by the length of the suffix required to + make the value unique on the server. \n If this field is + specified and the generated name exists, the server will + NOT return a 409 - instead, it will either return 201 Created + or 500 with Reason ServerTimeout indicating a unique name + could not be found in the time allotted, and the client + should retry (optionally after the time indicated in the + Retry-After header). \n Applied only if Name is not specified. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency" + type: string + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be used + to organize and categorize (scope and select) objects. May + match selectors of replication controllers and services. + More info: http://kubernetes.io/docs/user-guide/labels' + type: object + name: + description: 'Name must be unique within a namespace. Is required + when creating resources, although some resources may allow + a client to request the generation of an appropriate name + automatically. Name is primarily intended for creation idempotence + and configuration definition. Cannot be updated. More info: + http://kubernetes.io/docs/user-guide/identifiers#names' + type: string + namespace: + description: "Namespace defines the space within each name + must be unique. An empty namespace is equivalent to the + \"default\" namespace, but \"default\" is the canonical + representation. Not all objects are required to be scoped + to a namespace - the value of this field for those objects + will be empty. \n Must be a DNS_LABEL. Cannot be updated. + More info: http://kubernetes.io/docs/user-guide/namespaces" + type: string + ownerReferences: + description: List of objects depended by this object. If ALL + objects in the list have been deleted, this object will + be garbage collected. If this object is managed by a controller, + then an entry in this list will point to this controller, + with the controller field set to true. There cannot be more + than one managing controller. + items: + description: OwnerReference contains enough information + to let you identify an owning object. An owning object + must be in the same namespace as the dependent, or be + cluster-scoped, so there is no namespace field. + properties: + apiVersion: + description: API version of the referent. + type: string + blockOwnerDeletion: + description: If true, AND if the owner has the "foregroundDeletion" + finalizer, then the owner cannot be deleted from the + key-value store until this reference is removed. See + https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion + for how the garbage collector interacts with this + field and enforces the foreground deletion. Defaults + to false. To set this field, a user needs "delete" + permission of the owner, otherwise 422 (Unprocessable + Entity) will be returned. + type: boolean + controller: + description: If true, this reference points to the managing + controller. + type: boolean + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names' + type: string + uid: + description: 'UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids' + type: string + required: + - apiVersion + - kind + - name + - uid + type: object + x-kubernetes-map-type: atomic + type: array + type: object + required: + - group + - kind + type: object + required: + - aws + - kubernetes + type: object + status: + description: AdoptedResourceStatus defines the observed status of the + AdoptedResource. + properties: + conditions: + description: A collection of `ackv1alpha1.Condition` objects that + describe the various terminal states of the adopted resource CR + and its target custom resource + items: + description: Condition is the common struct used by all CRDs managed + by ACK service controllers to indicate terminal states of the + CR and its backend AWS service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + required: + - conditions + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm/crds/services.k8s.aws_fieldexports.yaml b/helm/crds/services.k8s.aws_fieldexports.yaml new file mode 100644 index 0000000..4a7ab61 --- /dev/null +++ b/helm/crds/services.k8s.aws_fieldexports.yaml @@ -0,0 +1,134 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: fieldexports.services.k8s.aws +spec: + group: services.k8s.aws + names: + kind: FieldExport + listKind: FieldExportList + plural: fieldexports + singular: fieldexport + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: FieldExport is the schema for the FieldExport API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: FieldExportSpec defines the desired state of the FieldExport. + properties: + from: + description: ResourceFieldSelector provides the values necessary to + identify an individual field on an individual K8s resource. + properties: + path: + type: string + resource: + description: NamespacedResource provides all the values necessary + to identify an ACK resource of a given type (within the same + namespace as the custom resource containing this type). + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - group + - kind + - name + type: object + required: + - path + - resource + type: object + to: + description: FieldExportTarget provides the values necessary to identify + the output path for a field export. + properties: + key: + description: Key overrides the default value (`.`) + for the FieldExport target + type: string + kind: + description: FieldExportOutputType represents all types that can + be produced by a field export operation + enum: + - configmap + - secret + type: string + name: + type: string + namespace: + description: Namespace is marked as optional, so we cannot compose + `NamespacedName` + type: string + required: + - kind + - name + type: object + required: + - from + - to + type: object + status: + description: FieldExportStatus defines the observed status of the FieldExport. + properties: + conditions: + description: A collection of `ackv1alpha1.Condition` objects that + describe the various recoverable states of the field CR + items: + description: Condition is the common struct used by all CRDs managed + by ACK service controllers to indicate terminal states of the + CR and its backend AWS service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + required: + - conditions + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm/templates/NOTES.txt b/helm/templates/NOTES.txt new file mode 100644 index 0000000..fe92dba --- /dev/null +++ b/helm/templates/NOTES.txt @@ -0,0 +1,16 @@ +{{ .Chart.Name }} has been installed. +This chart deploys "public.ecr.aws/aws-controllers-k8s/cloudwatch-controller:0.0.0-non-release-version". + +Check its status by running: + kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/instance={{ .Release.Name }}" + +You are now able to create Amazon CloudWatch (CloudWatch) resources! + +The controller is running in "{{ .Values.installScope }}" mode. +The controller is configured to manage AWS resources in region: "{{ .Values.aws.region }}" + +Visit https://aws-controllers-k8s.github.io/community/reference/ for an API +reference of all the resources that can be created using this controller. + +For more information on the AWS Controllers for Kubernetes (ACK) project, visit: +https://aws-controllers-k8s.github.io/community/ diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl new file mode 100644 index 0000000..391d5de --- /dev/null +++ b/helm/templates/_helpers.tpl @@ -0,0 +1,48 @@ +{{/* The name of the application this chart installs */}} +{{- define "app.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "app.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* The name and version as used by the chart label */}} +{{- define "chart.name-version" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* The name of the service account to use */}} +{{- define "service-account.name" -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} + +{{- define "watch-namespace" -}} +{{- if eq .Values.installScope "namespace" -}} +{{ .Values.watchNamespace | default .Release.Namespace }} +{{- end -}} +{{- end -}} + +{{/* The mount path for the shared credentials file */}} +{{- define "aws.credentials.secret_mount_path" -}} +{{- "/var/run/secrets/aws" -}} +{{- end -}} + +{{/* The path the shared credentials file is mounted */}} +{{- define "aws.credentials.path" -}} +{{- printf "%s/%s" (include "aws.credentials.secret_mount_path" .) .Values.aws.credentials.secretKey -}} +{{- end -}} diff --git a/helm/templates/cluster-role-binding.yaml b/helm/templates/cluster-role-binding.yaml new file mode 100644 index 0000000..42bb74f --- /dev/null +++ b/helm/templates/cluster-role-binding.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +{{ if eq .Values.installScope "cluster" }} +kind: ClusterRoleBinding +metadata: + name: {{ include "app.fullname" . }} +roleRef: + kind: ClusterRole +{{ else }} +kind: RoleBinding +metadata: + name: {{ include "app.fullname" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role +{{ end }} + apiGroup: rbac.authorization.k8s.io + name: ack-cloudwatch-controller +subjects: +- kind: ServiceAccount + name: {{ include "service-account.name" . }} + namespace: {{ .Release.Namespace }} diff --git a/helm/templates/cluster-role-controller.yaml b/helm/templates/cluster-role-controller.yaml new file mode 100644 index 0000000..14a04c7 --- /dev/null +++ b/helm/templates/cluster-role-controller.yaml @@ -0,0 +1,108 @@ +apiVersion: rbac.authorization.k8s.io/v1 +{{ if eq .Values.installScope "cluster" }} +kind: ClusterRole +metadata: + creationTimestamp: null + name: ack-cloudwatch-controller + labels: + {{- range $key, $value := .Values.role.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{ else }} +kind: Role +metadata: + creationTimestamp: null + name: ack-cloudwatch-controller + labels: + {{- range $key, $value := .Values.role.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + namespace: {{ .Release.Namespace }} +{{ end }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - patch + - watch +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms/status + verbs: + - get + - patch + - update +- apiGroups: + - services.k8s.aws + resources: + - adoptedresources + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - services.k8s.aws + resources: + - adoptedresources/status + verbs: + - get + - patch + - update +- apiGroups: + - services.k8s.aws + resources: + - fieldexports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - services.k8s.aws + resources: + - fieldexports/status + verbs: + - get + - patch + - update diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml new file mode 100644 index 0000000..4d087a5 --- /dev/null +++ b/helm/templates/deployment.yaml @@ -0,0 +1,154 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "app.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} + k8s-app: {{ include "app.name" . }} + helm.sh/chart: {{ include "chart.name-version" . }} +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: {{ include "app.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: +{{- if .Values.deployment.annotations }} + annotations: + {{- range $key, $value := .Values.deployment.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{- end }} + labels: + app.kubernetes.io/name: {{ include "app.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: Helm + k8s-app: {{ include "app.name" . }} +{{- range $key, $value := .Values.deployment.labels }} + {{ $key }}: {{ $value | quote }} +{{- end }} + spec: + serviceAccountName: {{ include "service-account.name" . }} + {{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- range .Values.image.pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + containers: + - command: + - ./bin/controller + args: + - --aws-region + - "$(AWS_REGION)" + - --aws-endpoint-url + - "$(AWS_ENDPOINT_URL)" + - --enable-development-logging + - "$(ACK_ENABLE_DEVELOPMENT_LOGGING)" + - --log-level + - "$(ACK_LOG_LEVEL)" + - --resource-tags + - "$(ACK_RESOURCE_TAGS)" + - --watch-namespace + - "$(ACK_WATCH_NAMESPACE)" + - --deletion-policy + - "$(DELETION_POLICY)" +{{- if gt .Values.reconcile.defaultResyncPeriod 0.0 }} + - --reconcile-default-resync-seconds + - "$(RECONCILE_DEFAULT_RESYNC_SECONDS)" +{{- end }} +{{- range $key, $value := .Values.reconcile.resourceResyncPeriods }} + - --reconcile-resource-resync-seconds + - "$(RECONCILE_RESOURCE_RESYNC_SECONDS_{{ $key | upper }})" +{{- end }} + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: controller + ports: + - name: http + containerPort: {{ .Values.deployment.containerPort }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + env: + - name: ACK_SYSTEM_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: AWS_REGION + value: {{ .Values.aws.region }} + - name: AWS_ENDPOINT_URL + value: {{ .Values.aws.endpoint_url | quote }} + - name: ACK_WATCH_NAMESPACE + value: {{ include "watch-namespace" . }} + - name: DELETION_POLICY + value: {{ .Values.deletionPolicy }} + - name: ACK_ENABLE_DEVELOPMENT_LOGGING + value: {{ .Values.log.enable_development_logging | quote }} + - name: ACK_LOG_LEVEL + value: {{ .Values.log.level | quote }} + - name: ACK_RESOURCE_TAGS + value: {{ join "," .Values.resourceTags | quote }} +{{- if gt .Values.reconcile.defaultResyncPeriod 0.0 }} + - name: RECONCILE_DEFAULT_RESYNC_SECONDS + value: {{ .Values.reconcile.defaultResyncPeriod | quote }} +{{- end }} +{{- range $key, $value := .Values.reconcile.resourceResyncPeriods }} + - name: RECONCILE_RESOURCE_RESYNC_SECONDS_{{ $key | upper }} + value: {{ $key }}={{ $value }} +{{- end }} + {{- if .Values.aws.credentials.secretName }} + - name: AWS_SHARED_CREDENTIALS_FILE + value: {{ include "aws.credentials.path" . }} + - name: AWS_PROFILE + value: {{ .Values.aws.credentials.profile }} + {{- end }} + {{- if .Values.deployment.extraEnvVars -}} + {{ toYaml .Values.deployment.extraEnvVars | nindent 8 }} + {{- end }} + volumeMounts: + {{- if .Values.aws.credentials.secretName }} + - name: {{ .Values.aws.credentials.secretName }} + mountPath: {{ include "aws.credentials.secret_mount_path" . }} + readOnly: true + {{- end }} + {{- if .Values.deployment.extraVolumeMounts -}} + {{ toYaml .Values.deployment.extraVolumeMounts | nindent 12 }} + {{- end }} + securityContext: + allowPrivilegeEscalation: false + privileged: false + runAsNonRoot: true + capabilities: + drop: + - ALL + securityContext: + seccompProfile: + type: RuntimeDefault + terminationGracePeriodSeconds: 10 + nodeSelector: {{ toYaml .Values.deployment.nodeSelector | nindent 8 }} + {{ if .Values.deployment.tolerations -}} + tolerations: {{ toYaml .Values.deployment.tolerations | nindent 8 }} + {{ end -}} + {{ if .Values.deployment.affinity -}} + affinity: {{ toYaml .Values.deployment.affinity | nindent 8 }} + {{ end -}} + {{ if .Values.deployment.priorityClassName -}} + priorityClassName: {{ .Values.deployment.priorityClassName }} + {{ end -}} + hostIPC: false + hostNetwork: false + hostPID: false + volumes: + {{- if .Values.aws.credentials.secretName -}} + - name: {{ .Values.aws.credentials.secretName }} + secret: + secretName: {{ .Values.aws.credentials.secretName }} + {{ end -}} +{{- if .Values.deployment.extraVolumes }} +{{ toYaml .Values.deployment.extraVolumes | indent 8}} +{{- end }} diff --git a/helm/templates/metrics-service.yaml b/helm/templates/metrics-service.yaml new file mode 100644 index 0000000..638858a --- /dev/null +++ b/helm/templates/metrics-service.yaml @@ -0,0 +1,29 @@ +{{- if .Values.metrics.service.create }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Chart.Name | trimSuffix "-chart" | trunc 44 }}-controller-metrics + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "app.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} + k8s-app: {{ include "app.name" . }} + helm.sh/chart: {{ include "chart.name-version" . }} +spec: + selector: + app.kubernetes.io/name: {{ include "app.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: Helm + k8s-app: {{ include "app.name" . }} +{{- range $key, $value := .Values.deployment.labels }} + {{ $key }}: {{ $value | quote }} +{{- end }} + type: {{ .Values.metrics.service.type }} + ports: + - name: metricsport + port: 8080 + targetPort: http + protocol: TCP +{{- end }} diff --git a/helm/templates/role-reader.yaml b/helm/templates/role-reader.yaml new file mode 100644 index 0000000..c3d7266 --- /dev/null +++ b/helm/templates/role-reader.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + creationTimestamp: null + name: ack-cloudwatch-reader + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms + verbs: + - get + - list + - watch diff --git a/helm/templates/role-writer.yaml b/helm/templates/role-writer.yaml new file mode 100644 index 0000000..7637e37 --- /dev/null +++ b/helm/templates/role-writer.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + creationTimestamp: null + name: ack-cloudwatch-writer + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms + + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - cloudwatch.services.k8s.aws + resources: + - metricalarms + verbs: + - get + - patch + - update diff --git a/helm/templates/service-account.yaml b/helm/templates/service-account.yaml new file mode 100644 index 0000000..7330639 --- /dev/null +++ b/helm/templates/service-account.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: {{ include "app.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} + k8s-app: {{ include "app.name" . }} + helm.sh/chart: {{ include "chart.name-version" . }} + name: {{ include "service-account.name" . }} + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $value := .Values.serviceAccount.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{- end }} diff --git a/helm/values.schema.json b/helm/values.schema.json new file mode 100644 index 0000000..fb4437b --- /dev/null +++ b/helm/values.schema.json @@ -0,0 +1,262 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "properties": { + "image": { + "description": "Container Image", + "properties": { + "repository": { + "type": "string", + "minLength": 1 + }, + "tag": { + "type": "string", + "minLength": 1 + }, + "pullPolicy": { + "type": "string", + "enum": ["IfNotPresent", "Always", "Never"] + }, + "pullSecrets": { + "type": "array" + } + }, + "required": [ + "repository", + "tag", + "pullPolicy" + ], + "type": "object" + }, + "nameOverride": { + "type": "string" + }, + "fullNameOverride": { + "type": "string" + }, + "deployment": { + "description": "Deployment settings", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "containerPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "nodeSelector": { + "type": "object" + }, + "tolerations": { + "type": "array" + }, + "affinity": { + "type": "object" + }, + "priorityClassName": { + "type": "string" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "extraEnvVars": { + "type": "array" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "role": { + "description": "Role settings", + "properties": { + "labels": { + "type": "object" + } + } + }, + "metrics": { + "description": "Metrics settings", + "properties": { + "service": { + "description": "Kubernetes service settings", + "properties": { + "create": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] + } + }, + "required": [ + "create", + "type" + ], + "type": "object" + } + }, + "required": [ + "service" + ], + "type": "object" + }, + "resources": { + "description": "Kubernetes resources settings", + "properties": { + "requests": { + "description": "Kubernetes resource requests", + "properties": { + "memory": { + "oneOf": [ + { "type": "number" }, + { "type": "string" } + ] + }, + "cpu": { + "oneOf": [ + { "type": "number" }, + { "type": "string" } + ] + } + }, + "required": [ + "memory", + "cpu" + ], + "type": "object" + }, + "limits": { + "description": "Kubernetes resource limits", + "properties": { + "memory": { + "oneOf": [ + { "type": "number" }, + { "type": "string" } + ] + }, + "cpu": { + "oneOf": [ + { "type": "number" }, + { "type": "string" } + ] + } + }, + "required": [ + "memory", + "cpu" + ], + "type": "object" + } + }, + "required": [ + "requests", + "limits" + ], + "type": "object" + }, + "aws": { + "description": "AWS API settings", + "properties": { + "region": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "credentials": { + "description": "AWS credentials information", + "properties": { + "secretName": { + "type": "string" + }, + "secretKey": { + "type": "string" + }, + "profile": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "log": { + "description": "Logging settings", + "properties": { + "enable_development_logging": { + "type": "boolean" + }, + "level": { + "type": "string" + } + }, + "type": "object" + }, + "installScope": { + "type": "string", + "enum": ["cluster", "namespace"] + }, + "watchNamespace": { + "type": "string" + }, + "resourceTags": { + "type": "array", + "items": { + "type": "string", + "pattern": "(^$|^.*=.*$)" + } + }, + "deletionPolicy": { + "type": "string", + "enum": ["delete", "retain"] + }, + "reconcile": { + "description": "Reconcile resync settings. Parameters to tune the controller's drift remediation period.", + "properties": { + "defaultResyncPeriod": { + "type": "number" + }, + "resourceResyncPeriods": { + "type": "object" + } + }, + "type": "object" + }, + "serviceAccount": { + "description": "ServiceAccount settings", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "annotations": { + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "image", + "deployment", + "metrics", + "resources", + "log", + "installScope", + "resourceTags", + "serviceAccount" + ], + "title": "Values", + "type": "object" +} diff --git a/helm/values.yaml b/helm/values.yaml new file mode 100644 index 0000000..14091d3 --- /dev/null +++ b/helm/values.yaml @@ -0,0 +1,123 @@ +# Default values for ack-cloudwatch-controller. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: public.ecr.aws/aws-controllers-k8s/cloudwatch-controller + tag: 0.0.0-non-release-version + pullPolicy: IfNotPresent + pullSecrets: [] + +nameOverride: "" +fullnameOverride: "" + +deployment: + annotations: {} + labels: {} + containerPort: 8080 + # Which nodeSelector to set? + # See: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector + nodeSelector: + kubernetes.io/os: linux + # Which tolerations to set? + # See: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + tolerations: [] + # What affinity to set? + # See: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + affinity: {} + # Which priorityClassName to set? + # See: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#pod-priority + priorityClassName: "" + extraVolumes: [] + extraVolumeMounts: [] + + # Additional server container environment variables + # + # You specify this manually like you would a raw deployment manifest. + # This means you can bind in environment variables from secrets. + # + # e.g. static environment variable: + # - name: DEMO_GREETING + # value: "Hello from the environment" + # + # e.g. secret environment variable: + # - name: USERNAME + # valueFrom: + # secretKeyRef: + # name: mysecret + # key: username + extraEnvVars: [] + + +# If "installScope: cluster" then these labels will be applied to ClusterRole +role: + labels: {} + +metrics: + service: + # Set to true to automatically create a Kubernetes Service resource for the + # Prometheus metrics server endpoint in controller + create: false + # Which Type to use for the Kubernetes Service? + # See: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types + type: "ClusterIP" + +resources: + requests: + memory: "64Mi" + cpu: "50m" + limits: + memory: "128Mi" + cpu: "100m" + +aws: + # If specified, use the AWS region for AWS API calls + region: "" + endpoint_url: "" + credentials: + # If specified, Secret with shared credentials file to use. + secretName: "" + # Secret stringData key that contains the credentials + secretKey: "credentials" + # Profile used for AWS credentials + profile: "default" + +# log level for the controller +log: + enable_development_logging: false + level: info + +# Set to "namespace" to install the controller in a namespaced scope, will only +# watch for object creation in the namespace. By default installScope is +# cluster wide. +installScope: cluster + +# Set the value of the "namespace" to be watched by the controller +# This value is only used when the `installScope` is set to "namespace". If left empty, the default value is the release namespace for the chart. +watchNamespace: "" + +resourceTags: + # Configures the ACK service controller to always set key/value pairs tags on + # resources that it manages. + - services.k8s.aws/controller-version=%CONTROLLER_SERVICE%-%CONTROLLER_VERSION% + - services.k8s.aws/namespace=%K8S_NAMESPACE% + +# Set to "retain" to keep all AWS resources intact even after the K8s resources +# have been deleted. By default, the ACK controller will delete the AWS resource +# before the K8s resource is removed. +deletionPolicy: delete + +# controller reconciliation configurations +reconcile: + # The default duration, in seconds, to wait before resyncing desired state of custom resources. + defaultResyncPeriod: 36000 # 10 Hours + # An object representing the reconcile resync configuration for each specific resource. + resourceResyncPeriods: {} + +serviceAccount: + # Specifies whether a service account should be created + create: true + # The name of the service account to use. + name: ack-cloudwatch-controller + annotations: {} + # eks.amazonaws.com/role-arn: arn:aws:iam::AWS_ACCOUNT_ID:role/IAM_ROLE_NAME diff --git a/pkg/resource/metric_alarm/delta.go b/pkg/resource/metric_alarm/delta.go new file mode 100644 index 0000000..728f505 --- /dev/null +++ b/pkg/resource/metric_alarm/delta.go @@ -0,0 +1,178 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package metric_alarm + +import ( + "bytes" + "reflect" + + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" +) + +// Hack to avoid import errors during build... +var ( + _ = &bytes.Buffer{} + _ = &reflect.Method{} + _ = &acktags.Tags{} +) + +// newResourceDelta returns a new `ackcompare.Delta` used to compare two +// resources +func newResourceDelta( + a *resource, + b *resource, +) *ackcompare.Delta { + delta := ackcompare.NewDelta() + if (a == nil && b != nil) || + (a != nil && b == nil) { + delta.Add("", a, b) + return delta + } + + if ackcompare.HasNilDifference(a.ko.Spec.ActionsEnabled, b.ko.Spec.ActionsEnabled) { + delta.Add("Spec.ActionsEnabled", a.ko.Spec.ActionsEnabled, b.ko.Spec.ActionsEnabled) + } else if a.ko.Spec.ActionsEnabled != nil && b.ko.Spec.ActionsEnabled != nil { + if *a.ko.Spec.ActionsEnabled != *b.ko.Spec.ActionsEnabled { + delta.Add("Spec.ActionsEnabled", a.ko.Spec.ActionsEnabled, b.ko.Spec.ActionsEnabled) + } + } + if !ackcompare.SliceStringPEqual(a.ko.Spec.AlarmActions, b.ko.Spec.AlarmActions) { + delta.Add("Spec.AlarmActions", a.ko.Spec.AlarmActions, b.ko.Spec.AlarmActions) + } + if ackcompare.HasNilDifference(a.ko.Spec.AlarmDescription, b.ko.Spec.AlarmDescription) { + delta.Add("Spec.AlarmDescription", a.ko.Spec.AlarmDescription, b.ko.Spec.AlarmDescription) + } else if a.ko.Spec.AlarmDescription != nil && b.ko.Spec.AlarmDescription != nil { + if *a.ko.Spec.AlarmDescription != *b.ko.Spec.AlarmDescription { + delta.Add("Spec.AlarmDescription", a.ko.Spec.AlarmDescription, b.ko.Spec.AlarmDescription) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.ComparisonOperator, b.ko.Spec.ComparisonOperator) { + delta.Add("Spec.ComparisonOperator", a.ko.Spec.ComparisonOperator, b.ko.Spec.ComparisonOperator) + } else if a.ko.Spec.ComparisonOperator != nil && b.ko.Spec.ComparisonOperator != nil { + if *a.ko.Spec.ComparisonOperator != *b.ko.Spec.ComparisonOperator { + delta.Add("Spec.ComparisonOperator", a.ko.Spec.ComparisonOperator, b.ko.Spec.ComparisonOperator) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.DatapointsToAlarm, b.ko.Spec.DatapointsToAlarm) { + delta.Add("Spec.DatapointsToAlarm", a.ko.Spec.DatapointsToAlarm, b.ko.Spec.DatapointsToAlarm) + } else if a.ko.Spec.DatapointsToAlarm != nil && b.ko.Spec.DatapointsToAlarm != nil { + if *a.ko.Spec.DatapointsToAlarm != *b.ko.Spec.DatapointsToAlarm { + delta.Add("Spec.DatapointsToAlarm", a.ko.Spec.DatapointsToAlarm, b.ko.Spec.DatapointsToAlarm) + } + } + if !reflect.DeepEqual(a.ko.Spec.Dimensions, b.ko.Spec.Dimensions) { + delta.Add("Spec.Dimensions", a.ko.Spec.Dimensions, b.ko.Spec.Dimensions) + } + if ackcompare.HasNilDifference(a.ko.Spec.EvaluateLowSampleCountPercentile, b.ko.Spec.EvaluateLowSampleCountPercentile) { + delta.Add("Spec.EvaluateLowSampleCountPercentile", a.ko.Spec.EvaluateLowSampleCountPercentile, b.ko.Spec.EvaluateLowSampleCountPercentile) + } else if a.ko.Spec.EvaluateLowSampleCountPercentile != nil && b.ko.Spec.EvaluateLowSampleCountPercentile != nil { + if *a.ko.Spec.EvaluateLowSampleCountPercentile != *b.ko.Spec.EvaluateLowSampleCountPercentile { + delta.Add("Spec.EvaluateLowSampleCountPercentile", a.ko.Spec.EvaluateLowSampleCountPercentile, b.ko.Spec.EvaluateLowSampleCountPercentile) + } + } + 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 { + if *a.ko.Spec.EvaluationPeriods != *b.ko.Spec.EvaluationPeriods { + delta.Add("Spec.EvaluationPeriods", a.ko.Spec.EvaluationPeriods, b.ko.Spec.EvaluationPeriods) + } + } + 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 { + if *a.ko.Spec.ExtendedStatistic != *b.ko.Spec.ExtendedStatistic { + delta.Add("Spec.ExtendedStatistic", a.ko.Spec.ExtendedStatistic, b.ko.Spec.ExtendedStatistic) + } + } + if !ackcompare.SliceStringPEqual(a.ko.Spec.InsufficientDataActions, b.ko.Spec.InsufficientDataActions) { + delta.Add("Spec.InsufficientDataActions", a.ko.Spec.InsufficientDataActions, b.ko.Spec.InsufficientDataActions) + } + if ackcompare.HasNilDifference(a.ko.Spec.MetricName, b.ko.Spec.MetricName) { + delta.Add("Spec.MetricName", a.ko.Spec.MetricName, b.ko.Spec.MetricName) + } else if a.ko.Spec.MetricName != nil && b.ko.Spec.MetricName != nil { + if *a.ko.Spec.MetricName != *b.ko.Spec.MetricName { + delta.Add("Spec.MetricName", a.ko.Spec.MetricName, b.ko.Spec.MetricName) + } + } + if !reflect.DeepEqual(a.ko.Spec.Metrics, b.ko.Spec.Metrics) { + delta.Add("Spec.Metrics", a.ko.Spec.Metrics, b.ko.Spec.Metrics) + } + if ackcompare.HasNilDifference(a.ko.Spec.Name, b.ko.Spec.Name) { + delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) + } else if a.ko.Spec.Name != nil && b.ko.Spec.Name != nil { + if *a.ko.Spec.Name != *b.ko.Spec.Name { + delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.Namespace, b.ko.Spec.Namespace) { + delta.Add("Spec.Namespace", a.ko.Spec.Namespace, b.ko.Spec.Namespace) + } else if a.ko.Spec.Namespace != nil && b.ko.Spec.Namespace != nil { + if *a.ko.Spec.Namespace != *b.ko.Spec.Namespace { + delta.Add("Spec.Namespace", a.ko.Spec.Namespace, b.ko.Spec.Namespace) + } + } + if !ackcompare.SliceStringPEqual(a.ko.Spec.OKActions, b.ko.Spec.OKActions) { + delta.Add("Spec.OKActions", a.ko.Spec.OKActions, b.ko.Spec.OKActions) + } + if ackcompare.HasNilDifference(a.ko.Spec.Period, b.ko.Spec.Period) { + delta.Add("Spec.Period", a.ko.Spec.Period, b.ko.Spec.Period) + } else if a.ko.Spec.Period != nil && b.ko.Spec.Period != nil { + if *a.ko.Spec.Period != *b.ko.Spec.Period { + delta.Add("Spec.Period", a.ko.Spec.Period, b.ko.Spec.Period) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.Statistic, b.ko.Spec.Statistic) { + delta.Add("Spec.Statistic", a.ko.Spec.Statistic, b.ko.Spec.Statistic) + } else if a.ko.Spec.Statistic != nil && b.ko.Spec.Statistic != nil { + if *a.ko.Spec.Statistic != *b.ko.Spec.Statistic { + delta.Add("Spec.Statistic", a.ko.Spec.Statistic, b.ko.Spec.Statistic) + } + } + if !ackcompare.MapStringStringEqual(ToACKTags(a.ko.Spec.Tags), ToACKTags(b.ko.Spec.Tags)) { + delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags) + } + if ackcompare.HasNilDifference(a.ko.Spec.Threshold, b.ko.Spec.Threshold) { + delta.Add("Spec.Threshold", a.ko.Spec.Threshold, b.ko.Spec.Threshold) + } else if a.ko.Spec.Threshold != nil && b.ko.Spec.Threshold != nil { + if *a.ko.Spec.Threshold != *b.ko.Spec.Threshold { + delta.Add("Spec.Threshold", a.ko.Spec.Threshold, b.ko.Spec.Threshold) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.ThresholdMetricID, b.ko.Spec.ThresholdMetricID) { + delta.Add("Spec.ThresholdMetricID", a.ko.Spec.ThresholdMetricID, b.ko.Spec.ThresholdMetricID) + } else if a.ko.Spec.ThresholdMetricID != nil && b.ko.Spec.ThresholdMetricID != nil { + if *a.ko.Spec.ThresholdMetricID != *b.ko.Spec.ThresholdMetricID { + delta.Add("Spec.ThresholdMetricID", a.ko.Spec.ThresholdMetricID, b.ko.Spec.ThresholdMetricID) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.TreatMissingData, b.ko.Spec.TreatMissingData) { + delta.Add("Spec.TreatMissingData", a.ko.Spec.TreatMissingData, b.ko.Spec.TreatMissingData) + } else if a.ko.Spec.TreatMissingData != nil && b.ko.Spec.TreatMissingData != nil { + if *a.ko.Spec.TreatMissingData != *b.ko.Spec.TreatMissingData { + delta.Add("Spec.TreatMissingData", a.ko.Spec.TreatMissingData, b.ko.Spec.TreatMissingData) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.Unit, b.ko.Spec.Unit) { + delta.Add("Spec.Unit", a.ko.Spec.Unit, b.ko.Spec.Unit) + } else if a.ko.Spec.Unit != nil && b.ko.Spec.Unit != nil { + if *a.ko.Spec.Unit != *b.ko.Spec.Unit { + delta.Add("Spec.Unit", a.ko.Spec.Unit, b.ko.Spec.Unit) + } + } + + return delta +} diff --git a/pkg/resource/metric_alarm/descriptor.go b/pkg/resource/metric_alarm/descriptor.go new file mode 100644 index 0000000..46afcce --- /dev/null +++ b/pkg/resource/metric_alarm/descriptor.go @@ -0,0 +1,155 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package metric_alarm + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + rtclient "sigs.k8s.io/controller-runtime/pkg/client" + k8sctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + svcapitypes "github.com/aws-controllers-k8s/cloudwatch-controller/apis/v1alpha1" +) + +const ( + finalizerString = "finalizers.cloudwatch.services.k8s.aws/MetricAlarm" +) + +var ( + GroupVersionResource = svcapitypes.GroupVersion.WithResource("metricalarms") + GroupKind = metav1.GroupKind{ + Group: "cloudwatch.services.k8s.aws", + Kind: "MetricAlarm", + } +) + +// resourceDescriptor implements the +// `aws-service-operator-k8s/pkg/types.AWSResourceDescriptor` interface +type resourceDescriptor struct { +} + +// GroupVersionKind returns a Kubernetes schema.GroupVersionKind struct that +// describes the API Group, Version and Kind of CRs described by the descriptor +func (d *resourceDescriptor) GroupVersionKind() schema.GroupVersionKind { + return svcapitypes.GroupVersion.WithKind(GroupKind.Kind) +} + +// EmptyRuntimeObject returns an empty object prototype that may be used in +// apimachinery and k8s client operations +func (d *resourceDescriptor) EmptyRuntimeObject() rtclient.Object { + return &svcapitypes.MetricAlarm{} +} + +// ResourceFromRuntimeObject returns an AWSResource that has been initialized +// with the supplied runtime.Object +func (d *resourceDescriptor) ResourceFromRuntimeObject( + obj rtclient.Object, +) acktypes.AWSResource { + return &resource{ + ko: obj.(*svcapitypes.MetricAlarm), + } +} + +// Delta returns an `ackcompare.Delta` object containing the difference between +// one `AWSResource` and another. +func (d *resourceDescriptor) Delta(a, b acktypes.AWSResource) *ackcompare.Delta { + return newResourceDelta(a.(*resource), b.(*resource)) +} + +// IsManaged returns true if the supplied AWSResource is under the management +// of an ACK service controller. What this means in practice is that the +// underlying custom resource (CR) in the AWSResource has had a +// resource-specific finalizer associated with it. +func (d *resourceDescriptor) IsManaged( + res acktypes.AWSResource, +) bool { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + // Remove use of custom code once + // https://github.com/kubernetes-sigs/controller-runtime/issues/994 is + // fixed. This should be able to be: + // + // return k8sctrlutil.ContainsFinalizer(obj, finalizerString) + return containsFinalizer(obj, finalizerString) +} + +// Remove once https://github.com/kubernetes-sigs/controller-runtime/issues/994 +// is fixed. +func containsFinalizer(obj rtclient.Object, finalizer string) bool { + f := obj.GetFinalizers() + for _, e := range f { + if e == finalizer { + return true + } + } + return false +} + +// MarkManaged places the supplied resource under the management of ACK. What +// this typically means is that the resource manager will decorate the +// underlying custom resource (CR) with a finalizer that indicates ACK is +// managing the resource and the underlying CR may not be deleted until ACK is +// finished cleaning up any backend AWS service resources associated with the +// CR. +func (d *resourceDescriptor) MarkManaged( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + k8sctrlutil.AddFinalizer(obj, finalizerString) +} + +// MarkUnmanaged removes the supplied resource from management by ACK. What +// this typically means is that the resource manager will remove a finalizer +// underlying custom resource (CR) that indicates ACK is managing the resource. +// This will allow the Kubernetes API server to delete the underlying CR. +func (d *resourceDescriptor) MarkUnmanaged( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + k8sctrlutil.RemoveFinalizer(obj, finalizerString) +} + +// MarkAdopted places descriptors on the custom resource that indicate the +// resource was not created from within ACK. +func (d *resourceDescriptor) MarkAdopted( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeObject in AWSResource") + } + curr := obj.GetAnnotations() + if curr == nil { + curr = make(map[string]string) + } + curr[ackv1alpha1.AnnotationAdopted] = "true" + obj.SetAnnotations(curr) +} diff --git a/pkg/resource/metric_alarm/identifiers.go b/pkg/resource/metric_alarm/identifiers.go new file mode 100644 index 0000000..4e9d81d --- /dev/null +++ b/pkg/resource/metric_alarm/identifiers.go @@ -0,0 +1,55 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package metric_alarm + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" +) + +// resourceIdentifiers implements the +// `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface +type resourceIdentifiers struct { + meta *ackv1alpha1.ResourceMetadata +} + +// ARN returns the AWS Resource Name for the backend AWS resource. If nil, +// this means the resource has not yet been created in the backend AWS +// service. +func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { + if ri.meta != nil { + return ri.meta.ARN + } + return nil +} + +// OwnerAccountID returns the AWS account identifier in which the +// backend AWS resource resides, or nil if this information is not known +// for the resource +func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { + if ri.meta != nil { + return ri.meta.OwnerAccountID + } + return nil +} + +// Region returns the AWS region in which the resource exists, or +// nil if this information is not known. +func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { + if ri.meta != nil { + return ri.meta.Region + } + return nil +} diff --git a/pkg/resource/metric_alarm/manager.go b/pkg/resource/metric_alarm/manager.go new file mode 100644 index 0000000..19e66d0 --- /dev/null +++ b/pkg/resource/metric_alarm/manager.go @@ -0,0 +1,360 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package metric_alarm + +import ( + "context" + "fmt" + "time" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" + ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + ackrt "github.com/aws-controllers-k8s/runtime/pkg/runtime" + ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log" + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + ackutil "github.com/aws-controllers-k8s/runtime/pkg/util" + "github.com/aws/aws-sdk-go/aws/session" + svcsdk "github.com/aws/aws-sdk-go/service/cloudwatch" + svcsdkapi "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + + svcapitypes "github.com/aws-controllers-k8s/cloudwatch-controller/apis/v1alpha1" +) + +var ( + _ = ackutil.InStrings + _ = acktags.NewTags() + _ = ackrt.MissingImageTagValue + _ = svcapitypes.MetricAlarm{} +) + +// +kubebuilder:rbac:groups=cloudwatch.services.k8s.aws,resources=metricalarms,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cloudwatch.services.k8s.aws,resources=metricalarms/status,verbs=get;update;patch + +var lateInitializeFieldNames = []string{} + +// resourceManager is responsible for providing a consistent way to perform +// CRUD operations in a backend AWS service API for Book custom resources. +type resourceManager struct { + // cfg is a copy of the ackcfg.Config object passed on start of the service + // controller + cfg ackcfg.Config + // log refers to the logr.Logger object handling logging for the service + // controller + log logr.Logger + // metrics contains a collection of Prometheus metric objects that the + // service controller and its reconcilers track + metrics *ackmetrics.Metrics + // rr is the Reconciler which can be used for various utility + // functions such as querying for Secret values given a SecretReference + rr acktypes.Reconciler + // awsAccountID is the AWS account identifier that contains the resources + // managed by this resource manager + awsAccountID ackv1alpha1.AWSAccountID + // The AWS Region that this resource manager targets + awsRegion ackv1alpha1.AWSRegion + // sess is the AWS SDK Session object used to communicate with the backend + // AWS service API + sess *session.Session + // sdk is a pointer to the AWS service API interface exposed by the + // aws-sdk-go/services/{alias}/{alias}iface package. + sdkapi svcsdkapi.CloudWatchAPI +} + +// concreteResource returns a pointer to a resource from the supplied +// generic AWSResource interface +func (rm *resourceManager) concreteResource( + res acktypes.AWSResource, +) *resource { + // cast the generic interface into a pointer type specific to the concrete + // implementing resource type managed by this resource manager + return res.(*resource) +} + +// ReadOne returns the currently-observed state of the supplied AWSResource in +// the backend AWS service API. +func (rm *resourceManager) ReadOne( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's ReadOne() method received resource with nil CR object") + } + observed, err := rm.sdkFind(ctx, r) + if err != nil { + if observed != nil { + return rm.onError(observed, err) + } + return rm.onError(r, err) + } + return rm.onSuccess(observed) +} + +// Create attempts to create the supplied AWSResource in the backend AWS +// service API, returning an AWSResource representing the newly-created +// resource +func (rm *resourceManager) Create( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Create() method received resource with nil CR object") + } + created, err := rm.sdkCreate(ctx, r) + if err != nil { + if created != nil { + return rm.onError(created, err) + } + return rm.onError(r, err) + } + return rm.onSuccess(created) +} + +// Update attempts to mutate the supplied desired AWSResource in the backend AWS +// service API, returning an AWSResource representing the newly-mutated +// resource. +// Note for specialized logic implementers can check to see how the latest +// observed resource differs from the supplied desired state. The +// higher-level reonciler determines whether or not the desired differs +// from the latest observed and decides whether to call the resource +// manager's Update method +func (rm *resourceManager) Update( + ctx context.Context, + resDesired acktypes.AWSResource, + resLatest acktypes.AWSResource, + delta *ackcompare.Delta, +) (acktypes.AWSResource, error) { + desired := rm.concreteResource(resDesired) + latest := rm.concreteResource(resLatest) + if desired.ko == nil || latest.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Update() method received resource with nil CR object") + } + updated, err := rm.sdkUpdate(ctx, desired, latest, delta) + if err != nil { + if updated != nil { + return rm.onError(updated, err) + } + return rm.onError(latest, err) + } + return rm.onSuccess(updated) +} + +// Delete attempts to destroy the supplied AWSResource in the backend AWS +// service API, returning an AWSResource representing the +// resource being deleted (if delete is asynchronous and takes time) +func (rm *resourceManager) Delete( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Update() method received resource with nil CR object") + } + observed, err := rm.sdkDelete(ctx, r) + if err != nil { + if observed != nil { + return rm.onError(observed, err) + } + return rm.onError(r, err) + } + + return rm.onSuccess(observed) +} + +// ARNFromName returns an AWS Resource Name from a given string name. This +// is useful for constructing ARNs for APIs that require ARNs in their +// GetAttributes operations but all we have (for new CRs at least) is a +// name for the resource +func (rm *resourceManager) ARNFromName(name string) string { + return fmt.Sprintf( + "arn:aws:cloudwatch:%s:%s:%s", + rm.awsRegion, + rm.awsAccountID, + name, + ) +} + +// LateInitialize returns an acktypes.AWSResource after setting the late initialized +// fields from the readOne call. This method will initialize the optional fields +// which were not provided by the k8s user but were defaulted by the AWS service. +// If there are no such fields to be initialized, the returned object is similar to +// object passed in the parameter. +func (rm *resourceManager) LateInitialize( + ctx context.Context, + latest acktypes.AWSResource, +) (acktypes.AWSResource, error) { + rlog := ackrtlog.FromContext(ctx) + // If there are no fields to late initialize, do nothing + if len(lateInitializeFieldNames) == 0 { + rlog.Debug("no late initialization required.") + return latest, nil + } + latestCopy := latest.DeepCopy() + lateInitConditionReason := "" + lateInitConditionMessage := "" + observed, err := rm.ReadOne(ctx, latestCopy) + if err != nil { + lateInitConditionMessage = "Unable to complete Read operation required for late initialization" + lateInitConditionReason = "Late Initialization Failure" + ackcondition.SetLateInitialized(latestCopy, corev1.ConditionFalse, &lateInitConditionMessage, &lateInitConditionReason) + ackcondition.SetSynced(latestCopy, corev1.ConditionFalse, nil, nil) + return latestCopy, err + } + lateInitializedRes := rm.lateInitializeFromReadOneOutput(observed, latestCopy) + incompleteInitialization := rm.incompleteLateInitialization(lateInitializedRes) + if incompleteInitialization { + // Add the condition with LateInitialized=False + lateInitConditionMessage = "Late initialization did not complete, requeuing with delay of 5 seconds" + lateInitConditionReason = "Delayed Late Initialization" + ackcondition.SetLateInitialized(lateInitializedRes, corev1.ConditionFalse, &lateInitConditionMessage, &lateInitConditionReason) + ackcondition.SetSynced(lateInitializedRes, corev1.ConditionFalse, nil, nil) + return lateInitializedRes, ackrequeue.NeededAfter(nil, time.Duration(5)*time.Second) + } + // Set LateInitialized condition to True + lateInitConditionMessage = "Late initialization successful" + lateInitConditionReason = "Late initialization successful" + ackcondition.SetLateInitialized(lateInitializedRes, corev1.ConditionTrue, &lateInitConditionMessage, &lateInitConditionReason) + return lateInitializedRes, nil +} + +// incompleteLateInitialization return true if there are fields which were supposed to be +// late initialized but are not. If all the fields are late initialized, false is returned +func (rm *resourceManager) incompleteLateInitialization( + res acktypes.AWSResource, +) bool { + return false +} + +// lateInitializeFromReadOneOutput late initializes the 'latest' resource from the 'observed' +// resource and returns 'latest' resource +func (rm *resourceManager) lateInitializeFromReadOneOutput( + observed acktypes.AWSResource, + latest acktypes.AWSResource, +) acktypes.AWSResource { + return latest +} + +// IsSynced returns true if the resource is synced. +func (rm *resourceManager) IsSynced(ctx context.Context, res acktypes.AWSResource) (bool, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's IsSynced() method received resource with nil CR object") + } + + return true, nil +} + +// EnsureTags ensures that tags are present inside the AWSResource. +// If the AWSResource does not have any existing resource tags, the 'tags' +// field is initialized and the controller tags are added. +// If the AWSResource has existing resource tags, then controller tags are +// added to the existing resource tags without overriding them. +// If the AWSResource does not support tags, only then the controller tags +// will not be added to the AWSResource. +func (rm *resourceManager) EnsureTags( + ctx context.Context, + res acktypes.AWSResource, + md acktypes.ServiceControllerMetadata, +) error { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's EnsureTags method received resource with nil CR object") + } + defaultTags := ackrt.GetDefaultTags(&rm.cfg, r.ko, md) + var existingTags []*svcapitypes.Tag + existingTags = r.ko.Spec.Tags + resourceTags := ToACKTags(existingTags) + tags := acktags.Merge(resourceTags, defaultTags) + r.ko.Spec.Tags = FromACKTags(tags) + return nil +} + +// newResourceManager returns a new struct implementing +// acktypes.AWSResourceManager +func newResourceManager( + cfg ackcfg.Config, + log logr.Logger, + metrics *ackmetrics.Metrics, + rr acktypes.Reconciler, + sess *session.Session, + id ackv1alpha1.AWSAccountID, + region ackv1alpha1.AWSRegion, +) (*resourceManager, error) { + return &resourceManager{ + cfg: cfg, + log: log, + metrics: metrics, + rr: rr, + awsAccountID: id, + awsRegion: region, + sess: sess, + sdkapi: svcsdk.New(sess), + }, nil +} + +// onError updates resource conditions and returns updated resource +// it returns nil if no condition is updated. +func (rm *resourceManager) onError( + r *resource, + err error, +) (acktypes.AWSResource, error) { + if r == nil { + return nil, err + } + r1, updated := rm.updateConditions(r, false, err) + if !updated { + return r, err + } + for _, condition := range r1.Conditions() { + if condition.Type == ackv1alpha1.ConditionTypeTerminal && + condition.Status == corev1.ConditionTrue { + // resource is in Terminal condition + // return Terminal error + return r1, ackerr.Terminal + } + } + return r1, err +} + +// onSuccess updates resource conditions and returns updated resource +// it returns the supplied resource if no condition is updated. +func (rm *resourceManager) onSuccess( + r *resource, +) (acktypes.AWSResource, error) { + if r == nil { + return nil, nil + } + r1, updated := rm.updateConditions(r, true, nil) + if !updated { + return r, nil + } + return r1, nil +} diff --git a/pkg/resource/metric_alarm/manager_factory.go b/pkg/resource/metric_alarm/manager_factory.go new file mode 100644 index 0000000..3071032 --- /dev/null +++ b/pkg/resource/metric_alarm/manager_factory.go @@ -0,0 +1,96 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package metric_alarm + +import ( + "fmt" + "sync" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" + ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/go-logr/logr" + + svcresource "github.com/aws-controllers-k8s/cloudwatch-controller/pkg/resource" +) + +// resourceManagerFactory produces resourceManager objects. It implements the +// `types.AWSResourceManagerFactory` interface. +type resourceManagerFactory struct { + sync.RWMutex + // rmCache contains resource managers for a particular AWS account ID + rmCache map[string]*resourceManager +} + +// ResourcePrototype returns an AWSResource that resource managers produced by +// this factory will handle +func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { + return &resourceDescriptor{} +} + +// ManagerFor returns a resource manager object that can manage resources for a +// supplied AWS account +func (f *resourceManagerFactory) ManagerFor( + cfg ackcfg.Config, + log logr.Logger, + metrics *ackmetrics.Metrics, + rr acktypes.Reconciler, + sess *session.Session, + id ackv1alpha1.AWSAccountID, + region ackv1alpha1.AWSRegion, +) (acktypes.AWSResourceManager, error) { + rmId := fmt.Sprintf("%s/%s", id, region) + f.RLock() + rm, found := f.rmCache[rmId] + f.RUnlock() + + if found { + return rm, nil + } + + f.Lock() + defer f.Unlock() + + rm, err := newResourceManager(cfg, log, metrics, rr, sess, id, region) + if err != nil { + return nil, err + } + f.rmCache[rmId] = rm + return rm, nil +} + +// IsAdoptable returns true if the resource is able to be adopted +func (f *resourceManagerFactory) IsAdoptable() bool { + return true +} + +// RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds +// Default is false which means resource will not be requeued after success. +func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { + return 0 +} + +func newResourceManagerFactory() *resourceManagerFactory { + return &resourceManagerFactory{ + rmCache: map[string]*resourceManager{}, + } +} + +func init() { + svcresource.RegisterManagerFactory(newResourceManagerFactory()) +} diff --git a/pkg/resource/metric_alarm/references.go b/pkg/resource/metric_alarm/references.go new file mode 100644 index 0000000..97755a7 --- /dev/null +++ b/pkg/resource/metric_alarm/references.go @@ -0,0 +1,56 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package metric_alarm + +import ( + "context" + "sigs.k8s.io/controller-runtime/pkg/client" + + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + + svcapitypes "github.com/aws-controllers-k8s/cloudwatch-controller/apis/v1alpha1" +) + +// ClearResolvedReferences removes any reference values that were made +// concrete in the spec. It returns a copy of the input AWSResource which +// contains the original *Ref values, but none of their respective concrete +// values. +func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) acktypes.AWSResource { + ko := rm.concreteResource(res).ko.DeepCopy() + + return &resource{ko} +} + +// ResolveReferences finds if there are any Reference field(s) present +// inside AWSResource passed in the parameter and attempts to resolve those +// reference field(s) into their respective target field(s). It returns a +// copy of the input AWSResource with resolved reference(s), a boolean which +// is set to true if the resource contains any references (regardless of if +// they are resolved successfully) and an error if the passed AWSResource's +// reference field(s) could not be resolved. +func (rm *resourceManager) ResolveReferences( + ctx context.Context, + apiReader client.Reader, + res acktypes.AWSResource, +) (acktypes.AWSResource, bool, error) { + return res, false, nil +} + +// validateReferenceFields validates the reference field and corresponding +// identifier field. +func validateReferenceFields(ko *svcapitypes.MetricAlarm) error { + return nil +} diff --git a/pkg/resource/metric_alarm/resource.go b/pkg/resource/metric_alarm/resource.go new file mode 100644 index 0000000..8a3edcf --- /dev/null +++ b/pkg/resource/metric_alarm/resource.go @@ -0,0 +1,100 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package metric_alarm + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackerrors "github.com/aws-controllers-k8s/runtime/pkg/errors" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + rtclient "sigs.k8s.io/controller-runtime/pkg/client" + + svcapitypes "github.com/aws-controllers-k8s/cloudwatch-controller/apis/v1alpha1" +) + +// Hack to avoid import errors during build... +var ( + _ = &ackerrors.MissingNameIdentifier +) + +// resource implements the `aws-controller-k8s/runtime/pkg/types.AWSResource` +// interface +type resource struct { + // The Kubernetes-native CR representing the resource + ko *svcapitypes.MetricAlarm +} + +// Identifiers returns an AWSResourceIdentifiers object containing various +// identifying information, including the AWS account ID that owns the +// resource, the resource's AWS Resource Name (ARN) +func (r *resource) Identifiers() acktypes.AWSResourceIdentifiers { + return &resourceIdentifiers{r.ko.Status.ACKResourceMetadata} +} + +// IsBeingDeleted returns true if the Kubernetes resource has a non-zero +// deletion timestamp +func (r *resource) IsBeingDeleted() bool { + return !r.ko.DeletionTimestamp.IsZero() +} + +// RuntimeObject returns the Kubernetes apimachinery/runtime representation of +// the AWSResource +func (r *resource) RuntimeObject() rtclient.Object { + return r.ko +} + +// MetaObject returns the Kubernetes apimachinery/apis/meta/v1.Object +// representation of the AWSResource +func (r *resource) MetaObject() metav1.Object { + return r.ko.GetObjectMeta() +} + +// Conditions returns the ACK Conditions collection for the AWSResource +func (r *resource) Conditions() []*ackv1alpha1.Condition { + return r.ko.Status.Conditions +} + +// ReplaceConditions sets the Conditions status field for the resource +func (r *resource) ReplaceConditions(conditions []*ackv1alpha1.Condition) { + r.ko.Status.Conditions = conditions +} + +// SetObjectMeta sets the ObjectMeta field for the resource +func (r *resource) SetObjectMeta(meta metav1.ObjectMeta) { + r.ko.ObjectMeta = meta +} + +// SetStatus will set the Status field for the resource +func (r *resource) SetStatus(desired acktypes.AWSResource) { + r.ko.Status = desired.(*resource).ko.Status +} + +// SetIdentifiers sets the Spec or Status field that is referenced as the unique +// resource identifier +func (r *resource) SetIdentifiers(identifier *ackv1alpha1.AWSIdentifiers) error { + if identifier.NameOrID == "" { + return ackerrors.MissingNameIdentifier + } + r.ko.Spec.Name = &identifier.NameOrID + + return nil +} + +// DeepCopy will return a copy of the resource +func (r *resource) DeepCopy() acktypes.AWSResource { + koCopy := r.ko.DeepCopy() + return &resource{koCopy} +} diff --git a/pkg/resource/metric_alarm/sdk.go b/pkg/resource/metric_alarm/sdk.go new file mode 100644 index 0000000..9a1715e --- /dev/null +++ b/pkg/resource/metric_alarm/sdk.go @@ -0,0 +1,866 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package metric_alarm + +import ( + "context" + "errors" + "fmt" + "reflect" + "strings" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log" + "github.com/aws/aws-sdk-go/aws" + svcsdk "github.com/aws/aws-sdk-go/service/cloudwatch" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + svcapitypes "github.com/aws-controllers-k8s/cloudwatch-controller/apis/v1alpha1" +) + +// Hack to avoid import errors during build... +var ( + _ = &metav1.Time{} + _ = strings.ToLower("") + _ = &aws.JSONValue{} + _ = &svcsdk.CloudWatch{} + _ = &svcapitypes.MetricAlarm{} + _ = ackv1alpha1.AWSAccountID("") + _ = &ackerr.NotFound + _ = &ackcondition.NotManagedMessage + _ = &reflect.Value{} + _ = fmt.Sprintf("") + _ = &ackrequeue.NoRequeue{} +) + +// sdkFind returns SDK-specific information about a supplied resource +func (rm *resourceManager) sdkFind( + ctx context.Context, + r *resource, +) (latest *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkFind") + defer func() { + exit(err) + }() + // If any required fields in the input shape are missing, AWS resource is + // not created yet. Return NotFound here to indicate to callers that the + // resource isn't yet created. + if rm.requiredFieldsMissingFromReadManyInput(r) { + return nil, ackerr.NotFound + } + + input, err := rm.newListRequestPayload(r) + if err != nil { + return nil, err + } + var resp *svcsdk.DescribeAlarmsOutput + resp, err = rm.sdkapi.DescribeAlarmsWithContext(ctx, input) + rm.metrics.RecordAPICall("READ_MANY", "DescribeAlarms", err) + if err != nil { + if awsErr, ok := ackerr.AWSError(err); ok && awsErr.Code() == "UNKNOWN" { + return nil, ackerr.NotFound + } + return nil, err + } + + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := r.ko.DeepCopy() + + found := false + for _, elem := range resp.MetricAlarms { + if elem.ActionsEnabled != nil { + ko.Spec.ActionsEnabled = elem.ActionsEnabled + } else { + ko.Spec.ActionsEnabled = nil + } + if elem.AlarmActions != nil { + f1 := []*string{} + for _, f1iter := range elem.AlarmActions { + var f1elem string + f1elem = *f1iter + f1 = append(f1, &f1elem) + } + ko.Spec.AlarmActions = f1 + } else { + ko.Spec.AlarmActions = nil + } + if elem.AlarmDescription != nil { + ko.Spec.AlarmDescription = elem.AlarmDescription + } else { + ko.Spec.AlarmDescription = nil + } + if elem.ComparisonOperator != nil { + ko.Spec.ComparisonOperator = elem.ComparisonOperator + } else { + ko.Spec.ComparisonOperator = nil + } + if elem.DatapointsToAlarm != nil { + ko.Spec.DatapointsToAlarm = elem.DatapointsToAlarm + } else { + ko.Spec.DatapointsToAlarm = nil + } + if elem.Dimensions != nil { + f8 := []*svcapitypes.Dimension{} + for _, f8iter := range elem.Dimensions { + f8elem := &svcapitypes.Dimension{} + if f8iter.Name != nil { + f8elem.Name = f8iter.Name + } + if f8iter.Value != nil { + f8elem.Value = f8iter.Value + } + f8 = append(f8, f8elem) + } + ko.Spec.Dimensions = f8 + } else { + ko.Spec.Dimensions = nil + } + if elem.EvaluateLowSampleCountPercentile != nil { + ko.Spec.EvaluateLowSampleCountPercentile = elem.EvaluateLowSampleCountPercentile + } else { + ko.Spec.EvaluateLowSampleCountPercentile = nil + } + if elem.EvaluationPeriods != nil { + ko.Spec.EvaluationPeriods = elem.EvaluationPeriods + } else { + ko.Spec.EvaluationPeriods = nil + } + if elem.ExtendedStatistic != nil { + ko.Spec.ExtendedStatistic = elem.ExtendedStatistic + } else { + ko.Spec.ExtendedStatistic = nil + } + if elem.InsufficientDataActions != nil { + f13 := []*string{} + for _, f13iter := range elem.InsufficientDataActions { + var f13elem string + f13elem = *f13iter + f13 = append(f13, &f13elem) + } + ko.Spec.InsufficientDataActions = f13 + } else { + ko.Spec.InsufficientDataActions = nil + } + if elem.MetricName != nil { + ko.Spec.MetricName = elem.MetricName + } else { + 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 + } + 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 := &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 f15elemf4f0f0iter.Value != nil { + f15elemf4f0f0elem.Value = f15elemf4f0f0iter.Value + } + f15elemf4f0f0 = append(f15elemf4f0f0, f15elemf4f0f0elem) + } + f15elemf4f0.Dimensions = f15elemf4f0f0 + } + if f15iter.MetricStat.Metric.MetricName != nil { + f15elemf4f0.MetricName = f15iter.MetricStat.Metric.MetricName + } + if f15iter.MetricStat.Metric.Namespace != nil { + f15elemf4f0.Namespace = f15iter.MetricStat.Metric.Namespace + } + f15elemf4.Metric = f15elemf4f0 + } + if f15iter.MetricStat.Period != nil { + f15elemf4.Period = f15iter.MetricStat.Period + } + if f15iter.MetricStat.Stat != nil { + f15elemf4.Stat = f15iter.MetricStat.Stat + } + if f15iter.MetricStat.Unit != nil { + f15elemf4.Unit = f15iter.MetricStat.Unit + } + f15elem.MetricStat = f15elemf4 + } + if f15iter.Period != nil { + f15elem.Period = f15iter.Period + } + if f15iter.ReturnData != nil { + f15elem.ReturnData = f15iter.ReturnData + } + f15 = append(f15, f15elem) + } + ko.Spec.Metrics = f15 + } else { + ko.Spec.Metrics = nil + } + if elem.Namespace != nil { + ko.Spec.Namespace = elem.Namespace + } else { + ko.Spec.Namespace = nil + } + if elem.OKActions != nil { + f17 := []*string{} + for _, f17iter := range elem.OKActions { + var f17elem string + f17elem = *f17iter + f17 = append(f17, &f17elem) + } + ko.Spec.OKActions = f17 + } else { + ko.Spec.OKActions = nil + } + if elem.Period != nil { + ko.Spec.Period = elem.Period + } else { + ko.Spec.Period = nil + } + if elem.Statistic != nil { + ko.Spec.Statistic = elem.Statistic + } else { + ko.Spec.Statistic = nil + } + if elem.Threshold != nil { + ko.Spec.Threshold = elem.Threshold + } else { + ko.Spec.Threshold = nil + } + if elem.ThresholdMetricId != nil { + ko.Spec.ThresholdMetricID = elem.ThresholdMetricId + } else { + ko.Spec.ThresholdMetricID = nil + } + if elem.TreatMissingData != nil { + ko.Spec.TreatMissingData = elem.TreatMissingData + } else { + ko.Spec.TreatMissingData = nil + } + if elem.Unit != nil { + ko.Spec.Unit = elem.Unit + } else { + ko.Spec.Unit = nil + } + found = true + break + } + if !found { + return nil, ackerr.NotFound + } + + rm.setStatusDefaults(ko) + return &resource{ko}, nil +} + +// requiredFieldsMissingFromReadManyInput returns true if there are any fields +// for the ReadMany Input shape that are required but not present in the +// resource's Spec or Status +func (rm *resourceManager) requiredFieldsMissingFromReadManyInput( + r *resource, +) bool { + return false +} + +// newListRequestPayload returns SDK-specific struct for the HTTP request +// payload of the List API call for the resource +func (rm *resourceManager) newListRequestPayload( + r *resource, +) (*svcsdk.DescribeAlarmsInput, error) { + res := &svcsdk.DescribeAlarmsInput{} + + return res, nil +} + +// sdkCreate creates the supplied resource in the backend AWS service API and +// returns a copy of the resource with resource fields (in both Spec and +// Status) filled in with values from the CREATE API operation's Output shape. +func (rm *resourceManager) sdkCreate( + ctx context.Context, + desired *resource, +) (created *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkCreate") + defer func() { + exit(err) + }() + input, err := rm.newCreateRequestPayload(ctx, desired) + if err != nil { + return nil, err + } + + var resp *svcsdk.PutMetricAlarmOutput + _ = resp + resp, err = rm.sdkapi.PutMetricAlarmWithContext(ctx, input) + rm.metrics.RecordAPICall("CREATE", "PutMetricAlarm", err) + if err != nil { + return nil, err + } + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := desired.ko.DeepCopy() + + rm.setStatusDefaults(ko) + return &resource{ko}, nil +} + +// newCreateRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Create API call for the resource +func (rm *resourceManager) newCreateRequestPayload( + ctx context.Context, + r *resource, +) (*svcsdk.PutMetricAlarmInput, error) { + res := &svcsdk.PutMetricAlarmInput{} + + if r.ko.Spec.ActionsEnabled != nil { + res.SetActionsEnabled(*r.ko.Spec.ActionsEnabled) + } + if r.ko.Spec.AlarmActions != nil { + f1 := []*string{} + for _, f1iter := range r.ko.Spec.AlarmActions { + var f1elem string + f1elem = *f1iter + f1 = append(f1, &f1elem) + } + res.SetAlarmActions(f1) + } + if r.ko.Spec.AlarmDescription != nil { + res.SetAlarmDescription(*r.ko.Spec.AlarmDescription) + } + if r.ko.Spec.Name != nil { + res.SetAlarmName(*r.ko.Spec.Name) + } + if r.ko.Spec.ComparisonOperator != nil { + res.SetComparisonOperator(*r.ko.Spec.ComparisonOperator) + } + if r.ko.Spec.DatapointsToAlarm != nil { + res.SetDatapointsToAlarm(*r.ko.Spec.DatapointsToAlarm) + } + if r.ko.Spec.Dimensions != nil { + f6 := []*svcsdk.Dimension{} + for _, f6iter := range r.ko.Spec.Dimensions { + f6elem := &svcsdk.Dimension{} + if f6iter.Name != nil { + f6elem.SetName(*f6iter.Name) + } + if f6iter.Value != nil { + f6elem.SetValue(*f6iter.Value) + } + f6 = append(f6, f6elem) + } + res.SetDimensions(f6) + } + if r.ko.Spec.EvaluateLowSampleCountPercentile != nil { + res.SetEvaluateLowSampleCountPercentile(*r.ko.Spec.EvaluateLowSampleCountPercentile) + } + if r.ko.Spec.EvaluationPeriods != nil { + res.SetEvaluationPeriods(*r.ko.Spec.EvaluationPeriods) + } + if r.ko.Spec.ExtendedStatistic != nil { + res.SetExtendedStatistic(*r.ko.Spec.ExtendedStatistic) + } + if r.ko.Spec.InsufficientDataActions != nil { + f10 := []*string{} + for _, f10iter := range r.ko.Spec.InsufficientDataActions { + var f10elem string + f10elem = *f10iter + f10 = append(f10, &f10elem) + } + res.SetInsufficientDataActions(f10) + } + if r.ko.Spec.MetricName != nil { + res.SetMetricName(*r.ko.Spec.MetricName) + } + if r.ko.Spec.Metrics != nil { + f12 := []*svcsdk.MetricDataQuery{} + for _, f12iter := range r.ko.Spec.Metrics { + f12elem := &svcsdk.MetricDataQuery{} + if f12iter.AccountID != nil { + f12elem.SetAccountId(*f12iter.AccountID) + } + if f12iter.Expression != nil { + f12elem.SetExpression(*f12iter.Expression) + } + if f12iter.ID != nil { + f12elem.SetId(*f12iter.ID) + } + if f12iter.Label != nil { + f12elem.SetLabel(*f12iter.Label) + } + if f12iter.MetricStat != nil { + f12elemf4 := &svcsdk.MetricStat{} + if f12iter.MetricStat.Metric != nil { + f12elemf4f0 := &svcsdk.Metric{} + if f12iter.MetricStat.Metric.Dimensions != nil { + f12elemf4f0f0 := []*svcsdk.Dimension{} + for _, f12elemf4f0f0iter := range f12iter.MetricStat.Metric.Dimensions { + f12elemf4f0f0elem := &svcsdk.Dimension{} + if f12elemf4f0f0iter.Name != nil { + f12elemf4f0f0elem.SetName(*f12elemf4f0f0iter.Name) + } + if f12elemf4f0f0iter.Value != nil { + f12elemf4f0f0elem.SetValue(*f12elemf4f0f0iter.Value) + } + f12elemf4f0f0 = append(f12elemf4f0f0, f12elemf4f0f0elem) + } + f12elemf4f0.SetDimensions(f12elemf4f0f0) + } + if f12iter.MetricStat.Metric.MetricName != nil { + f12elemf4f0.SetMetricName(*f12iter.MetricStat.Metric.MetricName) + } + if f12iter.MetricStat.Metric.Namespace != nil { + f12elemf4f0.SetNamespace(*f12iter.MetricStat.Metric.Namespace) + } + f12elemf4.SetMetric(f12elemf4f0) + } + if f12iter.MetricStat.Period != nil { + f12elemf4.SetPeriod(*f12iter.MetricStat.Period) + } + if f12iter.MetricStat.Stat != nil { + f12elemf4.SetStat(*f12iter.MetricStat.Stat) + } + if f12iter.MetricStat.Unit != nil { + f12elemf4.SetUnit(*f12iter.MetricStat.Unit) + } + f12elem.SetMetricStat(f12elemf4) + } + if f12iter.Period != nil { + f12elem.SetPeriod(*f12iter.Period) + } + if f12iter.ReturnData != nil { + f12elem.SetReturnData(*f12iter.ReturnData) + } + f12 = append(f12, f12elem) + } + res.SetMetrics(f12) + } + if r.ko.Spec.Namespace != nil { + res.SetNamespace(*r.ko.Spec.Namespace) + } + if r.ko.Spec.OKActions != nil { + f14 := []*string{} + for _, f14iter := range r.ko.Spec.OKActions { + var f14elem string + f14elem = *f14iter + f14 = append(f14, &f14elem) + } + res.SetOKActions(f14) + } + if r.ko.Spec.Period != nil { + res.SetPeriod(*r.ko.Spec.Period) + } + if r.ko.Spec.Statistic != nil { + res.SetStatistic(*r.ko.Spec.Statistic) + } + if r.ko.Spec.Tags != nil { + f17 := []*svcsdk.Tag{} + for _, f17iter := range r.ko.Spec.Tags { + f17elem := &svcsdk.Tag{} + if f17iter.Key != nil { + f17elem.SetKey(*f17iter.Key) + } + if f17iter.Value != nil { + f17elem.SetValue(*f17iter.Value) + } + f17 = append(f17, f17elem) + } + res.SetTags(f17) + } + if r.ko.Spec.Threshold != nil { + res.SetThreshold(*r.ko.Spec.Threshold) + } + if r.ko.Spec.ThresholdMetricID != nil { + res.SetThresholdMetricId(*r.ko.Spec.ThresholdMetricID) + } + if r.ko.Spec.TreatMissingData != nil { + res.SetTreatMissingData(*r.ko.Spec.TreatMissingData) + } + if r.ko.Spec.Unit != nil { + res.SetUnit(*r.ko.Spec.Unit) + } + + return res, nil +} + +// sdkUpdate patches the supplied resource in the backend AWS service API and +// returns a new resource with updated fields. +func (rm *resourceManager) sdkUpdate( + ctx context.Context, + desired *resource, + latest *resource, + delta *ackcompare.Delta, +) (updated *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkUpdate") + defer func() { + exit(err) + }() + input, err := rm.newUpdateRequestPayload(ctx, desired, delta) + if err != nil { + return nil, err + } + + var resp *svcsdk.PutMetricAlarmOutput + _ = resp + resp, err = rm.sdkapi.PutMetricAlarmWithContext(ctx, input) + rm.metrics.RecordAPICall("UPDATE", "PutMetricAlarm", err) + if err != nil { + return nil, err + } + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := desired.ko.DeepCopy() + + rm.setStatusDefaults(ko) + return &resource{ko}, nil +} + +// newUpdateRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Update API call for the resource +func (rm *resourceManager) newUpdateRequestPayload( + ctx context.Context, + r *resource, + delta *ackcompare.Delta, +) (*svcsdk.PutMetricAlarmInput, error) { + res := &svcsdk.PutMetricAlarmInput{} + + if r.ko.Spec.ActionsEnabled != nil { + res.SetActionsEnabled(*r.ko.Spec.ActionsEnabled) + } + if r.ko.Spec.AlarmActions != nil { + f1 := []*string{} + for _, f1iter := range r.ko.Spec.AlarmActions { + var f1elem string + f1elem = *f1iter + f1 = append(f1, &f1elem) + } + res.SetAlarmActions(f1) + } + if r.ko.Spec.AlarmDescription != nil { + res.SetAlarmDescription(*r.ko.Spec.AlarmDescription) + } + if r.ko.Spec.Name != nil { + res.SetAlarmName(*r.ko.Spec.Name) + } + if r.ko.Spec.ComparisonOperator != nil { + res.SetComparisonOperator(*r.ko.Spec.ComparisonOperator) + } + if r.ko.Spec.DatapointsToAlarm != nil { + res.SetDatapointsToAlarm(*r.ko.Spec.DatapointsToAlarm) + } + if r.ko.Spec.Dimensions != nil { + f6 := []*svcsdk.Dimension{} + for _, f6iter := range r.ko.Spec.Dimensions { + f6elem := &svcsdk.Dimension{} + if f6iter.Name != nil { + f6elem.SetName(*f6iter.Name) + } + if f6iter.Value != nil { + f6elem.SetValue(*f6iter.Value) + } + f6 = append(f6, f6elem) + } + res.SetDimensions(f6) + } + if r.ko.Spec.EvaluateLowSampleCountPercentile != nil { + res.SetEvaluateLowSampleCountPercentile(*r.ko.Spec.EvaluateLowSampleCountPercentile) + } + if r.ko.Spec.EvaluationPeriods != nil { + res.SetEvaluationPeriods(*r.ko.Spec.EvaluationPeriods) + } + if r.ko.Spec.ExtendedStatistic != nil { + res.SetExtendedStatistic(*r.ko.Spec.ExtendedStatistic) + } + if r.ko.Spec.InsufficientDataActions != nil { + f10 := []*string{} + for _, f10iter := range r.ko.Spec.InsufficientDataActions { + var f10elem string + f10elem = *f10iter + f10 = append(f10, &f10elem) + } + res.SetInsufficientDataActions(f10) + } + if r.ko.Spec.MetricName != nil { + res.SetMetricName(*r.ko.Spec.MetricName) + } + if r.ko.Spec.Metrics != nil { + f12 := []*svcsdk.MetricDataQuery{} + for _, f12iter := range r.ko.Spec.Metrics { + f12elem := &svcsdk.MetricDataQuery{} + if f12iter.AccountID != nil { + f12elem.SetAccountId(*f12iter.AccountID) + } + if f12iter.Expression != nil { + f12elem.SetExpression(*f12iter.Expression) + } + if f12iter.ID != nil { + f12elem.SetId(*f12iter.ID) + } + if f12iter.Label != nil { + f12elem.SetLabel(*f12iter.Label) + } + if f12iter.MetricStat != nil { + f12elemf4 := &svcsdk.MetricStat{} + if f12iter.MetricStat.Metric != nil { + f12elemf4f0 := &svcsdk.Metric{} + if f12iter.MetricStat.Metric.Dimensions != nil { + f12elemf4f0f0 := []*svcsdk.Dimension{} + for _, f12elemf4f0f0iter := range f12iter.MetricStat.Metric.Dimensions { + f12elemf4f0f0elem := &svcsdk.Dimension{} + if f12elemf4f0f0iter.Name != nil { + f12elemf4f0f0elem.SetName(*f12elemf4f0f0iter.Name) + } + if f12elemf4f0f0iter.Value != nil { + f12elemf4f0f0elem.SetValue(*f12elemf4f0f0iter.Value) + } + f12elemf4f0f0 = append(f12elemf4f0f0, f12elemf4f0f0elem) + } + f12elemf4f0.SetDimensions(f12elemf4f0f0) + } + if f12iter.MetricStat.Metric.MetricName != nil { + f12elemf4f0.SetMetricName(*f12iter.MetricStat.Metric.MetricName) + } + if f12iter.MetricStat.Metric.Namespace != nil { + f12elemf4f0.SetNamespace(*f12iter.MetricStat.Metric.Namespace) + } + f12elemf4.SetMetric(f12elemf4f0) + } + if f12iter.MetricStat.Period != nil { + f12elemf4.SetPeriod(*f12iter.MetricStat.Period) + } + if f12iter.MetricStat.Stat != nil { + f12elemf4.SetStat(*f12iter.MetricStat.Stat) + } + if f12iter.MetricStat.Unit != nil { + f12elemf4.SetUnit(*f12iter.MetricStat.Unit) + } + f12elem.SetMetricStat(f12elemf4) + } + if f12iter.Period != nil { + f12elem.SetPeriod(*f12iter.Period) + } + if f12iter.ReturnData != nil { + f12elem.SetReturnData(*f12iter.ReturnData) + } + f12 = append(f12, f12elem) + } + res.SetMetrics(f12) + } + if r.ko.Spec.Namespace != nil { + res.SetNamespace(*r.ko.Spec.Namespace) + } + if r.ko.Spec.OKActions != nil { + f14 := []*string{} + for _, f14iter := range r.ko.Spec.OKActions { + var f14elem string + f14elem = *f14iter + f14 = append(f14, &f14elem) + } + res.SetOKActions(f14) + } + if r.ko.Spec.Period != nil { + res.SetPeriod(*r.ko.Spec.Period) + } + if r.ko.Spec.Statistic != nil { + res.SetStatistic(*r.ko.Spec.Statistic) + } + if r.ko.Spec.Tags != nil { + f17 := []*svcsdk.Tag{} + for _, f17iter := range r.ko.Spec.Tags { + f17elem := &svcsdk.Tag{} + if f17iter.Key != nil { + f17elem.SetKey(*f17iter.Key) + } + if f17iter.Value != nil { + f17elem.SetValue(*f17iter.Value) + } + f17 = append(f17, f17elem) + } + res.SetTags(f17) + } + if r.ko.Spec.Threshold != nil { + res.SetThreshold(*r.ko.Spec.Threshold) + } + if r.ko.Spec.ThresholdMetricID != nil { + res.SetThresholdMetricId(*r.ko.Spec.ThresholdMetricID) + } + if r.ko.Spec.TreatMissingData != nil { + res.SetTreatMissingData(*r.ko.Spec.TreatMissingData) + } + if r.ko.Spec.Unit != nil { + res.SetUnit(*r.ko.Spec.Unit) + } + + return res, nil +} + +// sdkDelete deletes the supplied resource in the backend AWS service API +func (rm *resourceManager) sdkDelete( + ctx context.Context, + r *resource, +) (latest *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkDelete") + defer func() { + exit(err) + }() + input, err := rm.newDeleteRequestPayload(r) + if err != nil { + return nil, err + } + input.SetAlarmNames([]*string{r.ko.Spec.Name}) + + var resp *svcsdk.DeleteAlarmsOutput + _ = resp + resp, err = rm.sdkapi.DeleteAlarmsWithContext(ctx, input) + rm.metrics.RecordAPICall("DELETE", "DeleteAlarms", err) + return nil, err +} + +// newDeleteRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Delete API call for the resource +func (rm *resourceManager) newDeleteRequestPayload( + r *resource, +) (*svcsdk.DeleteAlarmsInput, error) { + res := &svcsdk.DeleteAlarmsInput{} + + return res, nil +} + +// setStatusDefaults sets default properties into supplied custom resource +func (rm *resourceManager) setStatusDefaults( + ko *svcapitypes.MetricAlarm, +) { + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if ko.Status.ACKResourceMetadata.Region == nil { + ko.Status.ACKResourceMetadata.Region = &rm.awsRegion + } + if ko.Status.ACKResourceMetadata.OwnerAccountID == nil { + ko.Status.ACKResourceMetadata.OwnerAccountID = &rm.awsAccountID + } + if ko.Status.Conditions == nil { + ko.Status.Conditions = []*ackv1alpha1.Condition{} + } +} + +// updateConditions returns updated resource, true; if conditions were updated +// else it returns nil, false +func (rm *resourceManager) updateConditions( + r *resource, + onSuccess bool, + err error, +) (*resource, bool) { + ko := r.ko.DeepCopy() + rm.setStatusDefaults(ko) + + // Terminal condition + var terminalCondition *ackv1alpha1.Condition = nil + var recoverableCondition *ackv1alpha1.Condition = nil + var syncCondition *ackv1alpha1.Condition = nil + for _, condition := range ko.Status.Conditions { + if condition.Type == ackv1alpha1.ConditionTypeTerminal { + terminalCondition = condition + } + if condition.Type == ackv1alpha1.ConditionTypeRecoverable { + recoverableCondition = condition + } + if condition.Type == ackv1alpha1.ConditionTypeResourceSynced { + syncCondition = condition + } + } + var termError *ackerr.TerminalError + if rm.terminalAWSError(err) || err == ackerr.SecretTypeNotSupported || err == ackerr.SecretNotFound || errors.As(err, &termError) { + if terminalCondition == nil { + terminalCondition = &ackv1alpha1.Condition{ + Type: ackv1alpha1.ConditionTypeTerminal, + } + ko.Status.Conditions = append(ko.Status.Conditions, terminalCondition) + } + var errorMessage = "" + if err == ackerr.SecretTypeNotSupported || err == ackerr.SecretNotFound || errors.As(err, &termError) { + errorMessage = err.Error() + } else { + awsErr, _ := ackerr.AWSError(err) + errorMessage = awsErr.Error() + } + terminalCondition.Status = corev1.ConditionTrue + terminalCondition.Message = &errorMessage + } else { + // Clear the terminal condition if no longer present + if terminalCondition != nil { + terminalCondition.Status = corev1.ConditionFalse + terminalCondition.Message = nil + } + // Handling Recoverable Conditions + if err != nil { + if recoverableCondition == nil { + // Add a new Condition containing a non-terminal error + recoverableCondition = &ackv1alpha1.Condition{ + Type: ackv1alpha1.ConditionTypeRecoverable, + } + ko.Status.Conditions = append(ko.Status.Conditions, recoverableCondition) + } + recoverableCondition.Status = corev1.ConditionTrue + awsErr, _ := ackerr.AWSError(err) + errorMessage := err.Error() + if awsErr != nil { + errorMessage = awsErr.Error() + } + recoverableCondition.Message = &errorMessage + } else if recoverableCondition != nil { + recoverableCondition.Status = corev1.ConditionFalse + recoverableCondition.Message = nil + } + } + // Required to avoid the "declared but not used" error in the default case + _ = syncCondition + if terminalCondition != nil || recoverableCondition != nil || syncCondition != nil { + return &resource{ko}, true // updated + } + return nil, false // not updated +} + +// terminalAWSError returns awserr, true; if the supplied error is an aws Error type +// and if the exception indicates that it is a Terminal exception +// 'Terminal' exception are specified in generator configuration +func (rm *resourceManager) terminalAWSError(err error) bool { + // No terminal_errors specified for this resource in generator config + return false +} diff --git a/pkg/resource/metric_alarm/tags.go b/pkg/resource/metric_alarm/tags.go new file mode 100644 index 0000000..703e744 --- /dev/null +++ b/pkg/resource/metric_alarm/tags.go @@ -0,0 +1,63 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package metric_alarm + +import ( + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" + + svcapitypes "github.com/aws-controllers-k8s/cloudwatch-controller/apis/v1alpha1" +) + +var ( + _ = svcapitypes.MetricAlarm{} + _ = acktags.NewTags() +) + +// ToACKTags converts the tags parameter into 'acktags.Tags' shape. +// This method helps in creating the hub(acktags.Tags) for merging +// default controller tags with existing resource tags. +func ToACKTags(tags []*svcapitypes.Tag) acktags.Tags { + result := acktags.NewTags() + if tags == nil || len(tags) == 0 { + return result + } + + for _, t := range tags { + if t.Key != nil { + if t.Value == nil { + result[*t.Key] = "" + } else { + result[*t.Key] = *t.Value + } + } + } + + return result +} + +// FromACKTags converts the tags parameter into []*svcapitypes.Tag shape. +// This method helps in setting the tags back inside AWSResource after merging +// default controller tags with existing resource tags. +func FromACKTags(tags acktags.Tags) []*svcapitypes.Tag { + result := []*svcapitypes.Tag{} + for k, v := range tags { + kCopy := k + vCopy := v + tag := svcapitypes.Tag{Key: &kCopy, Value: &vCopy} + result = append(result, &tag) + } + return result +} diff --git a/pkg/resource/registry.go b/pkg/resource/registry.go new file mode 100644 index 0000000..3f3aa28 --- /dev/null +++ b/pkg/resource/registry.go @@ -0,0 +1,45 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package resource + +import ( + ackrt "github.com/aws-controllers-k8s/runtime/pkg/runtime" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" +) + +// +kubebuilder:rbac:groups=services.k8s.aws,resources=adoptedresources,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=services.k8s.aws,resources=adoptedresources/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=services.k8s.aws,resources=fieldexports,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=services.k8s.aws,resources=fieldexports/status,verbs=get;update;patch +// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch +// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;patch +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;patch + +var ( + reg = ackrt.NewRegistry() +) + +// GetManagerFactories returns a slice of resource manager factories that are +// registered with this package +func GetManagerFactories() []acktypes.AWSResourceManagerFactory { + return reg.GetResourceManagerFactories() +} + +// RegisterManagerFactory registers a resource manager factory with the +// package's registry +func RegisterManagerFactory(f acktypes.AWSResourceManagerFactory) { + reg.RegisterResourceManagerFactory(f) +} diff --git a/pkg/version/version.go b/pkg/version/version.go new file mode 100644 index 0000000..de0f243 --- /dev/null +++ b/pkg/version/version.go @@ -0,0 +1,22 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package version + +var ( + GitVersion string + GitCommit string + BuildDate string +) diff --git a/templates/hooks/metricalarm/sdk_delete_post_build_request.go.tpl b/templates/hooks/metricalarm/sdk_delete_post_build_request.go.tpl new file mode 100644 index 0000000..3315a2c --- /dev/null +++ b/templates/hooks/metricalarm/sdk_delete_post_build_request.go.tpl @@ -0,0 +1 @@ + input.SetAlarmNames([]*string{r.ko.Spec.Name}) From 829286c9b71f0ce0af9eb4d821fbdad197745ff7 Mon Sep 17 00:00:00 2001 From: Jesse Bye <8467862+jessebye@users.noreply.github.com> Date: Mon, 24 Jul 2023 14:38:56 -0700 Subject: [PATCH 2/5] add e2e tests --- test/e2e/.gitignore | 1 + test/e2e/condition.py | 145 +++++++++++++++++++++++++++ test/e2e/metric_alarm.py | 90 +++++++++++++++++ test/e2e/resources/.gitkeep | 0 test/e2e/resources/metric_alarm.yaml | 14 +++ test/e2e/tests/.gitkeep | 0 test/e2e/tests/test_metric_alarm.py | 80 +++++++++++++++ 7 files changed, 330 insertions(+) create mode 100644 test/e2e/condition.py create mode 100644 test/e2e/metric_alarm.py delete mode 100644 test/e2e/resources/.gitkeep create mode 100644 test/e2e/resources/metric_alarm.yaml delete mode 100644 test/e2e/tests/.gitkeep create mode 100644 test/e2e/tests/test_metric_alarm.py diff --git a/test/e2e/.gitignore b/test/e2e/.gitignore index 92c35a4..22bf91a 100644 --- a/test/e2e/.gitignore +++ b/test/e2e/.gitignore @@ -2,3 +2,4 @@ __pycache__/ *.py[cod] **/bootstrap.yaml **/bootstrap.pkl +venv/ diff --git a/test/e2e/condition.py b/test/e2e/condition.py new file mode 100644 index 0000000..3d92b5f --- /dev/null +++ b/test/e2e/condition.py @@ -0,0 +1,145 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may +# not use this file except in compliance with the License. A copy of the +# License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +"""Utility functions to help processing Kubernetes resource conditions""" + +# TODO(jaypipes): Move these functions to acktest library. The reason these are +# here is because the existing k8s.assert_condition_state_message doesn't +# actually assert anything. It returns true or false and logs messages. + +import pytest + +from acktest.k8s import resource as k8s + +CONDITION_TYPE_ADOPTED = "ACK.Adopted" +CONDITION_TYPE_RESOURCE_SYNCED = "ACK.ResourceSynced" +CONDITION_TYPE_TERMINAL = "ACK.Terminal" +CONDITION_TYPE_RECOVERABLE = "ACK.Recoverable" +CONDITION_TYPE_ADVISORY = "ACK.Advisory" +CONDITION_TYPE_LATE_INITIALIZED = "ACK.LateInitialized" + + +def assert_type_status( + ref: k8s.CustomResourceReference, + cond_type_match: str = CONDITION_TYPE_RESOURCE_SYNCED, + cond_status_match: bool = True, +): + """Asserts that the supplied resource has a condition of type + ACK.ResourceSynced and that the Status of this condition is True. + + Usage: + from acktest.k8s import resource as k8s + + from e2e import condition + + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + db_cluster_id, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + k8s.wait_resource_consumed_by_controller(ref) + condition.assert_type_status( + ref, + condition.CONDITION_TYPE_RESOURCE_SYNCED, + False) + + Raises: + pytest.fail when condition of the specified type is not found or is not + in the supplied status. + """ + cond = k8s.get_resource_condition(ref, cond_type_match) + if cond is None: + msg = (f"Failed to find {cond_type_match} condition in " + f"resource {ref}") + pytest.fail(msg) + + cond_status = cond.get('status', None) + if str(cond_status) != str(cond_status_match): + msg = (f"Expected {cond_type_match} condition to " + f"have status {cond_status_match} but found {cond_status}") + pytest.fail(msg) + + +def assert_synced_status( + ref: k8s.CustomResourceReference, + cond_status_match: bool, +): + """Asserts that the supplied resource has a condition of type + ACK.ResourceSynced and that the Status of this condition is True. + + Usage: + from acktest.k8s import resource as k8s + + from e2e import condition + + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + db_cluster_id, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + k8s.wait_resource_consumed_by_controller(ref) + condition.assert_synced_status(ref, False) + + Raises: + pytest.fail when ACK.ResourceSynced condition is not found or is not in + a True status. + """ + assert_type_status(ref, CONDITION_TYPE_RESOURCE_SYNCED, cond_status_match) + + +def assert_synced(ref: k8s.CustomResourceReference): + """Asserts that the supplied resource has a condition of type + ACK.ResourceSynced and that the Status of this condition is True. + + Usage: + from acktest.k8s import resource as k8s + + from e2e import condition + + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + db_cluster_id, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + k8s.wait_resource_consumed_by_controller(ref) + condition.assert_synced(ref) + + Raises: + pytest.fail when ACK.ResourceSynced condition is not found or is not in + a True status. + """ + return assert_synced_status(ref, True) + + +def assert_not_synced(ref: k8s.CustomResourceReference): + """Asserts that the supplied resource has a condition of type + ACK.ResourceSynced and that the Status of this condition is False. + + Usage: + from acktest.k8s import resource as k8s + + from e2e import condition + + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + db_cluster_id, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + k8s.wait_resource_consumed_by_controller(ref) + condition.assert_not_synced(ref) + + Raises: + pytest.fail when ACK.ResourceSynced condition is not found or is not in + a False status. + """ + return assert_synced_status(ref, False) diff --git a/test/e2e/metric_alarm.py b/test/e2e/metric_alarm.py new file mode 100644 index 0000000..5bd4a95 --- /dev/null +++ b/test/e2e/metric_alarm.py @@ -0,0 +1,90 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may +# not use this file except in compliance with the License. A copy of the +# License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +"""Utilities for working with Metric Alarm resources""" + +import datetime +import time + +import boto3 +import pytest + +DEFAULT_WAIT_UNTIL_DELETED_TIMEOUT_SECONDS = 60*20 +DEFAULT_WAIT_UNTIL_DELETED_INTERVAL_SECONDS = 15 + + +def wait_until_deleted( + metric_alarm_name: str, + timeout_seconds: int = DEFAULT_WAIT_UNTIL_DELETED_TIMEOUT_SECONDS, + interval_seconds: int = DEFAULT_WAIT_UNTIL_DELETED_INTERVAL_SECONDS, + ) -> None: + """Waits until a Metric Alarm with a supplied name is no longer returned from + the CloudWatch API. + + Usage: + from e2e.metric_alarm import wait_until_deleted + + wait_until_deleted(alarm_name) + + Raises: + pytest.fail upon timeout or if the Metric Alarm goes to any other status + other than 'deleting' + """ + now = datetime.datetime.now() + timeout = now + datetime.timedelta(seconds=timeout_seconds) + + while True: + if datetime.datetime.now() >= timeout: + pytest.fail( + "Timed out waiting for Metric Alarm to be " + "deleted in CloudWatch API" + ) + time.sleep(interval_seconds) + + latest = get(metric_alarm_name) + if latest is None: + break + + +def exists(metric_alarm_name): + """Returns True if the supplied Metric Alarm exists, False otherwise. + """ + return get(metric_alarm_name) is not None + + +def get(metric_alarm_name): + """Returns a dict containing the Metric Alarm record from the CloudWatch API. + + If no such Metric Alarm exists, returns None. + """ + c = boto3.client('cloudwatch') + resp = c.describe_alarms(AlarmNames=[metric_alarm_name]) + if len(resp['MetricAlarms']) == 1: + return resp['MetricAlarms'][0] + return None + + +def get_tags(metric_alarm_arn): + """Returns a dict containing the Metric Alarm's tag records from the + CloudWatch API. + + If no such Metric Alarm exists, returns None. + """ + c = boto3.client('cloudwatch') + try: + resp = c.list_tags_for_resource( + ResourceName=metric_alarm_arn, + ) + return resp['Tags'] + except c.exceptions.ResourceNotFoundException: + return None diff --git a/test/e2e/resources/.gitkeep b/test/e2e/resources/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/test/e2e/resources/metric_alarm.yaml b/test/e2e/resources/metric_alarm.yaml new file mode 100644 index 0000000..e1b3896 --- /dev/null +++ b/test/e2e/resources/metric_alarm.yaml @@ -0,0 +1,14 @@ +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 diff --git a/test/e2e/tests/.gitkeep b/test/e2e/tests/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/test/e2e/tests/test_metric_alarm.py b/test/e2e/tests/test_metric_alarm.py new file mode 100644 index 0000000..b5181d6 --- /dev/null +++ b/test/e2e/tests/test_metric_alarm.py @@ -0,0 +1,80 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may +# not use this file except in compliance with the License. A copy of the +# License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +"""Integration tests for the CloudWatch API MetricAlarm resource +""" + +import time + +import pytest + +from acktest.k8s import resource as k8s +from acktest.resources import random_suffix_name +from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_cloudwatch_resource +from e2e.replacement_values import REPLACEMENT_VALUES +from e2e import condition +from e2e import metric_alarm + +RESOURCE_PLURAL = 'metricalarms' + +CHECK_STATUS_WAIT_SECONDS = 10 +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) + + replacements = REPLACEMENT_VALUES.copy() + replacements["METRIC_ALARM_NAME"] = metric_alarm_name + resource_data = load_cloudwatch_resource( + "metric_alarm", + additional_replacements=replacements, + ) + + # Create the k8s resource + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + metric_alarm_name, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + cr = k8s.wait_resource_consumed_by_controller(ref) + + assert cr is not None + assert k8s.get_resource_exists(ref) + + yield (ref, cr) + + # Try to delete, if doesn't already exist + _, deleted = k8s.delete_custom_resource( + ref, + period_length=DELETE_WAIT_AFTER_SECONDS, + ) + assert deleted + + metric_alarm.wait_until_deleted(metric_alarm_name) + + +@service_marker +@pytest.mark.canary +class TestMetricAlarm: + def test_crud(self, _metric_alarm): + (ref, cr) = _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) From f5c8751806b65092bf89d063c6ed4b7646a1478e Mon Sep 17 00:00:00 2001 From: Jesse Bye <8467862+jessebye@users.noreply.github.com> Date: Mon, 24 Jul 2023 14:41:40 -0700 Subject: [PATCH 3/5] remove jessebye from service-team --- OWNERS_ALIASES | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 12c74d9..0b4f69c 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -5,5 +5,4 @@ aliases: - a-hilaly - RedbackThomson - jljaco - service-team: - - jessebye + service-team: [] From 9433fe1506c981340dea4676aaf5b0875f8b077a Mon Sep 17 00:00:00 2001 From: Jesse Bye <8467862+jessebye@users.noreply.github.com> Date: Mon, 24 Jul 2023 14:41:49 -0700 Subject: [PATCH 4/5] add back TODO comment --- OWNERS_ALIASES | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 0b4f69c..993d39f 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -5,4 +5,5 @@ aliases: - a-hilaly - RedbackThomson - jljaco + # TODO: Add your team members' GitHub aliases to the team alias service-team: [] From 925b67cb2bea2cb23712b9e0a77cfc40cbfa48e2 Mon Sep 17 00:00:00 2001 From: Jesse Bye <8467862+jessebye@users.noreply.github.com> Date: Tue, 25 Jul 2023 12:16:20 -0700 Subject: [PATCH 5/5] add recommended-inline-policy --- config/iam/recommended-inline-policy | 1 + 1 file changed, 1 insertion(+) create mode 100644 config/iam/recommended-inline-policy diff --git a/config/iam/recommended-inline-policy b/config/iam/recommended-inline-policy new file mode 100644 index 0000000..4c230dc --- /dev/null +++ b/config/iam/recommended-inline-policy @@ -0,0 +1 @@ +arn:aws:iam::aws:policy/CloudWatchFullAccess