mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
refactor: move account identifiers to aws identifiers
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
-1
@@ -1,4 +1,4 @@
|
||||
package utils
|
||||
package identifiers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
}},
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
}},
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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 == "" {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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,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)
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,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})
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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"}})
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,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)
|
||||
}
|
||||
|
||||
@@ -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,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):
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user