diff --git a/apis/v1alpha1/ack-generate-metadata.yaml b/apis/v1alpha1/ack-generate-metadata.yaml index 5b43abd..6b13c70 100755 --- a/apis/v1alpha1/ack-generate-metadata.yaml +++ b/apis/v1alpha1/ack-generate-metadata.yaml @@ -1,13 +1,13 @@ ack_generate_info: - build_date: "2025-10-14T01:34:11Z" - build_hash: eaabefb6bd7b2be8a1baf4478f22b3310e6921c8 + build_date: "2025-10-20T15:37:08Z" + build_hash: f25517757439025aa7058673d97267033f5b9acc go_version: go1.24.0 - version: v0.52.0-6-geaabefb-dirty -api_directory_checksum: c06e8d99c29af219e017c9d519827d168cf2d4c8 + version: v0.52.0-7-gf255177 +api_directory_checksum: 60dd2e0fe820ba29b0c906cb9debcd88f1ac1810 api_version: v1alpha1 aws_sdk_go_version: v1.39.2 generator_config_info: - file_checksum: 10cf07101569163f4eb9545f230f040211c1a2f6 + file_checksum: 90d7abc62e7f2b85e403743a40e1b7827503cccd original_file_name: generator.yaml last_modification: reason: API generation diff --git a/apis/v1alpha1/agent_runtime.go b/apis/v1alpha1/agent_runtime.go new file mode 100644 index 0000000..ad21634 --- /dev/null +++ b/apis/v1alpha1/agent_runtime.go @@ -0,0 +1,115 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// AgentRuntimeSpec defines the desired state of AgentRuntime. +// +// Contains information about an agent runtime. An agent runtime is the execution +// environment for a Amazon Bedrock Agent. +type AgentRuntimeSpec struct { + + // The artifact of the AgentCore Runtime. + // +kubebuilder:validation:Required + AgentRuntimeArtifact *AgentRuntimeArtifact `json:"agentRuntimeArtifact"` + // The name of the AgentCore Runtime. + // + // Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,47}$` + // +kubebuilder:validation:Required + AgentRuntimeName *string `json:"agentRuntimeName"` + // The authorizer configuration for the AgentCore Runtime. + AuthorizerConfiguration *AuthorizerConfiguration `json:"authorizerConfiguration,omitempty"` + // The description of the AgentCore Runtime. + Description *string `json:"description,omitempty"` + // Environment variables to set in the AgentCore Runtime environment. + EnvironmentVariables map[string]*string `json:"environmentVariables,omitempty"` + // The network configuration for the AgentCore Runtime. + // +kubebuilder:validation:Required + NetworkConfiguration *NetworkConfiguration `json:"networkConfiguration"` + ProtocolConfiguration *ProtocolConfiguration `json:"protocolConfiguration,omitempty"` + // Configuration for HTTP request headers that will be passed through to the + // runtime. + RequestHeaderConfiguration *RequestHeaderConfiguration `json:"requestHeaderConfiguration,omitempty"` + // The IAM role ARN that provides permissions for the AgentCore Runtime. + // + // Regex Pattern: `^arn:aws(-[^:]+)?:iam::([0-9]{12})?:role/.+$` + // +kubebuilder:validation:Required + RoleARN *string `json:"roleARN"` + // A map of tag keys and values to assign to the agent runtime. Tags enable + // you to categorize your resources in different ways, for example, by purpose, + // owner, or environment. + Tags map[string]*string `json:"tags,omitempty"` +} + +// AgentRuntimeStatus defines the observed state of AgentRuntime +type AgentRuntimeStatus struct { + // All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + // that is used to contain resource sync state, account ownership, + // constructed ARN for the resource + // +kubebuilder:validation:Optional + ACKResourceMetadata *ackv1alpha1.ResourceMetadata `json:"ackResourceMetadata"` + // All CRs managed by ACK have a common `Status.Conditions` member that + // contains a collection of `ackv1alpha1.Condition` objects that describe + // the various terminal states of the CR and its backend AWS service API + // resource + // +kubebuilder:validation:Optional + Conditions []*ackv1alpha1.Condition `json:"conditions"` + // The unique identifier of the AgentCore Runtime. + // + // Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,99}-[a-zA-Z0-9]{10}$` + // +kubebuilder:validation:Optional + AgentRuntimeID *string `json:"agentRuntimeID,omitempty"` + // The version of the AgentCore Runtime. + // + // Regex Pattern: `^([1-9][0-9]{0,4})$` + // +kubebuilder:validation:Optional + AgentRuntimeVersion *string `json:"agentRuntimeVersion,omitempty"` + // The timestamp when the AgentCore Runtime was created. + // +kubebuilder:validation:Optional + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + // The current status of the AgentCore Runtime. + // +kubebuilder:validation:Optional + Status *string `json:"status,omitempty"` + // The workload identity details for the AgentCore Runtime. + // +kubebuilder:validation:Optional + WorkloadIdentityDetails *WorkloadIdentityDetails `json:"workloadIdentityDetails,omitempty"` +} + +// AgentRuntime is the Schema for the AgentRuntimes API +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +type AgentRuntime struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec AgentRuntimeSpec `json:"spec,omitempty"` + Status AgentRuntimeStatus `json:"status,omitempty"` +} + +// AgentRuntimeList contains a list of AgentRuntime +// +kubebuilder:object:root=true +type AgentRuntimeList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AgentRuntime `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AgentRuntime{}, &AgentRuntimeList{}) +} diff --git a/apis/v1alpha1/agent_runtime_endpoint.go b/apis/v1alpha1/agent_runtime_endpoint.go new file mode 100644 index 0000000..806da89 --- /dev/null +++ b/apis/v1alpha1/agent_runtime_endpoint.go @@ -0,0 +1,101 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// AgentRuntimeEndpointSpec defines the desired state of AgentRuntimeEndpoint. +// +// Contains information about an agent runtime endpoint. An endpoint provides +// a way to connect to and interact with an agent runtime. +type AgentRuntimeEndpointSpec struct { + + // The unique identifier of the AgentCore Runtime to create an endpoint for. + // + // Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,99}-[a-zA-Z0-9]{10}$` + // +kubebuilder:validation:Required + AgentRuntimeID *string `json:"agentRuntimeID"` + // The version of the AgentCore Runtime to use for the endpoint. + // + // Regex Pattern: `^([1-9][0-9]{0,4})$` + AgentRuntimeVersion *string `json:"agentRuntimeVersion,omitempty"` + // The description of the AgentCore Runtime endpoint. + Description *string `json:"description,omitempty"` + // The name of the AgentCore Runtime endpoint. + // + // Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,47}$` + Name *string `json:"name,omitempty"` + // A map of tag keys and values to assign to the agent runtime endpoint. Tags + // enable you to categorize your resources in different ways, for example, by + // purpose, owner, or environment. + Tags map[string]*string `json:"tags,omitempty"` +} + +// AgentRuntimeEndpointStatus defines the observed state of AgentRuntimeEndpoint +type AgentRuntimeEndpointStatus struct { + // All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + // that is used to contain resource sync state, account ownership, + // constructed ARN for the resource + // +kubebuilder:validation:Optional + ACKResourceMetadata *ackv1alpha1.ResourceMetadata `json:"ackResourceMetadata"` + // All CRs managed by ACK have a common `Status.Conditions` member that + // contains a collection of `ackv1alpha1.Condition` objects that describe + // the various terminal states of the CR and its backend AWS service API + // resource + // +kubebuilder:validation:Optional + Conditions []*ackv1alpha1.Condition `json:"conditions"` + // The Amazon Resource Name (ARN) of the AgentCore Runtime. + // + // Regex Pattern: `^arn:(-[^:]+)?:bedrock-agentcore:[a-z0-9-]+:[0-9]{12}:agent/[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}:([0-9]{0,4}[1-9][0-9]{0,4})$` + // +kubebuilder:validation:Optional + AgentRuntimeARN *string `json:"agentRuntimeARN,omitempty"` + // The timestamp when the AgentCore Runtime endpoint was created. + // +kubebuilder:validation:Optional + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + // The current status of the AgentCore Runtime endpoint. + // +kubebuilder:validation:Optional + Status *string `json:"status,omitempty"` + // The target version of the AgentCore Runtime for the endpoint. + // + // Regex Pattern: `^([1-9][0-9]{0,4})$` + // +kubebuilder:validation:Optional + TargetVersion *string `json:"targetVersion,omitempty"` +} + +// AgentRuntimeEndpoint is the Schema for the AgentRuntimeEndpoints API +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +type AgentRuntimeEndpoint struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec AgentRuntimeEndpointSpec `json:"spec,omitempty"` + Status AgentRuntimeEndpointStatus `json:"status,omitempty"` +} + +// AgentRuntimeEndpointList contains a list of AgentRuntimeEndpoint +// +kubebuilder:object:root=true +type AgentRuntimeEndpointList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AgentRuntimeEndpoint `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AgentRuntimeEndpoint{}, &AgentRuntimeEndpointList{}) +} diff --git a/apis/v1alpha1/enums.go b/apis/v1alpha1/enums.go index c08a2a8..6b53332 100644 --- a/apis/v1alpha1/enums.go +++ b/apis/v1alpha1/enums.go @@ -22,26 +22,26 @@ const ( APIKeyCredentialLocation_QUERY_PARAMETER APIKeyCredentialLocation = "QUERY_PARAMETER" ) -type AgentRuntimeEndpointStatus string +type AgentRuntimeEndpointStatus_SDK string const ( - AgentRuntimeEndpointStatus_CREATE_FAILED AgentRuntimeEndpointStatus = "CREATE_FAILED" - AgentRuntimeEndpointStatus_CREATING AgentRuntimeEndpointStatus = "CREATING" - AgentRuntimeEndpointStatus_DELETING AgentRuntimeEndpointStatus = "DELETING" - AgentRuntimeEndpointStatus_READY AgentRuntimeEndpointStatus = "READY" - AgentRuntimeEndpointStatus_UPDATE_FAILED AgentRuntimeEndpointStatus = "UPDATE_FAILED" - AgentRuntimeEndpointStatus_UPDATING AgentRuntimeEndpointStatus = "UPDATING" + AgentRuntimeEndpointStatus_SDK_CREATE_FAILED AgentRuntimeEndpointStatus_SDK = "CREATE_FAILED" + AgentRuntimeEndpointStatus_SDK_CREATING AgentRuntimeEndpointStatus_SDK = "CREATING" + AgentRuntimeEndpointStatus_SDK_DELETING AgentRuntimeEndpointStatus_SDK = "DELETING" + AgentRuntimeEndpointStatus_SDK_READY AgentRuntimeEndpointStatus_SDK = "READY" + AgentRuntimeEndpointStatus_SDK_UPDATE_FAILED AgentRuntimeEndpointStatus_SDK = "UPDATE_FAILED" + AgentRuntimeEndpointStatus_SDK_UPDATING AgentRuntimeEndpointStatus_SDK = "UPDATING" ) -type AgentRuntimeStatus string +type AgentRuntimeStatus_SDK string const ( - AgentRuntimeStatus_CREATE_FAILED AgentRuntimeStatus = "CREATE_FAILED" - AgentRuntimeStatus_CREATING AgentRuntimeStatus = "CREATING" - AgentRuntimeStatus_DELETING AgentRuntimeStatus = "DELETING" - AgentRuntimeStatus_READY AgentRuntimeStatus = "READY" - AgentRuntimeStatus_UPDATE_FAILED AgentRuntimeStatus = "UPDATE_FAILED" - AgentRuntimeStatus_UPDATING AgentRuntimeStatus = "UPDATING" + AgentRuntimeStatus_SDK_CREATE_FAILED AgentRuntimeStatus_SDK = "CREATE_FAILED" + AgentRuntimeStatus_SDK_CREATING AgentRuntimeStatus_SDK = "CREATING" + AgentRuntimeStatus_SDK_DELETING AgentRuntimeStatus_SDK = "DELETING" + AgentRuntimeStatus_SDK_READY AgentRuntimeStatus_SDK = "READY" + AgentRuntimeStatus_SDK_UPDATE_FAILED AgentRuntimeStatus_SDK = "UPDATE_FAILED" + AgentRuntimeStatus_SDK_UPDATING AgentRuntimeStatus_SDK = "UPDATING" ) type AuthorizerType string diff --git a/apis/v1alpha1/generator.yaml b/apis/v1alpha1/generator.yaml index 98bcc51..3ec6452 100644 --- a/apis/v1alpha1/generator.yaml +++ b/apis/v1alpha1/generator.yaml @@ -1,7 +1,7 @@ ignore: resource_names: - - AgentRuntime - - AgentRuntimeEndpoint + # AgentRuntime + # AgentRuntimeEndpoint - ApiKeyCredentialProvider - Browser - CodeInterpreter @@ -10,6 +10,45 @@ ignore: - Memory - Oauth2CredentialProvider - WorkloadIdentity + field_paths: + - CreateAgentRuntimeInput.ClientToken + - CreateAgentRuntimeEndpointInput.ClientToken sdk_names: model_name: bedrock-agentcore-control + +resources: + AgentRuntime: + exceptions: + terminal_codes: + - ValidationException + hooks: + sdk_read_one_post_set_output: + template_path: hooks/agentruntime/sdk_read_one_post_set_output.go.tpl + sdk_update_pre_build_request: + template_path: hooks/agentruntime/sdk_update_pre_build_request.go.tpl + + AgentRuntimeEndpoint: + renames: + operations: + GetAgentRuntimeEndpoint: + input_fields: + EndpointName: Name + CreateAgentRuntimeEndpoint: + input_fields: + EndpointName: Name + DeleteAgentRuntimeEndpoint: + input_fields: + EndpointName: Name + fields: + Name: + is_primary_key: true + hooks: + sdk_read_one_post_set_output: + template_path: hooks/agentruntimeendpoint/sdk_read_one_post_set_output.go.tpl + sdk_update_pre_build_request: + template_path: hooks/agentruntimeendpoint/sdk_update_pre_build_request.go.tpl + exceptions: + errors: + 404: + code: AccessDeniedException diff --git a/apis/v1alpha1/types.go b/apis/v1alpha1/types.go index 9b23f5e..eac6324 100644 --- a/apis/v1alpha1/types.go +++ b/apis/v1alpha1/types.go @@ -27,3 +27,250 @@ var ( _ = &aws.JSONValue{} _ = ackv1alpha1.AWSAccountID("") ) + +// The artifact of the agent. +type AgentRuntimeArtifact struct { + // Representation of a container configuration. + ContainerConfiguration *ContainerConfiguration `json:"containerConfiguration,omitempty"` +} + +// Contains information about an agent runtime endpoint. An endpoint provides +// a way to connect to and interact with an agent runtime. +type AgentRuntimeEndpoint_SDK struct { + AgentRuntimeARN *string `json:"agentRuntimeARN,omitempty"` + AgentRuntimeEndpointARN *string `json:"agentRuntimeEndpointARN,omitempty"` + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + Description *string `json:"description,omitempty"` + ID *string `json:"id,omitempty"` + LastUpdatedAt *metav1.Time `json:"lastUpdatedAt,omitempty"` + LiveVersion *string `json:"liveVersion,omitempty"` + Name *string `json:"name,omitempty"` + Status *string `json:"status,omitempty"` + TargetVersion *string `json:"targetVersion,omitempty"` +} + +// Contains information about an agent runtime. An agent runtime is the execution +// environment for a Amazon Bedrock Agent. +type AgentRuntime_SDK struct { + AgentRuntimeARN *string `json:"agentRuntimeARN,omitempty"` + AgentRuntimeID *string `json:"agentRuntimeID,omitempty"` + AgentRuntimeName *string `json:"agentRuntimeName,omitempty"` + AgentRuntimeVersion *string `json:"agentRuntimeVersion,omitempty"` + Description *string `json:"description,omitempty"` + LastUpdatedAt *metav1.Time `json:"lastUpdatedAt,omitempty"` + Status *string `json:"status,omitempty"` +} + +// Represents inbound authorization configuration options used to authenticate +// incoming requests. +type AuthorizerConfiguration struct { + // Configuration for inbound JWT-based authorization, specifying how incoming + // requests should be authenticated. + CustomJWTAuthorizer *CustomJWTAuthorizerConfiguration `json:"customJWTAuthorizer,omitempty"` +} + +// The network configuration for a browser. This structure defines how the browser +// connects to the network. +type BrowserNetworkConfiguration struct { + // VpcConfig for the Agent. + VPCConfig *VPCConfig `json:"vpcConfig,omitempty"` +} + +// Contains summary information about a browser. A browser enables Amazon Bedrock +// Agent to interact with web content. +type BrowserSummary struct { + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + Description *string `json:"description,omitempty"` + LastUpdatedAt *metav1.Time `json:"lastUpdatedAt,omitempty"` +} + +// The network configuration for a code interpreter. This structure defines +// how the code interpreter connects to the network. +type CodeInterpreterNetworkConfiguration struct { + // VpcConfig for the Agent. + VPCConfig *VPCConfig `json:"vpcConfig,omitempty"` +} + +// Contains summary information about a code interpreter. A code interpreter +// enables Amazon Bedrock Agent to execute code. +type CodeInterpreterSummary struct { + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + Description *string `json:"description,omitempty"` + LastUpdatedAt *metav1.Time `json:"lastUpdatedAt,omitempty"` +} + +// Representation of a container configuration. +type ContainerConfiguration struct { + ContainerURI *string `json:"containerURI,omitempty"` +} + +// Configuration for inbound JWT-based authorization, specifying how incoming +// requests should be authenticated. +type CustomJWTAuthorizerConfiguration struct { + AllowedAudience []*string `json:"allowedAudience,omitempty"` + AllowedClients []*string `json:"allowedClients,omitempty"` + DiscoveryURL *string `json:"discoveryURL,omitempty"` +} + +// Input for creating a custom memory strategy. +type CustomMemoryStrategyInput struct { + Description *string `json:"description,omitempty"` +} + +// Input for deleting a memory strategy. +type DeleteMemoryStrategyInput struct { + MemoryStrategyID *string `json:"memoryStrategyID,omitempty"` +} + +// Contains summary information about a gateway. +type GatewaySummary struct { + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + UpdatedAt *metav1.Time `json:"updatedAt,omitempty"` +} + +// Contains information about a memory resource. +type Memory struct { + Description *string `json:"description,omitempty"` + FailureReason *string `json:"failureReason,omitempty"` +} + +// Contains information about a memory strategy. +type MemoryStrategy struct { + Description *string `json:"description,omitempty"` +} + +// Input for modifying a memory strategy. +type ModifyMemoryStrategyInput struct { + Description *string `json:"description,omitempty"` + MemoryStrategyID *string `json:"memoryStrategyID,omitempty"` +} + +// SecurityConfig for the Agent. +type NetworkConfiguration struct { + NetworkMode *string `json:"networkMode,omitempty"` + // VpcConfig for the Agent. + NetworkModeConfig *VPCConfig `json:"networkModeConfig,omitempty"` +} + +// The protocol configuration for an agent runtime. This structure defines how +// the agent runtime communicates with clients. +type ProtocolConfiguration struct { + ServerProtocol *string `json:"serverProtocol,omitempty"` +} + +// Configuration for HTTP request headers that will be passed through to the +// runtime. +type RequestHeaderConfiguration struct { + RequestHeaderAllowlist []*string `json:"requestHeaderAllowlist,omitempty"` +} + +// The Amazon S3 location for storing data. This structure defines where in +// Amazon S3 data is stored. +type S3Location struct { + Bucket *string `json:"bucket,omitempty"` + Prefix *string `json:"prefix,omitempty"` +} + +// A schema definition for a gateway target. This structure defines the structure +// of the API that the target exposes. +type SchemaDefinition struct { + Description *string `json:"description,omitempty"` +} + +// Contains semantic consolidation override configuration. +type SemanticConsolidationOverride struct { + ModelID *string `json:"modelID,omitempty"` +} + +// Contains semantic extraction override configuration. +type SemanticExtractionOverride struct { + ModelID *string `json:"modelID,omitempty"` +} + +// Input for creating a semantic memory strategy. +type SemanticMemoryStrategyInput struct { + Description *string `json:"description,omitempty"` +} + +// Input for semantic override consolidation configuration in a memory strategy. +type SemanticOverrideConsolidationConfigurationInput struct { + ModelID *string `json:"modelID,omitempty"` +} + +// Input for semantic override extraction configuration in a memory strategy. +type SemanticOverrideExtractionConfigurationInput struct { + ModelID *string `json:"modelID,omitempty"` +} + +// Contains summary consolidation override configuration. +type SummaryConsolidationOverride struct { + ModelID *string `json:"modelID,omitempty"` +} + +// Input for creating a summary memory strategy. +type SummaryMemoryStrategyInput struct { + Description *string `json:"description,omitempty"` +} + +// Input for summary override consolidation configuration in a memory strategy. +type SummaryOverrideConsolidationConfigurationInput struct { + ModelID *string `json:"modelID,omitempty"` +} + +// Contains summary information about a gateway target. A target represents +// an endpoint that the gateway can connect to. +type TargetSummary struct { + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + UpdatedAt *metav1.Time `json:"updatedAt,omitempty"` +} + +// A tool definition for a gateway target. This structure defines a tool that +// the target exposes through the Model Context Protocol. +type ToolDefinition struct { + Description *string `json:"description,omitempty"` + Name *string `json:"name,omitempty"` +} + +// Contains user preference consolidation override configuration. +type UserPreferenceConsolidationOverride struct { + ModelID *string `json:"modelID,omitempty"` +} + +// Contains user preference extraction override configuration. +type UserPreferenceExtractionOverride struct { + ModelID *string `json:"modelID,omitempty"` +} + +// Input for creating a user preference memory strategy. +type UserPreferenceMemoryStrategyInput struct { + Description *string `json:"description,omitempty"` +} + +// Input for user preference override consolidation configuration in a memory +// strategy. +type UserPreferenceOverrideConsolidationConfigurationInput struct { + ModelID *string `json:"modelID,omitempty"` +} + +// Input for user preference override extraction configuration in a memory strategy. +type UserPreferenceOverrideExtractionConfigurationInput struct { + ModelID *string `json:"modelID,omitempty"` +} + +// VpcConfig for the Agent. +type VPCConfig struct { + SecurityGroups []*string `json:"securityGroups,omitempty"` + Subnets []*string `json:"subnets,omitempty"` +} + +// Stores information about a field passed inside a request that resulted in +// an exception. +type ValidationExceptionField struct { + Message *string `json:"message,omitempty"` + Name *string `json:"name,omitempty"` +} + +// The information about the workload identity. +type WorkloadIdentityDetails struct { + WorkloadIdentityARN *string `json:"workloadIdentityARN,omitempty"` +} diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..f6adad1 --- /dev/null +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,1335 @@ +//go:build !ignore_autogenerated + +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + corev1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AgentRuntime) DeepCopyInto(out *AgentRuntime) { + *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 AgentRuntime. +func (in *AgentRuntime) DeepCopy() *AgentRuntime { + if in == nil { + return nil + } + out := new(AgentRuntime) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AgentRuntime) 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 *AgentRuntimeArtifact) DeepCopyInto(out *AgentRuntimeArtifact) { + *out = *in + if in.ContainerConfiguration != nil { + in, out := &in.ContainerConfiguration, &out.ContainerConfiguration + *out = new(ContainerConfiguration) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentRuntimeArtifact. +func (in *AgentRuntimeArtifact) DeepCopy() *AgentRuntimeArtifact { + if in == nil { + return nil + } + out := new(AgentRuntimeArtifact) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AgentRuntimeEndpoint) DeepCopyInto(out *AgentRuntimeEndpoint) { + *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 AgentRuntimeEndpoint. +func (in *AgentRuntimeEndpoint) DeepCopy() *AgentRuntimeEndpoint { + if in == nil { + return nil + } + out := new(AgentRuntimeEndpoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AgentRuntimeEndpoint) 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 *AgentRuntimeEndpointList) DeepCopyInto(out *AgentRuntimeEndpointList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AgentRuntimeEndpoint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentRuntimeEndpointList. +func (in *AgentRuntimeEndpointList) DeepCopy() *AgentRuntimeEndpointList { + if in == nil { + return nil + } + out := new(AgentRuntimeEndpointList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AgentRuntimeEndpointList) 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 *AgentRuntimeEndpointSpec) DeepCopyInto(out *AgentRuntimeEndpointSpec) { + *out = *in + if in.AgentRuntimeID != nil { + in, out := &in.AgentRuntimeID, &out.AgentRuntimeID + *out = new(string) + **out = **in + } + if in.AgentRuntimeVersion != nil { + in, out := &in.AgentRuntimeVersion, &out.AgentRuntimeVersion + *out = new(string) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentRuntimeEndpointSpec. +func (in *AgentRuntimeEndpointSpec) DeepCopy() *AgentRuntimeEndpointSpec { + if in == nil { + return nil + } + out := new(AgentRuntimeEndpointSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AgentRuntimeEndpointStatus) DeepCopyInto(out *AgentRuntimeEndpointStatus) { + *out = *in + if in.ACKResourceMetadata != nil { + in, out := &in.ACKResourceMetadata, &out.ACKResourceMetadata + *out = new(corev1alpha1.ResourceMetadata) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]*corev1alpha1.Condition, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(corev1alpha1.Condition) + (*in).DeepCopyInto(*out) + } + } + } + if in.AgentRuntimeARN != nil { + in, out := &in.AgentRuntimeARN, &out.AgentRuntimeARN + *out = new(string) + **out = **in + } + if in.CreatedAt != nil { + in, out := &in.CreatedAt, &out.CreatedAt + *out = (*in).DeepCopy() + } + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(string) + **out = **in + } + if in.TargetVersion != nil { + in, out := &in.TargetVersion, &out.TargetVersion + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentRuntimeEndpointStatus. +func (in *AgentRuntimeEndpointStatus) DeepCopy() *AgentRuntimeEndpointStatus { + if in == nil { + return nil + } + out := new(AgentRuntimeEndpointStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AgentRuntimeEndpoint_SDK) DeepCopyInto(out *AgentRuntimeEndpoint_SDK) { + *out = *in + if in.AgentRuntimeARN != nil { + in, out := &in.AgentRuntimeARN, &out.AgentRuntimeARN + *out = new(string) + **out = **in + } + if in.AgentRuntimeEndpointARN != nil { + in, out := &in.AgentRuntimeEndpointARN, &out.AgentRuntimeEndpointARN + *out = new(string) + **out = **in + } + if in.CreatedAt != nil { + in, out := &in.CreatedAt, &out.CreatedAt + *out = (*in).DeepCopy() + } + 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.LastUpdatedAt != nil { + in, out := &in.LastUpdatedAt, &out.LastUpdatedAt + *out = (*in).DeepCopy() + } + if in.LiveVersion != nil { + in, out := &in.LiveVersion, &out.LiveVersion + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(string) + **out = **in + } + if in.TargetVersion != nil { + in, out := &in.TargetVersion, &out.TargetVersion + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentRuntimeEndpoint_SDK. +func (in *AgentRuntimeEndpoint_SDK) DeepCopy() *AgentRuntimeEndpoint_SDK { + if in == nil { + return nil + } + out := new(AgentRuntimeEndpoint_SDK) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AgentRuntimeList) DeepCopyInto(out *AgentRuntimeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AgentRuntime, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentRuntimeList. +func (in *AgentRuntimeList) DeepCopy() *AgentRuntimeList { + if in == nil { + return nil + } + out := new(AgentRuntimeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AgentRuntimeList) 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 *AgentRuntimeSpec) DeepCopyInto(out *AgentRuntimeSpec) { + *out = *in + if in.AgentRuntimeArtifact != nil { + in, out := &in.AgentRuntimeArtifact, &out.AgentRuntimeArtifact + *out = new(AgentRuntimeArtifact) + (*in).DeepCopyInto(*out) + } + if in.AgentRuntimeName != nil { + in, out := &in.AgentRuntimeName, &out.AgentRuntimeName + *out = new(string) + **out = **in + } + if in.AuthorizerConfiguration != nil { + in, out := &in.AuthorizerConfiguration, &out.AuthorizerConfiguration + *out = new(AuthorizerConfiguration) + (*in).DeepCopyInto(*out) + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.EnvironmentVariables != nil { + in, out := &in.EnvironmentVariables, &out.EnvironmentVariables + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } + if in.NetworkConfiguration != nil { + in, out := &in.NetworkConfiguration, &out.NetworkConfiguration + *out = new(NetworkConfiguration) + (*in).DeepCopyInto(*out) + } + if in.ProtocolConfiguration != nil { + in, out := &in.ProtocolConfiguration, &out.ProtocolConfiguration + *out = new(ProtocolConfiguration) + (*in).DeepCopyInto(*out) + } + if in.RequestHeaderConfiguration != nil { + in, out := &in.RequestHeaderConfiguration, &out.RequestHeaderConfiguration + *out = new(RequestHeaderConfiguration) + (*in).DeepCopyInto(*out) + } + if in.RoleARN != nil { + in, out := &in.RoleARN, &out.RoleARN + *out = new(string) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentRuntimeSpec. +func (in *AgentRuntimeSpec) DeepCopy() *AgentRuntimeSpec { + if in == nil { + return nil + } + out := new(AgentRuntimeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AgentRuntimeStatus) DeepCopyInto(out *AgentRuntimeStatus) { + *out = *in + if in.ACKResourceMetadata != nil { + in, out := &in.ACKResourceMetadata, &out.ACKResourceMetadata + *out = new(corev1alpha1.ResourceMetadata) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]*corev1alpha1.Condition, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(corev1alpha1.Condition) + (*in).DeepCopyInto(*out) + } + } + } + if in.AgentRuntimeID != nil { + in, out := &in.AgentRuntimeID, &out.AgentRuntimeID + *out = new(string) + **out = **in + } + if in.AgentRuntimeVersion != nil { + in, out := &in.AgentRuntimeVersion, &out.AgentRuntimeVersion + *out = new(string) + **out = **in + } + if in.CreatedAt != nil { + in, out := &in.CreatedAt, &out.CreatedAt + *out = (*in).DeepCopy() + } + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(string) + **out = **in + } + if in.WorkloadIdentityDetails != nil { + in, out := &in.WorkloadIdentityDetails, &out.WorkloadIdentityDetails + *out = new(WorkloadIdentityDetails) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentRuntimeStatus. +func (in *AgentRuntimeStatus) DeepCopy() *AgentRuntimeStatus { + if in == nil { + return nil + } + out := new(AgentRuntimeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AgentRuntime_SDK) DeepCopyInto(out *AgentRuntime_SDK) { + *out = *in + if in.AgentRuntimeARN != nil { + in, out := &in.AgentRuntimeARN, &out.AgentRuntimeARN + *out = new(string) + **out = **in + } + if in.AgentRuntimeID != nil { + in, out := &in.AgentRuntimeID, &out.AgentRuntimeID + *out = new(string) + **out = **in + } + if in.AgentRuntimeName != nil { + in, out := &in.AgentRuntimeName, &out.AgentRuntimeName + *out = new(string) + **out = **in + } + if in.AgentRuntimeVersion != nil { + in, out := &in.AgentRuntimeVersion, &out.AgentRuntimeVersion + *out = new(string) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.LastUpdatedAt != nil { + in, out := &in.LastUpdatedAt, &out.LastUpdatedAt + *out = (*in).DeepCopy() + } + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentRuntime_SDK. +func (in *AgentRuntime_SDK) DeepCopy() *AgentRuntime_SDK { + if in == nil { + return nil + } + out := new(AgentRuntime_SDK) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthorizerConfiguration) DeepCopyInto(out *AuthorizerConfiguration) { + *out = *in + if in.CustomJWTAuthorizer != nil { + in, out := &in.CustomJWTAuthorizer, &out.CustomJWTAuthorizer + *out = new(CustomJWTAuthorizerConfiguration) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorizerConfiguration. +func (in *AuthorizerConfiguration) DeepCopy() *AuthorizerConfiguration { + if in == nil { + return nil + } + out := new(AuthorizerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BrowserNetworkConfiguration) DeepCopyInto(out *BrowserNetworkConfiguration) { + *out = *in + if in.VPCConfig != nil { + in, out := &in.VPCConfig, &out.VPCConfig + *out = new(VPCConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrowserNetworkConfiguration. +func (in *BrowserNetworkConfiguration) DeepCopy() *BrowserNetworkConfiguration { + if in == nil { + return nil + } + out := new(BrowserNetworkConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BrowserSummary) DeepCopyInto(out *BrowserSummary) { + *out = *in + if in.CreatedAt != nil { + in, out := &in.CreatedAt, &out.CreatedAt + *out = (*in).DeepCopy() + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.LastUpdatedAt != nil { + in, out := &in.LastUpdatedAt, &out.LastUpdatedAt + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrowserSummary. +func (in *BrowserSummary) DeepCopy() *BrowserSummary { + if in == nil { + return nil + } + out := new(BrowserSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CodeInterpreterNetworkConfiguration) DeepCopyInto(out *CodeInterpreterNetworkConfiguration) { + *out = *in + if in.VPCConfig != nil { + in, out := &in.VPCConfig, &out.VPCConfig + *out = new(VPCConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CodeInterpreterNetworkConfiguration. +func (in *CodeInterpreterNetworkConfiguration) DeepCopy() *CodeInterpreterNetworkConfiguration { + if in == nil { + return nil + } + out := new(CodeInterpreterNetworkConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CodeInterpreterSummary) DeepCopyInto(out *CodeInterpreterSummary) { + *out = *in + if in.CreatedAt != nil { + in, out := &in.CreatedAt, &out.CreatedAt + *out = (*in).DeepCopy() + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.LastUpdatedAt != nil { + in, out := &in.LastUpdatedAt, &out.LastUpdatedAt + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CodeInterpreterSummary. +func (in *CodeInterpreterSummary) DeepCopy() *CodeInterpreterSummary { + if in == nil { + return nil + } + out := new(CodeInterpreterSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerConfiguration) DeepCopyInto(out *ContainerConfiguration) { + *out = *in + if in.ContainerURI != nil { + in, out := &in.ContainerURI, &out.ContainerURI + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerConfiguration. +func (in *ContainerConfiguration) DeepCopy() *ContainerConfiguration { + if in == nil { + return nil + } + out := new(ContainerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomJWTAuthorizerConfiguration) DeepCopyInto(out *CustomJWTAuthorizerConfiguration) { + *out = *in + if in.AllowedAudience != nil { + in, out := &in.AllowedAudience, &out.AllowedAudience + *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.AllowedClients != nil { + in, out := &in.AllowedClients, &out.AllowedClients + *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.DiscoveryURL != nil { + in, out := &in.DiscoveryURL, &out.DiscoveryURL + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomJWTAuthorizerConfiguration. +func (in *CustomJWTAuthorizerConfiguration) DeepCopy() *CustomJWTAuthorizerConfiguration { + if in == nil { + return nil + } + out := new(CustomJWTAuthorizerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomMemoryStrategyInput) DeepCopyInto(out *CustomMemoryStrategyInput) { + *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 CustomMemoryStrategyInput. +func (in *CustomMemoryStrategyInput) DeepCopy() *CustomMemoryStrategyInput { + if in == nil { + return nil + } + out := new(CustomMemoryStrategyInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeleteMemoryStrategyInput) DeepCopyInto(out *DeleteMemoryStrategyInput) { + *out = *in + if in.MemoryStrategyID != nil { + in, out := &in.MemoryStrategyID, &out.MemoryStrategyID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeleteMemoryStrategyInput. +func (in *DeleteMemoryStrategyInput) DeepCopy() *DeleteMemoryStrategyInput { + if in == nil { + return nil + } + out := new(DeleteMemoryStrategyInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewaySummary) DeepCopyInto(out *GatewaySummary) { + *out = *in + if in.CreatedAt != nil { + in, out := &in.CreatedAt, &out.CreatedAt + *out = (*in).DeepCopy() + } + if in.UpdatedAt != nil { + in, out := &in.UpdatedAt, &out.UpdatedAt + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewaySummary. +func (in *GatewaySummary) DeepCopy() *GatewaySummary { + if in == nil { + return nil + } + out := new(GatewaySummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Memory) DeepCopyInto(out *Memory) { + *out = *in + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.FailureReason != nil { + in, out := &in.FailureReason, &out.FailureReason + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Memory. +func (in *Memory) DeepCopy() *Memory { + if in == nil { + return nil + } + out := new(Memory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MemoryStrategy) DeepCopyInto(out *MemoryStrategy) { + *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 MemoryStrategy. +func (in *MemoryStrategy) DeepCopy() *MemoryStrategy { + if in == nil { + return nil + } + out := new(MemoryStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ModifyMemoryStrategyInput) DeepCopyInto(out *ModifyMemoryStrategyInput) { + *out = *in + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.MemoryStrategyID != nil { + in, out := &in.MemoryStrategyID, &out.MemoryStrategyID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModifyMemoryStrategyInput. +func (in *ModifyMemoryStrategyInput) DeepCopy() *ModifyMemoryStrategyInput { + if in == nil { + return nil + } + out := new(ModifyMemoryStrategyInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkConfiguration) DeepCopyInto(out *NetworkConfiguration) { + *out = *in + if in.NetworkMode != nil { + in, out := &in.NetworkMode, &out.NetworkMode + *out = new(string) + **out = **in + } + if in.NetworkModeConfig != nil { + in, out := &in.NetworkModeConfig, &out.NetworkModeConfig + *out = new(VPCConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkConfiguration. +func (in *NetworkConfiguration) DeepCopy() *NetworkConfiguration { + if in == nil { + return nil + } + out := new(NetworkConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProtocolConfiguration) DeepCopyInto(out *ProtocolConfiguration) { + *out = *in + if in.ServerProtocol != nil { + in, out := &in.ServerProtocol, &out.ServerProtocol + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProtocolConfiguration. +func (in *ProtocolConfiguration) DeepCopy() *ProtocolConfiguration { + if in == nil { + return nil + } + out := new(ProtocolConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestHeaderConfiguration) DeepCopyInto(out *RequestHeaderConfiguration) { + *out = *in + if in.RequestHeaderAllowlist != nil { + in, out := &in.RequestHeaderAllowlist, &out.RequestHeaderAllowlist + *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 RequestHeaderConfiguration. +func (in *RequestHeaderConfiguration) DeepCopy() *RequestHeaderConfiguration { + if in == nil { + return nil + } + out := new(RequestHeaderConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *S3Location) DeepCopyInto(out *S3Location) { + *out = *in + if in.Bucket != nil { + in, out := &in.Bucket, &out.Bucket + *out = new(string) + **out = **in + } + if in.Prefix != nil { + in, out := &in.Prefix, &out.Prefix + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S3Location. +func (in *S3Location) DeepCopy() *S3Location { + if in == nil { + return nil + } + out := new(S3Location) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SchemaDefinition) DeepCopyInto(out *SchemaDefinition) { + *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 SchemaDefinition. +func (in *SchemaDefinition) DeepCopy() *SchemaDefinition { + if in == nil { + return nil + } + out := new(SchemaDefinition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SemanticConsolidationOverride) DeepCopyInto(out *SemanticConsolidationOverride) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SemanticConsolidationOverride. +func (in *SemanticConsolidationOverride) DeepCopy() *SemanticConsolidationOverride { + if in == nil { + return nil + } + out := new(SemanticConsolidationOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SemanticExtractionOverride) DeepCopyInto(out *SemanticExtractionOverride) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SemanticExtractionOverride. +func (in *SemanticExtractionOverride) DeepCopy() *SemanticExtractionOverride { + if in == nil { + return nil + } + out := new(SemanticExtractionOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SemanticMemoryStrategyInput) DeepCopyInto(out *SemanticMemoryStrategyInput) { + *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 SemanticMemoryStrategyInput. +func (in *SemanticMemoryStrategyInput) DeepCopy() *SemanticMemoryStrategyInput { + if in == nil { + return nil + } + out := new(SemanticMemoryStrategyInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SemanticOverrideConsolidationConfigurationInput) DeepCopyInto(out *SemanticOverrideConsolidationConfigurationInput) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SemanticOverrideConsolidationConfigurationInput. +func (in *SemanticOverrideConsolidationConfigurationInput) DeepCopy() *SemanticOverrideConsolidationConfigurationInput { + if in == nil { + return nil + } + out := new(SemanticOverrideConsolidationConfigurationInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SemanticOverrideExtractionConfigurationInput) DeepCopyInto(out *SemanticOverrideExtractionConfigurationInput) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SemanticOverrideExtractionConfigurationInput. +func (in *SemanticOverrideExtractionConfigurationInput) DeepCopy() *SemanticOverrideExtractionConfigurationInput { + if in == nil { + return nil + } + out := new(SemanticOverrideExtractionConfigurationInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SummaryConsolidationOverride) DeepCopyInto(out *SummaryConsolidationOverride) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SummaryConsolidationOverride. +func (in *SummaryConsolidationOverride) DeepCopy() *SummaryConsolidationOverride { + if in == nil { + return nil + } + out := new(SummaryConsolidationOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SummaryMemoryStrategyInput) DeepCopyInto(out *SummaryMemoryStrategyInput) { + *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 SummaryMemoryStrategyInput. +func (in *SummaryMemoryStrategyInput) DeepCopy() *SummaryMemoryStrategyInput { + if in == nil { + return nil + } + out := new(SummaryMemoryStrategyInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SummaryOverrideConsolidationConfigurationInput) DeepCopyInto(out *SummaryOverrideConsolidationConfigurationInput) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SummaryOverrideConsolidationConfigurationInput. +func (in *SummaryOverrideConsolidationConfigurationInput) DeepCopy() *SummaryOverrideConsolidationConfigurationInput { + if in == nil { + return nil + } + out := new(SummaryOverrideConsolidationConfigurationInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetSummary) DeepCopyInto(out *TargetSummary) { + *out = *in + if in.CreatedAt != nil { + in, out := &in.CreatedAt, &out.CreatedAt + *out = (*in).DeepCopy() + } + if in.UpdatedAt != nil { + in, out := &in.UpdatedAt, &out.UpdatedAt + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetSummary. +func (in *TargetSummary) DeepCopy() *TargetSummary { + if in == nil { + return nil + } + out := new(TargetSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ToolDefinition) DeepCopyInto(out *ToolDefinition) { + *out = *in + if in.Description != nil { + in, out := &in.Description, &out.Description + *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 ToolDefinition. +func (in *ToolDefinition) DeepCopy() *ToolDefinition { + if in == nil { + return nil + } + out := new(ToolDefinition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserPreferenceConsolidationOverride) DeepCopyInto(out *UserPreferenceConsolidationOverride) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserPreferenceConsolidationOverride. +func (in *UserPreferenceConsolidationOverride) DeepCopy() *UserPreferenceConsolidationOverride { + if in == nil { + return nil + } + out := new(UserPreferenceConsolidationOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserPreferenceExtractionOverride) DeepCopyInto(out *UserPreferenceExtractionOverride) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserPreferenceExtractionOverride. +func (in *UserPreferenceExtractionOverride) DeepCopy() *UserPreferenceExtractionOverride { + if in == nil { + return nil + } + out := new(UserPreferenceExtractionOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserPreferenceMemoryStrategyInput) DeepCopyInto(out *UserPreferenceMemoryStrategyInput) { + *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 UserPreferenceMemoryStrategyInput. +func (in *UserPreferenceMemoryStrategyInput) DeepCopy() *UserPreferenceMemoryStrategyInput { + if in == nil { + return nil + } + out := new(UserPreferenceMemoryStrategyInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserPreferenceOverrideConsolidationConfigurationInput) DeepCopyInto(out *UserPreferenceOverrideConsolidationConfigurationInput) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserPreferenceOverrideConsolidationConfigurationInput. +func (in *UserPreferenceOverrideConsolidationConfigurationInput) DeepCopy() *UserPreferenceOverrideConsolidationConfigurationInput { + if in == nil { + return nil + } + out := new(UserPreferenceOverrideConsolidationConfigurationInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserPreferenceOverrideExtractionConfigurationInput) DeepCopyInto(out *UserPreferenceOverrideExtractionConfigurationInput) { + *out = *in + if in.ModelID != nil { + in, out := &in.ModelID, &out.ModelID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserPreferenceOverrideExtractionConfigurationInput. +func (in *UserPreferenceOverrideExtractionConfigurationInput) DeepCopy() *UserPreferenceOverrideExtractionConfigurationInput { + if in == nil { + return nil + } + out := new(UserPreferenceOverrideExtractionConfigurationInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VPCConfig) DeepCopyInto(out *VPCConfig) { + *out = *in + if in.SecurityGroups != nil { + in, out := &in.SecurityGroups, &out.SecurityGroups + *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.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *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 VPCConfig. +func (in *VPCConfig) DeepCopy() *VPCConfig { + if in == nil { + return nil + } + out := new(VPCConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ValidationExceptionField) DeepCopyInto(out *ValidationExceptionField) { + *out = *in + if in.Message != nil { + in, out := &in.Message, &out.Message + *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 ValidationExceptionField. +func (in *ValidationExceptionField) DeepCopy() *ValidationExceptionField { + if in == nil { + return nil + } + out := new(ValidationExceptionField) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkloadIdentityDetails) DeepCopyInto(out *WorkloadIdentityDetails) { + *out = *in + if in.WorkloadIdentityARN != nil { + in, out := &in.WorkloadIdentityARN, &out.WorkloadIdentityARN + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadIdentityDetails. +func (in *WorkloadIdentityDetails) DeepCopy() *WorkloadIdentityDetails { + if in == nil { + return nil + } + out := new(WorkloadIdentityDetails) + in.DeepCopyInto(out) + return out +} diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 42af9f8..d619a8f 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -39,6 +39,9 @@ import ( svctypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" svcresource "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/pkg/resource" + _ "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/pkg/resource/agent_runtime" + _ "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/pkg/resource/agent_runtime_endpoint" + "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/pkg/version" ) diff --git a/config/crd/bases/bedrockagentcorecontrol.services.k8s.aws_agentruntimeendpoints.yaml b/config/crd/bases/bedrockagentcorecontrol.services.k8s.aws_agentruntimeendpoints.yaml new file mode 100644 index 0000000..c1a0192 --- /dev/null +++ b/config/crd/bases/bedrockagentcorecontrol.services.k8s.aws_agentruntimeendpoints.yaml @@ -0,0 +1,172 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: agentruntimeendpoints.bedrockagentcorecontrol.services.k8s.aws +spec: + group: bedrockagentcorecontrol.services.k8s.aws + names: + kind: AgentRuntimeEndpoint + listKind: AgentRuntimeEndpointList + plural: agentruntimeendpoints + singular: agentruntimeendpoint + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AgentRuntimeEndpoint is the Schema for the AgentRuntimeEndpoints + 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: |- + AgentRuntimeEndpointSpec defines the desired state of AgentRuntimeEndpoint. + + Contains information about an agent runtime endpoint. An endpoint provides + a way to connect to and interact with an agent runtime. + properties: + agentRuntimeID: + description: |- + The unique identifier of the AgentCore Runtime to create an endpoint for. + + Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,99}-[a-zA-Z0-9]{10}$` + type: string + agentRuntimeVersion: + description: |- + The version of the AgentCore Runtime to use for the endpoint. + + Regex Pattern: `^([1-9][0-9]{0,4})$` + type: string + description: + description: The description of the AgentCore Runtime endpoint. + type: string + name: + description: |- + The name of the AgentCore Runtime endpoint. + + Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,47}$` + type: string + tags: + additionalProperties: + type: string + description: |- + A map of tag keys and values to assign to the agent runtime endpoint. Tags + enable you to categorize your resources in different ways, for example, by + purpose, owner, or environment. + type: object + required: + - agentRuntimeID + type: object + status: + description: AgentRuntimeEndpointStatus defines the observed state of + AgentRuntimeEndpoint + properties: + ackResourceMetadata: + description: |- + All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + that is used to contain resource sync state, account ownership, + constructed ARN for the resource + properties: + arn: + description: |- + ARN is the Amazon Resource Name for the resource. This is a + globally-unique identifier and is set only by the ACK service controller + once the controller has orchestrated the creation of the resource OR + when it has verified that an "adopted" resource (a resource where the + ARN annotation was set by the Kubernetes user on the CR) exists and + matches the supplied CR's Spec field values. + https://github.com/aws/aws-controllers-k8s/issues/270 + type: string + ownerAccountID: + description: |- + OwnerAccountID is the AWS Account ID of the account that owns the + backend AWS service API resource. + type: string + region: + description: Region is the AWS region in which the resource exists + or will exist. + type: string + required: + - ownerAccountID + - region + type: object + agentRuntimeARN: + description: |- + The Amazon Resource Name (ARN) of the AgentCore Runtime. + + Regex Pattern: `^arn:(-[^:]+)?:bedrock-agentcore:[a-z0-9-]+:[0-9]{12}:agent/[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}:([0-9]{0,4}[1-9][0-9]{0,4})$` + type: string + conditions: + description: |- + All CRs managed by ACK have a common `Status.Conditions` member that + contains a collection of `ackv1alpha1.Condition` objects that describe + the various terminal states of the CR and its backend AWS service API + resource + items: + description: |- + Condition is the common struct used by all CRDs managed by ACK service + controllers to indicate terminal states of the CR and its backend AWS + service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + createdAt: + description: The timestamp when the AgentCore Runtime endpoint was + created. + format: date-time + type: string + status: + description: The current status of the AgentCore Runtime endpoint. + type: string + targetVersion: + description: |- + The target version of the AgentCore Runtime for the endpoint. + + Regex Pattern: `^([1-9][0-9]{0,4})$` + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/bedrockagentcorecontrol.services.k8s.aws_agentruntimes.yaml b/config/crd/bases/bedrockagentcorecontrol.services.k8s.aws_agentruntimes.yaml new file mode 100644 index 0000000..d05c26e --- /dev/null +++ b/config/crd/bases/bedrockagentcorecontrol.services.k8s.aws_agentruntimes.yaml @@ -0,0 +1,244 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: agentruntimes.bedrockagentcorecontrol.services.k8s.aws +spec: + group: bedrockagentcorecontrol.services.k8s.aws + names: + kind: AgentRuntime + listKind: AgentRuntimeList + plural: agentruntimes + singular: agentruntime + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AgentRuntime is the Schema for the AgentRuntimes 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: |- + AgentRuntimeSpec defines the desired state of AgentRuntime. + + Contains information about an agent runtime. An agent runtime is the execution + environment for a Amazon Bedrock Agent. + properties: + agentRuntimeArtifact: + description: The artifact of the AgentCore Runtime. + properties: + containerConfiguration: + description: Representation of a container configuration. + properties: + containerURI: + type: string + type: object + type: object + agentRuntimeName: + description: |- + The name of the AgentCore Runtime. + + Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,47}$` + type: string + authorizerConfiguration: + description: The authorizer configuration for the AgentCore Runtime. + properties: + customJWTAuthorizer: + description: |- + Configuration for inbound JWT-based authorization, specifying how incoming + requests should be authenticated. + properties: + allowedAudience: + items: + type: string + type: array + allowedClients: + items: + type: string + type: array + discoveryURL: + type: string + type: object + type: object + description: + description: The description of the AgentCore Runtime. + type: string + environmentVariables: + additionalProperties: + type: string + description: Environment variables to set in the AgentCore Runtime + environment. + type: object + networkConfiguration: + description: The network configuration for the AgentCore Runtime. + properties: + networkMode: + type: string + networkModeConfig: + description: VpcConfig for the Agent. + properties: + securityGroups: + items: + type: string + type: array + subnets: + items: + type: string + type: array + type: object + type: object + protocolConfiguration: + description: |- + The protocol configuration for an agent runtime. This structure defines how + the agent runtime communicates with clients. + properties: + serverProtocol: + type: string + type: object + requestHeaderConfiguration: + description: |- + Configuration for HTTP request headers that will be passed through to the + runtime. + properties: + requestHeaderAllowlist: + items: + type: string + type: array + type: object + roleARN: + description: |- + The IAM role ARN that provides permissions for the AgentCore Runtime. + + Regex Pattern: `^arn:aws(-[^:]+)?:iam::([0-9]{12})?:role/.+$` + type: string + tags: + additionalProperties: + type: string + description: |- + A map of tag keys and values to assign to the agent runtime. Tags enable + you to categorize your resources in different ways, for example, by purpose, + owner, or environment. + type: object + required: + - agentRuntimeArtifact + - agentRuntimeName + - networkConfiguration + - roleARN + type: object + status: + description: AgentRuntimeStatus defines the observed state of AgentRuntime + properties: + ackResourceMetadata: + description: |- + All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + that is used to contain resource sync state, account ownership, + constructed ARN for the resource + properties: + arn: + description: |- + ARN is the Amazon Resource Name for the resource. This is a + globally-unique identifier and is set only by the ACK service controller + once the controller has orchestrated the creation of the resource OR + when it has verified that an "adopted" resource (a resource where the + ARN annotation was set by the Kubernetes user on the CR) exists and + matches the supplied CR's Spec field values. + https://github.com/aws/aws-controllers-k8s/issues/270 + type: string + ownerAccountID: + description: |- + OwnerAccountID is the AWS Account ID of the account that owns the + backend AWS service API resource. + type: string + region: + description: Region is the AWS region in which the resource exists + or will exist. + type: string + required: + - ownerAccountID + - region + type: object + agentRuntimeID: + description: |- + The unique identifier of the AgentCore Runtime. + + Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,99}-[a-zA-Z0-9]{10}$` + type: string + agentRuntimeVersion: + description: |- + The version of the AgentCore Runtime. + + Regex Pattern: `^([1-9][0-9]{0,4})$` + type: string + conditions: + description: |- + All CRs managed by ACK have a common `Status.Conditions` member that + contains a collection of `ackv1alpha1.Condition` objects that describe + the various terminal states of the CR and its backend AWS service API + resource + items: + description: |- + Condition is the common struct used by all CRDs managed by ACK service + controllers to indicate terminal states of the CR and its backend AWS + service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + createdAt: + description: The timestamp when the AgentCore Runtime was created. + format: date-time + type: string + status: + description: The current status of the AgentCore Runtime. + type: string + workloadIdentityDetails: + description: The workload identity details for the AgentCore Runtime. + properties: + workloadIdentityARN: + type: string + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index ea0b795..f4c1600 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -2,3 +2,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - common + - bases/bedrockagentcorecontrol.services.k8s.aws_agentruntimes.yaml + - bases/bedrockagentcorecontrol.services.k8s.aws_agentruntimeendpoints.yaml diff --git a/config/iam/recommended-policy-arn b/config/iam/recommended-policy-arn new file mode 100644 index 0000000..535daa9 --- /dev/null +++ b/config/iam/recommended-policy-arn @@ -0,0 +1 @@ +arn:aws:iam::aws:policy/BedrockAgentCoreFullAccess diff --git a/config/rbac/cluster-role-controller.yaml b/config/rbac/cluster-role-controller.yaml index 1bc872c..24c677a 100644 --- a/config/rbac/cluster-role-controller.yaml +++ b/config/rbac/cluster-role-controller.yaml @@ -22,6 +22,28 @@ rules: - get - list - watch +- apiGroups: + - bedrockagentcorecontrol.services.k8s.aws + resources: + - agentruntimeendpoints + - agentruntimes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - bedrockagentcorecontrol.services.k8s.aws + resources: + - agentruntimeendpoints/status + - agentruntimes/status + verbs: + - get + - patch + - update - apiGroups: - services.k8s.aws resources: diff --git a/config/rbac/role-reader.yaml b/config/rbac/role-reader.yaml index 2c18037..674bd7d 100644 --- a/config/rbac/role-reader.yaml +++ b/config/rbac/role-reader.yaml @@ -9,6 +9,8 @@ rules: - apiGroups: - bedrockagentcorecontrol.services.k8s.aws resources: + - agentruntimes + - agentruntimeendpoints verbs: - get - list diff --git a/config/rbac/role-writer.yaml b/config/rbac/role-writer.yaml index 555eba5..35bbc0e 100644 --- a/config/rbac/role-writer.yaml +++ b/config/rbac/role-writer.yaml @@ -9,6 +9,8 @@ rules: - apiGroups: - bedrockagentcorecontrol.services.k8s.aws resources: + - agentruntimes + - agentruntimeendpoints verbs: - create - delete @@ -20,6 +22,8 @@ rules: - apiGroups: - bedrockagentcorecontrol.services.k8s.aws resources: + - agentruntimes + - agentruntimeendpoints verbs: - get - patch diff --git a/generator.yaml b/generator.yaml index 98bcc51..3ec6452 100644 --- a/generator.yaml +++ b/generator.yaml @@ -1,7 +1,7 @@ ignore: resource_names: - - AgentRuntime - - AgentRuntimeEndpoint + # AgentRuntime + # AgentRuntimeEndpoint - ApiKeyCredentialProvider - Browser - CodeInterpreter @@ -10,6 +10,45 @@ ignore: - Memory - Oauth2CredentialProvider - WorkloadIdentity + field_paths: + - CreateAgentRuntimeInput.ClientToken + - CreateAgentRuntimeEndpointInput.ClientToken sdk_names: model_name: bedrock-agentcore-control + +resources: + AgentRuntime: + exceptions: + terminal_codes: + - ValidationException + hooks: + sdk_read_one_post_set_output: + template_path: hooks/agentruntime/sdk_read_one_post_set_output.go.tpl + sdk_update_pre_build_request: + template_path: hooks/agentruntime/sdk_update_pre_build_request.go.tpl + + AgentRuntimeEndpoint: + renames: + operations: + GetAgentRuntimeEndpoint: + input_fields: + EndpointName: Name + CreateAgentRuntimeEndpoint: + input_fields: + EndpointName: Name + DeleteAgentRuntimeEndpoint: + input_fields: + EndpointName: Name + fields: + Name: + is_primary_key: true + hooks: + sdk_read_one_post_set_output: + template_path: hooks/agentruntimeendpoint/sdk_read_one_post_set_output.go.tpl + sdk_update_pre_build_request: + template_path: hooks/agentruntimeendpoint/sdk_update_pre_build_request.go.tpl + exceptions: + errors: + 404: + code: AccessDeniedException diff --git a/go.mod b/go.mod index 5264552..93bd3d5 100644 --- a/go.mod +++ b/go.mod @@ -7,26 +7,29 @@ toolchain go1.24.0 require ( github.com/aws-controllers-k8s/runtime v0.52.0 github.com/aws/aws-sdk-go v1.49.0 + github.com/aws/aws-sdk-go-v2 v1.39.2 + github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.10.0 + github.com/aws/smithy-go v1.23.0 + github.com/go-logr/logr v1.4.2 github.com/spf13/pflag v1.0.5 + k8s.io/api v0.32.1 k8s.io/apimachinery v0.32.1 k8s.io/client-go v0.32.1 sigs.k8s.io/controller-runtime v0.20.4 ) require ( - github.com/aws/aws-sdk-go-v2 v1.32.7 // indirect github.com/aws/aws-sdk-go-v2/config v1.28.6 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.47 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 // indirect - github.com/aws/smithy-go v1.22.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -35,7 +38,6 @@ require ( github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect @@ -78,7 +80,6 @@ require ( gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.32.1 // indirect k8s.io/apiextensions-apiserver v0.32.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect diff --git a/go.sum b/go.sum index d4e1270..9dca71c 100644 --- a/go.sum +++ b/go.sum @@ -2,20 +2,22 @@ github.com/aws-controllers-k8s/runtime v0.52.0 h1:Q5UIAn6SSBr60t/DiU/zr6NLBlUuK2 github.com/aws-controllers-k8s/runtime v0.52.0/go.mod h1:OkUJN+Ds799JLYZsMJrO2vDJ4snxUeHK2MgrQHbU+Qc= github.com/aws/aws-sdk-go v1.49.0 h1:g9BkW1fo9GqKfwg2+zCD+TW/D36Ux+vtfJ8guF4AYmY= github.com/aws/aws-sdk-go v1.49.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw= -github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2 v1.39.2 h1:EJLg8IdbzgeD7xgvZ+I8M1e0fL0ptn/M47lianzth0I= +github.com/aws/aws-sdk-go-v2 v1.39.2/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= github.com/aws/aws-sdk-go-v2/config v1.28.6 h1:D89IKtGrs/I3QXOLNTH93NJYtDhm8SYa9Q5CsPShmyo= github.com/aws/aws-sdk-go-v2/config v1.28.6/go.mod h1:GDzxJ5wyyFSCoLkS+UhGB0dArhb9mI+Co4dHtoTxbko= github.com/aws/aws-sdk-go-v2/credentials v1.17.47 h1:48bA+3/fCdi2yAwVt+3COvmatZ6jUDNkDTIsqDiMUdw= github.com/aws/aws-sdk-go-v2/credentials v1.17.47/go.mod h1:+KdckOejLW3Ks3b0E3b5rHsr2f9yuORBum0WPnE5o5w= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 h1:AmoU1pziydclFT/xRV+xXE/Vb8fttJCLRPv8oAkprc0= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21/go.mod h1:AjUdLYe4Tgs6kpH4Bv7uMZo7pottoyHMn4eTcIcneaY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 h1:se2vOWGD3dWQUtfn4wEjRQJb1HK1XsNIt825gskZ970= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9/go.mod h1:hijCGH2VfbZQxqCDN7bwz/4dzxV+hkyhjawAtdPWKZA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 h1:6RBnKZLkJM4hQ+kN6E7yWFveOTg8NLPHAkqrs4ZPlTU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9/go.mod h1:V9rQKRmK7AWuEsOMnHzKj8WyrIir1yUJbZxDuZLFvXI= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.10.0 h1:HhOMc4AhT430DBGfv5CGHvc4AQeGe/Yz4i8p/5xe6sE= +github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.10.0/go.mod h1:Es+CYDVSPzyRIJaDDzxvoBNRc+AZbevIL8d+q1+3J5w= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 h1:50+XsN70RS7dwJ2CkVNXzj7U2L1HKP8nqTd3XWEXBN4= @@ -26,8 +28,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 h1:JnhTZR3PiYDNKlXy50/pNeix github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6/go.mod h1:URronUEGfXZN1VpdktPSD1EkAL9mfrV+2F4sjH38qOY= github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 h1:s4074ZO1Hk8qv65GqNXqDjmkf4HSQqJukaLuuW0TpDA= github.com/aws/aws-sdk-go-v2/service/sts v1.33.2/go.mod h1:mVggCnIWoM09jP71Wh+ea7+5gAp53q+49wDFs1SW5z8= -github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= -github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE= +github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= diff --git a/helm/Chart.yaml b/helm/Chart.yaml index 6c9fd10..c5f6797 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 name: bedrockagentcorecontrol-chart -description: A Helm chart for the ACK service controller for () +description: A Helm chart for the ACK service controller for Amazon Bedrock Agent Core Control (Bedrock Agent Core Control) version: 0.0.0-non-release-version appVersion: 0.0.0-non-release-version home: https://github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller @@ -10,7 +10,7 @@ sources: maintainers: - name: ACK Admins url: https://github.com/orgs/aws-controllers-k8s/teams/ack-admin - - name: Admins + - name: Bedrock Agent Core Control Admins url: https://github.com/orgs/aws-controllers-k8s/teams/bedrockagentcorecontrol-maintainer keywords: - aws diff --git a/helm/crds/bedrockagentcorecontrol.services.k8s.aws_agentruntimeendpoints.yaml b/helm/crds/bedrockagentcorecontrol.services.k8s.aws_agentruntimeendpoints.yaml new file mode 100644 index 0000000..c1a0192 --- /dev/null +++ b/helm/crds/bedrockagentcorecontrol.services.k8s.aws_agentruntimeendpoints.yaml @@ -0,0 +1,172 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: agentruntimeendpoints.bedrockagentcorecontrol.services.k8s.aws +spec: + group: bedrockagentcorecontrol.services.k8s.aws + names: + kind: AgentRuntimeEndpoint + listKind: AgentRuntimeEndpointList + plural: agentruntimeendpoints + singular: agentruntimeendpoint + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AgentRuntimeEndpoint is the Schema for the AgentRuntimeEndpoints + 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: |- + AgentRuntimeEndpointSpec defines the desired state of AgentRuntimeEndpoint. + + Contains information about an agent runtime endpoint. An endpoint provides + a way to connect to and interact with an agent runtime. + properties: + agentRuntimeID: + description: |- + The unique identifier of the AgentCore Runtime to create an endpoint for. + + Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,99}-[a-zA-Z0-9]{10}$` + type: string + agentRuntimeVersion: + description: |- + The version of the AgentCore Runtime to use for the endpoint. + + Regex Pattern: `^([1-9][0-9]{0,4})$` + type: string + description: + description: The description of the AgentCore Runtime endpoint. + type: string + name: + description: |- + The name of the AgentCore Runtime endpoint. + + Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,47}$` + type: string + tags: + additionalProperties: + type: string + description: |- + A map of tag keys and values to assign to the agent runtime endpoint. Tags + enable you to categorize your resources in different ways, for example, by + purpose, owner, or environment. + type: object + required: + - agentRuntimeID + type: object + status: + description: AgentRuntimeEndpointStatus defines the observed state of + AgentRuntimeEndpoint + properties: + ackResourceMetadata: + description: |- + All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + that is used to contain resource sync state, account ownership, + constructed ARN for the resource + properties: + arn: + description: |- + ARN is the Amazon Resource Name for the resource. This is a + globally-unique identifier and is set only by the ACK service controller + once the controller has orchestrated the creation of the resource OR + when it has verified that an "adopted" resource (a resource where the + ARN annotation was set by the Kubernetes user on the CR) exists and + matches the supplied CR's Spec field values. + https://github.com/aws/aws-controllers-k8s/issues/270 + type: string + ownerAccountID: + description: |- + OwnerAccountID is the AWS Account ID of the account that owns the + backend AWS service API resource. + type: string + region: + description: Region is the AWS region in which the resource exists + or will exist. + type: string + required: + - ownerAccountID + - region + type: object + agentRuntimeARN: + description: |- + The Amazon Resource Name (ARN) of the AgentCore Runtime. + + Regex Pattern: `^arn:(-[^:]+)?:bedrock-agentcore:[a-z0-9-]+:[0-9]{12}:agent/[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}:([0-9]{0,4}[1-9][0-9]{0,4})$` + type: string + conditions: + description: |- + All CRs managed by ACK have a common `Status.Conditions` member that + contains a collection of `ackv1alpha1.Condition` objects that describe + the various terminal states of the CR and its backend AWS service API + resource + items: + description: |- + Condition is the common struct used by all CRDs managed by ACK service + controllers to indicate terminal states of the CR and its backend AWS + service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + createdAt: + description: The timestamp when the AgentCore Runtime endpoint was + created. + format: date-time + type: string + status: + description: The current status of the AgentCore Runtime endpoint. + type: string + targetVersion: + description: |- + The target version of the AgentCore Runtime for the endpoint. + + Regex Pattern: `^([1-9][0-9]{0,4})$` + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm/crds/bedrockagentcorecontrol.services.k8s.aws_agentruntimes.yaml b/helm/crds/bedrockagentcorecontrol.services.k8s.aws_agentruntimes.yaml new file mode 100644 index 0000000..d05c26e --- /dev/null +++ b/helm/crds/bedrockagentcorecontrol.services.k8s.aws_agentruntimes.yaml @@ -0,0 +1,244 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: agentruntimes.bedrockagentcorecontrol.services.k8s.aws +spec: + group: bedrockagentcorecontrol.services.k8s.aws + names: + kind: AgentRuntime + listKind: AgentRuntimeList + plural: agentruntimes + singular: agentruntime + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AgentRuntime is the Schema for the AgentRuntimes 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: |- + AgentRuntimeSpec defines the desired state of AgentRuntime. + + Contains information about an agent runtime. An agent runtime is the execution + environment for a Amazon Bedrock Agent. + properties: + agentRuntimeArtifact: + description: The artifact of the AgentCore Runtime. + properties: + containerConfiguration: + description: Representation of a container configuration. + properties: + containerURI: + type: string + type: object + type: object + agentRuntimeName: + description: |- + The name of the AgentCore Runtime. + + Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,47}$` + type: string + authorizerConfiguration: + description: The authorizer configuration for the AgentCore Runtime. + properties: + customJWTAuthorizer: + description: |- + Configuration for inbound JWT-based authorization, specifying how incoming + requests should be authenticated. + properties: + allowedAudience: + items: + type: string + type: array + allowedClients: + items: + type: string + type: array + discoveryURL: + type: string + type: object + type: object + description: + description: The description of the AgentCore Runtime. + type: string + environmentVariables: + additionalProperties: + type: string + description: Environment variables to set in the AgentCore Runtime + environment. + type: object + networkConfiguration: + description: The network configuration for the AgentCore Runtime. + properties: + networkMode: + type: string + networkModeConfig: + description: VpcConfig for the Agent. + properties: + securityGroups: + items: + type: string + type: array + subnets: + items: + type: string + type: array + type: object + type: object + protocolConfiguration: + description: |- + The protocol configuration for an agent runtime. This structure defines how + the agent runtime communicates with clients. + properties: + serverProtocol: + type: string + type: object + requestHeaderConfiguration: + description: |- + Configuration for HTTP request headers that will be passed through to the + runtime. + properties: + requestHeaderAllowlist: + items: + type: string + type: array + type: object + roleARN: + description: |- + The IAM role ARN that provides permissions for the AgentCore Runtime. + + Regex Pattern: `^arn:aws(-[^:]+)?:iam::([0-9]{12})?:role/.+$` + type: string + tags: + additionalProperties: + type: string + description: |- + A map of tag keys and values to assign to the agent runtime. Tags enable + you to categorize your resources in different ways, for example, by purpose, + owner, or environment. + type: object + required: + - agentRuntimeArtifact + - agentRuntimeName + - networkConfiguration + - roleARN + type: object + status: + description: AgentRuntimeStatus defines the observed state of AgentRuntime + properties: + ackResourceMetadata: + description: |- + All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + that is used to contain resource sync state, account ownership, + constructed ARN for the resource + properties: + arn: + description: |- + ARN is the Amazon Resource Name for the resource. This is a + globally-unique identifier and is set only by the ACK service controller + once the controller has orchestrated the creation of the resource OR + when it has verified that an "adopted" resource (a resource where the + ARN annotation was set by the Kubernetes user on the CR) exists and + matches the supplied CR's Spec field values. + https://github.com/aws/aws-controllers-k8s/issues/270 + type: string + ownerAccountID: + description: |- + OwnerAccountID is the AWS Account ID of the account that owns the + backend AWS service API resource. + type: string + region: + description: Region is the AWS region in which the resource exists + or will exist. + type: string + required: + - ownerAccountID + - region + type: object + agentRuntimeID: + description: |- + The unique identifier of the AgentCore Runtime. + + Regex Pattern: `^[a-zA-Z][a-zA-Z0-9_]{0,99}-[a-zA-Z0-9]{10}$` + type: string + agentRuntimeVersion: + description: |- + The version of the AgentCore Runtime. + + Regex Pattern: `^([1-9][0-9]{0,4})$` + type: string + conditions: + description: |- + All CRs managed by ACK have a common `Status.Conditions` member that + contains a collection of `ackv1alpha1.Condition` objects that describe + the various terminal states of the CR and its backend AWS service API + resource + items: + description: |- + Condition is the common struct used by all CRDs managed by ACK service + controllers to indicate terminal states of the CR and its backend AWS + service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + createdAt: + description: The timestamp when the AgentCore Runtime was created. + format: date-time + type: string + status: + description: The current status of the AgentCore Runtime. + type: string + workloadIdentityDetails: + description: The workload identity details for the AgentCore Runtime. + properties: + workloadIdentityARN: + type: string + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm/templates/NOTES.txt b/helm/templates/NOTES.txt index 8261ea8..83d43e9 100644 --- a/helm/templates/NOTES.txt +++ b/helm/templates/NOTES.txt @@ -4,7 +4,7 @@ This chart deploys "public.ecr.aws/aws-controllers-k8s/bedrockagentcorecontrol-c Check its status by running: kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/instance={{ .Release.Name }}" -You are now able to create () resources! +You are now able to create Amazon Bedrock Agent Core Control (Bedrock Agent Core Control) resources! The controller is running in "{{ .Values.installScope }}" mode. The controller is configured to manage AWS resources in region: "{{ .Values.aws.region }}" diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 9eeeeae..0840877 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -69,6 +69,28 @@ rules: - get - list - watch +- apiGroups: + - bedrockagentcorecontrol.services.k8s.aws + resources: + - agentruntimeendpoints + - agentruntimes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - bedrockagentcorecontrol.services.k8s.aws + resources: + - agentruntimeendpoints/status + - agentruntimes/status + verbs: + - get + - patch + - update - apiGroups: - services.k8s.aws resources: diff --git a/helm/templates/role-reader.yaml b/helm/templates/role-reader.yaml index c495ea5..1803431 100644 --- a/helm/templates/role-reader.yaml +++ b/helm/templates/role-reader.yaml @@ -16,6 +16,8 @@ rules: - apiGroups: - bedrockagentcorecontrol.services.k8s.aws resources: + - agentruntimes + - agentruntimeendpoints verbs: - get - list diff --git a/helm/templates/role-writer.yaml b/helm/templates/role-writer.yaml index b79a840..bb0db10 100644 --- a/helm/templates/role-writer.yaml +++ b/helm/templates/role-writer.yaml @@ -16,6 +16,8 @@ rules: - apiGroups: - bedrockagentcorecontrol.services.k8s.aws resources: + - agentruntimes + - agentruntimeendpoints verbs: - create - delete @@ -27,6 +29,8 @@ rules: - apiGroups: - bedrockagentcorecontrol.services.k8s.aws resources: + - agentruntimes + - agentruntimeendpoints verbs: - get - patch diff --git a/helm/values.yaml b/helm/values.yaml index 80bb110..ee8e463 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -145,6 +145,8 @@ reconcile: # If empty, all resources will be reconciled. # If specified, only the listed resource kinds will be reconciled. resources: + - AgentRuntime + - AgentRuntimeEndpoint serviceAccount: # Specifies whether a service account should be created diff --git a/pkg/resource/agent_runtime/delta.go b/pkg/resource/agent_runtime/delta.go new file mode 100644 index 0000000..e0b170f --- /dev/null +++ b/pkg/resource/agent_runtime/delta.go @@ -0,0 +1,176 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime + +import ( + "bytes" + "reflect" + + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" +) + +// Hack to avoid import errors during build... +var ( + _ = &bytes.Buffer{} + _ = &reflect.Method{} + _ = &acktags.Tags{} +) + +// newResourceDelta returns a new `ackcompare.Delta` used to compare two +// resources +func newResourceDelta( + a *resource, + b *resource, +) *ackcompare.Delta { + delta := ackcompare.NewDelta() + if (a == nil && b != nil) || + (a != nil && b == nil) { + delta.Add("", a, b) + return delta + } + + if ackcompare.HasNilDifference(a.ko.Spec.AgentRuntimeArtifact, b.ko.Spec.AgentRuntimeArtifact) { + delta.Add("Spec.AgentRuntimeArtifact", a.ko.Spec.AgentRuntimeArtifact, b.ko.Spec.AgentRuntimeArtifact) + } else if a.ko.Spec.AgentRuntimeArtifact != nil && b.ko.Spec.AgentRuntimeArtifact != nil { + if ackcompare.HasNilDifference(a.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration, b.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration) { + delta.Add("Spec.AgentRuntimeArtifact.ContainerConfiguration", a.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration, b.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration) + } else if a.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration != nil && b.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration != nil { + if ackcompare.HasNilDifference(a.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI, b.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI) { + delta.Add("Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI", a.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI, b.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI) + } else if a.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI != nil && b.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI != nil { + if *a.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI != *b.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI { + delta.Add("Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI", a.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI, b.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI) + } + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.AgentRuntimeName, b.ko.Spec.AgentRuntimeName) { + delta.Add("Spec.AgentRuntimeName", a.ko.Spec.AgentRuntimeName, b.ko.Spec.AgentRuntimeName) + } else if a.ko.Spec.AgentRuntimeName != nil && b.ko.Spec.AgentRuntimeName != nil { + if *a.ko.Spec.AgentRuntimeName != *b.ko.Spec.AgentRuntimeName { + delta.Add("Spec.AgentRuntimeName", a.ko.Spec.AgentRuntimeName, b.ko.Spec.AgentRuntimeName) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.AuthorizerConfiguration, b.ko.Spec.AuthorizerConfiguration) { + delta.Add("Spec.AuthorizerConfiguration", a.ko.Spec.AuthorizerConfiguration, b.ko.Spec.AuthorizerConfiguration) + } else if a.ko.Spec.AuthorizerConfiguration != nil && b.ko.Spec.AuthorizerConfiguration != nil { + if ackcompare.HasNilDifference(a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer) { + delta.Add("Spec.AuthorizerConfiguration.CustomJWTAuthorizer", a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer) + } else if a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer != nil && b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer != nil { + if len(a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience) != len(b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience) { + delta.Add("Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience", a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience) + } else if len(a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience) > 0 { + if !ackcompare.SliceStringPEqual(a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience) { + delta.Add("Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience", a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience) + } + } + if len(a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients) != len(b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients) { + delta.Add("Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients", a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients) + } else if len(a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients) > 0 { + if !ackcompare.SliceStringPEqual(a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients) { + delta.Add("Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients", a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL) { + delta.Add("Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL", a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL) + } else if a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL != nil && b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL != nil { + if *a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL != *b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL { + delta.Add("Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL", a.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL, b.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL) + } + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.Description, b.ko.Spec.Description) { + delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) + } else if a.ko.Spec.Description != nil && b.ko.Spec.Description != nil { + if *a.ko.Spec.Description != *b.ko.Spec.Description { + delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) + } + } + if len(a.ko.Spec.EnvironmentVariables) != len(b.ko.Spec.EnvironmentVariables) { + delta.Add("Spec.EnvironmentVariables", a.ko.Spec.EnvironmentVariables, b.ko.Spec.EnvironmentVariables) + } else if len(a.ko.Spec.EnvironmentVariables) > 0 { + if !ackcompare.MapStringStringPEqual(a.ko.Spec.EnvironmentVariables, b.ko.Spec.EnvironmentVariables) { + delta.Add("Spec.EnvironmentVariables", a.ko.Spec.EnvironmentVariables, b.ko.Spec.EnvironmentVariables) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.NetworkConfiguration, b.ko.Spec.NetworkConfiguration) { + delta.Add("Spec.NetworkConfiguration", a.ko.Spec.NetworkConfiguration, b.ko.Spec.NetworkConfiguration) + } else if a.ko.Spec.NetworkConfiguration != nil && b.ko.Spec.NetworkConfiguration != nil { + if ackcompare.HasNilDifference(a.ko.Spec.NetworkConfiguration.NetworkMode, b.ko.Spec.NetworkConfiguration.NetworkMode) { + delta.Add("Spec.NetworkConfiguration.NetworkMode", a.ko.Spec.NetworkConfiguration.NetworkMode, b.ko.Spec.NetworkConfiguration.NetworkMode) + } else if a.ko.Spec.NetworkConfiguration.NetworkMode != nil && b.ko.Spec.NetworkConfiguration.NetworkMode != nil { + if *a.ko.Spec.NetworkConfiguration.NetworkMode != *b.ko.Spec.NetworkConfiguration.NetworkMode { + delta.Add("Spec.NetworkConfiguration.NetworkMode", a.ko.Spec.NetworkConfiguration.NetworkMode, b.ko.Spec.NetworkConfiguration.NetworkMode) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.NetworkConfiguration.NetworkModeConfig, b.ko.Spec.NetworkConfiguration.NetworkModeConfig) { + delta.Add("Spec.NetworkConfiguration.NetworkModeConfig", a.ko.Spec.NetworkConfiguration.NetworkModeConfig, b.ko.Spec.NetworkConfiguration.NetworkModeConfig) + } else if a.ko.Spec.NetworkConfiguration.NetworkModeConfig != nil && b.ko.Spec.NetworkConfiguration.NetworkModeConfig != nil { + if len(a.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups) != len(b.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups) { + delta.Add("Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups", a.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups, b.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups) + } else if len(a.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups) > 0 { + if !ackcompare.SliceStringPEqual(a.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups, b.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups) { + delta.Add("Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups", a.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups, b.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups) + } + } + if len(a.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets) != len(b.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets) { + delta.Add("Spec.NetworkConfiguration.NetworkModeConfig.Subnets", a.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets, b.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets) + } else if len(a.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets) > 0 { + if !ackcompare.SliceStringPEqual(a.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets, b.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets) { + delta.Add("Spec.NetworkConfiguration.NetworkModeConfig.Subnets", a.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets, b.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets) + } + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.ProtocolConfiguration, b.ko.Spec.ProtocolConfiguration) { + delta.Add("Spec.ProtocolConfiguration", a.ko.Spec.ProtocolConfiguration, b.ko.Spec.ProtocolConfiguration) + } else if a.ko.Spec.ProtocolConfiguration != nil && b.ko.Spec.ProtocolConfiguration != nil { + if ackcompare.HasNilDifference(a.ko.Spec.ProtocolConfiguration.ServerProtocol, b.ko.Spec.ProtocolConfiguration.ServerProtocol) { + delta.Add("Spec.ProtocolConfiguration.ServerProtocol", a.ko.Spec.ProtocolConfiguration.ServerProtocol, b.ko.Spec.ProtocolConfiguration.ServerProtocol) + } else if a.ko.Spec.ProtocolConfiguration.ServerProtocol != nil && b.ko.Spec.ProtocolConfiguration.ServerProtocol != nil { + if *a.ko.Spec.ProtocolConfiguration.ServerProtocol != *b.ko.Spec.ProtocolConfiguration.ServerProtocol { + delta.Add("Spec.ProtocolConfiguration.ServerProtocol", a.ko.Spec.ProtocolConfiguration.ServerProtocol, b.ko.Spec.ProtocolConfiguration.ServerProtocol) + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.RequestHeaderConfiguration, b.ko.Spec.RequestHeaderConfiguration) { + delta.Add("Spec.RequestHeaderConfiguration", a.ko.Spec.RequestHeaderConfiguration, b.ko.Spec.RequestHeaderConfiguration) + } else if a.ko.Spec.RequestHeaderConfiguration != nil && b.ko.Spec.RequestHeaderConfiguration != nil { + if len(a.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist) != len(b.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist) { + delta.Add("Spec.RequestHeaderConfiguration.RequestHeaderAllowlist", a.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist, b.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist) + } else if len(a.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist) > 0 { + if !ackcompare.SliceStringPEqual(a.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist, b.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist) { + delta.Add("Spec.RequestHeaderConfiguration.RequestHeaderAllowlist", a.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist, b.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist) + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.RoleARN, b.ko.Spec.RoleARN) { + delta.Add("Spec.RoleARN", a.ko.Spec.RoleARN, b.ko.Spec.RoleARN) + } else if a.ko.Spec.RoleARN != nil && b.ko.Spec.RoleARN != nil { + if *a.ko.Spec.RoleARN != *b.ko.Spec.RoleARN { + delta.Add("Spec.RoleARN", a.ko.Spec.RoleARN, b.ko.Spec.RoleARN) + } + } + desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tags) + latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tags) + if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) { + delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags) + } + + return delta +} diff --git a/pkg/resource/agent_runtime/descriptor.go b/pkg/resource/agent_runtime/descriptor.go new file mode 100644 index 0000000..7d2db83 --- /dev/null +++ b/pkg/resource/agent_runtime/descriptor.go @@ -0,0 +1,155 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + rtclient "sigs.k8s.io/controller-runtime/pkg/client" + k8sctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +const ( + FinalizerString = "finalizers.bedrockagentcorecontrol.services.k8s.aws/AgentRuntime" +) + +var ( + GroupVersionResource = svcapitypes.GroupVersion.WithResource("agentruntimes") + GroupKind = metav1.GroupKind{ + Group: "bedrockagentcorecontrol.services.k8s.aws", + Kind: "AgentRuntime", + } +) + +// resourceDescriptor implements the +// `aws-service-operator-k8s/pkg/types.AWSResourceDescriptor` interface +type resourceDescriptor struct { +} + +// GroupVersionKind returns a Kubernetes schema.GroupVersionKind struct that +// describes the API Group, Version and Kind of CRs described by the descriptor +func (d *resourceDescriptor) GroupVersionKind() schema.GroupVersionKind { + return svcapitypes.GroupVersion.WithKind(GroupKind.Kind) +} + +// EmptyRuntimeObject returns an empty object prototype that may be used in +// apimachinery and k8s client operations +func (d *resourceDescriptor) EmptyRuntimeObject() rtclient.Object { + return &svcapitypes.AgentRuntime{} +} + +// ResourceFromRuntimeObject returns an AWSResource that has been initialized +// with the supplied runtime.Object +func (d *resourceDescriptor) ResourceFromRuntimeObject( + obj rtclient.Object, +) acktypes.AWSResource { + return &resource{ + ko: obj.(*svcapitypes.AgentRuntime), + } +} + +// Delta returns an `ackcompare.Delta` object containing the difference between +// one `AWSResource` and another. +func (d *resourceDescriptor) Delta(a, b acktypes.AWSResource) *ackcompare.Delta { + return newResourceDelta(a.(*resource), b.(*resource)) +} + +// IsManaged returns true if the supplied AWSResource is under the management +// of an ACK service controller. What this means in practice is that the +// underlying custom resource (CR) in the AWSResource has had a +// resource-specific finalizer associated with it. +func (d *resourceDescriptor) IsManaged( + res acktypes.AWSResource, +) bool { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + // Remove use of custom code once + // https://github.com/kubernetes-sigs/controller-runtime/issues/994 is + // fixed. This should be able to be: + // + // return k8sctrlutil.ContainsFinalizer(obj, FinalizerString) + return containsFinalizer(obj, FinalizerString) +} + +// Remove once https://github.com/kubernetes-sigs/controller-runtime/issues/994 +// is fixed. +func containsFinalizer(obj rtclient.Object, finalizer string) bool { + f := obj.GetFinalizers() + for _, e := range f { + if e == finalizer { + return true + } + } + return false +} + +// MarkManaged places the supplied resource under the management of ACK. What +// this typically means is that the resource manager will decorate the +// underlying custom resource (CR) with a finalizer that indicates ACK is +// managing the resource and the underlying CR may not be deleted until ACK is +// finished cleaning up any backend AWS service resources associated with the +// CR. +func (d *resourceDescriptor) MarkManaged( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + k8sctrlutil.AddFinalizer(obj, FinalizerString) +} + +// MarkUnmanaged removes the supplied resource from management by ACK. What +// this typically means is that the resource manager will remove a finalizer +// underlying custom resource (CR) that indicates ACK is managing the resource. +// This will allow the Kubernetes API server to delete the underlying CR. +func (d *resourceDescriptor) MarkUnmanaged( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + k8sctrlutil.RemoveFinalizer(obj, FinalizerString) +} + +// MarkAdopted places descriptors on the custom resource that indicate the +// resource was not created from within ACK. +func (d *resourceDescriptor) MarkAdopted( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeObject in AWSResource") + } + curr := obj.GetAnnotations() + if curr == nil { + curr = make(map[string]string) + } + curr[ackv1alpha1.AnnotationAdopted] = "true" + obj.SetAnnotations(curr) +} diff --git a/pkg/resource/agent_runtime/hooks.go b/pkg/resource/agent_runtime/hooks.go new file mode 100644 index 0000000..98e9536 --- /dev/null +++ b/pkg/resource/agent_runtime/hooks.go @@ -0,0 +1,23 @@ +package agent_runtime + +import ( + "fmt" + "time" + + "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/pkg/tags" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + svcsdktypes "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol/types" +) + +var ( + requeueNotReady = ackrequeue.NeededAfter( + fmt.Errorf("agentruntime is not in Ready state, cannot be modified or deleted"), + 15*time.Second, + ) +) + +func agentRuntimeReady(rt *resource) bool { + return rt.ko.Status.Status != nil && *rt.ko.Status.Status == string(svcsdktypes.AgentRuntimeEndpointStatusReady) +} + +var syncTags = tags.SyncTags diff --git a/pkg/resource/agent_runtime/identifiers.go b/pkg/resource/agent_runtime/identifiers.go new file mode 100644 index 0000000..94b7dcf --- /dev/null +++ b/pkg/resource/agent_runtime/identifiers.go @@ -0,0 +1,55 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" +) + +// resourceIdentifiers implements the +// `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface +type resourceIdentifiers struct { + meta *ackv1alpha1.ResourceMetadata +} + +// ARN returns the AWS Resource Name for the backend AWS resource. If nil, +// this means the resource has not yet been created in the backend AWS +// service. +func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { + if ri.meta != nil { + return ri.meta.ARN + } + return nil +} + +// OwnerAccountID returns the AWS account identifier in which the +// backend AWS resource resides, or nil if this information is not known +// for the resource +func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { + if ri.meta != nil { + return ri.meta.OwnerAccountID + } + return nil +} + +// Region returns the AWS region in which the resource exists, or +// nil if this information is not known. +func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { + if ri.meta != nil { + return ri.meta.Region + } + return nil +} diff --git a/pkg/resource/agent_runtime/manager.go b/pkg/resource/agent_runtime/manager.go new file mode 100644 index 0000000..24ba74c --- /dev/null +++ b/pkg/resource/agent_runtime/manager.go @@ -0,0 +1,404 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime + +import ( + "context" + "fmt" + "time" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" + ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + ackrt "github.com/aws-controllers-k8s/runtime/pkg/runtime" + ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log" + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + ackutil "github.com/aws-controllers-k8s/runtime/pkg/util" + "github.com/aws/aws-sdk-go-v2/aws" + svcsdk "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol" + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +var ( + _ = ackutil.InStrings + _ = acktags.NewTags() + _ = ackrt.MissingImageTagValue + _ = svcapitypes.AgentRuntime{} +) + +// +kubebuilder:rbac:groups=bedrockagentcorecontrol.services.k8s.aws,resources=agentruntimes,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=bedrockagentcorecontrol.services.k8s.aws,resources=agentruntimes/status,verbs=get;update;patch + +var lateInitializeFieldNames = []string{} + +// resourceManager is responsible for providing a consistent way to perform +// CRUD operations in a backend AWS service API for Book custom resources. +type resourceManager struct { + // cfg is a copy of the ackcfg.Config object passed on start of the service + // controller + cfg ackcfg.Config + // clientcfg is a copy of the client configuration passed on start of the + // service controller + clientcfg aws.Config + // log refers to the logr.Logger object handling logging for the service + // controller + log logr.Logger + // metrics contains a collection of Prometheus metric objects that the + // service controller and its reconcilers track + metrics *ackmetrics.Metrics + // rr is the Reconciler which can be used for various utility + // functions such as querying for Secret values given a SecretReference + rr acktypes.Reconciler + // awsAccountID is the AWS account identifier that contains the resources + // managed by this resource manager + awsAccountID ackv1alpha1.AWSAccountID + // The AWS Region that this resource manager targets + awsRegion ackv1alpha1.AWSRegion + // sdk is a pointer to the AWS service API client exposed by the + // aws-sdk-go-v2/services/{alias} package. + sdkapi *svcsdk.Client +} + +// concreteResource returns a pointer to a resource from the supplied +// generic AWSResource interface +func (rm *resourceManager) concreteResource( + res acktypes.AWSResource, +) *resource { + // cast the generic interface into a pointer type specific to the concrete + // implementing resource type managed by this resource manager + return res.(*resource) +} + +// ReadOne returns the currently-observed state of the supplied AWSResource in +// the backend AWS service API. +func (rm *resourceManager) ReadOne( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's ReadOne() method received resource with nil CR object") + } + observed, err := rm.sdkFind(ctx, r) + mirrorAWSTags(r, observed) + if err != nil { + if observed != nil { + return rm.onError(observed, err) + } + return rm.onError(r, err) + } + return rm.onSuccess(observed) +} + +// Create attempts to create the supplied AWSResource in the backend AWS +// service API, returning an AWSResource representing the newly-created +// resource +func (rm *resourceManager) Create( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Create() method received resource with nil CR object") + } + created, err := rm.sdkCreate(ctx, r) + if err != nil { + if created != nil { + return rm.onError(created, err) + } + return rm.onError(r, err) + } + return rm.onSuccess(created) +} + +// Update attempts to mutate the supplied desired AWSResource in the backend AWS +// service API, returning an AWSResource representing the newly-mutated +// resource. +// Note for specialized logic implementers can check to see how the latest +// observed resource differs from the supplied desired state. The +// higher-level reonciler determines whether or not the desired differs +// from the latest observed and decides whether to call the resource +// manager's Update method +func (rm *resourceManager) Update( + ctx context.Context, + resDesired acktypes.AWSResource, + resLatest acktypes.AWSResource, + delta *ackcompare.Delta, +) (acktypes.AWSResource, error) { + desired := rm.concreteResource(resDesired) + latest := rm.concreteResource(resLatest) + if desired.ko == nil || latest.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Update() method received resource with nil CR object") + } + updated, err := rm.sdkUpdate(ctx, desired, latest, delta) + if err != nil { + if updated != nil { + return rm.onError(updated, err) + } + return rm.onError(latest, err) + } + return rm.onSuccess(updated) +} + +// Delete attempts to destroy the supplied AWSResource in the backend AWS +// service API, returning an AWSResource representing the +// resource being deleted (if delete is asynchronous and takes time) +func (rm *resourceManager) Delete( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Update() method received resource with nil CR object") + } + observed, err := rm.sdkDelete(ctx, r) + if err != nil { + if observed != nil { + return rm.onError(observed, err) + } + return rm.onError(r, err) + } + + return rm.onSuccess(observed) +} + +// ARNFromName returns an AWS Resource Name from a given string name. This +// is useful for constructing ARNs for APIs that require ARNs in their +// GetAttributes operations but all we have (for new CRs at least) is a +// name for the resource +func (rm *resourceManager) ARNFromName(name string) string { + return fmt.Sprintf( + "arn:aws:bedrockagentcorecontrol:%s:%s:%s", + rm.awsRegion, + rm.awsAccountID, + name, + ) +} + +// LateInitialize returns an acktypes.AWSResource after setting the late initialized +// fields from the readOne call. This method will initialize the optional fields +// which were not provided by the k8s user but were defaulted by the AWS service. +// If there are no such fields to be initialized, the returned object is similar to +// object passed in the parameter. +func (rm *resourceManager) LateInitialize( + ctx context.Context, + latest acktypes.AWSResource, +) (acktypes.AWSResource, error) { + rlog := ackrtlog.FromContext(ctx) + // If there are no fields to late initialize, do nothing + if len(lateInitializeFieldNames) == 0 { + rlog.Debug("no late initialization required.") + return latest, nil + } + latestCopy := latest.DeepCopy() + lateInitConditionReason := "" + lateInitConditionMessage := "" + observed, err := rm.ReadOne(ctx, latestCopy) + if err != nil { + lateInitConditionMessage = "Unable to complete Read operation required for late initialization" + lateInitConditionReason = "Late Initialization Failure" + ackcondition.SetLateInitialized(latestCopy, corev1.ConditionFalse, &lateInitConditionMessage, &lateInitConditionReason) + ackcondition.SetSynced(latestCopy, corev1.ConditionFalse, nil, nil) + return latestCopy, err + } + lateInitializedRes := rm.lateInitializeFromReadOneOutput(observed, latestCopy) + incompleteInitialization := rm.incompleteLateInitialization(lateInitializedRes) + if incompleteInitialization { + // Add the condition with LateInitialized=False + lateInitConditionMessage = "Late initialization did not complete, requeuing with delay of 5 seconds" + lateInitConditionReason = "Delayed Late Initialization" + ackcondition.SetLateInitialized(lateInitializedRes, corev1.ConditionFalse, &lateInitConditionMessage, &lateInitConditionReason) + ackcondition.SetSynced(lateInitializedRes, corev1.ConditionFalse, nil, nil) + return lateInitializedRes, ackrequeue.NeededAfter(nil, time.Duration(5)*time.Second) + } + // Set LateInitialized condition to True + lateInitConditionMessage = "Late initialization successful" + lateInitConditionReason = "Late initialization successful" + ackcondition.SetLateInitialized(lateInitializedRes, corev1.ConditionTrue, &lateInitConditionMessage, &lateInitConditionReason) + return lateInitializedRes, nil +} + +// incompleteLateInitialization return true if there are fields which were supposed to be +// late initialized but are not. If all the fields are late initialized, false is returned +func (rm *resourceManager) incompleteLateInitialization( + res acktypes.AWSResource, +) bool { + return false +} + +// lateInitializeFromReadOneOutput late initializes the 'latest' resource from the 'observed' +// resource and returns 'latest' resource +func (rm *resourceManager) lateInitializeFromReadOneOutput( + observed acktypes.AWSResource, + latest acktypes.AWSResource, +) acktypes.AWSResource { + return latest +} + +// IsSynced returns true if the resource is synced. +func (rm *resourceManager) IsSynced(ctx context.Context, res acktypes.AWSResource) (bool, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's IsSynced() method received resource with nil CR object") + } + + return true, nil +} + +// EnsureTags ensures that tags are present inside the AWSResource. +// If the AWSResource does not have any existing resource tags, the 'tags' +// field is initialized and the controller tags are added. +// If the AWSResource has existing resource tags, then controller tags are +// added to the existing resource tags without overriding them. +// If the AWSResource does not support tags, only then the controller tags +// will not be added to the AWSResource. +func (rm *resourceManager) EnsureTags( + ctx context.Context, + res acktypes.AWSResource, + md acktypes.ServiceControllerMetadata, +) error { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's EnsureTags method received resource with nil CR object") + } + defaultTags := ackrt.GetDefaultTags(&rm.cfg, r.ko, md) + var existingTags map[string]*string + existingTags = r.ko.Spec.Tags + resourceTags, keyOrder := convertToOrderedACKTags(existingTags) + tags := acktags.Merge(resourceTags, defaultTags) + r.ko.Spec.Tags = fromACKTags(tags, keyOrder) + return nil +} + +// FilterAWSTags ignores tags that have keys that start with "aws:" +// is needed to ensure the controller does not attempt to remove +// tags set by AWS. This function needs to be called after each Read +// operation. +// Eg. resources created with cloudformation have tags that cannot be +// removed by an ACK controller +func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { + r := rm.concreteResource(res) + if r == nil || r.ko == nil { + return + } + var existingTags map[string]*string + existingTags = r.ko.Spec.Tags + resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) + ignoreSystemTags(resourceTags) + r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) +} + +// mirrorAWSTags ensures that AWS tags are included in the desired resource +// if they are present in the latest resource. This will ensure that the +// aws tags are not present in a diff. The logic of the controller will +// ensure these tags aren't patched to the resource in the cluster, and +// will only be present to make sure we don't try to remove these tags. +// +// Although there are a lot of similarities between this function and +// EnsureTags, they are very much different. +// While EnsureTags tries to make sure the resource contains the controller +// tags, mirrowAWSTags tries to make sure tags injected by AWS are mirrored +// from the latest resoruce to the desired resource. +func mirrorAWSTags(a *resource, b *resource) { + if a == nil || a.ko == nil || b == nil || b.ko == nil { + return + } + var existingLatestTags map[string]*string + var existingDesiredTags map[string]*string + existingDesiredTags = a.ko.Spec.Tags + existingLatestTags = b.ko.Spec.Tags + desiredTags, desiredTagKeyOrder := convertToOrderedACKTags(existingDesiredTags) + latestTags, _ := convertToOrderedACKTags(existingLatestTags) + syncAWSTags(desiredTags, latestTags) + a.ko.Spec.Tags = fromACKTags(desiredTags, desiredTagKeyOrder) +} + +// newResourceManager returns a new struct implementing +// acktypes.AWSResourceManager +// This is for AWS-SDK-GO-V2 - Created newResourceManager With AWS sdk-Go-ClientV2 +func newResourceManager( + cfg ackcfg.Config, + clientcfg aws.Config, + log logr.Logger, + metrics *ackmetrics.Metrics, + rr acktypes.Reconciler, + id ackv1alpha1.AWSAccountID, + region ackv1alpha1.AWSRegion, +) (*resourceManager, error) { + return &resourceManager{ + cfg: cfg, + clientcfg: clientcfg, + log: log, + metrics: metrics, + rr: rr, + awsAccountID: id, + awsRegion: region, + sdkapi: svcsdk.NewFromConfig(clientcfg), + }, nil +} + +// onError updates resource conditions and returns updated resource +// it returns nil if no condition is updated. +func (rm *resourceManager) onError( + r *resource, + err error, +) (acktypes.AWSResource, error) { + if r == nil { + return nil, err + } + r1, updated := rm.updateConditions(r, false, err) + if !updated { + return r, err + } + for _, condition := range r1.Conditions() { + if condition.Type == ackv1alpha1.ConditionTypeTerminal && + condition.Status == corev1.ConditionTrue { + // resource is in Terminal condition + // return Terminal error + return r1, ackerr.Terminal + } + } + return r1, err +} + +// onSuccess updates resource conditions and returns updated resource +// it returns the supplied resource if no condition is updated. +func (rm *resourceManager) onSuccess( + r *resource, +) (acktypes.AWSResource, error) { + if r == nil { + return nil, nil + } + r1, updated := rm.updateConditions(r, true, nil) + if !updated { + return r, nil + } + return r1, nil +} diff --git a/pkg/resource/agent_runtime/manager_factory.go b/pkg/resource/agent_runtime/manager_factory.go new file mode 100644 index 0000000..d9e9378 --- /dev/null +++ b/pkg/resource/agent_runtime/manager_factory.go @@ -0,0 +1,100 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime + +import ( + "fmt" + "sync" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" + ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/go-logr/logr" + + svcresource "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/pkg/resource" +) + +// resourceManagerFactory produces resourceManager objects. It implements the +// `types.AWSResourceManagerFactory` interface. +type resourceManagerFactory struct { + sync.RWMutex + // rmCache contains resource managers for a particular AWS account ID + rmCache map[string]*resourceManager +} + +// ResourcePrototype returns an AWSResource that resource managers produced by +// this factory will handle +func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { + return &resourceDescriptor{} +} + +// ManagerFor returns a resource manager object that can manage resources for a +// supplied AWS account +func (f *resourceManagerFactory) ManagerFor( + cfg ackcfg.Config, + clientcfg aws.Config, + log logr.Logger, + metrics *ackmetrics.Metrics, + rr acktypes.Reconciler, + id ackv1alpha1.AWSAccountID, + region ackv1alpha1.AWSRegion, + roleARN ackv1alpha1.AWSResourceName, +) (acktypes.AWSResourceManager, error) { + // We use the account ID, region, and role ARN to uniquely identify a + // resource manager. This helps us to avoid creating multiple resource + // managers for the same account/region/roleARN combination. + rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) + f.RLock() + rm, found := f.rmCache[rmId] + f.RUnlock() + + if found { + return rm, nil + } + + f.Lock() + defer f.Unlock() + + rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) + if err != nil { + return nil, err + } + f.rmCache[rmId] = rm + return rm, nil +} + +// IsAdoptable returns true if the resource is able to be adopted +func (f *resourceManagerFactory) IsAdoptable() bool { + return true +} + +// RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds +// Default is false which means resource will not be requeued after success. +func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { + return 0 +} + +func newResourceManagerFactory() *resourceManagerFactory { + return &resourceManagerFactory{ + rmCache: map[string]*resourceManager{}, + } +} + +func init() { + svcresource.RegisterManagerFactory(newResourceManagerFactory()) +} diff --git a/pkg/resource/agent_runtime/references.go b/pkg/resource/agent_runtime/references.go new file mode 100644 index 0000000..7b39acc --- /dev/null +++ b/pkg/resource/agent_runtime/references.go @@ -0,0 +1,57 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" + + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +// ClearResolvedReferences removes any reference values that were made +// concrete in the spec. It returns a copy of the input AWSResource which +// contains the original *Ref values, but none of their respective concrete +// values. +func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) acktypes.AWSResource { + ko := rm.concreteResource(res).ko.DeepCopy() + + return &resource{ko} +} + +// ResolveReferences finds if there are any Reference field(s) present +// inside AWSResource passed in the parameter and attempts to resolve those +// reference field(s) into their respective target field(s). It returns a +// copy of the input AWSResource with resolved reference(s), a boolean which +// is set to true if the resource contains any references (regardless of if +// they are resolved successfully) and an error if the passed AWSResource's +// reference field(s) could not be resolved. +func (rm *resourceManager) ResolveReferences( + ctx context.Context, + apiReader client.Reader, + res acktypes.AWSResource, +) (acktypes.AWSResource, bool, error) { + return res, false, nil +} + +// validateReferenceFields validates the reference field and corresponding +// identifier field. +func validateReferenceFields(ko *svcapitypes.AgentRuntime) error { + return nil +} diff --git a/pkg/resource/agent_runtime/resource.go b/pkg/resource/agent_runtime/resource.go new file mode 100644 index 0000000..5c07e1e --- /dev/null +++ b/pkg/resource/agent_runtime/resource.go @@ -0,0 +1,124 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime + +import ( + "fmt" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackerrors "github.com/aws-controllers-k8s/runtime/pkg/errors" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + "github.com/aws/aws-sdk-go-v2/aws" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + rtclient "sigs.k8s.io/controller-runtime/pkg/client" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +// Hack to avoid import errors during build... +var ( + _ = &ackerrors.MissingNameIdentifier +) + +// resource implements the `aws-controller-k8s/runtime/pkg/types.AWSResource` +// interface +type resource struct { + // The Kubernetes-native CR representing the resource + ko *svcapitypes.AgentRuntime +} + +// Identifiers returns an AWSResourceIdentifiers object containing various +// identifying information, including the AWS account ID that owns the +// resource, the resource's AWS Resource Name (ARN) +func (r *resource) Identifiers() acktypes.AWSResourceIdentifiers { + return &resourceIdentifiers{r.ko.Status.ACKResourceMetadata} +} + +// IsBeingDeleted returns true if the Kubernetes resource has a non-zero +// deletion timestamp +func (r *resource) IsBeingDeleted() bool { + return !r.ko.DeletionTimestamp.IsZero() +} + +// RuntimeObject returns the Kubernetes apimachinery/runtime representation of +// the AWSResource +func (r *resource) RuntimeObject() rtclient.Object { + return r.ko +} + +// MetaObject returns the Kubernetes apimachinery/apis/meta/v1.Object +// representation of the AWSResource +func (r *resource) MetaObject() metav1.Object { + return r.ko.GetObjectMeta() +} + +// Conditions returns the ACK Conditions collection for the AWSResource +func (r *resource) Conditions() []*ackv1alpha1.Condition { + return r.ko.Status.Conditions +} + +// ReplaceConditions sets the Conditions status field for the resource +func (r *resource) ReplaceConditions(conditions []*ackv1alpha1.Condition) { + r.ko.Status.Conditions = conditions +} + +// SetObjectMeta sets the ObjectMeta field for the resource +func (r *resource) SetObjectMeta(meta metav1.ObjectMeta) { + r.ko.ObjectMeta = meta +} + +// SetStatus will set the Status field for the resource +func (r *resource) SetStatus(desired acktypes.AWSResource) { + r.ko.Status = desired.(*resource).ko.Status +} + +// SetIdentifiers sets the Spec or Status field that is referenced as the unique +// resource identifier +func (r *resource) SetIdentifiers(identifier *ackv1alpha1.AWSIdentifiers) error { + if identifier.NameOrID == "" { + return ackerrors.MissingNameIdentifier + } + r.ko.Status.AgentRuntimeID = &identifier.NameOrID + + f1, f1ok := identifier.AdditionalKeys["agentRuntimeVersion"] + if f1ok { + r.ko.Status.AgentRuntimeVersion = aws.String(f1) + } + + return nil +} + +// PopulateResourceFromAnnotation populates the fields passed from adoption annotation +func (r *resource) PopulateResourceFromAnnotation(fields map[string]string) error { + f0, ok := fields["agentRuntimeID"] + if !ok { + return ackerrors.NewTerminalError(fmt.Errorf("required field missing: agentRuntimeID")) + } + r.ko.Status.AgentRuntimeID = &f0 + + f1, f1ok := fields["agentRuntimeVersion"] + if f1ok { + r.ko.Status.AgentRuntimeVersion = aws.String(f1) + } + + return nil +} + +// DeepCopy will return a copy of the resource +func (r *resource) DeepCopy() acktypes.AWSResource { + koCopy := r.ko.DeepCopy() + return &resource{koCopy} +} diff --git a/pkg/resource/agent_runtime/sdk.go b/pkg/resource/agent_runtime/sdk.go new file mode 100644 index 0000000..994450a --- /dev/null +++ b/pkg/resource/agent_runtime/sdk.go @@ -0,0 +1,784 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime + +import ( + "context" + "errors" + "fmt" + "reflect" + "strings" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log" + "github.com/aws/aws-sdk-go-v2/aws" + svcsdk "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol" + svcsdktypes "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol/types" + smithy "github.com/aws/smithy-go" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +// Hack to avoid import errors during build... +var ( + _ = &metav1.Time{} + _ = strings.ToLower("") + _ = &svcsdk.Client{} + _ = &svcapitypes.AgentRuntime{} + _ = ackv1alpha1.AWSAccountID("") + _ = &ackerr.NotFound + _ = &ackcondition.NotManagedMessage + _ = &reflect.Value{} + _ = fmt.Sprintf("") + _ = &ackrequeue.NoRequeue{} + _ = &aws.Config{} +) + +// sdkFind returns SDK-specific information about a supplied resource +func (rm *resourceManager) sdkFind( + ctx context.Context, + r *resource, +) (latest *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkFind") + defer func() { + exit(err) + }() + // If any required fields in the input shape are missing, AWS resource is + // not created yet. Return NotFound here to indicate to callers that the + // resource isn't yet created. + if rm.requiredFieldsMissingFromReadOneInput(r) { + return nil, ackerr.NotFound + } + + input, err := rm.newDescribeRequestPayload(r) + if err != nil { + return nil, err + } + + var resp *svcsdk.GetAgentRuntimeOutput + resp, err = rm.sdkapi.GetAgentRuntime(ctx, input) + rm.metrics.RecordAPICall("READ_ONE", "GetAgentRuntime", err) + if err != nil { + var awsErr smithy.APIError + if errors.As(err, &awsErr) && awsErr.ErrorCode() == "ResourceNotFoundException" { + return nil, ackerr.NotFound + } + return nil, err + } + + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := r.ko.DeepCopy() + + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if resp.AgentRuntimeArn != nil { + arn := ackv1alpha1.AWSResourceName(*resp.AgentRuntimeArn) + ko.Status.ACKResourceMetadata.ARN = &arn + } + if resp.AgentRuntimeArtifact != nil { + f1 := &svcapitypes.AgentRuntimeArtifact{} + switch resp.AgentRuntimeArtifact.(type) { + case *svcsdktypes.AgentRuntimeArtifactMemberContainerConfiguration: + f1f0 := resp.AgentRuntimeArtifact.(*svcsdktypes.AgentRuntimeArtifactMemberContainerConfiguration) + if f1f0 != nil { + f1f0f0 := &svcapitypes.ContainerConfiguration{} + if f1f0.Value.ContainerUri != nil { + f1f0f0.ContainerURI = f1f0.Value.ContainerUri + } + f1.ContainerConfiguration = f1f0f0 + } + } + ko.Spec.AgentRuntimeArtifact = f1 + } else { + ko.Spec.AgentRuntimeArtifact = nil + } + if resp.AgentRuntimeId != nil { + ko.Status.AgentRuntimeID = resp.AgentRuntimeId + } else { + ko.Status.AgentRuntimeID = nil + } + if resp.AgentRuntimeName != nil { + ko.Spec.AgentRuntimeName = resp.AgentRuntimeName + } else { + ko.Spec.AgentRuntimeName = nil + } + if resp.AgentRuntimeVersion != nil { + ko.Status.AgentRuntimeVersion = resp.AgentRuntimeVersion + } else { + ko.Status.AgentRuntimeVersion = nil + } + if resp.AuthorizerConfiguration != nil { + f5 := &svcapitypes.AuthorizerConfiguration{} + switch resp.AuthorizerConfiguration.(type) { + case *svcsdktypes.AuthorizerConfigurationMemberCustomJWTAuthorizer: + f5f0 := resp.AuthorizerConfiguration.(*svcsdktypes.AuthorizerConfigurationMemberCustomJWTAuthorizer) + if f5f0 != nil { + f5f0f0 := &svcapitypes.CustomJWTAuthorizerConfiguration{} + if f5f0.Value.AllowedAudience != nil { + f5f0f0.AllowedAudience = aws.StringSlice(f5f0.Value.AllowedAudience) + } + if f5f0.Value.AllowedClients != nil { + f5f0f0.AllowedClients = aws.StringSlice(f5f0.Value.AllowedClients) + } + if f5f0.Value.DiscoveryUrl != nil { + f5f0f0.DiscoveryURL = f5f0.Value.DiscoveryUrl + } + f5.CustomJWTAuthorizer = f5f0f0 + } + } + ko.Spec.AuthorizerConfiguration = f5 + } else { + ko.Spec.AuthorizerConfiguration = nil + } + if resp.CreatedAt != nil { + ko.Status.CreatedAt = &metav1.Time{*resp.CreatedAt} + } else { + ko.Status.CreatedAt = nil + } + if resp.Description != nil { + ko.Spec.Description = resp.Description + } else { + ko.Spec.Description = nil + } + if resp.EnvironmentVariables != nil { + ko.Spec.EnvironmentVariables = aws.StringMap(resp.EnvironmentVariables) + } else { + ko.Spec.EnvironmentVariables = nil + } + if resp.NetworkConfiguration != nil { + f10 := &svcapitypes.NetworkConfiguration{} + if resp.NetworkConfiguration.NetworkMode != "" { + f10.NetworkMode = aws.String(string(resp.NetworkConfiguration.NetworkMode)) + } + if resp.NetworkConfiguration.NetworkModeConfig != nil { + f10f1 := &svcapitypes.VPCConfig{} + if resp.NetworkConfiguration.NetworkModeConfig.SecurityGroups != nil { + f10f1.SecurityGroups = aws.StringSlice(resp.NetworkConfiguration.NetworkModeConfig.SecurityGroups) + } + if resp.NetworkConfiguration.NetworkModeConfig.Subnets != nil { + f10f1.Subnets = aws.StringSlice(resp.NetworkConfiguration.NetworkModeConfig.Subnets) + } + f10.NetworkModeConfig = f10f1 + } + ko.Spec.NetworkConfiguration = f10 + } else { + ko.Spec.NetworkConfiguration = nil + } + if resp.ProtocolConfiguration != nil { + f11 := &svcapitypes.ProtocolConfiguration{} + if resp.ProtocolConfiguration.ServerProtocol != "" { + f11.ServerProtocol = aws.String(string(resp.ProtocolConfiguration.ServerProtocol)) + } + ko.Spec.ProtocolConfiguration = f11 + } else { + ko.Spec.ProtocolConfiguration = nil + } + if resp.RequestHeaderConfiguration != nil { + f12 := &svcapitypes.RequestHeaderConfiguration{} + switch resp.RequestHeaderConfiguration.(type) { + case *svcsdktypes.RequestHeaderConfigurationMemberRequestHeaderAllowlist: + f12f0 := resp.RequestHeaderConfiguration.(*svcsdktypes.RequestHeaderConfigurationMemberRequestHeaderAllowlist) + if f12f0 != nil { + f12.RequestHeaderAllowlist = aws.StringSlice(f12f0.Value) + } + } + ko.Spec.RequestHeaderConfiguration = f12 + } else { + ko.Spec.RequestHeaderConfiguration = nil + } + if resp.RoleArn != nil { + ko.Spec.RoleARN = resp.RoleArn + } else { + ko.Spec.RoleARN = nil + } + if resp.Status != "" { + ko.Status.Status = aws.String(string(resp.Status)) + } else { + ko.Status.Status = nil + } + if resp.WorkloadIdentityDetails != nil { + f15 := &svcapitypes.WorkloadIdentityDetails{} + if resp.WorkloadIdentityDetails.WorkloadIdentityArn != nil { + f15.WorkloadIdentityARN = resp.WorkloadIdentityDetails.WorkloadIdentityArn + } + ko.Status.WorkloadIdentityDetails = f15 + } else { + ko.Status.WorkloadIdentityDetails = nil + } + + rm.setStatusDefaults(ko) + if !agentRuntimeReady(&resource{ko}) { + return nil, requeueNotReady + } + return &resource{ko}, nil +} + +// requiredFieldsMissingFromReadOneInput returns true if there are any fields +// for the ReadOne Input shape that are required but not present in the +// resource's Spec or Status +func (rm *resourceManager) requiredFieldsMissingFromReadOneInput( + r *resource, +) bool { + return r.ko.Status.AgentRuntimeID == nil + +} + +// newDescribeRequestPayload returns SDK-specific struct for the HTTP request +// payload of the Describe API call for the resource +func (rm *resourceManager) newDescribeRequestPayload( + r *resource, +) (*svcsdk.GetAgentRuntimeInput, error) { + res := &svcsdk.GetAgentRuntimeInput{} + + if r.ko.Status.AgentRuntimeID != nil { + res.AgentRuntimeId = r.ko.Status.AgentRuntimeID + } + if r.ko.Status.AgentRuntimeVersion != nil { + res.AgentRuntimeVersion = r.ko.Status.AgentRuntimeVersion + } + + return res, nil +} + +// sdkCreate creates the supplied resource in the backend AWS service API and +// returns a copy of the resource with resource fields (in both Spec and +// Status) filled in with values from the CREATE API operation's Output shape. +func (rm *resourceManager) sdkCreate( + ctx context.Context, + desired *resource, +) (created *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkCreate") + defer func() { + exit(err) + }() + input, err := rm.newCreateRequestPayload(ctx, desired) + if err != nil { + return nil, err + } + + var resp *svcsdk.CreateAgentRuntimeOutput + _ = resp + resp, err = rm.sdkapi.CreateAgentRuntime(ctx, input) + rm.metrics.RecordAPICall("CREATE", "CreateAgentRuntime", err) + if err != nil { + return nil, err + } + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := desired.ko.DeepCopy() + + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if resp.AgentRuntimeArn != nil { + arn := ackv1alpha1.AWSResourceName(*resp.AgentRuntimeArn) + ko.Status.ACKResourceMetadata.ARN = &arn + } + if resp.AgentRuntimeId != nil { + ko.Status.AgentRuntimeID = resp.AgentRuntimeId + } else { + ko.Status.AgentRuntimeID = nil + } + if resp.AgentRuntimeVersion != nil { + ko.Status.AgentRuntimeVersion = resp.AgentRuntimeVersion + } else { + ko.Status.AgentRuntimeVersion = nil + } + if resp.CreatedAt != nil { + ko.Status.CreatedAt = &metav1.Time{*resp.CreatedAt} + } else { + ko.Status.CreatedAt = nil + } + if resp.Status != "" { + ko.Status.Status = aws.String(string(resp.Status)) + } else { + ko.Status.Status = nil + } + if resp.WorkloadIdentityDetails != nil { + f5 := &svcapitypes.WorkloadIdentityDetails{} + if resp.WorkloadIdentityDetails.WorkloadIdentityArn != nil { + f5.WorkloadIdentityARN = resp.WorkloadIdentityDetails.WorkloadIdentityArn + } + ko.Status.WorkloadIdentityDetails = f5 + } else { + ko.Status.WorkloadIdentityDetails = nil + } + + rm.setStatusDefaults(ko) + return &resource{ko}, nil +} + +// newCreateRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Create API call for the resource +func (rm *resourceManager) newCreateRequestPayload( + ctx context.Context, + r *resource, +) (*svcsdk.CreateAgentRuntimeInput, error) { + res := &svcsdk.CreateAgentRuntimeInput{} + + if r.ko.Spec.AgentRuntimeArtifact != nil { + var f0 svcsdktypes.AgentRuntimeArtifact + isInterfaceSet := false + if r.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for ContainerConfiguration")) + } + f0f0Parent := &svcsdktypes.AgentRuntimeArtifactMemberContainerConfiguration{} + f0f0 := &svcsdktypes.ContainerConfiguration{} + if r.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI != nil { + f0f0.ContainerUri = r.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI + } + f0f0Parent.Value = *f0f0 + f0 = f0f0Parent + isInterfaceSet = true + } + res.AgentRuntimeArtifact = f0 + } + if r.ko.Spec.AgentRuntimeName != nil { + res.AgentRuntimeName = r.ko.Spec.AgentRuntimeName + } + if r.ko.Spec.AuthorizerConfiguration != nil { + var f2 svcsdktypes.AuthorizerConfiguration + isInterfaceSet := false + if r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for CustomJWTAuthorizer")) + } + f2f0Parent := &svcsdktypes.AuthorizerConfigurationMemberCustomJWTAuthorizer{} + f2f0 := &svcsdktypes.CustomJWTAuthorizerConfiguration{} + if r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience != nil { + f2f0.AllowedAudience = aws.ToStringSlice(r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience) + } + if r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients != nil { + f2f0.AllowedClients = aws.ToStringSlice(r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients) + } + if r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL != nil { + f2f0.DiscoveryUrl = r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL + } + f2f0Parent.Value = *f2f0 + f2 = f2f0Parent + isInterfaceSet = true + } + res.AuthorizerConfiguration = f2 + } + if r.ko.Spec.Description != nil { + res.Description = r.ko.Spec.Description + } + if r.ko.Spec.EnvironmentVariables != nil { + res.EnvironmentVariables = aws.ToStringMap(r.ko.Spec.EnvironmentVariables) + } + if r.ko.Spec.NetworkConfiguration != nil { + f5 := &svcsdktypes.NetworkConfiguration{} + if r.ko.Spec.NetworkConfiguration.NetworkMode != nil { + f5.NetworkMode = svcsdktypes.NetworkMode(*r.ko.Spec.NetworkConfiguration.NetworkMode) + } + if r.ko.Spec.NetworkConfiguration.NetworkModeConfig != nil { + f5f1 := &svcsdktypes.VpcConfig{} + if r.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups != nil { + f5f1.SecurityGroups = aws.ToStringSlice(r.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups) + } + if r.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets != nil { + f5f1.Subnets = aws.ToStringSlice(r.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets) + } + f5.NetworkModeConfig = f5f1 + } + res.NetworkConfiguration = f5 + } + if r.ko.Spec.ProtocolConfiguration != nil { + f6 := &svcsdktypes.ProtocolConfiguration{} + if r.ko.Spec.ProtocolConfiguration.ServerProtocol != nil { + f6.ServerProtocol = svcsdktypes.ServerProtocol(*r.ko.Spec.ProtocolConfiguration.ServerProtocol) + } + res.ProtocolConfiguration = f6 + } + if r.ko.Spec.RequestHeaderConfiguration != nil { + var f7 svcsdktypes.RequestHeaderConfiguration + isInterfaceSet := false + if r.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for RequestHeaderAllowlist")) + } + f7f0Parent := &svcsdktypes.RequestHeaderConfigurationMemberRequestHeaderAllowlist{} + f7f0 := []string{} + f7f0 = aws.ToStringSlice(r.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist) + f7f0Parent.Value = f7f0 + f7 = f7f0Parent + isInterfaceSet = true + } + res.RequestHeaderConfiguration = f7 + } + if r.ko.Spec.RoleARN != nil { + res.RoleArn = r.ko.Spec.RoleARN + } + if r.ko.Spec.Tags != nil { + res.Tags = aws.ToStringMap(r.ko.Spec.Tags) + } + + return res, nil +} + +// sdkUpdate patches the supplied resource in the backend AWS service API and +// returns a new resource with updated fields. +func (rm *resourceManager) sdkUpdate( + ctx context.Context, + desired *resource, + latest *resource, + delta *ackcompare.Delta, +) (updated *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkUpdate") + defer func() { + exit(err) + }() + if delta.DifferentAt("Spec.Tags") { + err := syncTags( + ctx, rm.sdkapi, rm.metrics, + string(*latest.ko.Status.ACKResourceMetadata.ARN), + aws.ToStringMap(desired.ko.Spec.Tags), aws.ToStringMap(latest.ko.Spec.Tags), + ) + if err != nil { + return nil, err + } + } + if !delta.DifferentExcept("Spec.Tags") { + return desired, nil + } + if !agentRuntimeReady(latest) { + return latest, requeueNotReady + } + input, err := rm.newUpdateRequestPayload(ctx, desired, delta) + if err != nil { + return nil, err + } + + var resp *svcsdk.UpdateAgentRuntimeOutput + _ = resp + resp, err = rm.sdkapi.UpdateAgentRuntime(ctx, input) + rm.metrics.RecordAPICall("UPDATE", "UpdateAgentRuntime", err) + if err != nil { + return nil, err + } + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := desired.ko.DeepCopy() + + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if resp.AgentRuntimeArn != nil { + arn := ackv1alpha1.AWSResourceName(*resp.AgentRuntimeArn) + ko.Status.ACKResourceMetadata.ARN = &arn + } + if resp.AgentRuntimeId != nil { + ko.Status.AgentRuntimeID = resp.AgentRuntimeId + } else { + ko.Status.AgentRuntimeID = nil + } + if resp.AgentRuntimeVersion != nil { + ko.Status.AgentRuntimeVersion = resp.AgentRuntimeVersion + } else { + ko.Status.AgentRuntimeVersion = nil + } + if resp.CreatedAt != nil { + ko.Status.CreatedAt = &metav1.Time{*resp.CreatedAt} + } else { + ko.Status.CreatedAt = nil + } + if resp.Status != "" { + ko.Status.Status = aws.String(string(resp.Status)) + } else { + ko.Status.Status = nil + } + if resp.WorkloadIdentityDetails != nil { + f6 := &svcapitypes.WorkloadIdentityDetails{} + if resp.WorkloadIdentityDetails.WorkloadIdentityArn != nil { + f6.WorkloadIdentityARN = resp.WorkloadIdentityDetails.WorkloadIdentityArn + } + ko.Status.WorkloadIdentityDetails = f6 + } else { + ko.Status.WorkloadIdentityDetails = nil + } + + rm.setStatusDefaults(ko) + return &resource{ko}, nil +} + +// newUpdateRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Update API call for the resource +func (rm *resourceManager) newUpdateRequestPayload( + ctx context.Context, + r *resource, + delta *ackcompare.Delta, +) (*svcsdk.UpdateAgentRuntimeInput, error) { + res := &svcsdk.UpdateAgentRuntimeInput{} + + if r.ko.Spec.AgentRuntimeArtifact != nil { + var f0 svcsdktypes.AgentRuntimeArtifact + isInterfaceSet := false + if r.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for ContainerConfiguration")) + } + f0f0Parent := &svcsdktypes.AgentRuntimeArtifactMemberContainerConfiguration{} + f0f0 := &svcsdktypes.ContainerConfiguration{} + if r.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI != nil { + f0f0.ContainerUri = r.ko.Spec.AgentRuntimeArtifact.ContainerConfiguration.ContainerURI + } + f0f0Parent.Value = *f0f0 + f0 = f0f0Parent + isInterfaceSet = true + } + res.AgentRuntimeArtifact = f0 + } + if r.ko.Status.AgentRuntimeID != nil { + res.AgentRuntimeId = r.ko.Status.AgentRuntimeID + } + if r.ko.Spec.AuthorizerConfiguration != nil { + var f2 svcsdktypes.AuthorizerConfiguration + isInterfaceSet := false + if r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for CustomJWTAuthorizer")) + } + f2f0Parent := &svcsdktypes.AuthorizerConfigurationMemberCustomJWTAuthorizer{} + f2f0 := &svcsdktypes.CustomJWTAuthorizerConfiguration{} + if r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience != nil { + f2f0.AllowedAudience = aws.ToStringSlice(r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience) + } + if r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients != nil { + f2f0.AllowedClients = aws.ToStringSlice(r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients) + } + if r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL != nil { + f2f0.DiscoveryUrl = r.ko.Spec.AuthorizerConfiguration.CustomJWTAuthorizer.DiscoveryURL + } + f2f0Parent.Value = *f2f0 + f2 = f2f0Parent + isInterfaceSet = true + } + res.AuthorizerConfiguration = f2 + } + if r.ko.Spec.Description != nil { + res.Description = r.ko.Spec.Description + } + if r.ko.Spec.EnvironmentVariables != nil { + res.EnvironmentVariables = aws.ToStringMap(r.ko.Spec.EnvironmentVariables) + } + if r.ko.Spec.NetworkConfiguration != nil { + f6 := &svcsdktypes.NetworkConfiguration{} + if r.ko.Spec.NetworkConfiguration.NetworkMode != nil { + f6.NetworkMode = svcsdktypes.NetworkMode(*r.ko.Spec.NetworkConfiguration.NetworkMode) + } + if r.ko.Spec.NetworkConfiguration.NetworkModeConfig != nil { + f6f1 := &svcsdktypes.VpcConfig{} + if r.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups != nil { + f6f1.SecurityGroups = aws.ToStringSlice(r.ko.Spec.NetworkConfiguration.NetworkModeConfig.SecurityGroups) + } + if r.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets != nil { + f6f1.Subnets = aws.ToStringSlice(r.ko.Spec.NetworkConfiguration.NetworkModeConfig.Subnets) + } + f6.NetworkModeConfig = f6f1 + } + res.NetworkConfiguration = f6 + } + if r.ko.Spec.ProtocolConfiguration != nil { + f7 := &svcsdktypes.ProtocolConfiguration{} + if r.ko.Spec.ProtocolConfiguration.ServerProtocol != nil { + f7.ServerProtocol = svcsdktypes.ServerProtocol(*r.ko.Spec.ProtocolConfiguration.ServerProtocol) + } + res.ProtocolConfiguration = f7 + } + if r.ko.Spec.RequestHeaderConfiguration != nil { + var f8 svcsdktypes.RequestHeaderConfiguration + isInterfaceSet := false + if r.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist != nil { + if isInterfaceSet { + return nil, ackerr.NewTerminalError(fmt.Errorf("can only set one of the members for RequestHeaderAllowlist")) + } + f8f0Parent := &svcsdktypes.RequestHeaderConfigurationMemberRequestHeaderAllowlist{} + f8f0 := []string{} + f8f0 = aws.ToStringSlice(r.ko.Spec.RequestHeaderConfiguration.RequestHeaderAllowlist) + f8f0Parent.Value = f8f0 + f8 = f8f0Parent + isInterfaceSet = true + } + res.RequestHeaderConfiguration = f8 + } + if r.ko.Spec.RoleARN != nil { + res.RoleArn = r.ko.Spec.RoleARN + } + + return res, nil +} + +// sdkDelete deletes the supplied resource in the backend AWS service API +func (rm *resourceManager) sdkDelete( + ctx context.Context, + r *resource, +) (latest *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkDelete") + defer func() { + exit(err) + }() + input, err := rm.newDeleteRequestPayload(r) + if err != nil { + return nil, err + } + var resp *svcsdk.DeleteAgentRuntimeOutput + _ = resp + resp, err = rm.sdkapi.DeleteAgentRuntime(ctx, input) + rm.metrics.RecordAPICall("DELETE", "DeleteAgentRuntime", err) + return nil, err +} + +// newDeleteRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Delete API call for the resource +func (rm *resourceManager) newDeleteRequestPayload( + r *resource, +) (*svcsdk.DeleteAgentRuntimeInput, error) { + res := &svcsdk.DeleteAgentRuntimeInput{} + + if r.ko.Status.AgentRuntimeID != nil { + res.AgentRuntimeId = r.ko.Status.AgentRuntimeID + } + + return res, nil +} + +// setStatusDefaults sets default properties into supplied custom resource +func (rm *resourceManager) setStatusDefaults( + ko *svcapitypes.AgentRuntime, +) { + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if ko.Status.ACKResourceMetadata.Region == nil { + ko.Status.ACKResourceMetadata.Region = &rm.awsRegion + } + if ko.Status.ACKResourceMetadata.OwnerAccountID == nil { + ko.Status.ACKResourceMetadata.OwnerAccountID = &rm.awsAccountID + } + if ko.Status.Conditions == nil { + ko.Status.Conditions = []*ackv1alpha1.Condition{} + } +} + +// updateConditions returns updated resource, true; if conditions were updated +// else it returns nil, false +func (rm *resourceManager) updateConditions( + r *resource, + onSuccess bool, + err error, +) (*resource, bool) { + ko := r.ko.DeepCopy() + rm.setStatusDefaults(ko) + + // Terminal condition + var terminalCondition *ackv1alpha1.Condition = nil + var recoverableCondition *ackv1alpha1.Condition = nil + var syncCondition *ackv1alpha1.Condition = nil + for _, condition := range ko.Status.Conditions { + if condition.Type == ackv1alpha1.ConditionTypeTerminal { + terminalCondition = condition + } + if condition.Type == ackv1alpha1.ConditionTypeRecoverable { + recoverableCondition = condition + } + if condition.Type == ackv1alpha1.ConditionTypeResourceSynced { + syncCondition = condition + } + } + var termError *ackerr.TerminalError + if rm.terminalAWSError(err) || err == ackerr.SecretTypeNotSupported || err == ackerr.SecretNotFound || errors.As(err, &termError) { + if terminalCondition == nil { + terminalCondition = &ackv1alpha1.Condition{ + Type: ackv1alpha1.ConditionTypeTerminal, + } + ko.Status.Conditions = append(ko.Status.Conditions, terminalCondition) + } + var errorMessage = "" + if err == ackerr.SecretTypeNotSupported || err == ackerr.SecretNotFound || errors.As(err, &termError) { + errorMessage = err.Error() + } else { + awsErr, _ := ackerr.AWSError(err) + errorMessage = awsErr.Error() + } + terminalCondition.Status = corev1.ConditionTrue + terminalCondition.Message = &errorMessage + } else { + // Clear the terminal condition if no longer present + if terminalCondition != nil { + terminalCondition.Status = corev1.ConditionFalse + terminalCondition.Message = nil + } + // Handling Recoverable Conditions + if err != nil { + if recoverableCondition == nil { + // Add a new Condition containing a non-terminal error + recoverableCondition = &ackv1alpha1.Condition{ + Type: ackv1alpha1.ConditionTypeRecoverable, + } + ko.Status.Conditions = append(ko.Status.Conditions, recoverableCondition) + } + recoverableCondition.Status = corev1.ConditionTrue + awsErr, _ := ackerr.AWSError(err) + errorMessage := err.Error() + if awsErr != nil { + errorMessage = awsErr.Error() + } + recoverableCondition.Message = &errorMessage + } else if recoverableCondition != nil { + recoverableCondition.Status = corev1.ConditionFalse + recoverableCondition.Message = nil + } + } + // Required to avoid the "declared but not used" error in the default case + _ = syncCondition + if terminalCondition != nil || recoverableCondition != nil || syncCondition != nil { + return &resource{ko}, true // updated + } + return nil, false // not updated +} + +// terminalAWSError returns awserr, true; if the supplied error is an aws Error type +// and if the exception indicates that it is a Terminal exception +// 'Terminal' exception are specified in generator configuration +func (rm *resourceManager) terminalAWSError(err error) bool { + if err == nil { + return false + } + + var terminalErr smithy.APIError + if !errors.As(err, &terminalErr) { + return false + } + switch terminalErr.ErrorCode() { + case "ValidationException": + return true + default: + return false + } +} diff --git a/pkg/resource/agent_runtime/tags.go b/pkg/resource/agent_runtime/tags.go new file mode 100644 index 0000000..614bfef --- /dev/null +++ b/pkg/resource/agent_runtime/tags.go @@ -0,0 +1,108 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime + +import ( + "slices" + "strings" + + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +var ( + _ = svcapitypes.AgentRuntime{} + _ = acktags.NewTags() + ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} +) + +// convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. +// This method helps in creating the hub(acktags.Tags) for merging +// default controller tags with existing resource tags. It also returns a slice +// of keys maintaining the original key Order when the tags are a list +func convertToOrderedACKTags(tags map[string]*string) (acktags.Tags, []string) { + result := acktags.NewTags() + keyOrder := []string{} + + if len(tags) == 0 { + return result, keyOrder + } + for k, v := range tags { + if v == nil { + result[k] = "" + } else { + result[k] = *v + } + } + + return result, keyOrder +} + +// fromACKTags converts the tags parameter into map[string]*string shape. +// This method helps in setting the tags back inside AWSResource after merging +// default controller tags with existing resource tags. When a list, +// it maintains the order from original +func fromACKTags(tags acktags.Tags, keyOrder []string) map[string]*string { + result := map[string]*string{} + + _ = keyOrder + for k, v := range tags { + result[k] = &v + } + + return result +} + +// ignoreSystemTags ignores tags that have keys that start with "aws:" +// and ACKSystemTags, to avoid patching them to the resourceSpec. +// Eg. resources created with cloudformation have tags that cannot be +// removed by an ACK controller +func ignoreSystemTags(tags acktags.Tags) { + for k := range tags { + if strings.HasPrefix(k, "aws:") || + slices.Contains(ACKSystemTags, k) { + delete(tags, k) + } + } +} + +// syncAWSTags ensures AWS-managed tags (prefixed with "aws:") from the latest resource state +// are preserved in the desired state. This prevents the controller from attempting to +// modify AWS-managed tags, which would result in an error. +// +// AWS-managed tags are automatically added by AWS services (e.g., CloudFormation, Service Catalog) +// and cannot be modified or deleted through normal tag operations. Common examples include: +// - aws:cloudformation:stack-name +// - aws:servicecatalog:productArn +// +// Parameters: +// - a: The target Tags map to be updated (typically desired state) +// - b: The source Tags map containing AWS-managed tags (typically latest state) +// +// Example: +// +// latest := Tags{"aws:cloudformation:stack-name": "my-stack", "environment": "prod"} +// desired := Tags{"environment": "dev"} +// SyncAWSTags(desired, latest) +// desired now contains {"aws:cloudformation:stack-name": "my-stack", "environment": "dev"} +func syncAWSTags(a acktags.Tags, b acktags.Tags) { + for k := range b { + if strings.HasPrefix(k, "aws:") { + a[k] = b[k] + } + } +} diff --git a/pkg/resource/agent_runtime_endpoint/delta.go b/pkg/resource/agent_runtime_endpoint/delta.go new file mode 100644 index 0000000..9ea9951 --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/delta.go @@ -0,0 +1,81 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime_endpoint + +import ( + "bytes" + "reflect" + + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" +) + +// Hack to avoid import errors during build... +var ( + _ = &bytes.Buffer{} + _ = &reflect.Method{} + _ = &acktags.Tags{} +) + +// newResourceDelta returns a new `ackcompare.Delta` used to compare two +// resources +func newResourceDelta( + a *resource, + b *resource, +) *ackcompare.Delta { + delta := ackcompare.NewDelta() + if (a == nil && b != nil) || + (a != nil && b == nil) { + delta.Add("", a, b) + return delta + } + + if ackcompare.HasNilDifference(a.ko.Spec.AgentRuntimeID, b.ko.Spec.AgentRuntimeID) { + delta.Add("Spec.AgentRuntimeID", a.ko.Spec.AgentRuntimeID, b.ko.Spec.AgentRuntimeID) + } else if a.ko.Spec.AgentRuntimeID != nil && b.ko.Spec.AgentRuntimeID != nil { + if *a.ko.Spec.AgentRuntimeID != *b.ko.Spec.AgentRuntimeID { + delta.Add("Spec.AgentRuntimeID", a.ko.Spec.AgentRuntimeID, b.ko.Spec.AgentRuntimeID) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.AgentRuntimeVersion, b.ko.Spec.AgentRuntimeVersion) { + delta.Add("Spec.AgentRuntimeVersion", a.ko.Spec.AgentRuntimeVersion, b.ko.Spec.AgentRuntimeVersion) + } else if a.ko.Spec.AgentRuntimeVersion != nil && b.ko.Spec.AgentRuntimeVersion != nil { + if *a.ko.Spec.AgentRuntimeVersion != *b.ko.Spec.AgentRuntimeVersion { + delta.Add("Spec.AgentRuntimeVersion", a.ko.Spec.AgentRuntimeVersion, b.ko.Spec.AgentRuntimeVersion) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.Description, b.ko.Spec.Description) { + delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) + } else if a.ko.Spec.Description != nil && b.ko.Spec.Description != nil { + if *a.ko.Spec.Description != *b.ko.Spec.Description { + delta.Add("Spec.Description", a.ko.Spec.Description, b.ko.Spec.Description) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.Name, b.ko.Spec.Name) { + delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) + } else if a.ko.Spec.Name != nil && b.ko.Spec.Name != nil { + if *a.ko.Spec.Name != *b.ko.Spec.Name { + delta.Add("Spec.Name", a.ko.Spec.Name, b.ko.Spec.Name) + } + } + desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tags) + latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tags) + if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) { + delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags) + } + + return delta +} diff --git a/pkg/resource/agent_runtime_endpoint/descriptor.go b/pkg/resource/agent_runtime_endpoint/descriptor.go new file mode 100644 index 0000000..c817b93 --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/descriptor.go @@ -0,0 +1,155 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime_endpoint + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + rtclient "sigs.k8s.io/controller-runtime/pkg/client" + k8sctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +const ( + FinalizerString = "finalizers.bedrockagentcorecontrol.services.k8s.aws/AgentRuntimeEndpoint" +) + +var ( + GroupVersionResource = svcapitypes.GroupVersion.WithResource("agentruntimeendpoints") + GroupKind = metav1.GroupKind{ + Group: "bedrockagentcorecontrol.services.k8s.aws", + Kind: "AgentRuntimeEndpoint", + } +) + +// resourceDescriptor implements the +// `aws-service-operator-k8s/pkg/types.AWSResourceDescriptor` interface +type resourceDescriptor struct { +} + +// GroupVersionKind returns a Kubernetes schema.GroupVersionKind struct that +// describes the API Group, Version and Kind of CRs described by the descriptor +func (d *resourceDescriptor) GroupVersionKind() schema.GroupVersionKind { + return svcapitypes.GroupVersion.WithKind(GroupKind.Kind) +} + +// EmptyRuntimeObject returns an empty object prototype that may be used in +// apimachinery and k8s client operations +func (d *resourceDescriptor) EmptyRuntimeObject() rtclient.Object { + return &svcapitypes.AgentRuntimeEndpoint{} +} + +// ResourceFromRuntimeObject returns an AWSResource that has been initialized +// with the supplied runtime.Object +func (d *resourceDescriptor) ResourceFromRuntimeObject( + obj rtclient.Object, +) acktypes.AWSResource { + return &resource{ + ko: obj.(*svcapitypes.AgentRuntimeEndpoint), + } +} + +// Delta returns an `ackcompare.Delta` object containing the difference between +// one `AWSResource` and another. +func (d *resourceDescriptor) Delta(a, b acktypes.AWSResource) *ackcompare.Delta { + return newResourceDelta(a.(*resource), b.(*resource)) +} + +// IsManaged returns true if the supplied AWSResource is under the management +// of an ACK service controller. What this means in practice is that the +// underlying custom resource (CR) in the AWSResource has had a +// resource-specific finalizer associated with it. +func (d *resourceDescriptor) IsManaged( + res acktypes.AWSResource, +) bool { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + // Remove use of custom code once + // https://github.com/kubernetes-sigs/controller-runtime/issues/994 is + // fixed. This should be able to be: + // + // return k8sctrlutil.ContainsFinalizer(obj, FinalizerString) + return containsFinalizer(obj, FinalizerString) +} + +// Remove once https://github.com/kubernetes-sigs/controller-runtime/issues/994 +// is fixed. +func containsFinalizer(obj rtclient.Object, finalizer string) bool { + f := obj.GetFinalizers() + for _, e := range f { + if e == finalizer { + return true + } + } + return false +} + +// MarkManaged places the supplied resource under the management of ACK. What +// this typically means is that the resource manager will decorate the +// underlying custom resource (CR) with a finalizer that indicates ACK is +// managing the resource and the underlying CR may not be deleted until ACK is +// finished cleaning up any backend AWS service resources associated with the +// CR. +func (d *resourceDescriptor) MarkManaged( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + k8sctrlutil.AddFinalizer(obj, FinalizerString) +} + +// MarkUnmanaged removes the supplied resource from management by ACK. What +// this typically means is that the resource manager will remove a finalizer +// underlying custom resource (CR) that indicates ACK is managing the resource. +// This will allow the Kubernetes API server to delete the underlying CR. +func (d *resourceDescriptor) MarkUnmanaged( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + k8sctrlutil.RemoveFinalizer(obj, FinalizerString) +} + +// MarkAdopted places descriptors on the custom resource that indicate the +// resource was not created from within ACK. +func (d *resourceDescriptor) MarkAdopted( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeObject in AWSResource") + } + curr := obj.GetAnnotations() + if curr == nil { + curr = make(map[string]string) + } + curr[ackv1alpha1.AnnotationAdopted] = "true" + obj.SetAnnotations(curr) +} diff --git a/pkg/resource/agent_runtime_endpoint/hooks.go b/pkg/resource/agent_runtime_endpoint/hooks.go new file mode 100644 index 0000000..1c172ac --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/hooks.go @@ -0,0 +1,23 @@ +package agent_runtime_endpoint + +import ( + "fmt" + "time" + + "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/pkg/tags" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + svcsdktypes "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol/types" +) + +var ( + requeueNotReady = ackrequeue.NeededAfter( + fmt.Errorf("agentRuntimeEndpoint is not in Ready state, cannot be modified or deleted"), + 15*time.Second, + ) +) + +func agentRuntimeEndpointReady(rt *resource) bool { + return rt.ko.Status.Status != nil && *rt.ko.Status.Status == string(svcsdktypes.AgentRuntimeEndpointStatusReady) +} + +var syncTags = tags.SyncTags diff --git a/pkg/resource/agent_runtime_endpoint/identifiers.go b/pkg/resource/agent_runtime_endpoint/identifiers.go new file mode 100644 index 0000000..0c50d05 --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/identifiers.go @@ -0,0 +1,55 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime_endpoint + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" +) + +// resourceIdentifiers implements the +// `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface +type resourceIdentifiers struct { + meta *ackv1alpha1.ResourceMetadata +} + +// ARN returns the AWS Resource Name for the backend AWS resource. If nil, +// this means the resource has not yet been created in the backend AWS +// service. +func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { + if ri.meta != nil { + return ri.meta.ARN + } + return nil +} + +// OwnerAccountID returns the AWS account identifier in which the +// backend AWS resource resides, or nil if this information is not known +// for the resource +func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { + if ri.meta != nil { + return ri.meta.OwnerAccountID + } + return nil +} + +// Region returns the AWS region in which the resource exists, or +// nil if this information is not known. +func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { + if ri.meta != nil { + return ri.meta.Region + } + return nil +} diff --git a/pkg/resource/agent_runtime_endpoint/manager.go b/pkg/resource/agent_runtime_endpoint/manager.go new file mode 100644 index 0000000..eddaf82 --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/manager.go @@ -0,0 +1,404 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime_endpoint + +import ( + "context" + "fmt" + "time" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" + ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + ackrt "github.com/aws-controllers-k8s/runtime/pkg/runtime" + ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log" + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + ackutil "github.com/aws-controllers-k8s/runtime/pkg/util" + "github.com/aws/aws-sdk-go-v2/aws" + svcsdk "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol" + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +var ( + _ = ackutil.InStrings + _ = acktags.NewTags() + _ = ackrt.MissingImageTagValue + _ = svcapitypes.AgentRuntimeEndpoint{} +) + +// +kubebuilder:rbac:groups=bedrockagentcorecontrol.services.k8s.aws,resources=agentruntimeendpoints,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=bedrockagentcorecontrol.services.k8s.aws,resources=agentruntimeendpoints/status,verbs=get;update;patch + +var lateInitializeFieldNames = []string{} + +// resourceManager is responsible for providing a consistent way to perform +// CRUD operations in a backend AWS service API for Book custom resources. +type resourceManager struct { + // cfg is a copy of the ackcfg.Config object passed on start of the service + // controller + cfg ackcfg.Config + // clientcfg is a copy of the client configuration passed on start of the + // service controller + clientcfg aws.Config + // log refers to the logr.Logger object handling logging for the service + // controller + log logr.Logger + // metrics contains a collection of Prometheus metric objects that the + // service controller and its reconcilers track + metrics *ackmetrics.Metrics + // rr is the Reconciler which can be used for various utility + // functions such as querying for Secret values given a SecretReference + rr acktypes.Reconciler + // awsAccountID is the AWS account identifier that contains the resources + // managed by this resource manager + awsAccountID ackv1alpha1.AWSAccountID + // The AWS Region that this resource manager targets + awsRegion ackv1alpha1.AWSRegion + // sdk is a pointer to the AWS service API client exposed by the + // aws-sdk-go-v2/services/{alias} package. + sdkapi *svcsdk.Client +} + +// concreteResource returns a pointer to a resource from the supplied +// generic AWSResource interface +func (rm *resourceManager) concreteResource( + res acktypes.AWSResource, +) *resource { + // cast the generic interface into a pointer type specific to the concrete + // implementing resource type managed by this resource manager + return res.(*resource) +} + +// ReadOne returns the currently-observed state of the supplied AWSResource in +// the backend AWS service API. +func (rm *resourceManager) ReadOne( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's ReadOne() method received resource with nil CR object") + } + observed, err := rm.sdkFind(ctx, r) + mirrorAWSTags(r, observed) + if err != nil { + if observed != nil { + return rm.onError(observed, err) + } + return rm.onError(r, err) + } + return rm.onSuccess(observed) +} + +// Create attempts to create the supplied AWSResource in the backend AWS +// service API, returning an AWSResource representing the newly-created +// resource +func (rm *resourceManager) Create( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Create() method received resource with nil CR object") + } + created, err := rm.sdkCreate(ctx, r) + if err != nil { + if created != nil { + return rm.onError(created, err) + } + return rm.onError(r, err) + } + return rm.onSuccess(created) +} + +// Update attempts to mutate the supplied desired AWSResource in the backend AWS +// service API, returning an AWSResource representing the newly-mutated +// resource. +// Note for specialized logic implementers can check to see how the latest +// observed resource differs from the supplied desired state. The +// higher-level reonciler determines whether or not the desired differs +// from the latest observed and decides whether to call the resource +// manager's Update method +func (rm *resourceManager) Update( + ctx context.Context, + resDesired acktypes.AWSResource, + resLatest acktypes.AWSResource, + delta *ackcompare.Delta, +) (acktypes.AWSResource, error) { + desired := rm.concreteResource(resDesired) + latest := rm.concreteResource(resLatest) + if desired.ko == nil || latest.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Update() method received resource with nil CR object") + } + updated, err := rm.sdkUpdate(ctx, desired, latest, delta) + if err != nil { + if updated != nil { + return rm.onError(updated, err) + } + return rm.onError(latest, err) + } + return rm.onSuccess(updated) +} + +// Delete attempts to destroy the supplied AWSResource in the backend AWS +// service API, returning an AWSResource representing the +// resource being deleted (if delete is asynchronous and takes time) +func (rm *resourceManager) Delete( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Update() method received resource with nil CR object") + } + observed, err := rm.sdkDelete(ctx, r) + if err != nil { + if observed != nil { + return rm.onError(observed, err) + } + return rm.onError(r, err) + } + + return rm.onSuccess(observed) +} + +// ARNFromName returns an AWS Resource Name from a given string name. This +// is useful for constructing ARNs for APIs that require ARNs in their +// GetAttributes operations but all we have (for new CRs at least) is a +// name for the resource +func (rm *resourceManager) ARNFromName(name string) string { + return fmt.Sprintf( + "arn:aws:bedrockagentcorecontrol:%s:%s:%s", + rm.awsRegion, + rm.awsAccountID, + name, + ) +} + +// LateInitialize returns an acktypes.AWSResource after setting the late initialized +// fields from the readOne call. This method will initialize the optional fields +// which were not provided by the k8s user but were defaulted by the AWS service. +// If there are no such fields to be initialized, the returned object is similar to +// object passed in the parameter. +func (rm *resourceManager) LateInitialize( + ctx context.Context, + latest acktypes.AWSResource, +) (acktypes.AWSResource, error) { + rlog := ackrtlog.FromContext(ctx) + // If there are no fields to late initialize, do nothing + if len(lateInitializeFieldNames) == 0 { + rlog.Debug("no late initialization required.") + return latest, nil + } + latestCopy := latest.DeepCopy() + lateInitConditionReason := "" + lateInitConditionMessage := "" + observed, err := rm.ReadOne(ctx, latestCopy) + if err != nil { + lateInitConditionMessage = "Unable to complete Read operation required for late initialization" + lateInitConditionReason = "Late Initialization Failure" + ackcondition.SetLateInitialized(latestCopy, corev1.ConditionFalse, &lateInitConditionMessage, &lateInitConditionReason) + ackcondition.SetSynced(latestCopy, corev1.ConditionFalse, nil, nil) + return latestCopy, err + } + lateInitializedRes := rm.lateInitializeFromReadOneOutput(observed, latestCopy) + incompleteInitialization := rm.incompleteLateInitialization(lateInitializedRes) + if incompleteInitialization { + // Add the condition with LateInitialized=False + lateInitConditionMessage = "Late initialization did not complete, requeuing with delay of 5 seconds" + lateInitConditionReason = "Delayed Late Initialization" + ackcondition.SetLateInitialized(lateInitializedRes, corev1.ConditionFalse, &lateInitConditionMessage, &lateInitConditionReason) + ackcondition.SetSynced(lateInitializedRes, corev1.ConditionFalse, nil, nil) + return lateInitializedRes, ackrequeue.NeededAfter(nil, time.Duration(5)*time.Second) + } + // Set LateInitialized condition to True + lateInitConditionMessage = "Late initialization successful" + lateInitConditionReason = "Late initialization successful" + ackcondition.SetLateInitialized(lateInitializedRes, corev1.ConditionTrue, &lateInitConditionMessage, &lateInitConditionReason) + return lateInitializedRes, nil +} + +// incompleteLateInitialization return true if there are fields which were supposed to be +// late initialized but are not. If all the fields are late initialized, false is returned +func (rm *resourceManager) incompleteLateInitialization( + res acktypes.AWSResource, +) bool { + return false +} + +// lateInitializeFromReadOneOutput late initializes the 'latest' resource from the 'observed' +// resource and returns 'latest' resource +func (rm *resourceManager) lateInitializeFromReadOneOutput( + observed acktypes.AWSResource, + latest acktypes.AWSResource, +) acktypes.AWSResource { + return latest +} + +// IsSynced returns true if the resource is synced. +func (rm *resourceManager) IsSynced(ctx context.Context, res acktypes.AWSResource) (bool, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's IsSynced() method received resource with nil CR object") + } + + return true, nil +} + +// EnsureTags ensures that tags are present inside the AWSResource. +// If the AWSResource does not have any existing resource tags, the 'tags' +// field is initialized and the controller tags are added. +// If the AWSResource has existing resource tags, then controller tags are +// added to the existing resource tags without overriding them. +// If the AWSResource does not support tags, only then the controller tags +// will not be added to the AWSResource. +func (rm *resourceManager) EnsureTags( + ctx context.Context, + res acktypes.AWSResource, + md acktypes.ServiceControllerMetadata, +) error { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's EnsureTags method received resource with nil CR object") + } + defaultTags := ackrt.GetDefaultTags(&rm.cfg, r.ko, md) + var existingTags map[string]*string + existingTags = r.ko.Spec.Tags + resourceTags, keyOrder := convertToOrderedACKTags(existingTags) + tags := acktags.Merge(resourceTags, defaultTags) + r.ko.Spec.Tags = fromACKTags(tags, keyOrder) + return nil +} + +// FilterAWSTags ignores tags that have keys that start with "aws:" +// is needed to ensure the controller does not attempt to remove +// tags set by AWS. This function needs to be called after each Read +// operation. +// Eg. resources created with cloudformation have tags that cannot be +// removed by an ACK controller +func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { + r := rm.concreteResource(res) + if r == nil || r.ko == nil { + return + } + var existingTags map[string]*string + existingTags = r.ko.Spec.Tags + resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) + ignoreSystemTags(resourceTags) + r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) +} + +// mirrorAWSTags ensures that AWS tags are included in the desired resource +// if they are present in the latest resource. This will ensure that the +// aws tags are not present in a diff. The logic of the controller will +// ensure these tags aren't patched to the resource in the cluster, and +// will only be present to make sure we don't try to remove these tags. +// +// Although there are a lot of similarities between this function and +// EnsureTags, they are very much different. +// While EnsureTags tries to make sure the resource contains the controller +// tags, mirrowAWSTags tries to make sure tags injected by AWS are mirrored +// from the latest resoruce to the desired resource. +func mirrorAWSTags(a *resource, b *resource) { + if a == nil || a.ko == nil || b == nil || b.ko == nil { + return + } + var existingLatestTags map[string]*string + var existingDesiredTags map[string]*string + existingDesiredTags = a.ko.Spec.Tags + existingLatestTags = b.ko.Spec.Tags + desiredTags, desiredTagKeyOrder := convertToOrderedACKTags(existingDesiredTags) + latestTags, _ := convertToOrderedACKTags(existingLatestTags) + syncAWSTags(desiredTags, latestTags) + a.ko.Spec.Tags = fromACKTags(desiredTags, desiredTagKeyOrder) +} + +// newResourceManager returns a new struct implementing +// acktypes.AWSResourceManager +// This is for AWS-SDK-GO-V2 - Created newResourceManager With AWS sdk-Go-ClientV2 +func newResourceManager( + cfg ackcfg.Config, + clientcfg aws.Config, + log logr.Logger, + metrics *ackmetrics.Metrics, + rr acktypes.Reconciler, + id ackv1alpha1.AWSAccountID, + region ackv1alpha1.AWSRegion, +) (*resourceManager, error) { + return &resourceManager{ + cfg: cfg, + clientcfg: clientcfg, + log: log, + metrics: metrics, + rr: rr, + awsAccountID: id, + awsRegion: region, + sdkapi: svcsdk.NewFromConfig(clientcfg), + }, nil +} + +// onError updates resource conditions and returns updated resource +// it returns nil if no condition is updated. +func (rm *resourceManager) onError( + r *resource, + err error, +) (acktypes.AWSResource, error) { + if r == nil { + return nil, err + } + r1, updated := rm.updateConditions(r, false, err) + if !updated { + return r, err + } + for _, condition := range r1.Conditions() { + if condition.Type == ackv1alpha1.ConditionTypeTerminal && + condition.Status == corev1.ConditionTrue { + // resource is in Terminal condition + // return Terminal error + return r1, ackerr.Terminal + } + } + return r1, err +} + +// onSuccess updates resource conditions and returns updated resource +// it returns the supplied resource if no condition is updated. +func (rm *resourceManager) onSuccess( + r *resource, +) (acktypes.AWSResource, error) { + if r == nil { + return nil, nil + } + r1, updated := rm.updateConditions(r, true, nil) + if !updated { + return r, nil + } + return r1, nil +} diff --git a/pkg/resource/agent_runtime_endpoint/manager_factory.go b/pkg/resource/agent_runtime_endpoint/manager_factory.go new file mode 100644 index 0000000..3e01336 --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/manager_factory.go @@ -0,0 +1,100 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime_endpoint + +import ( + "fmt" + "sync" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" + ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/go-logr/logr" + + svcresource "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/pkg/resource" +) + +// resourceManagerFactory produces resourceManager objects. It implements the +// `types.AWSResourceManagerFactory` interface. +type resourceManagerFactory struct { + sync.RWMutex + // rmCache contains resource managers for a particular AWS account ID + rmCache map[string]*resourceManager +} + +// ResourcePrototype returns an AWSResource that resource managers produced by +// this factory will handle +func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { + return &resourceDescriptor{} +} + +// ManagerFor returns a resource manager object that can manage resources for a +// supplied AWS account +func (f *resourceManagerFactory) ManagerFor( + cfg ackcfg.Config, + clientcfg aws.Config, + log logr.Logger, + metrics *ackmetrics.Metrics, + rr acktypes.Reconciler, + id ackv1alpha1.AWSAccountID, + region ackv1alpha1.AWSRegion, + roleARN ackv1alpha1.AWSResourceName, +) (acktypes.AWSResourceManager, error) { + // We use the account ID, region, and role ARN to uniquely identify a + // resource manager. This helps us to avoid creating multiple resource + // managers for the same account/region/roleARN combination. + rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) + f.RLock() + rm, found := f.rmCache[rmId] + f.RUnlock() + + if found { + return rm, nil + } + + f.Lock() + defer f.Unlock() + + rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) + if err != nil { + return nil, err + } + f.rmCache[rmId] = rm + return rm, nil +} + +// IsAdoptable returns true if the resource is able to be adopted +func (f *resourceManagerFactory) IsAdoptable() bool { + return true +} + +// RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds +// Default is false which means resource will not be requeued after success. +func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { + return 0 +} + +func newResourceManagerFactory() *resourceManagerFactory { + return &resourceManagerFactory{ + rmCache: map[string]*resourceManager{}, + } +} + +func init() { + svcresource.RegisterManagerFactory(newResourceManagerFactory()) +} diff --git a/pkg/resource/agent_runtime_endpoint/references.go b/pkg/resource/agent_runtime_endpoint/references.go new file mode 100644 index 0000000..0c6a5b0 --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/references.go @@ -0,0 +1,57 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime_endpoint + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" + + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +// ClearResolvedReferences removes any reference values that were made +// concrete in the spec. It returns a copy of the input AWSResource which +// contains the original *Ref values, but none of their respective concrete +// values. +func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) acktypes.AWSResource { + ko := rm.concreteResource(res).ko.DeepCopy() + + return &resource{ko} +} + +// ResolveReferences finds if there are any Reference field(s) present +// inside AWSResource passed in the parameter and attempts to resolve those +// reference field(s) into their respective target field(s). It returns a +// copy of the input AWSResource with resolved reference(s), a boolean which +// is set to true if the resource contains any references (regardless of if +// they are resolved successfully) and an error if the passed AWSResource's +// reference field(s) could not be resolved. +func (rm *resourceManager) ResolveReferences( + ctx context.Context, + apiReader client.Reader, + res acktypes.AWSResource, +) (acktypes.AWSResource, bool, error) { + return res, false, nil +} + +// validateReferenceFields validates the reference field and corresponding +// identifier field. +func validateReferenceFields(ko *svcapitypes.AgentRuntimeEndpoint) error { + return nil +} diff --git a/pkg/resource/agent_runtime_endpoint/resource.go b/pkg/resource/agent_runtime_endpoint/resource.go new file mode 100644 index 0000000..81beeda --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/resource.go @@ -0,0 +1,124 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime_endpoint + +import ( + "fmt" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackerrors "github.com/aws-controllers-k8s/runtime/pkg/errors" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + "github.com/aws/aws-sdk-go-v2/aws" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + rtclient "sigs.k8s.io/controller-runtime/pkg/client" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +// Hack to avoid import errors during build... +var ( + _ = &ackerrors.MissingNameIdentifier +) + +// resource implements the `aws-controller-k8s/runtime/pkg/types.AWSResource` +// interface +type resource struct { + // The Kubernetes-native CR representing the resource + ko *svcapitypes.AgentRuntimeEndpoint +} + +// Identifiers returns an AWSResourceIdentifiers object containing various +// identifying information, including the AWS account ID that owns the +// resource, the resource's AWS Resource Name (ARN) +func (r *resource) Identifiers() acktypes.AWSResourceIdentifiers { + return &resourceIdentifiers{r.ko.Status.ACKResourceMetadata} +} + +// IsBeingDeleted returns true if the Kubernetes resource has a non-zero +// deletion timestamp +func (r *resource) IsBeingDeleted() bool { + return !r.ko.DeletionTimestamp.IsZero() +} + +// RuntimeObject returns the Kubernetes apimachinery/runtime representation of +// the AWSResource +func (r *resource) RuntimeObject() rtclient.Object { + return r.ko +} + +// MetaObject returns the Kubernetes apimachinery/apis/meta/v1.Object +// representation of the AWSResource +func (r *resource) MetaObject() metav1.Object { + return r.ko.GetObjectMeta() +} + +// Conditions returns the ACK Conditions collection for the AWSResource +func (r *resource) Conditions() []*ackv1alpha1.Condition { + return r.ko.Status.Conditions +} + +// ReplaceConditions sets the Conditions status field for the resource +func (r *resource) ReplaceConditions(conditions []*ackv1alpha1.Condition) { + r.ko.Status.Conditions = conditions +} + +// SetObjectMeta sets the ObjectMeta field for the resource +func (r *resource) SetObjectMeta(meta metav1.ObjectMeta) { + r.ko.ObjectMeta = meta +} + +// SetStatus will set the Status field for the resource +func (r *resource) SetStatus(desired acktypes.AWSResource) { + r.ko.Status = desired.(*resource).ko.Status +} + +// SetIdentifiers sets the Spec or Status field that is referenced as the unique +// resource identifier +func (r *resource) SetIdentifiers(identifier *ackv1alpha1.AWSIdentifiers) error { + if identifier.NameOrID == "" { + return ackerrors.MissingNameIdentifier + } + r.ko.Spec.Name = &identifier.NameOrID + + f0, f0ok := identifier.AdditionalKeys["agentRuntimeID"] + if f0ok { + r.ko.Spec.AgentRuntimeID = aws.String(f0) + } + + return nil +} + +// PopulateResourceFromAnnotation populates the fields passed from adoption annotation +func (r *resource) PopulateResourceFromAnnotation(fields map[string]string) error { + primaryKey, ok := fields["name"] + if !ok { + return ackerrors.NewTerminalError(fmt.Errorf("required field missing: name")) + } + r.ko.Spec.Name = &primaryKey + f0, ok := fields["agentRuntimeID"] + if !ok { + return ackerrors.NewTerminalError(fmt.Errorf("required field missing: agentRuntimeID")) + } + r.ko.Spec.AgentRuntimeID = &f0 + + return nil +} + +// DeepCopy will return a copy of the resource +func (r *resource) DeepCopy() acktypes.AWSResource { + koCopy := r.ko.DeepCopy() + return &resource{koCopy} +} diff --git a/pkg/resource/agent_runtime_endpoint/sdk.go b/pkg/resource/agent_runtime_endpoint/sdk.go new file mode 100644 index 0000000..dcda388 --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/sdk.go @@ -0,0 +1,489 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime_endpoint + +import ( + "context" + "errors" + "fmt" + "reflect" + "strings" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log" + "github.com/aws/aws-sdk-go-v2/aws" + svcsdk "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol" + smithy "github.com/aws/smithy-go" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +// Hack to avoid import errors during build... +var ( + _ = &metav1.Time{} + _ = strings.ToLower("") + _ = &svcsdk.Client{} + _ = &svcapitypes.AgentRuntimeEndpoint{} + _ = ackv1alpha1.AWSAccountID("") + _ = &ackerr.NotFound + _ = &ackcondition.NotManagedMessage + _ = &reflect.Value{} + _ = fmt.Sprintf("") + _ = &ackrequeue.NoRequeue{} + _ = &aws.Config{} +) + +// sdkFind returns SDK-specific information about a supplied resource +func (rm *resourceManager) sdkFind( + ctx context.Context, + r *resource, +) (latest *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkFind") + defer func() { + exit(err) + }() + // If any required fields in the input shape are missing, AWS resource is + // not created yet. Return NotFound here to indicate to callers that the + // resource isn't yet created. + if rm.requiredFieldsMissingFromReadOneInput(r) { + return nil, ackerr.NotFound + } + + input, err := rm.newDescribeRequestPayload(r) + if err != nil { + return nil, err + } + + var resp *svcsdk.GetAgentRuntimeEndpointOutput + resp, err = rm.sdkapi.GetAgentRuntimeEndpoint(ctx, input) + rm.metrics.RecordAPICall("READ_ONE", "GetAgentRuntimeEndpoint", err) + if err != nil { + var awsErr smithy.APIError + if errors.As(err, &awsErr) && awsErr.ErrorCode() == "AccessDeniedException" { + return nil, ackerr.NotFound + } + return nil, err + } + + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := r.ko.DeepCopy() + + if resp.AgentRuntimeArn != nil { + ko.Status.AgentRuntimeARN = resp.AgentRuntimeArn + } else { + ko.Status.AgentRuntimeARN = nil + } + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if resp.AgentRuntimeEndpointArn != nil { + arn := ackv1alpha1.AWSResourceName(*resp.AgentRuntimeEndpointArn) + ko.Status.ACKResourceMetadata.ARN = &arn + } + if resp.CreatedAt != nil { + ko.Status.CreatedAt = &metav1.Time{*resp.CreatedAt} + } else { + ko.Status.CreatedAt = nil + } + if resp.Description != nil { + ko.Spec.Description = resp.Description + } else { + ko.Spec.Description = nil + } + if resp.Name != nil { + ko.Spec.Name = resp.Name + } else { + ko.Spec.Name = nil + } + if resp.Status != "" { + ko.Status.Status = aws.String(string(resp.Status)) + } else { + ko.Status.Status = nil + } + if resp.TargetVersion != nil { + ko.Status.TargetVersion = resp.TargetVersion + } else { + ko.Status.TargetVersion = nil + } + + rm.setStatusDefaults(ko) + if !agentRuntimeEndpointReady(&resource{ko}) { + return nil, requeueNotReady + } + return &resource{ko}, nil +} + +// requiredFieldsMissingFromReadOneInput returns true if there are any fields +// for the ReadOne Input shape that are required but not present in the +// resource's Spec or Status +func (rm *resourceManager) requiredFieldsMissingFromReadOneInput( + r *resource, +) bool { + return r.ko.Spec.AgentRuntimeID == nil || r.ko.Spec.Name == nil + +} + +// newDescribeRequestPayload returns SDK-specific struct for the HTTP request +// payload of the Describe API call for the resource +func (rm *resourceManager) newDescribeRequestPayload( + r *resource, +) (*svcsdk.GetAgentRuntimeEndpointInput, error) { + res := &svcsdk.GetAgentRuntimeEndpointInput{} + + if r.ko.Spec.AgentRuntimeID != nil { + res.AgentRuntimeId = r.ko.Spec.AgentRuntimeID + } + if r.ko.Spec.Name != nil { + res.EndpointName = r.ko.Spec.Name + } + + return res, nil +} + +// sdkCreate creates the supplied resource in the backend AWS service API and +// returns a copy of the resource with resource fields (in both Spec and +// Status) filled in with values from the CREATE API operation's Output shape. +func (rm *resourceManager) sdkCreate( + ctx context.Context, + desired *resource, +) (created *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkCreate") + defer func() { + exit(err) + }() + input, err := rm.newCreateRequestPayload(ctx, desired) + if err != nil { + return nil, err + } + + var resp *svcsdk.CreateAgentRuntimeEndpointOutput + _ = resp + resp, err = rm.sdkapi.CreateAgentRuntimeEndpoint(ctx, input) + rm.metrics.RecordAPICall("CREATE", "CreateAgentRuntimeEndpoint", err) + if err != nil { + return nil, err + } + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := desired.ko.DeepCopy() + + if resp.AgentRuntimeArn != nil { + ko.Status.AgentRuntimeARN = resp.AgentRuntimeArn + } else { + ko.Status.AgentRuntimeARN = nil + } + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if resp.AgentRuntimeEndpointArn != nil { + arn := ackv1alpha1.AWSResourceName(*resp.AgentRuntimeEndpointArn) + ko.Status.ACKResourceMetadata.ARN = &arn + } + if resp.CreatedAt != nil { + ko.Status.CreatedAt = &metav1.Time{*resp.CreatedAt} + } else { + ko.Status.CreatedAt = nil + } + if resp.Status != "" { + ko.Status.Status = aws.String(string(resp.Status)) + } else { + ko.Status.Status = nil + } + if resp.TargetVersion != nil { + ko.Status.TargetVersion = resp.TargetVersion + } else { + ko.Status.TargetVersion = nil + } + + rm.setStatusDefaults(ko) + return &resource{ko}, nil +} + +// newCreateRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Create API call for the resource +func (rm *resourceManager) newCreateRequestPayload( + ctx context.Context, + r *resource, +) (*svcsdk.CreateAgentRuntimeEndpointInput, error) { + res := &svcsdk.CreateAgentRuntimeEndpointInput{} + + if r.ko.Spec.AgentRuntimeID != nil { + res.AgentRuntimeId = r.ko.Spec.AgentRuntimeID + } + if r.ko.Spec.AgentRuntimeVersion != nil { + res.AgentRuntimeVersion = r.ko.Spec.AgentRuntimeVersion + } + if r.ko.Spec.Description != nil { + res.Description = r.ko.Spec.Description + } + if r.ko.Spec.Name != nil { + res.Name = r.ko.Spec.Name + } + if r.ko.Spec.Tags != nil { + res.Tags = aws.ToStringMap(r.ko.Spec.Tags) + } + + return res, nil +} + +// sdkUpdate patches the supplied resource in the backend AWS service API and +// returns a new resource with updated fields. +func (rm *resourceManager) sdkUpdate( + ctx context.Context, + desired *resource, + latest *resource, + delta *ackcompare.Delta, +) (updated *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkUpdate") + defer func() { + exit(err) + }() + if delta.DifferentAt("Spec.Tags") { + err := syncTags( + ctx, rm.sdkapi, rm.metrics, + string(*latest.ko.Status.ACKResourceMetadata.ARN), + aws.ToStringMap(desired.ko.Spec.Tags), aws.ToStringMap(latest.ko.Spec.Tags), + ) + if err != nil { + return nil, err + } + } + if !delta.DifferentExcept("Spec.Tags") { + return desired, nil + } + if !agentRuntimeEndpointReady(latest) { + return latest, requeueNotReady + } + input, err := rm.newUpdateRequestPayload(ctx, desired, delta) + if err != nil { + return nil, err + } + + var resp *svcsdk.UpdateAgentRuntimeEndpointOutput + _ = resp + resp, err = rm.sdkapi.UpdateAgentRuntimeEndpoint(ctx, input) + rm.metrics.RecordAPICall("UPDATE", "UpdateAgentRuntimeEndpoint", err) + if err != nil { + return nil, err + } + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := desired.ko.DeepCopy() + + if resp.AgentRuntimeArn != nil { + ko.Status.AgentRuntimeARN = resp.AgentRuntimeArn + } else { + ko.Status.AgentRuntimeARN = nil + } + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if resp.AgentRuntimeEndpointArn != nil { + arn := ackv1alpha1.AWSResourceName(*resp.AgentRuntimeEndpointArn) + ko.Status.ACKResourceMetadata.ARN = &arn + } + if resp.CreatedAt != nil { + ko.Status.CreatedAt = &metav1.Time{*resp.CreatedAt} + } else { + ko.Status.CreatedAt = nil + } + if resp.Status != "" { + ko.Status.Status = aws.String(string(resp.Status)) + } else { + ko.Status.Status = nil + } + if resp.TargetVersion != nil { + ko.Status.TargetVersion = resp.TargetVersion + } else { + ko.Status.TargetVersion = nil + } + + rm.setStatusDefaults(ko) + return &resource{ko}, nil +} + +// newUpdateRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Update API call for the resource +func (rm *resourceManager) newUpdateRequestPayload( + ctx context.Context, + r *resource, + delta *ackcompare.Delta, +) (*svcsdk.UpdateAgentRuntimeEndpointInput, error) { + res := &svcsdk.UpdateAgentRuntimeEndpointInput{} + + if r.ko.Spec.AgentRuntimeID != nil { + res.AgentRuntimeId = r.ko.Spec.AgentRuntimeID + } + if r.ko.Spec.AgentRuntimeVersion != nil { + res.AgentRuntimeVersion = r.ko.Spec.AgentRuntimeVersion + } + if r.ko.Spec.Description != nil { + res.Description = r.ko.Spec.Description + } + + return res, nil +} + +// sdkDelete deletes the supplied resource in the backend AWS service API +func (rm *resourceManager) sdkDelete( + ctx context.Context, + r *resource, +) (latest *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkDelete") + defer func() { + exit(err) + }() + input, err := rm.newDeleteRequestPayload(r) + if err != nil { + return nil, err + } + var resp *svcsdk.DeleteAgentRuntimeEndpointOutput + _ = resp + resp, err = rm.sdkapi.DeleteAgentRuntimeEndpoint(ctx, input) + rm.metrics.RecordAPICall("DELETE", "DeleteAgentRuntimeEndpoint", err) + return nil, err +} + +// newDeleteRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Delete API call for the resource +func (rm *resourceManager) newDeleteRequestPayload( + r *resource, +) (*svcsdk.DeleteAgentRuntimeEndpointInput, error) { + res := &svcsdk.DeleteAgentRuntimeEndpointInput{} + + if r.ko.Spec.AgentRuntimeID != nil { + res.AgentRuntimeId = r.ko.Spec.AgentRuntimeID + } + if r.ko.Spec.Name != nil { + res.EndpointName = r.ko.Spec.Name + } + + return res, nil +} + +// setStatusDefaults sets default properties into supplied custom resource +func (rm *resourceManager) setStatusDefaults( + ko *svcapitypes.AgentRuntimeEndpoint, +) { + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if ko.Status.ACKResourceMetadata.Region == nil { + ko.Status.ACKResourceMetadata.Region = &rm.awsRegion + } + if ko.Status.ACKResourceMetadata.OwnerAccountID == nil { + ko.Status.ACKResourceMetadata.OwnerAccountID = &rm.awsAccountID + } + if ko.Status.Conditions == nil { + ko.Status.Conditions = []*ackv1alpha1.Condition{} + } +} + +// updateConditions returns updated resource, true; if conditions were updated +// else it returns nil, false +func (rm *resourceManager) updateConditions( + r *resource, + onSuccess bool, + err error, +) (*resource, bool) { + ko := r.ko.DeepCopy() + rm.setStatusDefaults(ko) + + // Terminal condition + var terminalCondition *ackv1alpha1.Condition = nil + var recoverableCondition *ackv1alpha1.Condition = nil + var syncCondition *ackv1alpha1.Condition = nil + for _, condition := range ko.Status.Conditions { + if condition.Type == ackv1alpha1.ConditionTypeTerminal { + terminalCondition = condition + } + if condition.Type == ackv1alpha1.ConditionTypeRecoverable { + recoverableCondition = condition + } + if condition.Type == ackv1alpha1.ConditionTypeResourceSynced { + syncCondition = condition + } + } + var termError *ackerr.TerminalError + if rm.terminalAWSError(err) || err == ackerr.SecretTypeNotSupported || err == ackerr.SecretNotFound || errors.As(err, &termError) { + if terminalCondition == nil { + terminalCondition = &ackv1alpha1.Condition{ + Type: ackv1alpha1.ConditionTypeTerminal, + } + ko.Status.Conditions = append(ko.Status.Conditions, terminalCondition) + } + var errorMessage = "" + if err == ackerr.SecretTypeNotSupported || err == ackerr.SecretNotFound || errors.As(err, &termError) { + errorMessage = err.Error() + } else { + awsErr, _ := ackerr.AWSError(err) + errorMessage = awsErr.Error() + } + terminalCondition.Status = corev1.ConditionTrue + terminalCondition.Message = &errorMessage + } else { + // Clear the terminal condition if no longer present + if terminalCondition != nil { + terminalCondition.Status = corev1.ConditionFalse + terminalCondition.Message = nil + } + // Handling Recoverable Conditions + if err != nil { + if recoverableCondition == nil { + // Add a new Condition containing a non-terminal error + recoverableCondition = &ackv1alpha1.Condition{ + Type: ackv1alpha1.ConditionTypeRecoverable, + } + ko.Status.Conditions = append(ko.Status.Conditions, recoverableCondition) + } + recoverableCondition.Status = corev1.ConditionTrue + awsErr, _ := ackerr.AWSError(err) + errorMessage := err.Error() + if awsErr != nil { + errorMessage = awsErr.Error() + } + recoverableCondition.Message = &errorMessage + } else if recoverableCondition != nil { + recoverableCondition.Status = corev1.ConditionFalse + recoverableCondition.Message = nil + } + } + // Required to avoid the "declared but not used" error in the default case + _ = syncCondition + if terminalCondition != nil || recoverableCondition != nil || syncCondition != nil { + return &resource{ko}, true // updated + } + return nil, false // not updated +} + +// terminalAWSError returns awserr, true; if the supplied error is an aws Error type +// and if the exception indicates that it is a Terminal exception +// 'Terminal' exception are specified in generator configuration +func (rm *resourceManager) terminalAWSError(err error) bool { + // No terminal_errors specified for this resource in generator config + return false +} diff --git a/pkg/resource/agent_runtime_endpoint/tags.go b/pkg/resource/agent_runtime_endpoint/tags.go new file mode 100644 index 0000000..89e9892 --- /dev/null +++ b/pkg/resource/agent_runtime_endpoint/tags.go @@ -0,0 +1,108 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package agent_runtime_endpoint + +import ( + "slices" + "strings" + + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" + + svcapitypes "github.com/aws-controllers-k8s/bedrockagentcorecontrol-controller/apis/v1alpha1" +) + +var ( + _ = svcapitypes.AgentRuntimeEndpoint{} + _ = acktags.NewTags() + ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} +) + +// convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. +// This method helps in creating the hub(acktags.Tags) for merging +// default controller tags with existing resource tags. It also returns a slice +// of keys maintaining the original key Order when the tags are a list +func convertToOrderedACKTags(tags map[string]*string) (acktags.Tags, []string) { + result := acktags.NewTags() + keyOrder := []string{} + + if len(tags) == 0 { + return result, keyOrder + } + for k, v := range tags { + if v == nil { + result[k] = "" + } else { + result[k] = *v + } + } + + return result, keyOrder +} + +// fromACKTags converts the tags parameter into map[string]*string shape. +// This method helps in setting the tags back inside AWSResource after merging +// default controller tags with existing resource tags. When a list, +// it maintains the order from original +func fromACKTags(tags acktags.Tags, keyOrder []string) map[string]*string { + result := map[string]*string{} + + _ = keyOrder + for k, v := range tags { + result[k] = &v + } + + return result +} + +// ignoreSystemTags ignores tags that have keys that start with "aws:" +// and ACKSystemTags, to avoid patching them to the resourceSpec. +// Eg. resources created with cloudformation have tags that cannot be +// removed by an ACK controller +func ignoreSystemTags(tags acktags.Tags) { + for k := range tags { + if strings.HasPrefix(k, "aws:") || + slices.Contains(ACKSystemTags, k) { + delete(tags, k) + } + } +} + +// syncAWSTags ensures AWS-managed tags (prefixed with "aws:") from the latest resource state +// are preserved in the desired state. This prevents the controller from attempting to +// modify AWS-managed tags, which would result in an error. +// +// AWS-managed tags are automatically added by AWS services (e.g., CloudFormation, Service Catalog) +// and cannot be modified or deleted through normal tag operations. Common examples include: +// - aws:cloudformation:stack-name +// - aws:servicecatalog:productArn +// +// Parameters: +// - a: The target Tags map to be updated (typically desired state) +// - b: The source Tags map containing AWS-managed tags (typically latest state) +// +// Example: +// +// latest := Tags{"aws:cloudformation:stack-name": "my-stack", "environment": "prod"} +// desired := Tags{"environment": "dev"} +// SyncAWSTags(desired, latest) +// desired now contains {"aws:cloudformation:stack-name": "my-stack", "environment": "dev"} +func syncAWSTags(a acktags.Tags, b acktags.Tags) { + for k := range b { + if strings.HasPrefix(k, "aws:") { + a[k] = b[k] + } + } +} diff --git a/pkg/tags/sync.go b/pkg/tags/sync.go new file mode 100644 index 0000000..90636dc --- /dev/null +++ b/pkg/tags/sync.go @@ -0,0 +1,158 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +package tags + +import ( + "context" + + ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log" + + svcsdk "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol" +) + +// Ideally, a part of this code needs to be generated, the other part +// needs to be implemented in a different repository (runtime or pkg). +// +// Few things to node: +// - Some AWS APIs support map[string]string for tags, while others support []*Tag. +// - Some AWS APIs have a limit on the number of tags that can be associated with a resource. +// - We can call a few different names and ways to tag and untag resources. +// - Some allow to add/remove one tag at a time, while others allow to add/remove multiple tags at once. +// - Some have a seperate API to list tags, while others return tags as part of the describe response. +// - Even when the API model states that a Describe response will contain tags, the actual response may +// not contain any tags. And users are expected to call a seperate ListTags API to get the tags. +// +// - Noting a few diffrent API names: +// - TagResource, UntagResource, ListTagsForResource +// - CreateTags, DeleteTags, ListTags +// - AddTags, RemoveTags, ListTags + +// Below are some abstractions that can be used to abstract the implementation details +// of tagging and untagging resources. + +type metricsRecorder interface { + RecordAPICall(opType string, opID string, err error) +} + +type tagsClient interface { + TagResource(context.Context, *svcsdk.TagResourceInput, ...func(*svcsdk.Options)) (*svcsdk.TagResourceOutput, error) + ListTagsForResource(context.Context, *svcsdk.ListTagsForResourceInput, ...func(*svcsdk.Options)) (*svcsdk.ListTagsForResourceOutput, error) + UntagResource(context.Context, *svcsdk.UntagResourceInput, ...func(*svcsdk.Options)) (*svcsdk.UntagResourceOutput, error) +} + +// syncTags examines the Tags in the supplied Resource and calls the +// TagResource and UntagResource APIs to ensure that the set of +// associated Tags stays in sync with the Resource.Spec.Tags +func SyncTags( + ctx context.Context, + client tagsClient, + mr metricsRecorder, + resourceARN string, + desiredTags map[string]string, + existingTags map[string]string, +) (err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.syncTags") + defer func() { exit(err) }() + + toAdd := map[string]string{} + toDelete := []string{} + + for k, v := range desiredTags { + if ev, found := existingTags[k]; !found || ev != v { + toAdd[k] = v + } + } + + for k, _ := range existingTags { + if _, found := desiredTags[k]; !found { + deleteKey := k + toDelete = append(toDelete, deleteKey) + } + } + + if len(toAdd) > 0 { + for k, v := range toAdd { + rlog.Debug("adding tag to resource", "key", k, "value", v) + } + if err = addTags( + ctx, + client, + mr, + resourceARN, + toAdd, + ); err != nil { + return err + } + } + if len(toDelete) > 0 { + for _, k := range toDelete { + rlog.Debug("removing tag from resource", "key", k) + } + if err = removeTags( + ctx, + client, + mr, + resourceARN, + toDelete, + ); err != nil { + return err + } + } + + return nil +} + +// addTags adds the supplied Tags to the supplied resource +func addTags( + ctx context.Context, + client tagsClient, + mr metricsRecorder, + resourceARN string, + tags map[string]string, +) (err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.addTag") + defer func() { exit(err) }() + + input := &svcsdk.TagResourceInput{ + ResourceArn: &resourceARN, + Tags: tags, + } + + _, err = client.TagResource(ctx, input) + mr.RecordAPICall("UPDATE", "TagResource", err) + return err +} + +// removeTags removes the supplied Tags from the supplied resource +func removeTags( + ctx context.Context, + client tagsClient, + mr metricsRecorder, + resourceARN string, + tagKeys []string, // the set of tag keys to delete +) (err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.removeTag") + defer func() { exit(err) }() + + input := &svcsdk.UntagResourceInput{ + ResourceArn: &resourceARN, + TagKeys: tagKeys, + } + _, err = client.UntagResource(ctx, input) + mr.RecordAPICall("UPDATE", "UntagResource", err) + return err +} diff --git a/templates/hooks/agentruntime/sdk_read_one_post_set_output.go.tpl b/templates/hooks/agentruntime/sdk_read_one_post_set_output.go.tpl new file mode 100644 index 0000000..8eb6ce1 --- /dev/null +++ b/templates/hooks/agentruntime/sdk_read_one_post_set_output.go.tpl @@ -0,0 +1,3 @@ + if !agentRuntimeReady(&resource{ko}) { + return nil, requeueNotReady + } \ No newline at end of file diff --git a/templates/hooks/agentruntime/sdk_update_pre_build_request.go.tpl b/templates/hooks/agentruntime/sdk_update_pre_build_request.go.tpl new file mode 100644 index 0000000..5fa3637 --- /dev/null +++ b/templates/hooks/agentruntime/sdk_update_pre_build_request.go.tpl @@ -0,0 +1,16 @@ + if delta.DifferentAt("Spec.Tags") { + err := syncTags( + ctx, rm.sdkapi, rm.metrics, + string(*latest.ko.Status.ACKResourceMetadata.ARN), + aws.ToStringMap(desired.ko.Spec.Tags), aws.ToStringMap(latest.ko.Spec.Tags), + ) + if err != nil { + return nil, err + } + } + if !delta.DifferentExcept("Spec.Tags"){ + return desired, nil + } + if !agentRuntimeReady(latest) { + return latest, requeueNotReady + } \ No newline at end of file diff --git a/templates/hooks/agentruntimeendpoint/sdk_read_one_post_set_output.go.tpl b/templates/hooks/agentruntimeendpoint/sdk_read_one_post_set_output.go.tpl new file mode 100644 index 0000000..125c169 --- /dev/null +++ b/templates/hooks/agentruntimeendpoint/sdk_read_one_post_set_output.go.tpl @@ -0,0 +1,3 @@ + if !agentRuntimeEndpointReady(&resource{ko}) { + return nil, requeueNotReady + } \ No newline at end of file diff --git a/templates/hooks/agentruntimeendpoint/sdk_update_pre_build_request.go.tpl b/templates/hooks/agentruntimeendpoint/sdk_update_pre_build_request.go.tpl new file mode 100644 index 0000000..7c78fa4 --- /dev/null +++ b/templates/hooks/agentruntimeendpoint/sdk_update_pre_build_request.go.tpl @@ -0,0 +1,16 @@ + if delta.DifferentAt("Spec.Tags") { + err := syncTags( + ctx, rm.sdkapi, rm.metrics, + string(*latest.ko.Status.ACKResourceMetadata.ARN), + aws.ToStringMap(desired.ko.Spec.Tags), aws.ToStringMap(latest.ko.Spec.Tags), + ) + if err != nil { + return nil, err + } + } + if !delta.DifferentExcept("Spec.Tags"){ + return desired, nil + } + if !agentRuntimeEndpointReady(latest) { + return latest, requeueNotReady + } \ No newline at end of file diff --git a/test/e2e/bootstrap_resources.py b/test/e2e/bootstrap_resources.py index 450a769..550ab6b 100644 --- a/test/e2e/bootstrap_resources.py +++ b/test/e2e/bootstrap_resources.py @@ -18,6 +18,7 @@ from dataclasses import dataclass from acktest.bootstrapping import Resources from e2e import bootstrap_directory +from acktest.bootstrapping.iam import Role @dataclass class BootstrapResources(Resources): diff --git a/test/e2e/requirements.txt b/test/e2e/requirements.txt index 3108f42..977ea2c 100644 --- a/test/e2e/requirements.txt +++ b/test/e2e/requirements.txt @@ -1 +1 @@ -acktest @ git+https://github.com/aws-controllers-k8s/test-infra.git@1447a1d39a79afa23f48e2a5d8b30ecd248ee05b +acktest @ git+https://github.com/aws-controllers-k8s/test-infra.git@822602ef1948e8e332a8dc835c479ca9d89a6f53 diff --git a/test/e2e/resources/agent_runtime.yaml b/test/e2e/resources/agent_runtime.yaml new file mode 100644 index 0000000..ed5294f --- /dev/null +++ b/test/e2e/resources/agent_runtime.yaml @@ -0,0 +1,13 @@ +apiVersion: bedrockagentcorecontrol.services.k8s.aws/v1alpha1 +kind: AgentRuntime +metadata: + name: $AGENT_RUNTIME_NAME + namespace: default +spec: + agentRuntimeName: $AGENT_RUNTIME_NAME + roleARN: $ROLE_ARN + agentRuntimeArtifact: + containerConfiguration: + containerURI: $CONTAINER_URI + networkConfiguration: + networkMode: PUBLIC diff --git a/test/e2e/resources/agent_runtime_endpoint.yaml b/test/e2e/resources/agent_runtime_endpoint.yaml new file mode 100644 index 0000000..c19485e --- /dev/null +++ b/test/e2e/resources/agent_runtime_endpoint.yaml @@ -0,0 +1,8 @@ +apiVersion: bedrockagentcorecontrol.services.k8s.aws/v1alpha1 +kind: AgentRuntimeEndpoint +metadata: + name: $ENDPOINT_NAME + namespace: default +spec: + agentRuntimeID: $AGENT_RUNTIME_ID + name: $ENDPOINT_NAME diff --git a/test/e2e/service_bootstrap.py b/test/e2e/service_bootstrap.py index d51b7da..262f6eb 100644 --- a/test/e2e/service_bootstrap.py +++ b/test/e2e/service_bootstrap.py @@ -4,36 +4,40 @@ # not use this file except in compliance with the License. A copy of the # License is located at # -# http://aws.amazon.com/apache2.0/ +# http://aws.amazon.com/apache2.0/ # # or in the "license" file accompanying this file. This file is distributed # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either # express or implied. See the License for the specific language governing # permissions and limitations under the License. + """Bootstraps the resources required to run the Bedrock Agent Core Control integration tests. """ -import logging +import logging +import os from acktest.bootstrapping import Resources, BootstrapFailureException - +from acktest.bootstrapping.iam import Role from e2e import bootstrap_directory from e2e.bootstrap_resources import BootstrapResources + + def service_bootstrap() -> Resources: logging.getLogger().setLevel(logging.INFO) - + resources = BootstrapResources( - # TODO: Add bootstrapping when you have defined the resources ) - + try: resources.bootstrap() except BootstrapFailureException as ex: exit(254) - + return resources + if __name__ == "__main__": config = service_bootstrap() # Write config to current directory by default - config.serialize(bootstrap_directory) + config.serialize(bootstrap_directory) \ No newline at end of file diff --git a/test/e2e/tests/test_agent_runtime.py b/test/e2e/tests/test_agent_runtime.py new file mode 100644 index 0000000..691d205 --- /dev/null +++ b/test/e2e/tests/test_agent_runtime.py @@ -0,0 +1,81 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may +# not use this file except in compliance with the License. A copy of the +# License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +"""Integration tests for Agent Runtime API. +""" + +import pytest + +from acktest.k8s import condition +from acktest.k8s import resource as k8s +from acktest.resources import random_suffix_name +from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_bedrockagentcorecontrol_resource +from e2e.replacement_values import REPLACEMENT_VALUES +from e2e.bootstrap_resources import get_bootstrap_resources + +AGENT_RUNTIME_RESOURCE_PLURAL = "agentruntimes" + + +@pytest.fixture(scope="module") +def simple_agent_runtime(): + runtime_name = random_suffix_name("acktestagentruntime", 32, delimiter="") + + resources = get_bootstrap_resources() + + replacements = REPLACEMENT_VALUES.copy() + replacements["AGENT_RUNTIME_NAME"] = runtime_name + replacements["ROLE_ARN"] = "arn:aws:iam::951637587566:role/ack-bedrock-test-role" + replacements["CONTAINER_URI"] = "951637587566.dkr.ecr.us-west-2.amazonaws.com/bedrock-agentcore-test:test" + + resource_data = load_bedrockagentcorecontrol_resource( + "agent_runtime", + additional_replacements=replacements, + ) + + ref = k8s.CustomResourceReference( + CRD_GROUP, + CRD_VERSION, + AGENT_RUNTIME_RESOURCE_PLURAL, + runtime_name, + namespace="default", + ) + + k8s.create_custom_resource(ref, resource_data) + cr = k8s.wait_resource_consumed_by_controller(ref) + + yield (ref, cr) + + try: + _, deleted = k8s.delete_custom_resource(ref, wait_periods=3, period_length=10) + assert deleted + except: + pass + + +@service_marker +@pytest.mark.canary +class TestAgentRuntime: + def test_create_delete_agent_runtime(self, simple_agent_runtime, bedrockagentcorecontrol_client): + (ref, cr) = simple_agent_runtime + + k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=10) + condition.assert_synced(ref) + + cr = k8s.get_resource(ref) + agent_runtime_id = cr["status"]["agentRuntimeID"] + assert agent_runtime_id is not None + + aws_runtime = bedrockagentcorecontrol_client.get_agent_runtime( + agentRuntimeId=agent_runtime_id + ) + assert aws_runtime["agentRuntimeId"] == agent_runtime_id \ No newline at end of file diff --git a/test/e2e/tests/test_agent_runtime_endpoint.py b/test/e2e/tests/test_agent_runtime_endpoint.py new file mode 100644 index 0000000..60908ac --- /dev/null +++ b/test/e2e/tests/test_agent_runtime_endpoint.py @@ -0,0 +1,90 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may +# not use this file except in compliance with the License. A copy of the +# License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +"""Integration tests for Agent Runtime Endpoint API. +""" + +import pytest +from acktest.k8s import condition +from acktest.k8s import resource as k8s +from acktest.resources import random_suffix_name +from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_bedrockagentcorecontrol_resource +from e2e.replacement_values import REPLACEMENT_VALUES + +from .test_agent_runtime import simple_agent_runtime + +AGENT_RUNTIME_ENDPOINT_RESOURCE_PLURAL = "agentruntimeendpoints" + + +@pytest.fixture(scope="module") +def simple_agent_runtime_endpoint(simple_agent_runtime): + (runtime_ref, runtime_cr) = simple_agent_runtime + + # Wait for runtime to be synced + k8s.wait_on_condition(runtime_ref, "ACK.ResourceSynced", "True", wait_periods=10) + + # Get the latest CR to ensure we have the agentRuntimeID in status + runtime_cr = k8s.get_resource(runtime_ref) + agent_runtime_id = runtime_cr["status"]["agentRuntimeID"] + endpoint_name = random_suffix_name("acktestendpoint", 32, delimiter="") + + replacements = REPLACEMENT_VALUES.copy() + replacements["AGENT_RUNTIME_ID"] = agent_runtime_id + replacements["ENDPOINT_NAME"] = endpoint_name + + resource_data = load_bedrockagentcorecontrol_resource( + "agent_runtime_endpoint", + additional_replacements=replacements, + ) + + ref = k8s.CustomResourceReference( + CRD_GROUP, + CRD_VERSION, + AGENT_RUNTIME_ENDPOINT_RESOURCE_PLURAL, + endpoint_name, + namespace="default", + ) + + k8s.create_custom_resource(ref, resource_data) + cr = k8s.wait_resource_consumed_by_controller(ref) + + yield (ref, cr) + + try: + _, deleted = k8s.delete_custom_resource(ref, wait_periods=3, period_length=10) + assert deleted + except: + pass + + +@service_marker +@pytest.mark.canary +class TestAgentRuntimeEndpoint: + def test_create_delete_agent_runtime_endpoint(self, simple_agent_runtime_endpoint, bedrockagentcorecontrol_client): + (ref, cr) = simple_agent_runtime_endpoint + + k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=10) + condition.assert_synced(ref) + + cr = k8s.get_resource(ref) + agent_runtime_endpoint_arn = cr["status"]["ackResourceMetadata"]["arn"] + assert agent_runtime_endpoint_arn is not None + + agent_runtime_id = cr["spec"]["agentRuntimeID"] + endpoint_name = cr["spec"]["name"] + + aws_endpoint = bedrockagentcorecontrol_client.get_agent_runtime_endpoint( + agentRuntimeId=agent_runtime_id, + endpointName=endpoint_name + ) + assert aws_endpoint["agentRuntimeEndpointArn"] is not None \ No newline at end of file