From 7d173f7db43ffa2c1bd6327033a1bbd7145c6691 Mon Sep 17 00:00:00 2001 From: "Kirill Sushkov (teeverr)" Date: Tue, 24 Oct 2023 14:14:22 +0200 Subject: [PATCH] add support for provisioned products from AWS Service Catalog Signed-off-by: Kirill Sushkov (teeverr) --- apis/aws.go | 2 + apis/servicecatalog/generator-config.yaml | 101 ++ apis/servicecatalog/v1alpha1/custom_types.go | 4 + apis/servicecatalog/v1alpha1/zz_doc.go | 24 + apis/servicecatalog/v1alpha1/zz_enums.go | 315 ++++ .../v1alpha1/zz_generated.deepcopy.go | 1374 +++++++++++++++++ .../v1alpha1/zz_generated.managed.go | 81 + .../v1alpha1/zz_generated.managedlist.go | 30 + .../v1alpha1/zz_groupversion_info.go | 41 + .../v1alpha1/zz_provisioned_product.go | 193 +++ apis/servicecatalog/v1alpha1/zz_types.go | 324 ++++ .../servicecatalog/provisionedproduct.yaml | 23 + go.mod | 9 +- go.sum | 11 +- ...aws.crossplane.io_provisionedproducts.yaml | 480 ++++++ pkg/clients/servicecatalog/fake/fake.go | 69 + pkg/clients/servicecatalog/servicecatalog.go | 82 + pkg/controller/aws.go | 2 + .../provisionedproduct/setup.go | 383 +++++ .../provisionedproduct/setup_test.go | 844 ++++++++++ .../provisionedproduct/zz_controller.go | 306 ++++ .../provisionedproduct/zz_conversions.go | 256 +++ pkg/controller/servicecatalog/setup.go | 33 + 23 files changed, 4980 insertions(+), 7 deletions(-) create mode 100644 apis/servicecatalog/generator-config.yaml create mode 100644 apis/servicecatalog/v1alpha1/custom_types.go create mode 100644 apis/servicecatalog/v1alpha1/zz_doc.go create mode 100644 apis/servicecatalog/v1alpha1/zz_enums.go create mode 100644 apis/servicecatalog/v1alpha1/zz_generated.deepcopy.go create mode 100644 apis/servicecatalog/v1alpha1/zz_generated.managed.go create mode 100644 apis/servicecatalog/v1alpha1/zz_generated.managedlist.go create mode 100644 apis/servicecatalog/v1alpha1/zz_groupversion_info.go create mode 100644 apis/servicecatalog/v1alpha1/zz_provisioned_product.go create mode 100644 apis/servicecatalog/v1alpha1/zz_types.go create mode 100644 examples/servicecatalog/provisionedproduct.yaml create mode 100644 package/crds/servicecatalog.aws.crossplane.io_provisionedproducts.yaml create mode 100644 pkg/clients/servicecatalog/fake/fake.go create mode 100644 pkg/clients/servicecatalog/servicecatalog.go create mode 100644 pkg/controller/servicecatalog/provisionedproduct/setup.go create mode 100644 pkg/controller/servicecatalog/provisionedproduct/setup_test.go create mode 100644 pkg/controller/servicecatalog/provisionedproduct/zz_controller.go create mode 100644 pkg/controller/servicecatalog/provisionedproduct/zz_conversions.go create mode 100644 pkg/controller/servicecatalog/setup.go diff --git a/apis/aws.go b/apis/aws.go index 897fafd4a9..01495d2f11 100644 --- a/apis/aws.go +++ b/apis/aws.go @@ -86,6 +86,7 @@ import ( s3control "github.com/crossplane-contrib/provider-aws/apis/s3control/v1alpha1" secretsmanagerv1alpha1 "github.com/crossplane-contrib/provider-aws/apis/secretsmanager/v1alpha1" secretsmanagerv1beta1 "github.com/crossplane-contrib/provider-aws/apis/secretsmanager/v1beta1" + servicecatalogv1alpha1 "github.com/crossplane-contrib/provider-aws/apis/servicecatalog/v1alpha1" servicediscoveryv1alpha1 "github.com/crossplane-contrib/provider-aws/apis/servicediscovery/v1alpha1" sesv2v1alpha1 "github.com/crossplane-contrib/provider-aws/apis/sesv2/v1alpha1" sfnv1alpha1 "github.com/crossplane-contrib/provider-aws/apis/sfn/v1alpha1" @@ -171,6 +172,7 @@ func init() { batchmanualv1alpha1.SchemeBuilder.AddToScheme, emrcontainersv1alpah1.SchemeBuilder.AddToScheme, autoscalingv1beta1.SchemeBuilder.AddToScheme, + servicecatalogv1alpha1.SchemeBuilder.AddToScheme, s3control.SchemeBuilder.AddToScheme, firehosev1alpha1.SchemeBuilder.AddToScheme, ) diff --git a/apis/servicecatalog/generator-config.yaml b/apis/servicecatalog/generator-config.yaml new file mode 100644 index 0000000000..92c8d94709 --- /dev/null +++ b/apis/servicecatalog/generator-config.yaml @@ -0,0 +1,101 @@ +--- +ignore: + resource_names: + - Constraint + - PortfolioShare + - Portfolio + - Cluster + - Product + - ProvisionedProductPlan + - ProvisioningArtifact + - ServiceAction + - TagOption + field_paths: + - ProvisionProductInput.ProvisionToken + - UpdateProvisioningParameter.UsePreviousValue + - UpdateProvisioningPreferences.StackSetOperationType + - ProvisionProductInput.ProvisionedProductName + - UpdateProvisionedProductInput.ProvisionedProductId + - UpdateProvisionedProductInput.ProvisionedProductName + - TerminateProvisionedProductInput.ProvisionedProductId + - TerminateProvisionedProductInput.ProvisionedProductName + - DescribeProvisionedProductInput.ProvisionedProductId + - DescribeProvisionedProductInput.ProvisionedProductName + - ProvisionProductOutput.RecordDetail.PathId + - ProvisionProductOutput.RecordDetail.ProductId + - ProvisionProductOutput.RecordDetail.ProvisioningArtifactId + shape_names: + - ProvisionedProductPlanSummary + - ProvisionedProductPlanDetails +operations: + ProvisionProduct: + operation_type: + - Create + resource_name: ProvisionedProduct + UpdateProvisionedProduct: + operation_type: + - Update + resource_name: ProvisionedProduct + DescribeProvisionedProduct: + operation_type: + - Read + resource_name: ProvisionedProduct + TerminateProvisionedProduct: + operation_type: + - Delete + resource_name: ProvisionedProduct +resources: + ProvisionedProduct: + exceptions: + errors: + 404: + code: ResourceNotFoundException + fields: + Outputs: + is_read_only: true + custom_field: + map_of: RecordOutput + Arn: + is_read_only: true + from: + operation: DescribeProvisionedProduct + path: ProvisionedProductDetail.Arn + CreatedTime: + is_read_only: true + from: + operation: DescribeProvisionedProduct + path: ProvisionedProductDetail.CreatedTime + LastProvisioningRecordId: + is_read_only: true + from: + operation: DescribeProvisionedProduct + path: ProvisionedProductDetail.LastProvisioningRecordId + LastProductID: + is_read_only: true + from: + operation: DescribeProvisionedProduct + path: ProvisionedProductDetail.ProductId + LastProvisioningArtifactID: + is_read_only: true + from: + operation: DescribeProvisionedProduct + path: ProvisionedProductDetail.ProvisioningArtifactId + LastProvisioningParameters: + is_read_only: true + custom_field: + list_of: ProvisioningParameter + LaunchRoleArn: + is_read_only: true + from: + operation: DescribeProvisionedProduct + path: ProvisionedProductDetail.LaunchRoleArn + Status: + is_read_only: true + from: + operation: DescribeProvisionedProduct + path: ProvisionedProductDetail.Status + StatusMessage: + is_read_only: true + from: + operation: DescribeProvisionedProduct + path: ProvisionedProductDetail.StatusMessage \ No newline at end of file diff --git a/apis/servicecatalog/v1alpha1/custom_types.go b/apis/servicecatalog/v1alpha1/custom_types.go new file mode 100644 index 0000000000..0f579cb91e --- /dev/null +++ b/apis/servicecatalog/v1alpha1/custom_types.go @@ -0,0 +1,4 @@ +package v1alpha1 + +// CustomProvisionedProductParameters includes the custom fields. +type CustomProvisionedProductParameters struct{} diff --git a/apis/servicecatalog/v1alpha1/zz_doc.go b/apis/servicecatalog/v1alpha1/zz_doc.go new file mode 100644 index 0000000000..1aa26ff243 --- /dev/null +++ b/apis/servicecatalog/v1alpha1/zz_doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by ack-generate. DO NOT EDIT. + +// +kubebuilder:object:generate=true +// Package v1alpha1 is the v1alpha1 version of the servicecatalog.aws.crossplane.io API. +// +groupName=servicecatalog.aws.crossplane.io +// +versionName=v1alpha1 + +package v1alpha1 diff --git a/apis/servicecatalog/v1alpha1/zz_enums.go b/apis/servicecatalog/v1alpha1/zz_enums.go new file mode 100644 index 0000000000..7c03b2eaa0 --- /dev/null +++ b/apis/servicecatalog/v1alpha1/zz_enums.go @@ -0,0 +1,315 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +type AccessLevelFilterKey string + +const ( + AccessLevelFilterKey_Account AccessLevelFilterKey = "Account" + AccessLevelFilterKey_Role AccessLevelFilterKey = "Role" + AccessLevelFilterKey_User AccessLevelFilterKey = "User" +) + +type AccessStatus string + +const ( + AccessStatus_ENABLED AccessStatus = "ENABLED" + AccessStatus_UNDER_CHANGE AccessStatus = "UNDER_CHANGE" + AccessStatus_DISABLED AccessStatus = "DISABLED" +) + +type ChangeAction string + +const ( + ChangeAction_ADD ChangeAction = "ADD" + ChangeAction_MODIFY ChangeAction = "MODIFY" + ChangeAction_REMOVE ChangeAction = "REMOVE" +) + +type CopyOption string + +const ( + CopyOption_CopyTags CopyOption = "CopyTags" +) + +type CopyProductStatus string + +const ( + CopyProductStatus_SUCCEEDED CopyProductStatus = "SUCCEEDED" + CopyProductStatus_IN_PROGRESS CopyProductStatus = "IN_PROGRESS" + CopyProductStatus_FAILED CopyProductStatus = "FAILED" +) + +type DescribePortfolioShareType string + +const ( + DescribePortfolioShareType_ACCOUNT DescribePortfolioShareType = "ACCOUNT" + DescribePortfolioShareType_ORGANIZATION DescribePortfolioShareType = "ORGANIZATION" + DescribePortfolioShareType_ORGANIZATIONAL_UNIT DescribePortfolioShareType = "ORGANIZATIONAL_UNIT" + DescribePortfolioShareType_ORGANIZATION_MEMBER_ACCOUNT DescribePortfolioShareType = "ORGANIZATION_MEMBER_ACCOUNT" +) + +type EngineWorkflowStatus string + +const ( + EngineWorkflowStatus_SUCCEEDED EngineWorkflowStatus = "SUCCEEDED" + EngineWorkflowStatus_FAILED EngineWorkflowStatus = "FAILED" +) + +type EvaluationType string + +const ( + EvaluationType_STATIC EvaluationType = "STATIC" + EvaluationType_DYNAMIC EvaluationType = "DYNAMIC" +) + +type LastSyncStatus string + +const ( + LastSyncStatus_SUCCEEDED LastSyncStatus = "SUCCEEDED" + LastSyncStatus_FAILED LastSyncStatus = "FAILED" +) + +type OrganizationNodeType string + +const ( + OrganizationNodeType_ORGANIZATION OrganizationNodeType = "ORGANIZATION" + OrganizationNodeType_ORGANIZATIONAL_UNIT OrganizationNodeType = "ORGANIZATIONAL_UNIT" + OrganizationNodeType_ACCOUNT OrganizationNodeType = "ACCOUNT" +) + +type PortfolioShareType string + +const ( + PortfolioShareType_IMPORTED PortfolioShareType = "IMPORTED" + PortfolioShareType_AWS_SERVICECATALOG PortfolioShareType = "AWS_SERVICECATALOG" + PortfolioShareType_AWS_ORGANIZATIONS PortfolioShareType = "AWS_ORGANIZATIONS" +) + +type PrincipalType string + +const ( + PrincipalType_IAM PrincipalType = "IAM" + PrincipalType_IAM_PATTERN PrincipalType = "IAM_PATTERN" +) + +type ProductSource string + +const ( + ProductSource_ACCOUNT ProductSource = "ACCOUNT" +) + +type ProductType string + +const ( + ProductType_CLOUD_FORMATION_TEMPLATE ProductType = "CLOUD_FORMATION_TEMPLATE" + ProductType_MARKETPLACE ProductType = "MARKETPLACE" + ProductType_TERRAFORM_OPEN_SOURCE ProductType = "TERRAFORM_OPEN_SOURCE" + ProductType_TERRAFORM_CLOUD ProductType = "TERRAFORM_CLOUD" +) + +type ProductViewFilterBy string + +const ( + ProductViewFilterBy_FullTextSearch ProductViewFilterBy = "FullTextSearch" + ProductViewFilterBy_Owner ProductViewFilterBy = "Owner" + ProductViewFilterBy_ProductType ProductViewFilterBy = "ProductType" + ProductViewFilterBy_SourceProductId ProductViewFilterBy = "SourceProductId" +) + +type ProductViewSortBy string + +const ( + ProductViewSortBy_Title ProductViewSortBy = "Title" + ProductViewSortBy_VersionCount ProductViewSortBy = "VersionCount" + ProductViewSortBy_CreationDate ProductViewSortBy = "CreationDate" +) + +type PropertyKey string + +const ( + PropertyKey_OWNER PropertyKey = "OWNER" + PropertyKey_LAUNCH_ROLE PropertyKey = "LAUNCH_ROLE" +) + +type ProvisionedProductPlanStatus string + +const ( + ProvisionedProductPlanStatus_CREATE_IN_PROGRESS ProvisionedProductPlanStatus = "CREATE_IN_PROGRESS" + ProvisionedProductPlanStatus_CREATE_SUCCESS ProvisionedProductPlanStatus = "CREATE_SUCCESS" + ProvisionedProductPlanStatus_CREATE_FAILED ProvisionedProductPlanStatus = "CREATE_FAILED" + ProvisionedProductPlanStatus_EXECUTE_IN_PROGRESS ProvisionedProductPlanStatus = "EXECUTE_IN_PROGRESS" + ProvisionedProductPlanStatus_EXECUTE_SUCCESS ProvisionedProductPlanStatus = "EXECUTE_SUCCESS" + ProvisionedProductPlanStatus_EXECUTE_FAILED ProvisionedProductPlanStatus = "EXECUTE_FAILED" +) + +type ProvisionedProductPlanType string + +const ( + ProvisionedProductPlanType_CLOUDFORMATION ProvisionedProductPlanType = "CLOUDFORMATION" +) + +type ProvisionedProductStatus_SDK string + +const ( + ProvisionedProductStatus_SDK_AVAILABLE ProvisionedProductStatus_SDK = "AVAILABLE" + ProvisionedProductStatus_SDK_UNDER_CHANGE ProvisionedProductStatus_SDK = "UNDER_CHANGE" + ProvisionedProductStatus_SDK_TAINTED ProvisionedProductStatus_SDK = "TAINTED" + ProvisionedProductStatus_SDK_ERROR ProvisionedProductStatus_SDK = "ERROR" + ProvisionedProductStatus_SDK_PLAN_IN_PROGRESS ProvisionedProductStatus_SDK = "PLAN_IN_PROGRESS" +) + +type ProvisionedProductViewFilterBy string + +const ( + ProvisionedProductViewFilterBy_SearchQuery ProvisionedProductViewFilterBy = "SearchQuery" +) + +type ProvisioningArtifactGuidance string + +const ( + ProvisioningArtifactGuidance_DEFAULT ProvisioningArtifactGuidance = "DEFAULT" + ProvisioningArtifactGuidance_DEPRECATED ProvisioningArtifactGuidance = "DEPRECATED" +) + +type ProvisioningArtifactPropertyName string + +const ( + ProvisioningArtifactPropertyName_Id ProvisioningArtifactPropertyName = "Id" +) + +type ProvisioningArtifactType string + +const ( + ProvisioningArtifactType_CLOUD_FORMATION_TEMPLATE ProvisioningArtifactType = "CLOUD_FORMATION_TEMPLATE" + ProvisioningArtifactType_MARKETPLACE_AMI ProvisioningArtifactType = "MARKETPLACE_AMI" + ProvisioningArtifactType_MARKETPLACE_CAR ProvisioningArtifactType = "MARKETPLACE_CAR" + ProvisioningArtifactType_TERRAFORM_OPEN_SOURCE ProvisioningArtifactType = "TERRAFORM_OPEN_SOURCE" + ProvisioningArtifactType_TERRAFORM_CLOUD ProvisioningArtifactType = "TERRAFORM_CLOUD" +) + +type RecordStatus string + +const ( + RecordStatus_CREATED RecordStatus = "CREATED" + RecordStatus_IN_PROGRESS RecordStatus = "IN_PROGRESS" + RecordStatus_IN_PROGRESS_IN_ERROR RecordStatus = "IN_PROGRESS_IN_ERROR" + RecordStatus_SUCCEEDED RecordStatus = "SUCCEEDED" + RecordStatus_FAILED RecordStatus = "FAILED" +) + +type Replacement string + +const ( + Replacement_TRUE Replacement = "TRUE" + Replacement_FALSE Replacement = "FALSE" + Replacement_CONDITIONAL Replacement = "CONDITIONAL" +) + +type RequiresRecreation string + +const ( + RequiresRecreation_NEVER RequiresRecreation = "NEVER" + RequiresRecreation_CONDITIONALLY RequiresRecreation = "CONDITIONALLY" + RequiresRecreation_ALWAYS RequiresRecreation = "ALWAYS" +) + +type ResourceAttribute string + +const ( + ResourceAttribute_PROPERTIES ResourceAttribute = "PROPERTIES" + ResourceAttribute_METADATA ResourceAttribute = "METADATA" + ResourceAttribute_CREATIONPOLICY ResourceAttribute = "CREATIONPOLICY" + ResourceAttribute_UPDATEPOLICY ResourceAttribute = "UPDATEPOLICY" + ResourceAttribute_DELETIONPOLICY ResourceAttribute = "DELETIONPOLICY" + ResourceAttribute_TAGS ResourceAttribute = "TAGS" +) + +type ServiceActionAssociationErrorCode string + +const ( + ServiceActionAssociationErrorCode_DUPLICATE_RESOURCE ServiceActionAssociationErrorCode = "DUPLICATE_RESOURCE" + ServiceActionAssociationErrorCode_INTERNAL_FAILURE ServiceActionAssociationErrorCode = "INTERNAL_FAILURE" + ServiceActionAssociationErrorCode_LIMIT_EXCEEDED ServiceActionAssociationErrorCode = "LIMIT_EXCEEDED" + ServiceActionAssociationErrorCode_RESOURCE_NOT_FOUND ServiceActionAssociationErrorCode = "RESOURCE_NOT_FOUND" + ServiceActionAssociationErrorCode_THROTTLING ServiceActionAssociationErrorCode = "THROTTLING" + ServiceActionAssociationErrorCode_INVALID_PARAMETER ServiceActionAssociationErrorCode = "INVALID_PARAMETER" +) + +type ServiceActionDefinitionKey string + +const ( + ServiceActionDefinitionKey_Name ServiceActionDefinitionKey = "Name" + ServiceActionDefinitionKey_Version ServiceActionDefinitionKey = "Version" + ServiceActionDefinitionKey_AssumeRole ServiceActionDefinitionKey = "AssumeRole" + ServiceActionDefinitionKey_Parameters ServiceActionDefinitionKey = "Parameters" +) + +type ServiceActionDefinitionType string + +const ( + ServiceActionDefinitionType_SSM_AUTOMATION ServiceActionDefinitionType = "SSM_AUTOMATION" +) + +type ShareStatus string + +const ( + ShareStatus_NOT_STARTED ShareStatus = "NOT_STARTED" + ShareStatus_IN_PROGRESS ShareStatus = "IN_PROGRESS" + ShareStatus_COMPLETED ShareStatus = "COMPLETED" + ShareStatus_COMPLETED_WITH_ERRORS ShareStatus = "COMPLETED_WITH_ERRORS" + ShareStatus_ERROR ShareStatus = "ERROR" +) + +type SortOrder string + +const ( + SortOrder_ASCENDING SortOrder = "ASCENDING" + SortOrder_DESCENDING SortOrder = "DESCENDING" +) + +type SourceType string + +const ( + SourceType_CODESTAR SourceType = "CODESTAR" +) + +type StackInstanceStatus string + +const ( + StackInstanceStatus_CURRENT StackInstanceStatus = "CURRENT" + StackInstanceStatus_OUTDATED StackInstanceStatus = "OUTDATED" + StackInstanceStatus_INOPERABLE StackInstanceStatus = "INOPERABLE" +) + +type StackSetOperationType string + +const ( + StackSetOperationType_CREATE StackSetOperationType = "CREATE" + StackSetOperationType_UPDATE StackSetOperationType = "UPDATE" + StackSetOperationType_DELETE StackSetOperationType = "DELETE" +) + +type Status string + +const ( + Status_AVAILABLE Status = "AVAILABLE" + Status_CREATING Status = "CREATING" + Status_FAILED Status = "FAILED" +) diff --git a/apis/servicecatalog/v1alpha1/zz_generated.deepcopy.go b/apis/servicecatalog/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..f921063802 --- /dev/null +++ b/apis/servicecatalog/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,1374 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CloudWatchDashboard) DeepCopyInto(out *CloudWatchDashboard) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudWatchDashboard. +func (in *CloudWatchDashboard) DeepCopy() *CloudWatchDashboard { + if in == nil { + return nil + } + out := new(CloudWatchDashboard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConstraintDetail) DeepCopyInto(out *ConstraintDetail) { + *out = *in + if in.ConstraintID != nil { + in, out := &in.ConstraintID, &out.ConstraintID + *out = new(string) + **out = **in + } + if in.Owner != nil { + in, out := &in.Owner, &out.Owner + *out = new(string) + **out = **in + } + if in.PortfolioID != nil { + in, out := &in.PortfolioID, &out.PortfolioID + *out = new(string) + **out = **in + } + if in.ProductID != nil { + in, out := &in.ProductID, &out.ProductID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConstraintDetail. +func (in *ConstraintDetail) DeepCopy() *ConstraintDetail { + if in == nil { + return nil + } + out := new(ConstraintDetail) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomProvisionedProductParameters) DeepCopyInto(out *CustomProvisionedProductParameters) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomProvisionedProductParameters. +func (in *CustomProvisionedProductParameters) DeepCopy() *CustomProvisionedProductParameters { + if in == nil { + return nil + } + out := new(CustomProvisionedProductParameters) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FailedServiceActionAssociation) DeepCopyInto(out *FailedServiceActionAssociation) { + *out = *in + if in.ProductID != nil { + in, out := &in.ProductID, &out.ProductID + *out = new(string) + **out = **in + } + if in.ProvisioningArtifactID != nil { + in, out := &in.ProvisioningArtifactID, &out.ProvisioningArtifactID + *out = new(string) + **out = **in + } + if in.ServiceActionID != nil { + in, out := &in.ServiceActionID, &out.ServiceActionID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailedServiceActionAssociation. +func (in *FailedServiceActionAssociation) DeepCopy() *FailedServiceActionAssociation { + if in == nil { + return nil + } + out := new(FailedServiceActionAssociation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LastSync) DeepCopyInto(out *LastSync) { + *out = *in + if in.LastSuccessfulSyncProvisioningArtifactID != nil { + in, out := &in.LastSuccessfulSyncProvisioningArtifactID, &out.LastSuccessfulSyncProvisioningArtifactID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LastSync. +func (in *LastSync) DeepCopy() *LastSync { + if in == nil { + return nil + } + out := new(LastSync) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LaunchPath) DeepCopyInto(out *LaunchPath) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LaunchPath. +func (in *LaunchPath) DeepCopy() *LaunchPath { + if in == nil { + return nil + } + out := new(LaunchPath) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LaunchPathSummary) DeepCopyInto(out *LaunchPathSummary) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]*Tag, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Tag) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LaunchPathSummary. +func (in *LaunchPathSummary) DeepCopy() *LaunchPathSummary { + if in == nil { + return nil + } + out := new(LaunchPathSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortfolioDetail) DeepCopyInto(out *PortfolioDetail) { + *out = *in + if in.DisplayName != nil { + in, out := &in.DisplayName, &out.DisplayName + *out = new(string) + **out = **in + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortfolioDetail. +func (in *PortfolioDetail) DeepCopy() *PortfolioDetail { + if in == nil { + return nil + } + out := new(PortfolioDetail) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortfolioShareDetail) DeepCopyInto(out *PortfolioShareDetail) { + *out = *in + if in.PrincipalID != nil { + in, out := &in.PrincipalID, &out.PrincipalID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortfolioShareDetail. +func (in *PortfolioShareDetail) DeepCopy() *PortfolioShareDetail { + if in == nil { + return nil + } + out := new(PortfolioShareDetail) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProductViewDetail) DeepCopyInto(out *ProductViewDetail) { + *out = *in + if in.CreatedTime != nil { + in, out := &in.CreatedTime, &out.CreatedTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProductViewDetail. +func (in *ProductViewDetail) DeepCopy() *ProductViewDetail { + if in == nil { + return nil + } + out := new(ProductViewDetail) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProductViewSummary) DeepCopyInto(out *ProductViewSummary) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.ProductID != nil { + in, out := &in.ProductID, &out.ProductID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProductViewSummary. +func (in *ProductViewSummary) DeepCopy() *ProductViewSummary { + if in == nil { + return nil + } + out := new(ProductViewSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisionedProduct) DeepCopyInto(out *ProvisionedProduct) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionedProduct. +func (in *ProvisionedProduct) DeepCopy() *ProvisionedProduct { + if in == nil { + return nil + } + out := new(ProvisionedProduct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ProvisionedProduct) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisionedProductAttribute) DeepCopyInto(out *ProvisionedProductAttribute) { + *out = *in + if in.ARN != nil { + in, out := &in.ARN, &out.ARN + *out = new(string) + **out = **in + } + if in.CreatedTime != nil { + in, out := &in.CreatedTime, &out.CreatedTime + *out = (*in).DeepCopy() + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.IdempotencyToken != nil { + in, out := &in.IdempotencyToken, &out.IdempotencyToken + *out = new(string) + **out = **in + } + if in.LastProvisioningRecordID != nil { + in, out := &in.LastProvisioningRecordID, &out.LastProvisioningRecordID + *out = new(string) + **out = **in + } + if in.LastRecordID != nil { + in, out := &in.LastRecordID, &out.LastRecordID + *out = new(string) + **out = **in + } + if in.LastSuccessfulProvisioningRecordID != nil { + in, out := &in.LastSuccessfulProvisioningRecordID, &out.LastSuccessfulProvisioningRecordID + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.ProductID != nil { + in, out := &in.ProductID, &out.ProductID + *out = new(string) + **out = **in + } + if in.ProductName != nil { + in, out := &in.ProductName, &out.ProductName + *out = new(string) + **out = **in + } + if in.ProvisioningArtifactID != nil { + in, out := &in.ProvisioningArtifactID, &out.ProvisioningArtifactID + *out = new(string) + **out = **in + } + if in.ProvisioningArtifactName != nil { + in, out := &in.ProvisioningArtifactName, &out.ProvisioningArtifactName + *out = new(string) + **out = **in + } + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(string) + **out = **in + } + if in.StatusMessage != nil { + in, out := &in.StatusMessage, &out.StatusMessage + *out = new(string) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]*Tag, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Tag) + (*in).DeepCopyInto(*out) + } + } + } + if in.Type != nil { + in, out := &in.Type, &out.Type + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionedProductAttribute. +func (in *ProvisionedProductAttribute) DeepCopy() *ProvisionedProductAttribute { + if in == nil { + return nil + } + out := new(ProvisionedProductAttribute) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisionedProductDetail) DeepCopyInto(out *ProvisionedProductDetail) { + *out = *in + if in.ARN != nil { + in, out := &in.ARN, &out.ARN + *out = new(string) + **out = **in + } + if in.CreatedTime != nil { + in, out := &in.CreatedTime, &out.CreatedTime + *out = (*in).DeepCopy() + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.IdempotencyToken != nil { + in, out := &in.IdempotencyToken, &out.IdempotencyToken + *out = new(string) + **out = **in + } + if in.LastProvisioningRecordID != nil { + in, out := &in.LastProvisioningRecordID, &out.LastProvisioningRecordID + *out = new(string) + **out = **in + } + if in.LastRecordID != nil { + in, out := &in.LastRecordID, &out.LastRecordID + *out = new(string) + **out = **in + } + if in.LastSuccessfulProvisioningRecordID != nil { + in, out := &in.LastSuccessfulProvisioningRecordID, &out.LastSuccessfulProvisioningRecordID + *out = new(string) + **out = **in + } + if in.LaunchRoleARN != nil { + in, out := &in.LaunchRoleARN, &out.LaunchRoleARN + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.ProductID != nil { + in, out := &in.ProductID, &out.ProductID + *out = new(string) + **out = **in + } + if in.ProvisioningArtifactID != nil { + in, out := &in.ProvisioningArtifactID, &out.ProvisioningArtifactID + *out = new(string) + **out = **in + } + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(string) + **out = **in + } + if in.StatusMessage != nil { + in, out := &in.StatusMessage, &out.StatusMessage + *out = new(string) + **out = **in + } + if in.Type != nil { + in, out := &in.Type, &out.Type + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionedProductDetail. +func (in *ProvisionedProductDetail) DeepCopy() *ProvisionedProductDetail { + if in == nil { + return nil + } + out := new(ProvisionedProductDetail) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisionedProductList) DeepCopyInto(out *ProvisionedProductList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ProvisionedProduct, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionedProductList. +func (in *ProvisionedProductList) DeepCopy() *ProvisionedProductList { + if in == nil { + return nil + } + out := new(ProvisionedProductList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ProvisionedProductList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisionedProductObservation) DeepCopyInto(out *ProvisionedProductObservation) { + *out = *in + if in.ARN != nil { + in, out := &in.ARN, &out.ARN + *out = new(string) + **out = **in + } + if in.CreatedTime != nil { + in, out := &in.CreatedTime, &out.CreatedTime + *out = (*in).DeepCopy() + } + if in.LastProductID != nil { + in, out := &in.LastProductID, &out.LastProductID + *out = new(string) + **out = **in + } + if in.LastProvisioningArtifactID != nil { + in, out := &in.LastProvisioningArtifactID, &out.LastProvisioningArtifactID + *out = new(string) + **out = **in + } + if in.LastProvisioningParameters != nil { + in, out := &in.LastProvisioningParameters, &out.LastProvisioningParameters + *out = make([]*ProvisioningParameter, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(ProvisioningParameter) + (*in).DeepCopyInto(*out) + } + } + } + if in.LastProvisioningRecordID != nil { + in, out := &in.LastProvisioningRecordID, &out.LastProvisioningRecordID + *out = new(string) + **out = **in + } + if in.LaunchRoleARN != nil { + in, out := &in.LaunchRoleARN, &out.LaunchRoleARN + *out = new(string) + **out = **in + } + if in.Outputs != nil { + in, out := &in.Outputs, &out.Outputs + *out = make(map[string]*RecordOutput, len(*in)) + for key, val := range *in { + var outVal *RecordOutput + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = new(RecordOutput) + (*in).DeepCopyInto(*out) + } + (*out)[key] = outVal + } + } + if in.ProvisionedProductID != nil { + in, out := &in.ProvisionedProductID, &out.ProvisionedProductID + *out = new(string) + **out = **in + } + if in.ProvisionedProductName != nil { + in, out := &in.ProvisionedProductName, &out.ProvisionedProductName + *out = new(string) + **out = **in + } + if in.ProvisionedProductType != nil { + in, out := &in.ProvisionedProductType, &out.ProvisionedProductType + *out = new(string) + **out = **in + } + if in.RecordErrors != nil { + in, out := &in.RecordErrors, &out.RecordErrors + *out = make([]*RecordError, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RecordError) + (*in).DeepCopyInto(*out) + } + } + } + if in.RecordID != nil { + in, out := &in.RecordID, &out.RecordID + *out = new(string) + **out = **in + } + if in.RecordTags != nil { + in, out := &in.RecordTags, &out.RecordTags + *out = make([]*RecordTag, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RecordTag) + (*in).DeepCopyInto(*out) + } + } + } + if in.RecordType != nil { + in, out := &in.RecordType, &out.RecordType + *out = new(string) + **out = **in + } + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(string) + **out = **in + } + if in.StatusMessage != nil { + in, out := &in.StatusMessage, &out.StatusMessage + *out = new(string) + **out = **in + } + if in.UpdatedTime != nil { + in, out := &in.UpdatedTime, &out.UpdatedTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionedProductObservation. +func (in *ProvisionedProductObservation) DeepCopy() *ProvisionedProductObservation { + if in == nil { + return nil + } + out := new(ProvisionedProductObservation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisionedProductParameters) DeepCopyInto(out *ProvisionedProductParameters) { + *out = *in + if in.AcceptLanguage != nil { + in, out := &in.AcceptLanguage, &out.AcceptLanguage + *out = new(string) + **out = **in + } + if in.NotificationARNs != nil { + in, out := &in.NotificationARNs, &out.NotificationARNs + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.PathID != nil { + in, out := &in.PathID, &out.PathID + *out = new(string) + **out = **in + } + if in.PathName != nil { + in, out := &in.PathName, &out.PathName + *out = new(string) + **out = **in + } + if in.ProductID != nil { + in, out := &in.ProductID, &out.ProductID + *out = new(string) + **out = **in + } + if in.ProductName != nil { + in, out := &in.ProductName, &out.ProductName + *out = new(string) + **out = **in + } + if in.ProvisioningArtifactID != nil { + in, out := &in.ProvisioningArtifactID, &out.ProvisioningArtifactID + *out = new(string) + **out = **in + } + if in.ProvisioningArtifactName != nil { + in, out := &in.ProvisioningArtifactName, &out.ProvisioningArtifactName + *out = new(string) + **out = **in + } + if in.ProvisioningParameters != nil { + in, out := &in.ProvisioningParameters, &out.ProvisioningParameters + *out = make([]*ProvisioningParameter, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(ProvisioningParameter) + (*in).DeepCopyInto(*out) + } + } + } + if in.ProvisioningPreferences != nil { + in, out := &in.ProvisioningPreferences, &out.ProvisioningPreferences + *out = new(ProvisioningPreferences) + (*in).DeepCopyInto(*out) + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]*Tag, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Tag) + (*in).DeepCopyInto(*out) + } + } + } + out.CustomProvisionedProductParameters = in.CustomProvisionedProductParameters +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionedProductParameters. +func (in *ProvisionedProductParameters) DeepCopy() *ProvisionedProductParameters { + if in == nil { + return nil + } + out := new(ProvisionedProductParameters) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisionedProductSpec) DeepCopyInto(out *ProvisionedProductSpec) { + *out = *in + in.ResourceSpec.DeepCopyInto(&out.ResourceSpec) + in.ForProvider.DeepCopyInto(&out.ForProvider) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionedProductSpec. +func (in *ProvisionedProductSpec) DeepCopy() *ProvisionedProductSpec { + if in == nil { + return nil + } + out := new(ProvisionedProductSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisionedProductStatus) DeepCopyInto(out *ProvisionedProductStatus) { + *out = *in + in.ResourceStatus.DeepCopyInto(&out.ResourceStatus) + in.AtProvider.DeepCopyInto(&out.AtProvider) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionedProductStatus. +func (in *ProvisionedProductStatus) DeepCopy() *ProvisionedProductStatus { + if in == nil { + return nil + } + out := new(ProvisionedProductStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisioningArtifact) DeepCopyInto(out *ProvisioningArtifact) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisioningArtifact. +func (in *ProvisioningArtifact) DeepCopy() *ProvisioningArtifact { + if in == nil { + return nil + } + out := new(ProvisioningArtifact) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisioningArtifactDetail) DeepCopyInto(out *ProvisioningArtifactDetail) { + *out = *in + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisioningArtifactDetail. +func (in *ProvisioningArtifactDetail) DeepCopy() *ProvisioningArtifactDetail { + if in == nil { + return nil + } + out := new(ProvisioningArtifactDetail) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisioningArtifactParameter) DeepCopyInto(out *ProvisioningArtifactParameter) { + *out = *in + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.ParameterKey != nil { + in, out := &in.ParameterKey, &out.ParameterKey + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisioningArtifactParameter. +func (in *ProvisioningArtifactParameter) DeepCopy() *ProvisioningArtifactParameter { + if in == nil { + return nil + } + out := new(ProvisioningArtifactParameter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisioningArtifactPreferences) DeepCopyInto(out *ProvisioningArtifactPreferences) { + *out = *in + if in.StackSetAccounts != nil { + in, out := &in.StackSetAccounts, &out.StackSetAccounts + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.StackSetRegions != nil { + in, out := &in.StackSetRegions, &out.StackSetRegions + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisioningArtifactPreferences. +func (in *ProvisioningArtifactPreferences) DeepCopy() *ProvisioningArtifactPreferences { + if in == nil { + return nil + } + out := new(ProvisioningArtifactPreferences) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisioningArtifactProperties) DeepCopyInto(out *ProvisioningArtifactProperties) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisioningArtifactProperties. +func (in *ProvisioningArtifactProperties) DeepCopy() *ProvisioningArtifactProperties { + if in == nil { + return nil + } + out := new(ProvisioningArtifactProperties) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisioningArtifactSummary) DeepCopyInto(out *ProvisioningArtifactSummary) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisioningArtifactSummary. +func (in *ProvisioningArtifactSummary) DeepCopy() *ProvisioningArtifactSummary { + if in == nil { + return nil + } + out := new(ProvisioningArtifactSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisioningParameter) DeepCopyInto(out *ProvisioningParameter) { + *out = *in + if in.Key != nil { + in, out := &in.Key, &out.Key + *out = new(string) + **out = **in + } + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisioningParameter. +func (in *ProvisioningParameter) DeepCopy() *ProvisioningParameter { + if in == nil { + return nil + } + out := new(ProvisioningParameter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProvisioningPreferences) DeepCopyInto(out *ProvisioningPreferences) { + *out = *in + if in.StackSetAccounts != nil { + in, out := &in.StackSetAccounts, &out.StackSetAccounts + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.StackSetFailureToleranceCount != nil { + in, out := &in.StackSetFailureToleranceCount, &out.StackSetFailureToleranceCount + *out = new(int64) + **out = **in + } + if in.StackSetFailureTolerancePercentage != nil { + in, out := &in.StackSetFailureTolerancePercentage, &out.StackSetFailureTolerancePercentage + *out = new(int64) + **out = **in + } + if in.StackSetMaxConcurrencyCount != nil { + in, out := &in.StackSetMaxConcurrencyCount, &out.StackSetMaxConcurrencyCount + *out = new(int64) + **out = **in + } + if in.StackSetMaxConcurrencyPercentage != nil { + in, out := &in.StackSetMaxConcurrencyPercentage, &out.StackSetMaxConcurrencyPercentage + *out = new(int64) + **out = **in + } + if in.StackSetRegions != nil { + in, out := &in.StackSetRegions, &out.StackSetRegions + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisioningPreferences. +func (in *ProvisioningPreferences) DeepCopy() *ProvisioningPreferences { + if in == nil { + return nil + } + out := new(ProvisioningPreferences) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RecordDetail) DeepCopyInto(out *RecordDetail) { + *out = *in + if in.CreatedTime != nil { + in, out := &in.CreatedTime, &out.CreatedTime + *out = (*in).DeepCopy() + } + if in.LaunchRoleARN != nil { + in, out := &in.LaunchRoleARN, &out.LaunchRoleARN + *out = new(string) + **out = **in + } + if in.ProvisionedProductID != nil { + in, out := &in.ProvisionedProductID, &out.ProvisionedProductID + *out = new(string) + **out = **in + } + if in.ProvisionedProductName != nil { + in, out := &in.ProvisionedProductName, &out.ProvisionedProductName + *out = new(string) + **out = **in + } + if in.ProvisionedProductType != nil { + in, out := &in.ProvisionedProductType, &out.ProvisionedProductType + *out = new(string) + **out = **in + } + if in.RecordErrors != nil { + in, out := &in.RecordErrors, &out.RecordErrors + *out = make([]*RecordError, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RecordError) + (*in).DeepCopyInto(*out) + } + } + } + if in.RecordID != nil { + in, out := &in.RecordID, &out.RecordID + *out = new(string) + **out = **in + } + if in.RecordTags != nil { + in, out := &in.RecordTags, &out.RecordTags + *out = make([]*RecordTag, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RecordTag) + (*in).DeepCopyInto(*out) + } + } + } + if in.RecordType != nil { + in, out := &in.RecordType, &out.RecordType + *out = new(string) + **out = **in + } + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(string) + **out = **in + } + if in.UpdatedTime != nil { + in, out := &in.UpdatedTime, &out.UpdatedTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecordDetail. +func (in *RecordDetail) DeepCopy() *RecordDetail { + if in == nil { + return nil + } + out := new(RecordDetail) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RecordError) DeepCopyInto(out *RecordError) { + *out = *in + if in.Code != nil { + in, out := &in.Code, &out.Code + *out = new(string) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecordError. +func (in *RecordError) DeepCopy() *RecordError { + if in == nil { + return nil + } + out := new(RecordError) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RecordOutput) DeepCopyInto(out *RecordOutput) { + *out = *in + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.OutputKey != nil { + in, out := &in.OutputKey, &out.OutputKey + *out = new(string) + **out = **in + } + if in.OutputValue != nil { + in, out := &in.OutputValue, &out.OutputValue + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecordOutput. +func (in *RecordOutput) DeepCopy() *RecordOutput { + if in == nil { + return nil + } + out := new(RecordOutput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RecordTag) DeepCopyInto(out *RecordTag) { + *out = *in + if in.Key != nil { + in, out := &in.Key, &out.Key + *out = new(string) + **out = **in + } + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecordTag. +func (in *RecordTag) DeepCopy() *RecordTag { + if in == nil { + return nil + } + out := new(RecordTag) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceActionAssociation) DeepCopyInto(out *ServiceActionAssociation) { + *out = *in + if in.ProductID != nil { + in, out := &in.ProductID, &out.ProductID + *out = new(string) + **out = **in + } + if in.ProvisioningArtifactID != nil { + in, out := &in.ProvisioningArtifactID, &out.ProvisioningArtifactID + *out = new(string) + **out = **in + } + if in.ServiceActionID != nil { + in, out := &in.ServiceActionID, &out.ServiceActionID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceActionAssociation. +func (in *ServiceActionAssociation) DeepCopy() *ServiceActionAssociation { + if in == nil { + return nil + } + out := new(ServiceActionAssociation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceActionSummary) DeepCopyInto(out *ServiceActionSummary) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceActionSummary. +func (in *ServiceActionSummary) DeepCopy() *ServiceActionSummary { + if in == nil { + return nil + } + out := new(ServiceActionSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StackInstance) DeepCopyInto(out *StackInstance) { + *out = *in + if in.Account != nil { + in, out := &in.Account, &out.Account + *out = new(string) + **out = **in + } + if in.Region != nil { + in, out := &in.Region, &out.Region + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StackInstance. +func (in *StackInstance) DeepCopy() *StackInstance { + if in == nil { + return nil + } + out := new(StackInstance) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Tag) DeepCopyInto(out *Tag) { + *out = *in + if in.Key != nil { + in, out := &in.Key, &out.Key + *out = new(string) + **out = **in + } + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Tag. +func (in *Tag) DeepCopy() *Tag { + if in == nil { + return nil + } + out := new(Tag) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpdateProvisioningParameter) DeepCopyInto(out *UpdateProvisioningParameter) { + *out = *in + if in.Key != nil { + in, out := &in.Key, &out.Key + *out = new(string) + **out = **in + } + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateProvisioningParameter. +func (in *UpdateProvisioningParameter) DeepCopy() *UpdateProvisioningParameter { + if in == nil { + return nil + } + out := new(UpdateProvisioningParameter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpdateProvisioningPreferences) DeepCopyInto(out *UpdateProvisioningPreferences) { + *out = *in + if in.StackSetAccounts != nil { + in, out := &in.StackSetAccounts, &out.StackSetAccounts + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.StackSetFailureToleranceCount != nil { + in, out := &in.StackSetFailureToleranceCount, &out.StackSetFailureToleranceCount + *out = new(int64) + **out = **in + } + if in.StackSetFailureTolerancePercentage != nil { + in, out := &in.StackSetFailureTolerancePercentage, &out.StackSetFailureTolerancePercentage + *out = new(int64) + **out = **in + } + if in.StackSetMaxConcurrencyCount != nil { + in, out := &in.StackSetMaxConcurrencyCount, &out.StackSetMaxConcurrencyCount + *out = new(int64) + **out = **in + } + if in.StackSetMaxConcurrencyPercentage != nil { + in, out := &in.StackSetMaxConcurrencyPercentage, &out.StackSetMaxConcurrencyPercentage + *out = new(int64) + **out = **in + } + if in.StackSetRegions != nil { + in, out := &in.StackSetRegions, &out.StackSetRegions + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateProvisioningPreferences. +func (in *UpdateProvisioningPreferences) DeepCopy() *UpdateProvisioningPreferences { + if in == nil { + return nil + } + out := new(UpdateProvisioningPreferences) + in.DeepCopyInto(out) + return out +} diff --git a/apis/servicecatalog/v1alpha1/zz_generated.managed.go b/apis/servicecatalog/v1alpha1/zz_generated.managed.go new file mode 100644 index 0000000000..8913a9a28b --- /dev/null +++ b/apis/servicecatalog/v1alpha1/zz_generated.managed.go @@ -0,0 +1,81 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by angryjet. DO NOT EDIT. + +package v1alpha1 + +import xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + +// GetCondition of this ProvisionedProduct. +func (mg *ProvisionedProduct) GetCondition(ct xpv1.ConditionType) xpv1.Condition { + return mg.Status.GetCondition(ct) +} + +// GetDeletionPolicy of this ProvisionedProduct. +func (mg *ProvisionedProduct) GetDeletionPolicy() xpv1.DeletionPolicy { + return mg.Spec.DeletionPolicy +} + +// GetManagementPolicies of this ProvisionedProduct. +func (mg *ProvisionedProduct) GetManagementPolicies() xpv1.ManagementPolicies { + return mg.Spec.ManagementPolicies +} + +// GetProviderConfigReference of this ProvisionedProduct. +func (mg *ProvisionedProduct) GetProviderConfigReference() *xpv1.Reference { + return mg.Spec.ProviderConfigReference +} + +// GetPublishConnectionDetailsTo of this ProvisionedProduct. +func (mg *ProvisionedProduct) GetPublishConnectionDetailsTo() *xpv1.PublishConnectionDetailsTo { + return mg.Spec.PublishConnectionDetailsTo +} + +// GetWriteConnectionSecretToReference of this ProvisionedProduct. +func (mg *ProvisionedProduct) GetWriteConnectionSecretToReference() *xpv1.SecretReference { + return mg.Spec.WriteConnectionSecretToReference +} + +// SetConditions of this ProvisionedProduct. +func (mg *ProvisionedProduct) SetConditions(c ...xpv1.Condition) { + mg.Status.SetConditions(c...) +} + +// SetDeletionPolicy of this ProvisionedProduct. +func (mg *ProvisionedProduct) SetDeletionPolicy(r xpv1.DeletionPolicy) { + mg.Spec.DeletionPolicy = r +} + +// SetManagementPolicies of this ProvisionedProduct. +func (mg *ProvisionedProduct) SetManagementPolicies(r xpv1.ManagementPolicies) { + mg.Spec.ManagementPolicies = r +} + +// SetProviderConfigReference of this ProvisionedProduct. +func (mg *ProvisionedProduct) SetProviderConfigReference(r *xpv1.Reference) { + mg.Spec.ProviderConfigReference = r +} + +// SetPublishConnectionDetailsTo of this ProvisionedProduct. +func (mg *ProvisionedProduct) SetPublishConnectionDetailsTo(r *xpv1.PublishConnectionDetailsTo) { + mg.Spec.PublishConnectionDetailsTo = r +} + +// SetWriteConnectionSecretToReference of this ProvisionedProduct. +func (mg *ProvisionedProduct) SetWriteConnectionSecretToReference(r *xpv1.SecretReference) { + mg.Spec.WriteConnectionSecretToReference = r +} diff --git a/apis/servicecatalog/v1alpha1/zz_generated.managedlist.go b/apis/servicecatalog/v1alpha1/zz_generated.managedlist.go new file mode 100644 index 0000000000..8454d50a75 --- /dev/null +++ b/apis/servicecatalog/v1alpha1/zz_generated.managedlist.go @@ -0,0 +1,30 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by angryjet. DO NOT EDIT. + +package v1alpha1 + +import resource "github.com/crossplane/crossplane-runtime/pkg/resource" + +// GetItems of this ProvisionedProductList. +func (l *ProvisionedProductList) GetItems() []resource.Managed { + items := make([]resource.Managed, len(l.Items)) + for i := range l.Items { + items[i] = &l.Items[i] + } + return items +} diff --git a/apis/servicecatalog/v1alpha1/zz_groupversion_info.go b/apis/servicecatalog/v1alpha1/zz_groupversion_info.go new file mode 100644 index 0000000000..bf2b38a88b --- /dev/null +++ b/apis/servicecatalog/v1alpha1/zz_groupversion_info.go @@ -0,0 +1,41 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +// Package type metadata. +const ( + CRDGroup = "servicecatalog.aws.crossplane.io" + CRDVersion = "v1alpha1" +) + +var ( + // GroupVersion is the API Group Version used to register the objects + GroupVersion = schema.GroupVersion{Group: CRDGroup, Version: CRDVersion} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/apis/servicecatalog/v1alpha1/zz_provisioned_product.go b/apis/servicecatalog/v1alpha1/zz_provisioned_product.go new file mode 100644 index 0000000000..f378cee196 --- /dev/null +++ b/apis/servicecatalog/v1alpha1/zz_provisioned_product.go @@ -0,0 +1,193 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +import ( + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// ProvisionedProductParameters defines the desired state of ProvisionedProduct +type ProvisionedProductParameters struct { + // Region is which region the ProvisionedProduct will be created. + // +kubebuilder:validation:Required + Region string `json:"region"` + // The language code. + // + // * jp - Japanese + // + // * zh - Chinese + AcceptLanguage *string `json:"acceptLanguage,omitempty"` + // Passed to CloudFormation. The SNS topic ARNs to which to publish stack-related + // events. + NotificationARNs []*string `json:"notificationARNs,omitempty"` + // The path identifier of the product. This value is optional if the product + // has a default path, and required if the product has more than one path. To + // list the paths for a product, use ListLaunchPaths. You must provide the name + // or ID, but not both. + PathID *string `json:"pathID,omitempty"` + // The name of the path. You must provide the name or ID, but not both. + PathName *string `json:"pathName,omitempty"` + // The product identifier. You must provide the name or ID, but not both. + ProductID *string `json:"productID,omitempty"` + // The name of the product. You must provide the name or ID, but not both. + ProductName *string `json:"productName,omitempty"` + // The identifier of the provisioning artifact. You must provide the name or + // ID, but not both. + ProvisioningArtifactID *string `json:"provisioningArtifactID,omitempty"` + // The name of the provisioning artifact. You must provide the name or ID, but + // not both. + ProvisioningArtifactName *string `json:"provisioningArtifactName,omitempty"` + // Parameters specified by the administrator that are required for provisioning + // the product. + ProvisioningParameters []*ProvisioningParameter `json:"provisioningParameters,omitempty"` + // An object that contains information about the provisioning preferences for + // a stack set. + ProvisioningPreferences *ProvisioningPreferences `json:"provisioningPreferences,omitempty"` + // One or more tags. + Tags []*Tag `json:"tags,omitempty"` + CustomProvisionedProductParameters `json:",inline"` +} + +// ProvisionedProductSpec defines the desired state of ProvisionedProduct +type ProvisionedProductSpec struct { + xpv1.ResourceSpec `json:",inline"` + ForProvider ProvisionedProductParameters `json:"forProvider"` +} + +// ProvisionedProductObservation defines the observed state of ProvisionedProduct +type ProvisionedProductObservation struct { + // The ARN of the provisioned product. + ARN *string `json:"arn,omitempty"` + // The UTC time stamp of the creation time. + CreatedTime *metav1.Time `json:"createdTime,omitempty"` + // The product identifier. For example, prod-abcdzk7xy33qa. + LastProductID *string `json:"lastProductID,omitempty"` + // The identifier of the provisioning artifact. For example, pa-4abcdjnxjj6ne. + LastProvisioningArtifactID *string `json:"lastProvisioningArtifactID,omitempty"` + + LastProvisioningParameters []*ProvisioningParameter `json:"lastProvisioningParameters,omitempty"` + // The record identifier of the last request performed on this provisioned product + // of the following types: + // + // * ProvisionProduct + // + // * UpdateProvisionedProduct + // + // * ExecuteProvisionedProductPlan + // + // * TerminateProvisionedProduct + LastProvisioningRecordID *string `json:"lastProvisioningRecordID,omitempty"` + // The ARN of the launch role associated with the provisioned product. + LaunchRoleARN *string `json:"launchRoleARN,omitempty"` + + Outputs map[string]*RecordOutput `json:"outputs,omitempty"` + // The identifier of the provisioned product. + ProvisionedProductID *string `json:"provisionedProductID,omitempty"` + // The user-friendly name of the provisioned product. + ProvisionedProductName *string `json:"provisionedProductName,omitempty"` + // The type of provisioned product. The supported values are CFN_STACK, CFN_STACKSET, + // TERRAFORM_OPEN_SOURCE, and TERRAFORM_CLOUD. + ProvisionedProductType *string `json:"provisionedProductType,omitempty"` + // The errors that occurred. + RecordErrors []*RecordError `json:"recordErrors,omitempty"` + // The identifier of the record. + RecordID *string `json:"recordID,omitempty"` + // One or more tags. + RecordTags []*RecordTag `json:"recordTags,omitempty"` + // The record type. + // + // * PROVISION_PRODUCT + // + // * UPDATE_PROVISIONED_PRODUCT + // + // * TERMINATE_PROVISIONED_PRODUCT + RecordType *string `json:"recordType,omitempty"` + // The current status of the provisioned product. + // + // * AVAILABLE - Stable state, ready to perform any operation. The most recent + // operation succeeded and completed. + // + // * UNDER_CHANGE - Transitive state. Operations performed might not have + // valid results. Wait for an AVAILABLE status before performing operations. + // + // * TAINTED - Stable state, ready to perform any operation. The stack has + // completed the requested operation but is not exactly what was requested. + // For example, a request to update to a new version failed and the stack + // rolled back to the current version. + // + // * ERROR - An unexpected error occurred. The provisioned product exists + // but the stack is not running. For example, CloudFormation received a parameter + // value that was not valid and could not launch the stack. + // + // * PLAN_IN_PROGRESS - Transitive state. The plan operations were performed + // to provision a new product, but resources have not yet been created. After + // reviewing the list of resources to be created, execute the plan. Wait + // for an AVAILABLE status before performing operations. + Status *string `json:"status,omitempty"` + // The current status message of the provisioned product. + StatusMessage *string `json:"statusMessage,omitempty"` + // The time when the record was last updated. + UpdatedTime *metav1.Time `json:"updatedTime,omitempty"` +} + +// ProvisionedProductStatus defines the observed state of ProvisionedProduct. +type ProvisionedProductStatus struct { + xpv1.ResourceStatus `json:",inline"` + AtProvider ProvisionedProductObservation `json:"atProvider,omitempty"` +} + +// +kubebuilder:object:root=true + +// ProvisionedProduct is the Schema for the ProvisionedProducts API +// +kubebuilder:printcolumn:name="READY",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status" +// +kubebuilder:printcolumn:name="SYNCED",type="string",JSONPath=".status.conditions[?(@.type=='Synced')].status" +// +kubebuilder:printcolumn:name="EXTERNAL-NAME",type="string",JSONPath=".metadata.annotations.crossplane\\.io/external-name" +// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +// +kubebuilder:resource:scope=Cluster,categories={crossplane,managed,aws} +type ProvisionedProduct struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec ProvisionedProductSpec `json:"spec"` + Status ProvisionedProductStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// ProvisionedProductList contains a list of ProvisionedProducts +type ProvisionedProductList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ProvisionedProduct `json:"items"` +} + +// Repository type metadata. +var ( + ProvisionedProductKind = "ProvisionedProduct" + ProvisionedProductGroupKind = schema.GroupKind{Group: CRDGroup, Kind: ProvisionedProductKind}.String() + ProvisionedProductKindAPIVersion = ProvisionedProductKind + "." + GroupVersion.String() + ProvisionedProductGroupVersionKind = GroupVersion.WithKind(ProvisionedProductKind) +) + +func init() { + SchemeBuilder.Register(&ProvisionedProduct{}, &ProvisionedProductList{}) +} diff --git a/apis/servicecatalog/v1alpha1/zz_types.go b/apis/servicecatalog/v1alpha1/zz_types.go new file mode 100644 index 0000000000..5d5e870a6c --- /dev/null +++ b/apis/servicecatalog/v1alpha1/zz_types.go @@ -0,0 +1,324 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Hack to avoid import errors during build... +var ( + _ = &metav1.Time{} +) + +// +kubebuilder:skipversion +type CloudWatchDashboard struct { + Name *string `json:"name,omitempty"` +} + +// +kubebuilder:skipversion +type ConstraintDetail struct { + ConstraintID *string `json:"constraintID,omitempty"` + + Owner *string `json:"owner,omitempty"` + + PortfolioID *string `json:"portfolioID,omitempty"` + + ProductID *string `json:"productID,omitempty"` +} + +// +kubebuilder:skipversion +type FailedServiceActionAssociation struct { + ProductID *string `json:"productID,omitempty"` + + ProvisioningArtifactID *string `json:"provisioningArtifactID,omitempty"` + + ServiceActionID *string `json:"serviceActionID,omitempty"` +} + +// +kubebuilder:skipversion +type LastSync struct { + LastSuccessfulSyncProvisioningArtifactID *string `json:"lastSuccessfulSyncProvisioningArtifactID,omitempty"` +} + +// +kubebuilder:skipversion +type LaunchPath struct { + ID *string `json:"id,omitempty"` +} + +// +kubebuilder:skipversion +type LaunchPathSummary struct { + ID *string `json:"id,omitempty"` + + Tags []*Tag `json:"tags,omitempty"` +} + +// +kubebuilder:skipversion +type PortfolioDetail struct { + DisplayName *string `json:"displayName,omitempty"` + + ID *string `json:"id,omitempty"` +} + +// +kubebuilder:skipversion +type PortfolioShareDetail struct { + PrincipalID *string `json:"principalID,omitempty"` +} + +// +kubebuilder:skipversion +type ProductViewDetail struct { + CreatedTime *metav1.Time `json:"createdTime,omitempty"` +} + +// +kubebuilder:skipversion +type ProductViewSummary struct { + ID *string `json:"id,omitempty"` + + Name *string `json:"name,omitempty"` + + ProductID *string `json:"productID,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisionedProductAttribute struct { + ARN *string `json:"arn,omitempty"` + + CreatedTime *metav1.Time `json:"createdTime,omitempty"` + + ID *string `json:"id,omitempty"` + + IdempotencyToken *string `json:"idempotencyToken,omitempty"` + + LastProvisioningRecordID *string `json:"lastProvisioningRecordID,omitempty"` + + LastRecordID *string `json:"lastRecordID,omitempty"` + + LastSuccessfulProvisioningRecordID *string `json:"lastSuccessfulProvisioningRecordID,omitempty"` + + Name *string `json:"name,omitempty"` + + ProductID *string `json:"productID,omitempty"` + + ProductName *string `json:"productName,omitempty"` + + ProvisioningArtifactID *string `json:"provisioningArtifactID,omitempty"` + + ProvisioningArtifactName *string `json:"provisioningArtifactName,omitempty"` + + Status *string `json:"status,omitempty"` + + StatusMessage *string `json:"statusMessage,omitempty"` + + Tags []*Tag `json:"tags,omitempty"` + + Type *string `json:"type_,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisionedProductDetail struct { + ARN *string `json:"arn,omitempty"` + + CreatedTime *metav1.Time `json:"createdTime,omitempty"` + + ID *string `json:"id,omitempty"` + + IdempotencyToken *string `json:"idempotencyToken,omitempty"` + + LastProvisioningRecordID *string `json:"lastProvisioningRecordID,omitempty"` + + LastRecordID *string `json:"lastRecordID,omitempty"` + + LastSuccessfulProvisioningRecordID *string `json:"lastSuccessfulProvisioningRecordID,omitempty"` + + LaunchRoleARN *string `json:"launchRoleARN,omitempty"` + + Name *string `json:"name,omitempty"` + + ProductID *string `json:"productID,omitempty"` + + ProvisioningArtifactID *string `json:"provisioningArtifactID,omitempty"` + + Status *string `json:"status,omitempty"` + + StatusMessage *string `json:"statusMessage,omitempty"` + + Type *string `json:"type_,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisioningArtifact struct { + ID *string `json:"id,omitempty"` + + Name *string `json:"name,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisioningArtifactDetail struct { + Description *string `json:"description,omitempty"` + + ID *string `json:"id,omitempty"` + + Name *string `json:"name,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisioningArtifactParameter struct { + Description *string `json:"description,omitempty"` + + ParameterKey *string `json:"parameterKey,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisioningArtifactPreferences struct { + StackSetAccounts []*string `json:"stackSetAccounts,omitempty"` + + StackSetRegions []*string `json:"stackSetRegions,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisioningArtifactProperties struct { + Name *string `json:"name,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisioningArtifactSummary struct { + ID *string `json:"id,omitempty"` + + Name *string `json:"name,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisioningParameter struct { + Key *string `json:"key,omitempty"` + + Value *string `json:"value,omitempty"` +} + +// +kubebuilder:skipversion +type ProvisioningPreferences struct { + StackSetAccounts []*string `json:"stackSetAccounts,omitempty"` + + StackSetFailureToleranceCount *int64 `json:"stackSetFailureToleranceCount,omitempty"` + + StackSetFailureTolerancePercentage *int64 `json:"stackSetFailureTolerancePercentage,omitempty"` + + StackSetMaxConcurrencyCount *int64 `json:"stackSetMaxConcurrencyCount,omitempty"` + + StackSetMaxConcurrencyPercentage *int64 `json:"stackSetMaxConcurrencyPercentage,omitempty"` + + StackSetRegions []*string `json:"stackSetRegions,omitempty"` +} + +// +kubebuilder:skipversion +type RecordDetail struct { + CreatedTime *metav1.Time `json:"createdTime,omitempty"` + + LaunchRoleARN *string `json:"launchRoleARN,omitempty"` + + ProvisionedProductID *string `json:"provisionedProductID,omitempty"` + + ProvisionedProductName *string `json:"provisionedProductName,omitempty"` + + ProvisionedProductType *string `json:"provisionedProductType,omitempty"` + + RecordErrors []*RecordError `json:"recordErrors,omitempty"` + + RecordID *string `json:"recordID,omitempty"` + + RecordTags []*RecordTag `json:"recordTags,omitempty"` + + RecordType *string `json:"recordType,omitempty"` + + Status *string `json:"status,omitempty"` + + UpdatedTime *metav1.Time `json:"updatedTime,omitempty"` +} + +// +kubebuilder:skipversion +type RecordError struct { + Code *string `json:"code,omitempty"` + + Description *string `json:"description,omitempty"` +} + +// +kubebuilder:skipversion +type RecordOutput struct { + Description *string `json:"description,omitempty"` + + OutputKey *string `json:"outputKey,omitempty"` + + OutputValue *string `json:"outputValue,omitempty"` +} + +// +kubebuilder:skipversion +type RecordTag struct { + Key *string `json:"key,omitempty"` + + Value *string `json:"value,omitempty"` +} + +// +kubebuilder:skipversion +type ServiceActionAssociation struct { + ProductID *string `json:"productID,omitempty"` + + ProvisioningArtifactID *string `json:"provisioningArtifactID,omitempty"` + + ServiceActionID *string `json:"serviceActionID,omitempty"` +} + +// +kubebuilder:skipversion +type ServiceActionSummary struct { + ID *string `json:"id,omitempty"` +} + +// +kubebuilder:skipversion +type StackInstance struct { + Account *string `json:"account,omitempty"` + + Region *string `json:"region,omitempty"` +} + +// +kubebuilder:skipversion +type Tag struct { + Key *string `json:"key,omitempty"` + + Value *string `json:"value,omitempty"` +} + +// +kubebuilder:skipversion +type UpdateProvisioningParameter struct { + Key *string `json:"key,omitempty"` + + Value *string `json:"value,omitempty"` +} + +// +kubebuilder:skipversion +type UpdateProvisioningPreferences struct { + StackSetAccounts []*string `json:"stackSetAccounts,omitempty"` + + StackSetFailureToleranceCount *int64 `json:"stackSetFailureToleranceCount,omitempty"` + + StackSetFailureTolerancePercentage *int64 `json:"stackSetFailureTolerancePercentage,omitempty"` + + StackSetMaxConcurrencyCount *int64 `json:"stackSetMaxConcurrencyCount,omitempty"` + + StackSetMaxConcurrencyPercentage *int64 `json:"stackSetMaxConcurrencyPercentage,omitempty"` + + StackSetRegions []*string `json:"stackSetRegions,omitempty"` +} diff --git a/examples/servicecatalog/provisionedproduct.yaml b/examples/servicecatalog/provisionedproduct.yaml new file mode 100644 index 0000000000..b6e4a5d2bd --- /dev/null +++ b/examples/servicecatalog/provisionedproduct.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: servicecatalog.aws.crossplane.io/v1alpha1 +kind: ProvisionedProduct +metadata: + name: awesome-s3-bucket +spec: + forProvider: + region: us-east-1 + productName: s3 + provisioningArtifactName: v1.0.0 + provisioningParameters: + - key: BucketName + value: "awesome-s3-bucket" + - key: BucketVersioning + value: "enabled" + - key: TransferAcceleration + value: "suspended" + - key: EncryptionType + value: "SSE-KMS" + - key: KMSArn + value: "none" + providerConfigRef: + name: provider-aws diff --git a/go.mod b/go.mod index 9bb88611f2..b5b9dfa6f9 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,12 @@ go 1.21 require ( github.com/aws-controllers-k8s/code-generator v0.26.1 github.com/aws/aws-sdk-go v1.44.334 - github.com/aws/aws-sdk-go-v2 v1.17.3 + github.com/aws/aws-sdk-go-v2 v1.19.0 github.com/aws/aws-sdk-go-v2/config v1.11.1 github.com/aws/aws-sdk-go-v2/credentials v1.6.5 github.com/aws/aws-sdk-go-v2/service/acm v1.16.0 github.com/aws/aws-sdk-go-v2/service/acmpca v1.12.0 + github.com/aws/aws-sdk-go-v2/service/cloudformation v1.30.1 github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.17.3 github.com/aws/aws-sdk-go-v2/service/ec2 v1.26.0 github.com/aws/aws-sdk-go-v2/service/ecr v1.12.0 @@ -34,6 +35,7 @@ require ( github.com/go-ini/ini v1.67.0 github.com/golang/mock v1.5.0 github.com/google/go-cmp v0.6.0 + github.com/google/uuid v1.3.1 github.com/jmattheis/goverter v0.18.0 github.com/mattbaird/jsonpatch v0.0.0-20200820163806-098863c1fc24 github.com/onsi/gomega v1.27.10 @@ -57,8 +59,8 @@ require ( github.com/aws-controllers-k8s/pkg v0.0.4 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.0.0 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.8.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.5.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21 // indirect @@ -88,7 +90,6 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.1 // indirect github.com/iancoleman/strcase v0.2.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index cfe2c7953b..04ff392673 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,9 @@ github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX github.com/aws/aws-sdk-go-v2 v1.16.7/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k= github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw= -github.com/aws/aws-sdk-go-v2 v1.17.3 h1:shN7NlnVzvDUgPQ+1rLMSxY8OWRNDRYtiqe0p/PgrhY= github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.19.0 h1:klAT+y3pGFBU/qVf1uzwttpBbiuozJYWzNLHioyDJ+k= +github.com/aws/aws-sdk-go-v2 v1.19.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.0.0 h1:yVUAwvJC/0WNPbyl0nA3j1L6CW1CN8wBubCRqtG7JLI= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.0.0/go.mod h1:Xn6sxgRuIDflLRJFj5Ev7UxABIkNbccFPV/p8itDReM= github.com/aws/aws-sdk-go-v2/config v1.11.1 h1:KXSjb7ZMLRtjxClFptukTYibiOqJS9NwBO+9WD3UMto= @@ -115,21 +116,25 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0p github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14/go.mod h1:kdjrMwHwrC3+FsKhNcCMJ7tUVj/8uSD5CZXeQ4wV6fM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 h1:I3cakv2Uy1vNmmhRQmFptYDxOvBnwCdNwyw63N0RaRU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 h1:hMUCiE3Zi5AHrRNGf5j985u0WyqI6r2NULhUfo0N/No= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35/go.mod h1:ipR5PvpSPqIqL5Mi82BxLnfMkHVbmco8kUwO2xrCi0M= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.0.2/go.mod h1:xT4XX6w5Sa3dhg50JrYyy3e4WPYo/+WjY/BXtqXVunU= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 h1:5NbbMrIzmUn/TXFqAle6mgrH5m9cOvMLRGL7pnG8tRE= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 h1:yOpYx+FTBdpk/g+sBU6Cb1H0U/TLEcYYp66mYqsPpcc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29/go.mod h1:M/eUABlDbw2uVrdAn+UsI6M727qp2fxkp8K0ejcBDUY= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.2 h1:IQup8Q6lorXeiA/rK72PeToWoWK8h7VAPgHNWdSrtgE= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.2/go.mod h1:VITe/MdW6EMXPb0o0txu/fsonXbMHUU2OC2Qp7ivU4o= github.com/aws/aws-sdk-go-v2/service/acm v1.16.0 h1:puhPHuHlBJM6S5fTM4W1WI8vM/zjmqdyy0Gzgx9NUe8= github.com/aws/aws-sdk-go-v2/service/acm v1.16.0/go.mod h1:LR3qi788mHzUYfv2MNs+xwbvig6QlrPYVOhKv/Ae5M0= github.com/aws/aws-sdk-go-v2/service/acmpca v1.12.0 h1:JL8J0ji+JK0t7JUUNtZg8atEUThdzk0KCgXY4a+7UXE= github.com/aws/aws-sdk-go-v2/service/acmpca v1.12.0/go.mod h1:AcCVrQKCGEWqfC1837nKJW2H5GdYseVfmGwhDjtcX3M= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.30.1 h1:MHKSdt+ECxOWD98MYj/Ocy4GS8GgAjgEDSPaiTaXP6U= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.30.1/go.mod h1:laKFhtn8EH6gcPl7KEQ4kcuSYcQF1tqUm82ENxMwlMk= github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.17.3 h1:xtwjqxVDO9tAmoUXVfJyMKFLVJlosjKrFLLuW4V8VO0= github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.17.3/go.mod h1:flSX+qf2r/mLgwTavyT/Gjs4dFtHcBmjMcVp/AqpSgc= github.com/aws/aws-sdk-go-v2/service/ec2 v1.26.0 h1:Q++veaxis1Dg7is9yi+aEPsIBRAgdkUxoIvyud7jOyo= diff --git a/package/crds/servicecatalog.aws.crossplane.io_provisionedproducts.yaml b/package/crds/servicecatalog.aws.crossplane.io_provisionedproducts.yaml new file mode 100644 index 0000000000..2601e7835e --- /dev/null +++ b/package/crds/servicecatalog.aws.crossplane.io_provisionedproducts.yaml @@ -0,0 +1,480 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: provisionedproducts.servicecatalog.aws.crossplane.io +spec: + group: servicecatalog.aws.crossplane.io + names: + categories: + - crossplane + - managed + - aws + kind: ProvisionedProduct + listKind: ProvisionedProductList + plural: provisionedproducts + singular: provisionedproduct + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: READY + type: string + - jsonPath: .status.conditions[?(@.type=='Synced')].status + name: SYNCED + type: string + - jsonPath: .metadata.annotations.crossplane\.io/external-name + name: EXTERNAL-NAME + type: string + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: ProvisionedProduct is the Schema for the ProvisionedProducts + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ProvisionedProductSpec defines the desired state of ProvisionedProduct + properties: + deletionPolicy: + default: Delete + description: 'DeletionPolicy specifies what will happen to the underlying + external when this managed resource is deleted - either "Delete" + or "Orphan" the external resource. This field is planned to be deprecated + in favor of the ManagementPolicies field in a future release. Currently, + both could be set independently and non-default values would be + honored if the feature flag is enabled. See the design doc for more + information: https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223' + enum: + - Orphan + - Delete + type: string + forProvider: + description: ProvisionedProductParameters defines the desired state + of ProvisionedProduct + properties: + acceptLanguage: + description: "The language code. \n * jp - Japanese \n * zh - + Chinese" + type: string + notificationARNs: + description: Passed to CloudFormation. The SNS topic ARNs to which + to publish stack-related events. + items: + type: string + type: array + pathID: + description: The path identifier of the product. This value is + optional if the product has a default path, and required if + the product has more than one path. To list the paths for a + product, use ListLaunchPaths. You must provide the name or ID, + but not both. + type: string + pathName: + description: The name of the path. You must provide the name or + ID, but not both. + type: string + productID: + description: The product identifier. You must provide the name + or ID, but not both. + type: string + productName: + description: The name of the product. You must provide the name + or ID, but not both. + type: string + provisioningArtifactID: + description: The identifier of the provisioning artifact. You + must provide the name or ID, but not both. + type: string + provisioningArtifactName: + description: The name of the provisioning artifact. You must provide + the name or ID, but not both. + type: string + provisioningParameters: + description: Parameters specified by the administrator that are + required for provisioning the product. + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + provisioningPreferences: + description: An object that contains information about the provisioning + preferences for a stack set. + properties: + stackSetAccounts: + items: + type: string + type: array + stackSetFailureToleranceCount: + format: int64 + type: integer + stackSetFailureTolerancePercentage: + format: int64 + type: integer + stackSetMaxConcurrencyCount: + format: int64 + type: integer + stackSetMaxConcurrencyPercentage: + format: int64 + type: integer + stackSetRegions: + items: + type: string + type: array + type: object + region: + description: Region is which region the ProvisionedProduct will + be created. + type: string + tags: + description: One or more tags. + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + required: + - region + type: object + managementPolicies: + default: + - '*' + description: 'THIS IS A BETA FIELD. It is on by default but can be + opted out through a Crossplane feature flag. ManagementPolicies + specify the array of actions Crossplane is allowed to take on the + managed and external resources. This field is planned to replace + the DeletionPolicy field in a future release. Currently, both could + be set independently and non-default values would be honored if + the feature flag is enabled. If both are custom, the DeletionPolicy + field will be ignored. See the design doc for more information: + https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223 + and this one: https://github.com/crossplane/crossplane/blob/444267e84783136daa93568b364a5f01228cacbe/design/one-pager-ignore-changes.md' + items: + description: A ManagementAction represents an action that the Crossplane + controllers can take on an external resource. + enum: + - Observe + - Create + - Update + - Delete + - LateInitialize + - '*' + type: string + type: array + providerConfigRef: + default: + name: default + description: ProviderConfigReference specifies how the provider that + will be used to create, observe, update, and delete this managed + resource should be configured. + properties: + name: + description: Name of the referenced object. + type: string + policy: + description: Policies for referencing. + properties: + resolution: + default: Required + description: Resolution specifies whether resolution of this + reference is required. The default is 'Required', which + means the reconcile will fail if the reference cannot be + resolved. 'Optional' means this reference will be a no-op + if it cannot be resolved. + enum: + - Required + - Optional + type: string + resolve: + description: Resolve specifies when this reference should + be resolved. The default is 'IfNotPresent', which will attempt + to resolve the reference only when the corresponding field + is not present. Use 'Always' to resolve the reference on + every reconcile. + enum: + - Always + - IfNotPresent + type: string + type: object + required: + - name + type: object + publishConnectionDetailsTo: + description: PublishConnectionDetailsTo specifies the connection secret + config which contains a name, metadata and a reference to secret + store config to which any connection details for this managed resource + should be written. Connection details frequently include the endpoint, + username, and password required to connect to the managed resource. + properties: + configRef: + default: + name: default + description: SecretStoreConfigRef specifies which secret store + config should be used for this ConnectionSecret. + properties: + name: + description: Name of the referenced object. + type: string + policy: + description: Policies for referencing. + properties: + resolution: + default: Required + description: Resolution specifies whether resolution of + this reference is required. The default is 'Required', + which means the reconcile will fail if the reference + cannot be resolved. 'Optional' means this reference + will be a no-op if it cannot be resolved. + enum: + - Required + - Optional + type: string + resolve: + description: Resolve specifies when this reference should + be resolved. The default is 'IfNotPresent', which will + attempt to resolve the reference only when the corresponding + field is not present. Use 'Always' to resolve the reference + on every reconcile. + enum: + - Always + - IfNotPresent + type: string + type: object + required: + - name + type: object + metadata: + description: Metadata is the metadata for connection secret. + properties: + annotations: + additionalProperties: + type: string + description: Annotations are the annotations to be added to + connection secret. - For Kubernetes secrets, this will be + used as "metadata.annotations". - It is up to Secret Store + implementation for others store types. + type: object + labels: + additionalProperties: + type: string + description: Labels are the labels/tags to be added to connection + secret. - For Kubernetes secrets, this will be used as "metadata.labels". + - It is up to Secret Store implementation for others store + types. + type: object + type: + description: Type is the SecretType for the connection secret. + - Only valid for Kubernetes Secret Stores. + type: string + type: object + name: + description: Name is the name of the connection secret. + type: string + required: + - name + type: object + writeConnectionSecretToRef: + description: WriteConnectionSecretToReference specifies the namespace + and name of a Secret to which any connection details for this managed + resource should be written. Connection details frequently include + the endpoint, username, and password required to connect to the + managed resource. This field is planned to be replaced in a future + release in favor of PublishConnectionDetailsTo. Currently, both + could be set independently and connection details would be published + to both without affecting each other. + properties: + name: + description: Name of the secret. + type: string + namespace: + description: Namespace of the secret. + type: string + required: + - name + - namespace + type: object + required: + - forProvider + type: object + status: + description: ProvisionedProductStatus defines the observed state of ProvisionedProduct. + properties: + atProvider: + description: ProvisionedProductObservation defines the observed state + of ProvisionedProduct + properties: + arn: + description: The ARN of the provisioned product. + type: string + createdTime: + description: The UTC time stamp of the creation time. + format: date-time + type: string + lastProductID: + description: The product identifier. For example, prod-abcdzk7xy33qa. + type: string + lastProvisioningArtifactID: + description: The identifier of the provisioning artifact. For + example, pa-4abcdjnxjj6ne. + type: string + lastProvisioningParameters: + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + lastProvisioningRecordID: + description: "The record identifier of the last request performed + on this provisioned product of the following types: \n * ProvisionProduct + \n * UpdateProvisionedProduct \n * ExecuteProvisionedProductPlan + \n * TerminateProvisionedProduct" + type: string + launchRoleARN: + description: The ARN of the launch role associated with the provisioned + product. + type: string + outputs: + additionalProperties: + properties: + description: + type: string + outputKey: + type: string + outputValue: + type: string + type: object + type: object + provisionedProductID: + description: The identifier of the provisioned product. + type: string + provisionedProductName: + description: The user-friendly name of the provisioned product. + type: string + provisionedProductType: + description: The type of provisioned product. The supported values + are CFN_STACK, CFN_STACKSET, TERRAFORM_OPEN_SOURCE, and TERRAFORM_CLOUD. + type: string + recordErrors: + description: The errors that occurred. + items: + properties: + code: + type: string + description: + type: string + type: object + type: array + recordID: + description: The identifier of the record. + type: string + recordTags: + description: One or more tags. + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + recordType: + description: "The record type. \n * PROVISION_PRODUCT \n * UPDATE_PROVISIONED_PRODUCT + \n * TERMINATE_PROVISIONED_PRODUCT" + type: string + status: + description: "The current status of the provisioned product. \n + * AVAILABLE - Stable state, ready to perform any operation. + The most recent operation succeeded and completed. \n * UNDER_CHANGE + - Transitive state. Operations performed might not have valid + results. Wait for an AVAILABLE status before performing operations. + \n * TAINTED - Stable state, ready to perform any operation. + The stack has completed the requested operation but is not exactly + what was requested. For example, a request to update to a new + version failed and the stack rolled back to the current version. + \n * ERROR - An unexpected error occurred. The provisioned product + exists but the stack is not running. For example, CloudFormation + received a parameter value that was not valid and could not + launch the stack. \n * PLAN_IN_PROGRESS - Transitive state. + The plan operations were performed to provision a new product, + but resources have not yet been created. After reviewing the + list of resources to be created, execute the plan. Wait for + an AVAILABLE status before performing operations." + type: string + statusMessage: + description: The current status message of the provisioned product. + type: string + updatedTime: + description: The time when the record was last updated. + format: date-time + type: string + type: object + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown? + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/pkg/clients/servicecatalog/fake/fake.go b/pkg/clients/servicecatalog/fake/fake.go new file mode 100644 index 0000000000..1d6a10d298 --- /dev/null +++ b/pkg/clients/servicecatalog/fake/fake.go @@ -0,0 +1,69 @@ +/* +Copyright 2023 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fake + +import ( + "context" + + cfsdkv2types "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + "github.com/aws/aws-sdk-go/aws/request" + svcsdk "github.com/aws/aws-sdk-go/service/servicecatalog" + + clientset "github.com/crossplane-contrib/provider-aws/pkg/clients/servicecatalog" +) + +var _ clientset.Client = (*MockCustomServiceCatalogClient)(nil) + +// MockCustomServiceCatalogClient is a type that implements all the methods for Client interface +type MockCustomServiceCatalogClient struct { + MockGetCloudformationStackParameters func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) + MockGetProvisionedProductOutputs func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) + MockDescribeRecord func(describeRecordInput *svcsdk.DescribeRecordInput) (*svcsdk.DescribeRecordOutput, error) + MockDescribeProduct func(*svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) + MockDescribeProvisioningArtifact func(*svcsdk.DescribeProvisioningArtifactInput) (*svcsdk.DescribeProvisioningArtifactOutput, error) + MockUpdateProvisionedProductWithContext func(context.Context, *svcsdk.UpdateProvisionedProductInput, ...request.Option) (*svcsdk.UpdateProvisionedProductOutput, error) +} + +// GetCloudformationStackParameters mocks GetCloudformationStackParameters method +func (m *MockCustomServiceCatalogClient) GetCloudformationStackParameters(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return m.MockGetCloudformationStackParameters(provisionedProductOutputs) +} + +// GetProvisionedProductOutputs mocks GetProvisionedProductOutputs method +func (m *MockCustomServiceCatalogClient) GetProvisionedProductOutputs(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return m.MockGetProvisionedProductOutputs(getPPInput) +} + +// DescribeRecord mocks DescribeRecord method +func (m *MockCustomServiceCatalogClient) DescribeRecord(describeRecordInput *svcsdk.DescribeRecordInput) (*svcsdk.DescribeRecordOutput, error) { + return m.MockDescribeRecord(describeRecordInput) +} + +// DescribeProvisioningArtifact mocks DescribeProvisioningArtifact method +func (m *MockCustomServiceCatalogClient) DescribeProvisioningArtifact(input *svcsdk.DescribeProvisioningArtifactInput) (*svcsdk.DescribeProvisioningArtifactOutput, error) { + return m.MockDescribeProvisioningArtifact(input) +} + +// UpdateProvisionedProductWithContext mocks UpdateProvisionedProductWithContext method +func (m *MockCustomServiceCatalogClient) UpdateProvisionedProductWithContext(ctx context.Context, input *svcsdk.UpdateProvisionedProductInput, opts ...request.Option) (*svcsdk.UpdateProvisionedProductOutput, error) { + return m.MockUpdateProvisionedProductWithContext(ctx, input, opts...) +} + +// DescribeProduct mocks DescribeProduct method +func (m *MockCustomServiceCatalogClient) DescribeProduct(input *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return m.MockDescribeProduct(input) +} diff --git a/pkg/clients/servicecatalog/servicecatalog.go b/pkg/clients/servicecatalog/servicecatalog.go new file mode 100644 index 0000000000..ff4913b3be --- /dev/null +++ b/pkg/clients/servicecatalog/servicecatalog.go @@ -0,0 +1,82 @@ +/* +Copyright 2023 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package servicecatalog + +import ( + "context" + "errors" + + cfsdkv2 "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfsdkv2types "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + svcsdk "github.com/aws/aws-sdk-go/service/servicecatalog" + svcsdkapi "github.com/aws/aws-sdk-go/service/servicecatalog/servicecatalogiface" +) + +const ( + cloudformationArnOutputName = "CloudformationStackARN" + errCloudformationStackArnNotFound = "provisioned product outputs do not contain cloudformation stack arn" +) + +// Client represents a custom client to retrieve information from AWS related to service catalog or cloud formation as resource behind the provisioned product +type Client interface { + GetCloudformationStackParameters([]*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) + GetProvisionedProductOutputs(*svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) + DescribeRecord(*svcsdk.DescribeRecordInput) (*svcsdk.DescribeRecordOutput, error) + DescribeProduct(*svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) +} + +// CustomServiceCatalogClient is the implementation of a Client +type CustomServiceCatalogClient struct { + CfClient *cfsdkv2.Client + Client svcsdkapi.ServiceCatalogAPI +} + +// GetCloudformationStackParameters retrieves parameters from cloudformation stack based on outputs from provisioned product +func (c *CustomServiceCatalogClient) GetCloudformationStackParameters(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + describeCfStacksInput := cfsdkv2.DescribeStacksInput{} + for i, output := range provisionedProductOutputs { + if *output.OutputKey == cloudformationArnOutputName { + describeCfStacksInput.StackName = output.OutputValue + break + } + if i+1 == len(provisionedProductOutputs) { + return []cfsdkv2types.Parameter{}, errors.New(errCloudformationStackArnNotFound) + } + } + describeCfStacksOutput, err := c.CfClient.DescribeStacks(context.TODO(), &describeCfStacksInput) + if err != nil { + return []cfsdkv2types.Parameter{}, err + } + return describeCfStacksOutput.Stacks[0].Parameters, nil +} + +// GetProvisionedProductOutputs is wrapped (*ServiceCatalog) GetProvisionedProductOutputs from github.com/aws/aws-sdk-go/service/servicecatalog +func (c *CustomServiceCatalogClient) GetProvisionedProductOutputs(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + getPPOutput, err := c.Client.GetProvisionedProductOutputs(getPPInput) + return getPPOutput, err +} + +// DescribeRecord is wrapped (*ServiceCatalog) DescribeRecord from github.com/aws/aws-sdk-go/service/servicecatalog +func (c *CustomServiceCatalogClient) DescribeRecord(describeRecordInput *svcsdk.DescribeRecordInput) (*svcsdk.DescribeRecordOutput, error) { + describeRecordOutput, err := c.Client.DescribeRecord(describeRecordInput) + return describeRecordOutput, err +} + +// DescribeProduct is wrapped (*ServiceCatalog) DescribeProduct from github.com/aws/aws-sdk-go/service/servicecatalog +func (c *CustomServiceCatalogClient) DescribeProduct(input *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return c.Client.DescribeProduct(input) +} diff --git a/pkg/controller/aws.go b/pkg/controller/aws.go index 89f608f015..8451a56f23 100644 --- a/pkg/controller/aws.go +++ b/pkg/controller/aws.go @@ -69,6 +69,7 @@ import ( "github.com/crossplane-contrib/provider-aws/pkg/controller/s3" "github.com/crossplane-contrib/provider-aws/pkg/controller/s3control" "github.com/crossplane-contrib/provider-aws/pkg/controller/secretsmanager" + "github.com/crossplane-contrib/provider-aws/pkg/controller/servicecatalog" "github.com/crossplane-contrib/provider-aws/pkg/controller/servicediscovery" "github.com/crossplane-contrib/provider-aws/pkg/controller/sesv2" "github.com/crossplane-contrib/provider-aws/pkg/controller/sfn" @@ -132,6 +133,7 @@ func Setup(mgr ctrl.Manager, o controller.Options) error { s3.Setup, s3control.Setup, secretsmanager.Setup, + servicecatalog.Setup, servicediscovery.Setup, sesv2.Setup, sfn.Setup, diff --git a/pkg/controller/servicecatalog/provisionedproduct/setup.go b/pkg/controller/servicecatalog/provisionedproduct/setup.go new file mode 100644 index 0000000000..6f37e5cd35 --- /dev/null +++ b/pkg/controller/servicecatalog/provisionedproduct/setup.go @@ -0,0 +1,383 @@ +/* +Copyright 2023 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package provisionedproduct + +import ( + "context" + "fmt" + "strings" + + awsconfig "github.com/aws/aws-sdk-go-v2/config" + cfsdkv2 "github.com/aws/aws-sdk-go-v2/service/cloudformation" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + svcsdk "github.com/aws/aws-sdk-go/service/servicecatalog" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane-runtime/pkg/connection" + "github.com/crossplane/crossplane-runtime/pkg/controller" + "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/meta" + "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" + "github.com/crossplane/crossplane-runtime/pkg/resource" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/uuid" + "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + + svcapitypes "github.com/crossplane-contrib/provider-aws/apis/servicecatalog/v1alpha1" + "github.com/crossplane-contrib/provider-aws/apis/v1alpha1" + clientset "github.com/crossplane-contrib/provider-aws/pkg/clients/servicecatalog" + "github.com/crossplane-contrib/provider-aws/pkg/features" + "github.com/crossplane-contrib/provider-aws/pkg/utils/pointer" +) + +const ( + acceptLanguageEnglish = "en" + + msgProvisionedProductStatusSdkTainted = "provisioned product has status TAINTED" + msgProvisionedProductStatusSdkUnderChange = "provisioned product is updating, availability depends on product" + msgProvisionedProductStatusSdkPlanInProgress = "provisioned product is awaiting plan approval" + msgProvisionedProductStatusSdkError = "provisioned product has status ERROR" + + errCouldNotGetProvisionedProductOutputs = "could not get provisioned product outputs" + errCouldNotGetCFParameters = "could not get cloudformation stack parameters" + errCouldNotDescribeRecord = "could not describe record" + errCouldNotLookupProduct = "could not lookup product" + errAwsAPICodeInvalidParametersException = "Last Successful Provisioning Record doesn't exist." +) + +type custom struct { + *external + client clientset.Client + cache cache +} + +type cache struct { + getProvisionedProductOutputs []*svcsdk.RecordOutput + lastProvisioningParameters []*svcapitypes.ProvisioningParameter +} + +// SetupProvisionedProduct adds a controller that reconciles a ProvisionedProduct +func SetupProvisionedProduct(mgr ctrl.Manager, o controller.Options) error { + name := managed.ControllerName(svcapitypes.ProvisionedProductKind) + awsCfg, err := awsconfig.LoadDefaultConfig(context.TODO()) + if err != nil { + return err + } + cfClient := cfsdkv2.NewFromConfig(awsCfg) + opts := []option{prepareSetupExternal(cfClient)} + cps := []managed.ConnectionPublisher{managed.NewAPISecretPublisher(mgr.GetClient(), mgr.GetScheme())} + if o.Features.Enabled(features.EnableAlphaExternalSecretStores) { + cps = append(cps, connection.NewDetailsManager(mgr.GetClient(), v1alpha1.StoreConfigGroupVersionKind)) + } + + reconcilerOpts := []managed.ReconcilerOption{ + managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), opts: opts}), + managed.WithInitializers(managed.NewNameAsExternalName(mgr.GetClient())), + managed.WithPollInterval(o.PollInterval), + managed.WithLogger(o.Logger.WithValues("controller", name)), + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + managed.WithConnectionPublishers(cps...), + } + + if o.Features.Enabled(features.EnableAlphaManagementPolicies) { + reconcilerOpts = append(reconcilerOpts, managed.WithManagementPolicies()) + } + + return ctrl.NewControllerManagedBy(mgr). + Named(name). + WithOptions(o.ForControllerRuntime()). + WithEventFilter(resource.DesiredStateChanged()). + For(&svcapitypes.ProvisionedProduct{}). + Complete(managed.NewReconciler(mgr, + resource.ManagedKind(svcapitypes.ProvisionedProductGroupVersionKind), + reconcilerOpts...)) +} + +func prepareSetupExternal(cfClient *cfsdkv2.Client) func(*external) { + return func(e *external) { + c := &custom{client: &clientset.CustomServiceCatalogClient{CfClient: cfClient, Client: e.client}} + e.preCreate = preCreate + e.preUpdate = c.preUpdate + e.lateInitialize = c.lateInitialize + e.isUpToDate = c.isUpToDate + e.preObserve = c.preObserve + e.postObserve = c.postObserve + e.preDelete = preDelete + } +} + +func (c *custom) lateInitialize(spec *svcapitypes.ProvisionedProductParameters, _ *svcsdk.DescribeProvisionedProductOutput) error { + acceptLanguageEnglish := acceptLanguageEnglish + spec.AcceptLanguage = pointer.LateInitialize(spec.AcceptLanguage, &acceptLanguageEnglish) + return nil +} + +func preCreate(_ context.Context, ds *svcapitypes.ProvisionedProduct, input *svcsdk.ProvisionProductInput) error { + input.ProvisionToken = aws.String(genIdempotencyToken()) + input.ProvisionedProductName = aws.String(meta.GetExternalName(ds)) + return nil +} + +func (c *custom) preUpdate(_ context.Context, ds *svcapitypes.ProvisionedProduct, input *svcsdk.UpdateProvisionedProductInput) error { + input.UpdateToken = aws.String(genIdempotencyToken()) + input.ProvisionedProductName = aws.String(meta.GetExternalName(ds)) + return nil +} + +func (c *custom) preObserve(_ context.Context, ds *svcapitypes.ProvisionedProduct, input *svcsdk.DescribeProvisionedProductInput) error { + input.Name = aws.String(meta.GetExternalName(ds)) + c.cache.lastProvisioningParameters = ds.Status.AtProvider.DeepCopy().LastProvisioningParameters + return nil +} + +func (c *custom) isUpToDate(_ context.Context, ds *svcapitypes.ProvisionedProduct, resp *svcsdk.DescribeProvisionedProductOutput) (bool, string, error) { //nolint:gocyclo + // If the product is undergoing change, we want to assume that it is not up-to-date. This will force this resource + // to be queued for an update (which will be skipped due to UNDER_CHANGE), and once that update fails, we will + // recheck the status again. This will allow us to quickly transition from UNDER_CHANGE to AVAILABLE without having + // to wait for the entire polling interval to pass before re-checking the status. + if ptr.Deref(resp.ProvisionedProductDetail.Status, "") == string(svcapitypes.ProvisionedProductStatus_SDK_UNDER_CHANGE) || + ptr.Deref(resp.ProvisionedProductDetail.Status, "") == string(svcapitypes.ProvisionedProductStatus_SDK_ERROR) { + return true, "", nil + } + + getPPOutputInput := &svcsdk.GetProvisionedProductOutputsInput{ProvisionedProductId: resp.ProvisionedProductDetail.Id} + getPPOutput, err := c.client.GetProvisionedProductOutputs(getPPOutputInput) + if err != nil { + // We want to specifically handle this exception, since it will occur when something + // is wrong with the provisioned product (error on creation, tainted, etc.) + // We will be able to handle those specific cases in postObserve + var aerr awserr.Error + if ok := errors.As(err, &aerr); ok && aerr.Code() == svcsdk.ErrCodeInvalidParametersException && aerr.Message() == errAwsAPICodeInvalidParametersException { + return false, "", nil + } + return false, "", errors.Wrap(err, errCouldNotGetProvisionedProductOutputs) + } + c.cache.getProvisionedProductOutputs = getPPOutput.Outputs + + productOrArtifactIsChanged, artifactDiff, err := c.productOrArtifactIsChanged(ds, resp.ProvisionedProductDetail) + if err != nil { + return false, "", errors.Wrap(err, "could not discover if product or artifact ids have changed") + } + provisioningParamsAreChanged, paramsDiff, err := c.provisioningParamsAreChanged(ds) + if err != nil { + return false, "", errors.Wrap(err, "could not compare provisioning parameters with previous ones") + } + + if productOrArtifactIsChanged || provisioningParamsAreChanged { + return false, fmt.Sprintf("%s; %s", artifactDiff, paramsDiff), nil + } + return true, "", nil +} + +func (c *custom) postObserve(_ context.Context, ds *svcapitypes.ProvisionedProduct, resp *svcsdk.DescribeProvisionedProductOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) { + if err != nil { + return managed.ExternalObservation{}, err + } + + describeRecordInput := svcsdk.DescribeRecordInput{Id: resp.ProvisionedProductDetail.LastRecordId} + describeRecordOutput, err := c.client.DescribeRecord(&describeRecordInput) + if err != nil { + return managed.ExternalObservation{}, errors.Wrap(err, errCouldNotDescribeRecord) + } + + setConditions(describeRecordOutput, resp, ds) + + var outputs = make(map[string]*svcapitypes.RecordOutput) + for _, v := range c.cache.getProvisionedProductOutputs { + outputs[*v.OutputKey] = &svcapitypes.RecordOutput{ + Description: v.Description, + OutputValue: v.OutputValue} + } + + ds.Status.AtProvider.Outputs = outputs + ds.Status.AtProvider.ARN = resp.ProvisionedProductDetail.Arn + ds.Status.AtProvider.CreatedTime = &metav1.Time{Time: *resp.ProvisionedProductDetail.CreatedTime} + ds.Status.AtProvider.LastProvisioningRecordID = resp.ProvisionedProductDetail.LastProvisioningRecordId + ds.Status.AtProvider.LaunchRoleARN = resp.ProvisionedProductDetail.LaunchRoleArn + ds.Status.AtProvider.Status = resp.ProvisionedProductDetail.Status + ds.Status.AtProvider.StatusMessage = resp.ProvisionedProductDetail.StatusMessage + ds.Status.AtProvider.ProvisionedProductType = resp.ProvisionedProductDetail.Type + ds.Status.AtProvider.RecordType = describeRecordOutput.RecordDetail.RecordType + ds.Status.AtProvider.LastProductID = describeRecordOutput.RecordDetail.ProductId + ds.Status.AtProvider.LastProvisioningArtifactID = describeRecordOutput.RecordDetail.ProvisioningArtifactId + ds.Status.AtProvider.LastProvisioningParameters = ds.Spec.ForProvider.ProvisioningParameters + + return obs, nil +} + +func preDelete(_ context.Context, ds *svcapitypes.ProvisionedProduct, input *svcsdk.TerminateProvisionedProductInput) (bool, error) { + if ptr.Deref(ds.Status.AtProvider.Status, "") == string(svcapitypes.ProvisionedProductStatus_SDK_UNDER_CHANGE) { + return true, nil + } + input.TerminateToken = aws.String(genIdempotencyToken()) + input.ProvisionedProductName = aws.String(meta.GetExternalName(ds)) + return false, nil +} + +func setConditions(describeRecordOutput *svcsdk.DescribeRecordOutput, resp *svcsdk.DescribeProvisionedProductOutput, ds *svcapitypes.ProvisionedProduct) { + ppStatus := aws.StringValue(resp.ProvisionedProductDetail.Status) + switch { + case ppStatus == string(svcapitypes.ProvisionedProductStatus_SDK_AVAILABLE): + ds.SetConditions(xpv1.Available()) + case ppStatus == string(svcapitypes.ProvisionedProductStatus_SDK_UNDER_CHANGE): + recordType := ptr.Deref(describeRecordOutput.RecordDetail.RecordType, "UPDATE_PROVISIONED_PRODUCT") + switch { + case recordType == "PROVISION_PRODUCT": + ds.SetConditions(xpv1.Creating()) + case recordType == "UPDATE_PROVISIONED_PRODUCT": + ds.SetConditions(xpv1.Unavailable().WithMessage(msgProvisionedProductStatusSdkUnderChange)) + case recordType == "TERMINATE_PROVISIONED_PRODUCT": + ds.SetConditions(xpv1.Deleting()) + } + case ppStatus == string(svcapitypes.ProvisionedProductStatus_SDK_PLAN_IN_PROGRESS): + ds.SetConditions(xpv1.Unavailable().WithMessage(msgProvisionedProductStatusSdkPlanInProgress)) + case ppStatus == string(svcapitypes.ProvisionedProductStatus_SDK_ERROR): + ds.SetConditions(xpv1.Unavailable().WithMessage(msgProvisionedProductStatusSdkError)) + case ppStatus == string(svcapitypes.ProvisionedProductStatus_SDK_TAINTED): + ds.SetConditions(xpv1.Unavailable().WithMessage(msgProvisionedProductStatusSdkTainted)) + } +} + +func (c *custom) provisioningParamsAreChanged(ds *svcapitypes.ProvisionedProduct) (bool, string, error) { //nolint:gocyclo + type ProvisioningParameter struct { + Key string + Value string + } + + // Compare provisioning params from desired state whits params from previous reconciliation loop(if it exists) + if c.cache.lastProvisioningParameters != nil { + less := func(a *svcapitypes.ProvisioningParameter, b *svcapitypes.ProvisioningParameter) bool { + return pointer.StringValue(a.Key) < pointer.StringValue(b.Key) + } + if diff := cmp.Diff(c.cache.lastProvisioningParameters, ds.Spec.ForProvider.ProvisioningParameters, cmpopts.SortSlices(less)); diff != "" { + return true, diff, nil + } + } + + cfStackParams, err := c.client.GetCloudformationStackParameters(c.cache.getProvisionedProductOutputs) + if err != nil { + return false, "", errors.Wrap(err, errCouldNotGetCFParameters) + } + + cfStackKeyValue := make(map[string]string) + for _, v := range cfStackParams { + if v.ParameterKey != nil { + cfStackKeyValue[*v.ParameterKey] = ptr.Deref(v.ParameterValue, "") + } + } + var diff []ProvisioningParameter + for _, v := range ds.Spec.ForProvider.ProvisioningParameters { + // In this comparison the controller ignores spaces from the left and right of the parameter value from + // the desired state. Because on cloudformation side spaces are also trimmed + if v.Key != nil { + if cfv, ok := cfStackKeyValue[*v.Key]; !ok || strings.TrimSpace(ptr.Deref(v.Value, "")) != cfv { + diff = append(diff, ProvisioningParameter{Key: *v.Key, Value: ptr.Deref(v.Value, "")}) + } + } + } + if diff != nil { + return true, fmt.Sprintf("ProvisioningParameters are changed: %v", diff), nil + } + + return false, "", nil +} + +func (c *custom) productOrArtifactIsChanged(ds *svcapitypes.ProvisionedProduct, + resp *svcsdk.ProvisionedProductDetail) (bool, string, error) { + // ProvisioningArtifactID and ProvisioningArtifactName are mutual exclusive params, the same about ProductID and ProductName + // But if describe a provisioned product aws api will return only IDs, so it's impossible to compare names with ids + // Two conditional statements below work only of IDs + var diffList []string + if ds.Spec.ForProvider.ProvisioningArtifactID != nil { + diff := cmp.Diff(*ds.Spec.ForProvider.ProvisioningArtifactID, *resp.ProvisioningArtifactId) + diffList = append(diffList, diff) + } + if ds.Spec.ForProvider.ProductID != nil { + diff := cmp.Diff(*ds.Spec.ForProvider.ProductID, *resp.ProductId) + diffList = append(diffList, diff) + } + // In case if the desired state has ProvisioningArtifactName the controller will run func `getArtifactID`, which produces + // additional request to aws api to resolve the artifact id(based on ProductId/ProductName) + // for further comparison with artifact id in the current state + if ds.Spec.ForProvider.ProvisioningArtifactName != nil { + desiredArtifactID, err := c.getArtifactID(ds) + if err != nil { + return false, "", err + } + diff := cmp.Diff(desiredArtifactID, *resp.ProvisioningArtifactId) + diffList = append(diffList, diff) + } + // If desired state includes ProductName the controller will resolve ID via func `getProductID`, + // which also produce additional api request + if ds.Spec.ForProvider.ProductName != nil { + desiredProductID, err := c.getProductID(ds.Spec.ForProvider.ProductName) + if err != nil { + return false, "", err + } + diff := cmp.Diff(desiredProductID, *resp.ProductId) + diffList = append(diffList, diff) + } + + finalDiff := "" + for _, diff := range diffList { + if diff != "" { + finalDiff += diff + } + } + if finalDiff != "" { + return true, finalDiff, nil + } + + return false, "", nil +} + +func (c *custom) getArtifactID(ds *svcapitypes.ProvisionedProduct) (string, error) { + input := svcsdk.DescribeProductInput{ + Id: ds.Spec.ForProvider.ProductID, + Name: ds.Spec.ForProvider.ProductName, + } + // DescribeProvisioningArtifact method fits much better, but it has a bug - it returns nothing if a product is a part of imported portfolio + output, err := c.client.DescribeProduct(&input) + if err != nil { + return "", errors.Wrap(err, errCouldNotLookupProduct) + } + for _, artifact := range output.ProvisioningArtifacts { + if ptr.Deref(ds.Spec.ForProvider.ProvisioningArtifactName, "") == *artifact.Name || + ptr.Deref(ds.Spec.ForProvider.ProvisioningArtifactID, "") == *artifact.Id { + return *artifact.Id, nil + } + } + return "", errors.Wrap(errors.New("artifact not found"), errCouldNotLookupProduct) +} + +func (c *custom) getProductID(productName *string) (string, error) { + input := svcsdk.DescribeProductInput{Name: productName} + // DescribeProvisioningArtifact method fits much better, but it has a bug - it returns nothing if a product is a part of imported portfolio + output, err := c.client.DescribeProduct(&input) + if err != nil { + return "", errors.Wrap(err, errCouldNotLookupProduct) + } + return ptr.Deref(output.ProductViewSummary.ProductId, ""), nil +} + +func genIdempotencyToken() string { + return fmt.Sprintf("provider-aws-%s", uuid.New()) +} diff --git a/pkg/controller/servicecatalog/provisionedproduct/setup_test.go b/pkg/controller/servicecatalog/provisionedproduct/setup_test.go new file mode 100644 index 0000000000..dd9ef42899 --- /dev/null +++ b/pkg/controller/servicecatalog/provisionedproduct/setup_test.go @@ -0,0 +1,844 @@ +/* +Copyright 2023 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package provisionedproduct + +import ( + "context" + "testing" + "time" + + cfsdkv2types "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + svcsdk "github.com/aws/aws-sdk-go/service/servicecatalog" + svcsdkapi "github.com/aws/aws-sdk-go/service/servicecatalog/servicecatalogiface" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" + "github.com/crossplane/crossplane-runtime/pkg/test" + "github.com/google/go-cmp/cmp" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/crossplane-contrib/provider-aws/apis/servicecatalog/v1alpha1" + clientset "github.com/crossplane-contrib/provider-aws/pkg/clients/servicecatalog" + "github.com/crossplane-contrib/provider-aws/pkg/clients/servicecatalog/fake" + "github.com/crossplane-contrib/provider-aws/pkg/utils/pointer" +) + +const ( + provisioningArtifactID = "pa-1234567890" + newProvisioningArtifactID = "pa-new1234567890" + provisioningArtifactName = "v1.0" + newProvisioningArtifactName = "v1.1" + productID = "prod-1234567890" + newProductID = "prod-new1234567890" + acceptLanguage = "jp" + latelyInitializedAcceptLanguage = "en" +) + +type args struct { + kube client.Client + cache cache + client svcsdkapi.ServiceCatalogAPI + customClient *fake.MockCustomServiceCatalogClient + provisionedProduct *v1alpha1.ProvisionedProduct + describeProvisionedProductOutput *svcsdk.DescribeProvisionedProductOutput +} + +type provisionedProductModifier func(provisionedProduct *v1alpha1.ProvisionedProduct) + +func withSpec(p v1alpha1.ProvisionedProductParameters) provisionedProductModifier { + return func(cr *v1alpha1.ProvisionedProduct) { cr.Spec.ForProvider = p } +} + +func withStatus(p v1alpha1.ProvisionedProductStatus) provisionedProductModifier { + return func(cr *v1alpha1.ProvisionedProduct) { cr.Status = p } +} + +func provisionedProduct(m ...provisionedProductModifier) *v1alpha1.ProvisionedProduct { + cr := &v1alpha1.ProvisionedProduct{} + cr.Name = "test-provisioned-product-name" + for _, f := range m { + f(cr) + } + return cr +} + +type describeProvisionedProductOutputModifier func(describeProvisionedProductOutput *svcsdk.DescribeProvisionedProductOutput) + +func withDetails(d svcsdk.ProvisionedProductDetail) describeProvisionedProductOutputModifier { + return func(output *svcsdk.DescribeProvisionedProductOutput) { output.ProvisionedProductDetail = &d } +} + +func describeProvisionedProduct(m ...describeProvisionedProductOutputModifier) *svcsdk.DescribeProvisionedProductOutput { + output := &svcsdk.DescribeProvisionedProductOutput{} + for _, f := range m { + f(output) + } + return output +} + +func setupFakeExternal(fakeClient clientset.Client, cache cache) func(*external) { + return func(e *external) { + c := &custom{client: fakeClient, cache: cache} + e.preCreate = preCreate + e.preUpdate = c.preUpdate + e.lateInitialize = c.lateInitialize + e.isUpToDate = c.isUpToDate + e.preObserve = c.preObserve + e.postObserve = c.postObserve + e.preDelete = preDelete + } +} + +func TestIsUpToDate(t *testing.T) { + provisioningArtifactID := provisioningArtifactID + newProvisioningArtifactID := newProvisioningArtifactID + provisioningArtifactName := provisioningArtifactName + newProvisioningArtifactName := newProvisioningArtifactName + productID := productID + newProductID := newProductID + + type want struct { + result bool + err error + } + cases := map[string]struct { + args + want + }{ + "ProductNameHasChanged": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + ProvisioningArtifactName: pointer.ToOrNilIfZeroValue(newProvisioningArtifactName), + ProductName: pointer.ToOrNilIfZeroValue("s3-product"), + ProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter"), Value: pointer.ToOrNilIfZeroValue("foo")}}, + }), + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE))}, + }), + }...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Id: pointer.ToOrNilIfZeroValue("pp-fake"), + ProductId: pointer.ToOrNilIfZeroValue(productID), + ProvisioningArtifactId: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockGetCloudformationStackParameters: func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return []cfsdkv2types.Parameter{{ParameterKey: pointer.ToOrNilIfZeroValue("Parameter"), ParameterValue: pointer.ToOrNilIfZeroValue("foo")}}, nil + }, + MockGetProvisionedProductOutputs: func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return &svcsdk.GetProvisionedProductOutputsOutput{}, nil + }, + MockDescribeProduct: func(dpInput *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return &svcsdk.DescribeProductOutput{ + ProductViewSummary: &svcsdk.ProductViewSummary{ + ProductId: dpInput.Id, + Name: pointer.ToOrNilIfZeroValue("fake-product"), + }, + ProvisioningArtifacts: []*svcsdk.ProvisioningArtifact{ + { + Id: pointer.ToOrNilIfZeroValue(newProvisioningArtifactID), + Name: pointer.ToOrNilIfZeroValue(newProvisioningArtifactName), + }, + }, + }, nil + }, + }, + cache: cache{lastProvisioningParameters: []*v1alpha1.ProvisioningParameter{}}, + }, + want: want{ + result: false, + err: nil, + }, + }, + "ProductIdHasChanged": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + ProvisioningArtifactName: pointer.ToOrNilIfZeroValue(newProvisioningArtifactName), + ProductID: pointer.ToOrNilIfZeroValue(newProductID), + ProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter"), Value: pointer.ToOrNilIfZeroValue("foo")}}, + }), + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE))}, + }), + }...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Id: pointer.ToOrNilIfZeroValue("pp-fake"), + ProductId: pointer.ToOrNilIfZeroValue(productID), + ProvisioningArtifactId: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockGetCloudformationStackParameters: func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return []cfsdkv2types.Parameter{{ParameterKey: pointer.ToOrNilIfZeroValue("Parameter"), ParameterValue: pointer.ToOrNilIfZeroValue("foo")}}, nil + }, + MockGetProvisionedProductOutputs: func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return &svcsdk.GetProvisionedProductOutputsOutput{}, nil + }, + MockDescribeProduct: func(dpInput *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return &svcsdk.DescribeProductOutput{ + ProductViewSummary: &svcsdk.ProductViewSummary{ + ProductId: dpInput.Id, + Name: pointer.ToOrNilIfZeroValue("fake-product"), + }, + ProvisioningArtifacts: []*svcsdk.ProvisioningArtifact{ + { + Id: pointer.ToOrNilIfZeroValue(newProvisioningArtifactID), + Name: pointer.ToOrNilIfZeroValue(newProvisioningArtifactName), + }, + }, + }, nil + }, + }, + cache: cache{lastProvisioningParameters: []*v1alpha1.ProvisioningParameter{}}, + }, + want: want{ + result: false, + err: nil, + }, + }, + "ArtifactNameHasChanged": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + ProvisioningArtifactName: pointer.ToOrNilIfZeroValue(provisioningArtifactName), + ProductID: pointer.ToOrNilIfZeroValue(productID), + ProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter"), Value: pointer.ToOrNilIfZeroValue("foo")}}, + }), + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE))}, + }), + }...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Id: pointer.ToOrNilIfZeroValue("pp-fake"), + ProductId: pointer.ToOrNilIfZeroValue(productID), + ProvisioningArtifactId: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockGetCloudformationStackParameters: func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return []cfsdkv2types.Parameter{{ParameterKey: pointer.ToOrNilIfZeroValue("Parameter"), ParameterValue: pointer.ToOrNilIfZeroValue("foo")}}, nil + }, + MockGetProvisionedProductOutputs: func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return &svcsdk.GetProvisionedProductOutputsOutput{}, nil + }, + MockDescribeProduct: func(dpInput *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return &svcsdk.DescribeProductOutput{ + ProductViewSummary: &svcsdk.ProductViewSummary{ + ProductId: dpInput.Id, + Name: pointer.ToOrNilIfZeroValue("fake-product"), + }, + ProvisioningArtifacts: []*svcsdk.ProvisioningArtifact{ + { + Name: pointer.ToOrNilIfZeroValue(provisioningArtifactName), + Id: pointer.ToOrNilIfZeroValue(newProvisioningArtifactID), + }, + }, + }, nil + }, + }, + cache: cache{lastProvisioningParameters: []*v1alpha1.ProvisioningParameter{}}, + }, + want: want{ + result: false, + err: nil, + }, + }, + "ArtifactIdHasChanged": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + ProvisioningArtifactID: pointer.ToOrNilIfZeroValue(newProvisioningArtifactID), + ProductID: pointer.ToOrNilIfZeroValue(productID), + ProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter"), Value: pointer.ToOrNilIfZeroValue("foo")}}, + }), + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE))}, + }), + }...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Id: pointer.ToOrNilIfZeroValue("pp-fake"), + ProductId: pointer.ToOrNilIfZeroValue(productID), + ProvisioningArtifactId: pointer.ToOrNilIfZeroValue(provisioningArtifactName), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockGetCloudformationStackParameters: func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return []cfsdkv2types.Parameter{{ParameterKey: pointer.ToOrNilIfZeroValue("Parameter"), ParameterValue: pointer.ToOrNilIfZeroValue("foo")}}, nil + }, + MockGetProvisionedProductOutputs: func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return &svcsdk.GetProvisionedProductOutputsOutput{}, nil + }, + MockDescribeProduct: func(dpInput *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return &svcsdk.DescribeProductOutput{ + ProductViewSummary: &svcsdk.ProductViewSummary{ + ProductId: dpInput.Id, + Name: pointer.ToOrNilIfZeroValue("fake product"), + }, + ProvisioningArtifacts: []*svcsdk.ProvisioningArtifact{ + { + Id: pointer.ToOrNilIfZeroValue(newProvisioningArtifactID), + }, + }, + }, nil + }, + }, + cache: cache{lastProvisioningParameters: []*v1alpha1.ProvisioningParameter{}}, + }, + want: want{ + result: false, + err: nil, + }, + }, + "ParametersValueHasChanged": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + ProvisioningArtifactID: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + ProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("bar")}}, + }), + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE))}, + }), + }...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Id: pointer.ToOrNilIfZeroValue("pp-fake"), + ProvisioningArtifactId: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockGetCloudformationStackParameters: func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return []cfsdkv2types.Parameter{ + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter1"), ParameterValue: pointer.ToOrNilIfZeroValue("foo")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter2"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter3"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter4"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + }, nil + }, + MockGetProvisionedProductOutputs: func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return &svcsdk.GetProvisionedProductOutputsOutput{}, nil + }, + MockDescribeProduct: func(dpInput *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return &svcsdk.DescribeProductOutput{ + ProductViewSummary: &svcsdk.ProductViewSummary{ + ProductId: dpInput.Id, + Name: pointer.ToOrNilIfZeroValue("fake product"), + }, + ProvisioningArtifacts: []*svcsdk.ProvisioningArtifact{ + { + Id: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }, + }, + }, nil + }, + }, + kube: &test.MockClient{ + MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { + pp := obj.(*v1alpha1.ProvisionedProduct) + pp.Status.AtProvider.LastProvisioningParameters = []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + } + return nil + }, + }, + cache: cache{lastProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + }}, + }, + want: want{ + result: false, + err: nil, + }, + }, + "ParameterHasBeenAddedWithNewValue": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + ProvisioningArtifactID: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + ProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + {Key: pointer.ToOrNilIfZeroValue("Parameter2"), Value: pointer.ToOrNilIfZeroValue("quux")}, + }, + }), + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE))}, + }), + }...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Id: pointer.ToOrNilIfZeroValue("pp-fake"), + ProvisioningArtifactId: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockGetCloudformationStackParameters: func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return []cfsdkv2types.Parameter{ + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter1"), ParameterValue: pointer.ToOrNilIfZeroValue("foo")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter2"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter3"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter4"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + }, nil + }, + MockGetProvisionedProductOutputs: func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return &svcsdk.GetProvisionedProductOutputsOutput{}, nil + }, + MockDescribeProduct: func(dpInput *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return &svcsdk.DescribeProductOutput{ + ProductViewSummary: &svcsdk.ProductViewSummary{ + ProductId: pointer.ToOrNilIfZeroValue("prod-fake"), + Name: pointer.ToOrNilIfZeroValue("fake product"), + }, + ProvisioningArtifacts: []*svcsdk.ProvisioningArtifact{ + { + Id: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }, + }, + }, nil + }, + }, + cache: cache{lastProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + }}, + }, + want: want{ + result: false, + err: nil, + }, + }, + "ParameterHasBeenAddedWithDefaultValue": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + ProvisioningArtifactID: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + ProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + {Key: pointer.ToOrNilIfZeroValue("Parameter2"), Value: pointer.ToOrNilIfZeroValue("product_default_value")}, + }, + }), + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE))}, + }), + }...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Id: pointer.ToOrNilIfZeroValue("pp-fake"), + ProvisioningArtifactId: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockGetCloudformationStackParameters: func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return []cfsdkv2types.Parameter{ + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter1"), ParameterValue: pointer.ToOrNilIfZeroValue("foo")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter2"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter3"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter4"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + }, nil + }, + MockGetProvisionedProductOutputs: func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return &svcsdk.GetProvisionedProductOutputsOutput{}, nil + }, + MockDescribeProduct: func(dpInput *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return &svcsdk.DescribeProductOutput{ + ProductViewSummary: &svcsdk.ProductViewSummary{ + ProductId: pointer.ToOrNilIfZeroValue("prod-fake"), + Name: pointer.ToOrNilIfZeroValue("fake product"), + }, + ProvisioningArtifacts: []*svcsdk.ProvisioningArtifact{ + { + Id: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }, + }, + }, nil + }, + }, + cache: cache{lastProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + {Key: pointer.ToOrNilIfZeroValue("Parameter2"), Value: pointer.ToOrNilIfZeroValue("product_default_value")}, + }}, + }, + want: want{ + result: true, + err: nil, + }, + }, + "ExistingParameterHasBeenRemoved": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + ProvisioningArtifactID: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + ProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + }, + }), + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE))}, + }), + }...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Id: pointer.ToOrNilIfZeroValue("pp-fake"), + ProvisioningArtifactId: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockGetCloudformationStackParameters: func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return []cfsdkv2types.Parameter{ + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter1"), ParameterValue: pointer.ToOrNilIfZeroValue("foo")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter2"), ParameterValue: pointer.ToOrNilIfZeroValue("no_ways_to_determine_is_it_default_value_or_not")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter3"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter4"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + }, nil + }, + MockGetProvisionedProductOutputs: func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return &svcsdk.GetProvisionedProductOutputsOutput{}, nil + }, + MockDescribeProduct: func(dpInput *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return &svcsdk.DescribeProductOutput{ + ProductViewSummary: &svcsdk.ProductViewSummary{ + ProductId: dpInput.Id, + Name: pointer.ToOrNilIfZeroValue("fake product"), + }, + ProvisioningArtifacts: []*svcsdk.ProvisioningArtifact{ + { + Id: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }, + }, + }, nil + }, + }, + cache: cache{lastProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + {Key: pointer.ToOrNilIfZeroValue("Parameter2"), Value: pointer.ToOrNilIfZeroValue("no_ways_to_determine_is_it_default_value_or_not")}, + }}, + }, + want: want{ + result: false, + err: nil, + }, + }, + "ParametersAreNotChanged": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + ProvisioningArtifactID: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + ProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + {Key: pointer.ToOrNilIfZeroValue("Parameter2"), Value: pointer.ToOrNilIfZeroValue("bar")}, + {Key: pointer.ToOrNilIfZeroValue("Parameter3"), Value: pointer.ToOrNilIfZeroValue("baz")}, + }, + }), + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE))}, + }), + }...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Id: pointer.ToOrNilIfZeroValue("pp-fake"), + ProvisioningArtifactId: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockGetCloudformationStackParameters: func(provisionedProductOutputs []*svcsdk.RecordOutput) ([]cfsdkv2types.Parameter, error) { + return []cfsdkv2types.Parameter{ + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter1"), ParameterValue: pointer.ToOrNilIfZeroValue("foo")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter2"), ParameterValue: pointer.ToOrNilIfZeroValue("bar")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter3"), ParameterValue: pointer.ToOrNilIfZeroValue("baz")}, + {ParameterKey: pointer.ToOrNilIfZeroValue("Parameter4"), ParameterValue: pointer.ToOrNilIfZeroValue("product_default_value")}, + }, nil + }, + MockGetProvisionedProductOutputs: func(getPPInput *svcsdk.GetProvisionedProductOutputsInput) (*svcsdk.GetProvisionedProductOutputsOutput, error) { + return &svcsdk.GetProvisionedProductOutputsOutput{}, nil + }, + MockDescribeProduct: func(dpInput *svcsdk.DescribeProductInput) (*svcsdk.DescribeProductOutput, error) { + return &svcsdk.DescribeProductOutput{ + ProductViewSummary: &svcsdk.ProductViewSummary{ + ProductId: dpInput.Id, + Name: pointer.ToOrNilIfZeroValue("fake product"), + }, + ProvisioningArtifacts: []*svcsdk.ProvisioningArtifact{ + { + Id: pointer.ToOrNilIfZeroValue(provisioningArtifactID), + }, + }, + }, nil + }, + }, + cache: cache{lastProvisioningParameters: []*v1alpha1.ProvisioningParameter{ + {Key: pointer.ToOrNilIfZeroValue("Parameter1"), Value: pointer.ToOrNilIfZeroValue("foo")}, + {Key: pointer.ToOrNilIfZeroValue("Parameter2"), Value: pointer.ToOrNilIfZeroValue("bar")}, + {Key: pointer.ToOrNilIfZeroValue("Parameter3"), Value: pointer.ToOrNilIfZeroValue("baz")}, + }}, + }, + want: want{ + result: true, + err: nil, + }, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + opts := []option{setupFakeExternal(tc.args.customClient, tc.args.cache)} + e := newExternal(tc.args.kube, tc.args.client, opts) + result, _, err := e.isUpToDate(context.TODO(), tc.args.provisionedProduct, tc.args.describeProvisionedProductOutput) + if diff := cmp.Diff(err, tc.want.err, test.EquateErrors()); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + if diff := cmp.Diff(tc.want.result, result); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + }) + } +} + +func TestLateInitialize(t *testing.T) { + type want struct { + acceptLanguage string + } + cases := map[string]struct { + args + want + }{ + "ValuesAreNotSpecified": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + AcceptLanguage: pointer.ToOrNilIfZeroValue(""), + }), + }...), + }, + want: want{ + acceptLanguage: latelyInitializedAcceptLanguage, + }, + }, + "ValuesAreSpecified": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withSpec(v1alpha1.ProvisionedProductParameters{ + AcceptLanguage: pointer.ToOrNilIfZeroValue(acceptLanguage), + }), + }...), + }, + want: want{ + acceptLanguage: acceptLanguage, + }, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + opts := []option{setupFakeExternal(tc.args.customClient, tc.args.cache)} + e := newExternal(tc.args.kube, tc.args.client, opts) + _ = e.lateInitialize(&tc.args.provisionedProduct.Spec.ForProvider, tc.args.describeProvisionedProductOutput) + if diff := cmp.Diff(tc.want.acceptLanguage, *tc.args.provisionedProduct.Spec.ForProvider.AcceptLanguage); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + }) + } +} + +func TestPostObserve(t *testing.T) { + type want struct { + status xpv1.Condition + } + testStaringTime := time.Now() + provisionedProductStatus := withStatus(v1alpha1.ProvisionedProductStatus{ + ResourceStatus: xpv1.ResourceStatus{ + ConditionedStatus: xpv1.ConditionedStatus{ + Conditions: []xpv1.Condition{}}}, + }) + cases := map[string]struct { + args + want + }{ + "StatusAvailable": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{provisionedProductStatus}...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_AVAILABLE)), + Arn: pointer.ToOrNilIfZeroValue("arn:utils:servicecatalog:fake"), + CreatedTime: &testStaringTime, + LastSuccessfulProvisioningRecordId: pointer.ToOrNilIfZeroValue("rec-fake"), + LaunchRoleArn: pointer.ToOrNilIfZeroValue("arn:utils:iam::fake"), + StatusMessage: pointer.ToOrNilIfZeroValue("fake"), + Type: pointer.ToOrNilIfZeroValue("CFN_STACK"), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockDescribeRecord: func(describeRecordInput *svcsdk.DescribeRecordInput) (*svcsdk.DescribeRecordOutput, error) { + return &svcsdk.DescribeRecordOutput{RecordDetail: &svcsdk.RecordDetail{RecordType: pointer.ToOrNilIfZeroValue("PROVISION_PRODUCT")}}, nil + }, + }, + }, + want: want{ + status: xpv1.Available(), + }, + }, + "StatusAvailableWithAmendment": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{provisionedProductStatus}...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_UNDER_CHANGE)), + Arn: pointer.ToOrNilIfZeroValue("arn:utils:servicecatalog:fake"), + CreatedTime: &testStaringTime, + LastSuccessfulProvisioningRecordId: pointer.ToOrNilIfZeroValue("rec-fake"), + LaunchRoleArn: pointer.ToOrNilIfZeroValue("arn:utils:iam::fake"), + StatusMessage: pointer.ToOrNilIfZeroValue("fake"), + Type: pointer.ToOrNilIfZeroValue("CFN_STACK"), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockDescribeRecord: func(describeRecordInput *svcsdk.DescribeRecordInput) (*svcsdk.DescribeRecordOutput, error) { + return &svcsdk.DescribeRecordOutput{RecordDetail: &svcsdk.RecordDetail{RecordType: pointer.ToOrNilIfZeroValue("UPDATE_PROVISIONED_PRODUCT")}}, nil + }, + }, + }, + want: want{ + status: xpv1.Unavailable().WithMessage(msgProvisionedProductStatusSdkUnderChange), + }, + }, + "StatusReconcileErrorProductError": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{provisionedProductStatus}...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_ERROR)), + Arn: pointer.ToOrNilIfZeroValue("arn:utils:servicecatalog:fake"), + CreatedTime: &testStaringTime, + LastSuccessfulProvisioningRecordId: pointer.ToOrNilIfZeroValue("rec-fake"), + LaunchRoleArn: pointer.ToOrNilIfZeroValue("arn:utils:iam::fake"), + StatusMessage: pointer.ToOrNilIfZeroValue("fake"), + Type: pointer.ToOrNilIfZeroValue("CFN_STACK"), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockDescribeRecord: func(describeRecordInput *svcsdk.DescribeRecordInput) (*svcsdk.DescribeRecordOutput, error) { + return &svcsdk.DescribeRecordOutput{RecordDetail: &svcsdk.RecordDetail{RecordType: pointer.ToOrNilIfZeroValue("PROVISION_PRODUCT")}}, nil + }, + }, + }, + want: want{ + status: xpv1.Unavailable().WithMessage(msgProvisionedProductStatusSdkError), + }, + }, + "StatusReconcileErrorProductTainted": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{provisionedProductStatus}...), + describeProvisionedProductOutput: describeProvisionedProduct([]describeProvisionedProductOutputModifier{ + withDetails(svcsdk.ProvisionedProductDetail{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_TAINTED)), + Arn: pointer.ToOrNilIfZeroValue("arn:utils:servicecatalog:fake"), + CreatedTime: &testStaringTime, + LastSuccessfulProvisioningRecordId: pointer.ToOrNilIfZeroValue("rec-fake"), + LaunchRoleArn: pointer.ToOrNilIfZeroValue("arn:utils:iam::fake"), + StatusMessage: pointer.ToOrNilIfZeroValue("fake"), + Type: pointer.ToOrNilIfZeroValue("CFN_STACK"), + }), + }...), + customClient: &fake.MockCustomServiceCatalogClient{ + MockDescribeRecord: func(describeRecordInput *svcsdk.DescribeRecordInput) (*svcsdk.DescribeRecordOutput, error) { + return &svcsdk.DescribeRecordOutput{RecordDetail: &svcsdk.RecordDetail{RecordType: pointer.ToOrNilIfZeroValue("PROVISION_PRODUCT")}}, nil + }, + }, + }, + want: want{ + status: xpv1.Unavailable().WithMessage(msgProvisionedProductStatusSdkTainted), + }, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + opts := []option{setupFakeExternal(tc.args.customClient, tc.args.cache)} + e := newExternal(tc.args.kube, tc.args.client, opts) + _, _ = e.postObserve(context.TODO(), tc.args.provisionedProduct, tc.args.describeProvisionedProductOutput, managed.ExternalObservation{}, nil) + conditions := tc.args.provisionedProduct.Status.Conditions + latestCondition := conditions[len(conditions)-1] + if diff := cmp.Diff(tc.want.status, latestCondition); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + test.EquateConditions() + }) + } +} + +func TestPreDelete(t *testing.T) { + type want struct { + ignoreDeletion bool + } + cases := map[string]struct { + args + want + }{ + "ignoreDeletion": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue(string(v1alpha1.ProvisionedProductStatus_SDK_UNDER_CHANGE))}, + }), + }...), + }, + want: want{ + ignoreDeletion: true, + }, + }, + "passDeletion": { + args: args{ + provisionedProduct: provisionedProduct([]provisionedProductModifier{ + withStatus(v1alpha1.ProvisionedProductStatus{ + AtProvider: v1alpha1.ProvisionedProductObservation{ + Status: pointer.ToOrNilIfZeroValue("NOT_UNDER_CHANGE")}, + }), + }...), + }, + want: want{ + ignoreDeletion: false, + }, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + opts := []option{setupFakeExternal(tc.args.customClient, tc.args.cache)} + e := newExternal(tc.args.kube, tc.args.client, opts) + ignore, _ := e.preDelete(context.TODO(), tc.args.provisionedProduct, &svcsdk.TerminateProvisionedProductInput{}) + if diff := cmp.Diff(tc.want.ignoreDeletion, ignore); diff != "" { + t.Errorf("r: -want, +got\n%s", diff) + + } + }) + } +} diff --git a/pkg/controller/servicecatalog/provisionedproduct/zz_controller.go b/pkg/controller/servicecatalog/provisionedproduct/zz_controller.go new file mode 100644 index 0000000000..0326d862ff --- /dev/null +++ b/pkg/controller/servicecatalog/provisionedproduct/zz_controller.go @@ -0,0 +1,306 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by ack-generate. DO NOT EDIT. + +package provisionedproduct + +import ( + "context" + + svcapi "github.com/aws/aws-sdk-go/service/servicecatalog" + svcsdk "github.com/aws/aws-sdk-go/service/servicecatalog" + svcsdkapi "github.com/aws/aws-sdk-go/service/servicecatalog/servicecatalogiface" + "github.com/google/go-cmp/cmp" + "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane-runtime/pkg/meta" + "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" + cpresource "github.com/crossplane/crossplane-runtime/pkg/resource" + + svcapitypes "github.com/crossplane-contrib/provider-aws/apis/servicecatalog/v1alpha1" + connectaws "github.com/crossplane-contrib/provider-aws/pkg/utils/connect/aws" + errorutils "github.com/crossplane-contrib/provider-aws/pkg/utils/errors" +) + +const ( + errUnexpectedObject = "managed resource is not an ProvisionedProduct resource" + + errCreateSession = "cannot create a new session" + errCreate = "cannot create ProvisionedProduct in AWS" + errUpdate = "cannot update ProvisionedProduct in AWS" + errDescribe = "failed to describe ProvisionedProduct" + errDelete = "failed to delete ProvisionedProduct" +) + +type connector struct { + kube client.Client + opts []option +} + +func (c *connector) Connect(ctx context.Context, mg cpresource.Managed) (managed.ExternalClient, error) { + cr, ok := mg.(*svcapitypes.ProvisionedProduct) + if !ok { + return nil, errors.New(errUnexpectedObject) + } + sess, err := connectaws.GetConfigV1(ctx, c.kube, mg, cr.Spec.ForProvider.Region) + if err != nil { + return nil, errors.Wrap(err, errCreateSession) + } + return newExternal(c.kube, svcapi.New(sess), c.opts), nil +} + +func (e *external) Observe(ctx context.Context, mg cpresource.Managed) (managed.ExternalObservation, error) { + cr, ok := mg.(*svcapitypes.ProvisionedProduct) + if !ok { + return managed.ExternalObservation{}, errors.New(errUnexpectedObject) + } + if meta.GetExternalName(cr) == "" { + return managed.ExternalObservation{ + ResourceExists: false, + }, nil + } + input := GenerateDescribeProvisionedProductInput(cr) + if err := e.preObserve(ctx, cr, input); err != nil { + return managed.ExternalObservation{}, errors.Wrap(err, "pre-observe failed") + } + resp, err := e.client.DescribeProvisionedProductWithContext(ctx, input) + if err != nil { + return managed.ExternalObservation{ResourceExists: false}, errorutils.Wrap(cpresource.Ignore(IsNotFound, err), errDescribe) + } + currentSpec := cr.Spec.ForProvider.DeepCopy() + if err := e.lateInitialize(&cr.Spec.ForProvider, resp); err != nil { + return managed.ExternalObservation{}, errors.Wrap(err, "late-init failed") + } + GenerateProvisionedProduct(resp).Status.AtProvider.DeepCopyInto(&cr.Status.AtProvider) + if meta.WasDeleted(cr) { // There is no need to run isUpToDate if the resource is deleted + return managed.ExternalObservation{ + ResourceExists: true, + ResourceUpToDate: true, + }, nil + } + upToDate, diff, err := e.isUpToDate(ctx, cr, resp) + if err != nil { + return managed.ExternalObservation{}, errors.Wrap(err, "isUpToDate check failed") + } + return e.postObserve(ctx, cr, resp, managed.ExternalObservation{ + ResourceExists: true, + ResourceUpToDate: upToDate, + Diff: diff, + ResourceLateInitialized: !cmp.Equal(&cr.Spec.ForProvider, currentSpec), + }, nil) +} + +func (e *external) Create(ctx context.Context, mg cpresource.Managed) (managed.ExternalCreation, error) { + cr, ok := mg.(*svcapitypes.ProvisionedProduct) + if !ok { + return managed.ExternalCreation{}, errors.New(errUnexpectedObject) + } + cr.Status.SetConditions(xpv1.Creating()) + input := GenerateProvisionProductInput(cr) + if err := e.preCreate(ctx, cr, input); err != nil { + return managed.ExternalCreation{}, errors.Wrap(err, "pre-create failed") + } + resp, err := e.client.ProvisionProductWithContext(ctx, input) + if err != nil { + return managed.ExternalCreation{}, errorutils.Wrap(err, errCreate) + } + + if resp.RecordDetail.CreatedTime != nil { + cr.Status.AtProvider.CreatedTime = &metav1.Time{*resp.RecordDetail.CreatedTime} + } else { + cr.Status.AtProvider.CreatedTime = nil + } + if resp.RecordDetail.LaunchRoleArn != nil { + cr.Status.AtProvider.LaunchRoleARN = resp.RecordDetail.LaunchRoleArn + } else { + cr.Status.AtProvider.LaunchRoleARN = nil + } + if resp.RecordDetail.ProvisionedProductId != nil { + cr.Status.AtProvider.ProvisionedProductID = resp.RecordDetail.ProvisionedProductId + } else { + cr.Status.AtProvider.ProvisionedProductID = nil + } + if resp.RecordDetail.ProvisionedProductName != nil { + cr.Status.AtProvider.ProvisionedProductName = resp.RecordDetail.ProvisionedProductName + } else { + cr.Status.AtProvider.ProvisionedProductName = nil + } + if resp.RecordDetail.ProvisionedProductType != nil { + cr.Status.AtProvider.ProvisionedProductType = resp.RecordDetail.ProvisionedProductType + } else { + cr.Status.AtProvider.ProvisionedProductType = nil + } + if resp.RecordDetail.RecordErrors != nil { + f5 := []*svcapitypes.RecordError{} + for _, f5iter := range resp.RecordDetail.RecordErrors { + f5elem := &svcapitypes.RecordError{} + if f5iter.Code != nil { + f5elem.Code = f5iter.Code + } + if f5iter.Description != nil { + f5elem.Description = f5iter.Description + } + f5 = append(f5, f5elem) + } + cr.Status.AtProvider.RecordErrors = f5 + } else { + cr.Status.AtProvider.RecordErrors = nil + } + if resp.RecordDetail.RecordId != nil { + cr.Status.AtProvider.RecordID = resp.RecordDetail.RecordId + } else { + cr.Status.AtProvider.RecordID = nil + } + if resp.RecordDetail.RecordTags != nil { + f7 := []*svcapitypes.RecordTag{} + for _, f7iter := range resp.RecordDetail.RecordTags { + f7elem := &svcapitypes.RecordTag{} + if f7iter.Key != nil { + f7elem.Key = f7iter.Key + } + if f7iter.Value != nil { + f7elem.Value = f7iter.Value + } + f7 = append(f7, f7elem) + } + cr.Status.AtProvider.RecordTags = f7 + } else { + cr.Status.AtProvider.RecordTags = nil + } + if resp.RecordDetail.RecordType != nil { + cr.Status.AtProvider.RecordType = resp.RecordDetail.RecordType + } else { + cr.Status.AtProvider.RecordType = nil + } + if resp.RecordDetail.Status != nil { + cr.Status.AtProvider.Status = resp.RecordDetail.Status + } else { + cr.Status.AtProvider.Status = nil + } + if resp.RecordDetail.UpdatedTime != nil { + cr.Status.AtProvider.UpdatedTime = &metav1.Time{*resp.RecordDetail.UpdatedTime} + } else { + cr.Status.AtProvider.UpdatedTime = nil + } + + return e.postCreate(ctx, cr, resp, managed.ExternalCreation{}, err) +} + +func (e *external) Update(ctx context.Context, mg cpresource.Managed) (managed.ExternalUpdate, error) { + cr, ok := mg.(*svcapitypes.ProvisionedProduct) + if !ok { + return managed.ExternalUpdate{}, errors.New(errUnexpectedObject) + } + input := GenerateUpdateProvisionedProductInput(cr) + if err := e.preUpdate(ctx, cr, input); err != nil { + return managed.ExternalUpdate{}, errors.Wrap(err, "pre-update failed") + } + resp, err := e.client.UpdateProvisionedProductWithContext(ctx, input) + return e.postUpdate(ctx, cr, resp, managed.ExternalUpdate{}, errorutils.Wrap(err, errUpdate)) +} + +func (e *external) Delete(ctx context.Context, mg cpresource.Managed) error { + cr, ok := mg.(*svcapitypes.ProvisionedProduct) + if !ok { + return errors.New(errUnexpectedObject) + } + cr.Status.SetConditions(xpv1.Deleting()) + input := GenerateTerminateProvisionedProductInput(cr) + ignore, err := e.preDelete(ctx, cr, input) + if err != nil { + return errors.Wrap(err, "pre-delete failed") + } + if ignore { + return nil + } + resp, err := e.client.TerminateProvisionedProductWithContext(ctx, input) + return e.postDelete(ctx, cr, resp, errorutils.Wrap(cpresource.Ignore(IsNotFound, err), errDelete)) +} + +type option func(*external) + +func newExternal(kube client.Client, client svcsdkapi.ServiceCatalogAPI, opts []option) *external { + e := &external{ + kube: kube, + client: client, + preObserve: nopPreObserve, + postObserve: nopPostObserve, + lateInitialize: nopLateInitialize, + isUpToDate: alwaysUpToDate, + preCreate: nopPreCreate, + postCreate: nopPostCreate, + preDelete: nopPreDelete, + postDelete: nopPostDelete, + preUpdate: nopPreUpdate, + postUpdate: nopPostUpdate, + } + for _, f := range opts { + f(e) + } + return e +} + +type external struct { + kube client.Client + client svcsdkapi.ServiceCatalogAPI + preObserve func(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.DescribeProvisionedProductInput) error + postObserve func(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.DescribeProvisionedProductOutput, managed.ExternalObservation, error) (managed.ExternalObservation, error) + lateInitialize func(*svcapitypes.ProvisionedProductParameters, *svcsdk.DescribeProvisionedProductOutput) error + isUpToDate func(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.DescribeProvisionedProductOutput) (bool, string, error) + preCreate func(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.ProvisionProductInput) error + postCreate func(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.ProvisionProductOutput, managed.ExternalCreation, error) (managed.ExternalCreation, error) + preDelete func(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.TerminateProvisionedProductInput) (bool, error) + postDelete func(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.TerminateProvisionedProductOutput, error) error + preUpdate func(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.UpdateProvisionedProductInput) error + postUpdate func(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.UpdateProvisionedProductOutput, managed.ExternalUpdate, error) (managed.ExternalUpdate, error) +} + +func nopPreObserve(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.DescribeProvisionedProductInput) error { + return nil +} + +func nopPostObserve(_ context.Context, _ *svcapitypes.ProvisionedProduct, _ *svcsdk.DescribeProvisionedProductOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) { + return obs, err +} +func nopLateInitialize(*svcapitypes.ProvisionedProductParameters, *svcsdk.DescribeProvisionedProductOutput) error { + return nil +} +func alwaysUpToDate(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.DescribeProvisionedProductOutput) (bool, string, error) { + return true, "", nil +} + +func nopPreCreate(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.ProvisionProductInput) error { + return nil +} +func nopPostCreate(_ context.Context, _ *svcapitypes.ProvisionedProduct, _ *svcsdk.ProvisionProductOutput, cre managed.ExternalCreation, err error) (managed.ExternalCreation, error) { + return cre, err +} +func nopPreDelete(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.TerminateProvisionedProductInput) (bool, error) { + return false, nil +} +func nopPostDelete(_ context.Context, _ *svcapitypes.ProvisionedProduct, _ *svcsdk.TerminateProvisionedProductOutput, err error) error { + return err +} +func nopPreUpdate(context.Context, *svcapitypes.ProvisionedProduct, *svcsdk.UpdateProvisionedProductInput) error { + return nil +} +func nopPostUpdate(_ context.Context, _ *svcapitypes.ProvisionedProduct, _ *svcsdk.UpdateProvisionedProductOutput, upd managed.ExternalUpdate, err error) (managed.ExternalUpdate, error) { + return upd, err +} diff --git a/pkg/controller/servicecatalog/provisionedproduct/zz_conversions.go b/pkg/controller/servicecatalog/provisionedproduct/zz_conversions.go new file mode 100644 index 0000000000..e18a9653d3 --- /dev/null +++ b/pkg/controller/servicecatalog/provisionedproduct/zz_conversions.go @@ -0,0 +1,256 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by ack-generate. DO NOT EDIT. + +package provisionedproduct + +import ( + "github.com/aws/aws-sdk-go/aws/awserr" + svcsdk "github.com/aws/aws-sdk-go/service/servicecatalog" + + svcapitypes "github.com/crossplane-contrib/provider-aws/apis/servicecatalog/v1alpha1" +) + +// NOTE(muvaf): We return pointers in case the function needs to start with an +// empty object, hence need to return a new pointer. + +// GenerateDescribeProvisionedProductInput returns input for read +// operation. +func GenerateDescribeProvisionedProductInput(cr *svcapitypes.ProvisionedProduct) *svcsdk.DescribeProvisionedProductInput { + res := &svcsdk.DescribeProvisionedProductInput{} + + if cr.Spec.ForProvider.AcceptLanguage != nil { + res.SetAcceptLanguage(*cr.Spec.ForProvider.AcceptLanguage) + } + + return res +} + +// GenerateProvisionedProduct returns the current state in the form of *svcapitypes.ProvisionedProduct. +func GenerateProvisionedProduct(resp *svcsdk.DescribeProvisionedProductOutput) *svcapitypes.ProvisionedProduct { + cr := &svcapitypes.ProvisionedProduct{} + + return cr +} + +// GenerateProvisionProductInput returns a create input. +func GenerateProvisionProductInput(cr *svcapitypes.ProvisionedProduct) *svcsdk.ProvisionProductInput { + res := &svcsdk.ProvisionProductInput{} + + if cr.Spec.ForProvider.AcceptLanguage != nil { + res.SetAcceptLanguage(*cr.Spec.ForProvider.AcceptLanguage) + } + if cr.Spec.ForProvider.NotificationARNs != nil { + f1 := []*string{} + for _, f1iter := range cr.Spec.ForProvider.NotificationARNs { + var f1elem string + f1elem = *f1iter + f1 = append(f1, &f1elem) + } + res.SetNotificationArns(f1) + } + if cr.Spec.ForProvider.PathID != nil { + res.SetPathId(*cr.Spec.ForProvider.PathID) + } + if cr.Spec.ForProvider.PathName != nil { + res.SetPathName(*cr.Spec.ForProvider.PathName) + } + if cr.Spec.ForProvider.ProductID != nil { + res.SetProductId(*cr.Spec.ForProvider.ProductID) + } + if cr.Spec.ForProvider.ProductName != nil { + res.SetProductName(*cr.Spec.ForProvider.ProductName) + } + if cr.Spec.ForProvider.ProvisioningArtifactID != nil { + res.SetProvisioningArtifactId(*cr.Spec.ForProvider.ProvisioningArtifactID) + } + if cr.Spec.ForProvider.ProvisioningArtifactName != nil { + res.SetProvisioningArtifactName(*cr.Spec.ForProvider.ProvisioningArtifactName) + } + if cr.Spec.ForProvider.ProvisioningParameters != nil { + f8 := []*svcsdk.ProvisioningParameter{} + for _, f8iter := range cr.Spec.ForProvider.ProvisioningParameters { + f8elem := &svcsdk.ProvisioningParameter{} + if f8iter.Key != nil { + f8elem.SetKey(*f8iter.Key) + } + if f8iter.Value != nil { + f8elem.SetValue(*f8iter.Value) + } + f8 = append(f8, f8elem) + } + res.SetProvisioningParameters(f8) + } + if cr.Spec.ForProvider.ProvisioningPreferences != nil { + f9 := &svcsdk.ProvisioningPreferences{} + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetAccounts != nil { + f9f0 := []*string{} + for _, f9f0iter := range cr.Spec.ForProvider.ProvisioningPreferences.StackSetAccounts { + var f9f0elem string + f9f0elem = *f9f0iter + f9f0 = append(f9f0, &f9f0elem) + } + f9.SetStackSetAccounts(f9f0) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetFailureToleranceCount != nil { + f9.SetStackSetFailureToleranceCount(*cr.Spec.ForProvider.ProvisioningPreferences.StackSetFailureToleranceCount) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetFailureTolerancePercentage != nil { + f9.SetStackSetFailureTolerancePercentage(*cr.Spec.ForProvider.ProvisioningPreferences.StackSetFailureTolerancePercentage) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetMaxConcurrencyCount != nil { + f9.SetStackSetMaxConcurrencyCount(*cr.Spec.ForProvider.ProvisioningPreferences.StackSetMaxConcurrencyCount) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetMaxConcurrencyPercentage != nil { + f9.SetStackSetMaxConcurrencyPercentage(*cr.Spec.ForProvider.ProvisioningPreferences.StackSetMaxConcurrencyPercentage) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetRegions != nil { + f9f5 := []*string{} + for _, f9f5iter := range cr.Spec.ForProvider.ProvisioningPreferences.StackSetRegions { + var f9f5elem string + f9f5elem = *f9f5iter + f9f5 = append(f9f5, &f9f5elem) + } + f9.SetStackSetRegions(f9f5) + } + res.SetProvisioningPreferences(f9) + } + if cr.Spec.ForProvider.Tags != nil { + f10 := []*svcsdk.Tag{} + for _, f10iter := range cr.Spec.ForProvider.Tags { + f10elem := &svcsdk.Tag{} + if f10iter.Key != nil { + f10elem.SetKey(*f10iter.Key) + } + if f10iter.Value != nil { + f10elem.SetValue(*f10iter.Value) + } + f10 = append(f10, f10elem) + } + res.SetTags(f10) + } + + return res +} + +// GenerateUpdateProvisionedProductInput returns an update input. +func GenerateUpdateProvisionedProductInput(cr *svcapitypes.ProvisionedProduct) *svcsdk.UpdateProvisionedProductInput { + res := &svcsdk.UpdateProvisionedProductInput{} + + if cr.Spec.ForProvider.AcceptLanguage != nil { + res.SetAcceptLanguage(*cr.Spec.ForProvider.AcceptLanguage) + } + if cr.Spec.ForProvider.PathID != nil { + res.SetPathId(*cr.Spec.ForProvider.PathID) + } + if cr.Spec.ForProvider.PathName != nil { + res.SetPathName(*cr.Spec.ForProvider.PathName) + } + if cr.Spec.ForProvider.ProductID != nil { + res.SetProductId(*cr.Spec.ForProvider.ProductID) + } + if cr.Spec.ForProvider.ProductName != nil { + res.SetProductName(*cr.Spec.ForProvider.ProductName) + } + if cr.Spec.ForProvider.ProvisioningArtifactID != nil { + res.SetProvisioningArtifactId(*cr.Spec.ForProvider.ProvisioningArtifactID) + } + if cr.Spec.ForProvider.ProvisioningArtifactName != nil { + res.SetProvisioningArtifactName(*cr.Spec.ForProvider.ProvisioningArtifactName) + } + if cr.Spec.ForProvider.ProvisioningParameters != nil { + f7 := []*svcsdk.UpdateProvisioningParameter{} + for _, f7iter := range cr.Spec.ForProvider.ProvisioningParameters { + f7elem := &svcsdk.UpdateProvisioningParameter{} + if f7iter.Key != nil { + f7elem.SetKey(*f7iter.Key) + } + if f7iter.Value != nil { + f7elem.SetValue(*f7iter.Value) + } + f7 = append(f7, f7elem) + } + res.SetProvisioningParameters(f7) + } + if cr.Spec.ForProvider.ProvisioningPreferences != nil { + f8 := &svcsdk.UpdateProvisioningPreferences{} + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetAccounts != nil { + f8f0 := []*string{} + for _, f8f0iter := range cr.Spec.ForProvider.ProvisioningPreferences.StackSetAccounts { + var f8f0elem string + f8f0elem = *f8f0iter + f8f0 = append(f8f0, &f8f0elem) + } + f8.SetStackSetAccounts(f8f0) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetFailureToleranceCount != nil { + f8.SetStackSetFailureToleranceCount(*cr.Spec.ForProvider.ProvisioningPreferences.StackSetFailureToleranceCount) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetFailureTolerancePercentage != nil { + f8.SetStackSetFailureTolerancePercentage(*cr.Spec.ForProvider.ProvisioningPreferences.StackSetFailureTolerancePercentage) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetMaxConcurrencyCount != nil { + f8.SetStackSetMaxConcurrencyCount(*cr.Spec.ForProvider.ProvisioningPreferences.StackSetMaxConcurrencyCount) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetMaxConcurrencyPercentage != nil { + f8.SetStackSetMaxConcurrencyPercentage(*cr.Spec.ForProvider.ProvisioningPreferences.StackSetMaxConcurrencyPercentage) + } + if cr.Spec.ForProvider.ProvisioningPreferences.StackSetRegions != nil { + f8f5 := []*string{} + for _, f8f5iter := range cr.Spec.ForProvider.ProvisioningPreferences.StackSetRegions { + var f8f5elem string + f8f5elem = *f8f5iter + f8f5 = append(f8f5, &f8f5elem) + } + f8.SetStackSetRegions(f8f5) + } + res.SetProvisioningPreferences(f8) + } + if cr.Spec.ForProvider.Tags != nil { + f9 := []*svcsdk.Tag{} + for _, f9iter := range cr.Spec.ForProvider.Tags { + f9elem := &svcsdk.Tag{} + if f9iter.Key != nil { + f9elem.SetKey(*f9iter.Key) + } + if f9iter.Value != nil { + f9elem.SetValue(*f9iter.Value) + } + f9 = append(f9, f9elem) + } + res.SetTags(f9) + } + + return res +} + +// GenerateTerminateProvisionedProductInput returns a deletion input. +func GenerateTerminateProvisionedProductInput(cr *svcapitypes.ProvisionedProduct) *svcsdk.TerminateProvisionedProductInput { + res := &svcsdk.TerminateProvisionedProductInput{} + + if cr.Spec.ForProvider.AcceptLanguage != nil { + res.SetAcceptLanguage(*cr.Spec.ForProvider.AcceptLanguage) + } + + return res +} + +// IsNotFound returns whether the given error is of type NotFound or not. +func IsNotFound(err error) bool { + awsErr, ok := err.(awserr.Error) + return ok && awsErr.Code() == "ResourceNotFoundException" +} diff --git a/pkg/controller/servicecatalog/setup.go b/pkg/controller/servicecatalog/setup.go new file mode 100644 index 0000000000..e289c8629e --- /dev/null +++ b/pkg/controller/servicecatalog/setup.go @@ -0,0 +1,33 @@ +/* +Copyright 2023 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package servicecatalog + +import ( + "github.com/crossplane/crossplane-runtime/pkg/controller" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/crossplane-contrib/provider-aws/pkg/controller/servicecatalog/provisionedproduct" + "github.com/crossplane-contrib/provider-aws/pkg/utils/setup" +) + +// Setup servicecatalog controllers. +func Setup(mgr ctrl.Manager, o controller.Options) error { + return setup.SetupControllers( + mgr, o, + provisionedproduct.SetupProvisionedProduct, + ) +}