refactor: move account identifiers to aws identifiers

This commit is contained in:
joshsiv-mulga
2026-10-06 11:20:26 +10:00
parent 5ac15bcecb
commit 02e0dd0dc6
104 changed files with 427 additions and 416 deletions
+1 -2
View File
@@ -46,7 +46,6 @@ import (
hostcommand "github.com/mulgadc/spinifex/spinifex/runtime/host/command"
"github.com/mulgadc/spinifex/spinifex/runtime/host/dns"
"github.com/mulgadc/spinifex/spinifex/services/viperblockd/vbwire"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"github.com/pterm/pterm"
@@ -889,7 +888,7 @@ func registerImportedAMISnapshot(store objectstore.ObjectStore, bucket string, a
StartTime: time.Now(),
Description: fmt.Sprintf("Imported AMI volume for %s", ami.Name),
Encrypted: encrypted,
OwnerID: utils.GlobalAccountID,
OwnerID: awsidentifiers.GlobalAccountID,
AvailabilityZone: az,
}
if err := ebsmetadata.NewStore(store, bucket).PutSnapshot(context.Background(), cfg); err != nil {
+4 -5
View File
@@ -26,7 +26,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/gateway/bedrock/hfhub"
"github.com/mulgadc/spinifex/spinifex/providers/ebs"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"github.com/pterm/pterm"
@@ -641,7 +640,7 @@ func registerWeightsSnapshot(store objectstore.ObjectStore, bucket, snapshotID,
StartTime: time.Now(),
Description: fmt.Sprintf("Ochre weights volume %s", volumeID),
Encrypted: encrypted,
OwnerID: utils.GlobalAccountID,
OwnerID: awsidentifiers.GlobalAccountID,
AvailabilityZone: az,
}
if err := ebsmetadata.NewStore(store, bucket).PutSnapshot(context.Background(), cfg); err != nil {
@@ -809,7 +808,7 @@ func materializeWeightsVolume(ctx context.Context, provider ebsprovider.EBSProvi
func newWeightsSnapshotChecker(store objectstore.ObjectStore, bucket string) weightsSnapshotChecker {
metadata := ebsmetadata.NewStore(store, bucket)
return func(ctx context.Context, snapshotID string) (bool, error) {
if _, err := metadata.GetSnapshot(ctx, utils.GlobalAccountID, snapshotID); err != nil {
if _, err := metadata.GetSnapshot(ctx, awsidentifiers.GlobalAccountID, snapshotID); err != nil {
if objectstore.IsNoSuchKeyError(err) {
return false, nil
}
@@ -1012,7 +1011,7 @@ func resolveHFToken(ctx context.Context, cmd *cobra.Command, cfg *config.Cluster
return ""
}
credStore := gateway_bedrock.NewCredentialStore(js, masterKey, nil)
token, ok, err := credStore.Resolve(ctx, utils.GlobalAccountID, vendorHuggingFace)
token, ok, err := credStore.Resolve(ctx, awsidentifiers.GlobalAccountID, vendorHuggingFace)
if err != nil || !ok {
return ""
}
@@ -1099,7 +1098,7 @@ func runOchreCredentialsSet(cmd *cobra.Command, _ []string) {
return
}
if accountID == "" {
accountID = utils.GlobalAccountID
accountID = awsidentifiers.GlobalAccountID
}
token, err := readTokenFromStdin(os.Stdin)
+2 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"os"
"time"
@@ -62,7 +63,7 @@ var applianceTeardownFn = func(ctx context.Context, purgeMetadata bool) error {
defer nc.Close()
_, err = utils.NATSRequest[handlers_ochrevector.TeardownApplianceResponse](ctx, nc,
handlers_ochrevector.SubjectTeardownAppliance, &handlers_ochrevector.TeardownApplianceRequest{PurgeMetadata: purgeMetadata},
applianceTeardownTimeout, utils.GlobalAccountID)
applianceTeardownTimeout, awsidentifiers.GlobalAccountID)
return err
}
+7 -7
View File
@@ -4,12 +4,12 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"os"
"strconv"
"time"
handlers_bedrock "github.com/mulgadc/spinifex/spinifex/handlers/bedrock"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
@@ -122,7 +122,7 @@ func waitForEndpointReady(ctx context.Context, svc handlers_bedrock.EndpointServ
timeout time.Duration, clock endpointWaitClock) (handlers_bedrock.EndpointRecord, time.Duration, error) {
start := clock.now()
for {
out, err := svc.Describe(ctx, &handlers_bedrock.DescribeEndpointInput{ModelID: modelID}, utils.GlobalAccountID)
out, err := svc.Describe(ctx, &handlers_bedrock.DescribeEndpointInput{ModelID: modelID}, awsidentifiers.GlobalAccountID)
if err != nil {
return handlers_bedrock.EndpointRecord{}, clock.now().Sub(start), err
}
@@ -216,7 +216,7 @@ func reclaimRows(rec handlers_bedrock.EndpointRecord) [][2]string {
// shared platform one — List itself now returns every account's records, not
// just the shared platform account's.
func listEndpointsOutput(ctx context.Context, svc handlers_bedrock.EndpointService) (string, error) {
out, err := svc.List(ctx, &handlers_bedrock.ListEndpointsInput{}, utils.GlobalAccountID)
out, err := svc.List(ctx, &handlers_bedrock.ListEndpointsInput{}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", err
}
@@ -239,7 +239,7 @@ func listEndpointsOutput(ctx context.Context, svc handlers_bedrock.EndpointServi
// the endpoint, then optionally wait for it. Returns the message to print.
func runEnsureEndpoint(ctx context.Context, svc handlers_bedrock.EndpointService, modelID string,
wait bool, timeout time.Duration, clock endpointWaitClock) (string, error) {
out, err := svc.Ensure(ctx, &handlers_bedrock.EnsureEndpointInput{ModelID: modelID}, utils.GlobalAccountID)
out, err := svc.Ensure(ctx, &handlers_bedrock.EnsureEndpointInput{ModelID: modelID}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", err
}
@@ -305,7 +305,7 @@ func runOchreEndpointDescribe(cmd *cobra.Command, _ []string) {
}
defer closeFn()
out, err := svc.Describe(context.Background(), &handlers_bedrock.DescribeEndpointInput{ModelID: modelID, AccountID: accountID}, utils.GlobalAccountID)
out, err := svc.Describe(context.Background(), &handlers_bedrock.DescribeEndpointInput{ModelID: modelID, AccountID: accountID}, awsidentifiers.GlobalAccountID)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
ochreExit(1)
@@ -337,7 +337,7 @@ func runOchreEndpointList(_ *cobra.Command, _ []string) {
// no record must not claim a teardown, and it points the operator at --account
// so a pinned, account-scoped record they can see in 'list' is reachable.
func deleteEndpointOutput(ctx context.Context, svc handlers_bedrock.EndpointService, modelID, accountID string) (string, error) {
out, err := svc.Delete(ctx, &handlers_bedrock.DeleteEndpointInput{ModelID: modelID, AccountID: accountID}, utils.GlobalAccountID)
out, err := svc.Delete(ctx, &handlers_bedrock.DeleteEndpointInput{ModelID: modelID, AccountID: accountID}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", err
}
@@ -353,7 +353,7 @@ func deleteEndpointOutput(ctx context.Context, svc handlers_bedrock.EndpointServ
// no-op message names the shared platform account rather than an empty string.
func resolveAccountLabel(accountID string) string {
if accountID == "" {
return utils.GlobalAccountID + " (shared platform)"
return awsidentifiers.GlobalAccountID + " (shared platform)"
}
return accountID
}
+3 -3
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"io"
"net/http"
"net/http/httptest"
@@ -22,7 +23,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/gateway/bedrock/hfhub"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
@@ -471,7 +471,7 @@ func TestResolveHFToken_FallsBackToStoredPlatformCredential(t *testing.T) {
require.NoError(t, handlers_iam.SaveMasterKey(filepath.Join(baseDir, "config", "master.key"), masterKey))
credStore := gateway_bedrock.NewCredentialStore(js, masterKey, nil)
require.NoError(t, credStore.PutCredential(context.Background(), utils.GlobalAccountID, vendorHuggingFace, "hf_stored_token"))
require.NoError(t, credStore.PutCredential(context.Background(), awsidentifiers.GlobalAccountID, vendorHuggingFace, "hf_stored_token"))
cmd := newOchreWeightsPullTestCmd(t, selfHostModelID, testHFRepo, "main", "", "")
cfg := &config.ClusterConfig{Node: "node1", Nodes: map[string]config.Config{"node1": {BaseDir: baseDir}}}
@@ -622,7 +622,7 @@ func TestRunOchreCredentialsSet_RoundTripsAndDefaultsToPlatformAccount(t *testin
verifyJS := testutil.NewJetStream(t, verifyConn)
credStore := gateway_bedrock.NewCredentialStore(verifyJS, masterKey, nil)
token, ok, err := credStore.Resolve(context.Background(), utils.GlobalAccountID, vendorHuggingFace)
token, ok, err := credStore.Resolve(context.Background(), awsidentifiers.GlobalAccountID, vendorHuggingFace)
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, "hf_supersecret", token)
+3 -3
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"io"
"net/http"
"net/http/httptest"
@@ -19,7 +20,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/metadata"
gateway_bedrock "github.com/mulgadc/spinifex/spinifex/gateway/bedrock"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
@@ -1095,7 +1095,7 @@ func TestRegisterWeightsSnapshot_WritesEC2ReadableMetadata(t *testing.T) {
require.NoError(t, registerWeightsSnapshot(store, bucket,
"snap-vol-abc", "vol-abc", 12*bytesPerGiB, "ap-southeast-2a", true))
cfg, err := ebsmetadata.NewStore(store, bucket).GetSnapshot(context.Background(), utils.GlobalAccountID, "snap-vol-abc")
cfg, err := ebsmetadata.NewStore(store, bucket).GetSnapshot(context.Background(), awsidentifiers.GlobalAccountID, "snap-vol-abc")
require.NoError(t, err)
assert.Equal(t, "snap-vol-abc", cfg.SnapshotID)
assert.Equal(t, "vol-abc", cfg.VolumeID)
@@ -1112,7 +1112,7 @@ func TestRegisterWeightsSnapshot_UnencryptedVolume(t *testing.T) {
require.NoError(t, registerWeightsSnapshot(store, "predastore",
"snap-vol-plain", "vol-plain", bytesPerGiB, "ap-southeast-2a", false))
cfg, err := ebsmetadata.NewStore(store, "predastore").GetSnapshot(context.Background(), utils.GlobalAccountID, "snap-vol-plain")
cfg, err := ebsmetadata.NewStore(store, "predastore").GetSnapshot(context.Background(), awsidentifiers.GlobalAccountID, "snap-vol-plain")
require.NoError(t, err)
assert.False(t, cfg.Encrypted)
}
+8 -8
View File
@@ -192,7 +192,7 @@ var backupAccountFn = func(ctx context.Context, accountID string) (*handlers_och
defer nc.Close()
return utils.NATSRequest[handlers_ochrevector.BackupAccountResponse](ctx, nc,
handlers_ochrevector.SubjectBackupAccount, &handlers_ochrevector.BackupAccountRequest{AccountID: accountID},
vectorBackupRestoreTimeout, utils.GlobalAccountID)
vectorBackupRestoreTimeout, awsidentifiers.GlobalAccountID)
}
// restoreAccountFn indirects the NATS call so runRestoreAccount is testable
@@ -205,7 +205,7 @@ var restoreAccountFn = func(ctx context.Context, accountID, objectKey string) er
defer nc.Close()
_, err = utils.NATSRequest[handlers_ochrevector.RestoreAccountResponse](ctx, nc,
handlers_ochrevector.SubjectRestoreAccount, &handlers_ochrevector.RestoreAccountRequest{AccountID: accountID, ObjectKey: objectKey},
vectorBackupRestoreTimeout, utils.GlobalAccountID)
vectorBackupRestoreTimeout, awsidentifiers.GlobalAccountID)
return err
}
@@ -331,7 +331,7 @@ func runIndexCreate(ctx context.Context, svc handlers_ochrevector.VectorService,
Name: name,
Dimension: dimension,
EmbeddingModel: model,
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", err
}
@@ -340,7 +340,7 @@ func runIndexCreate(ctx context.Context, svc handlers_ochrevector.VectorService,
// runIndexDelete is the testable core of 'ochre vector index delete'.
func runIndexDelete(ctx context.Context, svc handlers_ochrevector.VectorService, indexID string) (string, error) {
if _, err := svc.DeleteIndex(ctx, &handlers_ochrevector.DeleteIndexRequest{IndexID: indexID}, utils.GlobalAccountID); err != nil {
if _, err := svc.DeleteIndex(ctx, &handlers_ochrevector.DeleteIndexRequest{IndexID: indexID}, awsidentifiers.GlobalAccountID); err != nil {
return "", err
}
return fmt.Sprintf("✅ Index %s deleted.", indexID), nil
@@ -349,7 +349,7 @@ func runIndexDelete(ctx context.Context, svc handlers_ochrevector.VectorService,
// listIndexesOutput renders 'ochre vector index list'. Split from its Run
// function so it is testable against a fake service with no NATS connection.
func listIndexesOutput(ctx context.Context, svc handlers_ochrevector.VectorService) (string, error) {
out, err := svc.ListIndexes(ctx, &handlers_ochrevector.ListIndexesRequest{}, utils.GlobalAccountID)
out, err := svc.ListIndexes(ctx, &handlers_ochrevector.ListIndexesRequest{}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", err
}
@@ -376,7 +376,7 @@ func runIngest(ctx context.Context, svc handlers_ochrevector.VectorService, inde
ChunkOverlap: chunkOverlap,
Metadata: meta,
},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", err
}
@@ -385,7 +385,7 @@ func runIngest(ctx context.Context, svc handlers_ochrevector.VectorService, inde
// runJobDescribe is the testable core of 'ochre vector job describe'.
func runJobDescribe(ctx context.Context, svc handlers_ochrevector.VectorService, jobID string) (string, error) {
out, err := svc.DescribeJob(ctx, &handlers_ochrevector.DescribeJobRequest{JobID: jobID}, utils.GlobalAccountID)
out, err := svc.DescribeJob(ctx, &handlers_ochrevector.DescribeJobRequest{JobID: jobID}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", err
}
@@ -398,7 +398,7 @@ func runQuery(ctx context.Context, svc handlers_ochrevector.VectorService, index
if err != nil {
return "", err
}
out, err := svc.Query(ctx, &handlers_ochrevector.QueryRequest{IndexID: indexID, Text: text, K: k, Filter: filter}, utils.GlobalAccountID)
out, err := svc.Query(ctx, &handlers_ochrevector.QueryRequest{IndexID: indexID, Text: text, K: k, Filter: filter}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", err
}
@@ -2,11 +2,11 @@ package cmd
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/metadata"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -28,7 +28,7 @@ func TestRegisterImportedAMISnapshot_WritesEC2ReadableMetadata(t *testing.T) {
require.NoError(t, registerImportedAMISnapshot(store, bucket, ami, "ap-southeast-2a", true))
cfg, err := ebsmetadata.NewStore(store, bucket).GetSnapshot(context.Background(), utils.GlobalAccountID, "snap-ami-import01")
cfg, err := ebsmetadata.NewStore(store, bucket).GetSnapshot(context.Background(), awsidentifiers.GlobalAccountID, "snap-ami-import01")
require.NoError(t, err)
assert.Equal(t, "snap-ami-import01", cfg.SnapshotID)
assert.Equal(t, "ami-import01", cfg.VolumeID, "the import path creates the volume under the AMI's own ID")
@@ -37,7 +37,7 @@ func TestRegisterImportedAMISnapshot_WritesEC2ReadableMetadata(t *testing.T) {
assert.Equal(t, "100%", cfg.Progress)
assert.Equal(t, "ap-southeast-2a", cfg.AvailabilityZone)
assert.True(t, cfg.Encrypted)
assert.Equal(t, utils.GlobalAccountID, cfg.OwnerID, "a system-catalog import has no tenant account to own its snapshot")
assert.Equal(t, awsidentifiers.GlobalAccountID, cfg.OwnerID, "a system-catalog import has no tenant account to own its snapshot")
assert.Contains(t, cfg.Description, ami.Name)
}
@@ -49,7 +49,7 @@ func TestRegisterImportedAMISnapshot_UnencryptedVolume(t *testing.T) {
require.NoError(t, registerImportedAMISnapshot(store, "predastore", ami, "ap-southeast-2a", false))
cfg, err := ebsmetadata.NewStore(store, "predastore").GetSnapshot(context.Background(), utils.GlobalAccountID, "snap-ami-plain01")
cfg, err := ebsmetadata.NewStore(store, "predastore").GetSnapshot(context.Background(), awsidentifiers.GlobalAccountID, "snap-ami-plain01")
require.NoError(t, err)
assert.False(t, cfg.Encrypted)
}
+3 -3
View File
@@ -4,13 +4,13 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"strings"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/metadata"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// SystemOwnerAlias is the fixed owner alias written to AMI config on promotion.
@@ -59,7 +59,7 @@ func PromoteSystemImage(store objectstore.ObjectStore, bucket string, opts Promo
return nil, errors.New(awserrors.ErrorServerInternal)
}
if meta.ImageOwnerAlias == "" || !utils.IsAccountID(meta.ImageOwnerAlias) {
if meta.ImageOwnerAlias == "" || !awsidentifiers.IsAccountID(meta.ImageOwnerAlias) {
return nil, fmt.Errorf("%s is already a system-owned AMI (owner: %q); promotion not allowed", opts.ImageID, meta.ImageOwnerAlias)
}
@@ -81,7 +81,7 @@ func PromoteSystemImage(store objectstore.ObjectStore, bucket string, opts Promo
return nil, errors.New(awserrors.ErrorServerInternal)
}
if moveSnapshot {
snap.OwnerID = utils.GlobalAccountID
snap.OwnerID = awsidentifiers.GlobalAccountID
if err := metaStore.PutSnapshot(context.Background(), snap); err != nil {
slog.Error("PromoteSystemImage: write snapshot document under the global account",
"imageId", opts.ImageID, "snapshotId", meta.SnapshotID, "err", err)
+3 -3
View File
@@ -2,6 +2,7 @@ package admin
import (
"bytes"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/aws/aws-sdk-go/aws"
@@ -9,7 +10,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/metadata"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -58,9 +58,9 @@ func TestPromoteSystemImage_MovesSnapshotToGlobalAccount(t *testing.T) {
require.NoError(t, err)
metaStore := ebsmetadata.NewStore(store, testRemoveBucket)
moved, err := metaStore.GetSnapshot(t.Context(), utils.GlobalAccountID, snapID)
moved, err := metaStore.GetSnapshot(t.Context(), awsidentifiers.GlobalAccountID, snapID)
require.NoError(t, err)
assert.Equal(t, utils.GlobalAccountID, moved.OwnerID)
assert.Equal(t, awsidentifiers.GlobalAccountID, moved.OwnerID)
assert.Equal(t, "vol-source-001", moved.VolumeID)
_, err = metaStore.GetSnapshot(t.Context(), testRemoveAccountID, snapID)
+3 -3
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"strings"
"time"
@@ -13,7 +14,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/metadata"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// RemoveImageOpts configures RemoveSystemImage.
@@ -90,7 +90,7 @@ func PreviewRemoveSystemImage(store objectstore.ObjectStore, bucket, imageID str
preview.Name = meta.Name
preview.Owner = meta.ImageOwnerAlias
preview.Created = meta.CreationDate
preview.IsSystemOwned = meta.ImageOwnerAlias != "" && !utils.IsAccountID(meta.ImageOwnerAlias)
preview.IsSystemOwned = meta.ImageOwnerAlias != "" && !awsidentifiers.IsAccountID(meta.ImageOwnerAlias)
case objectstore.IsNoSuchKeyError(configErr):
// Config absent — salvage candidate. Leave ConfigPresent=false.
case errors.Is(configErr, ebsmetadata.ErrCorruptDocument):
@@ -213,7 +213,7 @@ func RemoveSystemImage(store objectstore.ObjectStore, bucket string, opts Remove
}
if configErr == nil && !opts.Force {
if meta.ImageOwnerAlias != "" && utils.IsAccountID(meta.ImageOwnerAlias) {
if meta.ImageOwnerAlias != "" && awsidentifiers.IsAccountID(meta.ImageOwnerAlias) {
return nil, fmt.Errorf("%s is account-owned (%s); use `aws ec2 deregister-image` followed by `aws ec2 delete-snapshot`",
opts.ImageID, meta.ImageOwnerAlias)
}
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"encoding/json"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"github.com/mulgadc/spinifex/spinifex/foundation/netaddr"
"log/slog"
"maps"
@@ -2178,7 +2179,7 @@ func (d *Daemon) startCluster() error {
// (matches AWS: every account has a default VPC with IGW + default SG)
if d.vpcService != nil {
failedDefaultVPCs := map[string]struct{}{}
for _, accountID := range []string{utils.GlobalAccountID, admin.DefaultAccountID()} {
for _, accountID := range []string{awsidentifiers.GlobalAccountID, admin.DefaultAccountID()} {
// Pass bootstrap IDs for the admin account so EnsureDefaultVPC uses
// the same IDs that admin init wrote to [bootstrap] in spinifex.toml.
var opts []handlers_ec2_vpc.BootstrapIDs
+2 -1
View File
@@ -3,6 +3,7 @@ package daemon
import (
"context"
"encoding/json"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"time"
@@ -107,7 +108,7 @@ func (d *Daemon) handleEnsureDefaultVpc(msg *nats.Msg) string {
// in skipAccounts are not touched — used to avoid attaching infrastructure to
// a half-built VPC when EnsureDefaultVPC failed earlier in startup.
func (d *Daemon) ensureDefaultVPCInfrastructure(skipAccounts map[string]struct{}) {
for _, accountID := range []string{utils.GlobalAccountID, admin.DefaultAccountID()} {
for _, accountID := range []string{awsidentifiers.GlobalAccountID, admin.DefaultAccountID()} {
if _, skip := skipAccounts[accountID]; skip {
continue
}
+3 -3
View File
@@ -2,6 +2,7 @@ package daemon
import (
"encoding/json"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"sync"
"testing"
"time"
@@ -13,7 +14,6 @@ import (
handlers_ec2_igw "github.com/mulgadc/spinifex/spinifex/handlers/ec2/igw"
handlers_ec2_routetable "github.com/mulgadc/spinifex/spinifex/handlers/ec2/routetable"
handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -261,7 +261,7 @@ func TestEnsureDefaultVPCInfrastructure_SkipsHalfBuiltAccounts(t *testing.T) {
daemon, _ := createDefaultVPCTestDaemon(t)
adminAccount := admin.DefaultAccountID()
for _, accountID := range []string{utils.GlobalAccountID, adminAccount} {
for _, accountID := range []string{awsidentifiers.GlobalAccountID, adminAccount} {
_, err := daemon.vpcService.EnsureDefaultVPC(accountID)
require.NoError(t, err)
}
@@ -273,7 +273,7 @@ func TestEnsureDefaultVPCInfrastructure_SkipsHalfBuiltAccounts(t *testing.T) {
require.NoError(t, err)
assert.Empty(t, skipped.InternetGateways, "a skipped account must not have infrastructure attached")
built, err := daemon.igwService.DescribeInternetGateways(t.Context(), &ec2.DescribeInternetGatewaysInput{}, utils.GlobalAccountID)
built, err := daemon.igwService.DescribeInternetGateways(t.Context(), &ec2.DescribeInternetGatewaysInput{}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
assert.Len(t, built.InternetGateways, 1)
+1 -1
View File
@@ -84,7 +84,7 @@ func (d *Daemon) LaunchSystemInstance(input *handlers_elbv2.SystemInstanceInput)
if input.BootMode == sysinstance.BootAMI {
return d.launchAMISystemInstance(input)
}
accountID := utils.GlobalAccountID
accountID := awsidentifiers.GlobalAccountID
// ENI account may differ from system account — the ENI is created under
// the caller's account, so lookups/updates must use that account ID.
eniAccountID := resolveENIAccount(input.AccountID, accountID)
+2 -1
View File
@@ -1,6 +1,7 @@
package daemon
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
@@ -14,7 +15,7 @@ func checkInstanceOwnership(nodeID string, msg *nats.Msg, instanceID, ownerAccou
callerAccountID := utils.AccountIDFromMsg(msg)
if ownerAccountID == "" {
if callerAccountID != utils.GlobalAccountID {
if callerAccountID != awsidentifiers.GlobalAccountID {
slog.Warn("Untenanted instance access denied (not root)",
"instanceId", instanceID, "callerAccount", callerAccountID)
respondWithError(nodeID, msg, awserrors.ErrorInvalidInstanceIDNotFound)
@@ -6,10 +6,9 @@ import (
"encoding/json"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strings"
"time"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// SchemaVersion is the document's field generation, and moves independently of
@@ -150,7 +149,7 @@ func AMIKey(imageID string) (string, error) { return key("amis", imageID) }
// untenanted document cannot be written, cannot exist, and never has to be
// read. A transposed (id, account) pair fails here too.
func partitionedKey(kind, accountID, id string) (string, error) {
if !utils.IsAccountID(accountID) {
if !awsidentifiers.IsAccountID(accountID) {
return "", fmt.Errorf("invalid EBS metadata account ID %q", accountID)
}
return key(kind+"/"+accountID, id)
@@ -1,10 +1,10 @@
package ebsmetadata
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"time"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -113,7 +113,7 @@ func TestPartitionedKeysRejectNonAccountOwner(t *testing.T) {
require.Error(t, err)
// The system account is an ordinary account and partitions like any other.
key, err := VolumeKey(utils.GlobalAccountID, "vol-1")
key, err := VolumeKey(awsidentifiers.GlobalAccountID, "vol-1")
require.NoError(t, err)
assert.Equal(t, "spinifex/ebsmetadata/v2/volumes/000000000000/vol-1.json", key)
}
+2 -2
View File
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"io"
"log/slog"
"sync"
@@ -13,7 +14,6 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// Store persists Spinifex-owned metadata documents in the existing object
@@ -192,7 +192,7 @@ func (s *Store) listSnapshotDocuments(ctx context.Context, accountID string, ski
// accountPrefix rejects the same accounts the key builders do, so a listing
// cannot widen to the whole tree by being handed an empty account.
func accountPrefix(kindPrefix, accountID string) (string, error) {
if !utils.IsAccountID(accountID) {
if !awsidentifiers.IsAccountID(accountID) {
return "", fmt.Errorf("invalid EBS metadata account ID %q", accountID)
}
return kindPrefix + accountID + "/", nil
@@ -1,4 +1,4 @@
package utils
package identifiers
// GlobalAccountID is the root/system account ID.
const GlobalAccountID = "000000000000"
@@ -1,4 +1,4 @@
package utils
package identifiers
import (
"testing"
+3 -3
View File
@@ -8,6 +8,7 @@ import (
"encoding/xml"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"io"
"net/http"
"net/http/httptest"
@@ -27,7 +28,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
handlers_sts "github.com/mulgadc/spinifex/spinifex/handlers/sts"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -1367,7 +1367,7 @@ func TestCheckPolicy_RootGlobalAccount_Bypasses(t *testing.T) {
AccessKeyID: testAccessKey,
SecretAccessKey: encryptedSecret,
UserName: "root",
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
Status: "Active",
},
},
@@ -2400,7 +2400,7 @@ func TestCheckPolicy_AssumedRole_ZeroPolicyRole_DenyAll(t *testing.T) {
// other session.
func TestCheckPolicy_AssumedRole_SessionNamedRoot_NoBypass(t *testing.T) {
cred := assumedRoleSessionCred("root",
"arn:aws:iam::"+utils.GlobalAccountID+":role/sneaky-role", utils.GlobalAccountID)
"arn:aws:iam::"+awsidentifiers.GlobalAccountID+":role/sneaky-role", awsidentifiers.GlobalAccountID)
var roleResolved bool
gw := newAssumedRoleEnforcementGateway(t, cred, func(_, roleName string) ([]handlers_iam.PolicyDocument, error) {
roleResolved = true
+2 -2
View File
@@ -5,10 +5,10 @@ import (
"encoding/base64"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strings"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go/jetstream"
)
@@ -78,7 +78,7 @@ func NewModelAccessStore(js jetstream.JetStream) *ModelAccessStore {
// account bypasses grants entirely, matching how handlers_quota exempts it
// from every quota dimension.
func (s *ModelAccessStore) Granted(ctx context.Context, accountID, modelID string) (bool, error) {
if accountID == utils.GlobalAccountID {
if accountID == awsidentifiers.GlobalAccountID {
return true, nil
}
kv, err := s.bucket.KV(ctx)
@@ -7,10 +7,10 @@ package gateway_bedrock
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/aws/aws-sdk-go/service/bedrock"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -21,7 +21,7 @@ import (
type systemBypassInner struct{}
func (systemBypassInner) Granted(_ context.Context, accountID, _ string) (bool, error) {
return accountID == utils.GlobalAccountID, nil
return accountID == awsidentifiers.GlobalAccountID, nil
}
func TestStagedOpenAccessResolver_StagedSelfHostGrantedWithoutInnerGrant(t *testing.T) {
@@ -66,7 +66,7 @@ func TestStagedOpenAccessResolver_ExplicitInnerGrantStillWins(t *testing.T) {
func TestStagedOpenAccessResolver_SystemAccountBypassIntact(t *testing.T) {
r := NewStagedOpenAccessResolver(systemBypassInner{})
granted, err := r.Granted(context.Background(), utils.GlobalAccountID, "nonexistent.model-v1:0")
granted, err := r.Granted(context.Background(), awsidentifiers.GlobalAccountID, "nonexistent.model-v1:0")
require.NoError(t, err)
assert.True(t, granted, "the inner resolver's system-account bypass must still win")
}
+2 -2
View File
@@ -3,11 +3,11 @@ package gateway_bedrock
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -156,7 +156,7 @@ func TestModelAccessStore_SystemAccountBypassesGrants(t *testing.T) {
_, _, js := testutil.StartTestJetStream(t)
store := NewModelAccessStore(js)
granted, err := store.Granted(context.Background(), utils.GlobalAccountID, selfHostTestModel)
granted, err := store.Granted(context.Background(), awsidentifiers.GlobalAccountID, selfHostTestModel)
require.NoError(t, err)
assert.True(t, granted, "the system account must bypass grants")
}
@@ -3,6 +3,7 @@ package gateway_ec2_instance
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"slices"
"strings"
@@ -307,7 +308,7 @@ func lookupPlacementGroupStrategy(ctx context.Context, natsConn *nats.Conn, acco
// isKnownInstanceType checks whether any daemon recognizes the given instance type.
func isKnownInstanceType(ctx context.Context, natsConn *nats.Conn, instanceType string) bool {
result, err := utils.NATSRequest[ec2.DescribeInstanceTypesOutput](ctx, natsConn, "ec2.DescribeInstanceTypes", &ec2.DescribeInstanceTypesInput{}, 3*time.Second, utils.GlobalAccountID)
result, err := utils.NATSRequest[ec2.DescribeInstanceTypesOutput](ctx, natsConn, "ec2.DescribeInstanceTypes", &ec2.DescribeInstanceTypesInput{}, 3*time.Second, awsidentifiers.GlobalAccountID)
if err != nil || result == nil {
return false
}
+4 -4
View File
@@ -2,6 +2,7 @@ package gateway
import (
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strings"
"testing"
"time"
@@ -12,7 +13,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
handlers_sts "github.com/mulgadc/spinifex/spinifex/handlers/sts"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -177,15 +177,15 @@ func TestResolveECRPrincipal_LongLivedUser(t *testing.T) {
func TestResolveECRPrincipal_GlobalRoot(t *testing.T) {
iamSvc := newECRMockIAMService()
seedECRTestUser(iamSvc, utils.GlobalAccountID, "root", ecrPrincipalTestAKID)
seedECRTestUser(iamSvc, awsidentifiers.GlobalAccountID, "root", ecrPrincipalTestAKID)
gw := &GatewayConfig{IAMService: iamSvc}
claims := &ecrauth.Claims{
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
PrincipalType: principalTypeUser,
AccessKeyID: ecrPrincipalTestAKID,
}
claims.Subject = "arn:aws:iam::" + utils.GlobalAccountID + ":root"
claims.Subject = "arn:aws:iam::" + awsidentifiers.GlobalAccountID + ":root"
got, err := gw.resolveECRPrincipal(claims)
require.NoError(t, err)
+2 -2
View File
@@ -5,12 +5,12 @@ import (
"encoding/json"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"slices"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
)
@@ -84,7 +84,7 @@ func AuthorizeInternal(ctx context.Context, natsConn *nats.Conn, action string,
// one — the binding to a cluster is AuthorizeInternal's, and needs NATS.
func requireCPAgent(ctx context.Context, action string, caller Caller) error {
if caller.PrincipalType != principalTypeAssumedRole ||
caller.AccountID != utils.GlobalAccountID ||
caller.AccountID != awsidentifiers.GlobalAccountID ||
caller.RoleName != handlers_eks.CPInstanceRoleName ||
caller.SessionName == "" {
slog.WarnContext(ctx, "EKS: internal route rejected for non-CP-agent caller",
+5 -5
View File
@@ -1,13 +1,13 @@
package gateway_eks_test
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
gateway_eks "github.com/mulgadc/spinifex/spinifex/gateway/eks"
handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"github.com/stretchr/testify/assert"
@@ -28,7 +28,7 @@ const (
// cpAgent is the principal an IMDS-credentialed control-plane VM presents.
func cpAgent(instanceID string) gateway_eks.Caller {
return gateway_eks.Caller{
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
PrincipalType: principalTypeAssumedRole,
RoleName: handlers_eks.CPInstanceRoleName,
SessionName: instanceID,
@@ -71,16 +71,16 @@ func TestAuthorizeInternal_RejectsNonCPPrincipals(t *testing.T) {
SessionName: cpInstanceID,
}},
{"system user, not a role session", gateway_eks.Caller{
AccountID: utils.GlobalAccountID, PrincipalType: "user", SessionName: "root",
AccountID: awsidentifiers.GlobalAccountID, PrincipalType: "user", SessionName: "root",
}},
{"another role in the system account", gateway_eks.Caller{
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
PrincipalType: principalTypeAssumedRole,
RoleName: "spinifex-rds-instance",
SessionName: cpInstanceID,
}},
{"no session name", gateway_eks.Caller{
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
PrincipalType: principalTypeAssumedRole,
RoleName: handlers_eks.CPInstanceRoleName,
}},
+4 -4
View File
@@ -5,6 +5,7 @@ package gateway
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"net/http"
"net/http/httptest"
"net/url"
@@ -16,7 +17,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
gateway_eks "github.com/mulgadc/spinifex/spinifex/gateway/eks"
handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go/jetstream"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -180,13 +180,13 @@ func dispatchEKSAsCPAgent(t *testing.T, gw *GatewayConfig, path, instanceID stri
roleName := handlers_eks.CPInstanceRoleName
req := httptest.NewRequest(http.MethodGet, path, nil)
ctx := context.WithValue(req.Context(), ctxService, "eks")
ctx = context.WithValue(ctx, ctxAccountID, utils.GlobalAccountID)
ctx = context.WithValue(ctx, ctxAccountID, awsidentifiers.GlobalAccountID)
ctx = context.WithValue(ctx, ctxIdentity, instanceID)
ctx = context.WithValue(ctx, ctxPrincipalType, principalTypeAssumedRole)
ctx = context.WithValue(ctx, ctxUnderlyingRoleARN,
"arn:aws:iam::"+utils.GlobalAccountID+":role/"+roleName)
"arn:aws:iam::"+awsidentifiers.GlobalAccountID+":role/"+roleName)
ctx = context.WithValue(ctx, ctxAssumedRoleARN,
"arn:aws:sts::"+utils.GlobalAccountID+":assumed-role/"+roleName+"/"+instanceID)
"arn:aws:sts::"+awsidentifiers.GlobalAccountID+":assumed-role/"+roleName+"/"+instanceID)
return gw.EKS_Request(httptest.NewRecorder(), req.WithContext(ctx))
}
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"encoding/xml"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"io"
"log/slog"
"maps"
@@ -777,7 +778,7 @@ func (gw *GatewayConfig) evaluatePrincipalPolicyResources(
switch principal.principalType {
case principalTypeUser:
if principal.identity == "root" && principal.accountID == utils.GlobalAccountID {
if principal.identity == "root" && principal.accountID == awsidentifiers.GlobalAccountID {
// Global root bypass — user branch only.
return nil
}
+7 -7
View File
@@ -3,6 +3,7 @@ package gateway_rds
import (
"context"
"encoding/json"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strings"
"testing"
"time"
@@ -11,7 +12,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
awsxml "github.com/mulgadc/spinifex/spinifex/foundation/aws/xml"
handlers_rds "github.com/mulgadc/spinifex/spinifex/handlers/rds"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -26,7 +26,7 @@ const (
// session under the system account whose session name is its own instance ID.
func agentCaller() Caller {
return Caller{
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
PrincipalType: principalTypeAssumedRole,
RoleName: handlers_rds.InstanceRoleName,
SessionName: testInstanceID,
@@ -72,12 +72,12 @@ func TestAuthorizeAgent_RejectsNonAgentCallers(t *testing.T) {
name string
caller Caller
}{
{"plain IAM user", Caller{AccountID: utils.GlobalAccountID, PrincipalType: "user", RoleName: handlers_rds.InstanceRoleName, SessionName: testInstanceID}},
{"root", Caller{AccountID: utils.GlobalAccountID, PrincipalType: "root", RoleName: handlers_rds.InstanceRoleName, SessionName: testInstanceID}},
{"plain IAM user", Caller{AccountID: awsidentifiers.GlobalAccountID, PrincipalType: "user", RoleName: handlers_rds.InstanceRoleName, SessionName: testInstanceID}},
{"root", Caller{AccountID: awsidentifiers.GlobalAccountID, PrincipalType: "root", RoleName: handlers_rds.InstanceRoleName, SessionName: testInstanceID}},
{"customer account", Caller{AccountID: testAccountID, PrincipalType: principalTypeAssumedRole, RoleName: handlers_rds.InstanceRoleName, SessionName: testInstanceID}},
{"another role", Caller{AccountID: utils.GlobalAccountID, PrincipalType: principalTypeAssumedRole, RoleName: "ecsInstanceRole", SessionName: testInstanceID}},
{"unresolvable role", Caller{AccountID: utils.GlobalAccountID, PrincipalType: principalTypeAssumedRole, RoleName: "", SessionName: testInstanceID}},
{"no session name", Caller{AccountID: utils.GlobalAccountID, PrincipalType: principalTypeAssumedRole, RoleName: handlers_rds.InstanceRoleName, SessionName: ""}},
{"another role", Caller{AccountID: awsidentifiers.GlobalAccountID, PrincipalType: principalTypeAssumedRole, RoleName: "ecsInstanceRole", SessionName: testInstanceID}},
{"unresolvable role", Caller{AccountID: awsidentifiers.GlobalAccountID, PrincipalType: principalTypeAssumedRole, RoleName: "", SessionName: testInstanceID}},
{"no session name", Caller{AccountID: awsidentifiers.GlobalAccountID, PrincipalType: principalTypeAssumedRole, RoleName: handlers_rds.InstanceRoleName, SessionName: ""}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+2 -2
View File
@@ -3,11 +3,11 @@ package gateway_rds
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_rds "github.com/mulgadc/spinifex/spinifex/handlers/rds"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// The resource a policy check evaluates against when the request names nothing
@@ -51,7 +51,7 @@ func AuthorizeCaller(ctx context.Context, action string, caller Caller) error {
// binding to a specific DB instance is authorizeAgent's, and needs NATS.
func requireAgentPrincipal(ctx context.Context, caller Caller) error {
if caller.PrincipalType != principalTypeAssumedRole ||
caller.AccountID != utils.GlobalAccountID ||
caller.AccountID != awsidentifiers.GlobalAccountID ||
caller.RoleName != handlers_rds.InstanceRoleName ||
caller.SessionName == "" {
slog.DebugContext(ctx, "RDS: internal action rejected for non-agent caller",
+3 -3
View File
@@ -1,6 +1,7 @@
package gateway_rds
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"slices"
"testing"
@@ -8,7 +9,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/policy"
handlers_rds "github.com/mulgadc/spinifex/spinifex/handlers/rds"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -46,11 +46,11 @@ func TestAuthorizeCaller_DeniesInternalActionsToCustomers(t *testing.T) {
RoleName: handlers_rds.InstanceRoleName, SessionName: testInstanceID,
}},
{"system user rather than a session", Caller{
AccountID: utils.GlobalAccountID, PrincipalType: "user",
AccountID: awsidentifiers.GlobalAccountID, PrincipalType: "user",
RoleName: handlers_rds.InstanceRoleName, SessionName: testInstanceID,
}},
{"system session under another role", Caller{
AccountID: utils.GlobalAccountID, PrincipalType: principalTypeAssumedRole,
AccountID: awsidentifiers.GlobalAccountID, PrincipalType: principalTypeAssumedRole,
RoleName: "ecsInstanceRole", SessionName: testInstanceID,
}},
}
+2 -2
View File
@@ -3,6 +3,7 @@ package gateway_rds
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"strconv"
"strings"
@@ -13,7 +14,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
gateway_ec2_instance "github.com/mulgadc/spinifex/spinifex/gateway/ec2/instance"
handlers_rds "github.com/mulgadc/spinifex/spinifex/handlers/rds"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
)
@@ -146,7 +146,7 @@ func DescribeOrderableDBInstanceOptions(ctx context.Context, input *rds.Describe
// collapse both onto the same answer.
func clusterRunnableTypes(ctx context.Context, nc *nats.Conn, env Env) (func(string) bool, error) {
out, err := gateway_ec2_instance.DescribeInstanceTypes(ctx, &ec2.DescribeInstanceTypesInput{},
nc, env.ExpectedNodes, nil, utils.GlobalAccountID)
nc, env.ExpectedNodes, nil, awsidentifiers.GlobalAccountID)
if err != nil {
slog.ErrorContext(ctx, "RDS: instance-type capability probe failed", "err", err)
return nil, errors.New(awserrors.ErrorServerInternal)
+4 -4
View File
@@ -3,6 +3,7 @@ package gateway
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"net/http"
"net/http/httptest"
"strings"
@@ -12,7 +13,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
handlers_rds "github.com/mulgadc/spinifex/spinifex/handlers/rds"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -40,13 +40,13 @@ func setupRDSUserRequest(body, accountID string) *http.Request {
// whose underlying role is the DB VM instance role.
func setupRDSAgentRequest(body, sessionName string) *http.Request {
req := setupRDSRequest(body)
roleARN := "arn:aws:iam::" + utils.GlobalAccountID + ":role/" + handlers_rds.InstanceRoleName
ctx := context.WithValue(req.Context(), ctxAccountID, utils.GlobalAccountID)
roleARN := "arn:aws:iam::" + awsidentifiers.GlobalAccountID + ":role/" + handlers_rds.InstanceRoleName
ctx := context.WithValue(req.Context(), ctxAccountID, awsidentifiers.GlobalAccountID)
ctx = context.WithValue(ctx, ctxIdentity, sessionName)
ctx = context.WithValue(ctx, ctxPrincipalType, principalTypeAssumedRole)
ctx = context.WithValue(ctx, ctxUnderlyingRoleARN, roleARN)
ctx = context.WithValue(ctx, ctxAssumedRoleARN,
"arn:aws:sts::"+utils.GlobalAccountID+":assumed-role/"+handlers_rds.InstanceRoleName+"/"+sessionName)
"arn:aws:sts::"+awsidentifiers.GlobalAccountID+":assumed-role/"+handlers_rds.InstanceRoleName+"/"+sessionName)
return req.WithContext(ctx)
}
+2 -2
View File
@@ -2,6 +2,7 @@ package gateway
import (
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"net/http"
@@ -13,7 +14,6 @@ import (
gateway_sts "github.com/mulgadc/spinifex/spinifex/gateway/sts"
handlers_sts "github.com/mulgadc/spinifex/spinifex/handlers/sts"
"github.com/mulgadc/spinifex/spinifex/ingress/aws/query"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// stsCaller bundles the SigV4-derived caller fields that any STS action may
@@ -225,7 +225,7 @@ func buildCallerARN(accountID, identity, principalType, assumedRoleARN string) (
case principalTypeRoot:
return spxarn.FormatIAMRoot(accountID), nil
case principalTypeUser:
if identity == "root" && accountID == utils.GlobalAccountID {
if identity == "root" && accountID == awsidentifiers.GlobalAccountID {
return spxarn.FormatIAMRoot(accountID), nil
}
if identity == "" {
+3 -3
View File
@@ -6,6 +6,7 @@ package gateway
import (
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"io"
"net/http"
"net/http/httptest"
@@ -17,7 +18,6 @@ import (
"github.com/aws/aws-sdk-go/service/sts"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -102,7 +102,7 @@ func stsPolicyRequest(t *testing.T, iamSvc handlers_iam.IAMService, stsSvc *flex
stsSvc = deniedSTSService(t)
}
return stsPolicyRequestAs(t, stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "alice",
principalType: principalTypeUser,
accessKey: "AKIAEXAMPLE",
@@ -168,7 +168,7 @@ func TestSTSRequest_AssumeRole_AssumedRoleCallerIsGated(t *testing.T) {
body := "Action=AssumeRole&RoleArn=" + stsTestRoleARN + "&RoleSessionName=s1"
params := func(iamSvc handlers_iam.IAMService, stsSvc *flexMockSTSService) stsRequestParams {
return stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "s1",
principalType: principalTypeAssumedRole,
accessKey: "ASIAEXAMPLE",
+13 -13
View File
@@ -3,6 +3,7 @@ package gateway
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"io"
"net/http"
"net/http/httptest"
@@ -15,7 +16,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
handlers_sts "github.com/mulgadc/spinifex/spinifex/handlers/sts"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -141,7 +141,7 @@ func TestSTSRequest_AssumeRole_Success(t *testing.T) {
},
}
handler := setupSTSRequestHandler(stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "alice",
principalType: principalTypeUser,
accessKey: "AKIAEXAMPLE",
@@ -172,7 +172,7 @@ func TestSTSRequest_GetCallerIdentity_AssumedRole(t *testing.T) {
},
}
handler := setupSTSRequestHandler(stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "s1",
principalType: principalTypeAssumedRole,
accessKey: "ASIAEXAMPLE",
@@ -197,7 +197,7 @@ func TestSTSRequest_GetCallerIdentity_AssumedRole(t *testing.T) {
func TestSTSRequest_GetCallerIdentity_RootShortcircuitsIAMLookup(t *testing.T) {
// Root short-circuits IAM lookup — flexMockIAMService.GetUser would cause InternalError otherwise.
handler := setupSTSRequestHandler(stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "root",
principalType: principalTypeUser,
accessKey: "AKIAROOT",
@@ -241,7 +241,7 @@ func TestSTSRequest_GetSessionToken_Success(t *testing.T) {
},
}
handler := setupSTSRequestHandler(stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "alice",
principalType: principalTypeUser,
accessKey: "AKIAEXAMPLE",
@@ -261,7 +261,7 @@ func TestSTSRequest_GetSessionToken_Success(t *testing.T) {
assert.Contains(t, xmlStr, "ASIAEXAMPLE123")
// Verify forwarded identity fields and that checkPolicy did not block (STS_Request runs no checkPolicy pass).
assert.Equal(t, utils.GlobalAccountID, got.accountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, got.accountID)
assert.Equal(t, "alice", got.userName)
assert.Equal(t, principalTypeUser, got.principalType)
assert.Equal(t, "AKIAEXAMPLE", got.accessKeyID)
@@ -270,7 +270,7 @@ func TestSTSRequest_GetSessionToken_Success(t *testing.T) {
func TestSTSRequest_UnknownAction(t *testing.T) {
handler := setupSTSRequestHandler(stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "root",
principalType: principalTypeUser,
accessKey: "AKIAROOT",
@@ -288,7 +288,7 @@ func TestSTSRequest_UnknownAction(t *testing.T) {
func TestSTSRequest_MissingAction(t *testing.T) {
handler := setupSTSRequestHandler(stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "root",
principalType: principalTypeUser,
accessKey: "AKIAROOT",
@@ -312,7 +312,7 @@ func TestSTSRequest_AssumeRole_MissingRoleArn(t *testing.T) {
},
}
handler := setupSTSRequestHandler(stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "alice",
principalType: principalTypeUser,
accessKey: "AKIAEXAMPLE",
@@ -336,7 +336,7 @@ func TestSTSRequest_NilService_InternalError(t *testing.T) {
gw := &GatewayConfig{DisableLogging: true, STSService: nil, IAMService: &flexMockIAMService{}}
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), ctxService, "sts")
ctx = context.WithValue(ctx, ctxAccountID, utils.GlobalAccountID)
ctx = context.WithValue(ctx, ctxAccountID, awsidentifiers.GlobalAccountID)
ctx = context.WithValue(ctx, ctxIdentity, "alice")
ctx = context.WithValue(ctx, ctxPrincipalType, principalTypeUser)
ctx = context.WithValue(ctx, ctxAccessKey, "AKIAEXAMPLE")
@@ -368,7 +368,7 @@ func TestSTSRequest_AssumeRole_NilIAMService_InternalError(t *testing.T) {
gw := &GatewayConfig{DisableLogging: true, STSService: svc, IAMService: nil}
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), ctxService, "sts")
ctx = context.WithValue(ctx, ctxAccountID, utils.GlobalAccountID)
ctx = context.WithValue(ctx, ctxAccountID, awsidentifiers.GlobalAccountID)
ctx = context.WithValue(ctx, ctxIdentity, "alice")
ctx = context.WithValue(ctx, ctxPrincipalType, principalTypeUser)
ctx = context.WithValue(ctx, ctxAccessKey, "AKIAEXAMPLE")
@@ -396,7 +396,7 @@ func TestSTSRequest_AssumeRole_ServiceError_PropagatesAccessDenied(t *testing.T)
},
}
handler := setupSTSRequestHandler(stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "alice",
principalType: principalTypeUser,
accessKey: "AKIAEXAMPLE",
@@ -423,7 +423,7 @@ func TestSTSRequest_GetCallerIdentity_User_LookupIAM(t *testing.T) {
},
}
handler := setupSTSRequestHandler(stsRequestParams{
accountID: utils.GlobalAccountID,
accountID: awsidentifiers.GlobalAccountID,
identity: "alice",
principalType: principalTypeUser,
accessKey: "AKIAEXAMPLE",
+2 -2
View File
@@ -4,13 +4,13 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
awsami "github.com/mulgadc/spinifex/spinifex/foundation/aws/ami"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// servingAMIRoleTag identifies the single vllm-serving runtime AMI, the same
@@ -36,7 +36,7 @@ func resolveServingAMI(ctx context.Context, imgSvc amiResolver) (string, error)
{Name: aws.String("tag:" + tags.ManagedByKey), Values: aws.StringSlice([]string{tags.ManagedByBedrock})},
{Name: aws.String("tag:" + servingAMIRoleTag), Values: aws.StringSlice([]string{"vllm-serving"})},
},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", fmt.Errorf("bedrock: describe vllm-serving AMI: %w", err)
}
+4 -4
View File
@@ -1,13 +1,13 @@
package handlers_bedrock
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"net/http"
"testing"
"time"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/gpu"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -213,7 +213,7 @@ func TestSelectEvictable_SkipsRecordCreatedPinnedViaEnsure(t *testing.T) {
func seedReadyEndpoint(t *testing.T, s *Service, modelID string, readyAt time.Time) EndpointRecord {
t.Helper()
rec := EndpointRecord{
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
ModelID: modelID,
State: StateReady,
NodeID: s.deps.NodeID,
@@ -222,14 +222,14 @@ func seedReadyEndpoint(t *testing.T, s *Service, modelID string, readyAt time.Ti
ReadyAt: readyAt,
Generation: 2,
}
_, err := s.store.Create(t.Context(), EndpointKey(utils.GlobalAccountID, modelID), &rec)
_, err := s.store.Create(t.Context(), EndpointKey(awsidentifiers.GlobalAccountID, modelID), &rec)
require.NoError(t, err)
return rec
}
func pinEndpoint(t *testing.T, s *Service, modelID string) {
t.Helper()
key := EndpointKey(utils.GlobalAccountID, modelID)
key := EndpointKey(awsidentifiers.GlobalAccountID, modelID)
rec, rev, found, err := s.store.getRevision(t.Context(), key)
require.NoError(t, err)
require.True(t, found)
+3 -3
View File
@@ -4,13 +4,13 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"net/netip"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// The system-VPC subnet lives inside OVN on br-int, so the daemon host has no
@@ -86,7 +86,7 @@ func ensureDaemonENI(ctx context.Context, vpcSvc launchVPCProvisioner, subnetID,
{Name: aws.String("subnet-id"), Values: aws.StringSlice([]string{subnetID})},
{Name: aws.String("description"), Values: aws.StringSlice([]string{desc})},
},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return nil, fmt.Errorf("bedrock: describe daemon ENI in subnet %s: %w", subnetID, err)
}
@@ -118,7 +118,7 @@ func ensureDaemonENI(ctx context.Context, vpcSvc launchVPCProvisioner, subnetID,
{Key: aws.String(bedrockDaemonNodeTagKey), Value: aws.String(nodeID)},
},
}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return nil, fmt.Errorf("bedrock: create daemon ENI in subnet %s: %w", subnetID, err)
}
+10 -10
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"net"
"slices"
@@ -18,7 +19,6 @@ import (
gateway_bedrock "github.com/mulgadc/spinifex/spinifex/gateway/bedrock"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
handlers_systemvpc "github.com/mulgadc/spinifex/spinifex/handlers/systemvpc"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// vllmServePort is the vLLM OpenAI-compatible server's listen port, baked
@@ -211,7 +211,7 @@ func LaunchServingVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (out
snapshotIDs[m.ModelID] = snapshotID
}
sysRefs, err := EnsureSystemVPC(ctx, deps.SystemVPC, &deps.Config.Bedrock, utils.GlobalAccountID, region)
sysRefs, err := EnsureSystemVPC(ctx, deps.SystemVPC, &deps.Config.Bedrock, awsidentifiers.GlobalAccountID, region)
if err != nil {
return nil, err
}
@@ -272,7 +272,7 @@ func LaunchServingVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (out
}
volumeIDs[m.ModelID] = weightsVolumeID
rollback = append(rollback, func(ctx context.Context) {
if _, delErr := deps.Volume.DeleteVolume(ctx, &ec2.DeleteVolumeInput{VolumeId: aws.String(weightsVolumeID)}, utils.GlobalAccountID); delErr != nil {
if _, delErr := deps.Volume.DeleteVolume(ctx, &ec2.DeleteVolumeInput{VolumeId: aws.String(weightsVolumeID)}, awsidentifiers.GlobalAccountID); delErr != nil {
slog.WarnContext(ctx, "bedrock: rollback delete of orphaned weights volume failed",
"model", m.ModelID, "volumeId", weightsVolumeID, "err", delErr)
}
@@ -300,7 +300,7 @@ func LaunchServingVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (out
// The VM and its primary NIC live in the system account: a serving VM
// has no customer owner of its own, only the accountID the endpoint
// record is keyed under (a separate, KV-level concern from VM ownership).
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
SubnetID: systemSubnetID,
ENIID: eni.id,
ENIMac: eni.mac,
@@ -326,7 +326,7 @@ func LaunchServingVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (out
primaryModelID := in.Members[0].ModelID
for _, m := range in.Members {
weightsVolumeID := volumeIDs[m.ModelID]
attachedDevice, err := deps.Attacher.AttachVolume(ctx, utils.GlobalAccountID, instanceID, weightsVolumeID, devices[m.ModelID])
attachedDevice, err := deps.Attacher.AttachVolume(ctx, awsidentifiers.GlobalAccountID, instanceID, weightsVolumeID, devices[m.ModelID])
if err != nil {
return nil, fmt.Errorf("bedrock: attach weights volume %s to %s: %w", weightsVolumeID, instanceID, err)
}
@@ -373,7 +373,7 @@ func TerminateServingVM(ctx context.Context, deps LaunchDeps, rec EndpointRecord
if member.WeightsVolumeID == "" {
continue
}
if _, err := deps.Volume.DeleteVolume(ctx, &ec2.DeleteVolumeInput{VolumeId: aws.String(member.WeightsVolumeID)}, utils.GlobalAccountID); err != nil &&
if _, err := deps.Volume.DeleteVolume(ctx, &ec2.DeleteVolumeInput{VolumeId: aws.String(member.WeightsVolumeID)}, awsidentifiers.GlobalAccountID); err != nil &&
!awserrors.IsNotFound(err) {
errs = append(errs, fmt.Errorf("delete weights volume %s for %s: %w", member.WeightsVolumeID, modelID, err))
}
@@ -417,7 +417,7 @@ func createLaunchENI(ctx context.Context, vpcSvc launchVPCProvisioner, subnetID,
{Key: aws.String(bedrockInstanceTagKey), Value: aws.String(modelID)},
},
}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return nil, fmt.Errorf("bedrock: create ENI in subnet %s: %w", subnetID, err)
}
@@ -437,12 +437,12 @@ func createLaunchENI(ctx context.Context, vpcSvc launchVPCProvisioner, subnetID,
// Detach comes first because a terminated VM can leave the attachment record
// behind, which a plain delete rejects as InUse.
func deleteLaunchENI(ctx context.Context, vpcSvc launchVPCProvisioner, eniID string) {
if err := vpcSvc.DetachENI(ctx, utils.GlobalAccountID, eniID); err != nil && !awserrors.IsNotFound(err) {
if err := vpcSvc.DetachENI(ctx, awsidentifiers.GlobalAccountID, eniID); err != nil && !awserrors.IsNotFound(err) {
slog.DebugContext(ctx, "bedrock: rollback ENI detach failed", "eniId", eniID, "err", err)
}
if _, err := vpcSvc.DeleteNetworkInterface(ctx, &ec2.DeleteNetworkInterfaceInput{
NetworkInterfaceId: aws.String(eniID),
}, utils.GlobalAccountID); err != nil && !awserrors.IsNotFound(err) {
}, awsidentifiers.GlobalAccountID); err != nil && !awserrors.IsNotFound(err) {
slog.WarnContext(ctx, "bedrock: rollback delete of orphaned ENI failed", "eniId", eniID, "err", err)
}
}
@@ -462,7 +462,7 @@ func createWeightsVolume(ctx context.Context, volSvc launchVolumeProvisioner, az
{Key: aws.String(bedrockInstanceTagKey), Value: aws.String(modelID)},
},
}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", fmt.Errorf("bedrock: clone weights volume for %s from snapshot %s: %w", modelID, snapshotID, err)
}
+6 -6
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"time"
@@ -11,7 +12,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
"github.com/mulgadc/spinifex/spinifex/foundation/telemetry"
gateway_bedrock "github.com/mulgadc/spinifex/spinifex/gateway/bedrock"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// Sweep and lease timing. The holder refreshes well inside the bucket's TTL,
@@ -127,7 +127,7 @@ func (r *Reaper) IsLeader() bool {
// sweepOnce scrapes every READY endpoint once and acts on what it saw. One
// endpoint's failure does not stop the pass: the others still need deciding.
func (r *Reaper) sweepOnce(ctx context.Context) error {
recs, err := r.svc.store.list(ctx, utils.GlobalAccountID)
recs, err := r.svc.store.list(ctx, awsidentifiers.GlobalAccountID)
if err != nil {
return err
}
@@ -191,7 +191,7 @@ func (r *Reaper) sweepEndpoint(ctx context.Context, rec EndpointRecord) error {
slog.InfoContext(ctx, "bedrock reaper: reclaiming an idle endpoint",
"model", rec.ModelID, "instanceId", rec.InstanceID,
"idle_ms", otelsetup.Millis(now.Sub(updated.LastActive())))
if _, err := r.svc.Delete(ctx, &DeleteEndpointInput{ModelID: rec.ModelID}, utils.GlobalAccountID); err != nil {
if _, err := r.svc.Delete(ctx, &DeleteEndpointInput{ModelID: rec.ModelID}, awsidentifiers.GlobalAccountID); err != nil {
return fmt.Errorf("reap idle endpoint: %w", err)
}
return nil
@@ -254,13 +254,13 @@ func (r *Reaper) recordScrapeFailure(ctx context.Context, rec EndpointRecord, ca
slog.ErrorContext(ctx, "bedrock reaper: endpoint unreachable; terminating and relaunching",
"model", rec.ModelID, "instanceId", rec.InstanceID,
"consecutiveFailures", updated.ScrapeFailures, "err", cause)
if _, err := r.svc.Delete(ctx, &DeleteEndpointInput{ModelID: rec.ModelID}, utils.GlobalAccountID); err != nil {
if _, err := r.svc.Delete(ctx, &DeleteEndpointInput{ModelID: rec.ModelID}, awsidentifiers.GlobalAccountID); err != nil {
return fmt.Errorf("terminate unreachable endpoint: %w", err)
}
// A relaunch that cannot be admitted (the device did not come back, or
// another model took it) is not a sweep failure: the endpoint is gone, which
// was the point, and the next invoke will ask for it again.
if _, err := r.svc.Ensure(ctx, &EnsureEndpointInput{ModelID: rec.ModelID}, utils.GlobalAccountID); err != nil {
if _, err := r.svc.Ensure(ctx, &EnsureEndpointInput{ModelID: rec.ModelID}, awsidentifiers.GlobalAccountID); err != nil {
slog.WarnContext(ctx, "bedrock reaper: relaunch of an unreachable endpoint was refused",
"model", rec.ModelID, "err", err)
}
@@ -275,7 +275,7 @@ func (r *Reaper) persistObservation(ctx context.Context, prev, next EndpointReco
prev.SuccessTotal == next.SuccessTotal && prev.ScrapeFailures == next.ScrapeFailures {
return nil
}
key := resolveKey(utils.GlobalAccountID, next.ModelID)
key := resolveKey(awsidentifiers.GlobalAccountID, next.ModelID)
current, rev, found, err := r.svc.store.getRevision(ctx, key)
if err != nil {
return err
+9 -9
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"io"
"net/http"
"strings"
@@ -14,7 +15,6 @@ import (
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
gateway_bedrock "github.com/mulgadc/spinifex/spinifex/gateway/bedrock"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -120,7 +120,7 @@ func (f *reaperFixture) ready(t *testing.T) EndpointRecord {
// endpoint that has been up and quiet for a while.
func (f *reaperFixture) age(t *testing.T, readyAgo, activeAgo time.Duration) EndpointRecord {
t.Helper()
key := resolveKey(utils.GlobalAccountID, testModelID)
key := resolveKey(awsidentifiers.GlobalAccountID, testModelID)
rec, rev, found, err := f.store.getRevision(t.Context(), key)
require.NoError(t, err)
require.True(t, found)
@@ -137,7 +137,7 @@ func (f *reaperFixture) age(t *testing.T, readyAgo, activeAgo time.Duration) End
func (f *reaperFixture) current(t *testing.T) (EndpointRecord, bool) {
t.Helper()
rec, _, found, err := f.store.getRevision(t.Context(), resolveKey(utils.GlobalAccountID, testModelID))
rec, _, found, err := f.store.getRevision(t.Context(), resolveKey(awsidentifiers.GlobalAccountID, testModelID))
require.NoError(t, err)
return rec, found
}
@@ -175,7 +175,7 @@ func TestReaper_NeverReapsPinnedEndpoint(t *testing.T) {
f.ready(t)
f.age(t, time.Hour, time.Hour)
key := resolveKey(utils.GlobalAccountID, testModelID)
key := resolveKey(awsidentifiers.GlobalAccountID, testModelID)
rec, rev, _, err := f.store.getRevision(t.Context(), key)
require.NoError(t, err)
rec.Pinned = true
@@ -289,7 +289,7 @@ func TestReaper_PinnedEndpointNotReapedOnScrapeFailure(t *testing.T) {
f := newReaperFixture(t, ReaperDeps{IdleTTL: time.Hour})
f.ready(t)
key := resolveKey(utils.GlobalAccountID, testModelID)
key := resolveKey(awsidentifiers.GlobalAccountID, testModelID)
rec, rev, found, err := f.store.getRevision(t.Context(), key)
require.NoError(t, err)
require.True(t, found)
@@ -316,9 +316,9 @@ func TestReaper_ServiceOnlyBundleLivenessProbedNotReaped(t *testing.T) {
f := newReaperFixture(t, ReaperDeps{IdleTTL: time.Nanosecond})
const embedModelID = "embed-only-bundle"
key := resolveKey(utils.GlobalAccountID, embedModelID)
key := resolveKey(awsidentifiers.GlobalAccountID, embedModelID)
rec := EndpointRecord{
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
ModelID: embedModelID,
State: StateReady,
BaseURL: "http://10.0.0.1:8001",
@@ -378,9 +378,9 @@ func TestReaper_UnchangedObservationWritesNothing(t *testing.T) {
// scrapes neither, so a launch in progress cannot be torn down under it.
func TestReaper_SkipsNonReadyRecords(t *testing.T) {
f := newReaperFixture(t, ReaperDeps{IdleTTL: time.Nanosecond})
key := resolveKey(utils.GlobalAccountID, testModelID)
key := resolveKey(awsidentifiers.GlobalAccountID, testModelID)
rec := EndpointRecord{
AccountID: utils.GlobalAccountID, ModelID: testModelID, State: StateStarting, Generation: 1,
AccountID: awsidentifiers.GlobalAccountID, ModelID: testModelID, State: StateStarting, Generation: 1,
}
_, err := f.store.Create(t.Context(), key, &rec)
require.NoError(t, err)
+2 -2
View File
@@ -2,12 +2,12 @@ package handlers_bedrock
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"net/http"
"sync"
"time"
gateway_bedrock "github.com/mulgadc/spinifex/spinifex/gateway/bedrock"
"github.com/mulgadc/spinifex/spinifex/utils"
"golang.org/x/sync/singleflight"
)
@@ -159,7 +159,7 @@ func (r *DynamicEndpointResolver) Endpoint(ctx context.Context, modelID string)
// empty base URL means "not resolved", which is the only outcome a cold model
// can have: the launch outlives this request by design.
func (r *DynamicEndpointResolver) resolve(ctx context.Context, modelID string) (string, error) {
baseURL, err := r.describeAndEnsure(ctx, utils.GlobalAccountID, modelID, false)
baseURL, err := r.describeAndEnsure(ctx, awsidentifiers.GlobalAccountID, modelID, false)
if err != nil || baseURL == "" {
return baseURL, err
}
+5 -5
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"net"
"net/http"
@@ -15,7 +16,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
gateway_bedrock "github.com/mulgadc/spinifex/spinifex/gateway/bedrock"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
)
@@ -141,12 +141,12 @@ func (s *Service) httpClient() *http.Client {
return &http.Client{}
}
// resolveAccountID returns accountID, or utils.GlobalAccountID for the zero
// resolveAccountID returns accountID, or awsidentifiers.GlobalAccountID for the zero
// value, so every existing Ensure/Describe/Delete caller that leaves the
// input's AccountID unset keeps resolving to the shared platform endpoint.
func resolveAccountID(accountID string) string {
if accountID == "" {
return utils.GlobalAccountID
return awsidentifiers.GlobalAccountID
}
return accountID
}
@@ -262,7 +262,7 @@ func (s *Service) Ensure(ctx context.Context, in *EnsureEndpointInput, _ string)
// Delete takes the per-key mutex for the victim while Ensure holds it for
// wantModelID. The two can never be the same key, so the locks are disjoint.
func (s *Service) evictForCapacity(ctx context.Context, wantModelID string, minVRAMMiB int) bool {
recs, err := s.store.list(ctx, utils.GlobalAccountID)
recs, err := s.store.list(ctx, awsidentifiers.GlobalAccountID)
if err != nil {
slog.ErrorContext(ctx, "bedrock: list endpoints for eviction failed", "model", wantModelID, "err", err)
return false
@@ -284,7 +284,7 @@ func (s *Service) evictForCapacity(ctx context.Context, wantModelID string, minV
slog.InfoContext(ctx, "bedrock: evicting an idle endpoint to make room",
"evicting", victim.ModelID, "instanceId", victim.InstanceID, "for", wantModelID,
"idleSince", victim.LastActive())
if _, err := s.Delete(ctx, &DeleteEndpointInput{ModelID: victim.ModelID}, utils.GlobalAccountID); err != nil {
if _, err := s.Delete(ctx, &DeleteEndpointInput{ModelID: victim.ModelID}, awsidentifiers.GlobalAccountID); err != nil {
slog.ErrorContext(ctx, "bedrock: eviction failed; the pending launch keeps its capacity refusal",
"evicting", victim.ModelID, "for", wantModelID, "err", err)
return false
+10 -10
View File
@@ -1,6 +1,7 @@
package handlers_bedrock
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"net/http"
"sync"
"testing"
@@ -11,7 +12,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/gpu"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -209,9 +209,9 @@ func TestDelete_RefusesNonReadyState(t *testing.T) {
h := newLaunchHarness()
s, _ := newTestService(t, h, http.StatusOK, sufficientGPU())
key := resolveKey(utils.GlobalAccountID, testModelID)
key := resolveKey(awsidentifiers.GlobalAccountID, testModelID)
rec := EndpointRecord{
AccountID: utils.GlobalAccountID, ModelID: testModelID, State: StateStarting, Generation: 1,
AccountID: awsidentifiers.GlobalAccountID, ModelID: testModelID, State: StateStarting, Generation: 1,
}
_, err := s.store.Create(t.Context(), key, &rec)
require.NoError(t, err)
@@ -229,9 +229,9 @@ func TestDelete_ResumesFromDraining(t *testing.T) {
h := newLaunchHarness()
s, _ := newTestService(t, h, http.StatusOK, sufficientGPU())
key := resolveKey(utils.GlobalAccountID, testModelID)
key := resolveKey(awsidentifiers.GlobalAccountID, testModelID)
rec := EndpointRecord{
AccountID: utils.GlobalAccountID, ModelID: testModelID, State: StateDraining,
AccountID: awsidentifiers.GlobalAccountID, ModelID: testModelID, State: StateDraining,
InstanceID: "i-stranded", Generation: 2,
}
_, err := s.store.Create(t.Context(), key, &rec)
@@ -246,7 +246,7 @@ func TestDelete_ResumesFromDraining(t *testing.T) {
assert.Contains(t, h.launcher.terminated, "i-stranded", "the resume must still tear the VM down")
}
// testAccountID is a non-Global account, distinct from utils.GlobalAccountID,
// testAccountID is a non-Global account, distinct from awsidentifiers.GlobalAccountID,
// standing in for a real tenant across the account-scoping tests below.
const testAccountID = "111111111111"
@@ -260,11 +260,11 @@ func TestEnsure_EmptyAccountIDKeysGlobalAndUnpinned(t *testing.T) {
out, err := s.Ensure(t.Context(), &EnsureEndpointInput{ModelID: testModelID}, "")
require.NoError(t, err)
assert.Equal(t, utils.GlobalAccountID, out.Endpoint.AccountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, out.Endpoint.AccountID)
assert.False(t, out.Endpoint.Pinned)
s.WaitLaunches()
rec, found, err := s.store.get(t.Context(), resolveKey(utils.GlobalAccountID, testModelID))
rec, found, err := s.store.get(t.Context(), resolveKey(awsidentifiers.GlobalAccountID, testModelID))
require.NoError(t, err)
require.True(t, found, "an empty AccountID must key the record under GlobalAccountID")
assert.False(t, rec.Pinned)
@@ -291,7 +291,7 @@ func TestEnsure_RealAccountIDKeysUnderAccountAndPersistsPinned(t *testing.T) {
assert.True(t, rec.Pinned)
// Nothing must have landed under the shared Global key.
_, foundGlobal, err := s.store.get(t.Context(), resolveKey(utils.GlobalAccountID, testModelID))
_, foundGlobal, err := s.store.get(t.Context(), resolveKey(awsidentifiers.GlobalAccountID, testModelID))
require.NoError(t, err)
assert.False(t, foundGlobal)
}
@@ -405,7 +405,7 @@ func TestList_ReturnsEndpointsAcrossAllAccountsIncludingPinned(t *testing.T) {
}
global, ok := byModel[testModelID]
require.True(t, ok, "the shared GlobalAccountID endpoint must still list unchanged")
assert.Equal(t, utils.GlobalAccountID, global.AccountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, global.AccountID)
assert.False(t, global.Pinned)
pinned, ok := byModel[pinnedModelID]
+3 -3
View File
@@ -15,7 +15,7 @@ const (
// current record without launching a second VM.
//
// AccountID scopes the endpoint to a tenant; empty resolves to
// utils.GlobalAccountID, the shared platform endpoint every caller used
// awsidentifiers.GlobalAccountID, the shared platform endpoint every caller used
// before per-account endpoints existed. Pinned marks a created endpoint
// exempt from idle reaping and eviction.
type EnsureEndpointInput struct {
@@ -29,7 +29,7 @@ type EnsureEndpointOutput struct {
}
// DescribeEndpointInput looks up modelID's current endpoint record.
// AccountID scopes the lookup; empty resolves to utils.GlobalAccountID.
// AccountID scopes the lookup; empty resolves to awsidentifiers.GlobalAccountID.
type DescribeEndpointInput struct {
ModelID string `json:"model_id"`
AccountID string `json:"account_id,omitempty"`
@@ -49,7 +49,7 @@ type ListEndpointsOutput struct {
// DeleteEndpointInput requests a READY endpoint move to DRAINING and its VM
// be torn down. Idempotent: an already-ABSENT endpoint returns success.
// AccountID scopes the target; empty resolves to utils.GlobalAccountID.
// AccountID scopes the target; empty resolves to awsidentifiers.GlobalAccountID.
type DeleteEndpointInput struct {
ModelID string `json:"model_id"`
AccountID string `json:"account_id,omitempty"`
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"github.com/aws/aws-sdk-go/aws"
@@ -12,7 +13,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
"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"
)
@@ -67,7 +67,7 @@ func NewAccountSettingsServiceImplWithNATS(ctx context.Context, cfg *config.Conf
// Falls back to GlobalAccountID for pre-Phase-4 resources with no accountID.
func settingsKey(accountID string) string {
if accountID == "" {
return utils.GlobalAccountID
return awsidentifiers.GlobalAccountID
}
return accountID
}
@@ -2,11 +2,11 @@ package handlers_ec2_account
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -140,6 +140,6 @@ func TestSerialConsole_MultiAccountIsolation(t *testing.T) {
}
func TestSettingsKey_EmptyAccountIDFallback(t *testing.T) {
assert.Equal(t, utils.GlobalAccountID, settingsKey(""))
assert.Equal(t, awsidentifiers.GlobalAccountID, settingsKey(""))
assert.Equal(t, "123456789012", settingsKey("123456789012"))
}
@@ -2,13 +2,13 @@ package handlers_ec2_image
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"strings"
"testing"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/metadata"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -93,7 +93,7 @@ func TestGetAMISourceVolumeID_ImportedSystemAMI(t *testing.T) {
// registerImportedAMISnapshot writes. Deriving it here would let the
// fixture follow the read path and pin nothing.
require.NoError(t, svc.MetadataStore().PutSnapshot(context.Background(), ebsmetadata.Snapshot{
SnapshotID: "snap-sysimp01", VolumeID: "vol-imported", OwnerID: utils.GlobalAccountID,
SnapshotID: "snap-sysimp01", VolumeID: "vol-imported", OwnerID: awsidentifiers.GlobalAccountID,
}))
got, err := svc.GetAMISourceVolumeID(context.Background(), "ami-sysimp01")
@@ -3,6 +3,7 @@ package handlers_ec2_image_test
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strconv"
"strings"
"testing"
@@ -16,7 +17,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_ec2_image "github.com/mulgadc/spinifex/spinifex/handlers/ec2/image"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -156,7 +156,7 @@ func TestDescribeImagesByID_SystemAMIIsVisibleToEveryAccount(t *testing.T) {
require.NoError(t, err)
require.Len(t, out.Images, 1)
assert.Equal(t, utils.GlobalAccountID, aws.StringValue(out.Images[0].OwnerId))
assert.Equal(t, awsidentifiers.GlobalAccountID, aws.StringValue(out.Images[0].OwnerId))
assert.Equal(t, "amazon", aws.StringValue(out.Images[0].ImageOwnerAlias))
}
+6 -6
View File
@@ -248,14 +248,14 @@ func (s *ImageServiceImpl) describeImagesByIDs(ctx context.Context, input *ec2.D
func renderVisibleImage(amiMeta ebsmetadata.AMI, input *ec2.DescribeImagesInput, accountID string,
parsedFilters map[string][]string, encryptedAtRest bool) *ec2.Image {
amiOwner := amiMeta.ImageOwnerAlias
isSystemAMI := amiOwner != "" && !utils.IsAccountID(amiOwner)
isSystemAMI := amiOwner != "" && !awsidentifiers.IsAccountID(amiOwner)
// Resolved up front so the owner filter below compares against the same
// value the OwnerId field reports, rather than the raw alias string a
// system AMI carries instead of a numeric account ID.
ownerID := amiOwner
if isSystemAMI {
ownerID = utils.GlobalAccountID
ownerID = awsidentifiers.GlobalAccountID
}
if !callerCanReadAMI(amiMeta, accountID) {
@@ -619,10 +619,10 @@ func (s *ImageServiceImpl) GetAMIConfig(ctx context.Context, imageID string) (eb
// drift from this predicate. An empty alias is a corrupt document rather than a
// system image, so it derives nothing and the fallback cannot answer for it.
func snapshotAccountForAMI(meta ebsmetadata.AMI) (accountID string, derived bool) {
if utils.IsAccountID(meta.ImageOwnerAlias) {
if awsidentifiers.IsAccountID(meta.ImageOwnerAlias) {
return meta.ImageOwnerAlias, false
}
return utils.GlobalAccountID, meta.ImageOwnerAlias != ""
return awsidentifiers.GlobalAccountID, meta.ImageOwnerAlias != ""
}
// GetAMISourceVolumeID returns the volume whose blocks imageID's snapshot
@@ -745,7 +745,7 @@ func (s *ImageServiceImpl) checkAMIOwnership(meta ebsmetadata.AMI, accountID str
slog.Error("checkAMIOwnership: AMI config has empty ImageOwnerAlias", "imageId", meta.ImageID)
return errors.New(awserrors.ErrorServerInternal)
}
if !utils.IsAccountID(owner) || owner != accountID {
if !awsidentifiers.IsAccountID(owner) || owner != accountID {
return errors.New(awserrors.ErrorUnauthorizedOperation)
}
return nil
@@ -758,7 +758,7 @@ func callerCanReadAMI(meta ebsmetadata.AMI, accountID string) bool {
if owner == "" {
return false
}
if !utils.IsAccountID(owner) {
if !awsidentifiers.IsAccountID(owner) {
return true
}
return owner == accountID
@@ -2,6 +2,7 @@ package handlers_ec2_image
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"io"
"log/slog"
"net/http"
@@ -18,7 +19,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/domains/ec2/ebs/metadata"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -1095,7 +1095,7 @@ func TestDescribeImages_OwnerSelf_GlobalAccountIncludesSystemAMI(t *testing.T) {
out, err := svc.DescribeImages(context.Background(), &ec2.DescribeImagesInput{
Owners: []*string{aws.String("self")},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
gotIDs := make([]string, len(out.Images))
@@ -1379,15 +1379,15 @@ func TestRegisterImage_EmptyCallerAccountIsRefusedAtTheBoundary(t *testing.T) {
func TestRegisterImage_SystemAccountSnapshot(t *testing.T) {
svc, store := setupTestImageService(t)
putTestSnapshotConfig(t, store, "snap-sys01", 8, utils.GlobalAccountID)
putTestSnapshotConfig(t, store, "snap-sys01", 8, awsidentifiers.GlobalAccountID)
out, err := svc.RegisterImage(context.Background(), validRegisterImageServiceInput("snap-sys01"), utils.GlobalAccountID)
out, err := svc.RegisterImage(context.Background(), validRegisterImageServiceInput("snap-sys01"), awsidentifiers.GlobalAccountID)
require.NoError(t, err)
require.NotNil(t, out.ImageId)
meta, err := svc.GetAMIConfig(context.Background(), *out.ImageId)
require.NoError(t, err)
assert.Equal(t, utils.GlobalAccountID, meta.ImageOwnerAlias)
assert.Equal(t, awsidentifiers.GlobalAccountID, meta.ImageOwnerAlias)
}
func TestRegisterImage_ArchitectureAndVirtualizationDefaults(t *testing.T) {
@@ -2,6 +2,7 @@ package handlers_ec2_instance
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/aws/aws-sdk-go/aws"
@@ -12,7 +13,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
vmmock "github.com/mulgadc/spinifex/spinifex/runtime/compute/vm/mock"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -54,7 +54,7 @@ func TestValidateMetadataOptions(t *testing.T) {
// Enabling IMDSv1 on an existing instance is applied and echoed back; IMDSv1-only
// guest agents can be switched on after launch without a relaunch.
func TestModifyInstanceMetadataOptions_EnableV1(t *testing.T) {
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
id := "i-imdsv1"
v := &vm.VM{
ID: id, AccountID: owner, Status: vm.StateRunning,
@@ -77,7 +77,7 @@ func TestModifyInstanceMetadataOptions_EnableV1(t *testing.T) {
// An unrecognised http-tokens state is still refused, and the instance is left
// untouched — no partial application of a rejected request.
func TestModifyInstanceMetadataOptions_RejectUnknownTokensState(t *testing.T) {
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
id := "i-imdsbad"
v := &vm.VM{
ID: id, AccountID: owner, Status: vm.StateRunning,
@@ -98,7 +98,7 @@ func TestModifyInstanceMetadataOptions_RejectUnknownTokensState(t *testing.T) {
// allows this in any state, so it must not return IncorrectInstanceState. The
// no-op http-tokens=required is accepted alongside it.
func TestModifyInstanceMetadataOptions_HopLimitRunning(t *testing.T) {
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
id := "i-hop-run"
v := &vm.VM{
ID: id, AccountID: owner, Status: vm.StateRunning,
@@ -120,7 +120,7 @@ func TestModifyInstanceMetadataOptions_HopLimitRunning(t *testing.T) {
// The stopped-store fallback persists the hop-limit change too.
func TestModifyInstanceMetadataOptions_HopLimitStopped(t *testing.T) {
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
id := "i-hop-stop"
stored := &vm.VM{
ID: id, AccountID: owner, Status: vm.StateStopped,
@@ -148,7 +148,7 @@ func TestModifyInstanceMetadataOptions_NotFound(t *testing.T) {
_, err := svc.ModifyInstanceMetadataOptions(context.Background(), &ec2.ModifyInstanceMetadataOptionsInput{
InstanceId: aws.String("i-ghost"),
HttpPutResponseHopLimit: aws.Int64(2),
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
require.Error(t, err)
assert.True(t, awserrors.IsErrorCode(err, awserrors.ErrorInvalidInstanceIDNotFound), "got %v", err)
}
@@ -157,7 +157,7 @@ func TestModifyInstanceMetadataOptions_NotFound(t *testing.T) {
// guards) returns ServerInternal rather than panicking the daemon — on both the
// running and stopped paths.
func TestModifyInstanceMetadataOptions_NilInstance(t *testing.T) {
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
t.Run("running", func(t *testing.T) {
id := "i-nil-run"
@@ -186,7 +186,7 @@ func TestModifyInstanceMetadataOptions_NilInstance(t *testing.T) {
// A legacy instance launched before the constant block (nil MetadataOptions) is
// stamped with the full IMDSv2-only block on the first modify, not just the hop.
func TestModifyInstanceMetadataOptions_LegacyNilBlockStamped(t *testing.T) {
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
id := "i-legacy"
v := &vm.VM{
ID: id, AccountID: owner, Status: vm.StateRunning,
@@ -285,7 +285,7 @@ func TestPrepareRunInstances_RejectUnsupportedMetadataOptions(t *testing.T) {
MetadataOptions: &ec2.InstanceMetadataOptionsRequest{
HttpEndpoint: aws.String(ec2.InstanceMetadataEndpointStateDisabled),
},
}, utils.GlobalAccountID, "")
}, awsidentifiers.GlobalAccountID, "")
require.Error(t, err)
assert.True(t, awserrors.IsErrorCode(err, awserrors.ErrorUnsupportedOperation), "got %v", err)
}
@@ -662,7 +662,7 @@ func (s *InstanceServiceImpl) PrepareRunInstances(ctx context.Context, input *ec
}
// Caller must own the AMI or the owner alias must be non-account-ID (e.g. "self", "spinifex", "").
amiOwner := amiMeta.ImageOwnerAlias
if amiOwner != "" && amiOwner != accountID && utils.IsAccountID(amiOwner) {
if amiOwner != "" && amiOwner != accountID && awsidentifiers.IsAccountID(amiOwner) {
slog.WarnContext(ctx, "PrepareRunInstances: AMI not owned by caller", "imageId", *input.ImageId, "amiOwner", amiOwner, "accountID", accountID)
return nil, nil, nil, errors.New(awserrors.ErrorInvalidAMIIDNotFound)
}
@@ -1965,7 +1965,7 @@ var DescribeInstanceStatusValidFilters = map[string]bool{
// Pre-Phase4 instances (empty AccountID) are only visible to root (GlobalAccountID).
func IsInstanceVisible(callerAccountID, ownerAccountID string) bool {
if ownerAccountID == "" {
return callerAccountID == utils.GlobalAccountID
return callerAccountID == awsidentifiers.GlobalAccountID
}
return callerAccountID == ownerAccountID
}
@@ -1977,7 +1977,7 @@ func IsInstanceVisibleToCaller(accountID string, v *vm.VM) bool {
if !IsInstanceVisible(accountID, v.AccountID) {
return false
}
return v.ManagedBy == "" || accountID == utils.GlobalAccountID
return v.ManagedBy == "" || accountID == awsidentifiers.GlobalAccountID
}
// instanceMatchesFilters checks whether a VM + its built ec2.Instance copy satisfy all parsed awsfilters.
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strings"
"sync"
"sync/atomic"
@@ -25,7 +26,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/runtime/compute/gpu"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
vmmock "github.com/mulgadc/spinifex/spinifex/runtime/compute/vm/mock"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -806,7 +806,7 @@ func TestDescribeInstanceTypes_CapacityFilterHitsAvailable(t *testing.T) {
func TestDescribeInstances_Empty(t *testing.T) {
svc := &InstanceServiceImpl{vmMgr: mgrWith(map[string]*vm.VM{})}
out, err := svc.DescribeInstances(context.Background(), &ec2.DescribeInstancesInput{}, utils.GlobalAccountID)
out, err := svc.DescribeInstances(context.Background(), &ec2.DescribeInstancesInput{}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
assert.Empty(t, out.Reservations)
}
@@ -879,17 +879,17 @@ func TestDescribeInstances_HidesManagedSystemVMFromCustomer(t *testing.T) {
func TestDescribeInstances_RootSeesManagedSystemVM(t *testing.T) {
v := &vm.VM{
ID: "i-lb",
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
ManagedBy: tags.ManagedByELBv2,
Reservation: &ec2.Reservation{
ReservationId: aws.String("r-lb"),
OwnerId: aws.String(utils.GlobalAccountID),
OwnerId: aws.String(awsidentifiers.GlobalAccountID),
},
Instance: &ec2.Instance{InstanceId: aws.String("i-lb")},
}
svc := &InstanceServiceImpl{vmMgr: mgrWith(map[string]*vm.VM{v.ID: v}), config: &config.Config{}}
out, err := svc.DescribeInstances(context.Background(), &ec2.DescribeInstancesInput{}, utils.GlobalAccountID)
out, err := svc.DescribeInstances(context.Background(), &ec2.DescribeInstancesInput{}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
require.Len(t, out.Reservations, 1)
assert.Equal(t, "i-lb", *out.Reservations[0].Instances[0].InstanceId)
@@ -922,7 +922,7 @@ func TestDescribeInstances_MalformedID(t *testing.T) {
input := &ec2.DescribeInstancesInput{
InstanceIds: []*string{aws.String("not-an-id")},
}
_, err := svc.DescribeInstances(context.Background(), input, utils.GlobalAccountID)
_, err := svc.DescribeInstances(context.Background(), input, awsidentifiers.GlobalAccountID)
require.Error(t, err)
assert.Equal(t, awserrors.ErrorInvalidInstanceIDMalformed, err.Error())
}
@@ -948,7 +948,7 @@ func TestDescribeInstances_FilterByInstanceID(t *testing.T) {
}), config: &config.Config{}}
input := &ec2.DescribeInstancesInput{InstanceIds: []*string{aws.String("i-keep")}}
out, err := svc.DescribeInstances(context.Background(), input, utils.GlobalAccountID)
out, err := svc.DescribeInstances(context.Background(), input, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
require.Len(t, out.Reservations, 1)
assert.Equal(t, "i-keep", *out.Reservations[0].Instances[0].InstanceId)
@@ -968,7 +968,7 @@ func TestDescribeInstances_ReservationGrouping(t *testing.T) {
}
svc := &InstanceServiceImpl{vmMgr: mgrWith(instances), config: &config.Config{}}
out, err := svc.DescribeInstances(context.Background(), &ec2.DescribeInstancesInput{}, utils.GlobalAccountID)
out, err := svc.DescribeInstances(context.Background(), &ec2.DescribeInstancesInput{}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
require.Len(t, out.Reservations, 1)
assert.Equal(t, "r-shared", aws.StringValue(out.Reservations[0].ReservationId))
@@ -990,7 +990,7 @@ func TestDescribeInstances_FilterExcludesOnlyInstance_ReturnsZeroReservations(t
input := &ec2.DescribeInstancesInput{
Filters: []*ec2.Filter{{Name: aws.String("instance-type"), Values: []*string{aws.String("t3.nano")}}},
}
out, err := svc.DescribeInstances(context.Background(), input, utils.GlobalAccountID)
out, err := svc.DescribeInstances(context.Background(), input, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
assert.Empty(t, out.Reservations, "a reservation with every instance filtered out must not appear in the response")
}
@@ -1010,7 +1010,7 @@ func TestDescribeInstancesFromKV_FilterExcludesOnlyInstance_ReturnsZeroReservati
input := &ec2.DescribeInstancesInput{
Filters: []*ec2.Filter{{Name: aws.String("instance-type"), Values: []*string{aws.String("t3.nano")}}},
}
out, err := svc.describeInstancesFromKV(context.Background(), input, utils.GlobalAccountID, listFn, 80, "stopped", "DescribeStoppedInstances")
out, err := svc.describeInstancesFromKV(context.Background(), input, awsidentifiers.GlobalAccountID, listFn, 80, "stopped", "DescribeStoppedInstances")
require.NoError(t, err)
assert.Empty(t, out.Reservations, "a reservation with every instance filtered out must not appear in the response")
}
@@ -1035,7 +1035,7 @@ func TestDescribeInstanceAttribute_MissingAttribute(t *testing.T) {
func TestDescribeInstanceAttribute_RunningInstance(t *testing.T) {
id := "i-attr1"
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
v := &vm.VM{
ID: id,
InstanceType: "t3.large",
@@ -1128,7 +1128,7 @@ func TestDescribeInstanceAttribute_NotRunning_NoStore(t *testing.T) {
func TestDescribeInstanceAttribute_FoundInStoppedStore(t *testing.T) {
id := "i-stopped1"
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
store := &vmmock.StateStore{Stopped: map[string]*vm.VM{
id: {ID: id, InstanceType: "t3.medium", AccountID: owner},
}}
@@ -1153,7 +1153,7 @@ func TestDescribeInstanceAttribute_NotFound(t *testing.T) {
_, err := svc.DescribeInstanceAttribute(context.Background(), &ec2.DescribeInstanceAttributeInput{
InstanceId: aws.String("i-ghost"),
Attribute: aws.String(ec2.InstanceAttributeNameInstanceType),
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
require.Error(t, err)
assert.Equal(t, awserrors.ErrorInvalidInstanceIDNotFound, err.Error())
}
@@ -1172,7 +1172,7 @@ func TestDescribeInstanceAttribute_HiddenForOtherAccount(t *testing.T) {
}
func TestDescribeInstanceAttribute_DisableApiTermination(t *testing.T) {
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
tests := []struct {
name string
@@ -1236,7 +1236,7 @@ func TestDescribeStoppedInstances_NilStore(t *testing.T) {
}
func TestDescribeStoppedInstances_HappyPath(t *testing.T) {
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
store := &vmmock.StateStore{
Stopped: map[string]*vm.VM{
"i-stop1": {
@@ -1266,7 +1266,7 @@ func TestDescribeTerminatedInstances_NilStore(t *testing.T) {
}
func TestDescribeTerminatedInstances_HappyPath(t *testing.T) {
owner := utils.GlobalAccountID
owner := awsidentifiers.GlobalAccountID
store := &vmmock.StateStore{
Terminated: map[string]*vm.VM{
"i-term1": {
@@ -1346,7 +1346,7 @@ func TestIsInstanceVisible(t *testing.T) {
owner string
want bool
}{
{"empty owner, global caller", utils.GlobalAccountID, "", true},
{"empty owner, global caller", awsidentifiers.GlobalAccountID, "", true},
{"empty owner, non-global caller", "111122223333", "", false},
{"matching account", "111122223333", "111122223333", true},
{"different accounts", "111122223333", "999988887777", false},
@@ -4472,7 +4472,7 @@ func runningVM(id, owner string) *vm.VM {
func TestDescribeInstanceStatus_Empty(t *testing.T) {
svc := instanceStatusService(t, "az-a", map[string]*vm.VM{})
out, err := svc.DescribeInstanceStatus(context.Background(), &ec2.DescribeInstanceStatusInput{}, utils.GlobalAccountID)
out, err := svc.DescribeInstanceStatus(context.Background(), &ec2.DescribeInstanceStatusInput{}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
require.NotNil(t, out)
assert.Empty(t, out.InstanceStatuses)
@@ -4683,7 +4683,7 @@ func TestDescribeInstanceStatus_MalformedInstanceID(t *testing.T) {
svc := instanceStatusService(t, "az-a", map[string]*vm.VM{})
_, err := svc.DescribeInstanceStatus(context.Background(), &ec2.DescribeInstanceStatusInput{
InstanceIds: []*string{aws.String("not-an-id")},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
require.Error(t, err)
assert.Equal(t, awserrors.ErrorInvalidInstanceIDMalformed, err.Error())
}
@@ -534,7 +534,7 @@ func (s *SnapshotServiceImpl) describeSnapshotsByIDs(ctx context.Context, input
// An untenanted caller has no prefix to read under; refuse here rather than
// report a snapshot that may well exist as absent. The key builder owns the
// wording, so the strict variant reports what the listing path reports.
if !utils.IsAccountID(accountID) {
if !awsidentifiers.IsAccountID(accountID) {
_, keyErr := ebsmetadata.SnapshotKey(accountID, snapshotIDs[0])
slog.ErrorContext(ctx, "DescribeSnapshots refused a caller with no account", "accountID", accountID)
if strict {
@@ -7,6 +7,7 @@ package handlers_ec2_snapshot
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strings"
"testing"
@@ -19,7 +20,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/providers/ebs"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -52,17 +52,17 @@ func TestDeleteSnapshot_LeavesNoDocument(t *testing.T) {
func TestSnapshot_SystemAccountIsAnOrdinaryAccount(t *testing.T) {
ctx := context.Background()
svc, store := setupTestSnapshotService(t)
createTestVolumeForAccount(t, svc, store, "vol-sys", 8, utils.GlobalAccountID)
createTestVolumeForAccount(t, svc, store, "vol-sys", 8, awsidentifiers.GlobalAccountID)
snap, err := svc.CreateSnapshot(ctx, &ec2.CreateSnapshotInput{VolumeId: aws.String("vol-sys")}, utils.GlobalAccountID)
snap, err := svc.CreateSnapshot(ctx, &ec2.CreateSnapshotInput{VolumeId: aws.String("vol-sys")}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
listed, err := svc.DescribeSnapshots(ctx, &ec2.DescribeSnapshotsInput{}, utils.GlobalAccountID)
listed, err := svc.DescribeSnapshots(ctx, &ec2.DescribeSnapshotsInput{}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
require.Len(t, listed.Snapshots, 1)
assert.Equal(t, aws.StringValue(snap.SnapshotId), aws.StringValue(listed.Snapshots[0].SnapshotId))
_, err = svc.DeleteSnapshot(ctx, &ec2.DeleteSnapshotInput{SnapshotId: snap.SnapshotId}, utils.GlobalAccountID)
_, err = svc.DeleteSnapshot(ctx, &ec2.DeleteSnapshotInput{SnapshotId: snap.SnapshotId}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
}
@@ -257,9 +257,9 @@ func TestDescribeSnapshots_ForeignOwnerIDReadsNothing(t *testing.T) {
func TestDeleteSnapshot_BlockedByACloneInAnotherAccount(t *testing.T) {
ctx := context.Background()
svc, store := setupTestSnapshotService(t)
createTestVolumeForAccount(t, svc, store, "vol-system", 8, utils.GlobalAccountID)
createTestVolumeForAccount(t, svc, store, "vol-system", 8, awsidentifiers.GlobalAccountID)
snap, err := svc.CreateSnapshot(ctx, &ec2.CreateSnapshotInput{VolumeId: aws.String("vol-system")}, utils.GlobalAccountID)
snap, err := svc.CreateSnapshot(ctx, &ec2.CreateSnapshotInput{VolumeId: aws.String("vol-system")}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
seedVolumeDocument(t, store, ebsmetadata.Volume{
@@ -268,7 +268,7 @@ func TestDeleteSnapshot_BlockedByACloneInAnotherAccount(t *testing.T) {
SnapshotID: aws.StringValue(snap.SnapshotId),
})
_, err = svc.DeleteSnapshot(ctx, &ec2.DeleteSnapshotInput{SnapshotId: snap.SnapshotId}, utils.GlobalAccountID)
_, err = svc.DeleteSnapshot(ctx, &ec2.DeleteSnapshotInput{SnapshotId: snap.SnapshotId}, awsidentifiers.GlobalAccountID)
require.Error(t, err)
assert.Equal(t, awserrors.ErrorInvalidSnapshotInUse, err.Error())
}
+7 -7
View File
@@ -1,11 +1,11 @@
package handlers_elbv2
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
iammock "github.com/mulgadc/spinifex/spinifex/handlers/iam/mock"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
)
@@ -17,8 +17,8 @@ func TestEnsureLBInstanceProfile_UsesLazyProvider(t *testing.T) {
f := iammock.New()
s := &ELBv2ServiceImpl{IAMProvider: func() handlers_iam.SystemInstanceRoleEnsurer { return f }}
arn := s.ensureLBInstanceProfile(utils.GlobalAccountID)
assert.Equal(t, "arn:aws:iam::"+utils.GlobalAccountID+":instance-profile/"+lbAgentSystemRoleName, arn)
arn := s.ensureLBInstanceProfile(awsidentifiers.GlobalAccountID)
assert.Equal(t, "arn:aws:iam::"+awsidentifiers.GlobalAccountID+":instance-profile/"+lbAgentSystemRoleName, arn)
}
// TestEnsureLBInstanceProfile_CreatesInSystemAccount asserts the role and profile
@@ -30,9 +30,9 @@ func TestEnsureLBInstanceProfile_CreatesInSystemAccount(t *testing.T) {
f := iammock.New()
s := &ELBv2ServiceImpl{IAM: f}
s.ensureLBInstanceProfile(utils.GlobalAccountID)
assert.Equal(t, utils.GlobalAccountID, f.LastRoleAcct)
assert.Equal(t, utils.GlobalAccountID, f.LastProfileAcct)
s.ensureLBInstanceProfile(awsidentifiers.GlobalAccountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, f.LastRoleAcct)
assert.Equal(t, awsidentifiers.GlobalAccountID, f.LastProfileAcct)
}
// TestEnsureLBInstanceProfile_NotReadyFallsBack asserts an unwired IAM (no field,
@@ -41,5 +41,5 @@ func TestEnsureLBInstanceProfile_CreatesInSystemAccount(t *testing.T) {
func TestEnsureLBInstanceProfile_NotReadyFallsBack(t *testing.T) {
t.Parallel()
s := &ELBv2ServiceImpl{IAMProvider: func() handlers_iam.SystemInstanceRoleEnsurer { return nil }}
assert.Empty(t, s.ensureLBInstanceProfile(utils.GlobalAccountID))
assert.Empty(t, s.ensureLBInstanceProfile(awsidentifiers.GlobalAccountID))
}
+4 -4
View File
@@ -503,7 +503,7 @@ func (s *ELBv2ServiceImpl) launchLBVM(ctx context.Context, lbID, scheme string,
// secret rides in fw_cfg. Falls back to baked system keys when IAM is unwired.
// The role lives in the system account because the LB VM (and its ENI) run
// there — IMDS resolves the profile under the instance's account.
profileARN := s.ensureLBInstanceProfile(utils.GlobalAccountID)
profileARN := s.ensureLBInstanceProfile(awsidentifiers.GlobalAccountID)
nics := s.buildMicrovmNICs(primaryIP, primaryMAC, subnets[0], eniIDs[0], scheme, extraENIInputs, accountID)
launchInput := &SystemInstanceInput{
@@ -610,7 +610,7 @@ func (s *ELBv2ServiceImpl) RebuildSystemInstanceInput(rc RecoveryContext) (*Syst
// Re-ensure the instance profile so a recovered LB VM keeps IMDS creds; the
// ensure is idempotent and converges on the existing role/profile. The role
// lives in the system account where the LB VM runs, not the LB owner account.
profileARN := s.ensureLBInstanceProfile(utils.GlobalAccountID)
profileARN := s.ensureLBInstanceProfile(awsidentifiers.GlobalAccountID)
return &SystemInstanceInput{
InstanceType: rc.InstanceType,
@@ -1047,7 +1047,7 @@ func (s *ELBv2ServiceImpl) LBAgentHeartbeat(ctx context.Context, input *LBAgentH
slog.ErrorContext(ctx, "LBAgentHeartbeat: failed to get LB", "lbId", lbID, "err", err)
return nil, errors.New(awserrors.ErrorServerInternal)
}
if lb == nil || (lb.AccountID != accountID && accountID != utils.GlobalAccountID) {
if lb == nil || (lb.AccountID != accountID && accountID != awsidentifiers.GlobalAccountID) {
// Log to distinguish a stuck-in-provisioning LB from one whose heartbeat never arrived.
slog.WarnContext(ctx, "LBAgentHeartbeat: LB not found or account mismatch",
"lbId", lbID, "accountId", accountID, "found", lb != nil)
@@ -1106,7 +1106,7 @@ func (s *ELBv2ServiceImpl) GetLBConfig(ctx context.Context, input *GetLBConfigIn
slog.ErrorContext(ctx, "GetLBConfig: failed to get LB", "lbId", lbID, "err", err)
return nil, errors.New(awserrors.ErrorServerInternal)
}
if lb == nil || (lb.AccountID != accountID && accountID != utils.GlobalAccountID) {
if lb == nil || (lb.AccountID != accountID && accountID != awsidentifiers.GlobalAccountID) {
return nil, errors.New(awserrors.ErrorELBv2LoadBalancerNotFound)
}
+3 -3
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/xml"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"sort"
"strings"
"sync"
@@ -16,7 +17,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
awsxml "github.com/mulgadc/spinifex/spinifex/foundation/aws/xml"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -2375,7 +2375,7 @@ func TestLBAgentHeartbeat_SystemAccountAllowed(t *testing.T) {
out, err := svc.LBAgentHeartbeat(context.Background(), &LBAgentHeartbeatInput{
LBID: aws.String("lb-sys1"),
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
assert.Equal(t, StateActive, *out.Status)
}
@@ -2471,7 +2471,7 @@ func TestGetLBConfig_SystemAccountAllowed(t *testing.T) {
out, err := svc.GetLBConfig(context.Background(), &GetLBConfigInput{
LBID: aws.String("lb-syscfg1"),
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
assert.Equal(t, "global\n log stdout\n", *out.ConfigText)
}
+7 -7
View File
@@ -2,13 +2,13 @@ package handlers_iam
import (
"encoding/json"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -370,28 +370,28 @@ func TestSeedBootstrap_AccountScoped(t *testing.T) {
err = svc.SeedBootstrap(&BootstrapData{
AccessKeyID: "AKIAROOTEXAMPLE12345",
EncryptedSecret: encryptedSecret,
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
})
require.NoError(t, err)
// Root user stored at 000000000000:root
out, err := svc.GetUser(utils.GlobalAccountID, &iam.GetUserInput{
out, err := svc.GetUser(awsidentifiers.GlobalAccountID, &iam.GetUserInput{
UserName: aws.String("root"),
})
require.NoError(t, err)
assert.Equal(t, "root", *out.User.UserName)
assert.Contains(t, *out.User.Arn, utils.GlobalAccountID)
assert.Contains(t, *out.User.Arn, awsidentifiers.GlobalAccountID)
// Access key has correct AccountID
ak, err := svc.LookupAccessKey("AKIAROOTEXAMPLE12345")
require.NoError(t, err)
assert.Equal(t, utils.GlobalAccountID, ak.AccountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, ak.AccountID)
assert.Equal(t, "root", ak.UserName)
// Global account record was created
account, err := svc.GetAccount(utils.GlobalAccountID)
account, err := svc.GetAccount(awsidentifiers.GlobalAccountID)
require.NoError(t, err)
assert.Equal(t, utils.GlobalAccountID, account.AccountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, account.AccountID)
assert.Equal(t, "system", account.AccountName)
assert.Equal(t, "ACTIVE", account.Status)
}
+8 -8
View File
@@ -7,6 +7,7 @@ import (
"encoding/json"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"maps"
"net/netip"
@@ -30,7 +31,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
"github.com/mulgadc/spinifex/spinifex/foundation/state/migrate"
"github.com/mulgadc/spinifex/spinifex/utils"
)
const (
@@ -828,7 +828,7 @@ func (s *IAMServiceImpl) SeedBootstrap(data *BootstrapData) error {
ctx := context.Background()
// --- Seed system account (000000000000) ---
systemAccount := Account{
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
AccountName: "system",
Status: AccountStatusActive,
CreatedAt: time.Now().UTC().Format(time.RFC3339),
@@ -837,16 +837,16 @@ func (s *IAMServiceImpl) SeedBootstrap(data *BootstrapData) error {
if err != nil {
return fmt.Errorf("marshal system account: %w", err)
}
if _, err := s.accountsBucket.Create(ctx, utils.GlobalAccountID, accountData); err != nil && !errors.Is(err, jetstream.ErrKeyExists) {
if _, err := s.accountsBucket.Create(ctx, awsidentifiers.GlobalAccountID, accountData); err != nil && !errors.Is(err, jetstream.ErrKeyExists) {
return fmt.Errorf("seed system account: %w", err)
}
kvKey := utils.GlobalAccountID + ".root"
kvKey := awsidentifiers.GlobalAccountID + ".root"
rootUser := User{
UserName: "root",
UserID: "AIDAAAAAAAAAAAAAAAAA",
AccountID: utils.GlobalAccountID,
ARN: arn.FormatIAMRoot(utils.GlobalAccountID),
AccountID: awsidentifiers.GlobalAccountID,
ARN: arn.FormatIAMRoot(awsidentifiers.GlobalAccountID),
Path: "/",
CreatedAt: time.Now().UTC().Format(time.RFC3339),
AccessKeys: []string{data.AccessKeyID},
@@ -873,7 +873,7 @@ func (s *IAMServiceImpl) SeedBootstrap(data *BootstrapData) error {
AccessKeyID: data.AccessKeyID,
SecretAccessKey: data.EncryptedSecret,
UserName: "root",
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
Status: AccessKeyStatusActive,
CreatedAt: rootUser.CreatedAt,
}
@@ -889,7 +889,7 @@ func (s *IAMServiceImpl) SeedBootstrap(data *BootstrapData) error {
} else if err != nil {
return fmt.Errorf("seed root access key: %w", err)
} else {
slog.Info("System root user seeded", "accountID", utils.GlobalAccountID, "accessKeyID", data.AccessKeyID)
slog.Info("System root user seeded", "accountID", awsidentifiers.GlobalAccountID, "accessKeyID", data.AccessKeyID)
}
// --- Seed admin account (000000000001) if present ---
+14 -14
View File
@@ -2,6 +2,7 @@ package handlers_iam
import (
"encoding/hex"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"strings"
"testing"
@@ -13,7 +14,6 @@ import (
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/admin"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -21,7 +21,7 @@ import (
// Interface compliance check.
var _ IAMService = (*IAMServiceImpl)(nil)
const testAccountID = utils.GlobalAccountID
const testAccountID = awsidentifiers.GlobalAccountID
func setupTestIAMService(t *testing.T) *IAMServiceImpl {
t.Helper()
@@ -847,24 +847,24 @@ func TestSeedBootstrap(t *testing.T) {
err = svc.SeedBootstrap(&BootstrapData{
AccessKeyID: "AKIAEXAMPLE123456789",
EncryptedSecret: encryptedSecret,
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
})
require.NoError(t, err)
// Verify root user exists at account-scoped key
out, err := svc.GetUser(utils.GlobalAccountID, &iam.GetUserInput{
out, err := svc.GetUser(awsidentifiers.GlobalAccountID, &iam.GetUserInput{
UserName: aws.String("root"),
})
require.NoError(t, err)
assert.Equal(t, "root", *out.User.UserName)
assert.Contains(t, *out.User.Arn, utils.GlobalAccountID)
assert.Contains(t, *out.User.Arn, awsidentifiers.GlobalAccountID)
assert.Contains(t, *out.User.Arn, "root")
// Verify access key exists with AccountID
ak, err := svc.LookupAccessKey("AKIAEXAMPLE123456789")
require.NoError(t, err)
assert.Equal(t, "root", ak.UserName)
assert.Equal(t, utils.GlobalAccountID, ak.AccountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, ak.AccountID)
assert.Equal(t, "Active", ak.Status)
// Verify secret is decryptable
@@ -873,9 +873,9 @@ func TestSeedBootstrap(t *testing.T) {
assert.Equal(t, "test-secret-key", decrypted)
// Verify global account record was created
account, err := svc.GetAccount(utils.GlobalAccountID)
account, err := svc.GetAccount(awsidentifiers.GlobalAccountID)
require.NoError(t, err)
assert.Equal(t, utils.GlobalAccountID, account.AccountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, account.AccountID)
assert.Equal(t, "system", account.AccountName)
assert.Equal(t, "ACTIVE", account.Status)
}
@@ -888,7 +888,7 @@ func TestSeedBootstrap_Idempotent(t *testing.T) {
data := &BootstrapData{
AccessKeyID: "AKIAEXAMPLE123456789",
EncryptedSecret: encryptedSecret,
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
}
// First call seeds
@@ -900,7 +900,7 @@ func TestSeedBootstrap_Idempotent(t *testing.T) {
require.NoError(t, err)
// Root user should still exist with original data
out, err := svc.GetUser(utils.GlobalAccountID, &iam.GetUserInput{
out, err := svc.GetUser(awsidentifiers.GlobalAccountID, &iam.GetUserInput{
UserName: aws.String("root"),
})
require.NoError(t, err)
@@ -919,7 +919,7 @@ func TestSeedBootstrap_WithAdmin(t *testing.T) {
err = svc.SeedBootstrap(&BootstrapData{
AccessKeyID: "AKIASYSTEM1234567890",
EncryptedSecret: systemSecret,
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
Admin: &AdminBootstrapData{
AccountID: "000000000001",
AccountName: "spinifex",
@@ -931,7 +931,7 @@ func TestSeedBootstrap_WithAdmin(t *testing.T) {
require.NoError(t, err)
// Verify system root user exists
out, err := svc.GetUser(utils.GlobalAccountID, &iam.GetUserInput{
out, err := svc.GetUser(awsidentifiers.GlobalAccountID, &iam.GetUserInput{
UserName: aws.String("root"),
})
require.NoError(t, err)
@@ -987,12 +987,12 @@ func TestSeedBootstrap_AdminNil_BackwardCompat(t *testing.T) {
err = svc.SeedBootstrap(&BootstrapData{
AccessKeyID: "AKIAEXAMPLE123456789",
EncryptedSecret: encryptedSecret,
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
})
require.NoError(t, err)
// Root user should exist
out, err := svc.GetUser(utils.GlobalAccountID, &iam.GetUserInput{
out, err := svc.GetUser(awsidentifiers.GlobalAccountID, &iam.GetUserInput{
UserName: aws.String("root"),
})
require.NoError(t, err)
+1 -1
View File
@@ -30,7 +30,7 @@ const applianceBucketHistory = 1
const appliancePostgresKey = "postgres"
// ApplianceIdentifier is the appliance's reserved, deployment-wide identifier
// (D2): a system resource under utils.GlobalAccountID, never a
// (D2): a system resource under awsidentifiers.GlobalAccountID, never a
// caller-supplied or generated id.
const ApplianceIdentifier = "ochre-vector-pg"
+6 -6
View File
@@ -4,13 +4,13 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"net/netip"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// The appliance's reachable address is the customer-ENI IP RDS places in the
@@ -81,7 +81,7 @@ func ensureDaemonENI(ctx context.Context, vpcSvc vpcProvisioner, subnetID, nodeI
{Name: aws.String("subnet-id"), Values: aws.StringSlice([]string{subnetID})},
{Name: aws.String("description"), Values: aws.StringSlice([]string{desc})},
},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return nil, fmt.Errorf("ochrevector: describe daemon ENI in subnet %s: %w", subnetID, err)
}
@@ -123,7 +123,7 @@ func ensureDaemonENI(ctx context.Context, vpcSvc vpcProvisioner, subnetID, nodeI
{Key: aws.String(ochreDaemonNodeTagKey), Value: aws.String(nodeID)},
},
}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return nil, fmt.Errorf("ochrevector: create daemon ENI in subnet %s: %w", subnetID, err)
}
@@ -153,7 +153,7 @@ func ensureENIGroups(ctx context.Context, vpcSvc vpcProvisioner, ni *ec2.Network
_, err := vpcSvc.ModifyNetworkInterfaceAttribute(ctx, &ec2.ModifyNetworkInterfaceAttributeInput{
NetworkInterfaceId: ni.NetworkInterfaceId,
Groups: aws.StringSlice(groupIDs),
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return fmt.Errorf("ochrevector: set daemon ENI %s security groups: %w", aws.StringValue(ni.NetworkInterfaceId), err)
}
@@ -201,7 +201,7 @@ func resolveApplianceTarget(ctx context.Context, deps HostPortDeps, identifier s
Filters: []*ec2.Filter{
{Name: aws.String("tag:" + applianceInstanceTagKey), Values: aws.StringSlice([]string{identifier})},
},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", "", "", nil, fmt.Errorf("ochrevector: describe appliance ENI for %s: %w", identifier, err)
}
@@ -238,7 +238,7 @@ func resolveApplianceTarget(ctx context.Context, deps HostPortDeps, identifier s
subOut, err := deps.VPC.DescribeSubnets(ctx, &ec2.DescribeSubnetsInput{
Filters: []*ec2.Filter{{Name: aws.String("subnet-id"), Values: aws.StringSlice([]string{subnetID})}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", "", "", nil, fmt.Errorf("ochrevector: describe subnet %s: %w", subnetID, err)
}
+2 -2
View File
@@ -2,10 +2,10 @@ package handlers_ochrevector
import (
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"regexp"
"github.com/jackc/pgx/v5"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// indexIDPattern is a conservative allowlist for anything that reaches a SQL
@@ -18,7 +18,7 @@ var indexIDPattern = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}$`)
// AWS-style account id before it ever reaches a SQL identifier or
// search_path.
func validateAccountID(accountID string) error {
if !utils.IsAccountID(accountID) {
if !awsidentifiers.IsAccountID(accountID) {
return fmt.Errorf("ochrevector: invalid account id %q", accountID)
}
return nil
@@ -5,14 +5,14 @@
package handlers_ochrevector
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
)
func TestValidateAccountID(t *testing.T) {
assert.NoError(t, validateAccountID(utils.GlobalAccountID))
assert.NoError(t, validateAccountID(awsidentifiers.GlobalAccountID))
assert.NoError(t, validateAccountID("123456789012"))
assert.Error(t, validateAccountID(""))
@@ -34,8 +34,8 @@ func TestValidateIndexID(t *testing.T) {
}
func TestSchemaAndRoleNames(t *testing.T) {
assert.Equal(t, "kb_"+utils.GlobalAccountID, schemaName(utils.GlobalAccountID))
assert.Equal(t, "kb_"+utils.GlobalAccountID+"_role", roleName(utils.GlobalAccountID))
assert.Equal(t, "kb_"+awsidentifiers.GlobalAccountID, schemaName(awsidentifiers.GlobalAccountID))
assert.Equal(t, "kb_"+awsidentifiers.GlobalAccountID+"_role", roleName(awsidentifiers.GlobalAccountID))
}
func TestTableAndIndexNames(t *testing.T) {
@@ -3,6 +3,7 @@ package handlers_ochrevector
import (
"context"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strings"
"time"
@@ -99,7 +100,7 @@ func (l *rdsLauncher) create(ctx context.Context, identifier, masterUsername, ma
MasterUsername: aws.String(masterUsername),
MasterUserPassword: aws.String(masterPassword),
}
_, err := utils.NATSRequest[rds.CreateDBInstanceOutput](ctx, l.nc, rdsCreateSubject, input, rdsCreateTimeout, utils.GlobalAccountID)
_, err := utils.NATSRequest[rds.CreateDBInstanceOutput](ctx, l.nc, rdsCreateSubject, input, rdsCreateTimeout, awsidentifiers.GlobalAccountID)
if err != nil {
if strings.Contains(err.Error(), awserrors.ErrorDBInstanceAlreadyExists) {
return nil
@@ -121,7 +122,7 @@ func (l *rdsLauncher) Delete(ctx context.Context, identifier string) error {
DBInstanceIdentifier: aws.String(identifier),
SkipFinalSnapshot: aws.Bool(true),
}
_, err := utils.NATSRequest[rds.DeleteDBInstanceOutput](ctx, l.nc, rdsDeleteSubject, input, rdsDeleteTimeout, utils.GlobalAccountID)
_, err := utils.NATSRequest[rds.DeleteDBInstanceOutput](ctx, l.nc, rdsDeleteSubject, input, rdsDeleteTimeout, awsidentifiers.GlobalAccountID)
if err != nil {
if strings.Contains(err.Error(), awserrors.ErrorDBInstanceNotFound) {
return nil
@@ -136,7 +137,7 @@ func (l *rdsLauncher) Delete(ctx context.Context, identifier string) error {
func (l *rdsLauncher) pollUntilAvailable(ctx context.Context, identifier string) (string, int, error) {
for {
out, err := utils.NATSRequest[rds.DescribeDBInstancesOutput](ctx, l.nc, rdsDescribeSubject,
&rds.DescribeDBInstancesInput{DBInstanceIdentifier: aws.String(identifier)}, rdsDescribeTimeout, utils.GlobalAccountID)
&rds.DescribeDBInstancesInput{DBInstanceIdentifier: aws.String(identifier)}, rdsDescribeTimeout, awsidentifiers.GlobalAccountID)
if err != nil {
return "", 0, fmt.Errorf("ochrevector: describe appliance db instance %s: %w", identifier, err)
}
+3 -3
View File
@@ -4,13 +4,13 @@ import (
"context"
"encoding/json"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"sync"
"time"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go/jetstream"
"golang.org/x/time/rate"
)
@@ -42,7 +42,7 @@ func (s *Service) SetBedrockUsage(r BedrockUsageReader) {
// stream-fed counter catches up. A few seconds of lag behind real usage is
// an accepted property of a monthly cap.
func (s *Service) CheckBedrockTokens(ctx context.Context, accountID string) error {
if s == nil || !s.limits.TokensPerMonthEnabled || accountID == utils.GlobalAccountID {
if s == nil || !s.limits.TokensPerMonthEnabled || accountID == awsidentifiers.GlobalAccountID {
return nil
}
if s.bedrockUsage == nil {
@@ -66,7 +66,7 @@ func (s *Service) CheckBedrockTokens(ctx context.Context, accountID string) erro
// limit is to occasionally allow a little more, never to add network latency
// to every invocation for a slightly tighter cap.
func (s *Service) CheckBedrockRPM(accountID string) error {
if s == nil || !s.limits.RequestsPerMinuteEnabled || accountID == utils.GlobalAccountID {
if s == nil || !s.limits.RequestsPerMinuteEnabled || accountID == awsidentifiers.GlobalAccountID {
return nil
}
if !s.rpm.allow(accountID, s.limits.RequestsPerMinute) {
+3 -3
View File
@@ -4,12 +4,12 @@ import (
"context"
"encoding/json"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"time"
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go/jetstream"
toml "github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/assert"
@@ -62,7 +62,7 @@ func TestCheckBedrockTokens_DisabledIsNoop(t *testing.T) {
func TestCheckBedrockTokens_ExemptSystemAccount(t *testing.T) {
s := New(Limits{TokensPerMonthEnabled: true, TokensPerMonth: 1}, nil)
s.SetBedrockUsage(stubBedrockUsageReader{tokens: 1_000_000})
assert.NoError(t, s.CheckBedrockTokens(context.Background(), utils.GlobalAccountID))
assert.NoError(t, s.CheckBedrockTokens(context.Background(), awsidentifiers.GlobalAccountID))
}
// TestCheckBedrockTokens_NoReaderIsNoop covers a wiring gap: the dimension is
@@ -103,7 +103,7 @@ func TestCheckBedrockRPM_DisabledIsNoop(t *testing.T) {
func TestCheckBedrockRPM_ExemptSystemAccount(t *testing.T) {
s := New(Limits{RequestsPerMinuteEnabled: true, RequestsPerMinute: 1}, nil)
for range 10 {
assert.NoError(t, s.CheckBedrockRPM(utils.GlobalAccountID))
assert.NoError(t, s.CheckBedrockRPM(awsidentifiers.GlobalAccountID))
}
}
+8 -6
View File
@@ -2,10 +2,10 @@ package handlers_quota
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// liveLimits is a representative enabled tier with distinct caps per dimension.
@@ -54,20 +54,22 @@ func TestEnforceLiveExemptShortCircuits(t *testing.T) {
{"vpc disabled", func() error { return disabled.EnforceVPCs(context.Background(), nil, normalAccount, 1) }},
{"subnet disabled", func() error { return disabled.EnforceSubnets(context.Background(), nil, normalAccount, 1) }},
{"eip disabled", func() error { return disabled.EnforceEIPs(context.Background(), nil, normalAccount, 1) }},
{"vpc system account", func() error { return enabled.EnforceVPCs(context.Background(), nil, utils.GlobalAccountID, 1) }},
{"subnet system account", func() error { return enabled.EnforceSubnets(context.Background(), nil, utils.GlobalAccountID, 1) }},
{"eip system account", func() error { return enabled.EnforceEIPs(context.Background(), nil, utils.GlobalAccountID, 1) }},
{"vpc system account", func() error { return enabled.EnforceVPCs(context.Background(), nil, awsidentifiers.GlobalAccountID, 1) }},
{"subnet system account", func() error {
return enabled.EnforceSubnets(context.Background(), nil, awsidentifiers.GlobalAccountID, 1)
}},
{"eip system account", func() error { return enabled.EnforceEIPs(context.Background(), nil, awsidentifiers.GlobalAccountID, 1) }},
{"lb disabled", func() error {
return disabled.EnforceLoadBalancers(context.Background(), nil, normalAccount, 1)
}},
{"lb system account", func() error {
return enabled.EnforceLoadBalancers(context.Background(), nil, utils.GlobalAccountID, 1)
return enabled.EnforceLoadBalancers(context.Background(), nil, awsidentifiers.GlobalAccountID, 1)
}},
{"rds disabled", func() error {
return disabled.EnforceRDSInstances(context.Background(), nil, normalAccount, 1)
}},
{"rds system account", func() error {
return enabled.EnforceRDSInstances(context.Background(), nil, utils.GlobalAccountID, 1)
return enabled.EnforceRDSInstances(context.Background(), nil, awsidentifiers.GlobalAccountID, 1)
}},
}
for _, tc := range cases {
+2 -2
View File
@@ -6,10 +6,10 @@ package handlers_quota
import (
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"time"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go/jetstream"
)
@@ -132,5 +132,5 @@ func (s *Service) Exempt(accountID string) bool {
if s == nil || !s.limits.Enabled {
return true
}
return accountID == utils.GlobalAccountID
return accountID == awsidentifiers.GlobalAccountID
}
+3 -3
View File
@@ -1,9 +1,9 @@
package handlers_quota
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/mulgadc/spinifex/spinifex/utils"
toml "github.com/pelletier/go-toml/v2"
)
@@ -73,10 +73,10 @@ func TestExempt(t *testing.T) {
accountID string
want bool
}{
{"system account when enabled", Limits{Enabled: true}, utils.GlobalAccountID, true},
{"system account when enabled", Limits{Enabled: true}, awsidentifiers.GlobalAccountID, true},
{"normal account when enabled", Limits{Enabled: true}, normalAccount, false},
{"normal account when disabled", Limits{Enabled: false}, normalAccount, true},
{"system account when disabled", Limits{Enabled: false}, utils.GlobalAccountID, true},
{"system account when disabled", Limits{Enabled: false}, awsidentifiers.GlobalAccountID, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+3 -3
View File
@@ -3,11 +3,11 @@ package handlers_quota
import (
"context"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/instancetypes"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// AccountLister enumerates the account IDs whose vCPU counters reconcile should
@@ -37,7 +37,7 @@ func (s *Service) Reconcile(ctx context.Context, accounts AccountLister, list In
}
charged := make([]string, 0, len(ids))
for _, accountID := range ids {
if accountID != utils.GlobalAccountID {
if accountID != awsidentifiers.GlobalAccountID {
charged = append(charged, accountID)
}
}
@@ -75,7 +75,7 @@ func (s *Service) Reconcile(ctx context.Context, accounts AccountLister, list In
// nothing indexes it by account, but it runs once per settled burst instead of
// once per account per tick.
func (s *Service) ReconcileAccount(ctx context.Context, accountID string, list InstanceVCPULister) error {
if s == nil || !s.limits.Enabled || accountID == utils.GlobalAccountID {
if s == nil || !s.limits.Enabled || accountID == awsidentifiers.GlobalAccountID {
return nil
}
before := s.counterRevisions(ctx, []string{accountID})
+9 -10
View File
@@ -3,9 +3,8 @@ package handlers_quota
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// staticTotals serves a fixed per-account total as one scan, and records how
@@ -81,13 +80,13 @@ func TestReconcileSkipsSystemAccount(t *testing.T) {
s := newVCPUService(t, Limits{Enabled: true, VCPUs: 100})
// Park a non-zero value directly under the system key; AddVCPU would no-op it.
seedCounter(t, s, utils.GlobalAccountID, 42)
seedCounter(t, s, awsidentifiers.GlobalAccountID, 42)
if err := s.Reconcile(context.Background(), accountList(utils.GlobalAccountID, testAccount),
staticTotals(map[string]int{utils.GlobalAccountID: 99, testAccount: 2}, true, nil)); err != nil {
if err := s.Reconcile(context.Background(), accountList(awsidentifiers.GlobalAccountID, testAccount),
staticTotals(map[string]int{awsidentifiers.GlobalAccountID: 99, testAccount: 2}, true, nil)); err != nil {
t.Fatalf("Reconcile: %v", err)
}
assertCounter(t, s, utils.GlobalAccountID, 42)
assertCounter(t, s, awsidentifiers.GlobalAccountID, 42)
assertCounter(t, s, testAccount, 2)
}
@@ -186,12 +185,12 @@ func TestReconcileAccountTouchesOnlyThatAccount(t *testing.T) {
func TestReconcileAccountSkipsSystemAccount(t *testing.T) {
s := newVCPUService(t, Limits{Enabled: true, VCPUs: 100})
seedCounter(t, s, utils.GlobalAccountID, 42)
if err := s.ReconcileAccount(context.Background(), utils.GlobalAccountID,
staticTotals(map[string]int{utils.GlobalAccountID: 0}, true, nil)); err != nil {
seedCounter(t, s, awsidentifiers.GlobalAccountID, 42)
if err := s.ReconcileAccount(context.Background(), awsidentifiers.GlobalAccountID,
staticTotals(map[string]int{awsidentifiers.GlobalAccountID: 0}, true, nil)); err != nil {
t.Fatalf("ReconcileAccount: %v", err)
}
assertCounter(t, s, utils.GlobalAccountID, 42)
assertCounter(t, s, awsidentifiers.GlobalAccountID, 42)
}
// A disabled service never reaches the KV: both entry points are a no-op even
+3 -3
View File
@@ -3,12 +3,12 @@ package handlers_quota
import (
"context"
"encoding/json"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/instancetypes"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// InstanceVCPULister totals the vCPUs each account currently holds, in one
@@ -61,7 +61,7 @@ func RecordVCPULister(records recordSource, prefix string) InstanceVCPULister {
for i := range items {
record := &items[i].Value
accountID := record.Metadata.AccountID
if accountID == "" || accountID == utils.GlobalAccountID {
if accountID == "" || accountID == awsidentifiers.GlobalAccountID {
continue
}
if recordIsTerminal(record) {
@@ -113,7 +113,7 @@ func AccountForRecord(value []byte) (accountID string, ok bool) {
if err := json.Unmarshal(value, &record); err != nil {
return "", false
}
if record.Metadata.AccountID == "" || record.Metadata.AccountID == utils.GlobalAccountID {
if record.Metadata.AccountID == "" || record.Metadata.AccountID == awsidentifiers.GlobalAccountID {
return "", false
}
return record.Metadata.AccountID, true
+3 -3
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/mulgadc/spinifex/internal/testkit"
@@ -11,7 +12,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
handlers_quota "github.com/mulgadc/spinifex/spinifex/handlers/quota"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/require"
)
@@ -69,7 +69,7 @@ func TestRecordVCPULister_ChargesStoppedButNotTerminal(t *testing.T) {
// rather than present as zero — the caller's account list is what zeroes it.
func TestRecordVCPULister_SkipsSystemAccountAndReportsNothingAsAbsent(t *testing.T) {
store := recordStore(t)
putRecord(t, store, "i-1", utils.GlobalAccountID, "m5.xlarge", vm.StateRunning)
putRecord(t, store, "i-1", awsidentifiers.GlobalAccountID, "m5.xlarge", vm.StateRunning)
totals, complete, err := handlers_quota.RecordVCPULister(store, recordPrefix)(t.Context())
require.NoError(t, err)
@@ -193,7 +193,7 @@ func TestAccountForRecord(t *testing.T) {
})
require.NoError(t, err)
system, err := json.Marshal(vm.InstanceRecord{
Metadata: resource.Metadata{Name: "i-2", AccountID: utils.GlobalAccountID},
Metadata: resource.Metadata{Name: "i-2", AccountID: awsidentifiers.GlobalAccountID},
})
require.NoError(t, err)
unowned, err := json.Marshal(vm.InstanceRecord{Metadata: resource.Metadata{Name: "i-3"}})
+5 -3
View File
@@ -2,12 +2,12 @@ package handlers_quota
import (
"context"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
)
func vol(id string, size int64) *ec2.Volume {
@@ -101,9 +101,11 @@ func TestEnforceVolumeExemptShortCircuits(t *testing.T) {
{"modify disabled", func() error {
return disabled.EnforceVolumeModify(context.Background(), nil, normalAccount, "vol-a", 1)
}},
{"create system account", func() error { return enabled.EnforceVolumeCreate(context.Background(), nil, utils.GlobalAccountID, 1) }},
{"create system account", func() error {
return enabled.EnforceVolumeCreate(context.Background(), nil, awsidentifiers.GlobalAccountID, 1)
}},
{"modify system account", func() error {
return enabled.EnforceVolumeModify(context.Background(), nil, utils.GlobalAccountID, "vol-a", 1)
return enabled.EnforceVolumeModify(context.Background(), nil, awsidentifiers.GlobalAccountID, "vol-a", 1)
}},
}
for _, tc := range cases {
+5 -3
View File
@@ -1,12 +1,12 @@
package handlers_quota
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// reservationOf builds a reservation of n instances of one type, modelling what
@@ -130,9 +130,11 @@ func TestLaunchExemptShortCircuits(t *testing.T) {
}{
{"enforce disabled", func() error { return disabled.EnforceLaunch(t.Context(), testAccount, "t3.micro", 1000) }},
{"charge disabled", func() error { return disabled.ChargeLaunch(t.Context(), testAccount, reservationOf("t3.micro", 1000)) }},
{"enforce system account", func() error { return enabled.EnforceLaunch(t.Context(), utils.GlobalAccountID, "t3.micro", 1000) }},
{"enforce system account", func() error {
return enabled.EnforceLaunch(t.Context(), awsidentifiers.GlobalAccountID, "t3.micro", 1000)
}},
{"charge system account", func() error {
return enabled.ChargeLaunch(t.Context(), utils.GlobalAccountID, reservationOf("t3.micro", 1000))
return enabled.ChargeLaunch(t.Context(), awsidentifiers.GlobalAccountID, reservationOf("t3.micro", 1000))
}},
}
for _, tc := range cases {
+2 -2
View File
@@ -2,12 +2,12 @@ package handlers_quota
import (
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// reservation builds a single reservation whose instances carry the given type
@@ -153,7 +153,7 @@ func TestEnforceRetypeExemptShortCircuits(t *testing.T) {
return disabled.EnforceRetype(t.Context(), failResolver, testAccount, "i-a", "m5.xlarge")
}},
{"system account", func() (int, error) {
return enabled.EnforceRetype(t.Context(), failResolver, utils.GlobalAccountID, "i-a", "m5.xlarge")
return enabled.EnforceRetype(t.Context(), failResolver, awsidentifiers.GlobalAccountID, "i-a", "m5.xlarge")
}},
}
for _, tc := range cases {
+3 -3
View File
@@ -1,12 +1,12 @@
package handlers_quota
import (
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"sync"
"testing"
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go/jetstream"
)
@@ -62,8 +62,8 @@ func TestVCPUExemptShortCircuits(t *testing.T) {
}{
{"check disabled", func() error { return disabled.CheckVCPU(t.Context(), testAccount, 1000) }},
{"add disabled", func() error { return disabled.AddVCPU(t.Context(), testAccount, 1000) }},
{"check system account", func() error { return enabled.CheckVCPU(t.Context(), utils.GlobalAccountID, 1000) }},
{"add system account", func() error { return enabled.AddVCPU(t.Context(), utils.GlobalAccountID, 1000) }},
{"check system account", func() error { return enabled.CheckVCPU(t.Context(), awsidentifiers.GlobalAccountID, 1000) }},
{"add system account", func() error { return enabled.AddVCPU(t.Context(), awsidentifiers.GlobalAccountID, 1000) }},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
+1 -2
View File
@@ -12,7 +12,6 @@ import (
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"
)
// The first VM behind a DB instance. Replacement and recovery increment it,
@@ -50,7 +49,7 @@ func (s *Service) CreateDBInstance(ctx context.Context, input *rds.CreateDBInsta
}
// The agent cannot bootstrap without this profile, so resolve it before the
// identifier reservation or any launch side effects.
profileARN, err := ensureInstanceProfile(s.deps.IAM, utils.GlobalAccountID)
profileARN, err := ensureInstanceProfile(s.deps.IAM, awsidentifiers.GlobalAccountID)
if err != nil {
return nil, err
}
+2 -2
View File
@@ -3,6 +3,7 @@ package handlers_rds
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"slices"
"strings"
"testing"
@@ -16,7 +17,6 @@ import (
handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc"
iammock "github.com/mulgadc/spinifex/spinifex/handlers/iam/mock"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -282,7 +282,7 @@ func TestCreateDBInstance_ProvisionsAndRecordsTheInstance(t *testing.T) {
assert.Equal(t, int64(firstVMGeneration), entry.VMGeneration)
require.NotNil(t, h.launch.launcher.input)
assert.Equal(t, rdsInstanceProfileARN(utils.GlobalAccountID), h.launch.launcher.input.IamInstanceProfileArn)
assert.Equal(t, rdsInstanceProfileARN(awsidentifiers.GlobalAccountID), h.launch.launcher.input.IamInstanceProfileArn)
}
func TestCreateDBInstance_IAMFailurePrecedesReservationAndLaunch(t *testing.T) {
+5 -5
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"time"
@@ -14,7 +15,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/mulgadc/spinifex/spinifex/utils"
)
var errFinalSnapshotInProgress = errors.New("rds: final DB snapshot creation is still in progress")
@@ -370,7 +370,7 @@ func (s *Service) takeFinalSnapshot(ctx context.Context, kv *kvstore.Bucket, acc
{Key: aws.String(rdsSnapshotAccountTagKey), Value: aws.String(accountID)},
},
}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
s.rollbackFinalSnapshotReservation(ctx, kv, rec.FinalSnapshotIdentifier, rev)
return fmt.Errorf("rds: take the final snapshot of %s: %w", rec.DBInstanceIdentifier, err)
@@ -463,7 +463,7 @@ func (s *Service) releaseDataVolume(ctx context.Context, kv *kvstore.Bucket, acc
}
_, err = s.deps.Launch.Volume.DeleteVolume(ctx, &ec2.DeleteVolumeInput{
VolumeId: aws.String(rec.DataVolumeID),
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
switch {
case err == nil || awserrors.IsNotFound(err):
return nil
@@ -512,7 +512,7 @@ func (s *Service) snapshotsHolding(ctx context.Context, volumeID string) ([]stri
Name: aws.String("volume-id"),
Values: aws.StringSlice([]string{volumeID}),
}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
if awserrors.IsNotFound(err) {
return nil, nil
@@ -543,6 +543,6 @@ func (s *Service) deleteInstanceENIs(ctx context.Context, accountID string, rec
deleteLaunchENI(ctx, vpcSvc, accountID, rec.ENIID)
}
if rec.SystemENIID != "" {
deleteLaunchENI(ctx, vpcSvc, utils.GlobalAccountID, rec.SystemENIID)
deleteLaunchENI(ctx, vpcSvc, awsidentifiers.GlobalAccountID, rec.SystemENIID)
}
}
+10 -10
View File
@@ -3,13 +3,13 @@ package handlers_rds
import (
"encoding/json"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"slices"
"testing"
"github.com/aws/aws-sdk-go/aws"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
iammock "github.com/mulgadc/spinifex/spinifex/handlers/iam/mock"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -57,12 +57,12 @@ func TestInstanceRolePolicy_GrantsOnlyTheInternalActions(t *testing.T) {
func TestEnsureInstanceProfile_CreatesInSystemAccount(t *testing.T) {
t.Parallel()
f := iammock.New()
arn, err := ensureInstanceProfile(func() handlers_iam.SystemInstanceRoleEnsurer { return f }, utils.GlobalAccountID)
arn, err := ensureInstanceProfile(func() handlers_iam.SystemInstanceRoleEnsurer { return f }, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
assert.Equal(t, "arn:aws:iam::"+utils.GlobalAccountID+":instance-profile/"+InstanceRoleName, arn)
assert.Equal(t, utils.GlobalAccountID, f.LastRoleAcct)
assert.Equal(t, utils.GlobalAccountID, f.LastProfileAcct)
assert.Equal(t, "arn:aws:iam::"+awsidentifiers.GlobalAccountID+":instance-profile/"+InstanceRoleName, arn)
assert.Equal(t, awsidentifiers.GlobalAccountID, f.LastRoleAcct)
assert.Equal(t, awsidentifiers.GlobalAccountID, f.LastProfileAcct)
assert.Equal(t, handlers_iam.EC2InstanceTrustPolicy, f.LastTrustDoc,
"AssumeRoleForInstance only mints credentials for the EC2 trust document")
}
@@ -74,9 +74,9 @@ func TestEnsureInstanceProfile_IsIdempotent(t *testing.T) {
f := iammock.New()
provider := func() handlers_iam.SystemInstanceRoleEnsurer { return f }
first, err := ensureInstanceProfile(provider, utils.GlobalAccountID)
first, err := ensureInstanceProfile(provider, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
second, err := ensureInstanceProfile(provider, utils.GlobalAccountID)
second, err := ensureInstanceProfile(provider, awsidentifiers.GlobalAccountID)
require.NoError(t, err)
assert.Equal(t, first, second)
@@ -100,7 +100,7 @@ func TestEnsureInstanceProfile_RejectsUnavailableIAM(t *testing.T) {
}
for name, provider := range tests {
t.Run(name, func(t *testing.T) {
arn, err := ensureInstanceProfile(provider, utils.GlobalAccountID)
arn, err := ensureInstanceProfile(provider, awsidentifiers.GlobalAccountID)
require.Error(t, err)
assert.Empty(t, arn)
assert.Contains(t, err.Error(), "IAM")
@@ -115,7 +115,7 @@ func TestEnsureInstanceProfile_PreservesEnsureFailure(t *testing.T) {
f.PutRolePolicyErr = ensureErr
arn, err := ensureInstanceProfile(
func() handlers_iam.SystemInstanceRoleEnsurer { return f }, utils.GlobalAccountID)
func() handlers_iam.SystemInstanceRoleEnsurer { return f }, awsidentifiers.GlobalAccountID)
require.Error(t, err)
assert.ErrorIs(t, err, ensureErr)
@@ -129,7 +129,7 @@ func TestEnsureInstanceProfile_RejectsEmptyARN(t *testing.T) {
f.EmptyInstanceProfileARN = true
arn, err := ensureInstanceProfile(
func() handlers_iam.SystemInstanceRoleEnsurer { return f }, utils.GlobalAccountID)
func() handlers_iam.SystemInstanceRoleEnsurer { return f }, awsidentifiers.GlobalAccountID)
require.Error(t, err)
assert.Empty(t, arn)
+10 -9
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"net"
"slices"
@@ -185,13 +186,13 @@ func LaunchDBInstanceVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (o
return nil, err
}
sysRefs, err := EnsureSystemVPC(ctx, deps.SystemVPC, &deps.Config.RDS, utils.GlobalAccountID, region)
sysRefs, err := EnsureSystemVPC(ctx, deps.SystemVPC, &deps.Config.RDS, awsidentifiers.GlobalAccountID, region)
if err != nil {
return nil, err
}
systemSubnetID := sysRefs.PrivateSubnetIDs[0]
systemSGID, err := EnsureSystemSecurityGroup(ctx, deps.VPC, utils.GlobalAccountID, region, sysRefs.VpcID)
systemSGID, err := EnsureSystemSecurityGroup(ctx, deps.VPC, awsidentifiers.GlobalAccountID, region, sysRefs.VpcID)
if err != nil {
return nil, err
}
@@ -223,13 +224,13 @@ func LaunchDBInstanceVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (o
}
}()
systemENI, err := createLaunchENI(ctx, deps.VPC, utils.GlobalAccountID, systemSubnetID, []string{systemSGID},
systemENI, err := createLaunchENI(ctx, deps.VPC, awsidentifiers.GlobalAccountID, systemSubnetID, []string{systemSGID},
"RDS management NIC for "+in.DBInstanceIdentifier, in.DBInstanceIdentifier, false)
if err != nil {
return nil, err
}
rollback = append(rollback, func(ctx context.Context) {
deleteLaunchENI(ctx, deps.VPC, utils.GlobalAccountID, systemENI.id)
deleteLaunchENI(ctx, deps.VPC, awsidentifiers.GlobalAccountID, systemENI.id)
})
// A replace adopts the ENI the endpoint already resolves to; only a create
@@ -261,7 +262,7 @@ func LaunchDBInstanceVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (o
ImageID: amiID,
// The VM and its primary NIC live in the system account; the customer
// ENI carries its own account so the daemon updates the right record.
AccountID: utils.GlobalAccountID,
AccountID: awsidentifiers.GlobalAccountID,
SubnetID: systemSubnetID,
ENIID: systemENI.id,
ENIMac: systemENI.mac,
@@ -314,7 +315,7 @@ func LaunchDBInstanceVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (o
{Key: aws.String(rdsInstanceTagKey), Value: aws.String(in.DBInstanceIdentifier)},
},
}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if volErr != nil {
return nil, fmt.Errorf("rds: create data volume for %s: %w", in.DBInstanceIdentifier, volErr)
}
@@ -324,7 +325,7 @@ func LaunchDBInstanceVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (o
volumeID = aws.StringValue(volume.VolumeId)
volumeEncrypted = aws.BoolValue(volume.Encrypted)
rollback = append(rollback, func(ctx context.Context) {
if _, delErr := deps.Volume.DeleteVolume(ctx, &ec2.DeleteVolumeInput{VolumeId: aws.String(volumeID)}, utils.GlobalAccountID); delErr != nil {
if _, delErr := deps.Volume.DeleteVolume(ctx, &ec2.DeleteVolumeInput{VolumeId: aws.String(volumeID)}, awsidentifiers.GlobalAccountID); delErr != nil {
slog.WarnContext(ctx, "rds: rollback delete of orphaned data volume failed",
"dbInstance", in.DBInstanceIdentifier, "volumeId", volumeID, "err", delErr)
}
@@ -338,7 +339,7 @@ func LaunchDBInstanceVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (o
}
}
device, err := deps.Attacher.AttachVolume(ctx, utils.GlobalAccountID, instanceID, volumeID, dataVolumeDevice)
device, err := deps.Attacher.AttachVolume(ctx, awsidentifiers.GlobalAccountID, instanceID, volumeID, dataVolumeDevice)
if err != nil {
return nil, fmt.Errorf("rds: attach data volume %s to %s: %w", volumeID, instanceID, err)
}
@@ -532,7 +533,7 @@ func resolveEngineAMI(ctx context.Context, amiSvc launchAMIResolver, engine, ver
})
}
out, err := amiSvc.DescribeImages(ctx, &ec2.DescribeImagesInput{Filters: filters}, utils.GlobalAccountID)
out, err := amiSvc.DescribeImages(ctx, &ec2.DescribeImagesInput{Filters: filters}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", fmt.Errorf("rds: describe %s AMI: %w", engine, err)
}
+5 -5
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strings"
"testing"
@@ -17,7 +18,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
handlers_systemvpc "github.com/mulgadc/spinifex/spinifex/handlers/systemvpc"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -572,7 +572,7 @@ func TestLaunchDBInstanceVMWiresBothNICs(t *testing.T) {
// The system NIC sits in the RDS system VPC's private subnet under the
// system account. That is the NIC with NAT egress, which is how the in-guest
// agent reaches the gateway from a customer DB subnet that has none.
assert.Equal(t, utils.GlobalAccountID, h.enis.accts[0])
assert.Equal(t, awsidentifiers.GlobalAccountID, h.enis.accts[0])
assert.True(t, strings.HasPrefix(aws.StringValue(sysENI.SubnetId), "subnet-rdssys"),
"the primary NIC must land in the RDS system VPC, got %s", aws.StringValue(sysENI.SubnetId))
// Its own ingress-free group, not the system VPC's default one — whose sole
@@ -606,7 +606,7 @@ func TestLaunchDBInstanceVMWiresBothNICs(t *testing.T) {
assert.Equal(t, sysinstance.BootAMI, in.BootMode)
assert.Equal(t, tags.ManagedByRDS, in.ManagedBy)
assert.Equal(t, testEngineAMI, in.ImageID)
assert.Equal(t, utils.GlobalAccountID, in.AccountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, in.AccountID)
assert.Equal(t, aws.StringValue(sysENI.SubnetId), in.SubnetID)
assert.Equal(t, out.SystemENIID, in.ENIID)
require.Len(t, in.ExtraENIs, 1)
@@ -718,12 +718,12 @@ func TestLaunchDBInstanceVMAttachesTheDataVolume(t *testing.T) {
assert.Equal(t, "ap-southeast-2a", aws.StringValue(vol.AvailabilityZone))
assert.Equal(t, tags.ManagedByRDS, tagOf(vol.TagSpecifications, tags.ManagedByKey))
assert.Equal(t, "mydb", tagOf(vol.TagSpecifications, rdsInstanceTagKey))
assert.Equal(t, utils.GlobalAccountID, h.volumes.accts[0], "the data volume belongs to the system account, like the VM it serves")
assert.Equal(t, awsidentifiers.GlobalAccountID, h.volumes.accts[0], "the data volume belongs to the system account, like the VM it serves")
assert.Equal(t, "i-rds0001", h.attacher.instanceID)
assert.Equal(t, "vol-rdsdata01", h.attacher.volumeID)
assert.Equal(t, dataVolumeDevice, h.attacher.device)
assert.Equal(t, utils.GlobalAccountID, h.attacher.accountID)
assert.Equal(t, awsidentifiers.GlobalAccountID, h.attacher.accountID)
assert.Equal(t, "vol-rdsdata01", out.DataVolumeID)
assert.Equal(t, vm.VolumeSerial(out.DataVolumeID), out.DataVolumeSerial)
+3 -2
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"slices"
"strings"
@@ -430,7 +431,7 @@ func (c *natsInstanceCommander) RebootInstance(ctx context.Context, instanceID s
// ownership check on the far side compares against that same account.
func (c *natsInstanceCommander) send(ctx context.Context, instanceID string, attrs ec2v1.EC2CommandAttributes) error {
cmd := ec2v1.EC2InstanceCommand{ID: instanceID, Attributes: attrs}
_, err := utils.NATSRequest[struct{}](ctx, c.nc, ec2v1.InstanceCommandSubject(instanceID), cmd, c.timeout, utils.GlobalAccountID)
_, err := utils.NATSRequest[struct{}](ctx, c.nc, ec2v1.InstanceCommandSubject(instanceID), cmd, c.timeout, awsidentifiers.GlobalAccountID)
if err == nil {
return nil
}
@@ -448,6 +449,6 @@ func (c *natsInstanceCommander) send(ctx context.Context, instanceID string, att
func (c *natsInstanceCommander) StartStoppedInstance(ctx context.Context, instanceID string) error {
_, err := utils.NATSRequest[handlers_ec2_instance.StartStoppedInstanceOutput](ctx, c.nc, "ec2.start",
handlers_ec2_instance.StartStoppedInstanceInput{InstanceID: instanceID}, c.timeout, utils.GlobalAccountID)
handlers_ec2_instance.StartStoppedInstanceInput{InstanceID: instanceID}, c.timeout, awsidentifiers.GlobalAccountID)
return err
}
+6 -6
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"sync"
"time"
@@ -14,7 +15,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/lifecycle/reconciler"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvlease"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/nats-io/nats.go/jetstream"
)
@@ -357,7 +357,7 @@ func (r *Reconciler) remediateSystemENISG(ctx context.Context, kv *kvstore.Bucke
if _, err := r.svc.deps.Launch.VPC.ModifyNetworkInterfaceAttribute(ctx, &ec2.ModifyNetworkInterfaceAttributeInput{
NetworkInterfaceId: aws.String(rec.SystemENIID),
Groups: aws.StringSlice([]string{sgID}),
}, utils.GlobalAccountID); err != nil {
}, awsidentifiers.GlobalAccountID); err != nil {
return false, fmt.Errorf("rds: move the system NIC of %s onto %s: %w", rec.DBInstanceIdentifier, sgID, err)
}
// Recorded only once vpcd has accepted the change, so a failure above is
@@ -383,11 +383,11 @@ func (r *Reconciler) ensuredSystemSG(ctx context.Context) (string, error) {
if deps.VPC == nil || deps.Config == nil {
return "", errors.New("rds reconciler: no VPC path is configured to place system NICs on their own security group")
}
refs, err := EnsureSystemVPC(ctx, deps.SystemVPC, &deps.Config.RDS, utils.GlobalAccountID, deps.Config.Region)
refs, err := EnsureSystemVPC(ctx, deps.SystemVPC, &deps.Config.RDS, awsidentifiers.GlobalAccountID, deps.Config.Region)
if err != nil {
return "", err
}
sgID, err := EnsureSystemSecurityGroup(ctx, deps.VPC, utils.GlobalAccountID, deps.Config.Region, refs.VpcID)
sgID, err := EnsureSystemSecurityGroup(ctx, deps.VPC, awsidentifiers.GlobalAccountID, deps.Config.Region, refs.VpcID)
if err != nil {
return "", err
}
@@ -764,7 +764,7 @@ func (s *Service) findEC2SnapshotFor(ctx context.Context, accountID, dbSnapshotI
Values: aws.StringSlice([]string{accountID}),
},
},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
if awserrors.IsNotFound(err) {
return "", nil
@@ -879,7 +879,7 @@ func NewDescribeInstanceState(describe func(*ec2.DescribeInstancesInput, string)
func (d *describeInstanceState) InstanceState(_ context.Context, instanceID, _ string) (string, error) {
out, err := d.describe(&ec2.DescribeInstancesInput{
InstanceIds: []*string{aws.String(instanceID)},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", err
}
+3 -3
View File
@@ -4,10 +4,10 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// The one primitive a class change, a storage grow that rides the same outage,
@@ -55,7 +55,7 @@ func (s *Service) replaceInstanceVM(ctx context.Context, kv *kvstore.Bucket, acc
}
// Resolve the profile before stopping the engine or terminating its VM. A
// profile failure must leave the current database serving.
profileARN, err := ensureInstanceProfile(s.deps.IAM, utils.GlobalAccountID)
profileARN, err := ensureInstanceProfile(s.deps.IAM, awsidentifiers.GlobalAccountID)
if err != nil {
return err
}
@@ -248,5 +248,5 @@ func (s *Service) deleteSystemENI(ctx context.Context, rec *DBInstanceRecord) {
if rec.SystemENIID == "" || s.deps.Launch.VPC == nil {
return
}
deleteLaunchENI(ctx, s.deps.Launch.VPC, utils.GlobalAccountID, rec.SystemENIID)
deleteLaunchENI(ctx, s.deps.Launch.VPC, awsidentifiers.GlobalAccountID, rec.SystemENIID)
}
+2 -2
View File
@@ -3,10 +3,10 @@ package handlers_rds
import (
"context"
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"time"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -351,5 +351,5 @@ func TestReplaceInstanceVM_LaunchesWithTheInstancesOwnIdentity(t *testing.T) {
assert.Equal(t, testAccountID, h.launch.launcher.input.ExtraENIs[0].AccountID)
assert.NotEqual(t, testAccountID, h.launch.launcher.input.AccountID,
"the VM and its management NIC live in the system account")
assert.Equal(t, rdsInstanceProfileARN(utils.GlobalAccountID), h.launch.launcher.input.IamInstanceProfileArn)
assert.Equal(t, rdsInstanceProfileARN(awsidentifiers.GlobalAccountID), h.launch.launcher.input.IamInstanceProfileArn)
}
+4 -4
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"strings"
@@ -13,7 +14,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// Builds a new DB instance on a volume created from the snapshot. It is a fresh
@@ -65,7 +65,7 @@ func (s *Service) RestoreDBInstanceFromDBSnapshot(ctx context.Context, input *rd
}
// The agent cannot bootstrap without this profile, so resolve it before the
// identifier reservation or restored-volume creation.
profileARN, err := ensureInstanceProfile(s.deps.IAM, utils.GlobalAccountID)
profileARN, err := ensureInstanceProfile(s.deps.IAM, awsidentifiers.GlobalAccountID)
if err != nil {
return nil, err
}
@@ -384,7 +384,7 @@ func (s *Service) createRestoreVolume(ctx context.Context, req *validatedCreate,
{Key: aws.String(rdsInstanceTagKey), Value: aws.String(req.Identifier)},
},
}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return nil, fmt.Errorf("rds: create the data volume for %s from %s: %w",
req.Identifier, snapshot.DBSnapshotIdentifier, err)
@@ -404,7 +404,7 @@ func (s *Service) discardRestoreVolume(ctx context.Context, volumeID string) {
defer cancel()
if _, err := s.deps.Launch.Volume.DeleteVolume(rbCtx, &ec2.DeleteVolumeInput{
VolumeId: aws.String(volumeID),
}, utils.GlobalAccountID); err != nil && !awserrors.IsNotFound(err) {
}, awsidentifiers.GlobalAccountID); err != nil && !awserrors.IsNotFound(err) {
slog.WarnContext(rbCtx, "rds: rollback delete of a restored data volume failed",
"volumeId", volumeID, "err", err)
}
+3 -3
View File
@@ -2,6 +2,7 @@ package handlers_rds
import (
"errors"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"testing"
"time"
@@ -10,7 +11,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -57,7 +57,7 @@ func TestRestoreDBInstanceFromDBSnapshot_BuildsANewInstanceOnTheSnapshotsData(t
assert.Equal(t, tags.ManagedByRDS, tagOf(created[0].TagSpecifications, tags.ManagedByKey))
// System-owned like every RDS data volume, so the customer reaches it only
// through the DB instance.
assert.Equal(t, []string{utils.GlobalAccountID}, h.launch.volumes.accts)
assert.Equal(t, []string{awsidentifiers.GlobalAccountID}, h.launch.volumes.accts)
stored := h.instance(t, testRestoredID)
assert.Equal(t, "vol-rdsdata01", stored.DataVolumeID)
@@ -72,7 +72,7 @@ func TestRestoreDBInstanceFromDBSnapshot_BuildsANewInstanceOnTheSnapshotsData(t
assert.Empty(t, stored.Bootstrap.MasterUserPassword)
require.NotNil(t, h.launch.launcher.input)
assert.Equal(t, rdsInstanceProfileARN(utils.GlobalAccountID), h.launch.launcher.input.IamInstanceProfileArn)
assert.Equal(t, rdsInstanceProfileARN(awsidentifiers.GlobalAccountID), h.launch.launcher.input.IamInstanceProfileArn)
}
func TestRestoreDBInstanceFromDBSnapshot_IAMFailurePrecedesReservationAndVolume(t *testing.T) {
+4 -4
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"slices"
"strings"
@@ -15,7 +16,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// The EC2 snapshot surface the RDS control plane drives. A DB snapshot is an
@@ -174,7 +174,7 @@ func (s *Service) snapshotDataVolume(ctx context.Context, accountID string, rec
{Key: aws.String(rdsSnapshotAccountTagKey), Value: aws.String(accountID)},
},
}},
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return "", crashConsistent, fmt.Errorf("rds: snapshot the data volume of %s: %w", rec.DBInstanceIdentifier, err)
}
@@ -368,7 +368,7 @@ func (s *Service) deleteEC2Snapshot(ctx context.Context, kv *kvstore.Bucket, acc
}
_, err := s.deps.Snapshots.DeleteSnapshot(ctx, &ec2.DeleteSnapshotInput{
SnapshotId: aws.String(rec.SnapshotID),
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
switch {
case err == nil || awserrors.IsNotFound(err):
return nil
@@ -444,7 +444,7 @@ func (s *Service) reclaimRetainedVolume(ctx context.Context, kv *kvstore.Bucket,
}
_, err = s.deps.Launch.Volume.DeleteVolume(ctx, &ec2.DeleteVolumeInput{
VolumeId: aws.String(retained.VolumeID),
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
switch {
case err == nil || awserrors.IsNotFound(err):
case awserrors.IsErrorCode(err, awserrors.ErrorVolumeInUse):
+3 -3
View File
@@ -4,12 +4,12 @@ import (
"context"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/utils"
)
// ModifyVolume refuses a volume a running VM holds, so a storage grow is
@@ -128,7 +128,7 @@ func (s *Service) growDataVolume(ctx context.Context, volumeID string, targetGiB
if _, err := s.deps.Storage.ModifyVolume(ctx, &ec2.ModifyVolumeInput{
VolumeId: aws.String(volumeID),
Size: aws.Int64(targetGiB),
}, utils.GlobalAccountID); err != nil {
}, awsidentifiers.GlobalAccountID); err != nil {
return fmt.Errorf("grow the data volume %s to %d GiB: %w", volumeID, targetGiB, err)
}
slog.InfoContext(ctx, "rds: data volume grown",
@@ -142,7 +142,7 @@ func (s *Service) growDataVolume(ctx context.Context, volumeID string, targetGiB
func (s *Service) dataVolumeSize(ctx context.Context, volumeID string) (int64, error) {
out, err := s.deps.Storage.DescribeVolumes(ctx, &ec2.DescribeVolumesInput{
VolumeIds: aws.StringSlice([]string{volumeID}),
}, utils.GlobalAccountID)
}, awsidentifiers.GlobalAccountID)
if err != nil {
return 0, fmt.Errorf("read the data volume %s: %w", volumeID, err)
}
+2 -2
View File
@@ -10,6 +10,7 @@ import (
"encoding/json"
"errors"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"log/slog"
"regexp"
"slices"
@@ -24,7 +25,6 @@ import (
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvstore"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
"github.com/mulgadc/spinifex/spinifex/utils"
)
const (
@@ -438,7 +438,7 @@ func matchAWSPrincipalEntry(clause, callerARN string) bool {
if clause == globalWildcard {
return true
}
if utils.IsAccountID(clause) {
if awsidentifiers.IsAccountID(clause) {
clause = arn.FormatIAMRoot(clause)
}
if clause == callerARN {
+2 -2
View File
@@ -6,6 +6,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"strings"
"testing"
"time"
@@ -15,13 +16,12 @@ import (
"github.com/aws/aws-sdk-go/service/sts"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
"github.com/mulgadc/spinifex/spinifex/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const (
testCallerAccountID = utils.GlobalAccountID
testCallerAccountID = awsidentifiers.GlobalAccountID
testCallerUserName = "alice"
testCallerAccessKeyID = "AKIAIOSFODNN7EXAMPLE"
testCrossAccountID = "999999999999"

Some files were not shown because too many files have changed in this diff Show More