├── test └── e2e │ ├── .gitignore │ ├── requirements.txt │ ├── resources │ ├── global_cluster.yaml │ ├── db_snapshot.yaml │ ├── db_parameter_group_aurora_postgresql14.yaml │ ├── db_cluster_snapshot.yaml │ ├── db_cluster_parameter_group_aurora_postgresql14.yaml │ ├── db_subnet_group_2az.yaml │ ├── db_cluster_endpoint.yaml │ ├── db_parameter_group_postgres13_standard.yaml │ ├── db_proxy.yaml │ ├── db_cluster_parameter_group_aurora_mysql5.7.yaml │ ├── db_instance_ref.yaml │ ├── db_cluster_parameter_group_aurora_mysql8.0_logging.yaml │ ├── db_cluster_mysql_serverless.yaml │ ├── db_cluster_ref.yaml │ ├── db_cluster_aurora_postgres.yaml │ ├── db_cluster_aurora_postgres_log_exports.yaml │ ├── db_instance_postgres14_t3_micro.yaml │ └── db_cluster_aurora_postgres_clone.yaml │ ├── tests │ ├── __init__.py │ └── test_global_cluster.py │ ├── tag.py │ ├── replacement_values.py │ ├── service_cleanup.py │ ├── __init__.py │ ├── bootstrap_resources.py │ ├── service_bootstrap.py │ ├── fixtures.py │ ├── conftest.py │ ├── db_cluster_endpoint.py │ └── db_subnet_group.py ├── NOTICE ├── config ├── iam │ └── recommended-policy-arn ├── rbac │ ├── service-account.yaml │ ├── kustomization.yaml │ ├── cluster-role-binding.yaml │ ├── leader-election-role-binding.yaml │ ├── leader-election-role.yaml │ ├── role-reader.yaml │ ├── role-writer.yaml │ └── cluster-role-controller.yaml ├── overlays │ └── namespaced │ │ ├── role.json │ │ ├── role-binding.json │ │ └── kustomization.yaml ├── crd │ ├── common │ │ ├── kustomization.yaml │ │ └── bases │ │ │ └── services.k8s.aws_iamroleselectors.yaml │ └── kustomization.yaml ├── controller │ ├── kustomization.yaml │ ├── service.yaml │ └── deployment.yaml └── default │ └── kustomization.yaml ├── .gitignore ├── templates └── hooks │ ├── db_cluster_endpoint │ ├── delta_pre_compare.go.tpl │ ├── sdk_read_many_post_set_output.go.tpl │ └── sdk_update_pre_build_request.go.tpl │ ├── db_parameter_group │ ├── delta_pre_compare.go.tpl │ ├── sdk_create_post_set_output.go.tpl │ └── sdk_read_many_post_set_output.go.tpl │ ├── db_subnet_group │ ├── delta_pre_compare.go.tpl │ ├── sdk_update_pre_set_output.go.tpl │ └── sdk_read_many_post_set_output.go.tpl │ ├── db_cluster_parameter_group │ ├── delta_pre_compare.go.tpl │ ├── sdk_create_post_set_output.go.tpl │ └── sdk_read_many_post_set_output.go.tpl │ ├── db_proxy │ ├── sdk_delete_pre_build_request.go.tpl │ ├── sdk_read_many_post_set_output.go.tpl │ ├── sdk_update_post_set_output.go.tpl │ ├── sdk_create_post_set_output.go.tpl │ └── sdk_update_pre_build_request.go.tpl │ ├── db_cluster │ ├── sdk_delete_pre_build_request.go.tpl │ ├── sdk_delete_post_build_request.go.tpl │ ├── sdk_create_post_set_output.go.tpl │ ├── sdk_create_pre_build_request.go.tpl │ ├── delta_pre_compare.go.tpl │ ├── sdk_file_end.go.tpl │ └── sdk_read_many_post_set_output.go.tpl │ ├── db_instance │ ├── sdk_delete_pre_build_request.go.tpl │ ├── sdk_delete_post_build_request.go.tpl │ ├── sdk_update_pre_set_output.go.tpl │ ├── sdk_create_post_set_output.go.tpl │ ├── sdk_create_pre_build_request.go.tpl │ ├── sdk_update_pre_build_request.go.tpl │ ├── sdk_file_end.go.tpl │ ├── delta_pre_compare.go.tpl │ └── sdk_update_post_build_request.go.tpl │ ├── db_snapshot │ ├── sdk_update_pre_build_request.go.tpl │ ├── sdk_create_post_set_output.go.tpl │ └── sdk_read_many_post_set_output.go.tpl │ └── db_cluster_snapshot │ ├── sdk_update_pre_build_request.go.tpl │ ├── sdk_create_post_set_output.go.tpl │ └── sdk_read_many_post_set_output.go.tpl ├── OWNERS ├── apis └── v1alpha1 │ ├── doc.go │ ├── ack-generate-metadata.yaml │ ├── groupversion_info.go │ └── annotation.go ├── .github └── workflows │ ├── postsubmit.yaml │ └── create-release.yml ├── SECURITY.md ├── metadata.yaml ├── CODE_OF_CONDUCT.md ├── OWNERS_ALIASES ├── Makefile ├── helm ├── Chart.yaml ├── templates │ ├── service-account.yaml │ ├── NOTES.txt │ ├── role-reader.yaml │ ├── leader-election-role.yaml │ ├── leader-election-role-binding.yaml │ ├── metrics-service.yaml │ ├── role-writer.yaml │ ├── caches-role.yaml │ ├── cluster-role-controller.yaml │ ├── caches-role-binding.yaml │ └── cluster-role-binding.yaml └── crds │ └── services.k8s.aws_iamroleselectors.yaml ├── pkg ├── version │ └── version.go ├── resource │ ├── db_proxy │ │ ├── identifiers.go │ │ ├── references.go │ │ └── manager_factory.go │ ├── db_cluster │ │ ├── identifiers.go │ │ ├── manager_factory.go │ │ └── custom_update_test.go │ ├── db_instance │ │ ├── identifiers.go │ │ └── manager_factory.go │ ├── db_snapshot │ │ ├── identifiers.go │ │ ├── delta.go │ │ └── manager_factory.go │ ├── global_cluster │ │ ├── identifiers.go │ │ ├── references.go │ │ └── manager_factory.go │ ├── db_subnet_group │ │ ├── identifiers.go │ │ ├── delta.go │ │ └── manager_factory.go │ ├── db_cluster_endpoint │ │ ├── identifiers.go │ │ └── manager_factory.go │ ├── db_cluster_snapshot │ │ ├── identifiers.go │ │ ├── delta.go │ │ └── manager_factory.go │ ├── db_parameter_group │ │ ├── identifiers.go │ │ ├── references.go │ │ ├── delta.go │ │ └── manager_factory.go │ ├── db_cluster_parameter_group │ │ ├── identifiers.go │ │ ├── references.go │ │ ├── delta.go │ │ └── manager_factory.go │ └── registry.go └── util │ ├── tags.go │ ├── annotations.go │ ├── annotations_test.go │ ├── parameter_cache.go │ ├── parameters.go │ └── tags_test.go ├── olm └── olmconfig.yaml ├── GOVERNANCE.md ├── CONTRIBUTING.md └── go.local.mod /test/e2e/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | **/bootstrap.pkl -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | -------------------------------------------------------------------------------- /config/iam/recommended-policy-arn: -------------------------------------------------------------------------------- 1 | arn:aws:iam::aws:policy/AmazonRDSFullAccess 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *~ 4 | .idea 5 | .vscode 6 | /docs/site 7 | bin 8 | build -------------------------------------------------------------------------------- /templates/hooks/db_cluster_endpoint/delta_pre_compare.go.tpl: -------------------------------------------------------------------------------- 1 | compareTags(delta, a, b) 2 | -------------------------------------------------------------------------------- /templates/hooks/db_parameter_group/delta_pre_compare.go.tpl: -------------------------------------------------------------------------------- 1 | compareTags(delta, a, b) 2 | -------------------------------------------------------------------------------- /templates/hooks/db_subnet_group/delta_pre_compare.go.tpl: -------------------------------------------------------------------------------- 1 | compareTags(delta, a, b) 2 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - core-ack-team -------------------------------------------------------------------------------- /templates/hooks/db_cluster_parameter_group/delta_pre_compare.go.tpl: -------------------------------------------------------------------------------- 1 | compareTags(delta, a, b) 2 | -------------------------------------------------------------------------------- /test/e2e/requirements.txt: -------------------------------------------------------------------------------- 1 | acktest @ git+https://github.com/aws-controllers-k8s/test-infra.git@e05e2903b8193f882b6caac7d052e009317219d7 -------------------------------------------------------------------------------- /templates/hooks/db_proxy/sdk_delete_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | if proxyDeleting(r) { 2 | return r, requeueWaitWhileDeleting 3 | } 4 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster/sdk_delete_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | if clusterDeleting(r) { 2 | return r, requeueWaitWhileDeleting 3 | } 4 | -------------------------------------------------------------------------------- /templates/hooks/db_instance/sdk_delete_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | if instanceDeleting(r) { 2 | return r, requeueWaitWhileDeleting 3 | } 4 | -------------------------------------------------------------------------------- /config/rbac/service-account.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: ack-rds-controller 6 | namespace: ack-system 7 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster/sdk_delete_post_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | err = setDeleteDBClusterInput(r, input) 2 | if err != nil { 3 | return nil, err 4 | } 5 | -------------------------------------------------------------------------------- /config/overlays/namespaced/role.json: -------------------------------------------------------------------------------- 1 | [{"op": "replace", "path": "/kind", "value": "Role"}, 2 | {"op": "add", "path": "/metadata/namespace", "value": "ack-system"}] -------------------------------------------------------------------------------- /templates/hooks/db_instance/sdk_delete_post_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | err = setDeleteDBInstanceInput(r, input) 2 | if err != nil { 3 | return nil, err 4 | } 5 | -------------------------------------------------------------------------------- /templates/hooks/db_parameter_group/sdk_create_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if err = rm.syncParameters(ctx, desired, nil); err != nil { 2 | return nil, err 3 | } 4 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster_parameter_group/sdk_create_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if err = rm.syncParameters(ctx, desired, nil); err != nil { 2 | return nil, err 3 | } 4 | -------------------------------------------------------------------------------- /apis/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | // +k8s:deepcopy-gen=package 2 | // Package v1alpha1 is the v1alpha1 version of the rds.services.k8s.aws API. 3 | // +groupName=rds.services.k8s.aws 4 | package v1alpha1 5 | -------------------------------------------------------------------------------- /templates/hooks/db_subnet_group/sdk_update_pre_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if delta.DifferentAt("Spec.Tags") { 2 | if err = rm.syncTags(ctx, desired, latest); err != nil { 3 | return nil, err 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /config/overlays/namespaced/role-binding.json: -------------------------------------------------------------------------------- 1 | [{"op": "replace", "path": "/kind", "value": "RoleBinding"}, 2 | {"op": "add", "path": "/metadata/namespace", "value": "ack-system"}, 3 | {"op": "replace", "path": "/roleRef/kind", "value": "Role"}] -------------------------------------------------------------------------------- /config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - cluster-role-binding.yaml 3 | - cluster-role-controller.yaml 4 | - role-reader.yaml 5 | - role-writer.yaml 6 | - service-account.yaml 7 | - leader-election-role.yaml 8 | - leader-election-role-binding.yaml 9 | -------------------------------------------------------------------------------- /.github/workflows/postsubmit.yaml: -------------------------------------------------------------------------------- 1 | name: Hydrate Go Proxy 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | call-hydrate-go-proxy: 10 | uses: aws-controllers-k8s/.github/.github/workflows/reusable-postsubmit.yaml@main 11 | -------------------------------------------------------------------------------- /config/crd/common/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Code generated in runtime. DO NOT EDIT. 2 | 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | resources: 6 | - bases/services.k8s.aws_iamroleselectors.yaml 7 | - bases/services.k8s.aws_fieldexports.yaml 8 | -------------------------------------------------------------------------------- /config/controller/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - deployment.yaml 3 | - service.yaml 4 | apiVersion: kustomize.config.k8s.io/v1beta1 5 | kind: Kustomization 6 | images: 7 | - name: controller 8 | newName: public.ecr.aws/aws-controllers-k8s/rds-controller 9 | newTag: 1.7.0 10 | -------------------------------------------------------------------------------- /test/e2e/resources/global_cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: GlobalCluster 3 | metadata: 4 | name: $GLOBAL_CLUSTER_NAME 5 | spec: 6 | globalClusterIdentifier: $GLOBAL_CLUSTER_NAME 7 | engine: $GLOBAL_CLUSTER_ENGINE 8 | databaseName: $GLOBAL_CLUSTER_DB_NAME 9 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security issue notifications 2 | 3 | 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. 4 | -------------------------------------------------------------------------------- /test/e2e/resources/db_snapshot.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBSnapshot 3 | metadata: 4 | name: $DB_SNAPSHOT_ID 5 | spec: 6 | dbInstanceIdentifier: $DB_INSTANCE_ID 7 | dbSnapshotIdentifier: $DB_SNAPSHOT_ID 8 | tags: 9 | - key: environment 10 | value: dev -------------------------------------------------------------------------------- /metadata.yaml: -------------------------------------------------------------------------------- 1 | service: 2 | full_name: "Amazon Relational Database Service" 3 | short_name: "RDS" 4 | link: "https://aws.amazon.com/rds/" 5 | documentation: "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html" 6 | api_versions: 7 | - api_version: v1alpha1 8 | status: available 9 | -------------------------------------------------------------------------------- /test/e2e/resources/db_parameter_group_aurora_postgresql14.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBParameterGroup 3 | metadata: 4 | name: $DB_PARAMETER_GROUP_NAME 5 | spec: 6 | name: $DB_PARAMETER_GROUP_NAME 7 | description: $DB_PARAMETER_GROUP_DESC 8 | family: aurora-postgresql14 9 | -------------------------------------------------------------------------------- /templates/hooks/db_proxy/sdk_read_many_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if !proxyAvailable(&resource{ko}) { 2 | // Setting resource synced condition to false will trigger a requeue of 3 | // the resource. No need to return a requeue error here. 4 | ackcondition.SetSynced(&resource{ko}, corev1.ConditionFalse, nil, nil) 5 | } -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: Create Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*.*.*" 7 | 8 | permissions: 9 | contents: write # For creating releases 10 | 11 | jobs: 12 | call-create-release: 13 | uses: aws-controllers-k8s/.github/.github/workflows/reusable-create-release.yaml@main 14 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_snapshot.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBClusterSnapshot 3 | metadata: 4 | name: $DB_CLUSTER_SNAPSHOT_ID 5 | spec: 6 | dbClusterIdentifier: $DB_CLUSTER_ID 7 | dbClusterSnapshotIdentifier: $DB_CLUSTER_SNAPSHOT_ID 8 | tags: 9 | - key: environment 10 | value: dev -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_parameter_group_aurora_postgresql14.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBClusterParameterGroup 3 | metadata: 4 | name: $DB_CLUSTER_PARAMETER_GROUP_NAME 5 | spec: 6 | name: $DB_CLUSTER_PARAMETER_GROUP_NAME 7 | description: $DB_CLUSTER_PARAMETER_GROUP_DESC 8 | family: aurora-postgresql14 9 | -------------------------------------------------------------------------------- /config/controller/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: ack-rds-metrics-service 5 | namespace: ack-system 6 | spec: 7 | selector: 8 | app.kubernetes.io/name: ack-rds-controller 9 | ports: 10 | - name: metricsport 11 | port: 8080 12 | targetPort: http 13 | protocol: TCP 14 | type: ClusterIP 15 | -------------------------------------------------------------------------------- /config/rbac/cluster-role-binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: ack-rds-controller-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: ack-rds-controller 9 | subjects: 10 | - kind: ServiceAccount 11 | name: ack-rds-controller 12 | namespace: ack-system 13 | -------------------------------------------------------------------------------- /test/e2e/resources/db_subnet_group_2az.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBSubnetGroup 3 | metadata: 4 | name: $DB_SUBNET_GROUP_NAME 5 | spec: 6 | name: $DB_SUBNET_GROUP_NAME 7 | description: $DB_SUBNET_GROUP_DESC 8 | subnetIDs: 9 | - $PUBLIC_SUBNET_1 10 | - $PUBLIC_SUBNET_2 11 | tags: 12 | - key: environment 13 | value: dev 14 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster_endpoint/sdk_read_many_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if ko.Status.ACKResourceMetadata != nil && ko.Status.ACKResourceMetadata.ARN != nil { 2 | resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN) 3 | tags, err := rm.getTags(ctx, *resourceARN) 4 | if err != nil { 5 | return nil, err 6 | } 7 | ko.Spec.Tags = tags 8 | } 9 | -------------------------------------------------------------------------------- /templates/hooks/db_instance/sdk_update_pre_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | ko.Status = latest.ko.Status 2 | setLastAppliedSecretReferenceAnnotation(&resource{ko}) 3 | // Setting resource synced condition to false will trigger a requeue of 4 | // the resource. No need to return a requeue error here. 5 | ackcondition.SetSynced(&resource{ko}, corev1.ConditionFalse, nil, nil) 6 | return &resource{ko}, nil 7 | -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_endpoint.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBClusterEndpoint 3 | metadata: 4 | name: $DB_CLUSTER_ENDPOINT_IDENTIFIER 5 | spec: 6 | dbClusterEndpointIdentifier: $DB_CLUSTER_ENDPOINT_IDENTIFIER 7 | dbClusterIdentifier: $DB_CLUSTER_IDENTIFIER 8 | endpointType: $ENDPOINT_TYPE 9 | tags: 10 | - key: environment 11 | value: dev 12 | -------------------------------------------------------------------------------- /OWNERS_ALIASES: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners#owners_aliases 2 | 3 | aliases: 4 | core-ack-team: 5 | - a-hilaly 6 | - jlbutler 7 | - michaelhtm 8 | - rushmash91 9 | - knottnt 10 | # emeritus-core-ack-team: 11 | # - TiberiuGC 12 | # - jaypipes 13 | # - jljaco 14 | # - mhausenblas 15 | # - RedbackThomson 16 | # - vijtrip2 17 | # - ivelichkovich -------------------------------------------------------------------------------- /config/rbac/leader-election-role-binding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | namespace: ack-system 6 | name: rds-leader-election-rolebinding 7 | roleRef: 8 | apiGroup: rbac.authorization.k8s.io 9 | kind: Role 10 | name: rds-leader-election-role 11 | subjects: 12 | - kind: ServiceAccount 13 | name: ack-rds-controller 14 | namespace: ack-system 15 | -------------------------------------------------------------------------------- /config/overlays/namespaced/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - ../../default 3 | patches: 4 | - path: role.json 5 | target: 6 | group: rbac.authorization.k8s.io 7 | version: v1 8 | kind: ClusterRole 9 | name: ack-rds-controller 10 | - path: role-binding.json 11 | target: 12 | group: rbac.authorization.k8s.io 13 | version: v1 14 | kind: ClusterRoleBinding 15 | name: ack-rds-controller-rolebinding -------------------------------------------------------------------------------- /test/e2e/resources/db_parameter_group_postgres13_standard.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBParameterGroup 3 | metadata: 4 | name: $DB_PARAMETER_GROUP_NAME 5 | spec: 6 | name: $DB_PARAMETER_GROUP_NAME 7 | description: $DB_PARAMETER_GROUP_DESC 8 | family: postgres13 9 | parameterOverrides: 10 | array_nulls: "1" 11 | authentication_timeout: "50" 12 | tags: 13 | - key: environment 14 | value: dev 15 | -------------------------------------------------------------------------------- /test/e2e/resources/db_proxy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBProxy 3 | metadata: 4 | name: $DB_PROXY_NAME 5 | spec: 6 | name: $DB_PROXY_NAME 7 | engineFamily: $DB_PROXY_ENGINE_FAMILY 8 | roleARN: $IAM_ROLE_ARN 9 | auth: 10 | - secretARN: $SECRET_ARN 11 | authScheme: SECRETS 12 | iamAuth: DISABLED 13 | description: $DESCRIPTION 14 | vpcSubnetIDs: 15 | - $PUBLIC_SUBNET_1 16 | - $PUBLIC_SUBNET_2 17 | -------------------------------------------------------------------------------- /templates/hooks/db_snapshot/sdk_update_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | if delta.DifferentAt("Spec.Tags") { 2 | if err = rm.syncTags(ctx, desired, latest); err != nil { 3 | return nil, err 4 | } 5 | } 6 | if !snapshotAvailable(latest) { 7 | msg := "DB instance cannot be modifed while in '" + *latest.ko.Status.Status + "' status" 8 | ackcondition.SetSynced(desired, corev1.ConditionFalse, &msg, nil) 9 | return desired, requeueWaitUntilCanModify(latest) 10 | } 11 | -------------------------------------------------------------------------------- /templates/hooks/db_proxy/sdk_update_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | // When ModifyDBProxy API is successful, it asynchronously 2 | // updates the DBProxyStatus. Requeue to find the current 3 | // DBProxy status and set Synced condition accordingly 4 | if err == nil { 5 | // Setting resource synced condition to false will trigger a requeue of 6 | // the resource. No need to return a requeue error here. 7 | ackcondition.SetSynced(&resource{ko}, corev1.ConditionFalse, nil, nil) 8 | } -------------------------------------------------------------------------------- /templates/hooks/db_cluster_snapshot/sdk_update_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | if delta.DifferentAt("Spec.Tags") { 2 | if err = rm.syncTags(ctx, desired, latest); err != nil { 3 | return nil, err 4 | } 5 | } 6 | if !clusterSnapshotAvailable(latest) { 7 | msg := "DB cluster snapshot cannot be modifed while in '" + *latest.ko.Status.Status + "' status" 8 | ackcondition.SetSynced(desired, corev1.ConditionFalse, &msg, nil) 9 | return desired, requeueWaitUntilCanModify(latest) 10 | } 11 | -------------------------------------------------------------------------------- /config/rbac/leader-election-role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: rds-leader-election-role 6 | namespace: ack-system 7 | rules: 8 | - apiGroups: 9 | - coordination.k8s.io 10 | resources: 11 | - leases 12 | verbs: 13 | - get 14 | - list 15 | - watch 16 | - create 17 | - update 18 | - patch 19 | - delete 20 | - apiGroups: 21 | - "" 22 | resources: 23 | - events 24 | verbs: 25 | - create 26 | - patch 27 | -------------------------------------------------------------------------------- /templates/hooks/db_snapshot/sdk_create_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | r := &resource{ko} 2 | // We expect the DB snapshot to be in 'creating' status since we just 3 | // issued the call to create it, but I suppose it doesn't hurt to check 4 | // here. 5 | if snapshotCreating(r) { 6 | // Setting resource synced condition to false will trigger a requeue of 7 | // the resource. No need to return a requeue error here. 8 | ackcondition.SetSynced(r, corev1.ConditionFalse, nil, nil) 9 | return r, nil 10 | } -------------------------------------------------------------------------------- /templates/hooks/db_cluster_snapshot/sdk_create_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | r := &resource{ko} 2 | // We expect the DB cluster snapshot to be in 'creating' status since we just 3 | // issued the call to create it, but I suppose it doesn't hurt to check here. 4 | if clusterSnapshotCreating(r) { 5 | // Setting resource synced condition to false will trigger a requeue of 6 | // the resource. No need to return a requeue error here. 7 | ackcondition.SetSynced(r, corev1.ConditionFalse, nil, nil) 8 | return r, nil 9 | } -------------------------------------------------------------------------------- /templates/hooks/db_proxy/sdk_create_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | // We expect the DB proxy to be in 'creating' status since we just 2 | // issued the call to create it, but I suppose it doesn't hurt to check 3 | // here. 4 | if proxyCreating(&resource{ko}) { 5 | // Setting resource synced condition to false will trigger a requeue of 6 | // the resource. No need to return a requeue error here. 7 | ackcondition.SetSynced(&resource{ko}, corev1.ConditionFalse, nil, nil) 8 | return &resource{ko}, nil 9 | } 10 | -------------------------------------------------------------------------------- /apis/v1alpha1/ack-generate-metadata.yaml: -------------------------------------------------------------------------------- 1 | ack_generate_info: 2 | build_date: "2025-11-29T03:44:25Z" 3 | build_hash: 23c7074fa310ad1ccb38946775397c203b49f024 4 | go_version: go1.25.4 5 | version: v0.56.0 6 | api_directory_checksum: 90b0d1adcc91f4a1b1f1b436e3ac0c30d9271678 7 | api_version: v1alpha1 8 | aws_sdk_go_version: v1.32.6 9 | generator_config_info: 10 | file_checksum: 23c3c400e5913ebaa0047af70fda453b065ce321 11 | original_file_name: generator.yaml 12 | last_modification: 13 | reason: API generation 14 | -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_parameter_group_aurora_mysql5.7.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBClusterParameterGroup 3 | metadata: 4 | name: $DB_CLUSTER_PARAMETER_GROUP_NAME 5 | spec: 6 | name: $DB_CLUSTER_PARAMETER_GROUP_NAME 7 | description: $DB_CLUSTER_PARAMETER_GROUP_DESC 8 | family: "aurora-mysql5.7" 9 | tags: 10 | - key: environment 11 | value: dev 12 | parameterOverrides: 13 | aurora_binlog_read_buffer_size: "8192" 14 | aurora_read_replica_read_committed: "OFF" 15 | -------------------------------------------------------------------------------- /test/e2e/resources/db_instance_ref.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBInstance 3 | metadata: 4 | name: $DB_INSTANCE_ID 5 | spec: 6 | # NOTE(jaypipes): This needs to be db.t3.medium to support Aurora PostgreSQL 7 | # 14.6+. Smaller sizes will result in an InvalidParameterCombination. 8 | dbInstanceClass: db.t3.medium 9 | dbInstanceIdentifier: $DB_INSTANCE_ID 10 | dbClusterIdentifier: $DB_CLUSTER_ID 11 | dbParameterGroupRef: 12 | from: 13 | name: $DB_PARAMETER_GROUP_NAME 14 | engine: aurora-postgresql 15 | -------------------------------------------------------------------------------- /config/rbac/role-reader.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | creationTimestamp: null 6 | name: ack-rds-reader 7 | namespace: default 8 | rules: 9 | - apiGroups: 10 | - rds.services.k8s.aws 11 | resources: 12 | - dbclusters 13 | - dbclusterendpoints 14 | - dbclusterparametergroups 15 | - dbclustersnapshots 16 | - dbinstances 17 | - dbparametergroups 18 | - dbproxies 19 | - dbsnapshots 20 | - dbsubnetgroups 21 | - globalclusters 22 | verbs: 23 | - get 24 | - list 25 | - watch 26 | -------------------------------------------------------------------------------- /config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Adds namespace to all resources. 2 | # namespace: 3 | 4 | # Value of this field is prepended to the 5 | # names of all resources, e.g. a deployment named 6 | # "wordpress" becomes "alices-wordpress". 7 | # Note that it should also match with the prefix (text before '-') of the namespace 8 | # field above. 9 | # namePrefix: 10 | 11 | # Labels to add to all resources and selectors. 12 | #commonLabels: 13 | # someName: someValue 14 | 15 | resources: 16 | - ../crd 17 | - ../rbac 18 | - ../controller 19 | 20 | patchesStrategicMerge: 21 | -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_parameter_group_aurora_mysql8.0_logging.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBClusterParameterGroup 3 | metadata: 4 | name: $DB_CLUSTER_PARAMETER_GROUP_NAME 5 | spec: 6 | name: $DB_CLUSTER_PARAMETER_GROUP_NAME 7 | description: $DB_CLUSTER_PARAMETER_GROUP_DESC 8 | family: $DB_CLUSTER_PARAMETER_GROUP_FAMILY 9 | parameterOverrides: 10 | slow_query_log: "$PARAM_SLOW_QUERY_LOG_VALUE" 11 | long_query_time: "$PARAM_LONG_QUERY_TIME_VALUE" 12 | log_queries_not_using_indexes: "$PARAM_LOG_QUERIES_NOT_USING_INDEXES_VALUE" -------------------------------------------------------------------------------- /templates/hooks/db_cluster_endpoint/sdk_update_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | if !clusterEndpointReadyForUpdate(latest) { 2 | msg := "DB cluster is not available for modification in '" + 3 | *latest.ko.Status.Status + "' status" 4 | ackcondition.SetSynced(desired, corev1.ConditionFalse, &msg, nil) 5 | return desired, requeueWaitUntilCanModify(latest) 6 | } 7 | 8 | if delta.DifferentAt("Spec.Tags") { 9 | if err = rm.syncTags(ctx, desired, latest); err != nil { 10 | return nil, err 11 | } 12 | } 13 | 14 | if !delta.DifferentExcept("Spec.Tags") { 15 | return desired, nil 16 | } 17 | -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_mysql_serverless.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBCluster 3 | metadata: 4 | name: $DB_CLUSTER_ID 5 | spec: 6 | copyTagsToSnapshot: $COPY_TAGS_TO_SNAPSHOT 7 | dbClusterIdentifier: $DB_CLUSTER_ID 8 | databaseName: $DB_NAME 9 | engine: aurora-mysql 10 | engineMode: provisioned 11 | masterUsername: root 12 | masterUserPassword: 13 | namespace: $MASTER_USER_PASS_SECRET_NAMESPACE 14 | name: $MASTER_USER_PASS_SECRET_NAME 15 | key: $MASTER_USER_PASS_SECRET_KEY 16 | tags: 17 | - key: environment 18 | value: dev 19 | -------------------------------------------------------------------------------- /templates/hooks/db_snapshot/sdk_read_many_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if ko.Status.ACKResourceMetadata != nil && ko.Status.ACKResourceMetadata.ARN != nil { 2 | resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN) 3 | tags, err := rm.getTags(ctx, *resourceARN) 4 | if err != nil { 5 | return nil, err 6 | } 7 | ko.Spec.Tags = tags 8 | } 9 | if !snapshotAvailable(&resource{ko}) { 10 | // Setting resource synced condition to false will trigger a requeue of 11 | // the resource. No need to return a requeue error here. 12 | ackcondition.SetSynced(&resource{ko}, corev1.ConditionFalse, nil, nil) 13 | } 14 | -------------------------------------------------------------------------------- /test/e2e/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster_snapshot/sdk_read_many_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if ko.Status.ACKResourceMetadata != nil && ko.Status.ACKResourceMetadata.ARN != nil { 2 | resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN) 3 | tags, err := rm.getTags(ctx, *resourceARN) 4 | if err != nil { 5 | return nil, err 6 | } 7 | ko.Spec.Tags = tags 8 | } 9 | if !clusterSnapshotAvailable(&resource{ko}) { 10 | // Setting resource synced condition to false will trigger a requeue of 11 | // the resource. No need to return a requeue error here. 12 | ackcondition.SetSynced(&resource{ko}, corev1.ConditionFalse, nil, nil) 13 | } 14 | -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_ref.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBCluster 3 | metadata: 4 | name: $DB_CLUSTER_ID 5 | spec: 6 | copyTagsToSnapshot: false 7 | dbClusterIdentifier: $DB_CLUSTER_ID 8 | databaseName: $DB_NAME 9 | dbClusterParameterGroupRef: 10 | from: 11 | name: $DB_CLUSTER_PARAMETER_GROUP_NAME 12 | engine: aurora-postgresql 13 | engineMode: provisioned 14 | engineVersion: "14.6" 15 | masterUsername: root 16 | masterUserPassword: 17 | namespace: $MASTER_USER_PASS_SECRET_NAMESPACE 18 | name: $MASTER_USER_PASS_SECRET_NAME 19 | key: $MASTER_USER_PASS_SECRET_KEY 20 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster/sdk_create_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | // set the last-applied-secret-reference annotation on the DB instance 2 | // resource. 3 | r := &resource{ko} 4 | setLastAppliedSecretReferenceAnnotation(r) 5 | // We expect the DB cluster to be in 'creating' status since we just 6 | // issued the call to create it, but I suppose it doesn't hurt to check 7 | // here. 8 | if clusterCreating(r) { 9 | // Setting resource synced condition to false will trigger a requeue of 10 | // the resource. No need to return a requeue error here. 11 | ackcondition.SetSynced(r, corev1.ConditionFalse, nil, nil) 12 | return r, nil 13 | } 14 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster/sdk_create_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | // if request has SnapshotIdentifier spec, create request will call RestoreDBClusterFromSnapshotWithContext 2 | // instead of normal create api 3 | if desired.ko.Spec.SnapshotIdentifier != nil { 4 | return rm.restoreDbClusterFromSnapshot(ctx, desired) 5 | } 6 | 7 | // if request has SourceDBClusterIdentifier spec, create request will call RestoreDBClusterToPointInTimeWithContext 8 | // instead of normal create api 9 | if desired.ko.Spec.SourceDBClusterIdentifier != nil { 10 | return rm.restoreDbClusterToPointInTime(ctx, desired) 11 | } 12 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster/delta_pre_compare.go.tpl: -------------------------------------------------------------------------------- 1 | compareTags(delta, a, b) 2 | 3 | // Handle special case for StorageType field for Aurora engines 4 | // When StorageType is set to "aurora" (default), the API doesn't return it 5 | 6 | isAuroraEngine := (b.ko.Spec.Engine != nil && (*b.ko.Spec.Engine == "aurora-mysql" || *b.ko.Spec.Engine == "aurora-postgresql")) 7 | 8 | if isAuroraEngine && (a.ko.Spec.StorageType != nil && *a.ko.Spec.StorageType == "aurora" && b.ko.Spec.StorageType == nil) { 9 | b.ko.Spec.StorageType = aws.String("aurora") 10 | } 11 | 12 | compareSecretReferenceChanges(delta, a, b) 13 | -------------------------------------------------------------------------------- /templates/hooks/db_instance/sdk_create_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | // set the last-applied-secret-reference annotation on the DB instance 2 | // resource. 3 | r := &resource{ko} 4 | setLastAppliedSecretReferenceAnnotation(r) 5 | 6 | // We expect the DB instance to be in 'creating' status since we just 7 | // issued the call to create it, but I suppose it doesn't hurt to check 8 | // here. 9 | if instanceCreating(r) { 10 | // Setting resource synced condition to false will trigger a requeue of 11 | // the resource. No need to return a requeue error here. 12 | ackcondition.SetSynced(r, corev1.ConditionFalse, nil, nil) 13 | return r, nil 14 | } -------------------------------------------------------------------------------- /templates/hooks/db_instance/sdk_create_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | // if request has DBSnapshotIdentifier spec, create request will call RestoreDBInstanceFromDBSnapshotWithContext 2 | // instead of normal create api 3 | if desired.ko.Spec.DBSnapshotIdentifier != nil { 4 | return rm.restoreDbInstanceFromDbSnapshot(ctx, desired) 5 | } 6 | // if request has SourceDBInstanceIdentifier spec, create request will call CreateDBInstanceReadReplicaWithContext 7 | // instead of normal create api 8 | if desired.ko.Spec.SourceDBInstanceIdentifier != nil { 9 | return rm.createDBInstanceReadReplica(ctx, desired) 10 | } 11 | -------------------------------------------------------------------------------- /templates/hooks/db_parameter_group/sdk_read_many_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if ko.Status.ACKResourceMetadata != nil && ko.Status.ACKResourceMetadata.ARN != nil { 2 | resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN) 3 | tags, err := rm.getTags(ctx, *resourceARN) 4 | if err != nil { 5 | return nil, err 6 | } 7 | ko.Spec.Tags = tags 8 | } 9 | if ko.Spec.Name != nil { 10 | groupName := ko.Spec.Name 11 | params, paramStatuses, err := rm.getParameters(ctx, groupName) 12 | if err != nil { 13 | return nil, err 14 | } 15 | ko.Spec.ParameterOverrides = params 16 | ko.Status.ParameterOverrideStatuses = paramStatuses 17 | } 18 | -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_aurora_postgres.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBCluster 3 | metadata: 4 | name: $DB_CLUSTER_ID 5 | spec: 6 | autoMinorVersionUpgrade: false 7 | copyTagsToSnapshot: false 8 | dbClusterIdentifier: $DB_CLUSTER_ID 9 | enableIAMDatabaseAuthentication: false 10 | engine: aurora-postgresql 11 | engineMode: provisioned 12 | engineVersion: "14.15" 13 | masterUsername: root 14 | masterUserPassword: 15 | namespace: $MASTER_USER_PASS_SECRET_NAMESPACE 16 | name: $MASTER_USER_PASS_SECRET_NAME 17 | key: $MASTER_USER_PASS_SECRET_KEY 18 | port: 5432 19 | storageEncrypted: true 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash # Use bash syntax 2 | 3 | # Set up variables 4 | GO111MODULE=on 5 | 6 | # Build ldflags 7 | VERSION ?= "v0.0.0" 8 | GITCOMMIT=$(shell git rev-parse HEAD) 9 | BUILDDATE=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') 10 | GO_LDFLAGS=-ldflags "-X main.version=$(VERSION) \ 11 | -X main.buildHash=$(GITCOMMIT) \ 12 | -X main.buildDate=$(BUILDDATE)" 13 | 14 | .PHONY: all test 15 | 16 | all: test 17 | 18 | test: ## Run code tests 19 | go test -v ./... 20 | 21 | help: ## Show this help. 22 | @grep -F -h "##" $(MAKEFILE_LIST) | grep -F -v grep | sed -e 's/\\$$//' \ 23 | | awk -F'[:#]' '{print $$1 = sprintf("%-30s", $$1), $$4}' -------------------------------------------------------------------------------- /templates/hooks/db_subnet_group/sdk_read_many_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if ko.Status.ACKResourceMetadata != nil && ko.Status.ACKResourceMetadata.ARN != nil { 2 | resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN) 3 | tags, err := rm.getTags(ctx, *resourceARN) 4 | if err != nil { 5 | return nil, err 6 | } 7 | ko.Spec.Tags = tags 8 | } 9 | 10 | if ko.Status.Subnets != nil { 11 | f0 := []*string{} 12 | for _, subnetIdIter := range ko.Status.Subnets { 13 | if subnetIdIter.SubnetIdentifier != nil { 14 | f0 = append(f0, subnetIdIter.SubnetIdentifier) 15 | } 16 | } 17 | ko.Spec.SubnetIDs = f0 18 | } -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - common 5 | - bases/rds.services.k8s.aws_dbclusters.yaml 6 | - bases/rds.services.k8s.aws_dbclusterendpoints.yaml 7 | - bases/rds.services.k8s.aws_dbclusterparametergroups.yaml 8 | - bases/rds.services.k8s.aws_dbclustersnapshots.yaml 9 | - bases/rds.services.k8s.aws_dbinstances.yaml 10 | - bases/rds.services.k8s.aws_dbparametergroups.yaml 11 | - bases/rds.services.k8s.aws_dbproxies.yaml 12 | - bases/rds.services.k8s.aws_dbsnapshots.yaml 13 | - bases/rds.services.k8s.aws_dbsubnetgroups.yaml 14 | - bases/rds.services.k8s.aws_globalclusters.yaml 15 | -------------------------------------------------------------------------------- /helm/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | name: rds-chart 3 | description: A Helm chart for the ACK service controller for Amazon Relational Database Service (RDS) 4 | version: 1.7.0 5 | appVersion: 1.7.0 6 | home: https://github.com/aws-controllers-k8s/rds-controller 7 | icon: https://raw.githubusercontent.com/aws/eks-charts/master/docs/logo/aws.png 8 | sources: 9 | - https://github.com/aws-controllers-k8s/rds-controller 10 | maintainers: 11 | - name: ACK Admins 12 | url: https://github.com/orgs/aws-controllers-k8s/teams/ack-admin 13 | - name: RDS Admins 14 | url: https://github.com/orgs/aws-controllers-k8s/teams/rds-maintainer 15 | keywords: 16 | - aws 17 | - kubernetes 18 | - rds 19 | -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_aurora_postgres_log_exports.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBCluster 3 | metadata: 4 | name: $DB_CLUSTER_ID 5 | spec: 6 | autoMinorVersionUpgrade: false 7 | copyTagsToSnapshot: false 8 | dbClusterIdentifier: $DB_CLUSTER_ID 9 | enableIAMDatabaseAuthentication: false 10 | engine: aurora-postgresql 11 | enableCloudwatchLogsExports: 12 | - postgresql 13 | engineMode: provisioned 14 | engineVersion: "14.15" 15 | masterUsername: root 16 | masterUserPassword: 17 | namespace: $MASTER_USER_PASS_SECRET_NAMESPACE 18 | name: $MASTER_USER_PASS_SECRET_NAME 19 | key: $MASTER_USER_PASS_SECRET_KEY 20 | port: 5432 21 | storageEncrypted: true 22 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster_parameter_group/sdk_read_many_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if ko.Status.ACKResourceMetadata != nil && ko.Status.ACKResourceMetadata.ARN != nil { 2 | resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN) 3 | tags, err := rm.getTags(ctx, *resourceARN) 4 | if err != nil { 5 | return nil, err 6 | } 7 | ko.Spec.Tags = tags 8 | } 9 | if ko.Spec.Name != nil { 10 | groupName := ko.Spec.Name 11 | params, paramStatuses, err := rm.getParameters(ctx, groupName) 12 | if err != nil { 13 | return nil, err 14 | } 15 | ko.Spec.ParameterOverrides = params 16 | ko.Status.ParameterOverrideStatuses = paramStatuses 17 | } 18 | -------------------------------------------------------------------------------- /test/e2e/resources/db_instance_postgres14_t3_micro.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBInstance 3 | metadata: 4 | name: $DB_INSTANCE_ID 5 | spec: 6 | allocatedStorage: 5 7 | # Disable automated backups since it adds time to the provisioning 8 | # workflow... 9 | backupRetentionPeriod: 0 10 | copyTagsToSnapshot: $COPY_TAGS_TO_SNAPSHOT 11 | dbInstanceClass: db.t3.micro 12 | dbInstanceIdentifier: $DB_INSTANCE_ID 13 | engine: postgres 14 | engineVersion: "14.15" 15 | masterUsername: root 16 | masterUserPassword: 17 | namespace: $MASTER_USER_PASS_SECRET_NAMESPACE 18 | name: $MASTER_USER_PASS_SECRET_NAME 19 | key: $MASTER_USER_PASS_SECRET_KEY 20 | multiAZ: false 21 | tags: 22 | - key: environment 23 | value: dev 24 | -------------------------------------------------------------------------------- /helm/templates/service-account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 7 | app.kubernetes.io/instance: {{ .Release.Name }} 8 | app.kubernetes.io/managed-by: Helm 9 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 10 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 11 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 12 | name: {{ include "ack-rds-controller.service-account.name" . }} 13 | namespace: {{ .Release.Namespace }} 14 | annotations: 15 | {{- range $key, $value := .Values.serviceAccount.annotations }} 16 | {{ $key }}: {{ $value | quote }} 17 | {{- end }} 18 | {{- end }} 19 | -------------------------------------------------------------------------------- /test/e2e/resources/db_cluster_aurora_postgres_clone.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rds.services.k8s.aws/v1alpha1 2 | kind: DBCluster 3 | metadata: 4 | name: $DB_CLUSTER_ID 5 | spec: 6 | autoMinorVersionUpgrade: false 7 | copyTagsToSnapshot: false 8 | dbClusterIdentifier: $DB_CLUSTER_ID 9 | enableIAMDatabaseAuthentication: false 10 | engine: aurora-postgresql 11 | engineMode: provisioned 12 | engineVersion: "14.15" 13 | masterUsername: root 14 | masterUserPassword: 15 | namespace: $MASTER_USER_PASS_SECRET_NAMESPACE 16 | name: $MASTER_USER_PASS_SECRET_NAME 17 | key: $MASTER_USER_PASS_SECRET_KEY 18 | sourceDBClusterIdentifier: $SOURCE_DB_CLUSTER_ID 19 | restoreType: $RESTORE_TYPE 20 | useLatestRestorableTime: $USE_LATEST_RESTORABLE_TIME 21 | port: 5432 22 | storageEncrypted: true 23 | -------------------------------------------------------------------------------- /pkg/version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package version 17 | 18 | var ( 19 | GitVersion string 20 | GitCommit string 21 | BuildDate string 22 | ) 23 | -------------------------------------------------------------------------------- /helm/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | {{ .Chart.Name }} has been installed. 2 | This chart deploys "public.ecr.aws/aws-controllers-k8s/rds-controller:1.7.0". 3 | 4 | Check its status by running: 5 | kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/instance={{ .Release.Name }}" 6 | 7 | You are now able to create Amazon Relational Database Service (RDS) resources! 8 | 9 | The controller is running in "{{ .Values.installScope }}" mode. 10 | The controller is configured to manage AWS resources in region: "{{ .Values.aws.region }}" 11 | 12 | Visit https://aws-controllers-k8s.github.io/community/reference/ for an API 13 | reference of all the resources that can be created using this controller. 14 | 15 | For more information on the AWS Controllers for Kubernetes (ACK) project, visit: 16 | https://aws-controllers-k8s.github.io/community/ 17 | -------------------------------------------------------------------------------- /config/rbac/role-writer.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | creationTimestamp: null 6 | name: ack-rds-writer 7 | namespace: default 8 | rules: 9 | - apiGroups: 10 | - rds.services.k8s.aws 11 | resources: 12 | - dbclusters 13 | - dbclusterendpoints 14 | - dbclusterparametergroups 15 | - dbclustersnapshots 16 | - dbinstances 17 | - dbparametergroups 18 | - dbproxies 19 | - dbsnapshots 20 | - dbsubnetgroups 21 | - globalclusters 22 | verbs: 23 | - create 24 | - delete 25 | - get 26 | - list 27 | - patch 28 | - update 29 | - watch 30 | - apiGroups: 31 | - rds.services.k8s.aws 32 | resources: 33 | - dbclusters 34 | - dbclusterendpoints 35 | - dbclusterparametergroups 36 | - dbclustersnapshots 37 | - dbinstances 38 | - dbparametergroups 39 | - dbproxies 40 | - dbsnapshots 41 | - dbsubnetgroups 42 | - globalclusters 43 | verbs: 44 | - get 45 | - patch 46 | - update 47 | -------------------------------------------------------------------------------- /helm/templates/role-reader.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | creationTimestamp: null 6 | name: {{ include "ack-rds-controller.app.fullname" . }}-reader 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 10 | app.kubernetes.io/instance: {{ .Release.Name }} 11 | app.kubernetes.io/managed-by: Helm 12 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 13 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 14 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 15 | rules: 16 | - apiGroups: 17 | - rds.services.k8s.aws 18 | resources: 19 | - dbclusters 20 | - dbclusterendpoints 21 | - dbclusterparametergroups 22 | - dbclustersnapshots 23 | - dbinstances 24 | - dbparametergroups 25 | - dbproxies 26 | - dbsnapshots 27 | - dbsubnetgroups 28 | - globalclusters 29 | verbs: 30 | - get 31 | - list 32 | - watch 33 | -------------------------------------------------------------------------------- /templates/hooks/db_proxy/sdk_update_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | if proxyDeleting(latest) { 2 | msg := "DB proxy is currently being deleted" 3 | ackcondition.SetSynced(desired, corev1.ConditionFalse, &msg, nil) 4 | return desired, requeueWaitWhileDeleting 5 | } 6 | if proxyCreating(latest) { 7 | msg := "DB proxy is currently being created" 8 | ackcondition.SetSynced(desired, corev1.ConditionFalse, &msg, nil) 9 | return desired, requeueWaitUntilCanModify(latest) 10 | } 11 | if proxyHasTerminalStatus(latest) { 12 | msg := "DB proxy is in '"+*latest.ko.Status.Status+"' status" 13 | ackcondition.SetTerminal(desired, corev1.ConditionTrue, &msg, nil) 14 | ackcondition.SetSynced(desired, corev1.ConditionTrue, nil, nil) 15 | return desired, nil 16 | } 17 | if !proxyAvailable(latest) { 18 | msg := "DB proxy cannot be modifed while in '" + *latest.ko.Status.Status + "' status" 19 | ackcondition.SetSynced(desired, corev1.ConditionFalse, &msg, nil) 20 | return desired, requeueWaitUntilCanModify(latest) 21 | } -------------------------------------------------------------------------------- /test/e2e/tag.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | """Utilities for working with tags 15 | TODO: use tags.clean from test-infra after updating the bootstrap 16 | method for rds tests 17 | """ 18 | 19 | ACK_SYSTEM_TAG_PREFIX = "services.k8s.aws/" 20 | 21 | 22 | def clean(tags): 23 | """Returns supplied tags collection, stripped of ACK system tags. 24 | """ 25 | return [ 26 | t for t in tags if not t['Key'].startswith(ACK_SYSTEM_TAG_PREFIX) 27 | ] -------------------------------------------------------------------------------- /test/e2e/replacement_values.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | """Stores the values used by each of the integration tests for replacing the 14 | RDS-specific test variables. 15 | """ 16 | from e2e.bootstrap_resources import get_bootstrap_resources 17 | 18 | REPLACEMENT_VALUES = { 19 | "PUBLIC_SUBNET_1": get_bootstrap_resources().ClusterVPC.public_subnets.subnet_ids[0], 20 | "PUBLIC_SUBNET_2": get_bootstrap_resources().ClusterVPC.public_subnets.subnet_ids[1] 21 | } 22 | -------------------------------------------------------------------------------- /test/e2e/service_cleanup.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | """Cleans up the resources created by the bootstrapping process. 15 | """ 16 | 17 | import logging 18 | 19 | from acktest.bootstrapping import Resources 20 | 21 | from e2e import bootstrap_directory 22 | 23 | def service_cleanup(): 24 | logging.getLogger().setLevel(logging.INFO) 25 | 26 | resources = Resources.deserialize(bootstrap_directory) 27 | resources.cleanup() 28 | 29 | if __name__ == "__main__": 30 | service_cleanup() 31 | -------------------------------------------------------------------------------- /helm/templates/leader-election-role.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.leaderElection.enabled }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: {{ include "ack-rds-controller.app.fullname" . }}-leaderelection 6 | {{ if .Values.leaderElection.namespace }} 7 | namespace: {{ .Values.leaderElection.namespace }} 8 | {{ else }} 9 | namespace: {{ .Release.Namespace }} 10 | {{ end }} 11 | labels: 12 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 13 | app.kubernetes.io/instance: {{ .Release.Name }} 14 | app.kubernetes.io/managed-by: Helm 15 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 16 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 17 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 18 | rules: 19 | - apiGroups: 20 | - coordination.k8s.io 21 | resources: 22 | - leases 23 | verbs: 24 | - get 25 | - list 26 | - watch 27 | - create 28 | - update 29 | - patch 30 | - delete 31 | - apiGroups: 32 | - "" 33 | resources: 34 | - events 35 | verbs: 36 | - create 37 | - patch{{- end }} 38 | -------------------------------------------------------------------------------- /helm/templates/leader-election-role-binding.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.leaderElection.enabled }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | name: {{ include "ack-rds-controller.app.fullname" . }}-leaderelection 6 | {{ if .Values.leaderElection.namespace }} 7 | namespace: {{ .Values.leaderElection.namespace }} 8 | {{ else }} 9 | namespace: {{ .Release.Namespace }} 10 | {{ end }} 11 | labels: 12 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 13 | app.kubernetes.io/instance: {{ .Release.Name }} 14 | app.kubernetes.io/managed-by: Helm 15 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 16 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 17 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 18 | roleRef: 19 | apiGroup: rbac.authorization.k8s.io 20 | kind: Role 21 | name: {{ include "ack-rds-controller.app.fullname" . }}-leaderelection 22 | subjects: 23 | - kind: ServiceAccount 24 | name: {{ include "ack-rds-controller.service-account.name" . }} 25 | namespace: {{ .Release.Namespace }}{{- end }} 26 | -------------------------------------------------------------------------------- /helm/templates/metrics-service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.metrics.service.create }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ .Chart.Name | trimSuffix "-chart" | trunc 44 }}-controller-metrics 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 9 | app.kubernetes.io/instance: {{ .Release.Name }} 10 | app.kubernetes.io/managed-by: Helm 11 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 12 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 13 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 14 | spec: 15 | selector: 16 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 17 | app.kubernetes.io/instance: {{ .Release.Name }} 18 | app.kubernetes.io/managed-by: Helm 19 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 20 | {{- range $key, $value := .Values.deployment.labels }} 21 | {{ $key }}: {{ $value | quote }} 22 | {{- end }} 23 | type: {{ .Values.metrics.service.type }} 24 | ports: 25 | - name: metricsport 26 | port: 8080 27 | targetPort: http 28 | protocol: TCP 29 | {{- end }} 30 | -------------------------------------------------------------------------------- /apis/v1alpha1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package v1alpha1 17 | 18 | import ( 19 | "k8s.io/apimachinery/pkg/runtime/schema" 20 | "sigs.k8s.io/controller-runtime/pkg/scheme" 21 | ) 22 | 23 | var ( 24 | // GroupVersion is the API Group Version used to register the objects 25 | GroupVersion = schema.GroupVersion{Group: "rds.services.k8s.aws", Version: "v1alpha1"} 26 | 27 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 28 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 29 | 30 | // AddToScheme adds the types in this group-version to the given scheme. 31 | AddToScheme = SchemeBuilder.AddToScheme 32 | ) 33 | -------------------------------------------------------------------------------- /templates/hooks/db_instance/sdk_update_pre_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | res := desired.ko.DeepCopy() 2 | res.Status = latest.ko.Status 3 | 4 | if instanceDeleting(latest) { 5 | msg := "DB instance is currently being deleted" 6 | ackcondition.SetSynced(&resource{res}, corev1.ConditionFalse, &msg, nil) 7 | return &resource{res}, requeueWaitWhileDeleting 8 | } 9 | if instanceCreating(latest) { 10 | msg := "DB instance is currently being created" 11 | ackcondition.SetSynced(&resource{res}, corev1.ConditionFalse, &msg, nil) 12 | return &resource{res}, requeueWaitUntilCanModify(latest) 13 | } 14 | if instanceHasTerminalStatus(latest) { 15 | msg := "DB instance is in '"+*latest.ko.Status.DBInstanceStatus+"' status" 16 | ackcondition.SetTerminal(&resource{res}, corev1.ConditionTrue, &msg, nil) 17 | ackcondition.SetSynced(&resource{res}, corev1.ConditionTrue, nil, nil) 18 | return &resource{res}, nil 19 | } 20 | if !instanceAvailable(latest) && !needStorageUpdate(latest, delta) { 21 | msg := "DB instance cannot be modifed while in '" + *latest.ko.Status.DBInstanceStatus + "' status" 22 | ackcondition.SetSynced(&resource{res}, corev1.ConditionFalse, &msg, nil) 23 | return &resource{res}, requeueWaitUntilCanModify(latest) 24 | } 25 | if delta.DifferentAt("Spec.Tags") { 26 | if err = rm.syncTags(ctx, desired, latest); err != nil { 27 | return nil, err 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/e2e/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | import pytest 15 | from typing import Dict, Any 16 | from pathlib import Path 17 | 18 | from acktest.resources import load_resource_file 19 | 20 | SERVICE_NAME = "rds" 21 | CRD_GROUP = "rds.services.k8s.aws" 22 | CRD_VERSION = "v1alpha1" 23 | 24 | # PyTest marker for the current service 25 | service_marker = pytest.mark.service(arg=SERVICE_NAME) 26 | 27 | bootstrap_directory = Path(__file__).parent 28 | resource_directory = Path(__file__).parent / "resources" 29 | def load_rds_resource(resource_name: str, additional_replacements: Dict[str, Any] = {}): 30 | """ Overrides the default `load_resource_file` to access the specific resources 31 | directory for the current service. 32 | """ 33 | return load_resource_file(resource_directory, resource_name, additional_replacements=additional_replacements) -------------------------------------------------------------------------------- /helm/templates/role-writer.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | creationTimestamp: null 6 | name: {{ include "ack-rds-controller.app.fullname" . }}-writer 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 10 | app.kubernetes.io/instance: {{ .Release.Name }} 11 | app.kubernetes.io/managed-by: Helm 12 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 13 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 14 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 15 | rules: 16 | - apiGroups: 17 | - rds.services.k8s.aws 18 | resources: 19 | - dbclusters 20 | - dbclusterendpoints 21 | - dbclusterparametergroups 22 | - dbclustersnapshots 23 | - dbinstances 24 | - dbparametergroups 25 | - dbproxies 26 | - dbsnapshots 27 | - dbsubnetgroups 28 | - globalclusters 29 | verbs: 30 | - create 31 | - delete 32 | - get 33 | - list 34 | - patch 35 | - update 36 | - watch 37 | - apiGroups: 38 | - rds.services.k8s.aws 39 | resources: 40 | - dbclusters 41 | - dbclusterendpoints 42 | - dbclusterparametergroups 43 | - dbclustersnapshots 44 | - dbinstances 45 | - dbparametergroups 46 | - dbproxies 47 | - dbsnapshots 48 | - dbsubnetgroups 49 | - globalclusters 50 | verbs: 51 | - get 52 | - patch 53 | - update 54 | -------------------------------------------------------------------------------- /helm/templates/caches-role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: {{ include "ack-rds-controller.app.fullname" . }}-namespaces-cache 5 | labels: 6 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 7 | app.kubernetes.io/instance: {{ .Release.Name }} 8 | app.kubernetes.io/managed-by: Helm 9 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 10 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 11 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 12 | rules: 13 | - apiGroups: 14 | - "" 15 | resources: 16 | - namespaces 17 | verbs: 18 | - get 19 | - list 20 | - watch 21 | --- 22 | apiVersion: rbac.authorization.k8s.io/v1 23 | kind: Role 24 | metadata: 25 | name: {{ include "ack-rds-controller.app.fullname" . }}-configmaps-cache 26 | namespace: {{ .Release.Namespace }} 27 | labels: 28 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 29 | app.kubernetes.io/instance: {{ .Release.Name }} 30 | app.kubernetes.io/managed-by: Helm 31 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 32 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 33 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 34 | rules: 35 | - apiGroups: 36 | - "" 37 | resources: 38 | - configmaps 39 | verbs: 40 | - get 41 | - list 42 | - watch -------------------------------------------------------------------------------- /templates/hooks/db_instance/sdk_file_end.go.tpl: -------------------------------------------------------------------------------- 1 | {{ $CRD := .CRD }} 2 | {{ $SDKAPI := .SDKAPI }} 3 | 4 | {{/* Maintain operations here */}} 5 | {{ range $operationName := Each "RestoreDBInstanceFromDBSnapshot" "CreateDBInstanceReadReplica" }} 6 | 7 | {{- $operation := (index $SDKAPI.API.Operations $operationName)}} 8 | 9 | {{- $inputRef := $operation.InputRef }} 10 | {{- $inputShapeName := $inputRef.ShapeName }} 11 | 12 | {{- $outputRef := $operation.OutputRef }} 13 | {{- $outputShapeName := $outputRef.ShapeName }} 14 | 15 | 16 | {{/* Some operations have custom structure */}} 17 | {{- if (eq $operationName "RestoreDBInstanceFromDBSnapshot") }} 18 | 19 | // new{{ $inputShapeName }} returns a {{ $inputShapeName }} object 20 | // with each the field set by the corresponding configuration's fields. 21 | func (rm *resourceManager) new{{ $inputShapeName }}( 22 | r *resource, 23 | ) (*svcsdk.{{ $inputShapeName }}, error) { 24 | res := &svcsdk.{{ $inputShapeName }}{} 25 | 26 | {{ GoCodeSetSDKForStruct $CRD "" "res" $inputRef "" "r.ko.Spec" 1 }} 27 | return res, nil 28 | } 29 | {{ end }} 30 | 31 | // setResourceFrom{{ $outputShapeName }} sets a resource {{ $outputShapeName }} type 32 | // given the SDK type. 33 | func (rm *resourceManager) setResourceFrom{{ $outputShapeName }}( 34 | r *resource, 35 | resp *svcsdk.{{ $outputShapeName }}, 36 | ) { 37 | {{ GoCodeSetCreateOutput $CRD "resp" "r.ko" 1 }} 38 | } 39 | 40 | {{- end }} 41 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster/sdk_file_end.go.tpl: -------------------------------------------------------------------------------- 1 | {{ $CRD := .CRD }} 2 | {{ $SDKAPI := .SDKAPI }} 3 | 4 | {{/* Maintain operations here */}} 5 | {{ range $operationName := Each "RestoreDBClusterFromSnapshot" "RestoreDBClusterToPointInTime" }} 6 | 7 | {{- $operation := (index $SDKAPI.API.Operations $operationName)}} 8 | 9 | {{- $inputRef := $operation.InputRef }} 10 | {{- $inputShapeName := $inputRef.ShapeName }} 11 | 12 | {{- $outputRef := $operation.OutputRef }} 13 | {{- $outputShapeName := $outputRef.ShapeName }} 14 | 15 | 16 | {{/* Some operations have custom structure */}} 17 | {{- if (eq $operationName "RestoreDBClusterFromSnapshot" "RestoreDBClusterToPointInTime") }} 18 | 19 | // new{{ $inputShapeName }} returns a {{ $inputShapeName }} object 20 | // with each the field set by the corresponding configuration's fields. 21 | func (rm *resourceManager) new{{ $inputShapeName }}( 22 | r *resource, 23 | ) (*svcsdk.{{ $inputShapeName }}, error) { 24 | res := &svcsdk.{{ $inputShapeName }}{} 25 | 26 | {{ GoCodeSetSDKForStruct $CRD "" "res" $inputRef "" "r.ko.Spec" 1 }} 27 | return res, nil 28 | } 29 | {{ end }} 30 | 31 | // setResourceFrom{{ $outputShapeName }} sets a resource {{ $outputShapeName }} type 32 | // given the SDK type. 33 | func (rm *resourceManager) setResourceFrom{{ $outputShapeName }}( 34 | r *resource, 35 | resp *svcsdk.{{ $outputShapeName }}, 36 | ) { 37 | {{ GoCodeSetCreateOutput $CRD "resp" "r.ko" 1 }} 38 | } 39 | 40 | {{- end }} 41 | -------------------------------------------------------------------------------- /test/e2e/bootstrap_resources.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | """Declares the structure of the bootstrapped resources and provides a loader 15 | for them. 16 | """ 17 | 18 | from dataclasses import dataclass 19 | from acktest.bootstrapping.vpc import VPC 20 | from acktest.bootstrapping.iam import Role 21 | from acktest.bootstrapping import Resources 22 | from e2e import bootstrap_directory 23 | 24 | 25 | @dataclass 26 | class BootstrapResources(Resources): 27 | ClusterVPC: VPC 28 | RDSProxyRole: Role 29 | 30 | _bootstrap_resources = None 31 | 32 | 33 | def get_bootstrap_resources(bootstrap_file_name: str = "bootstrap.pkl") -> BootstrapResources: 34 | global _bootstrap_resources 35 | if _bootstrap_resources is None: 36 | _bootstrap_resources = BootstrapResources.deserialize(bootstrap_directory, bootstrap_file_name=bootstrap_file_name) 37 | return _bootstrap_resources 38 | -------------------------------------------------------------------------------- /templates/hooks/db_instance/delta_pre_compare.go.tpl: -------------------------------------------------------------------------------- 1 | // Do not consider any of the following fields for delta if they are missing in 2 | // desired(a) but are present in latest(b) because each of these fields is 3 | // late-initialized 4 | // This special handling is only needed for DBInstance because late 5 | // initialized values are not returned after successful ModifyDBInstance 6 | // call. They are only populated once the DBInstance returns back to 7 | // available. 8 | if a.ko.Spec.AvailabilityZone == nil && 9 | b.ko.Spec.AvailabilityZone != nil { 10 | a.ko.Spec.AvailabilityZone = b.ko.Spec.AvailabilityZone 11 | } 12 | if a.ko.Spec.BackupTarget == nil && 13 | b.ko.Spec.BackupTarget != nil && 14 | *b.ko.Spec.BackupTarget == ServiceDefaultBackupTarget { 15 | a.ko.Spec.BackupTarget = b.ko.Spec.BackupTarget 16 | } 17 | if a.ko.Spec.NetworkType == nil && 18 | b.ko.Spec.NetworkType != nil && 19 | *b.ko.Spec.NetworkType == ServiceDefaultNetworkType { 20 | a.ko.Spec.NetworkType = b.ko.Spec.NetworkType 21 | } 22 | if a.ko.Spec.PerformanceInsightsEnabled == nil && 23 | b.ko.Spec.PerformanceInsightsEnabled != nil { 24 | a.ko.Spec.PerformanceInsightsEnabled = func() *bool {a := false; return &a }() 25 | } 26 | 27 | // RDS will choose preferred engine minor version if only 28 | // engine major version is provided and controler should not 29 | // treat them as different, such as spec has 14, status has 14.1 30 | // controller should treat them as same 31 | reconcileEngineVersion(a, b) 32 | compareTags(delta, a, b) 33 | compareSecretReferenceChanges(delta, a, b) 34 | -------------------------------------------------------------------------------- /test/e2e/service_bootstrap.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | """Bootstraps the resources required to run the RDS integration tests. 14 | """ 15 | 16 | import logging 17 | 18 | from e2e import bootstrap_directory 19 | from acktest.bootstrapping import Resources, BootstrapFailureException 20 | from acktest.bootstrapping.vpc import VPC 21 | from acktest.bootstrapping.iam import Role 22 | from e2e.bootstrap_resources import BootstrapResources 23 | 24 | 25 | def service_bootstrap() -> Resources: 26 | logging.getLogger().setLevel(logging.INFO) 27 | 28 | resources = BootstrapResources( 29 | ClusterVPC=VPC(name_prefix="cluster-vpc", num_public_subnet=2, num_private_subnet=2), 30 | RDSProxyRole=Role("rds-proxy-role", "rds.amazonaws.com", managed_policies=["arn:aws:iam::aws:policy/SecretsManagerReadWrite"]) 31 | ) 32 | 33 | try: 34 | resources.bootstrap() 35 | except BootstrapFailureException as ex: 36 | exit(254) 37 | 38 | return resources 39 | 40 | if __name__ == "__main__": 41 | config = service_bootstrap() 42 | # Write config to current directory by default 43 | config.serialize(bootstrap_directory) 44 | -------------------------------------------------------------------------------- /helm/templates/cluster-role-controller.yaml: -------------------------------------------------------------------------------- 1 | {{ $labels := .Values.role.labels }} 2 | {{ $appVersion := .Chart.AppVersion | quote }} 3 | {{ $rbacRules := include "ack-rds-controller.rbac-rules" . }} 4 | {{ $fullname := include "ack-rds-controller.app.fullname" . }} 5 | {{ $chartVersion := include "ack-rds-controller.chart.name-version" . }} 6 | {{ if eq .Values.installScope "cluster" }} 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRole 9 | metadata: 10 | name: {{ include "ack-rds-controller.app.fullname" . }} 11 | labels: 12 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 13 | app.kubernetes.io/instance: {{ .Release.Name }} 14 | app.kubernetes.io/managed-by: Helm 15 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 16 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 17 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 18 | {{- range $key, $value := $labels }} 19 | {{ $key }}: {{ $value | quote }} 20 | {{- end }} 21 | {{$rbacRules }} 22 | {{ else if eq .Values.installScope "namespace" }} 23 | {{ $wn := include "ack-rds-controller.watch-namespace" . }} 24 | {{ $namespaces := split "," $wn }} 25 | {{ range $namespaces }} 26 | --- 27 | apiVersion: rbac.authorization.k8s.io/v1 28 | kind: Role 29 | metadata: 30 | name: {{ $fullname }}-{{ . }} 31 | namespace: {{ . }} 32 | labels: 33 | app.kubernetes.io/name: {{ $fullname }} 34 | app.kubernetes.io/instance: {{ $.Release.Name }} 35 | app.kubernetes.io/managed-by: Helm 36 | app.kubernetes.io/version: {{ $appVersion }} 37 | k8s-app: {{ $fullname }} 38 | helm.sh/chart: {{ $chartVersion }} 39 | {{- range $key, $value := $labels }} 40 | {{ $key }}: {{ $value | quote }} 41 | {{- end }} 42 | {{ $rbacRules }} 43 | {{ end }} 44 | {{ end }} -------------------------------------------------------------------------------- /helm/templates/caches-role-binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: {{ include "ack-rds-controller.app.fullname" . }}-namespaces-cache 5 | labels: 6 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 7 | app.kubernetes.io/instance: {{ .Release.Name }} 8 | app.kubernetes.io/managed-by: Helm 9 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 10 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 11 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 12 | roleRef: 13 | kind: ClusterRole 14 | apiGroup: rbac.authorization.k8s.io 15 | name: {{ include "ack-rds-controller.app.fullname" . }}-namespaces-cache 16 | subjects: 17 | - kind: ServiceAccount 18 | name: {{ include "ack-rds-controller.service-account.name" . }} 19 | namespace: {{ .Release.Namespace }} 20 | --- 21 | apiVersion: rbac.authorization.k8s.io/v1 22 | kind: RoleBinding 23 | metadata: 24 | name: {{ include "ack-rds-controller.app.fullname" . }}-configmaps-cache 25 | namespace: {{ .Release.Namespace }} 26 | labels: 27 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 28 | app.kubernetes.io/instance: {{ .Release.Name }} 29 | app.kubernetes.io/managed-by: Helm 30 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 31 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 32 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 33 | roleRef: 34 | kind: Role 35 | apiGroup: rbac.authorization.k8s.io 36 | name: {{ include "ack-rds-controller.app.fullname" . }}-configmaps-cache 37 | subjects: 38 | - kind: ServiceAccount 39 | name: {{ include "ack-rds-controller.service-account.name" . }} 40 | namespace: {{ .Release.Namespace }} 41 | -------------------------------------------------------------------------------- /test/e2e/fixtures.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | """Fixtures common to all RDS controller tests""" 15 | 16 | import dataclasses 17 | 18 | from acktest.k8s import resource as k8s 19 | import boto3 20 | import pytest 21 | 22 | 23 | @pytest.fixture(scope="module") 24 | def rds_client(): 25 | return boto3.client('rds') 26 | 27 | 28 | @dataclasses.dataclass 29 | class SecretKeyReference: 30 | ns: str 31 | name: str 32 | key: str 33 | val: str 34 | 35 | 36 | @pytest.fixture(scope="module") 37 | def k8s_secret(): 38 | """Manages the lifecycle of a Kubernetes Secret for use in tests. 39 | 40 | Usage: 41 | from e2e.fixtures import k8s_secret 42 | 43 | class TestThing: 44 | def test_thing(self, k8s_secret): 45 | secret = k8s_secret( 46 | "default", "mysecret", "mykey", "myval", 47 | ) 48 | """ 49 | created = [] 50 | def _k8s_secret(ns, name, key, val): 51 | k8s.create_opaque_secret(ns, name, key, val) 52 | secret_ref = SecretKeyReference(ns, name, key, val) 53 | created.append(secret_ref) 54 | return secret_ref 55 | 56 | yield _k8s_secret 57 | 58 | for secret_ref in created: 59 | k8s.delete_secret(secret_ref.ns, secret_ref.name) 60 | -------------------------------------------------------------------------------- /templates/hooks/db_instance/sdk_update_post_build_request.go.tpl: -------------------------------------------------------------------------------- 1 | // ModifyDBInstance call will return ValidationError when the 2 | // ModifyDBInstanceRequest contains the same DBSubnetGroupName 3 | // as the DBInstance. So, if there is no delta between 4 | // desired and latest for Spec.DBSubnetGroupName, exclude it 5 | // from ModifyDBInstanceRequest 6 | if !delta.DifferentAt("Spec.DBSubnetGroupName") { 7 | input.DBSubnetGroupName = nil 8 | } 9 | 10 | // RDS will not compare diff value and accept any modify db call 11 | // for below values, MonitoringInterval, CACertificateIdentifier 12 | // and user master password, NetworkType 13 | // hence if there is no delta between desired 14 | // and latest, exclude it from ModifyDBInstanceRequest 15 | if !delta.DifferentAt("Spec.MonitoringInterval") { 16 | input.MonitoringInterval = nil 17 | } 18 | if !delta.DifferentAt("Spec.CACertificateIdentifier") { 19 | input.CACertificateIdentifier = nil 20 | } 21 | if !delta.DifferentAt("Spec.MasterUserPassword") { 22 | input.MasterUserPassword = nil 23 | } 24 | if !delta.DifferentAt("Spec.NetworkType") { 25 | input.NetworkType = nil 26 | } 27 | 28 | // For dbInstance inside dbCluster, it's either aurora or 29 | // multi-az cluster case, in either case, the below params 30 | // are not controlled in instance level. 31 | // hence when DBClusterIdentifier appear, set them to nil 32 | // Please refer to doc : https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DeleteDBInstance.html 33 | if desired.ko.Spec.DBClusterIdentifier != nil { 34 | input.AllocatedStorage = nil 35 | input.BackupRetentionPeriod = nil 36 | input.PreferredBackupWindow = nil 37 | input.DeletionProtection = nil 38 | } 39 | -------------------------------------------------------------------------------- /pkg/resource/db_proxy/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_proxy 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/resource/db_instance/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_instance 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/resource/db_snapshot/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_snapshot 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/resource/global_cluster/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package global_cluster 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/resource/db_subnet_group/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_subnet_group 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster_endpoint/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster_endpoint 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster_snapshot/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster_snapshot 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/resource/db_parameter_group/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_parameter_group 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /test/e2e/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | import os 15 | import pytest 16 | import boto3 17 | 18 | from acktest import k8s 19 | 20 | 21 | def pytest_addoption(parser): 22 | parser.addoption("--runslow", action="store_true", default=False, help="run slow tests") 23 | 24 | 25 | def pytest_configure(config): 26 | config.addinivalue_line( 27 | "markers", "canary: mark test to also run in canary tests" 28 | ) 29 | config.addinivalue_line( 30 | "markers", "service(arg): mark test associated with a given service" 31 | ) 32 | config.addinivalue_line( 33 | "markers", "slow: mark test as slow to run" 34 | ) 35 | 36 | def pytest_collection_modifyitems(config, items): 37 | if config.getoption("--runslow"): 38 | return 39 | skip_slow = pytest.mark.skip(reason="need --runslow option to run") 40 | for item in items: 41 | if "slow" in item.keywords: 42 | item.add_marker(skip_slow) 43 | 44 | # Provide a k8s client to interact with the integration test cluster 45 | @pytest.fixture(scope='class') 46 | def k8s_client(): 47 | return k8s._get_k8s_api_client() 48 | 49 | @pytest.fixture(scope='module') 50 | def rds_client(): 51 | return boto3.client('rds') 52 | 53 | @pytest.fixture(scope='module') 54 | def rds_resource(): 55 | return boto3.resource('rds') 56 | 57 | @pytest.fixture(scope='module') 58 | def sts_client(): 59 | return boto3.client('sts') -------------------------------------------------------------------------------- /olm/olmconfig.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | annotations: 3 | capabilityLevel: Basic Install 4 | shortDescription: AWS RDS controller is a service controller for managing RDS resources 5 | in Kubernetes 6 | displayName: AWS Controllers for Kubernetes - Amazon RDS 7 | description: |- 8 | Manage Amazon Relational Database Service ("RDS") resources in AWS from within your Kubernetes cluster. 9 | 10 | 11 | **About Amazon RDS** 12 | 13 | 14 | Amazon Relational Database Service (Amazon RDS) makes it easy to set up, 15 | operate, and scale a relational database in the cloud. It provides 16 | cost-efficient and resizable capacity while automating time-consuming 17 | administration tasks such as hardware provisioning, database setup, patching 18 | and backups. It frees you to focus on your applications so you can give them 19 | the fast performance, high availability, security and compatibility they need. 20 | 21 | 22 | Amazon RDS is available on several database instance types - optimized for 23 | memory, performance or I/O -and provides you with six familiar database 24 | engines to choose from, including Amazon Aurora, PostgreSQL, MySQL, MariaDB, 25 | Oracle Database, and SQL Server. You can use the AWS Database Migration 26 | Service to easily migrate or replicate your existing databases to Amazon RDS. 27 | 28 | 29 | **About the AWS Controllers for Kubernetes** 30 | 31 | 32 | This controller is a component of the [AWS Controller for Kubernetes](https://github.com/aws/aws-controllers-k8s) 33 | project. 34 | 35 | 36 | **Pre-Installation Steps** 37 | 38 | 39 | Please follow the following link: [Red Hat OpenShift](https://aws-controllers-k8s.github.io/community/docs/user-docs/openshift/) 40 | samples: 41 | - kind: DBParameterGroup 42 | spec: '{}' 43 | - kind: DBSubnetGroup 44 | spec: '{}' 45 | maintainers: 46 | - name: "rds maintainer team" 47 | email: "ack-maintainers@amazon.com" 48 | links: 49 | - name: Amazon RDS Developer Resources 50 | url: https://aws.amazon.com/rds/developer-resources/ 51 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster_parameter_group/identifiers.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster_parameter_group 17 | 18 | import ( 19 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 20 | ) 21 | 22 | // resourceIdentifiers implements the 23 | // `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface 24 | type resourceIdentifiers struct { 25 | meta *ackv1alpha1.ResourceMetadata 26 | } 27 | 28 | // ARN returns the AWS Resource Name for the backend AWS resource. If nil, 29 | // this means the resource has not yet been created in the backend AWS 30 | // service. 31 | func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { 32 | if ri.meta != nil { 33 | return ri.meta.ARN 34 | } 35 | return nil 36 | } 37 | 38 | // OwnerAccountID returns the AWS account identifier in which the 39 | // backend AWS resource resides, or nil if this information is not known 40 | // for the resource 41 | func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { 42 | if ri.meta != nil { 43 | return ri.meta.OwnerAccountID 44 | } 45 | return nil 46 | } 47 | 48 | // Region returns the AWS region in which the resource exists, or 49 | // nil if this information is not known. 50 | func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { 51 | if ri.meta != nil { 52 | return ri.meta.Region 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /test/e2e/db_cluster_endpoint.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | """Utilities for working with DB cluster endpoint resources""" 15 | 16 | import time 17 | from typing import Dict, Optional, List 18 | 19 | import boto3 20 | import pytest 21 | 22 | def get_client(): 23 | return boto3.client('rds') 24 | 25 | def get(db_cluster_endpoint_identifier: str) -> Optional[Dict]: 26 | c = get_client() 27 | try: 28 | resp = c.describe_db_cluster_endpoints( 29 | DBClusterEndpointIdentifier=db_cluster_endpoint_identifier, 30 | ) 31 | if len(resp['DBClusterEndpoints']) == 0: 32 | return None 33 | return resp['DBClusterEndpoints'][0] 34 | except c.exceptions.DBClusterEndpointNotFoundFault: 35 | return None 36 | 37 | def get_tags(endpoint_arn: str) -> List[Dict]: 38 | c = get_client() 39 | try: 40 | resp = c.list_tags_for_resource( 41 | ResourceName=endpoint_arn, 42 | ) 43 | return resp['TagList'] 44 | except c.exceptions.DBClusterEndpointNotFoundFault: 45 | return [] 46 | 47 | def wait_until_deleted(db_cluster_endpoint_identifier: str, max_attempts: int = 60) -> None: 48 | attempt = 0 49 | while attempt < max_attempts: 50 | if get(db_cluster_endpoint_identifier) is None: 51 | return 52 | attempt += 1 53 | time.sleep(10) 54 | pytest.fail( 55 | "Timed out waiting for DB snapshot to be " 56 | "deleted in RDS API" 57 | ) -------------------------------------------------------------------------------- /GOVERNANCE.md: -------------------------------------------------------------------------------- 1 | # Project governance 2 | 3 | This document lays out the guidelines under which the AWS Controllers for Kubernetes (ACK) project will be governed. 4 | The goal is to make sure that the roles and responsibilities are well defined and clarify on how decisions are made. 5 | 6 | ## Roles 7 | 8 | In the context of ACK, we consider the following roles: 9 | 10 | * __Users__ ... everyone using ACK, typically willing to provide feedback on ACK by proposing features and/or filing issues. 11 | * __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). 12 | * __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. 13 | * __Advisory Board__ ... is responsible for defining the guidelines and processes that the project operates under. 14 | 15 | The initial members of the Advisory Board are `@jaypipes` and `@mhausenblas`. 16 | 17 | 18 | ## Communication 19 | 20 | The primary mechanism for communication will be via the `#provider-aws` channel on the Kubernetes Slack community. 21 | All features and bug fixes will be tracked as issues in GitHub. All decisions will be documented in GitHub issues. 22 | 23 | In the future, we may consider using a public mailing list, which can be better archived. 24 | 25 | ## Roadmap Planning 26 | 27 | Maintainers will share roadmap and release versions as milestones in GitHub. 28 | 29 | ## Release Management 30 | 31 | The Advisory Board will propose a release management proposal via a GitHub issue and resolve it there. 32 | 33 | ## Other relevant governance resources 34 | 35 | * The ACK [Contributing Guidelines](CONTRIBUTING.md) 36 | * Our [Code of Conduct](CODE_OF_CONDUCT.md) 37 | -------------------------------------------------------------------------------- /pkg/resource/registry.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package resource 17 | 18 | import ( 19 | ackrt "github.com/aws-controllers-k8s/runtime/pkg/runtime" 20 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 21 | ) 22 | 23 | // +kubebuilder:rbac:groups=services.k8s.aws,resources=iamroleselectors,verbs=get;list;watch;create;update;patch;delete 24 | // +kubebuilder:rbac:groups=services.k8s.aws,resources=iamroleselectors/status,verbs=get;update;patch 25 | // +kubebuilder:rbac:groups=services.k8s.aws,resources=fieldexports,verbs=get;list;watch;create;update;patch;delete 26 | // +kubebuilder:rbac:groups=services.k8s.aws,resources=fieldexports/status,verbs=get;update;patch 27 | // +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch 28 | // +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;patch 29 | // +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;patch 30 | 31 | var ( 32 | reg = ackrt.NewRegistry() 33 | ) 34 | 35 | // GetManagerFactories returns a slice of resource manager factories that are 36 | // registered with this package 37 | func GetManagerFactories() []acktypes.AWSResourceManagerFactory { 38 | return reg.GetResourceManagerFactories() 39 | } 40 | 41 | // RegisterManagerFactory registers a resource manager factory with the 42 | // package's registry 43 | func RegisterManagerFactory(f acktypes.AWSResourceManagerFactory) { 44 | reg.RegisterResourceManagerFactory(f) 45 | } 46 | -------------------------------------------------------------------------------- /templates/hooks/db_cluster/sdk_read_many_post_set_output.go.tpl: -------------------------------------------------------------------------------- 1 | if ko.Status.ACKResourceMetadata != nil && ko.Status.ACKResourceMetadata.ARN != nil { 2 | resourceARN := (*string)(ko.Status.ACKResourceMetadata.ARN) 3 | tags, err := rm.getTags(ctx, *resourceARN) 4 | if err != nil { 5 | return nil, err 6 | } 7 | ko.Spec.Tags = tags 8 | } 9 | if !clusterAvailable(&resource{ko}) { 10 | // Setting resource synced condition to false will trigger a requeue of 11 | // the resource. No need to return a requeue error here. 12 | ackcondition.SetSynced(&resource{ko}, corev1.ConditionFalse, nil, nil) 13 | } else { 14 | ackcondition.SetSynced(&resource{ko}, corev1.ConditionTrue, nil, nil) 15 | } 16 | if len(r.ko.Spec.VPCSecurityGroupIDs) > 0 { 17 | // If the desired resource has security groups specified then update the spec of the latest resource with the 18 | // value from the status. This is done so that when a cluster is created without security groups and gets a 19 | // default security group attached to it, it is not overwritten with empty security groups from the 20 | // desired resource. 21 | sgIDs := make([]*string, len(ko.Status.VPCSecurityGroups)) 22 | for i, sg := range ko.Status.VPCSecurityGroups { 23 | id := *sg.VPCSecurityGroupID 24 | sgIDs[i] = &id 25 | } 26 | ko.Spec.VPCSecurityGroupIDs = sgIDs 27 | } 28 | if r.ko.Spec.DBClusterParameterGroupName != nil { 29 | // If the desired resource has db cluster parameter group name specified then update the spec of the latest 30 | // resource with the value from the status. 31 | ko.Spec.DBClusterParameterGroupName = ko.Status.DBClusterParameterGroup 32 | } 33 | 34 | if r.ko.Spec.EnableIAMDatabaseAuthentication != nil { 35 | // If the desired resource has IAM authentication explicitly enabled or disabled then update the spec of the 36 | // latest resource with the value from the status. 37 | ko.Spec.EnableIAMDatabaseAuthentication = ko.Status.IAMDatabaseAuthenticationEnabled 38 | } 39 | 40 | ko.Spec.EnableCloudwatchLogsExports = ko.Status.EnabledCloudwatchLogsExports 41 | -------------------------------------------------------------------------------- /config/rbac/cluster-role-controller.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: ack-rds-controller 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | - secrets 12 | verbs: 13 | - get 14 | - list 15 | - patch 16 | - watch 17 | - apiGroups: 18 | - "" 19 | resources: 20 | - namespaces 21 | verbs: 22 | - get 23 | - list 24 | - watch 25 | - apiGroups: 26 | - ec2.services.k8s.aws 27 | resources: 28 | - securitygroups 29 | - securitygroups/status 30 | - subnets 31 | - subnets/status 32 | verbs: 33 | - get 34 | - list 35 | - apiGroups: 36 | - kms.services.k8s.aws 37 | resources: 38 | - keys 39 | - keys/status 40 | verbs: 41 | - get 42 | - list 43 | - apiGroups: 44 | - rds.services.k8s.aws 45 | resources: 46 | - dbclusterendpoints 47 | - dbclusterparametergroups 48 | - dbclusters 49 | - dbclustersnapshots 50 | - dbinstances 51 | - dbparametergroups 52 | - dbproxies 53 | - dbsnapshots 54 | - dbsubnetgroups 55 | - globalclusters 56 | verbs: 57 | - create 58 | - delete 59 | - get 60 | - list 61 | - patch 62 | - update 63 | - watch 64 | - apiGroups: 65 | - rds.services.k8s.aws 66 | resources: 67 | - dbclusterendpoints/status 68 | - dbclusterparametergroups/status 69 | - dbclusters/status 70 | - dbclustersnapshots/status 71 | - dbinstances/status 72 | - dbparametergroups/status 73 | - dbproxies/status 74 | - dbsnapshots/status 75 | - dbsubnetgroups/status 76 | - globalclusters/status 77 | verbs: 78 | - get 79 | - patch 80 | - update 81 | - apiGroups: 82 | - services.k8s.aws 83 | resources: 84 | - fieldexports 85 | - iamroleselectors 86 | verbs: 87 | - create 88 | - delete 89 | - get 90 | - list 91 | - patch 92 | - update 93 | - watch 94 | - apiGroups: 95 | - services.k8s.aws 96 | resources: 97 | - fieldexports/status 98 | - iamroleselectors/status 99 | verbs: 100 | - get 101 | - patch 102 | - update 103 | -------------------------------------------------------------------------------- /helm/templates/cluster-role-binding.yaml: -------------------------------------------------------------------------------- 1 | {{ if eq .Values.installScope "cluster" }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: {{ include "ack-rds-controller.app.fullname" . }}-rolebinding 6 | labels: 7 | app.kubernetes.io/name: {{ include "ack-rds-controller.app.name" . }} 8 | app.kubernetes.io/instance: {{ .Release.Name }} 9 | app.kubernetes.io/managed-by: Helm 10 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 11 | k8s-app: {{ include "ack-rds-controller.app.name" . }} 12 | helm.sh/chart: {{ include "ack-rds-controller.chart.name-version" . }} 13 | roleRef: 14 | kind: ClusterRole 15 | apiGroup: rbac.authorization.k8s.io 16 | name: {{ include "ack-rds-controller.app.fullname" . }} 17 | subjects: 18 | - kind: ServiceAccount 19 | name: {{ include "ack-rds-controller.service-account.name" . }} 20 | namespace: {{ .Release.Namespace }} 21 | {{ else if eq .Values.installScope "namespace" }} 22 | {{ $wn := include "ack-rds-controller.watch-namespace" . }} 23 | {{ $namespaces := split "," $wn }} 24 | {{ $fullname := include "ack-rds-controller.app.fullname" . }} 25 | {{ $releaseNamespace := .Release.Namespace }} 26 | {{ $serviceAccountName := include "ack-rds-controller.service-account.name" . }} 27 | {{ $chartVersion := include "ack-rds-controller.chart.name-version" . }} 28 | {{ $appVersion := .Chart.AppVersion | quote }} 29 | {{ range $namespaces }} 30 | --- 31 | apiVersion: rbac.authorization.k8s.io/v1 32 | kind: RoleBinding 33 | metadata: 34 | name: {{ $fullname }}-{{ . }} 35 | namespace: {{ . }} 36 | labels: 37 | app.kubernetes.io/name: {{ $fullname }} 38 | app.kubernetes.io/instance: {{ $.Release.Name }} 39 | app.kubernetes.io/managed-by: Helm 40 | app.kubernetes.io/version: {{ $appVersion }} 41 | k8s-app: {{ $fullname }} 42 | helm.sh/chart: {{ $chartVersion }} 43 | roleRef: 44 | kind: Role 45 | apiGroup: rbac.authorization.k8s.io 46 | name: {{ $fullname }}-{{ . }} 47 | subjects: 48 | - kind: ServiceAccount 49 | name: {{ $serviceAccountName }} 50 | namespace: {{ $releaseNamespace }} 51 | {{ end }} 52 | {{ end }} -------------------------------------------------------------------------------- /pkg/resource/db_proxy/references.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_proxy 17 | 18 | import ( 19 | "context" 20 | 21 | "sigs.k8s.io/controller-runtime/pkg/client" 22 | 23 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 24 | 25 | svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1" 26 | ) 27 | 28 | // ClearResolvedReferences removes any reference values that were made 29 | // concrete in the spec. It returns a copy of the input AWSResource which 30 | // contains the original *Ref values, but none of their respective concrete 31 | // values. 32 | func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) acktypes.AWSResource { 33 | ko := rm.concreteResource(res).ko.DeepCopy() 34 | 35 | return &resource{ko} 36 | } 37 | 38 | // ResolveReferences finds if there are any Reference field(s) present 39 | // inside AWSResource passed in the parameter and attempts to resolve those 40 | // reference field(s) into their respective target field(s). It returns a 41 | // copy of the input AWSResource with resolved reference(s), a boolean which 42 | // is set to true if the resource contains any references (regardless of if 43 | // they are resolved successfully) and an error if the passed AWSResource's 44 | // reference field(s) could not be resolved. 45 | func (rm *resourceManager) ResolveReferences( 46 | ctx context.Context, 47 | apiReader client.Reader, 48 | res acktypes.AWSResource, 49 | ) (acktypes.AWSResource, bool, error) { 50 | return res, false, nil 51 | } 52 | 53 | // validateReferenceFields validates the reference field and corresponding 54 | // identifier field. 55 | func validateReferenceFields(ko *svcapitypes.DBProxy) error { 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /pkg/resource/global_cluster/references.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package global_cluster 17 | 18 | import ( 19 | "context" 20 | 21 | "sigs.k8s.io/controller-runtime/pkg/client" 22 | 23 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 24 | 25 | svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1" 26 | ) 27 | 28 | // ClearResolvedReferences removes any reference values that were made 29 | // concrete in the spec. It returns a copy of the input AWSResource which 30 | // contains the original *Ref values, but none of their respective concrete 31 | // values. 32 | func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) acktypes.AWSResource { 33 | ko := rm.concreteResource(res).ko.DeepCopy() 34 | 35 | return &resource{ko} 36 | } 37 | 38 | // ResolveReferences finds if there are any Reference field(s) present 39 | // inside AWSResource passed in the parameter and attempts to resolve those 40 | // reference field(s) into their respective target field(s). It returns a 41 | // copy of the input AWSResource with resolved reference(s), a boolean which 42 | // is set to true if the resource contains any references (regardless of if 43 | // they are resolved successfully) and an error if the passed AWSResource's 44 | // reference field(s) could not be resolved. 45 | func (rm *resourceManager) ResolveReferences( 46 | ctx context.Context, 47 | apiReader client.Reader, 48 | res acktypes.AWSResource, 49 | ) (acktypes.AWSResource, bool, error) { 50 | return res, false, nil 51 | } 52 | 53 | // validateReferenceFields validates the reference field and corresponding 54 | // identifier field. 55 | func validateReferenceFields(ko *svcapitypes.GlobalCluster) error { 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /pkg/resource/db_parameter_group/references.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_parameter_group 17 | 18 | import ( 19 | "context" 20 | 21 | "sigs.k8s.io/controller-runtime/pkg/client" 22 | 23 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 24 | 25 | svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1" 26 | ) 27 | 28 | // ClearResolvedReferences removes any reference values that were made 29 | // concrete in the spec. It returns a copy of the input AWSResource which 30 | // contains the original *Ref values, but none of their respective concrete 31 | // values. 32 | func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) acktypes.AWSResource { 33 | ko := rm.concreteResource(res).ko.DeepCopy() 34 | 35 | return &resource{ko} 36 | } 37 | 38 | // ResolveReferences finds if there are any Reference field(s) present 39 | // inside AWSResource passed in the parameter and attempts to resolve those 40 | // reference field(s) into their respective target field(s). It returns a 41 | // copy of the input AWSResource with resolved reference(s), a boolean which 42 | // is set to true if the resource contains any references (regardless of if 43 | // they are resolved successfully) and an error if the passed AWSResource's 44 | // reference field(s) could not be resolved. 45 | func (rm *resourceManager) ResolveReferences( 46 | ctx context.Context, 47 | apiReader client.Reader, 48 | res acktypes.AWSResource, 49 | ) (acktypes.AWSResource, bool, error) { 50 | return res, false, nil 51 | } 52 | 53 | // validateReferenceFields validates the reference field and corresponding 54 | // identifier field. 55 | func validateReferenceFields(ko *svcapitypes.DBParameterGroup) error { 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster_parameter_group/references.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster_parameter_group 17 | 18 | import ( 19 | "context" 20 | 21 | "sigs.k8s.io/controller-runtime/pkg/client" 22 | 23 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 24 | 25 | svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1" 26 | ) 27 | 28 | // ClearResolvedReferences removes any reference values that were made 29 | // concrete in the spec. It returns a copy of the input AWSResource which 30 | // contains the original *Ref values, but none of their respective concrete 31 | // values. 32 | func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) acktypes.AWSResource { 33 | ko := rm.concreteResource(res).ko.DeepCopy() 34 | 35 | return &resource{ko} 36 | } 37 | 38 | // ResolveReferences finds if there are any Reference field(s) present 39 | // inside AWSResource passed in the parameter and attempts to resolve those 40 | // reference field(s) into their respective target field(s). It returns a 41 | // copy of the input AWSResource with resolved reference(s), a boolean which 42 | // is set to true if the resource contains any references (regardless of if 43 | // they are resolved successfully) and an error if the passed AWSResource's 44 | // reference field(s) could not be resolved. 45 | func (rm *resourceManager) ResolveReferences( 46 | ctx context.Context, 47 | apiReader client.Reader, 48 | res acktypes.AWSResource, 49 | ) (acktypes.AWSResource, bool, error) { 50 | return res, false, nil 51 | } 52 | 53 | // validateReferenceFields validates the reference field and corresponding 54 | // identifier field. 55 | func validateReferenceFields(ko *svcapitypes.DBClusterParameterGroup) error { 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /pkg/util/tags.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | package util 15 | 16 | import ( 17 | ackutil "github.com/aws-controllers-k8s/runtime/pkg/util" 18 | 19 | svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1" 20 | ) 21 | 22 | // TODO(a-hilaly) most of the utility in this package should ideally go to 23 | // ack runtime or pkg repository. 24 | 25 | // computeTagsDelta compares two Tag arrays and return two different list 26 | // containing the addedOrupdated and removed tags. The removed tags array 27 | // only contains the tags Keys. 28 | func ComputeTagsDelta( 29 | a []*svcapitypes.Tag, 30 | b []*svcapitypes.Tag, 31 | ) (addedOrUpdated []*svcapitypes.Tag, removed []string) { 32 | var visitedIndexes []string 33 | mainLoop: 34 | for _, aElement := range b { 35 | visitedIndexes = append(visitedIndexes, *aElement.Key) 36 | for _, bElement := range a { 37 | if equalStrings(aElement.Key, bElement.Key) { 38 | if !equalStrings(aElement.Value, bElement.Value) { 39 | addedOrUpdated = append(addedOrUpdated, bElement) 40 | } 41 | continue mainLoop 42 | } 43 | } 44 | removed = append(removed, *aElement.Key) 45 | } 46 | for _, bElement := range a { 47 | if !ackutil.InStrings(*bElement.Key, visitedIndexes) { 48 | addedOrUpdated = append(addedOrUpdated, bElement) 49 | } 50 | } 51 | return addedOrUpdated, removed 52 | } 53 | 54 | // equalTags returns true if two Tag arrays are equal regardless of the order 55 | // of their elements. 56 | func EqualTags( 57 | a []*svcapitypes.Tag, 58 | b []*svcapitypes.Tag, 59 | ) bool { 60 | addedOrUpdated, removed := ComputeTagsDelta(a, b) 61 | return len(addedOrUpdated) == 0 && len(removed) == 0 62 | } 63 | 64 | func equalStrings(a, b *string) bool { 65 | if a == nil { 66 | return b == nil || *b == "" 67 | } 68 | return (*a == "" && b == nil) || *a == *b 69 | } 70 | -------------------------------------------------------------------------------- /pkg/util/annotations.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "strconv" 5 | 6 | svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1" 7 | ) 8 | 9 | type DeleteInputAnnotationParameters struct { 10 | SkipFinalSnapshot *bool 11 | FinalDBSnapshotIdentifier *string 12 | DeleteAutomatedBackup *bool 13 | } 14 | 15 | var ( 16 | // If not specified skipFinalSnapshot will be set to true by default. 17 | // 18 | // Kept for historical purpuse: This was the value that we set in the generator.yaml 19 | // before writing this annotation parsing functions. 20 | // 21 | // DeleteDBCluster: 22 | // override_values: 23 | // # Clearly this is not ideal, but will suffice until we add custom hook 24 | // # points to the build_request methods to enable a genmeration of the 25 | // # final snapshot identifier to use. 26 | // SkipFinalSnapshot: true 27 | defaultSkipFinalSnapshot = true 28 | ) 29 | 30 | // parseDeletionAnnotations parses the deletion annotations on the supplied 31 | // resource. 32 | func ParseDeletionAnnotations(annotations map[string]string) (*DeleteInputAnnotationParameters, error) { 33 | params := &DeleteInputAnnotationParameters{ 34 | SkipFinalSnapshot: &defaultSkipFinalSnapshot, 35 | } 36 | if len(annotations) == 0 { 37 | return params, nil 38 | } 39 | 40 | // Parse SkipFinalSnapshot annotation 41 | skipFinalSnapshotAnnotationValue, ok := annotations[svcapitypes.SkipFinalSnapshotAnnotation] 42 | if ok && skipFinalSnapshotAnnotationValue != "" { 43 | skipFinalSnapshot, err := strconv.ParseBool(skipFinalSnapshotAnnotationValue) 44 | if err != nil { 45 | return nil, err 46 | } 47 | params.SkipFinalSnapshot = &skipFinalSnapshot 48 | } 49 | 50 | // Parse FinalDBSnapshotIdentifier annotation 51 | finalDBSnapshotIdentifierAnnotationValue, ok := annotations[svcapitypes.FinalDBSnapshotIdentifierAnnotation] 52 | if ok { 53 | params.FinalDBSnapshotIdentifier = &finalDBSnapshotIdentifierAnnotationValue 54 | } 55 | 56 | // Parse DeleteAutomatedBackup annotation 57 | deleteAutomatedBackupAnnotationValue, ok := annotations[svcapitypes.DeleteAutomatedBackupsAnnotation] 58 | if ok && deleteAutomatedBackupAnnotationValue != "" { 59 | deleteAutomatedBackup, err := strconv.ParseBool(deleteAutomatedBackupAnnotationValue) 60 | if err != nil { 61 | return nil, err 62 | } 63 | params.DeleteAutomatedBackup = &deleteAutomatedBackup 64 | } 65 | return params, nil 66 | } 67 | -------------------------------------------------------------------------------- /pkg/resource/db_subnet_group/delta.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_subnet_group 17 | 18 | import ( 19 | "bytes" 20 | "reflect" 21 | 22 | ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" 23 | acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" 24 | ) 25 | 26 | // Hack to avoid import errors during build... 27 | var ( 28 | _ = &bytes.Buffer{} 29 | _ = &reflect.Method{} 30 | _ = &acktags.Tags{} 31 | ) 32 | 33 | // newResourceDelta returns a new `ackcompare.Delta` used to compare two 34 | // resources 35 | func newResourceDelta( 36 | a *resource, 37 | b *resource, 38 | ) *ackcompare.Delta { 39 | delta := ackcompare.NewDelta() 40 | if (a == nil && b != nil) || 41 | (a != nil && b == nil) { 42 | delta.Add("", a, b) 43 | return delta 44 | } 45 | compareTags(delta, a, b) 46 | 47 | if ackcompare.HasNilDifference(a.ko.Spec.Description, b.ko.Spec.Description) { 48 | delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) 49 | } else if a.ko.Spec.Description != nil && b.ko.Spec.Description != nil { 50 | if *a.ko.Spec.Description != *b.ko.Spec.Description { 51 | delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) 52 | } 53 | } 54 | if ackcompare.HasNilDifference(a.ko.Spec.Name, b.ko.Spec.Name) { 55 | delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) 56 | } else if a.ko.Spec.Name != nil && b.ko.Spec.Name != nil { 57 | if *a.ko.Spec.Name != *b.ko.Spec.Name { 58 | delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) 59 | } 60 | } 61 | if len(a.ko.Spec.SubnetIDs) != len(b.ko.Spec.SubnetIDs) { 62 | delta.Add("Spec.SubnetIDs", a.ko.Spec.SubnetIDs, b.ko.Spec.SubnetIDs) 63 | } else if len(a.ko.Spec.SubnetIDs) > 0 { 64 | if !ackcompare.SliceStringPEqual(a.ko.Spec.SubnetIDs, b.ko.Spec.SubnetIDs) { 65 | delta.Add("Spec.SubnetIDs", a.ko.Spec.SubnetIDs, b.ko.Spec.SubnetIDs) 66 | } 67 | } 68 | if !reflect.DeepEqual(a.ko.Spec.SubnetRefs, b.ko.Spec.SubnetRefs) { 69 | delta.Add("Spec.SubnetRefs", a.ko.Spec.SubnetRefs, b.ko.Spec.SubnetRefs) 70 | } 71 | 72 | return delta 73 | } 74 | -------------------------------------------------------------------------------- /pkg/util/annotations_test.go: -------------------------------------------------------------------------------- 1 | package util_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1" 8 | "github.com/aws-controllers-k8s/rds-controller/pkg/util" 9 | "github.com/aws/aws-sdk-go/aws" 10 | ) 11 | 12 | func TestParseDeletionAnnotations(t *testing.T) { 13 | tests := []struct { 14 | name string 15 | annotations map[string]string 16 | want *util.DeleteInputAnnotationParameters 17 | wantErr bool 18 | }{ 19 | { 20 | name: "no annotations", 21 | annotations: map[string]string{}, 22 | want: &util.DeleteInputAnnotationParameters{ 23 | SkipFinalSnapshot: aws.Bool(true), 24 | FinalDBSnapshotIdentifier: nil, 25 | DeleteAutomatedBackup: nil, 26 | }, 27 | wantErr: false, 28 | }, 29 | { 30 | name: "all annotations set - turn on all snapshot options", 31 | annotations: map[string]string{ 32 | svcapitypes.SkipFinalSnapshotAnnotation: "false", 33 | svcapitypes.FinalDBSnapshotIdentifierAnnotation: "final-snapshot", 34 | svcapitypes.DeleteAutomatedBackupsAnnotation: "false", 35 | }, 36 | want: &util.DeleteInputAnnotationParameters{ 37 | SkipFinalSnapshot: aws.Bool(false), 38 | FinalDBSnapshotIdentifier: aws.String("final-snapshot"), 39 | DeleteAutomatedBackup: aws.Bool(false), 40 | }, 41 | wantErr: false, 42 | }, 43 | { 44 | name: "all annotations set - turn off all snapshot options", 45 | annotations: map[string]string{ 46 | svcapitypes.SkipFinalSnapshotAnnotation: "true", 47 | svcapitypes.DeleteAutomatedBackupsAnnotation: "true", 48 | }, 49 | want: &util.DeleteInputAnnotationParameters{ 50 | SkipFinalSnapshot: aws.Bool(true), 51 | FinalDBSnapshotIdentifier: nil, 52 | DeleteAutomatedBackup: aws.Bool(true), 53 | }, 54 | wantErr: false, 55 | }, 56 | { 57 | name: "invalid SkipFinalSnapshot annotation", 58 | annotations: map[string]string{ 59 | svcapitypes.SkipFinalSnapshotAnnotation: "invalid", 60 | }, 61 | want: nil, 62 | wantErr: true, 63 | }, 64 | { 65 | name: "invalid DeleteAutomatedBackups annotation", 66 | annotations: map[string]string{ 67 | svcapitypes.DeleteAutomatedBackupsAnnotation: "invalid", 68 | }, 69 | want: nil, 70 | wantErr: true, 71 | }, 72 | } 73 | 74 | for _, tt := range tests { 75 | t.Run(tt.name, func(t *testing.T) { 76 | got, err := util.ParseDeletionAnnotations(tt.annotations) 77 | if (err != nil) != tt.wantErr { 78 | t.Errorf("ParseDeletionAnnotations() error = %v, wantErr %v", err, tt.wantErr) 79 | return 80 | } 81 | if !reflect.DeepEqual(got, tt.want) { 82 | t.Errorf("ParseDeletionAnnotations() = %v, want %v", got, tt.want) 83 | } 84 | }) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /apis/v1alpha1/annotation.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | package v1alpha1 15 | 16 | import "fmt" 17 | 18 | var ( 19 | // LastAppliedConfigMapAnnotation is the annotation key used to store the namespaced name 20 | // of the last used secret for setting the master user password of a DBInstance or DBCluster. 21 | // 22 | // The secret namespaced name stored in this annotation is used to compute the "reference" delta 23 | // when the user updates the DBInstance or DBCluster resource. 24 | // 25 | // This annotation is only applied by the rds-controller, and should not be modified by the user. 26 | // In case the user modifies this annotation, the rds-controller may not be able to correctly 27 | // compute the "reference" delta, and can result in the rds-controller making unnecessary password 28 | // updates to the DBInstance or DBCluster. 29 | LastAppliedSecretAnnotation = fmt.Sprintf("%s/last-applied-secret-reference", GroupVersion.Group) 30 | // SkipFinalSnapshot is the annotation key used to skip the final snapshot when deleting a DBInstance 31 | // or DBCluster. If this annotation is set to "true", the final snapshot will be skipped. The default 32 | // value is "true" - meaning that when the annotation is not present, the final snapshot will be skipped. 33 | SkipFinalSnapshotAnnotation = fmt.Sprintf("%s/skip-final-snapshot", GroupVersion.Group) 34 | // FinalDBSnapshotIdentifier is the annotation key used to specify the final snapshot identifier when 35 | // deleting a DBInstance or DBCluster. If this annotation is set, the final snapshot will be created with 36 | // the specified identifier. 37 | // 38 | // If the SkipFinalSnapshot annotation is set to "true", this annotation will be ignored. 39 | FinalDBSnapshotIdentifierAnnotation = fmt.Sprintf("%s/final-db-snapshot-identifier", GroupVersion.Group) 40 | // DeleteAutomatedBackups is the annotation key used to specify whether automated backups should be 41 | // deleted when deleting a DBInstance or DBCluster. If this annotation is set to "true", automated backups 42 | // will be deleted. The default value is "false" - meaning that when the annotation is not present, automated 43 | // backups will not be deleted. 44 | DeleteAutomatedBackupsAnnotation = fmt.Sprintf("%s/delete-automated-backups", GroupVersion.Group) 45 | ) 46 | -------------------------------------------------------------------------------- /pkg/resource/db_snapshot/delta.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_snapshot 17 | 18 | import ( 19 | "bytes" 20 | "reflect" 21 | 22 | ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" 23 | acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" 24 | ) 25 | 26 | // Hack to avoid import errors during build... 27 | var ( 28 | _ = &bytes.Buffer{} 29 | _ = &reflect.Method{} 30 | _ = &acktags.Tags{} 31 | ) 32 | 33 | // newResourceDelta returns a new `ackcompare.Delta` used to compare two 34 | // resources 35 | func newResourceDelta( 36 | a *resource, 37 | b *resource, 38 | ) *ackcompare.Delta { 39 | delta := ackcompare.NewDelta() 40 | if (a == nil && b != nil) || 41 | (a != nil && b == nil) { 42 | delta.Add("", a, b) 43 | return delta 44 | } 45 | 46 | if ackcompare.HasNilDifference(a.ko.Spec.DBInstanceIdentifier, b.ko.Spec.DBInstanceIdentifier) { 47 | delta.Add("Spec.DBInstanceIdentifier", a.ko.Spec.DBInstanceIdentifier, b.ko.Spec.DBInstanceIdentifier) 48 | } else if a.ko.Spec.DBInstanceIdentifier != nil && b.ko.Spec.DBInstanceIdentifier != nil { 49 | if *a.ko.Spec.DBInstanceIdentifier != *b.ko.Spec.DBInstanceIdentifier { 50 | delta.Add("Spec.DBInstanceIdentifier", a.ko.Spec.DBInstanceIdentifier, b.ko.Spec.DBInstanceIdentifier) 51 | } 52 | } 53 | if !reflect.DeepEqual(a.ko.Spec.DBInstanceIdentifierRef, b.ko.Spec.DBInstanceIdentifierRef) { 54 | delta.Add("Spec.DBInstanceIdentifierRef", a.ko.Spec.DBInstanceIdentifierRef, b.ko.Spec.DBInstanceIdentifierRef) 55 | } 56 | if ackcompare.HasNilDifference(a.ko.Spec.DBSnapshotIdentifier, b.ko.Spec.DBSnapshotIdentifier) { 57 | delta.Add("Spec.DBSnapshotIdentifier", a.ko.Spec.DBSnapshotIdentifier, b.ko.Spec.DBSnapshotIdentifier) 58 | } else if a.ko.Spec.DBSnapshotIdentifier != nil && b.ko.Spec.DBSnapshotIdentifier != nil { 59 | if *a.ko.Spec.DBSnapshotIdentifier != *b.ko.Spec.DBSnapshotIdentifier { 60 | delta.Add("Spec.DBSnapshotIdentifier", a.ko.Spec.DBSnapshotIdentifier, b.ko.Spec.DBSnapshotIdentifier) 61 | } 62 | } 63 | desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tags) 64 | latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tags) 65 | if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) { 66 | delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags) 67 | } 68 | 69 | return delta 70 | } 71 | -------------------------------------------------------------------------------- /pkg/resource/db_parameter_group/delta.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_parameter_group 17 | 18 | import ( 19 | "bytes" 20 | "reflect" 21 | 22 | ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" 23 | acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" 24 | ) 25 | 26 | // Hack to avoid import errors during build... 27 | var ( 28 | _ = &bytes.Buffer{} 29 | _ = &reflect.Method{} 30 | _ = &acktags.Tags{} 31 | ) 32 | 33 | // newResourceDelta returns a new `ackcompare.Delta` used to compare two 34 | // resources 35 | func newResourceDelta( 36 | a *resource, 37 | b *resource, 38 | ) *ackcompare.Delta { 39 | delta := ackcompare.NewDelta() 40 | if (a == nil && b != nil) || 41 | (a != nil && b == nil) { 42 | delta.Add("", a, b) 43 | return delta 44 | } 45 | compareTags(delta, a, b) 46 | 47 | if ackcompare.HasNilDifference(a.ko.Spec.Description, b.ko.Spec.Description) { 48 | delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) 49 | } else if a.ko.Spec.Description != nil && b.ko.Spec.Description != nil { 50 | if *a.ko.Spec.Description != *b.ko.Spec.Description { 51 | delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) 52 | } 53 | } 54 | if ackcompare.HasNilDifference(a.ko.Spec.Family, b.ko.Spec.Family) { 55 | delta.Add("Spec.Family", a.ko.Spec.Family, b.ko.Spec.Family) 56 | } else if a.ko.Spec.Family != nil && b.ko.Spec.Family != nil { 57 | if *a.ko.Spec.Family != *b.ko.Spec.Family { 58 | delta.Add("Spec.Family", a.ko.Spec.Family, b.ko.Spec.Family) 59 | } 60 | } 61 | if ackcompare.HasNilDifference(a.ko.Spec.Name, b.ko.Spec.Name) { 62 | delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) 63 | } else if a.ko.Spec.Name != nil && b.ko.Spec.Name != nil { 64 | if *a.ko.Spec.Name != *b.ko.Spec.Name { 65 | delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) 66 | } 67 | } 68 | if len(a.ko.Spec.ParameterOverrides) != len(b.ko.Spec.ParameterOverrides) { 69 | delta.Add("Spec.ParameterOverrides", a.ko.Spec.ParameterOverrides, b.ko.Spec.ParameterOverrides) 70 | } else if len(a.ko.Spec.ParameterOverrides) > 0 { 71 | if !ackcompare.MapStringStringPEqual(a.ko.Spec.ParameterOverrides, b.ko.Spec.ParameterOverrides) { 72 | delta.Add("Spec.ParameterOverrides", a.ko.Spec.ParameterOverrides, b.ko.Spec.ParameterOverrides) 73 | } 74 | } 75 | 76 | return delta 77 | } 78 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster_snapshot/delta.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster_snapshot 17 | 18 | import ( 19 | "bytes" 20 | "reflect" 21 | 22 | ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" 23 | acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" 24 | ) 25 | 26 | // Hack to avoid import errors during build... 27 | var ( 28 | _ = &bytes.Buffer{} 29 | _ = &reflect.Method{} 30 | _ = &acktags.Tags{} 31 | ) 32 | 33 | // newResourceDelta returns a new `ackcompare.Delta` used to compare two 34 | // resources 35 | func newResourceDelta( 36 | a *resource, 37 | b *resource, 38 | ) *ackcompare.Delta { 39 | delta := ackcompare.NewDelta() 40 | if (a == nil && b != nil) || 41 | (a != nil && b == nil) { 42 | delta.Add("", a, b) 43 | return delta 44 | } 45 | 46 | if ackcompare.HasNilDifference(a.ko.Spec.DBClusterIdentifier, b.ko.Spec.DBClusterIdentifier) { 47 | delta.Add("Spec.DBClusterIdentifier", a.ko.Spec.DBClusterIdentifier, b.ko.Spec.DBClusterIdentifier) 48 | } else if a.ko.Spec.DBClusterIdentifier != nil && b.ko.Spec.DBClusterIdentifier != nil { 49 | if *a.ko.Spec.DBClusterIdentifier != *b.ko.Spec.DBClusterIdentifier { 50 | delta.Add("Spec.DBClusterIdentifier", a.ko.Spec.DBClusterIdentifier, b.ko.Spec.DBClusterIdentifier) 51 | } 52 | } 53 | if !reflect.DeepEqual(a.ko.Spec.DBClusterIdentifierRef, b.ko.Spec.DBClusterIdentifierRef) { 54 | delta.Add("Spec.DBClusterIdentifierRef", a.ko.Spec.DBClusterIdentifierRef, b.ko.Spec.DBClusterIdentifierRef) 55 | } 56 | if ackcompare.HasNilDifference(a.ko.Spec.DBClusterSnapshotIdentifier, b.ko.Spec.DBClusterSnapshotIdentifier) { 57 | delta.Add("Spec.DBClusterSnapshotIdentifier", a.ko.Spec.DBClusterSnapshotIdentifier, b.ko.Spec.DBClusterSnapshotIdentifier) 58 | } else if a.ko.Spec.DBClusterSnapshotIdentifier != nil && b.ko.Spec.DBClusterSnapshotIdentifier != nil { 59 | if *a.ko.Spec.DBClusterSnapshotIdentifier != *b.ko.Spec.DBClusterSnapshotIdentifier { 60 | delta.Add("Spec.DBClusterSnapshotIdentifier", a.ko.Spec.DBClusterSnapshotIdentifier, b.ko.Spec.DBClusterSnapshotIdentifier) 61 | } 62 | } 63 | desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tags) 64 | latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tags) 65 | if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) { 66 | delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags) 67 | } 68 | 69 | return delta 70 | } 71 | -------------------------------------------------------------------------------- /pkg/util/parameter_cache.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | package util 15 | 16 | import ( 17 | "context" 18 | "sync" 19 | ) 20 | 21 | // ParamMeta stores metadata about a parameter in a parameter group 22 | type ParamMeta struct { 23 | IsModifiable bool 24 | IsDynamic bool 25 | } 26 | 27 | // MetaFetcher is the functor we pass to the paramMetaCache that allows it to 28 | // fetch engine default parameter information 29 | type MetaFetcher func(ctx context.Context, family string) (map[string]ParamMeta, error) 30 | 31 | // ParamMetaCache stores information about a parameter for a DB parameter group 32 | // family. We use this cached information to determine whether a parameter is 33 | // statically or dynamically defined (whether changes can be applied 34 | // immediately or pending a reboot) and whether a parameter is modifiable. 35 | // 36 | // Keeping things super simple for now and not adding any TTL or expiration 37 | // behaviour to the cache. Engine defaults are pretty static information... 38 | type ParamMetaCache struct { 39 | sync.RWMutex 40 | Hits uint64 41 | Misses uint64 42 | Cache map[string]map[string]ParamMeta 43 | } 44 | 45 | // Get retrieves the metadata for a named parameter group family and parameter 46 | // name. 47 | func (c *ParamMetaCache) Get( 48 | ctx context.Context, 49 | family string, 50 | name string, 51 | fetcher MetaFetcher, 52 | ) (*ParamMeta, error) { 53 | var err error 54 | var found bool 55 | var metas map[string]ParamMeta 56 | var meta ParamMeta 57 | 58 | // We need to release the lock right after the read operation, because 59 | // loadFamily might call a writeLock below 60 | c.RLock() 61 | metas, found = c.Cache[family] 62 | c.RUnlock() 63 | 64 | if !found { 65 | c.Misses++ 66 | metas, err = c.loadFamily(ctx, family, fetcher) 67 | if err != nil { 68 | return nil, err 69 | } 70 | } 71 | meta, found = metas[name] 72 | if !found { 73 | return nil, NewErrUnknownParameter(name) 74 | } 75 | c.Hits++ 76 | return &meta, nil 77 | } 78 | 79 | // loadFamily fetches parameter information from the AWS RDS 80 | // DescribeEngineDefaultParameters API and caches that information. 81 | func (c *ParamMetaCache) loadFamily( 82 | ctx context.Context, 83 | family string, 84 | fetcher MetaFetcher, 85 | ) (map[string]ParamMeta, error) { 86 | familyMeta, err := fetcher(ctx, family) 87 | if err != nil { 88 | return nil, err 89 | } 90 | c.Lock() 91 | defer c.Unlock() 92 | c.Cache[family] = familyMeta 93 | return familyMeta, nil 94 | } 95 | -------------------------------------------------------------------------------- /test/e2e/db_subnet_group.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | """Utilities for working with DB subnet resources""" 15 | 16 | import datetime 17 | import time 18 | 19 | import boto3 20 | import pytest 21 | 22 | DEFAULT_WAIT_UNTIL_DELETED_TIMEOUT_SECONDS = 60*10 23 | DEFAULT_WAIT_UNTIL_DELETED_INTERVAL_SECONDS = 15 24 | 25 | 26 | def wait_until_deleted( 27 | db_subnet_group_name: str, 28 | timeout_seconds: int = DEFAULT_WAIT_UNTIL_DELETED_TIMEOUT_SECONDS, 29 | interval_seconds: int = DEFAULT_WAIT_UNTIL_DELETED_INTERVAL_SECONDS, 30 | ) -> None: 31 | """Waits until a DB subnet_group with a supplied ID is no longer returned from 32 | the RDS API. 33 | 34 | Usage: 35 | from e2e.db_subnet_group import wait_until_deleted 36 | 37 | wait_until_deleted(subnet_group_id) 38 | 39 | Raises: 40 | pytest.fail upon timeout or if the DB subnet_group goes to any other status 41 | other than 'deleting' 42 | """ 43 | now = datetime.datetime.now() 44 | timeout = now + datetime.timedelta(seconds=timeout_seconds) 45 | 46 | while True: 47 | if datetime.datetime.now() >= timeout: 48 | pytest.fail( 49 | "Timed out waiting for DB subnet_group to be " 50 | "deleted in RDS API" 51 | ) 52 | time.sleep(interval_seconds) 53 | 54 | latest = get(db_subnet_group_name) 55 | if latest is None: 56 | break 57 | 58 | if latest['DBSubnetGroupStatus'] != "deleting": 59 | pytest.fail( 60 | "Status is not 'deleting' for DB subnet_group that was " 61 | "deleted. Status is " + latest['DBSubnetGroupStatus'] 62 | ) 63 | 64 | 65 | def get(db_subnet_group_name): 66 | """Returns a dict containing the DB subnet_group record from the RDS API. 67 | 68 | If no such DB subnet_group exists, returns None. 69 | """ 70 | c = boto3.client('rds') 71 | try: 72 | resp = c.describe_db_subnet_groups( 73 | DBSubnetGroupName=db_subnet_group_name, 74 | ) 75 | assert len(resp['DBSubnetGroups']) == 1 76 | return resp['DBSubnetGroups'][0] 77 | except c.exceptions.DBSubnetGroupNotFoundFault: 78 | return None 79 | 80 | 81 | def get_tags(db_subnet_group_arn): 82 | """Returns a dict containing the DB subnet group's tag records from the RDS 83 | API. 84 | 85 | If no such DB subnet group exists, returns None. 86 | """ 87 | c = boto3.client('rds') 88 | try: 89 | resp = c.list_tags_for_resource( 90 | ResourceName=db_subnet_group_arn, 91 | ) 92 | return resp['TagList'] 93 | except c.exceptions.DBSubnetGroupNotFoundFault: 94 | return None 95 | -------------------------------------------------------------------------------- /pkg/util/parameters.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | package util 15 | 16 | import ( 17 | "fmt" 18 | 19 | ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" 20 | "github.com/samber/lo" 21 | ) 22 | 23 | var ( 24 | ErrUnknownParameter = fmt.Errorf("unknown parameter") 25 | ErrUnmodifiableParameter = fmt.Errorf("parameter is not modifiable") 26 | ) 27 | 28 | // Parameters represents the elements of a DB Parameter Group 29 | // or a DB Cluster Parameter Group 30 | type Parameters map[string]*string 31 | 32 | // NewErrUnknownParameter generates an ACK terminal error about 33 | // an unknown parameter 34 | func NewErrUnknownParameter(name string) error { 35 | // This is a terminal error because unless the user removes this parameter 36 | // from their list of parameter overrides, we will not be able to get the 37 | // resource into a synced state. 38 | return ackerr.NewTerminalError( 39 | fmt.Errorf("%w: %s", ErrUnknownParameter, name), 40 | ) 41 | } 42 | 43 | // NewErrUnmodifiableParameter generates an ACK terminal error about 44 | // a parameter that may not be modified 45 | func NewErrUnmodifiableParameter(name string) error { 46 | // This is a terminal error because unless the user removes this parameter 47 | // from their list of parameter overrides, we will not be able to get the 48 | // resource into a synced state. 49 | return ackerr.NewTerminalError( 50 | fmt.Errorf("%w: %s", ErrUnmodifiableParameter, name), 51 | ) 52 | } 53 | 54 | // GetParametersDifference compares two Parameters maps and returns the 55 | // parameters to add & update, the unchanged parameters, and 56 | // the parameters to remove 57 | func GetParametersDifference( 58 | to, from Parameters, 59 | ) (added, unchanged, removed Parameters) { 60 | // we need to convert the tag tuples to a comparable interface type 61 | fromPairs := lo.ToPairs(from) 62 | toPairs := lo.ToPairs(to) 63 | 64 | left, right := lo.Difference(fromPairs, toPairs) 65 | middle := lo.Intersect(fromPairs, toPairs) 66 | 67 | removed = lo.FromPairs(left) 68 | added = lo.FromPairs(right) 69 | unchanged = lo.FromPairs(middle) 70 | 71 | return added, unchanged, removed 72 | } 73 | 74 | // ChunkParameters splits a supplied map of parameters into multiple 75 | // slices of maps of parameters of a given size. 76 | func ChunkParameters( 77 | input Parameters, 78 | chunkSize int, 79 | ) []Parameters { 80 | var chunks []Parameters 81 | chunk := Parameters{} 82 | idx := 0 83 | for k, v := range input { 84 | if idx < chunkSize { 85 | chunk[k] = v 86 | idx++ 87 | } else { 88 | // reset the chunker 89 | chunks = append(chunks, chunk) 90 | chunk = Parameters{} 91 | idx = 0 92 | } 93 | } 94 | chunks = append(chunks, chunk) 95 | 96 | return chunks 97 | } 98 | -------------------------------------------------------------------------------- /test/e2e/tests/test_global_cluster.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | # not use this file except in compliance with the License. A copy of the 5 | # License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | """Integration tests for the RDS API Global Cluster resource 15 | """ 16 | 17 | import time 18 | 19 | import pytest 20 | 21 | from acktest.k8s import resource as k8s 22 | from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_rds_resource 23 | from e2e.replacement_values import REPLACEMENT_VALUES 24 | from e2e import condition 25 | from e2e import global_cluster 26 | from e2e.fixtures import k8s_secret 27 | from e2e import tag 28 | from e2e.bootstrap_resources import get_bootstrap_resources 29 | 30 | RESOURCE_PLURAL = 'globalclusters' 31 | 32 | DELETE_WAIT_AFTER_SECONDS = 120 33 | 34 | # Time we wait after resource becoming available in RDS and checking the CR's 35 | # Status has been updated. 36 | CHECK_STATUS_WAIT_SECONDS = 60*4 37 | 38 | MODIFY_WAIT_AFTER_SECONDS = 20 39 | 40 | 41 | @service_marker 42 | @pytest.mark.canary 43 | class TestGlobalCluster: 44 | 45 | def test_crud_postgresql_globalcluster( 46 | self, 47 | ): 48 | global_cluster_id = "my-test-global-cluster" 49 | global_cluster_engine = "aurora-postgresql" 50 | global_cluster_db_name = 'testdb' 51 | 52 | replacements = REPLACEMENT_VALUES.copy() 53 | replacements["GLOBAL_CLUSTER_NAME"] = global_cluster_id 54 | replacements["GLOBAL_CLUSTER_ENGINE"] = global_cluster_engine 55 | replacements["GLOBAL_CLUSTER_DB_NAME"] = global_cluster_db_name 56 | 57 | resource_data = load_rds_resource( 58 | "global_cluster", 59 | additional_replacements=replacements, 60 | ) 61 | 62 | ref = k8s.CustomResourceReference( 63 | CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, 64 | global_cluster_id, namespace="default", 65 | ) 66 | # First try create global cluster 67 | k8s.create_custom_resource(ref, resource_data) 68 | cr = k8s.wait_resource_consumed_by_controller(ref) 69 | 70 | # global cluster is available immediately upon created 71 | assert cr is not None 72 | assert 'status' in cr 73 | assert 'status' in cr['status'] 74 | assert cr['status']['status'] == 'available' 75 | 76 | # assert global cluster is synced 77 | cr = k8s.get_resource(ref) 78 | assert cr is not None 79 | assert 'status' in cr 80 | assert 'status' in cr['status'] 81 | condition.assert_synced(ref) 82 | 83 | latest = global_cluster.get(global_cluster_id) 84 | arn = latest['GlobalClusterArn'] 85 | 86 | # now start delete global cluster 87 | k8s.delete_custom_resource(ref) 88 | 89 | time.sleep(DELETE_WAIT_AFTER_SECONDS) 90 | 91 | global_cluster.wait_until_deleted(global_cluster_id) 92 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster_parameter_group/delta.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster_parameter_group 17 | 18 | import ( 19 | "bytes" 20 | "reflect" 21 | 22 | ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" 23 | acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" 24 | ) 25 | 26 | // Hack to avoid import errors during build... 27 | var ( 28 | _ = &bytes.Buffer{} 29 | _ = &reflect.Method{} 30 | _ = &acktags.Tags{} 31 | ) 32 | 33 | // newResourceDelta returns a new `ackcompare.Delta` used to compare two 34 | // resources 35 | func newResourceDelta( 36 | a *resource, 37 | b *resource, 38 | ) *ackcompare.Delta { 39 | delta := ackcompare.NewDelta() 40 | if (a == nil && b != nil) || 41 | (a != nil && b == nil) { 42 | delta.Add("", a, b) 43 | return delta 44 | } 45 | compareTags(delta, a, b) 46 | 47 | if ackcompare.HasNilDifference(a.ko.Spec.Description, b.ko.Spec.Description) { 48 | delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) 49 | } else if a.ko.Spec.Description != nil && b.ko.Spec.Description != nil { 50 | if *a.ko.Spec.Description != *b.ko.Spec.Description { 51 | delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) 52 | } 53 | } 54 | if ackcompare.HasNilDifference(a.ko.Spec.Family, b.ko.Spec.Family) { 55 | delta.Add("Spec.Family", a.ko.Spec.Family, b.ko.Spec.Family) 56 | } else if a.ko.Spec.Family != nil && b.ko.Spec.Family != nil { 57 | if *a.ko.Spec.Family != *b.ko.Spec.Family { 58 | delta.Add("Spec.Family", a.ko.Spec.Family, b.ko.Spec.Family) 59 | } 60 | } 61 | if ackcompare.HasNilDifference(a.ko.Spec.Name, b.ko.Spec.Name) { 62 | delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) 63 | } else if a.ko.Spec.Name != nil && b.ko.Spec.Name != nil { 64 | if *a.ko.Spec.Name != *b.ko.Spec.Name { 65 | delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) 66 | } 67 | } 68 | if len(a.ko.Spec.ParameterOverrides) != len(b.ko.Spec.ParameterOverrides) { 69 | delta.Add("Spec.ParameterOverrides", a.ko.Spec.ParameterOverrides, b.ko.Spec.ParameterOverrides) 70 | } else if len(a.ko.Spec.ParameterOverrides) > 0 { 71 | if !ackcompare.MapStringStringPEqual(a.ko.Spec.ParameterOverrides, b.ko.Spec.ParameterOverrides) { 72 | delta.Add("Spec.ParameterOverrides", a.ko.Spec.ParameterOverrides, b.ko.Spec.ParameterOverrides) 73 | } 74 | } 75 | if len(a.ko.Spec.Parameters) != len(b.ko.Spec.Parameters) { 76 | delta.Add("Spec.Parameters", a.ko.Spec.Parameters, b.ko.Spec.Parameters) 77 | } else if len(a.ko.Spec.Parameters) > 0 { 78 | if !reflect.DeepEqual(a.ko.Spec.Parameters, b.ko.Spec.Parameters) { 79 | delta.Add("Spec.Parameters", a.ko.Spec.Parameters, b.ko.Spec.Parameters) 80 | } 81 | } 82 | 83 | return delta 84 | } 85 | -------------------------------------------------------------------------------- /helm/crds/services.k8s.aws_iamroleselectors.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.19.0 7 | name: iamroleselectors.services.k8s.aws 8 | spec: 9 | group: services.k8s.aws 10 | names: 11 | kind: IAMRoleSelector 12 | listKind: IAMRoleSelectorList 13 | plural: iamroleselectors 14 | singular: iamroleselector 15 | scope: Cluster 16 | versions: 17 | - name: v1alpha1 18 | schema: 19 | openAPIV3Schema: 20 | description: IAMRoleSelector is the schema for the IAMRoleSelector API. 21 | properties: 22 | apiVersion: 23 | description: |- 24 | APIVersion defines the versioned schema of this representation of an object. 25 | Servers should convert recognized schemas to the latest internal value, and 26 | may reject unrecognized values. 27 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 28 | type: string 29 | kind: 30 | description: |- 31 | Kind is a string value representing the REST resource this object represents. 32 | Servers may infer this from the endpoint the client submits requests to. 33 | Cannot be updated. 34 | In CamelCase. 35 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 36 | type: string 37 | metadata: 38 | type: object 39 | spec: 40 | properties: 41 | arn: 42 | type: string 43 | x-kubernetes-validations: 44 | - message: Value is immutable once set 45 | rule: self == oldSelf 46 | namespaceSelector: 47 | description: IAMRoleSelectorSpec defines the desired state of IAMRoleSelector 48 | properties: 49 | labelSelector: 50 | description: LabelSelector is a label query over a set of resources. 51 | properties: 52 | matchLabels: 53 | additionalProperties: 54 | type: string 55 | type: object 56 | required: 57 | - matchLabels 58 | type: object 59 | names: 60 | items: 61 | type: string 62 | type: array 63 | required: 64 | - names 65 | type: object 66 | resourceTypeSelector: 67 | items: 68 | properties: 69 | group: 70 | type: string 71 | kind: 72 | type: string 73 | version: 74 | type: string 75 | required: 76 | - group 77 | - kind 78 | - version 79 | type: object 80 | type: array 81 | required: 82 | - arn 83 | type: object 84 | status: 85 | type: object 86 | type: object 87 | served: true 88 | storage: true 89 | subresources: 90 | status: {} 91 | -------------------------------------------------------------------------------- /config/crd/common/bases/services.k8s.aws_iamroleselectors.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.19.0 7 | name: iamroleselectors.services.k8s.aws 8 | spec: 9 | group: services.k8s.aws 10 | names: 11 | kind: IAMRoleSelector 12 | listKind: IAMRoleSelectorList 13 | plural: iamroleselectors 14 | singular: iamroleselector 15 | scope: Cluster 16 | versions: 17 | - name: v1alpha1 18 | schema: 19 | openAPIV3Schema: 20 | description: IAMRoleSelector is the schema for the IAMRoleSelector API. 21 | properties: 22 | apiVersion: 23 | description: |- 24 | APIVersion defines the versioned schema of this representation of an object. 25 | Servers should convert recognized schemas to the latest internal value, and 26 | may reject unrecognized values. 27 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 28 | type: string 29 | kind: 30 | description: |- 31 | Kind is a string value representing the REST resource this object represents. 32 | Servers may infer this from the endpoint the client submits requests to. 33 | Cannot be updated. 34 | In CamelCase. 35 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 36 | type: string 37 | metadata: 38 | type: object 39 | spec: 40 | properties: 41 | arn: 42 | type: string 43 | x-kubernetes-validations: 44 | - message: Value is immutable once set 45 | rule: self == oldSelf 46 | namespaceSelector: 47 | description: IAMRoleSelectorSpec defines the desired state of IAMRoleSelector 48 | properties: 49 | labelSelector: 50 | description: LabelSelector is a label query over a set of resources. 51 | properties: 52 | matchLabels: 53 | additionalProperties: 54 | type: string 55 | type: object 56 | required: 57 | - matchLabels 58 | type: object 59 | names: 60 | items: 61 | type: string 62 | type: array 63 | required: 64 | - names 65 | type: object 66 | resourceTypeSelector: 67 | items: 68 | properties: 69 | group: 70 | type: string 71 | kind: 72 | type: string 73 | version: 74 | type: string 75 | required: 76 | - group 77 | - kind 78 | - version 79 | type: object 80 | type: array 81 | required: 82 | - arn 83 | type: object 84 | status: 85 | type: object 86 | type: object 87 | served: true 88 | storage: true 89 | subresources: 90 | status: {} 91 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug 4 | report, new feature, correction, or additional documentation, we greatly value 5 | feedback and contributions from our community. 6 | 7 | Please read through this document before submitting any issues or pull requests 8 | to ensure we have all the necessary information to effectively respond to your 9 | bug report or contribution. 10 | 11 | ## Reporting Bugs/Feature Requests 12 | 13 | We welcome you to use the GitHub issue tracker to report bugs or suggest 14 | features. 15 | 16 | When filing an issue, please check existing open, or recently closed, issues to 17 | make sure somebody else hasn't already reported the issue. Please try to 18 | include as much information as you can. Details like these are incredibly 19 | useful: 20 | 21 | * A reproducible test case or series of steps 22 | * The version of our code being used 23 | * Any modifications you've made relevant to the bug 24 | * Anything unusual about your environment or deployment 25 | 26 | ## Contributing via Pull Requests 27 | 28 | Contributions via pull requests are much appreciated. Before sending us a pull 29 | request, please ensure that: 30 | 31 | 1. You are working against the latest source on the *main* branch. 32 | 2. You check existing open, and recently merged, pull requests to make sure 33 | someone else hasn't addressed the problem already. 34 | 3. You open an issue to discuss any significant work - we would hate for your 35 | time to be wasted. 36 | 37 | To send us a pull request, please: 38 | 39 | 1. Fork the repository. 40 | 2. Modify the source; please focus on the specific change you are contributing. 41 | If you also reformat all the code, it will be hard for us to focus on your 42 | change. 43 | 3. Ensure local tests pass. 44 | 4. Commit to your fork using clear commit messages. 45 | 5. Send us a pull request, answering any default questions in the pull request 46 | interface. 47 | 6. Pay attention to any automated CI failures reported in the pull request, and 48 | stay involved in the conversation. 49 | 50 | GitHub provides additional document on [forking a repository][fork] and 51 | [creating a pull request][pr]. 52 | 53 | [fork]: https://help.github.com/articles/fork-a-repo/ 54 | [pr]: https://help.github.com/articles/creating-a-pull-request/ 55 | 56 | ## Finding contributions to work on 57 | 58 | Looking at the existing issues is a great way to find something to contribute 59 | on. As our projects, by default, use the default GitHub issue labels 60 | (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at 61 | any 'help wanted' issues is a great place to start. 62 | 63 | ## Developer documentation 64 | 65 | [See the documentation][dev-docs] for detailed development information. 66 | 67 | [dev-docs]: https://aws-controllers-k8s.github.io/community/docs/contributor-docs/overview/ 68 | 69 | ## Code of Conduct 70 | 71 | We adhere to the [Amazon Open Source Code of Conduct][coc]. 72 | 73 | [coc]: https://aws.github.io/code-of-conduct 74 | 75 | ## Security issue notifications 76 | 77 | If you discover a potential security issue in this project we ask that you 78 | notify AWS/Amazon Security via our [vulnerability reporting page][vuln]. Please 79 | do **not** create a public Github issue. 80 | 81 | [vuln]: http://aws.amazon.com/security/vulnerability-reporting/ 82 | 83 | ## License 84 | 85 | This project is [licensed][./LICENSE] under the Apache-2.0 License. 86 | -------------------------------------------------------------------------------- /pkg/util/tags_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | package util_test 15 | 16 | import ( 17 | "reflect" 18 | "testing" 19 | 20 | "github.com/aws/aws-sdk-go/aws" 21 | 22 | svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1" 23 | "github.com/aws-controllers-k8s/rds-controller/pkg/util" 24 | ) 25 | 26 | var ( 27 | tagA = &svcapitypes.Tag{Key: aws.String("A"), Value: aws.String("1")} 28 | tagB = &svcapitypes.Tag{Key: aws.String("B"), Value: aws.String("2")} 29 | tagC = &svcapitypes.Tag{Key: aws.String("C"), Value: aws.String("3")} 30 | tagD = &svcapitypes.Tag{Key: aws.String("D"), Value: aws.String("4")} 31 | tagE = &svcapitypes.Tag{Key: aws.String("E"), Value: aws.String("5")} 32 | tagE2 = &svcapitypes.Tag{Key: aws.String("E"), Value: aws.String("6")} 33 | ) 34 | 35 | func TestComputeTagsDelta(t *testing.T) { 36 | type args struct { 37 | a []*svcapitypes.Tag 38 | b []*svcapitypes.Tag 39 | } 40 | tests := []struct { 41 | name string 42 | args args 43 | wantAddedOrUpdated []*svcapitypes.Tag 44 | wantRemoved []string 45 | }{ 46 | { 47 | name: "empty arrays", 48 | args: args{}, 49 | wantAddedOrUpdated: nil, 50 | wantRemoved: nil, 51 | }, 52 | { 53 | name: "only added tags", 54 | args: args{ 55 | a: []*svcapitypes.Tag{tagA, tagB, tagC}, 56 | }, 57 | wantAddedOrUpdated: []*svcapitypes.Tag{tagA, tagB, tagC}, 58 | wantRemoved: nil, 59 | }, 60 | { 61 | name: "only removed tags", 62 | args: args{ 63 | b: []*svcapitypes.Tag{tagA, tagB, tagC}, 64 | }, 65 | wantAddedOrUpdated: nil, 66 | wantRemoved: []string{"A", "B", "C"}, 67 | }, 68 | { 69 | name: "added and removed tags", 70 | args: args{ 71 | a: []*svcapitypes.Tag{tagD, tagE}, 72 | b: []*svcapitypes.Tag{tagA, tagB, tagC}, 73 | }, 74 | wantAddedOrUpdated: []*svcapitypes.Tag{tagD, tagE}, 75 | wantRemoved: []string{"A", "B", "C"}, 76 | }, 77 | { 78 | name: "added, updated and removed tags", 79 | args: args{ 80 | a: []*svcapitypes.Tag{tagD, tagE2}, 81 | b: []*svcapitypes.Tag{tagA, tagB, tagC, tagE}, 82 | }, 83 | // notice the order of b is not the same. 84 | wantAddedOrUpdated: []*svcapitypes.Tag{tagE2, tagD}, 85 | wantRemoved: []string{"A", "B", "C"}, 86 | }, 87 | } 88 | for _, tt := range tests { 89 | t.Run(tt.name, func(t *testing.T) { 90 | gotAddedOrUpdated, gotRemoved := util.ComputeTagsDelta(tt.args.a, tt.args.b) 91 | if !reflect.DeepEqual(gotAddedOrUpdated, tt.wantAddedOrUpdated) { 92 | t.Errorf("ComputeTagsDelta() gotAddedOrUpdated = %v, want %v", gotAddedOrUpdated, tt.wantAddedOrUpdated) 93 | } 94 | if !reflect.DeepEqual(gotRemoved, tt.wantRemoved) { 95 | t.Errorf("ComputeTagsDelta() gotRemoved = %v, want %v", gotRemoved, tt.wantRemoved) 96 | } 97 | }) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/resource/db_proxy/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_proxy 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/resource/db_instance/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_instance 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/resource/db_snapshot/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_snapshot 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/resource/db_subnet_group/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_subnet_group 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/resource/global_cluster/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package global_cluster 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster_endpoint/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster_endpoint 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster_snapshot/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster_snapshot 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/resource/db_parameter_group/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_parameter_group 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster_parameter_group/manager_factory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | // Code generated by ack-generate. DO NOT EDIT. 15 | 16 | package db_cluster_parameter_group 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" 23 | ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" 24 | ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" 25 | acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" 26 | "github.com/aws/aws-sdk-go-v2/aws" 27 | "github.com/go-logr/logr" 28 | 29 | svcresource "github.com/aws-controllers-k8s/rds-controller/pkg/resource" 30 | ) 31 | 32 | // resourceManagerFactory produces resourceManager objects. It implements the 33 | // `types.AWSResourceManagerFactory` interface. 34 | type resourceManagerFactory struct { 35 | sync.RWMutex 36 | // rmCache contains resource managers for a particular AWS account ID 37 | rmCache map[string]*resourceManager 38 | } 39 | 40 | // ResourcePrototype returns an AWSResource that resource managers produced by 41 | // this factory will handle 42 | func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { 43 | return &resourceDescriptor{} 44 | } 45 | 46 | // ManagerFor returns a resource manager object that can manage resources for a 47 | // supplied AWS account 48 | func (f *resourceManagerFactory) ManagerFor( 49 | cfg ackcfg.Config, 50 | clientcfg aws.Config, 51 | log logr.Logger, 52 | metrics *ackmetrics.Metrics, 53 | rr acktypes.Reconciler, 54 | id ackv1alpha1.AWSAccountID, 55 | region ackv1alpha1.AWSRegion, 56 | roleARN ackv1alpha1.AWSResourceName, 57 | ) (acktypes.AWSResourceManager, error) { 58 | // We use the account ID, region, and role ARN to uniquely identify a 59 | // resource manager. This helps us to avoid creating multiple resource 60 | // managers for the same account/region/roleARN combination. 61 | rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) 62 | f.RLock() 63 | rm, found := f.rmCache[rmId] 64 | f.RUnlock() 65 | 66 | if found { 67 | return rm, nil 68 | } 69 | 70 | f.Lock() 71 | defer f.Unlock() 72 | 73 | rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) 74 | if err != nil { 75 | return nil, err 76 | } 77 | f.rmCache[rmId] = rm 78 | return rm, nil 79 | } 80 | 81 | // IsAdoptable returns true if the resource is able to be adopted 82 | func (f *resourceManagerFactory) IsAdoptable() bool { 83 | return true 84 | } 85 | 86 | // RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds 87 | // Default is false which means resource will not be requeued after success. 88 | func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { 89 | return 0 90 | } 91 | 92 | func newResourceManagerFactory() *resourceManagerFactory { 93 | return &resourceManagerFactory{ 94 | rmCache: map[string]*resourceManager{}, 95 | } 96 | } 97 | 98 | func init() { 99 | svcresource.RegisterManagerFactory(newResourceManagerFactory()) 100 | } 101 | -------------------------------------------------------------------------------- /config/controller/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: ack-system 5 | --- 6 | apiVersion: apps/v1 7 | kind: Deployment 8 | metadata: 9 | name: ack-rds-controller 10 | namespace: ack-system 11 | labels: 12 | app.kubernetes.io/name: ack-rds-controller 13 | app.kubernetes.io/part-of: ack-system 14 | spec: 15 | selector: 16 | matchLabels: 17 | app.kubernetes.io/name: ack-rds-controller 18 | replicas: 1 19 | template: 20 | metadata: 21 | labels: 22 | app.kubernetes.io/name: ack-rds-controller 23 | spec: 24 | containers: 25 | - command: 26 | - ./bin/controller 27 | args: 28 | - --aws-region 29 | - "$(AWS_REGION)" 30 | - --aws-endpoint-url 31 | - "$(AWS_ENDPOINT_URL)" 32 | - --enable-development-logging=$(ACK_ENABLE_DEVELOPMENT_LOGGING) 33 | - --log-level 34 | - "$(ACK_LOG_LEVEL)" 35 | - --resource-tags 36 | - "$(ACK_RESOURCE_TAGS)" 37 | - --watch-namespace 38 | - "$(ACK_WATCH_NAMESPACE)" 39 | - --enable-leader-election=$(ENABLE_LEADER_ELECTION) 40 | - --leader-election-namespace 41 | - "$(LEADER_ELECTION_NAMESPACE)" 42 | - --reconcile-default-max-concurrent-syncs 43 | - "$(RECONCILE_DEFAULT_MAX_CONCURRENT_SYNCS)" 44 | - --feature-gates 45 | - "$(FEATURE_GATES)" 46 | - --enable-carm=$(ENABLE_CARM) 47 | image: controller:latest 48 | name: controller 49 | ports: 50 | - name: http 51 | containerPort: 8080 52 | resources: 53 | limits: 54 | cpu: 100m 55 | memory: 300Mi 56 | requests: 57 | cpu: 100m 58 | memory: 200Mi 59 | env: 60 | - name: ACK_SYSTEM_NAMESPACE 61 | valueFrom: 62 | fieldRef: 63 | fieldPath: metadata.namespace 64 | - name: AWS_REGION 65 | value: "" 66 | - name: AWS_ENDPOINT_URL 67 | value: "" 68 | - name: ACK_WATCH_NAMESPACE 69 | value: "" 70 | - name: ACK_ENABLE_DEVELOPMENT_LOGGING 71 | value: "false" 72 | - name: ACK_LOG_LEVEL 73 | value: "info" 74 | - name: ACK_RESOURCE_TAGS 75 | value: "services.k8s.aws/controller-version=%CONTROLLER_SERVICE%-%CONTROLLER_VERSION%,services.k8s.aws/namespace=%K8S_NAMESPACE%" 76 | - name: ENABLE_LEADER_ELECTION 77 | value: "false" 78 | - name: LEADER_ELECTION_NAMESPACE 79 | value: "ack-system" 80 | - name: "RECONCILE_DEFAULT_MAX_CONCURRENT_SYNCS" 81 | value: "1" 82 | - name: "FEATURE_GATES" 83 | value: "" 84 | - name: "ENABLE_CARM" 85 | value: "true" 86 | securityContext: 87 | allowPrivilegeEscalation: false 88 | privileged: false 89 | runAsNonRoot: true 90 | capabilities: 91 | drop: 92 | - ALL 93 | livenessProbe: 94 | httpGet: 95 | path: /healthz 96 | port: 8081 97 | initialDelaySeconds: 15 98 | periodSeconds: 20 99 | readinessProbe: 100 | httpGet: 101 | path: /readyz 102 | port: 8081 103 | initialDelaySeconds: 5 104 | periodSeconds: 10 105 | securityContext: 106 | seccompProfile: 107 | type: RuntimeDefault 108 | terminationGracePeriodSeconds: 10 109 | serviceAccountName: ack-rds-controller 110 | hostIPC: false 111 | hostPID: false 112 | hostNetwork: false 113 | dnsPolicy: ClusterFirst 114 | -------------------------------------------------------------------------------- /go.local.mod: -------------------------------------------------------------------------------- 1 | module github.com/aws-controllers-k8s/rds-controller 2 | 3 | go 1.17 4 | 5 | replace github.com/aws-controllers-k8s/runtime => ../runtime 6 | 7 | require ( 8 | github.com/aws-controllers-k8s/kms-controller v0.0.15 9 | github.com/aws-controllers-k8s/runtime v0.24.1 10 | github.com/aws/aws-sdk-go v1.44.93 11 | github.com/go-logr/logr v1.2.3 12 | github.com/spf13/pflag v1.0.5 13 | k8s.io/api v0.26.1 14 | k8s.io/apimachinery v0.26.1 15 | k8s.io/client-go v0.26.1 16 | sigs.k8s.io/controller-runtime v0.14.5 17 | ) 18 | 19 | require ( 20 | github.com/beorn7/perks v1.0.1 // indirect 21 | github.com/cenkalti/backoff/v4 v4.1.3 // indirect 22 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 23 | github.com/davecgh/go-spew v1.1.1 // indirect 24 | github.com/emicklei/go-restful/v3 v3.9.0 // indirect 25 | github.com/evanphx/json-patch v4.12.0+incompatible // indirect 26 | github.com/evanphx/json-patch/v5 v5.6.0 // indirect 27 | github.com/fsnotify/fsnotify v1.6.0 // indirect 28 | github.com/go-logr/zapr v1.2.3 // indirect 29 | github.com/go-openapi/jsonpointer v0.19.5 // indirect 30 | github.com/go-openapi/jsonreference v0.20.0 // indirect 31 | github.com/go-openapi/swag v0.19.14 // indirect 32 | github.com/gogo/protobuf v1.3.2 // indirect 33 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 34 | github.com/golang/protobuf v1.5.2 // indirect 35 | github.com/google/gnostic v0.5.7-v3refs // indirect 36 | github.com/google/go-cmp v0.5.9 // indirect 37 | github.com/google/gofuzz v1.1.0 // indirect 38 | github.com/google/uuid v1.1.2 // indirect 39 | github.com/googleapis/gnostic v0.5.5 // indirect 40 | github.com/imdario/mergo v0.3.12 // indirect 41 | github.com/itchyny/gojq v0.12.6 // indirect 42 | github.com/itchyny/timefmt-go v0.1.3 // indirect 43 | github.com/jaypipes/envutil v1.0.0 // indirect 44 | github.com/jmespath/go-jmespath v0.4.0 // indirect 45 | github.com/josharian/intern v1.0.0 // indirect 46 | github.com/json-iterator/go v1.1.12 // indirect 47 | github.com/mailru/easyjson v0.7.6 // indirect 48 | github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect 49 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 50 | github.com/modern-go/reflect2 v1.0.2 // indirect 51 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 52 | github.com/pkg/errors v0.9.1 // indirect 53 | github.com/prometheus/client_golang v1.14.0 // indirect 54 | github.com/prometheus/client_model v0.3.0 // indirect 55 | github.com/prometheus/common v0.37.0 // indirect 56 | github.com/prometheus/procfs v0.8.0 // indirect 57 | github.com/samber/lo v1.37.0 // indirect 58 | go.uber.org/atomic v1.7.0 // indirect 59 | go.uber.org/multierr v1.6.0 // indirect 60 | go.uber.org/zap v1.24.0 // indirect 61 | golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect 62 | golang.org/x/net v0.7.0 // indirect 63 | golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect 64 | golang.org/x/sys v0.5.0 // indirect 65 | golang.org/x/term v0.5.0 // indirect 66 | golang.org/x/text v0.7.0 // indirect 67 | golang.org/x/time v0.3.0 // indirect 68 | gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect 69 | google.golang.org/appengine v1.6.7 // indirect 70 | google.golang.org/protobuf v1.28.1 // indirect 71 | gopkg.in/inf.v0 v0.9.1 // indirect 72 | gopkg.in/yaml.v2 v2.4.0 // indirect 73 | gopkg.in/yaml.v3 v3.0.1 // indirect 74 | k8s.io/apiextensions-apiserver v0.26.1 // indirect 75 | k8s.io/component-base v0.26.1 // indirect 76 | k8s.io/klog/v2 v2.80.1 // indirect 77 | k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect 78 | k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect 79 | sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect 80 | sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect 81 | sigs.k8s.io/yaml v1.3.0 // indirect 82 | ) 83 | -------------------------------------------------------------------------------- /pkg/resource/db_cluster/custom_update_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 | // not use this file except in compliance with the License. A copy of the 5 | // License is located at 6 | // 7 | // http://aws.amazon.com/apache2.0/ 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | package db_cluster 15 | 16 | import ( 17 | "context" 18 | "testing" 19 | 20 | ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" 21 | "github.com/aws/aws-sdk-go-v2/aws" 22 | "github.com/stretchr/testify/assert" 23 | 24 | svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1" 25 | ) 26 | 27 | func TestNewCustomUpdateRequestPayload_PreferredBackupWindow(t *testing.T) { 28 | // Test case to verify that PreferredBackupWindow is included in the ModifyDBCluster API call 29 | // when Spec.PreferredBackupWindow is in the delta 30 | 31 | // Setup 32 | rm := &resourceManager{} 33 | ctx := context.Background() 34 | 35 | // Create desired resource with PreferredBackupWindow set 36 | desired := &resource{ 37 | ko: &svcapitypes.DBCluster{ 38 | Spec: svcapitypes.DBClusterSpec{ 39 | DBClusterIdentifier: aws.String("test-cluster"), 40 | PreferredBackupWindow: aws.String("07:00-09:00"), 41 | }, 42 | }, 43 | } 44 | 45 | // Create latest resource with different PreferredBackupWindow 46 | latest := &resource{ 47 | ko: &svcapitypes.DBCluster{ 48 | Spec: svcapitypes.DBClusterSpec{ 49 | DBClusterIdentifier: aws.String("test-cluster"), 50 | PreferredBackupWindow: aws.String("05:00-07:00"), 51 | }, 52 | }, 53 | } 54 | 55 | // Create delta with PreferredBackupWindow difference 56 | delta := ackcompare.NewDelta() 57 | delta.Add("Spec.PreferredBackupWindow", latest.ko.Spec.PreferredBackupWindow, desired.ko.Spec.PreferredBackupWindow) 58 | 59 | // Call the function under test 60 | input, err := rm.newCustomUpdateRequestPayload(ctx, desired, latest, delta) 61 | 62 | // Assertions 63 | assert.NoError(t, err) 64 | assert.NotNil(t, input) 65 | assert.Equal(t, *desired.ko.Spec.PreferredBackupWindow, *input.PreferredBackupWindow) 66 | } 67 | 68 | func TestNewCustomUpdateRequestPayload_PreferredBackupWindowNotInDelta(t *testing.T) { 69 | // Test case to verify that PreferredBackupWindow is NOT included in the ModifyDBCluster API call 70 | // when Spec.PreferredBackupWindow is NOT in the delta 71 | 72 | // Setup 73 | rm := &resourceManager{} 74 | ctx := context.Background() 75 | 76 | // Create desired resource with PreferredBackupWindow set 77 | desired := &resource{ 78 | ko: &svcapitypes.DBCluster{ 79 | Spec: svcapitypes.DBClusterSpec{ 80 | DBClusterIdentifier: aws.String("test-cluster"), 81 | PreferredBackupWindow: aws.String("07:00-09:00"), 82 | }, 83 | }, 84 | } 85 | 86 | // Create latest resource with same PreferredBackupWindow 87 | latest := &resource{ 88 | ko: &svcapitypes.DBCluster{ 89 | Spec: svcapitypes.DBClusterSpec{ 90 | DBClusterIdentifier: aws.String("test-cluster"), 91 | PreferredBackupWindow: aws.String("07:00-09:00"), 92 | }, 93 | }, 94 | } 95 | 96 | // Create delta without PreferredBackupWindow difference 97 | delta := ackcompare.NewDelta() 98 | 99 | // Call the function under test 100 | input, err := rm.newCustomUpdateRequestPayload(ctx, desired, latest, delta) 101 | 102 | // Assertions 103 | assert.NoError(t, err) 104 | assert.NotNil(t, input) 105 | assert.Nil(t, input.PreferredBackupWindow) 106 | } 107 | --------------------------------------------------------------------------------