mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-19 19:01:42 +00:00
refactor: move resource id generation to aws foundation
This commit is contained in:
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/admin"
|
||||
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
|
||||
"github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/metadata"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/clustersize"
|
||||
handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc"
|
||||
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
|
||||
@@ -778,7 +779,7 @@ func runimagesImportCmd(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
|
||||
// Describe the image/AMI as the control-plane document it will become.
|
||||
volumeId := utils.GenerateResourceID("ami")
|
||||
volumeId := awsidentifiers.GenerateResourceID("ami")
|
||||
amiName := fmt.Sprintf("ami-%s-%s-%s", image.Distro, image.Version, image.Arch)
|
||||
if amiNameOverride != "" {
|
||||
amiName = amiNameOverride
|
||||
@@ -1726,9 +1727,9 @@ func runAdminInit(cmd *cobra.Command, args []string) {
|
||||
IPSecEnabled: ipsecEnabled,
|
||||
}
|
||||
if externalMode != "" {
|
||||
bootstrapVpcId := utils.GenerateResourceID("vpc")
|
||||
bootstrapSubnetId := utils.GenerateResourceID("subnet")
|
||||
bootstrapIgwId := utils.GenerateResourceID("igw")
|
||||
bootstrapVpcId := awsidentifiers.GenerateResourceID("vpc")
|
||||
bootstrapSubnetId := awsidentifiers.GenerateResourceID("subnet")
|
||||
bootstrapIgwId := awsidentifiers.GenerateResourceID("igw")
|
||||
networkConfig.ExternalMode = externalMode
|
||||
networkConfig.Pools = externalPools
|
||||
networkConfig.PoolDNSServers = dnsServers
|
||||
@@ -1815,9 +1816,9 @@ func runAdminInit(cmd *cobra.Command, args []string) {
|
||||
// These are written to [bootstrap] in spinifex.toml so vpcd can
|
||||
// create OVN topology on first boot. The daemon uses the same IDs
|
||||
// when it creates the records in NATS KV via EnsureDefaultVPC.
|
||||
bootstrapVpcId := utils.GenerateResourceID("vpc")
|
||||
bootstrapSubnetId := utils.GenerateResourceID("subnet")
|
||||
bootstrapIgwId := utils.GenerateResourceID("igw")
|
||||
bootstrapVpcId := awsidentifiers.GenerateResourceID("vpc")
|
||||
bootstrapSubnetId := awsidentifiers.GenerateResourceID("subnet")
|
||||
bootstrapIgwId := awsidentifiers.GenerateResourceID("igw")
|
||||
|
||||
configSettings := admin.ConfigSettings{
|
||||
AccessKey: accessKey,
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/admin"
|
||||
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
|
||||
"github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/metadata"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
gateway_bedrock "github.com/mulgadc/spinifex/spinifex/gateway/bedrock"
|
||||
"github.com/mulgadc/spinifex/spinifex/gateway/bedrock/hfhub"
|
||||
"github.com/mulgadc/spinifex/spinifex/providers/ebs"
|
||||
@@ -757,7 +758,7 @@ func runStageWeights(ctx context.Context, store objectstore.ObjectStore, weights
|
||||
// a live provider -- so it is exercised live rather than in unit tests.
|
||||
func materializeWeightsVolume(ctx context.Context, provider ebsprovider.EBSProvider, nodeID string, node config.Config, downloadDir string, contentBytes int64) (string, error) {
|
||||
tmpDir := filepath.Dir(downloadDir)
|
||||
volumeId := utils.GenerateResourceID("vol")
|
||||
volumeId := awsidentifiers.GenerateResourceID("vol")
|
||||
imagePath := filepath.Join(tmpDir, volumeId+".img")
|
||||
|
||||
fmt.Println("Building filesystem image ...")
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
handlers_ochrevector "github.com/mulgadc/spinifex/spinifex/handlers/ochrevector"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/pterm/pterm"
|
||||
@@ -326,7 +327,7 @@ func parseFilterFlag(raw string) (*handlers_ochrevector.Filter, error) {
|
||||
// creates it. Returns the message to print.
|
||||
func runIndexCreate(ctx context.Context, svc handlers_ochrevector.VectorService, name string, dimension int, model string) (string, error) {
|
||||
out, err := svc.CreateIndex(ctx, &handlers_ochrevector.CreateIndexRequest{
|
||||
IndexID: utils.GenerateResourceID("idx"),
|
||||
IndexID: awsidentifiers.GenerateResourceID("idx"),
|
||||
Name: name,
|
||||
Dimension: dimension,
|
||||
EmbeddingModel: model,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mulgadc/spinifex/spinifex/domains/ec2/instancetypes"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
@@ -44,7 +45,7 @@ func (d *Daemon) handleEC2CreateCapacityReservation(msg *nats.Msg) string {
|
||||
}
|
||||
|
||||
rec := &capacityReservation{
|
||||
ID: utils.GenerateResourceID("cr"),
|
||||
ID: awsidentifiers.GenerateResourceID("cr"),
|
||||
AccountID: accountID,
|
||||
InstanceType: instanceType,
|
||||
AvailabilityZone: aws.StringValue(input.AvailabilityZone),
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mulgadc/spinifex/contracts/ec2/v1"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc"
|
||||
handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2"
|
||||
@@ -135,7 +136,7 @@ func (d *Daemon) LaunchSystemInstance(input *handlers_elbv2.SystemInstanceInput)
|
||||
{Key: aws.String(tags.ManagedByKey), Value: aws.String(tags.ManagedByELBv2)},
|
||||
}
|
||||
instance.Reservation = &ec2.Reservation{}
|
||||
instance.Reservation.SetReservationId(utils.GenerateResourceID("r"))
|
||||
instance.Reservation.SetReservationId(awsidentifiers.GenerateResourceID("r"))
|
||||
instance.Reservation.SetOwnerId(accountID)
|
||||
instance.Reservation.Instances = []*ec2.Instance{ec2Instance}
|
||||
// Mirror the customer-instance path (handlers/ec2/instance/service_impl.go:334)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package identifiers
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// GenerateResourceID generates a unique resource ID with the given prefix.
|
||||
// Format: {prefix}-{17 hex chars} using crypto/rand.
|
||||
func GenerateResourceID(prefix string) string {
|
||||
b := make([]byte, 9)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
//nolint:forbidigo // Continuing after the CSPRNG fails could create predictable resource IDs.
|
||||
panic("crypto/rand failed: " + err.Error())
|
||||
}
|
||||
return prefix + "-" + hex.EncodeToString(b)[:17]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package identifiers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGenerateResourceID(t *testing.T) {
|
||||
tests := []struct {
|
||||
prefix string
|
||||
}{
|
||||
{"i"},
|
||||
{"r"},
|
||||
{"vol"},
|
||||
{"snap"},
|
||||
{"key"},
|
||||
{"eigw"},
|
||||
{"ami"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.prefix, func(t *testing.T) {
|
||||
id := GenerateResourceID(tt.prefix)
|
||||
assert.True(t, strings.HasPrefix(id, tt.prefix+"-"))
|
||||
// prefix + "-" + 17 hex chars
|
||||
assert.Len(t, id, len(tt.prefix)+1+17)
|
||||
|
||||
// Verify uniqueness
|
||||
id2 := GenerateResourceID(tt.prefix)
|
||||
assert.NotEqual(t, id, id2)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/mulgadc/spinifex/contracts/ec2/v1"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/arn"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/nats-io/nats.go"
|
||||
@@ -686,7 +687,7 @@ func TestCountInstanceProfileAssociations_NoMatches(t *testing.T) {
|
||||
// utils generator would break replay parsing of Disassociate/Replace.
|
||||
func TestAssociationIDFormat(t *testing.T) {
|
||||
t.Parallel()
|
||||
id := utils.GenerateResourceID("iip-assoc")
|
||||
id := awsidentifiers.GenerateResourceID("iip-assoc")
|
||||
assert.True(t, strings.HasPrefix(id, "iip-assoc-"),
|
||||
"GenerateResourceID must preserve the AWS-style hyphen between prefix and suffix")
|
||||
suffix := strings.TrimPrefix(id, "iip-assoc-")
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
clusterv1 "github.com/mulgadc/spinifex/contracts/cluster/v1"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
handlers_ec2_placementgroup "github.com/mulgadc/spinifex/spinifex/handlers/ec2/placementgroup"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
|
||||
@@ -57,7 +58,7 @@ func distributeInstances(ctx context.Context, input *ec2.RunInstancesInput, nats
|
||||
allocations := spreadAllocate(nodes, launchCount)
|
||||
// Minted once here and handed to every node, so a launch that spreads
|
||||
// across nodes comes back as one reservation instead of one per node.
|
||||
reservationID := utils.GenerateResourceID("r")
|
||||
reservationID := awsidentifiers.GenerateResourceID("r")
|
||||
results := launchOnNodes(ctx, allocations, input, natsConn, accountID, reservationID)
|
||||
return aggregateResults(ctx, results, minCount, natsConn, accountID)
|
||||
}
|
||||
@@ -281,7 +282,7 @@ func distributeInstancesSpread(ctx context.Context, input *ec2.RunInstancesInput
|
||||
// A spread group puts one instance on each node, so without a shared ID
|
||||
// every node mints its own and one launch comes back as several
|
||||
// reservations.
|
||||
spreadReservationID := utils.GenerateResourceID("r")
|
||||
spreadReservationID := awsidentifiers.GenerateResourceID("r")
|
||||
results := launchOnNodes(ctx, allocations, input, natsConn, accountID, spreadReservationID)
|
||||
|
||||
var allInstances []*ec2.Instance
|
||||
|
||||
@@ -15,12 +15,12 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
gateway_ec2_instance "github.com/mulgadc/spinifex/spinifex/gateway/ec2/instance"
|
||||
handlers_ec2_spotinstance "github.com/mulgadc/spinifex/spinifex/handlers/ec2/spotinstance"
|
||||
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
|
||||
handlers_quota "github.com/mulgadc/spinifex/spinifex/handlers/quota"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
@@ -192,7 +192,7 @@ func buildSpotRequests(input *ec2.RequestSpotInstancesInput, runInput *ec2.RunIn
|
||||
requests := make([]*ec2.SpotInstanceRequest, 0, count)
|
||||
for range count {
|
||||
req := &ec2.SpotInstanceRequest{
|
||||
SpotInstanceRequestId: aws.String(utils.GenerateResourceID("sir")),
|
||||
SpotInstanceRequestId: aws.String(awsidentifiers.GenerateResourceID("sir")),
|
||||
State: aws.String(ec2.SpotInstanceStateActive),
|
||||
Type: aws.String(spotType),
|
||||
ProductDescription: aws.String(ec2.RIProductDescriptionLinuxUnix),
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/migrate"
|
||||
@@ -94,7 +95,7 @@ func (s *EgressOnlyIGWServiceImpl) CreateEgressOnlyInternetGateway(ctx context.C
|
||||
return nil, awserrors.IDNotFound(awserrors.ErrorInvalidVpcIDNotFound, "vpc", *input.VpcId)
|
||||
}
|
||||
|
||||
eigwID := utils.GenerateResourceID("eigw")
|
||||
eigwID := awsidentifiers.GenerateResourceID("eigw")
|
||||
|
||||
record := EgressOnlyIGWRecord{
|
||||
EgressOnlyInternetGatewayId: eigwID,
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/migrate"
|
||||
@@ -109,7 +110,7 @@ func (s *EIPServiceImpl) AllocateAddress(ctx context.Context, input *ec2.Allocat
|
||||
}
|
||||
|
||||
func (s *EIPServiceImpl) allocateAddress(ctx context.Context, input *ec2.AllocateAddressInput, accountID string) (*ec2.AllocateAddressOutput, error) {
|
||||
allocID := utils.GenerateResourceID("eipalloc")
|
||||
allocID := awsidentifiers.GenerateResourceID("eipalloc")
|
||||
|
||||
var publicIP, poolName string
|
||||
var err error
|
||||
@@ -256,7 +257,7 @@ func (s *EIPServiceImpl) AssociateAddress(ctx context.Context, input *ec2.Associ
|
||||
privateIP = *input.PrivateIpAddress
|
||||
}
|
||||
|
||||
associationID := utils.GenerateResourceID("eipassoc")
|
||||
associationID := awsidentifiers.GenerateResourceID("eipassoc")
|
||||
|
||||
record.AssociationId = associationID
|
||||
record.ENIId = eniID
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/paging"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
@@ -115,7 +116,7 @@ func NewIGWServiceImplWithNATS(ctx context.Context, cfg *config.Config, natsConn
|
||||
|
||||
// CreateInternetGateway creates a new Internet Gateway (initially detached).
|
||||
func (s *IGWServiceImpl) CreateInternetGateway(ctx context.Context, input *ec2.CreateInternetGatewayInput, accountID string) (*ec2.CreateInternetGatewayOutput, error) {
|
||||
igwID := utils.GenerateResourceID("igw")
|
||||
igwID := awsidentifiers.GenerateResourceID("igw")
|
||||
return s.createIGW(ctx, input, accountID, igwID)
|
||||
}
|
||||
|
||||
|
||||
@@ -434,8 +434,8 @@ func (s *ImageServiceImpl) CreateImageFromInstance(params CreateImageParams, acc
|
||||
}
|
||||
}
|
||||
|
||||
amiID := utils.GenerateResourceID("ami")
|
||||
snapshotID := utils.GenerateResourceID("snap")
|
||||
amiID := awsidentifiers.GenerateResourceID("ami")
|
||||
snapshotID := awsidentifiers.GenerateResourceID("snap")
|
||||
|
||||
slog.Info("CreateImageFromInstance", "instanceId", *input.InstanceId,
|
||||
"rootVolumeId", params.RootVolumeID, "amiId", amiID, "snapshotId", snapshotID,
|
||||
@@ -862,8 +862,8 @@ func (s *ImageServiceImpl) CopyImage(ctx context.Context, input *ec2.CopyImageIn
|
||||
return nil, errors.New(awserrors.ErrorInvalidAMINameDuplicate)
|
||||
}
|
||||
|
||||
newSnapshotID := utils.GenerateResourceID("snap")
|
||||
newImageID := utils.GenerateResourceID("ami")
|
||||
newSnapshotID := awsidentifiers.GenerateResourceID("snap")
|
||||
newImageID := awsidentifiers.GenerateResourceID("ami")
|
||||
|
||||
// New snap shares source VolumeID — no block copy.
|
||||
snapSizeGiB := uint64(0)
|
||||
@@ -1092,7 +1092,7 @@ func (s *ImageServiceImpl) RegisterImage(ctx context.Context, input *ec2.Registe
|
||||
|
||||
tags := awstags.Extract(input.TagSpecifications, "image")
|
||||
|
||||
amiID := utils.GenerateResourceID("ami")
|
||||
amiID := awsidentifiers.GenerateResourceID("ami")
|
||||
meta := ebsmetadata.AMI{
|
||||
ImageID: amiID,
|
||||
Name: name,
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
ec2platform "github.com/mulgadc/spinifex/spinifex/domains/ec2/platform"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
|
||||
handlers_dns "github.com/mulgadc/spinifex/spinifex/handlers/dns"
|
||||
handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc"
|
||||
@@ -206,7 +207,7 @@ func parseVolumeParams(input *ec2.RunInstancesInput) volumeParams {
|
||||
}
|
||||
|
||||
if strings.HasPrefix(*input.ImageId, "ami-") {
|
||||
p.imageId = utils.GenerateResourceID("vol")
|
||||
p.imageId = awsidentifiers.GenerateResourceID("vol")
|
||||
p.snapshotId = *input.ImageId
|
||||
} else {
|
||||
p.imageId = *input.ImageId
|
||||
@@ -326,7 +327,7 @@ func (s *InstanceServiceImpl) RunInstance(input *ec2.RunInstancesInput) (*vm.VM,
|
||||
return nil, nil, errors.New(awserrors.ErrorInvalidInstanceType)
|
||||
}
|
||||
|
||||
instanceId := utils.GenerateResourceID("i")
|
||||
instanceId := awsidentifiers.GenerateResourceID("i")
|
||||
|
||||
// Create new instance structure
|
||||
instance := &vm.VM{
|
||||
@@ -382,7 +383,7 @@ func (s *InstanceServiceImpl) RunInstance(input *ec2.RunInstancesInput) (*vm.VM,
|
||||
arn := aws.StringValue(input.IamInstanceProfile.Arn)
|
||||
if arn != "" {
|
||||
instance.IamInstanceProfileArn = arn
|
||||
instance.IamInstanceProfileAssociationId = utils.GenerateResourceID("iip-assoc")
|
||||
instance.IamInstanceProfileAssociationId = awsidentifiers.GenerateResourceID("iip-assoc")
|
||||
ec2Instance.IamInstanceProfile = &ec2.IamInstanceProfile{
|
||||
Arn: aws.String(arn),
|
||||
}
|
||||
@@ -987,7 +988,7 @@ func (s *InstanceServiceImpl) PrepareRunInstances(ctx context.Context, input *ec
|
||||
}
|
||||
|
||||
reservation := &ec2.Reservation{}
|
||||
reservation.SetReservationId(utils.GenerateResourceID("r"))
|
||||
reservation.SetReservationId(awsidentifiers.GenerateResourceID("r"))
|
||||
reservation.SetOwnerId(accountID)
|
||||
reservation.Instances = allEC2Instances
|
||||
|
||||
@@ -1346,7 +1347,7 @@ func (s *InstanceServiceImpl) AssociateIamInstanceProfile(ctx context.Context, i
|
||||
return nil, errors.New(awserrors.ErrorMissingParameter)
|
||||
}
|
||||
profileArn := command.IamProfileAssociationData.InstanceProfileArn
|
||||
newID := utils.GenerateResourceID("iip-assoc")
|
||||
newID := awsidentifiers.GenerateResourceID("iip-assoc")
|
||||
timestamp := time.Now().UTC()
|
||||
|
||||
var alreadyAssociated bool
|
||||
@@ -1441,7 +1442,7 @@ func (s *InstanceServiceImpl) ReplaceIamProfileAssociation(ctx context.Context,
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
newID := utils.GenerateResourceID("iip-assoc")
|
||||
newID := awsidentifiers.GenerateResourceID("iip-assoc")
|
||||
timestamp := time.Now().UTC()
|
||||
var swapped bool
|
||||
_, err := s.vmMgr.UpdateAndPersist(owner, func(v *vm.VM) bool {
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
@@ -210,7 +211,7 @@ func (s *KeyServiceImpl) CreateKeyPair(ctx context.Context, input *ec2.CreateKey
|
||||
}
|
||||
|
||||
// Build response (similar to AWS EC2)
|
||||
keyPairID := utils.GenerateResourceID("key")
|
||||
keyPairID := awsidentifiers.GenerateResourceID("key")
|
||||
tagMap := awstags.Extract(input.TagSpecifications, "key-pair")
|
||||
tags := awstags.MapToEC2(tagMap)
|
||||
// AWS ends RSA material at its END line, while OpenSSH-format Ed25519
|
||||
@@ -986,7 +987,7 @@ func (s *KeyServiceImpl) ImportKeyPair(ctx context.Context, input *ec2.ImportKey
|
||||
}
|
||||
|
||||
// Generate key pair ID
|
||||
keyPairID := utils.GenerateResourceID("key")
|
||||
keyPairID := awsidentifiers.GenerateResourceID("key")
|
||||
|
||||
// Build response output
|
||||
tagMap := awstags.Extract(input.TagSpecifications, "key-pair")
|
||||
|
||||
@@ -17,10 +17,10 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/migrate"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
)
|
||||
@@ -277,7 +277,7 @@ func (s *LaunchTemplateServiceImpl) CreateLaunchTemplate(ctx context.Context, in
|
||||
return nil, errors.New(awserrors.ErrorInvalidParameterValue)
|
||||
}
|
||||
|
||||
ltID := utils.GenerateResourceID("lt")
|
||||
ltID := awsidentifiers.GenerateResourceID("lt")
|
||||
if err := s.claimName(ctx, accountID, name, ltID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/migrate"
|
||||
@@ -140,7 +141,7 @@ func (s *NatGatewayServiceImpl) CreateNatGateway(ctx context.Context, input *ec2
|
||||
return nil, errors.New(awserrors.ErrorResourceAlreadyAssociated)
|
||||
}
|
||||
|
||||
natgwID := utils.GenerateResourceID("nat")
|
||||
natgwID := awsidentifiers.GenerateResourceID("nat")
|
||||
record := NatGatewayRecord{
|
||||
NatGatewayId: natgwID,
|
||||
VpcId: subnetRecord.VpcId,
|
||||
@@ -166,7 +167,7 @@ func (s *NatGatewayServiceImpl) CreateNatGateway(ctx context.Context, input *ec2
|
||||
// NAT GW reusing the same allocation). Linkage is the shared AllocationId;
|
||||
// DeleteNatGateway clears it back to allocated. Non-fatal: the NAT GW is
|
||||
// already stored, so a failed mark only weakens the reuse guard until then.
|
||||
eipRecord.AssociationId = utils.GenerateResourceID("eipassoc")
|
||||
eipRecord.AssociationId = awsidentifiers.GenerateResourceID("eipassoc")
|
||||
eipRecord.VpcId = subnetRecord.VpcId
|
||||
eipRecord.State = "associated"
|
||||
if eipData, err := json.Marshal(eipRecord); err == nil {
|
||||
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/arn"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/migrate"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
)
|
||||
@@ -112,7 +112,7 @@ func (s *PlacementGroupServiceImpl) CreatePlacementGroup(ctx context.Context, in
|
||||
|
||||
groupName := *input.GroupName
|
||||
key := kvutil.AccountKey(accountID, groupName)
|
||||
groupID := utils.GenerateResourceID("pg")
|
||||
groupID := awsidentifiers.GenerateResourceID("pg")
|
||||
|
||||
record := PlacementGroupRecord{
|
||||
GroupId: groupID,
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/paging"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
@@ -489,7 +490,7 @@ func (s *RouteTableServiceImpl) allRouteTablesForVPC(ctx context.Context, accoun
|
||||
// Exported for use by VPC service when creating default VPCs.
|
||||
func (s *RouteTableServiceImpl) CreateRouteTableForVPC(vpcID, vpcCidr, accountID string, isMain bool, rtbID string) (*RouteTableRecord, error) {
|
||||
if rtbID == "" {
|
||||
rtbID = utils.GenerateResourceID("rtb")
|
||||
rtbID = awsidentifiers.GenerateResourceID("rtb")
|
||||
}
|
||||
|
||||
record := RouteTableRecord{
|
||||
@@ -512,7 +513,7 @@ func (s *RouteTableServiceImpl) CreateRouteTableForVPC(vpcID, vpcCidr, accountID
|
||||
if isMain {
|
||||
record.Associations = []AssociationRecord{
|
||||
{
|
||||
AssociationId: utils.GenerateResourceID("rtbassoc"),
|
||||
AssociationId: awsidentifiers.GenerateResourceID("rtbassoc"),
|
||||
Main: true,
|
||||
},
|
||||
}
|
||||
@@ -1020,7 +1021,7 @@ func (s *RouteTableServiceImpl) AssociateRouteTable(ctx context.Context, input *
|
||||
}
|
||||
}
|
||||
|
||||
assocID := utils.GenerateResourceID("rtbassoc")
|
||||
assocID := awsidentifiers.GenerateResourceID("rtbassoc")
|
||||
if err := s.mutateRouteTableCAS(ctx, accountID, rtbID, func(rec *RouteTableRecord) (bool, error) {
|
||||
// Re-check same-table association under the fresh read: a concurrent
|
||||
// associate for this subnet may have landed since the precheck.
|
||||
@@ -1224,7 +1225,7 @@ func (s *RouteTableServiceImpl) ReplaceRouteTableAssociation(ctx context.Context
|
||||
s.publishIGWRouteEventsForAssociation(ctx, accountID, "vpc.delete-igw-route", &oldRecord, assoc.SubnetId)
|
||||
|
||||
// Add to new table with new ID
|
||||
newAssocID := utils.GenerateResourceID("rtbassoc")
|
||||
newAssocID := awsidentifiers.GenerateResourceID("rtbassoc")
|
||||
newRecord.Associations = append(newRecord.Associations, AssociationRecord{
|
||||
AssociationId: newAssocID,
|
||||
SubnetId: assoc.SubnetId,
|
||||
|
||||
@@ -188,7 +188,7 @@ func (s *SnapshotServiceImpl) CreateSnapshot(ctx context.Context, input *ec2.Cre
|
||||
|
||||
slog.InfoContext(ctx, "CreateSnapshot request", "volumeId", volumeID)
|
||||
|
||||
snapshotID := utils.GenerateResourceID("snap")
|
||||
snapshotID := awsidentifiers.GenerateResourceID("snap")
|
||||
if s.provider == nil {
|
||||
slog.ErrorContext(ctx, "no EBS provider configured", "op", "CreateSnapshot")
|
||||
return nil, errors.New(awserrors.ErrorServerInternal)
|
||||
@@ -822,7 +822,7 @@ func (s *SnapshotServiceImpl) CopySnapshot(ctx context.Context, input *ec2.CopyS
|
||||
return nil, errors.New(awserrors.ErrorUnsupportedOperation)
|
||||
}
|
||||
|
||||
newSnapshotID := utils.GenerateResourceID("snap")
|
||||
newSnapshotID := awsidentifiers.GenerateResourceID("snap")
|
||||
copied, err := s.provider.CopySnapshot(ctx, ebsprovider.CopySnapshotRequest{
|
||||
Versioned: ebsprovider.NewVersioned(),
|
||||
SourceSnapshotID: sourceSnapshotID,
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
ebspolicy "github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/policy"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
handlers_ec2_instance "github.com/mulgadc/spinifex/spinifex/handlers/ec2/instance"
|
||||
"github.com/mulgadc/spinifex/spinifex/providers/ebs"
|
||||
@@ -177,7 +178,7 @@ func (s *VolumeServiceImpl) CreateVolume(ctx context.Context, input *ec2.CreateV
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
volumeID := utils.GenerateResourceID("vol")
|
||||
volumeID := awsidentifiers.GenerateResourceID("vol")
|
||||
|
||||
// Honor caller-supplied Iops for gp3, else the 3000 baseline. The ceiling is
|
||||
// min(16000, 500*size) but never below the free baseline, so small volumes
|
||||
|
||||
@@ -603,7 +603,7 @@ func TestApplyRecordTags_Provider_VisibleViaDescribeVolumes(t *testing.T) {
|
||||
// prefixFailingObjectStore fails PutObject for any key under failPrefix and
|
||||
// records the last such key, so a test can recover a randomly generated
|
||||
// resource ID from the write CreateVolume/CreateSnapshot attempted, without
|
||||
// needing to predict utils.GenerateResourceID's output up front.
|
||||
// needing to predict awsidentifiers.GenerateResourceID's output up front.
|
||||
type prefixFailingObjectStore struct {
|
||||
objectstore.ObjectStore
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
)
|
||||
|
||||
@@ -161,11 +161,11 @@ func (s *VPCServiceImpl) proposeDefaultVPC(ctx context.Context, accountID string
|
||||
return fmt.Errorf("allocate VNI for default VPC: %w", err)
|
||||
}
|
||||
claim = &defaultVPCClaim{
|
||||
VpcId: cmp.Or(ids.VpcId, utils.GenerateResourceID("vpc")),
|
||||
SubnetId: cmp.Or(ids.SubnetId, utils.GenerateResourceID("subnet")),
|
||||
GroupId: utils.GenerateResourceID("sg"),
|
||||
RouteTableId: utils.GenerateResourceID("rtb"),
|
||||
InternetGatewayId: cmp.Or(ids.IgwId, utils.GenerateResourceID("igw")),
|
||||
VpcId: cmp.Or(ids.VpcId, awsidentifiers.GenerateResourceID("vpc")),
|
||||
SubnetId: cmp.Or(ids.SubnetId, awsidentifiers.GenerateResourceID("subnet")),
|
||||
GroupId: awsidentifiers.GenerateResourceID("sg"),
|
||||
RouteTableId: awsidentifiers.GenerateResourceID("rtb"),
|
||||
InternetGatewayId: cmp.Or(ids.IgwId, awsidentifiers.GenerateResourceID("igw")),
|
||||
Cidr: DefaultVPCCidr,
|
||||
SubnetCidr: DefaultSubnetCidr,
|
||||
VNI: vni,
|
||||
@@ -202,7 +202,7 @@ func (s *VPCServiceImpl) adoptExistingDefaultVPC(ctx context.Context, accountID
|
||||
|
||||
claim := &defaultVPCClaim{
|
||||
VpcId: vpc.VpcId,
|
||||
InternetGatewayId: cmp.Or(ids.IgwId, utils.GenerateResourceID("igw")),
|
||||
InternetGatewayId: cmp.Or(ids.IgwId, awsidentifiers.GenerateResourceID("igw")),
|
||||
Cidr: vpc.CidrBlock,
|
||||
VNI: vpc.VNI,
|
||||
Complete: true,
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/paging"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
@@ -143,7 +144,7 @@ func (s *VPCServiceImpl) CreateNetworkInterface(ctx context.Context, input *ec2.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
eniId := utils.GenerateResourceID("eni")
|
||||
eniId := awsidentifiers.GenerateResourceID("eni")
|
||||
|
||||
// Allocate IP from subnet, or claim the caller's requested address.
|
||||
var privateIP string
|
||||
@@ -711,7 +712,7 @@ func (s *VPCServiceImpl) attachENI(ctx context.Context, accountID, eniId, instan
|
||||
return "", errors.New(awserrors.ErrorInvalidNetworkInterfaceInUse)
|
||||
}
|
||||
|
||||
attachmentId := utils.GenerateResourceID("eni-attach")
|
||||
attachmentId := awsidentifiers.GenerateResourceID("eni-attach")
|
||||
record.Status = "in-use"
|
||||
record.AttachmentId = attachmentId
|
||||
record.InstanceId = instanceId
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/paging"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
@@ -25,10 +26,10 @@ import (
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
)
|
||||
|
||||
// sgIDRegex must stay in lockstep with utils.GenerateResourceID("sg").
|
||||
// sgIDRegex must stay in lockstep with awsidentifiers.GenerateResourceID("sg").
|
||||
var sgIDRegex = regexp.MustCompile(`^sg-[0-9a-f]{17}$`)
|
||||
|
||||
// SGRuleIDRegex must stay in lockstep with utils.GenerateResourceID("sgr").
|
||||
// SGRuleIDRegex must stay in lockstep with awsidentifiers.GenerateResourceID("sgr").
|
||||
// Exported so the EC2 gateway can validate SecurityGroupRuleIds without
|
||||
// re-implementing the format check.
|
||||
var SGRuleIDRegex = regexp.MustCompile(`^sgr-[0-9a-f]{17}$`)
|
||||
@@ -241,7 +242,7 @@ func (s *VPCServiceImpl) CreateSecurityGroup(ctx context.Context, input *ec2.Cre
|
||||
return nil, errors.New(awserrors.ErrorResourceLimitExceeded)
|
||||
}
|
||||
|
||||
groupId := utils.GenerateResourceID("sg")
|
||||
groupId := awsidentifiers.GenerateResourceID("sg")
|
||||
|
||||
description := ""
|
||||
if input.Description != nil {
|
||||
@@ -250,7 +251,7 @@ func (s *VPCServiceImpl) CreateSecurityGroup(ctx context.Context, input *ec2.Cre
|
||||
|
||||
// Default egress rule: allow all outbound traffic
|
||||
defaultEgress := []SGRule{
|
||||
{RuleId: utils.GenerateResourceID("sgr"), IpProtocol: "-1", FromPort: 0, ToPort: 0, CidrIp: "0.0.0.0/0"},
|
||||
{RuleId: awsidentifiers.GenerateResourceID("sgr"), IpProtocol: "-1", FromPort: 0, ToPort: 0, CidrIp: "0.0.0.0/0"},
|
||||
}
|
||||
|
||||
record := SecurityGroupRecord{
|
||||
@@ -1942,7 +1943,7 @@ func ipPermissionsToSGRules(perms []*ec2.IpPermission, mode sgParseMode) ([]SGRu
|
||||
return nil, err
|
||||
}
|
||||
if mode == sgParseAuthorize {
|
||||
r.RuleId = utils.GenerateResourceID("sgr")
|
||||
r.RuleId = awsidentifiers.GenerateResourceID("sgr")
|
||||
}
|
||||
rules = append(rules, r)
|
||||
appended = true
|
||||
@@ -1960,7 +1961,7 @@ func ipPermissionsToSGRules(perms []*ec2.IpPermission, mode sgParseMode) ([]SGRu
|
||||
return nil, err
|
||||
}
|
||||
if mode == sgParseAuthorize {
|
||||
r.RuleId = utils.GenerateResourceID("sgr")
|
||||
r.RuleId = awsidentifiers.GenerateResourceID("sgr")
|
||||
}
|
||||
rules = append(rules, r)
|
||||
appended = true
|
||||
@@ -1978,7 +1979,7 @@ func ipPermissionsToSGRules(perms []*ec2.IpPermission, mode sgParseMode) ([]SGRu
|
||||
return nil, err
|
||||
}
|
||||
if mode == sgParseAuthorize {
|
||||
r.RuleId = utils.GenerateResourceID("sgr")
|
||||
r.RuleId = awsidentifiers.GenerateResourceID("sgr")
|
||||
}
|
||||
rules = append(rules, r)
|
||||
appended = true
|
||||
@@ -2153,7 +2154,7 @@ func (s *VPCServiceImpl) requestSGEvent(topic string, evt SGEvent) error {
|
||||
// AWS-equivalent rules, bypassing the public-API reserved-name guard. Used by
|
||||
// CreateVpc.
|
||||
func (s *VPCServiceImpl) createDefaultSecurityGroupInternal(ctx context.Context, accountID, vpcId string) (string, error) {
|
||||
record, _, err := s.storeDefaultSecurityGroup(ctx, accountID, vpcId, utils.GenerateResourceID("sg"))
|
||||
record, _, err := s.storeDefaultSecurityGroup(ctx, accountID, vpcId, awsidentifiers.GenerateResourceID("sg"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -2172,10 +2173,10 @@ func (s *VPCServiceImpl) storeDefaultSecurityGroup(ctx context.Context, accountI
|
||||
Description: defaultSecurityGroupDescription,
|
||||
VpcId: vpcId,
|
||||
IngressRules: []SGRule{
|
||||
{RuleId: utils.GenerateResourceID("sgr"), IpProtocol: "-1", FromPort: 0, ToPort: 0, SourceSG: groupId},
|
||||
{RuleId: awsidentifiers.GenerateResourceID("sgr"), IpProtocol: "-1", FromPort: 0, ToPort: 0, SourceSG: groupId},
|
||||
},
|
||||
EgressRules: []SGRule{
|
||||
{RuleId: utils.GenerateResourceID("sgr"), IpProtocol: "-1", FromPort: 0, ToPort: 0, CidrIp: "0.0.0.0/0"},
|
||||
{RuleId: awsidentifiers.GenerateResourceID("sgr"), IpProtocol: "-1", FromPort: 0, ToPort: 0, CidrIp: "0.0.0.0/0"},
|
||||
},
|
||||
Tags: map[string]string{},
|
||||
IsDefault: true,
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/arn"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsfilters "github.com/mulgadc/spinifex/spinifex/foundation/aws/filters"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/paging"
|
||||
awstags "github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
@@ -296,7 +297,7 @@ func (s *VPCServiceImpl) CreateVpc(ctx context.Context, input *ec2.CreateVpcInpu
|
||||
return nil, errors.New(awserrors.ErrorServerInternal)
|
||||
}
|
||||
|
||||
vpcID := utils.GenerateResourceID("vpc")
|
||||
vpcID := awsidentifiers.GenerateResourceID("vpc")
|
||||
|
||||
record := VPCRecord{
|
||||
VpcId: vpcID,
|
||||
@@ -778,7 +779,7 @@ func (s *VPCServiceImpl) CreateSubnet(ctx context.Context, input *ec2.CreateSubn
|
||||
az = s.config.AZ
|
||||
}
|
||||
|
||||
subnetID := utils.GenerateResourceID("subnet")
|
||||
subnetID := awsidentifiers.GenerateResourceID("subnet")
|
||||
|
||||
// Calculate available IPs (total hosts minus AWS reserved: network, router, DNS, future, broadcast)
|
||||
// ones is validated to be 16-28 above, so (32-ones) is always 4-16 and safe for uint conversion
|
||||
@@ -1497,7 +1498,7 @@ func (s *VPCServiceImpl) createMainRouteTable(ctx context.Context, accountID, vp
|
||||
"routeTableId", existing, "vpcId", vpcID, "accountID", accountID)
|
||||
return nil
|
||||
}
|
||||
_, err := s.writeMainRouteTable(ctx, accountID, vpcID, vpcCidr, utils.GenerateResourceID("rtb"))
|
||||
_, err := s.writeMainRouteTable(ctx, accountID, vpcID, vpcCidr, awsidentifiers.GenerateResourceID("rtb"))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1540,7 +1541,7 @@ func (s *VPCServiceImpl) writeMainRouteTable(ctx context.Context, accountID, vpc
|
||||
AssociationId string `json:"association_id"`
|
||||
Main bool `json:"main"`
|
||||
}{
|
||||
{AssociationId: utils.GenerateResourceID("rtbassoc"), Main: true},
|
||||
{AssociationId: awsidentifiers.GenerateResourceID("rtbassoc"), Main: true},
|
||||
},
|
||||
Tags: make(map[string]string),
|
||||
CreatedAt: time.Now(),
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
acmdomain "github.com/mulgadc/spinifex/spinifex/domains/acm"
|
||||
resourcearn "github.com/mulgadc/spinifex/spinifex/foundation/aws/arn"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
|
||||
handlers_dns "github.com/mulgadc/spinifex/spinifex/handlers/dns"
|
||||
@@ -1296,7 +1297,7 @@ func (s *ELBv2ServiceImpl) createLoadBalancer(ctx context.Context, input *elbv2.
|
||||
}
|
||||
}
|
||||
|
||||
lbID := utils.GenerateResourceID("lb")
|
||||
lbID := awsidentifiers.GenerateResourceID("lb")
|
||||
lbArn := resourcearn.FormatELBv2LoadBalancer(s.region, accountID, name, lbID, lbType)
|
||||
arnPathSegment := resourcearn.ELBv2LBPathSegment(lbType)
|
||||
dnsPrefix := ""
|
||||
@@ -1982,7 +1983,7 @@ func (s *ELBv2ServiceImpl) CreateTargetGroup(ctx context.Context, input *elbv2.C
|
||||
hc.Matcher = *input.Matcher.HttpCode
|
||||
}
|
||||
|
||||
tgID := utils.GenerateResourceID("tg")
|
||||
tgID := awsidentifiers.GenerateResourceID("tg")
|
||||
tgArn := resourcearn.FormatELBv2TargetGroup(s.region, accountID, name, tgID)
|
||||
|
||||
tags := tagsFromSDK(input.Tags)
|
||||
@@ -2669,7 +2670,7 @@ func (s *ELBv2ServiceImpl) CreateListener(ctx context.Context, input *elbv2.Crea
|
||||
return nil, err
|
||||
}
|
||||
|
||||
listenerID := utils.GenerateResourceID("lst")
|
||||
listenerID := awsidentifiers.GenerateResourceID("lst")
|
||||
listenerArn := resourcearn.FormatELBv2Listener(s.region, accountID, lb.Name, lb.LoadBalancerID, listenerID, lb.Type)
|
||||
|
||||
var actions []ListenerAction
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/elbv2"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
)
|
||||
|
||||
// Regex guards for rule condition values — rejected at write time so the renderer
|
||||
@@ -78,7 +78,7 @@ func (s *ELBv2ServiceImpl) CreateRule(ctx context.Context, input *elbv2.CreateRu
|
||||
}
|
||||
}
|
||||
|
||||
ruleID := utils.GenerateResourceID("rule")
|
||||
ruleID := awsidentifiers.GenerateResourceID("rule")
|
||||
ruleArn, err := buildRuleArn(listener.ListenerArn, ruleID)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "CreateRule: failed to build ARN", "listenerArn", listener.ListenerArn, "err", err)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// indexIDPattern is a conservative allowlist for anything that reaches a SQL
|
||||
// identifier: utils.GenerateResourceID's own alphabet ("idx-<17 hex>") plus
|
||||
// identifier: awsidentifiers.GenerateResourceID's own alphabet ("idx-<17 hex>") plus
|
||||
// enough headroom that a caller-supplied id still round-trips safely rather
|
||||
// than being silently rejected.
|
||||
var indexIDPattern = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}$`)
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
)
|
||||
|
||||
// Embedder is the local seam for batch text embedding: the same method set
|
||||
@@ -127,7 +127,7 @@ func (s *IngestService) StartIngest(ctx context.Context, accountID, indexID stri
|
||||
|
||||
now := time.Now().UTC()
|
||||
rec := JobRecord{
|
||||
ID: utils.GenerateResourceID("job"),
|
||||
ID: awsidentifiers.GenerateResourceID("job"),
|
||||
IndexID: indexID,
|
||||
DataSourceID: dataSourceID,
|
||||
Source: source,
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
|
||||
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
)
|
||||
|
||||
// The staged master password is encrypted at rest under bootstrap-payloads/{id}
|
||||
@@ -86,7 +86,7 @@ func (s *Service) writeBootstrapPayload(ctx context.Context, kv *kvstore.Bucket,
|
||||
return "", err
|
||||
}
|
||||
keyID := bootstrapKeyID(key)
|
||||
payloadID := utils.GenerateResourceID(bootstrapPayloadIDPrefix)
|
||||
payloadID := awsidentifiers.GenerateResourceID(bootstrapPayloadIDPrefix)
|
||||
|
||||
plaintext, err := json.Marshal(bootstrapPayloadClaims{
|
||||
EnvelopeVersion: bootstrapEnvelopeVersion,
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/rds"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
|
||||
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
@@ -150,7 +151,7 @@ func newDBInstanceRecord(accountID string, req *validatedCreate, placement *endp
|
||||
now := time.Now().UTC()
|
||||
return DBInstanceRecord{
|
||||
DBInstanceIdentifier: req.Identifier,
|
||||
DbiResourceID: utils.GenerateResourceID(dbiResourceIDPrefix),
|
||||
DbiResourceID: awsidentifiers.GenerateResourceID(dbiResourceIDPrefix),
|
||||
AccountID: accountID,
|
||||
Status: StatusCreating,
|
||||
VMGeneration: firstVMGeneration,
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/network/ovn"
|
||||
"github.com/mulgadc/spinifex/spinifex/network/ovn/nbdb"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
)
|
||||
|
||||
// Client implements ovn.Client with in-memory storage for testing.
|
||||
@@ -95,7 +95,7 @@ func (m *Client) CreateLogicalSwitch(_ context.Context, ls *nbdb.LogicalSwitch)
|
||||
return fmt.Errorf("logical switch %q already exists", ls.Name)
|
||||
}
|
||||
if ls.UUID == "" {
|
||||
ls.UUID = utils.GenerateResourceID("ovn")
|
||||
ls.UUID = awsidentifiers.GenerateResourceID("ovn")
|
||||
}
|
||||
stored := *ls
|
||||
m.Switches[ls.Name] = &stored
|
||||
@@ -112,7 +112,7 @@ func (m *Client) EnsureLogicalSwitch(_ context.Context, ls *nbdb.LogicalSwitch)
|
||||
return &result, false, nil
|
||||
}
|
||||
if ls.UUID == "" {
|
||||
ls.UUID = utils.GenerateResourceID("ovn")
|
||||
ls.UUID = awsidentifiers.GenerateResourceID("ovn")
|
||||
}
|
||||
stored := *ls
|
||||
m.Switches[ls.Name] = &stored
|
||||
@@ -164,7 +164,7 @@ func (m *Client) CreateLogicalSwitchPort(_ context.Context, switchName string, l
|
||||
return fmt.Errorf("logical switch port %q already exists", lsp.Name)
|
||||
}
|
||||
if lsp.UUID == "" {
|
||||
lsp.UUID = utils.GenerateResourceID("ovn")
|
||||
lsp.UUID = awsidentifiers.GenerateResourceID("ovn")
|
||||
}
|
||||
stored := *lsp
|
||||
m.Ports[lsp.Name] = &stored
|
||||
@@ -192,7 +192,7 @@ func (m *Client) CreateLogicalSwitchPortInGroups(_ context.Context, switchName s
|
||||
}
|
||||
}
|
||||
if lsp.UUID == "" {
|
||||
lsp.UUID = utils.GenerateResourceID("ovn")
|
||||
lsp.UUID = awsidentifiers.GenerateResourceID("ovn")
|
||||
}
|
||||
stored := *lsp
|
||||
m.Ports[lsp.Name] = &stored
|
||||
@@ -276,7 +276,7 @@ func (m *Client) CreateLogicalRouter(_ context.Context, lr *nbdb.LogicalRouter)
|
||||
return fmt.Errorf("logical router %q already exists", lr.Name)
|
||||
}
|
||||
if lr.UUID == "" {
|
||||
lr.UUID = utils.GenerateResourceID("ovn")
|
||||
lr.UUID = awsidentifiers.GenerateResourceID("ovn")
|
||||
}
|
||||
stored := *lr
|
||||
m.Routers[lr.Name] = &stored
|
||||
@@ -293,7 +293,7 @@ func (m *Client) EnsureLogicalRouter(_ context.Context, lr *nbdb.LogicalRouter)
|
||||
return &result, false, nil
|
||||
}
|
||||
if lr.UUID == "" {
|
||||
lr.UUID = utils.GenerateResourceID("ovn")
|
||||
lr.UUID = awsidentifiers.GenerateResourceID("ovn")
|
||||
}
|
||||
stored := *lr
|
||||
m.Routers[lr.Name] = &stored
|
||||
@@ -357,7 +357,7 @@ func (m *Client) CreateLogicalRouterPort(_ context.Context, routerName string, l
|
||||
return fmt.Errorf("logical router port %q already exists", lrp.Name)
|
||||
}
|
||||
if lrp.UUID == "" {
|
||||
lrp.UUID = utils.GenerateResourceID("ovn")
|
||||
lrp.UUID = awsidentifiers.GenerateResourceID("ovn")
|
||||
}
|
||||
stored := *lrp
|
||||
m.RouterPorts[lrp.Name] = &stored
|
||||
@@ -415,7 +415,7 @@ func (m *Client) CreateDHCPOptions(_ context.Context, opts *nbdb.DHCPOptions) (s
|
||||
m.Mu.Lock()
|
||||
defer m.Mu.Unlock()
|
||||
if opts.UUID == "" {
|
||||
opts.UUID = utils.GenerateResourceID("dhcp")
|
||||
opts.UUID = awsidentifiers.GenerateResourceID("dhcp")
|
||||
}
|
||||
stored := *opts
|
||||
m.DHCPOpts[opts.UUID] = &stored
|
||||
@@ -487,7 +487,7 @@ func (m *Client) AddNAT(_ context.Context, routerName string, nat *nbdb.NAT) err
|
||||
return fmt.Errorf("logical router %q not found", routerName)
|
||||
}
|
||||
if nat.UUID == "" {
|
||||
nat.UUID = utils.GenerateResourceID("nat")
|
||||
nat.UUID = awsidentifiers.GenerateResourceID("nat")
|
||||
}
|
||||
stored := *nat
|
||||
m.NATs[nat.UUID] = &stored
|
||||
@@ -676,7 +676,7 @@ func (m *Client) AddStaticRoute(_ context.Context, routerName string, route *nbd
|
||||
return fmt.Errorf("logical router %q not found", routerName)
|
||||
}
|
||||
if route.UUID == "" {
|
||||
route.UUID = utils.GenerateResourceID("route")
|
||||
route.UUID = awsidentifiers.GenerateResourceID("route")
|
||||
}
|
||||
stored := *route
|
||||
m.StaticRoutes[route.UUID] = &stored
|
||||
@@ -743,7 +743,7 @@ func (m *Client) AddLogicalRouterPolicy(_ context.Context, routerName string, po
|
||||
return fmt.Errorf("logical router %q not found", routerName)
|
||||
}
|
||||
if policy.UUID == "" {
|
||||
policy.UUID = utils.GenerateResourceID("lrp")
|
||||
policy.UUID = awsidentifiers.GenerateResourceID("lrp")
|
||||
}
|
||||
stored := *policy
|
||||
m.LRPolicies[policy.UUID] = &stored
|
||||
@@ -827,7 +827,7 @@ func (m *Client) CreatePortGroup(_ context.Context, name string, ports []string)
|
||||
return fmt.Errorf("port group %q already exists", name)
|
||||
}
|
||||
pg := &nbdb.PortGroup{
|
||||
UUID: utils.GenerateResourceID("pg"),
|
||||
UUID: awsidentifiers.GenerateResourceID("pg"),
|
||||
Name: name,
|
||||
Ports: ports,
|
||||
}
|
||||
@@ -844,7 +844,7 @@ func (m *Client) EnsurePortGroup(_ context.Context, name string, ports []string)
|
||||
return &result, false, nil
|
||||
}
|
||||
pg := &nbdb.PortGroup{
|
||||
UUID: utils.GenerateResourceID("pg"),
|
||||
UUID: awsidentifiers.GenerateResourceID("pg"),
|
||||
Name: name,
|
||||
Ports: ports,
|
||||
}
|
||||
@@ -951,7 +951,7 @@ func (m *Client) EnsureAddressSet(_ context.Context, name string, addresses []st
|
||||
return existing.UUID, nil
|
||||
}
|
||||
as := &nbdb.AddressSet{
|
||||
UUID: utils.GenerateResourceID("as"),
|
||||
UUID: awsidentifiers.GenerateResourceID("as"),
|
||||
Name: name,
|
||||
Addresses: slices.Clone(addresses),
|
||||
}
|
||||
@@ -986,7 +986,7 @@ func (m *Client) AddACLs(_ context.Context, portGroupName string, specs []ovn.AC
|
||||
}
|
||||
for _, spec := range specs {
|
||||
acl := &nbdb.ACL{
|
||||
UUID: utils.GenerateResourceID("acl"),
|
||||
UUID: awsidentifiers.GenerateResourceID("acl"),
|
||||
Direction: spec.Direction,
|
||||
Priority: spec.Priority,
|
||||
Match: spec.Match,
|
||||
@@ -1065,7 +1065,7 @@ func (m *Client) ReplaceACLs(_ context.Context, portGroupName string, specs []ov
|
||||
pg.ACLs = pg.ACLs[:0]
|
||||
for _, spec := range specs {
|
||||
acl := &nbdb.ACL{
|
||||
UUID: utils.GenerateResourceID("acl"),
|
||||
UUID: awsidentifiers.GenerateResourceID("acl"),
|
||||
Direction: spec.Direction,
|
||||
Priority: spec.Priority,
|
||||
Match: spec.Match,
|
||||
@@ -1119,7 +1119,7 @@ func (m *Client) SetGatewayChassis(_ context.Context, lrpName string, chassisNam
|
||||
return nil
|
||||
}
|
||||
gc := &nbdb.GatewayChassis{
|
||||
UUID: utils.GenerateResourceID("gc"),
|
||||
UUID: awsidentifiers.GenerateResourceID("gc"),
|
||||
Name: gcName,
|
||||
ChassisName: chassisName,
|
||||
Priority: priority,
|
||||
@@ -1181,7 +1181,7 @@ func (m *Client) SeedGatewayChassis(lrpName string, gc *nbdb.GatewayChassis) {
|
||||
m.Mu.Lock()
|
||||
defer m.Mu.Unlock()
|
||||
if gc.UUID == "" {
|
||||
gc.UUID = utils.GenerateResourceID("gc")
|
||||
gc.UUID = awsidentifiers.GenerateResourceID("gc")
|
||||
}
|
||||
m.GatewayChassis[gc.UUID] = gc
|
||||
if lrp, ok := m.RouterPorts[lrpName]; ok {
|
||||
|
||||
@@ -18,11 +18,11 @@ import (
|
||||
awss3 "github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/mulgadc/bluebottle/pkg/safecast"
|
||||
viperblocklegacyv1 "github.com/mulgadc/spinifex/contracts/viperblockd/legacy/v1"
|
||||
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
|
||||
"github.com/mulgadc/spinifex/spinifex/providers/ebs"
|
||||
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
|
||||
"github.com/mulgadc/spinifex/spinifex/runtime/compute/nbd"
|
||||
hostprocess "github.com/mulgadc/spinifex/spinifex/runtime/host/process"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
vbtypes "github.com/mulgadc/viperblock/types"
|
||||
"github.com/mulgadc/viperblock/viperblock"
|
||||
"github.com/nats-io/nats.go"
|
||||
@@ -1047,7 +1047,7 @@ func handleCreateSnapshot(ctx context.Context, cfg *Config, nc *nats.Conn, msg *
|
||||
return
|
||||
}
|
||||
|
||||
operationID := utils.GenerateResourceID("op")
|
||||
operationID := awsidentifiers.GenerateResourceID("op")
|
||||
respondProvider(ctx, msg, ebsprovider.CreateSnapshotResponse{
|
||||
Versioned: ebsprovider.NewVersioned(),
|
||||
OperationID: operationID,
|
||||
|
||||
@@ -2,8 +2,6 @@ package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log/slog"
|
||||
@@ -13,17 +11,6 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
)
|
||||
|
||||
// GenerateResourceID generates a unique resource ID with the given prefix.
|
||||
// Format: {prefix}-{17 hex chars} using crypto/rand.
|
||||
func GenerateResourceID(prefix string) string {
|
||||
b := make([]byte, 9)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
//nolint:forbidigo // Continuing after the CSPRNG fails could create predictable resource IDs.
|
||||
panic("crypto/rand failed: " + err.Error())
|
||||
}
|
||||
return prefix + "-" + hex.EncodeToString(b)[:17]
|
||||
}
|
||||
|
||||
// GenerateErrorPayload serializes an ec2.ResponseError with the given code as JSON.
|
||||
func GenerateErrorPayload(code string) (jsonResponse []byte) {
|
||||
return GenerateErrorPayloadWithMessage(code, "")
|
||||
|
||||
@@ -1,39 +1,11 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGenerateResourceID(t *testing.T) {
|
||||
tests := []struct {
|
||||
prefix string
|
||||
}{
|
||||
{"i"},
|
||||
{"r"},
|
||||
{"vol"},
|
||||
{"snap"},
|
||||
{"key"},
|
||||
{"eigw"},
|
||||
{"ami"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.prefix, func(t *testing.T) {
|
||||
id := GenerateResourceID(tt.prefix)
|
||||
assert.True(t, strings.HasPrefix(id, tt.prefix+"-"))
|
||||
// prefix + "-" + 17 hex chars
|
||||
assert.Len(t, id, len(tt.prefix)+1+17)
|
||||
|
||||
// Verify uniqueness
|
||||
id2 := GenerateResourceID(tt.prefix)
|
||||
assert.NotEqual(t, id, id2)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalJsonPayload(t *testing.T) {
|
||||
type TestStruct struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
Reference in New Issue
Block a user