diff --git a/hive/gateway/ec2/image/CopyImage.go b/hive/gateway/ec2/image/CopyImage.go index 6581971b9..a6efd6eb4 100644 --- a/hive/gateway/ec2/image/CopyImage.go +++ b/hive/gateway/ec2/image/CopyImage.go @@ -1,16 +1,14 @@ package gateway_ec2_image import ( - "bytes" "encoding/json" "errors" "fmt" "log/slog" "strings" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/mulgadc/hive/hive/utils" ) @@ -120,8 +118,9 @@ func CopyImage(input *ec2.CopyImageInput) (output ec2.CopyImageOutput, err error return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_CopyImage(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_image.NewCopyImageHandler(handlers_ec2_image.NewMockImageService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -142,39 +141,3 @@ func CopyImage(input *ec2.CopyImageInput) (output ec2.CopyImageOutput, err error return output, nil } - -func EC2_Process_CopyImage(jsonData []byte) (output []byte) { - - var input ec2.CopyImageInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateCopyImageInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually copy the image. - // This is a placeholder response for testing the framework. - - result := &ec2.CopyImageOutput{ - ImageId: aws.String("ami-0987654321fedcba0"), - } - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_CopyImage could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/image/CreateImage.go b/hive/gateway/ec2/image/CreateImage.go index 0ff95abb3..57336b66b 100644 --- a/hive/gateway/ec2/image/CreateImage.go +++ b/hive/gateway/ec2/image/CreateImage.go @@ -1,16 +1,14 @@ package gateway_ec2_image import ( - "bytes" "encoding/json" "errors" "fmt" "log/slog" "strings" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/mulgadc/hive/hive/utils" ) @@ -119,8 +117,9 @@ func CreateImage(input *ec2.CreateImageInput) (output ec2.CreateImageOutput, err return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_CreateImage(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_image.NewCreateImageHandler(handlers_ec2_image.NewMockImageService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -141,39 +140,3 @@ func CreateImage(input *ec2.CreateImageInput) (output ec2.CreateImageOutput, err return output, nil } - -func EC2_Process_CreateImage(jsonData []byte) (output []byte) { - - var input ec2.CreateImageInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateCreateImageInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually create the image from the instance. - // This is a placeholder response for testing the framework. - - result := &ec2.CreateImageOutput{ - ImageId: aws.String("ami-0123456789abcdef0"), - } - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_CreateImage could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/image/CreateImage_test.go b/hive/gateway/ec2/image/CreateImage_test.go index 7b3728cb3..76056940d 100644 --- a/hive/gateway/ec2/image/CreateImage_test.go +++ b/hive/gateway/ec2/image/CreateImage_test.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/mulgadc/hive/hive/utils" "github.com/stretchr/testify/assert" ) @@ -90,7 +91,7 @@ func TestEC2ProcessCreateImage(t *testing.T) { Name: aws.String("test-image"), }, wantValidationErr: true, - wantErrCode: "ValidationError", + wantErrCode: "MissingParameter", }, { name: "ValidCreateImage", @@ -117,7 +118,8 @@ func TestEC2ProcessCreateImage(t *testing.T) { assert.NoError(t, err) } - jsonResp := EC2_Process_CreateImage(jsonData) + handler := handlers_ec2_image.NewCreateImageHandler(handlers_ec2_image.NewMockImageService()) + jsonResp := handler.Process(jsonData) responseError, err := utils.ValidateErrorPayload(jsonResp) if tt.wantValidationErr { diff --git a/hive/gateway/ec2/image/DeregisterImage.go b/hive/gateway/ec2/image/DeregisterImage.go index cc77637f5..c6d1cc873 100644 --- a/hive/gateway/ec2/image/DeregisterImage.go +++ b/hive/gateway/ec2/image/DeregisterImage.go @@ -1,7 +1,6 @@ package gateway_ec2_image import ( - "bytes" "encoding/json" "errors" "fmt" @@ -9,7 +8,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/mulgadc/hive/hive/utils" ) @@ -74,8 +73,9 @@ func DeregisterImage(input *ec2.DeregisterImageInput) (output ec2.DeregisterImag return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_DeregisterImage(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_image.NewDeregisterImageHandler(handlers_ec2_image.NewMockImageService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -96,39 +96,3 @@ func DeregisterImage(input *ec2.DeregisterImageInput) (output ec2.DeregisterImag return output, nil } - -func EC2_Process_DeregisterImage(jsonData []byte) (output []byte) { - - var input ec2.DeregisterImageInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateDeregisterImageInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually deregister the image. - // This is a placeholder response for testing the framework. - - // DeregisterImageOutput has no exported fields, so we return a simple success indicator - // to distinguish from error responses - result := map[string]bool{"Return": true} - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_DeregisterImage could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/image/DescribeImageAttribute.go b/hive/gateway/ec2/image/DescribeImageAttribute.go index bcf2102e6..5819e41f4 100644 --- a/hive/gateway/ec2/image/DescribeImageAttribute.go +++ b/hive/gateway/ec2/image/DescribeImageAttribute.go @@ -1,16 +1,14 @@ package gateway_ec2_image import ( - "bytes" "encoding/json" "errors" "fmt" "log/slog" "strings" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/mulgadc/hive/hive/utils" ) @@ -119,8 +117,9 @@ func DescribeImageAttribute(input *ec2.DescribeImageAttributeInput) (output ec2. return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_DescribeImageAttribute(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_image.NewDescribeImageAttributeHandler(handlers_ec2_image.NewMockImageService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -141,42 +140,3 @@ func DescribeImageAttribute(input *ec2.DescribeImageAttributeInput) (output ec2. return output, nil } - -func EC2_Process_DescribeImageAttribute(jsonData []byte) (output []byte) { - - var input ec2.DescribeImageAttributeInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateDescribeImageAttributeInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually describe image attributes. - // This is a placeholder response for testing the framework. - - result := &ec2.DescribeImageAttributeOutput{ - ImageId: input.ImageId, - Description: &ec2.AttributeValue{ - Value: aws.String("Test image description"), - }, - } - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_DescribeImageAttribute could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/image/DescribeImages.go b/hive/gateway/ec2/image/DescribeImages.go index cf9fe57da..8d544a3f6 100644 --- a/hive/gateway/ec2/image/DescribeImages.go +++ b/hive/gateway/ec2/image/DescribeImages.go @@ -1,16 +1,14 @@ package gateway_ec2_image import ( - "bytes" "encoding/json" "errors" "fmt" "log/slog" "strings" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/mulgadc/hive/hive/utils" ) @@ -108,8 +106,9 @@ func DescribeImages(input *ec2.DescribeImagesInput) (output ec2.DescribeImagesOu return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_DescribeImages(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_image.NewDescribeImagesHandler(handlers_ec2_image.NewMockImageService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -130,49 +129,3 @@ func DescribeImages(input *ec2.DescribeImagesInput) (output ec2.DescribeImagesOu return output, nil } - -func EC2_Process_DescribeImages(jsonData []byte) (output []byte) { - - var input ec2.DescribeImagesInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateDescribeImagesInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually query images from the system. - // This is a placeholder response for testing the framework. - - result := &ec2.DescribeImagesOutput{ - Images: []*ec2.Image{ - { - ImageId: aws.String("ami-0123456789abcdef0"), - Name: aws.String("test-image"), - State: aws.String("available"), - Architecture: aws.String("x86_64"), - ImageType: aws.String("machine"), - OwnerId: aws.String("123456789012"), - Public: aws.Bool(false), - }, - }, - } - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_DescribeImages could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/image/ModifyImageAttribute.go b/hive/gateway/ec2/image/ModifyImageAttribute.go index ee9b7d936..9508a7456 100644 --- a/hive/gateway/ec2/image/ModifyImageAttribute.go +++ b/hive/gateway/ec2/image/ModifyImageAttribute.go @@ -1,7 +1,6 @@ package gateway_ec2_image import ( - "bytes" "encoding/json" "errors" "fmt" @@ -9,7 +8,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/mulgadc/hive/hive/utils" ) @@ -100,8 +99,9 @@ func ModifyImageAttribute(input *ec2.ModifyImageAttributeInput) (output ec2.Modi return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_ModifyImageAttribute(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_image.NewModifyImageAttributeHandler(handlers_ec2_image.NewMockImageService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -122,39 +122,3 @@ func ModifyImageAttribute(input *ec2.ModifyImageAttributeInput) (output ec2.Modi return output, nil } - -func EC2_Process_ModifyImageAttribute(jsonData []byte) (output []byte) { - - var input ec2.ModifyImageAttributeInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateModifyImageAttributeInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually modify image attributes. - // This is a placeholder response for testing the framework. - - // ModifyImageAttributeOutput has no exported fields, so we return a simple success indicator - // to distinguish from error responses - result := map[string]bool{"Return": true} - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_ModifyImageAttribute could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/image/RegisterImage.go b/hive/gateway/ec2/image/RegisterImage.go index d1fd25340..58324623d 100644 --- a/hive/gateway/ec2/image/RegisterImage.go +++ b/hive/gateway/ec2/image/RegisterImage.go @@ -1,15 +1,13 @@ package gateway_ec2_image import ( - "bytes" "encoding/json" "errors" "fmt" "log/slog" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/mulgadc/hive/hive/utils" ) @@ -139,8 +137,9 @@ func RegisterImage(input *ec2.RegisterImageInput) (output ec2.RegisterImageOutpu return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_RegisterImage(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_image.NewRegisterImageHandler(handlers_ec2_image.NewMockImageService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -161,39 +160,3 @@ func RegisterImage(input *ec2.RegisterImageInput) (output ec2.RegisterImageOutpu return output, nil } - -func EC2_Process_RegisterImage(jsonData []byte) (output []byte) { - - var input ec2.RegisterImageInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateRegisterImageInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually register the image. - // This is a placeholder response for testing the framework. - - result := &ec2.RegisterImageOutput{ - ImageId: aws.String("ami-0123456789abcdef0"), - } - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_RegisterImage could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/image/ResetImageAttribute.go b/hive/gateway/ec2/image/ResetImageAttribute.go index 3a4ab2f9f..fcd90e3f9 100644 --- a/hive/gateway/ec2/image/ResetImageAttribute.go +++ b/hive/gateway/ec2/image/ResetImageAttribute.go @@ -1,7 +1,6 @@ package gateway_ec2_image import ( - "bytes" "encoding/json" "errors" "fmt" @@ -9,7 +8,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/mulgadc/hive/hive/utils" ) @@ -85,8 +84,9 @@ func ResetImageAttribute(input *ec2.ResetImageAttributeInput) (output ec2.ResetI return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_ResetImageAttribute(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_image.NewResetImageAttributeHandler(handlers_ec2_image.NewMockImageService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -107,39 +107,3 @@ func ResetImageAttribute(input *ec2.ResetImageAttributeInput) (output ec2.ResetI return output, nil } - -func EC2_Process_ResetImageAttribute(jsonData []byte) (output []byte) { - - var input ec2.ResetImageAttributeInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateResetImageAttributeInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually reset image attributes. - // This is a placeholder response for testing the framework. - - // ResetImageAttributeOutput has no exported fields, so we return a simple success indicator - // to distinguish from error responses - result := map[string]bool{"Return": true} - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_ResetImageAttribute could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/instance/RunInstances.go b/hive/gateway/ec2/instance/RunInstances.go new file mode 100644 index 000000000..5d4426b62 --- /dev/null +++ b/hive/gateway/ec2/instance/RunInstances.go @@ -0,0 +1,215 @@ +package gateway_ec2_instance + +import ( + "encoding/json" + "errors" + "fmt" + "log/slog" + "strings" + + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/handlers/ec2/instance" + "github.com/mulgadc/hive/hive/utils" +) + +type RunInstancesResponse struct { + Reservation *ec2.Reservation `locationName:"RunInstancesResponse"` +} + +/* +Sample JSON: + + "RunInstances":{ + "name":"RunInstances", // Function name + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"RunInstancesRequest"}, // Input shape from AWS API + "output":{"shape":"Reservation"} // Output shape from AWS API + }, + + "RunInstancesRequest":{ + "type":"structure", + "required":[ + "MaxCount", + "MinCount" + ], + "members":{ + "BlockDeviceMappings":{ + "shape":"BlockDeviceMappingRequestList", + "locationName":"BlockDeviceMapping" + }, + "ImageId":{"shape":"ImageId"}, + "InstanceType":{"shape":"InstanceType"}, + "Ipv6AddressCount":{"shape":"Integer"}, + "Ipv6Addresses":{ + "shape":"InstanceIpv6AddressList", + "locationName":"Ipv6Address" + }, + "KernelId":{"shape":"KernelId"}, + "KeyName":{"shape":"KeyPairName"}, + "MaxCount":{"shape":"Integer"}, + "MinCount":{"shape":"Integer"}, + "Monitoring":{"shape":"RunInstancesMonitoringEnabled"}, + "Placement":{"shape":"Placement"}, + "RamdiskId":{"shape":"RamdiskId"}, + "SecurityGroupIds":{ + "shape":"SecurityGroupIdStringList", + "locationName":"SecurityGroupId" + }, + "SecurityGroups":{ + "shape":"SecurityGroupStringList", + "locationName":"SecurityGroup" + }, + "SubnetId":{"shape":"SubnetId"}, + "UserData":{"shape":"RunInstancesUserData"}, + "AdditionalInfo":{ + "shape":"String", + "locationName":"additionalInfo" + }, + "ClientToken":{ + "shape":"String", + "idempotencyToken":true, + "locationName":"clientToken" + }, + "DisableApiTermination":{ + "shape":"Boolean", + "locationName":"disableApiTermination" + }, + "DryRun":{ + "shape":"Boolean", + "locationName":"dryRun" + }, + "EbsOptimized":{ + "shape":"Boolean", + "locationName":"ebsOptimized" + }, + "IamInstanceProfile":{ + "shape":"IamInstanceProfileSpecification", + "locationName":"iamInstanceProfile" + }, + "InstanceInitiatedShutdownBehavior":{ + "shape":"ShutdownBehavior", + "locationName":"instanceInitiatedShutdownBehavior" + }, + "NetworkInterfaces":{ + "shape":"InstanceNetworkInterfaceSpecificationList", + "locationName":"networkInterface" + }, + "PrivateIpAddress":{ + "shape":"String", + "locationName":"privateIpAddress" + }, + "ElasticGpuSpecification":{"shape":"ElasticGpuSpecifications"}, + "ElasticInferenceAccelerators":{ + "shape":"ElasticInferenceAccelerators", + "locationName":"ElasticInferenceAccelerator" + }, + "TagSpecifications":{ + "shape":"TagSpecificationList", + "locationName":"TagSpecification" + }, + "LaunchTemplate":{"shape":"LaunchTemplateSpecification"}, + "InstanceMarketOptions":{"shape":"InstanceMarketOptionsRequest"}, + "CreditSpecification":{"shape":"CreditSpecificationRequest"}, + "CpuOptions":{"shape":"CpuOptionsRequest"}, + "CapacityReservationSpecification":{"shape":"CapacityReservationSpecification"}, + "HibernationOptions":{"shape":"HibernationOptionsRequest"}, + "LicenseSpecifications":{ + "shape":"LicenseSpecificationListRequest", + "locationName":"LicenseSpecification" + }, + "MetadataOptions":{"shape":"InstanceMetadataOptionsRequest"}, + "EnclaveOptions":{"shape":"EnclaveOptionsRequest"}, + "PrivateDnsNameOptions":{"shape":"PrivateDnsNameOptionsRequest"}, + "MaintenanceOptions":{"shape":"InstanceMaintenanceOptionsRequest"}, + "DisableApiStop":{"shape":"Boolean"}, + "EnablePrimaryIpv6":{"shape":"Boolean"} + } + }, +*/ + +func ValidateRunInstancesInput(input *ec2.RunInstancesInput) (err error) { + + // Check required args from JSON above + // required:[ + // "MaxCount", + // "MinCount" + // ] + + if input == nil { + return errors.New("MissingParameter") + } + + if input.MinCount == nil { + return errors.New("MissingParameter") + } + + if *input.MinCount == 0 { + return errors.New("InvalidParameterValue") + } + + if *input.MaxCount == 0 { + return errors.New("InvalidParameterValue") + } + + // Additional validation from EC2 spec + if *input.MinCount > *input.MaxCount { + return errors.New("InvalidParameterValue") + } + + if input.ImageId == nil || *input.ImageId == "" { + return errors.New("MissingParameter") + } + + if input.InstanceType == nil || *input.InstanceType == "" { + return errors.New("MissingParameter") + } + + if !strings.HasPrefix(*input.ImageId, "ami-") { + return errors.New("InvalidAMIID.Malformed") + + } + + return + +} + +func RunInstances(input *ec2.RunInstancesInput) (reservation ec2.Reservation, err error) { + + // Validate input + err = ValidateRunInstancesInput(input) + + if err != nil { + return reservation, err + } + + // Marshal to JSON, to send over the wire for processing (NATS) + jsonData, err := json.Marshal(input) + if err != nil { + return reservation, fmt.Errorf("failed to marshal input to JSON: %w", err) + } + + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_instance.NewRunInstancesHandler(handlers_ec2_instance.NewMockInstanceService()) + jsonResp := handler.Process(jsonData) + + // Validate if the response is successful or an error + + responseError, err := utils.ValidateErrorPayload(jsonResp) + + if err != nil { + slog.Error("Runinstances failed", "err", responseError.Code) + return reservation, errors.New(*responseError.Code) + } + + // Unmarshal the JSON response back into a Reservation struct + err = json.Unmarshal(jsonResp, &reservation) + if err != nil { + return reservation, fmt.Errorf("failed to unmarshal JSON response to Reservation: %w", err) + } + + return reservation, nil + +} diff --git a/hive/gateway/ec2/instance/RunInstances_test.go b/hive/gateway/ec2/instance/RunInstances_test.go new file mode 100644 index 000000000..d4d99f81f --- /dev/null +++ b/hive/gateway/ec2/instance/RunInstances_test.go @@ -0,0 +1,288 @@ +package gateway_ec2_instance + +import ( + "encoding/json" + "errors" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/handlers/ec2/instance" + "github.com/mulgadc/hive/hive/utils" + "github.com/stretchr/testify/assert" +) + +var defaults = ec2.RunInstancesInput{ + ImageId: aws.String("ami-0abcdef1234567890"), + InstanceType: aws.String("t2.micro"), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + KeyName: aws.String("my-key-pair"), + SecurityGroupIds: []*string{ + aws.String("sg-0123456789abcdef0"), + }, + SubnetId: aws.String("subnet-6e7f829e"), +} + +func TestParseRunInstances(t *testing.T) { + + // Group multiple tests + tests := []struct { + name string + input *ec2.RunInstancesInput + want error + }{ + + { + name: "InvalidMinCount", + input: &ec2.RunInstancesInput{ + ImageId: defaults.ImageId, + InstanceType: defaults.InstanceType, + MinCount: aws.Int64(0), + MaxCount: aws.Int64(1), + KeyName: defaults.KeyName, + SecurityGroupIds: defaults.SecurityGroupIds, + SubnetId: defaults.SubnetId, + }, + want: errors.New("InvalidParameterValue"), + }, + + { + name: "InvalidMaxCount", + input: &ec2.RunInstancesInput{ + ImageId: defaults.ImageId, + InstanceType: defaults.InstanceType, + MinCount: aws.Int64(1), + MaxCount: aws.Int64(0), + KeyName: defaults.KeyName, + SecurityGroupIds: defaults.SecurityGroupIds, + SubnetId: defaults.SubnetId, + }, + want: errors.New("InvalidParameterValue"), + }, + + { + name: "InvalidMinCount", + input: &ec2.RunInstancesInput{ + ImageId: defaults.ImageId, + InstanceType: defaults.InstanceType, + MinCount: aws.Int64(0), + MaxCount: aws.Int64(1), + KeyName: defaults.KeyName, + SecurityGroupIds: defaults.SecurityGroupIds, + SubnetId: defaults.SubnetId, + }, + want: errors.New("InvalidParameterValue"), + }, + + { + name: "InvalidNoImageId", + input: &ec2.RunInstancesInput{ + ImageId: aws.String(""), + InstanceType: defaults.InstanceType, + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + KeyName: defaults.KeyName, + SecurityGroupIds: defaults.SecurityGroupIds, + SubnetId: defaults.SubnetId, + }, + want: errors.New("MissingParameter"), + }, + + { + name: "InvalidNoInstanceType", + input: &ec2.RunInstancesInput{ + ImageId: defaults.ImageId, + InstanceType: aws.String(""), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + KeyName: defaults.KeyName, + SecurityGroupIds: defaults.SecurityGroupIds, + SubnetId: defaults.SubnetId, + }, + want: errors.New("MissingParameter"), + }, + + { + name: "InvalidNoInstanceType", + input: &ec2.RunInstancesInput{ + ImageId: aws.String("invalid-name-here"), + InstanceType: defaults.InstanceType, + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + KeyName: defaults.KeyName, + SecurityGroupIds: defaults.SecurityGroupIds, + SubnetId: defaults.SubnetId, + }, + want: errors.New("InvalidAMIID.Malformed"), + }, + + // Successful test + { + name: "ValidTest", + input: &ec2.RunInstancesInput{ + ImageId: defaults.ImageId, + InstanceType: defaults.InstanceType, + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + KeyName: defaults.KeyName, + SecurityGroupIds: defaults.SecurityGroupIds, + SubnetId: defaults.SubnetId, + }, + want: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + response, err := RunInstances(test.input) + + // Use assert to check if the error is as expected + assert.Equal(t, test.want, err) + + if err != nil { + assert.Len(t, response.Instances, 0) + //assert.Nil(t, response) + } else { + + // Check expected output + assert.Len(t, response.Instances, 1) + + // ImageID returned + if len(response.Instances) > 0 { + + // ImageId matches our AMI + assert.Equal(t, defaults.ImageId, response.Instances[0].ImageId) + + // InstanceID starts with i- + assert.True(t, true, strings.HasPrefix(*response.Instances[0].ImageId, "i-")) + + // InstanceType matches + assert.Equal(t, defaults.InstanceType, response.Instances[0].InstanceType) + + // KeyName matches + assert.Equal(t, defaults.KeyName, response.Instances[0].KeyName) + + // State should be 16, booting. + assert.Equal(t, aws.Int64(16), response.Instances[0].State.Code) + + assert.Equal(t, aws.String("running"), response.Instances[0].State.Name) + + // Subnet should match + assert.Equal(t, defaults.SubnetId, response.Instances[0].SubnetId) + + } + + } + + }) + } + + // Additional test + +} + +func TestEC2ProcessRunInstances(t *testing.T) { + makeValidInput := func() *ec2.RunInstancesInput { + return &ec2.RunInstancesInput{ + ImageId: aws.String(*defaults.ImageId), + InstanceType: aws.String(*defaults.InstanceType), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + KeyName: aws.String(*defaults.KeyName), + SecurityGroupIds: []*string{aws.String(*defaults.SecurityGroupIds[0])}, + SubnetId: aws.String(*defaults.SubnetId), + } + } + + tests := []struct { + name string + payload interface{} + rawJSON []byte + wantValidationErr bool + wantErrCode string + assertFn func(t *testing.T, reservation ec2.Reservation) + }{ + { + name: "MismatchedShape", + payload: &ec2.DescribeInstancesInput{DryRun: aws.Bool(true)}, + wantValidationErr: true, + wantErrCode: "ValidationError", + }, + { + name: "MissingRequiredFields", + payload: &ec2.RunInstancesInput{ + ImageId: aws.String("ami-0abcdef1234567890"), + MaxCount: aws.Int64(1), + }, + wantValidationErr: true, + wantErrCode: "MissingParameter", + }, + { + name: "UnknownFieldInPayload", + rawJSON: []byte(`{ + "ImageId":"ami-0abcdef1234567890", + "InstanceType":"t2.micro", + "MinCount":1, + "MaxCount":1, + "Unexpected":true + }`), + wantValidationErr: true, + wantErrCode: "ValidationError", + }, + { + name: "ValidRunInstances", + payload: makeValidInput(), + assertFn: func(t *testing.T, reservation ec2.Reservation) { + assert.Len(t, reservation.Instances, 1) + if len(reservation.Instances) == 0 { + return + } + instance := reservation.Instances[0] + assert.Equal(t, defaults.ImageId, instance.ImageId) + assert.Equal(t, defaults.InstanceType, instance.InstanceType) + assert.Equal(t, defaults.KeyName, instance.KeyName) + assert.Equal(t, aws.Int64(16), instance.State.Code) + assert.Equal(t, aws.String("running"), instance.State.Name) + assert.Equal(t, defaults.SubnetId, instance.SubnetId) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var ( + jsonData []byte + err error + ) + + if tt.rawJSON != nil { + jsonData = tt.rawJSON + } else { + jsonData, err = json.Marshal(tt.payload) + assert.NoError(t, err) + } + + handler := handlers_ec2_instance.NewRunInstancesHandler(handlers_ec2_instance.NewMockInstanceService()) + jsonResp := handler.Process(jsonData) + + responseError, err := utils.ValidateErrorPayload(jsonResp) + + if tt.wantValidationErr { + assert.Error(t, err) + assert.Equal(t, tt.wantErrCode, aws.StringValue(responseError.Code)) + return + } + + assert.NoError(t, err) + + var reservation ec2.Reservation + assert.NoError(t, json.Unmarshal(jsonResp, &reservation)) + + if tt.assertFn != nil { + tt.assertFn(t, reservation) + } + }) + } +} diff --git a/hive/gateway/ec2/key/CreateKeyPair.go b/hive/gateway/ec2/key/CreateKeyPair.go index cdc0a2571..54e02b5bf 100644 --- a/hive/gateway/ec2/key/CreateKeyPair.go +++ b/hive/gateway/ec2/key/CreateKeyPair.go @@ -1,15 +1,13 @@ package gateway_ec2_key import ( - "bytes" "encoding/json" "errors" "fmt" "log/slog" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/key" "github.com/mulgadc/hive/hive/utils" ) @@ -76,8 +74,9 @@ func CreateKeyPair(input *ec2.CreateKeyPairInput) (output ec2.CreateKeyPairOutpu return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_CreateKeyPair(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_key.NewCreateKeyPairHandler(handlers_ec2_key.NewMockKeyService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -98,42 +97,3 @@ func CreateKeyPair(input *ec2.CreateKeyPairInput) (output ec2.CreateKeyPairOutpu return output, nil } - -func EC2_Process_CreateKeyPair(jsonData []byte) (output []byte) { - - var input ec2.CreateKeyPairInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateCreateKeyPairInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually create the key pair. - // This is a placeholder response for testing the framework. - - result := &ec2.CreateKeyPairOutput{ - KeyFingerprint: aws.String("1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f"), - KeyMaterial: aws.String("-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA...\n-----END RSA PRIVATE KEY-----"), - KeyName: input.KeyName, - KeyPairId: aws.String("key-0123456789abcdef0"), - } - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_CreateKeyPair could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/key/CreateKeyPair_test.go b/hive/gateway/ec2/key/CreateKeyPair_test.go index 49dca904b..5fccf7e6c 100644 --- a/hive/gateway/ec2/key/CreateKeyPair_test.go +++ b/hive/gateway/ec2/key/CreateKeyPair_test.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/handlers/ec2/key" "github.com/mulgadc/hive/hive/utils" "github.com/stretchr/testify/assert" ) @@ -83,7 +84,7 @@ func TestEC2ProcessCreateKeyPair(t *testing.T) { KeyName: aws.String(""), }, wantValidationErr: true, - wantErrCode: "ValidationError", + wantErrCode: "MissingParameter", }, { name: "ValidCreateKeyPair", @@ -112,7 +113,8 @@ func TestEC2ProcessCreateKeyPair(t *testing.T) { assert.NoError(t, err) } - jsonResp := EC2_Process_CreateKeyPair(jsonData) + handler := handlers_ec2_key.NewCreateKeyPairHandler(handlers_ec2_key.NewMockKeyService()) + jsonResp := handler.Process(jsonData) responseError, err := utils.ValidateErrorPayload(jsonResp) if tt.wantValidationErr { diff --git a/hive/gateway/ec2/key/DeleteKeyPair.go b/hive/gateway/ec2/key/DeleteKeyPair.go index 268fe67fc..8b4181980 100644 --- a/hive/gateway/ec2/key/DeleteKeyPair.go +++ b/hive/gateway/ec2/key/DeleteKeyPair.go @@ -1,15 +1,13 @@ package gateway_ec2_key import ( - "bytes" "encoding/json" "errors" "fmt" "log/slog" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/key" "github.com/mulgadc/hive/hive/utils" ) @@ -85,8 +83,9 @@ func DeleteKeyPair(input *ec2.DeleteKeyPairInput) (output ec2.DeleteKeyPairOutpu return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_DeleteKeyPair(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_key.NewDeleteKeyPairHandler(handlers_ec2_key.NewMockKeyService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -107,40 +106,3 @@ func DeleteKeyPair(input *ec2.DeleteKeyPairInput) (output ec2.DeleteKeyPairOutpu return output, nil } - -func EC2_Process_DeleteKeyPair(jsonData []byte) (output []byte) { - - var input ec2.DeleteKeyPairInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateDeleteKeyPairInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually delete the key pair. - // This is a placeholder response for testing the framework. - - result := &ec2.DeleteKeyPairOutput{ - Return: aws.Bool(true), - KeyPairId: input.KeyPairId, - } - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_DeleteKeyPair could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/key/DescribeKeyPairs.go b/hive/gateway/ec2/key/DescribeKeyPairs.go index d023c5c2d..0a2898272 100644 --- a/hive/gateway/ec2/key/DescribeKeyPairs.go +++ b/hive/gateway/ec2/key/DescribeKeyPairs.go @@ -1,15 +1,13 @@ package gateway_ec2_key import ( - "bytes" "encoding/json" "errors" "fmt" "log/slog" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/key" "github.com/mulgadc/hive/hive/utils" ) @@ -77,8 +75,9 @@ func DescribeKeyPairs(input *ec2.DescribeKeyPairsInput) (output ec2.DescribeKeyP return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_DescribeKeyPairs(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_key.NewDescribeKeyPairsHandler(handlers_ec2_key.NewMockKeyService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -99,46 +98,3 @@ func DescribeKeyPairs(input *ec2.DescribeKeyPairsInput) (output ec2.DescribeKeyP return output, nil } - -func EC2_Process_DescribeKeyPairs(jsonData []byte) (output []byte) { - - var input ec2.DescribeKeyPairsInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateDescribeKeyPairsInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually query key pairs from the system. - // This is a placeholder response for testing the framework. - - result := &ec2.DescribeKeyPairsOutput{ - KeyPairs: []*ec2.KeyPairInfo{ - { - KeyPairId: aws.String("key-0123456789abcdef0"), - KeyFingerprint: aws.String("1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f"), - KeyName: aws.String("test-key"), - KeyType: aws.String("rsa"), - }, - }, - } - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_DescribeKeyPairs could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/gateway/ec2/key/ImportKeyPair.go b/hive/gateway/ec2/key/ImportKeyPair.go index d5750b1b3..c58bcd371 100644 --- a/hive/gateway/ec2/key/ImportKeyPair.go +++ b/hive/gateway/ec2/key/ImportKeyPair.go @@ -1,15 +1,13 @@ package gateway_ec2_key import ( - "bytes" "encoding/json" "errors" "fmt" "log/slog" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/hive/hive/awserrors" + "github.com/mulgadc/hive/hive/handlers/ec2/key" "github.com/mulgadc/hive/hive/utils" ) @@ -91,8 +89,9 @@ func ImportKeyPair(input *ec2.ImportKeyPairInput) (output ec2.ImportKeyPairOutpu return output, fmt.Errorf("failed to marshal input to JSON: %w", err) } - // Run the simulated JSON request via NATS, which will return a JSON response - jsonResp := EC2_Process_ImportKeyPair(jsonData) + // Run the simulated JSON request via handler, which will return a JSON response + handler := handlers_ec2_key.NewImportKeyPairHandler(handlers_ec2_key.NewMockKeyService()) + jsonResp := handler.Process(jsonData) // Validate if the response is successful or an error responseError, err := utils.ValidateErrorPayload(jsonResp) @@ -113,41 +112,3 @@ func ImportKeyPair(input *ec2.ImportKeyPairInput) (output ec2.ImportKeyPairOutpu return output, nil } - -func EC2_Process_ImportKeyPair(jsonData []byte) (output []byte) { - - var input ec2.ImportKeyPairInput - - decoder := json.NewDecoder(bytes.NewReader(jsonData)) - decoder.DisallowUnknownFields() - - err := decoder.Decode(&input) - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // Ensure the payload provided the fields that EC2 expects before proceeding. - err = ValidateImportKeyPairInput(&input) - - if err != nil { - return utils.GenerateErrorPayload(awserrors.ErrorValidationError) - } - - // TODO: Add the logic to actually import the key pair. - // This is a placeholder response for testing the framework. - - result := &ec2.ImportKeyPairOutput{ - KeyFingerprint: aws.String("1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f"), - KeyName: input.KeyName, - KeyPairId: aws.String("key-0987654321fedcba0"), - } - - // Return as JSON, to simulate the NATS response - jsonResponse, err := json.Marshal(result) - if err != nil { - slog.Error("EC2_Process_ImportKeyPair could not marshal output", "err", err) - return nil - } - - return jsonResponse -} diff --git a/hive/utils/utils.go b/hive/utils/utils.go index fee6b8cbb..d84ba6435 100644 --- a/hive/utils/utils.go +++ b/hive/utils/utils.go @@ -264,11 +264,13 @@ func ValidateErrorPayload(payload []byte) (responseError ec2.ResponseError, err err = decoder.Decode(&responseError) - if err == nil { - // TODO: Move error codes with vars to errors.go + if err == nil && responseError.Code != nil { + // Successfully decoded as ResponseError AND has a non-nil Code field + // This is a real error response return responseError, errors.New("ResponseError detected") } + // Either failed to decode (not an error structure) or Code is nil (empty valid response) return responseError, nil }