refactor: move system instance contract to EC2 domain

This commit is contained in:
joshsiv-mulga
2026-10-06 11:48:12 +10:00
parent b292ffd959
commit cabe0e99b2
19 changed files with 90 additions and 90 deletions
+5 -5
View File
@@ -9,10 +9,10 @@ import (
"strings"
"time"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/telemetry"
handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/nats-io/nats.go"
)
@@ -136,7 +136,7 @@ const systemTerminateRemoteTimeout = 90 * time.Second
// ErrSystemInstanceNotFound, which callers treat as idempotent success.
func (d *Daemon) terminateSystemInstanceRemote(instanceID string) error {
if d.natsConn == nil {
return fmt.Errorf("%w: %s", sysinstance.ErrSystemInstanceNotFound, instanceID)
return fmt.Errorf("%w: %s", systeminstance.ErrSystemInstanceNotFound, instanceID)
}
subject := fmt.Sprintf("system.TerminateInstance.%s", instanceID)
reply, err := d.natsConn.Request(subject, nil, systemTerminateRemoteTimeout)
@@ -144,7 +144,7 @@ func (d *Daemon) terminateSystemInstanceRemote(instanceID string) error {
if errors.Is(err, nats.ErrNoResponders) {
slog.Debug("terminateSystemInstanceRemote: no owner subscribed; VM already gone",
"instanceId", instanceID)
return fmt.Errorf("%w: %s", sysinstance.ErrSystemInstanceNotFound, instanceID)
return fmt.Errorf("%w: %s", systeminstance.ErrSystemInstanceNotFound, instanceID)
}
return fmt.Errorf("route terminate %s: %w", instanceID, err)
}
@@ -153,8 +153,8 @@ func (d *Daemon) terminateSystemInstanceRemote(instanceID string) error {
return fmt.Errorf("decode routed terminate reply %s: %w", instanceID, err)
}
if env.Error != "" {
if strings.Contains(env.Error, sysinstance.ErrSystemInstanceNotFound.Error()) {
return fmt.Errorf("%w: %s", sysinstance.ErrSystemInstanceNotFound, instanceID)
if strings.Contains(env.Error, systeminstance.ErrSystemInstanceNotFound.Error()) {
return fmt.Errorf("%w: %s", systeminstance.ErrSystemInstanceNotFound, instanceID)
}
return fmt.Errorf("routed terminate %s: %s", instanceID, env.Error)
}
@@ -5,8 +5,8 @@ import (
"testing"
"time"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -379,7 +379,7 @@ func TestTerminateSystemInstanceRemote_NoResponders(t *testing.T) {
err = d.terminateSystemInstanceRemote("i-orphan")
require.Error(t, err)
assert.ErrorIs(t, err, sysinstance.ErrSystemInstanceNotFound,
assert.ErrorIs(t, err, systeminstance.ErrSystemInstanceNotFound,
"no owner means the VM is gone — caller must see idempotent NotFound, not a hang")
}
@@ -395,7 +395,7 @@ func TestTerminateSystemInstanceRemote_NotFoundPropagated(t *testing.T) {
sub, err := nc.Subscribe("system.TerminateInstance.i-gone", func(msg *nats.Msg) {
payload, _ := json.Marshal(systemInstanceTerminateEnvelope{
Error: sysinstance.ErrSystemInstanceNotFound.Error() + ": i-gone",
Error: systeminstance.ErrSystemInstanceNotFound.Error() + ": i-gone",
})
_ = msg.Respond(payload)
})
@@ -404,7 +404,7 @@ func TestTerminateSystemInstanceRemote_NotFoundPropagated(t *testing.T) {
err = d.terminateSystemInstanceRemote("i-gone")
require.Error(t, err)
assert.ErrorIs(t, err, sysinstance.ErrSystemInstanceNotFound)
assert.ErrorIs(t, err, systeminstance.ErrSystemInstanceNotFound)
}
// TestTerminateSystemInstanceRemote_ErrorPropagated: a real teardown failure on
@@ -427,7 +427,7 @@ func TestTerminateSystemInstanceRemote_ErrorPropagated(t *testing.T) {
err = d.terminateSystemInstanceRemote("i-stuck")
require.Error(t, err)
assert.Contains(t, err.Error(), "volume detach timed out")
assert.NotErrorIs(t, err, sysinstance.ErrSystemInstanceNotFound,
assert.NotErrorIs(t, err, systeminstance.ErrSystemInstanceNotFound,
"a real failure must not be misreported as idempotent NotFound")
}
@@ -437,7 +437,7 @@ func TestTerminateSystemInstanceRemote_WithoutConn(t *testing.T) {
d := &Daemon{node: "node-a"}
err := d.terminateSystemInstanceRemote("i-x")
require.Error(t, err)
assert.ErrorIs(t, err, sysinstance.ErrSystemInstanceNotFound)
assert.ErrorIs(t, err, systeminstance.ErrSystemInstanceNotFound)
}
// TestHandleSystemLaunchInstance_PanicRecovered drives a valid launch against a
+6 -6
View File
@@ -15,11 +15,11 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/contracts/ec2/v1"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
awsidentifiers "github.com/mulgadc/spinifex/spinifex/foundation/aws/identifiers"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc"
handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/mulgadc/spinifex/spinifex/network/topology"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
hostprocess "github.com/mulgadc/spinifex/spinifex/runtime/host/process"
@@ -60,7 +60,7 @@ func (d *Daemon) recordENIInstanceOwner(eniAccountID, eniID, instanceOwnerID str
// for an explicit DeleteOnTermination, persists it onto the record. An ENI that
// has to outlive its VM is only safe once that flag is stored, so a failed stamp
// fails the attach rather than leaving a disposable NIC behind.
func (d *Daemon) attachExtraENI(eniAccountID string, extra sysinstance.ExtraENIInput, instanceID string, deviceIndex int64) error {
func (d *Daemon) attachExtraENI(eniAccountID string, extra systeminstance.ExtraENIInput, instanceID string, deviceIndex int64) error {
if _, err := d.vpcService.AttachENI(eniAccountID, extra.ENIID, instanceID, deviceIndex); err != nil {
return err
}
@@ -81,7 +81,7 @@ func (d *Daemon) attachExtraENI(eniAccountID string, extra sysinstance.ExtraENII
// (bundled vmlinuz+initramfs, fw_cfg-delivered config). There is no AMI,
// volume, or cloud-init path.
func (d *Daemon) LaunchSystemInstance(input *handlers_elbv2.SystemInstanceInput) (*handlers_elbv2.SystemInstanceOutput, error) {
if input.BootMode == sysinstance.BootAMI {
if input.BootMode == systeminstance.BootAMI {
return d.launchAMISystemInstance(input)
}
accountID := awsidentifiers.GlobalAccountID
@@ -442,7 +442,7 @@ func (d *Daemon) LaunchSystemInstance(input *handlers_elbv2.SystemInstanceInput)
// gets the same admission, GPU claim and teardown-time release as a customer
// VM: PrepareRunInstances gates on a free GPU slot, LaunchRunInstances claims
// the device, and vm.Manager's cleanup chain releases it.
func (d *Daemon) launchAMISystemInstance(input *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) {
func (d *Daemon) launchAMISystemInstance(input *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error) {
if d.instanceService == nil {
return nil, errors.New("sysinstance: instance service not initialized")
}
@@ -540,7 +540,7 @@ func (d *Daemon) launchAMISystemInstance(input *sysinstance.SystemInstanceInput)
"mgmtIP", inst.MgmtIP,
"privateIp", privateIP,
)
return &sysinstance.SystemInstanceOutput{
return &systeminstance.SystemInstanceOutput{
InstanceID: inst.ID,
PrivateIP: privateIP,
MgmtIP: inst.MgmtIP,
@@ -631,7 +631,7 @@ func (d *Daemon) reclaimSystemInstanceEIP(instanceID string) {
func (d *Daemon) terminateSystemInstanceLocal(instanceID string) error {
instance, exists := d.vmMgr.Get(instanceID)
if !exists {
return fmt.Errorf("%w: %s", sysinstance.ErrSystemInstanceNotFound, instanceID)
return fmt.Errorf("%w: %s", systeminstance.ErrSystemInstanceNotFound, instanceID)
}
// Release EIP through the EIP service for system VMs whose public IP was
@@ -13,13 +13,13 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
handlers_ec2_eip "github.com/mulgadc/spinifex/spinifex/handlers/ec2/eip"
handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc"
"github.com/mulgadc/spinifex/spinifex/handlers/elbv2"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/mulgadc/spinifex/spinifex/network/external"
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
"github.com/nats-io/nats.go"
@@ -917,7 +917,7 @@ func TestAttachExtraENI_DeleteOnTerminationFalseSurvivesTerminate(t *testing.T)
f := newENIHotPlugFixture(t)
f.vmInst.AccountID = testAccountID
require.NoError(t, f.daemon.attachExtraENI(testAccountID, sysinstance.ExtraENIInput{
require.NoError(t, f.daemon.attachExtraENI(testAccountID, systeminstance.ExtraENIInput{
ENIID: f.eniID,
DeleteOnTermination: aws.Bool(false),
}, f.vmInst.ID, 1))
@@ -942,7 +942,7 @@ func TestAttachExtraENI_NilDeleteOnTerminationStaysDisposable(t *testing.T) {
f := newENIHotPlugFixture(t)
f.vmInst.AccountID = testAccountID
require.NoError(t, f.daemon.attachExtraENI(testAccountID, sysinstance.ExtraENIInput{
require.NoError(t, f.daemon.attachExtraENI(testAccountID, systeminstance.ExtraENIInput{
ENIID: f.eniID,
}, f.vmInst.ID, 1))
@@ -1,8 +1,8 @@
// Package sysinstance holds the boot-agnostic contract for system-managed VMs.
// Package systeminstance holds the boot-agnostic contract for system-managed VMs.
// Hidden from DescribeInstances; supports two boot styles: BootDirect (fw_cfg microVM)
// and BootAMI (AMI booting from the Ec2 IMDS datasource). Types live here to avoid an
// eks→elbv2 import cycle.
package sysinstance
package systeminstance
import "errors"
+7 -7
View File
@@ -11,8 +11,8 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
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"
)
@@ -300,16 +300,16 @@ func (f *fakeAttacher) AttachVolume(_ context.Context, _, _, _, device string) (
type fakeInstanceLauncher struct {
mu sync.Mutex
launchCount atomic.Int32
requests []*sysinstance.SystemInstanceInput
requests []*systeminstance.SystemInstanceInput
terminated []string
nextID int
failLaunch error
terminateErr error
}
var _ sysinstance.SystemInstanceLauncher = (*fakeInstanceLauncher)(nil)
var _ systeminstance.SystemInstanceLauncher = (*fakeInstanceLauncher)(nil)
func (f *fakeInstanceLauncher) LaunchSystemInstance(in *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) {
func (f *fakeInstanceLauncher) LaunchSystemInstance(in *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error) {
f.launchCount.Add(1)
f.mu.Lock()
f.requests = append(f.requests, in)
@@ -321,12 +321,12 @@ func (f *fakeInstanceLauncher) LaunchSystemInstance(in *sysinstance.SystemInstan
f.nextID++
id := f.nextID
f.mu.Unlock()
return &sysinstance.SystemInstanceOutput{InstanceID: fmt.Sprintf("i-%d", id)}, nil
return &systeminstance.SystemInstanceOutput{InstanceID: fmt.Sprintf("i-%d", id)}, nil
}
// lastInput returns the most recent LaunchSystemInstance request, for tests
// that assert on how a launch was wired.
func (f *fakeInstanceLauncher) lastInput() *sysinstance.SystemInstanceInput {
func (f *fakeInstanceLauncher) lastInput() *systeminstance.SystemInstanceInput {
f.mu.Lock()
defer f.mu.Unlock()
if len(f.requests) == 0 {
@@ -335,7 +335,7 @@ func (f *fakeInstanceLauncher) lastInput() *sysinstance.SystemInstanceInput {
return f.requests[len(f.requests)-1]
}
func (f *fakeInstanceLauncher) launches() []*sysinstance.SystemInstanceInput {
func (f *fakeInstanceLauncher) launches() []*systeminstance.SystemInstanceInput {
f.mu.Lock()
defer f.mu.Unlock()
return f.requests
+6 -6
View File
@@ -14,10 +14,10 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
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"
)
@@ -62,7 +62,7 @@ type LaunchDeps struct {
Config *config.Config
SystemVPC handlers_systemvpc.Deps
VPC launchVPCProvisioner
Instance sysinstance.SystemInstanceLauncher
Instance systeminstance.SystemInstanceLauncher
Image amiResolver
Volume launchVolumeProvisioner
Attacher volumeAttacher
@@ -292,8 +292,8 @@ func LaunchServingVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (out
Members: userDataMembers,
})
sysOut, err := deps.Instance.LaunchSystemInstance(&sysinstance.SystemInstanceInput{
BootMode: sysinstance.BootAMI,
sysOut, err := deps.Instance.LaunchSystemInstance(&systeminstance.SystemInstanceInput{
BootMode: systeminstance.BootAMI,
ManagedBy: tags.ManagedByBedrock,
InstanceType: in.InstanceType,
ImageID: amiID,
@@ -316,7 +316,7 @@ func LaunchServingVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (out
instanceID := sysOut.InstanceID
terminateVM = func(ctx context.Context) {
if termErr := deps.Instance.TerminateSystemInstance(instanceID); termErr != nil &&
!errors.Is(termErr, sysinstance.ErrSystemInstanceNotFound) {
!errors.Is(termErr, systeminstance.ErrSystemInstanceNotFound) {
slog.WarnContext(ctx, "bedrock: rollback terminate of failed serving VM failed",
"group", in.GroupID, "instanceId", instanceID, "err", termErr)
}
@@ -362,7 +362,7 @@ func TerminateServingVM(ctx context.Context, deps LaunchDeps, rec EndpointRecord
var errs []error
if rec.InstanceID != "" {
if err := deps.Instance.TerminateSystemInstance(rec.InstanceID); err != nil &&
!errors.Is(err, sysinstance.ErrSystemInstanceNotFound) {
!errors.Is(err, systeminstance.ErrSystemInstanceNotFound) {
errs = append(errs, fmt.Errorf("terminate instance %s: %w", rec.InstanceID, err))
}
}
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"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/nats-io/nats.go"
"github.com/stretchr/testify/assert"
@@ -352,7 +352,7 @@ func TestDelete_BareDeleteMissesAccountScopedPinnedButScopedClearsGoneVM(t *test
// The instance vanished out of band: the scoped delete must still clear the
// record rather than stall on a gone VM.
h.launcher.terminateErr = sysinstance.ErrSystemInstanceNotFound
h.launcher.terminateErr = systeminstance.ErrSystemInstanceNotFound
scoped, err := s.Delete(t.Context(), &DeleteEndpointInput{ModelID: testModelID, AccountID: testAccountID}, "")
require.NoError(t, err)
@@ -16,9 +16,9 @@ import (
types "github.com/mulgadc/spinifex/contracts/cluster/v1"
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/instancetypes"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
handlers_ec2_placementgroup "github.com/mulgadc/spinifex/spinifex/handlers/ec2/placementgroup"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -224,11 +224,11 @@ type seqK3sInst struct {
var _ k3sInstanceLauncher = (*seqK3sInst)(nil)
func (i *seqK3sInst) LaunchSystemInstance(in *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) {
func (i *seqK3sInst) LaunchSystemInstance(in *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error) {
return i.LaunchSystemInstanceOnNode("", in)
}
func (i *seqK3sInst) LaunchSystemInstanceOnNode(nodeID string, in *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) {
func (i *seqK3sInst) LaunchSystemInstanceOnNode(nodeID string, in *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error) {
i.mu.Lock()
defer i.mu.Unlock()
if i.failNodes[nodeID] {
@@ -243,7 +243,7 @@ func (i *seqK3sInst) LaunchSystemInstanceOnNode(nodeID string, in *sysinstance.S
if nodeID == "" {
id = "i-local"
}
return &sysinstance.SystemInstanceOutput{InstanceID: id, MgmtIP: "10.255.0.9"}, nil
return &systeminstance.SystemInstanceOutput{InstanceID: id, MgmtIP: "10.255.0.9"}, nil
}
func (i *seqK3sInst) TerminateSystemInstance(instanceID string) error {
+6 -6
View File
@@ -13,10 +13,10 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
awsami "github.com/mulgadc/spinifex/spinifex/foundation/aws/ami"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
)
// ErrEKSServerAMINotFound is returned when no AMI with the EKS managed-by tag
@@ -41,10 +41,10 @@ type k3sVPCProvisioner interface {
// The VM boots from the eks-server AMI and needs a mgmt-bridge NIC via the
// system-instance path to reach the daemon's NATS endpoint.
type k3sInstanceLauncher interface {
LaunchSystemInstance(input *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error)
LaunchSystemInstance(input *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error)
// LaunchSystemInstanceOnNode pins the VM to a specific host for HA spread.
// An empty nodeID launches in-process like LaunchSystemInstance.
LaunchSystemInstanceOnNode(nodeID string, input *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error)
LaunchSystemInstanceOnNode(nodeID string, input *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error)
TerminateSystemInstance(instanceID string) error
}
@@ -248,8 +248,8 @@ func LaunchK3sServerVM(ctx context.Context,
userData := buildK3sUserData(in)
sysOut, err := instSvc.LaunchSystemInstanceOnNode(in.TargetNodeID, &sysinstance.SystemInstanceInput{
BootMode: sysinstance.BootAMI,
sysOut, err := instSvc.LaunchSystemInstanceOnNode(in.TargetNodeID, &systeminstance.SystemInstanceInput{
BootMode: systeminstance.BootAMI,
ManagedBy: tags.ManagedByEKS,
InstanceType: instanceType,
ImageID: amiID,
@@ -301,7 +301,7 @@ func TerminateK3sServerVM(ctx context.Context,
if instanceID != "" {
// "instance not found" on a retry is idempotent success; proceed to the ENI/SG/KV sweep.
if err := instSvc.TerminateSystemInstance(instanceID); err != nil {
if errors.Is(err, sysinstance.ErrSystemInstanceNotFound) {
if errors.Is(err, systeminstance.ErrSystemInstanceNotFound) {
slog.DebugContext(ctx, "TerminateK3sServerVM: instance already gone", "instanceId", instanceID)
} else {
slog.WarnContext(ctx, "TerminateK3sServerVM: terminate failed", "instanceId", instanceID, "err", err)
+9 -9
View File
@@ -10,9 +10,9 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -95,22 +95,22 @@ func (f *fakeK3sVPC) DescribeNetworkInterfaces(_ context.Context, input *ec2.Des
}
type fakeK3sInst struct {
launchCalls []*sysinstance.SystemInstanceInput
launchCalls []*systeminstance.SystemInstanceInput
launchNodes []string // TargetNodeID per launch (parallel to launchCalls)
terminateCalls []string
launchOut *sysinstance.SystemInstanceOutput
launchOut *systeminstance.SystemInstanceOutput
launchErr error
terminateErr error
}
var _ k3sInstanceLauncher = (*fakeK3sInst)(nil)
func (f *fakeK3sInst) LaunchSystemInstance(input *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) {
func (f *fakeK3sInst) LaunchSystemInstance(input *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error) {
return f.LaunchSystemInstanceOnNode("", input)
}
func (f *fakeK3sInst) LaunchSystemInstanceOnNode(nodeID string, input *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) {
func (f *fakeK3sInst) LaunchSystemInstanceOnNode(nodeID string, input *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error) {
f.launchCalls = append(f.launchCalls, input)
f.launchNodes = append(f.launchNodes, nodeID)
if f.launchErr != nil {
@@ -119,7 +119,7 @@ func (f *fakeK3sInst) LaunchSystemInstanceOnNode(nodeID string, input *sysinstan
if f.launchOut != nil {
return f.launchOut, nil
}
return &sysinstance.SystemInstanceOutput{InstanceID: "i-aaa111"}, nil
return &systeminstance.SystemInstanceOutput{InstanceID: "i-aaa111"}, nil
}
func (f *fakeK3sInst) TerminateSystemInstance(instanceID string) error {
@@ -332,7 +332,7 @@ func TestLaunchK3sServerVM_HappyPath(t *testing.T) {
require.Len(t, inst.launchCalls, 1)
runIn := inst.launchCalls[0]
assert.Equal(t, sysinstance.BootAMI, runIn.BootMode)
assert.Equal(t, systeminstance.BootAMI, runIn.BootMode)
assert.Equal(t, tags.ManagedByEKS, runIn.ManagedBy)
assert.Equal(t, "ami-eks-server-001", runIn.ImageID)
assert.Equal(t, defaultK3sServerInstanceType, runIn.InstanceType)
@@ -660,7 +660,7 @@ func TestK3sServerJoinURL(t *testing.T) {
func TestLaunchK3sServerVM_RunInstancesEmptyReservationRollsBack(t *testing.T) {
vpc, ami := &fakeK3sVPC{}, &fakeK3sAMI{}
inst := &fakeK3sInst{launchOut: &sysinstance.SystemInstanceOutput{}}
inst := &fakeK3sInst{launchOut: &systeminstance.SystemInstanceOutput{}}
_, err := LaunchK3sServerVM(context.Background(), vpc, inst, ami, validK3sInput())
require.Error(t, err)
@@ -753,7 +753,7 @@ func TestTerminateK3sServerVM_InstanceAlreadyGoneIsIdempotent(t *testing.T) {
// returns ErrSystemInstanceNotFound. This must not block teardown; the ENI
// delete still runs.
vpc := &fakeK3sVPC{}
inst := &fakeK3sInst{terminateErr: fmt.Errorf("%w: i-aaa111", sysinstance.ErrSystemInstanceNotFound)}
inst := &fakeK3sInst{terminateErr: fmt.Errorf("%w: i-aaa111", systeminstance.ErrSystemInstanceNotFound)}
err := TerminateK3sServerVM(context.Background(), vpc, inst, "111122223333", "i-aaa111", "eni-aaa111")
require.NoError(t, err, "instance already gone must be idempotent success")
+4 -4
View File
@@ -10,9 +10,9 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
)
// nlbProvisioner is the narrow ELBv2 surface needed by cluster NLB helpers.
@@ -21,7 +21,7 @@ type nlbProvisioner interface {
CreateLoadBalancerSync(input *elbv2.CreateLoadBalancerInput, accountID string) (*elbv2.CreateLoadBalancerOutput, error)
// CreateClusterNLBSync is CreateLoadBalancerSync plus cross-account ENIs threaded
// onto the LB VM at launch (the customer-VPC Set A private-endpoint NIC).
CreateClusterNLBSync(input *elbv2.CreateLoadBalancerInput, accountID string, crossAccountENIs []sysinstance.ExtraENIInput) (*elbv2.CreateLoadBalancerOutput, error)
CreateClusterNLBSync(input *elbv2.CreateLoadBalancerInput, accountID string, crossAccountENIs []systeminstance.ExtraENIInput) (*elbv2.CreateLoadBalancerOutput, error)
DescribeLoadBalancers(ctx context.Context, input *elbv2.DescribeLoadBalancersInput, accountID string) (*elbv2.DescribeLoadBalancersOutput, error)
DeleteLoadBalancer(ctx context.Context, input *elbv2.DeleteLoadBalancerInput, accountID string) (*elbv2.DeleteLoadBalancerOutput, error)
DescribeTags(ctx context.Context, input *elbv2.DescribeTagsInput, accountID string) (*elbv2.DescribeTagsOutput, error)
@@ -139,7 +139,7 @@ func safeELBv2Name(prefix, clusterName, suffix string) string {
// NLB managed-SG ingress; ignored for an internal NLB (its ingress already
// tracks the VPC CIDR) and for the wide-open default, which the LB carries out
// of the box.
func EnsureClusterNLB(ctx context.Context, nlbp nlbProvisioner, accountID, clusterName string, subnetIDs []string, internetFacing bool, publicAccessCidrs []string, crossAccountENIs []sysinstance.ExtraENIInput) (*ClusterNLB, error) {
func EnsureClusterNLB(ctx context.Context, nlbp nlbProvisioner, accountID, clusterName string, subnetIDs []string, internetFacing bool, publicAccessCidrs []string, crossAccountENIs []systeminstance.ExtraENIInput) (*ClusterNLB, error) {
if clusterName == "" {
return nil, errors.New("eks: EnsureClusterNLB empty cluster name")
}
@@ -346,7 +346,7 @@ func deleteClusterTG(ctx context.Context, nlbp nlbProvisioner, accountID, tgName
return nil
}
func ensureClusterLB(ctx context.Context, nlbp nlbProvisioner, accountID, clusterName, lbName string, subnetIDs []string, internetFacing bool, crossAccountENIs []sysinstance.ExtraENIInput, out *ClusterNLB) error {
func ensureClusterLB(ctx context.Context, nlbp nlbProvisioner, accountID, clusterName, lbName string, subnetIDs []string, internetFacing bool, crossAccountENIs []systeminstance.ExtraENIInput, out *ClusterNLB) error {
if lb, err := lookupLBByName(ctx, nlbp, accountID, lbName); err != nil {
return err
} else if lb != nil {
+3 -3
View File
@@ -9,8 +9,8 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -18,7 +18,7 @@ import (
type fakeNLBProvisioner struct {
createLBCalls []*elbv2.CreateLoadBalancerInput
createLBSyncCalls []*elbv2.CreateLoadBalancerInput
createClusterNLBExtras [][]sysinstance.ExtraENIInput
createClusterNLBExtras [][]systeminstance.ExtraENIInput
describeLBCalls []*elbv2.DescribeLoadBalancersInput
deleteLBCalls []*elbv2.DeleteLoadBalancerInput
createTGCalls []*elbv2.CreateTargetGroupInput
@@ -95,7 +95,7 @@ func (f *fakeNLBProvisioner) CreateLoadBalancerSync(input *elbv2.CreateLoadBalan
// CreateClusterNLBSync records the cross-account ENIs and delegates to the sync
// path so existing front-end-IP assertions still hold.
func (f *fakeNLBProvisioner) CreateClusterNLBSync(input *elbv2.CreateLoadBalancerInput, accountID string, crossAccountENIs []sysinstance.ExtraENIInput) (*elbv2.CreateLoadBalancerOutput, error) {
func (f *fakeNLBProvisioner) CreateClusterNLBSync(input *elbv2.CreateLoadBalancerInput, accountID string, crossAccountENIs []systeminstance.ExtraENIInput) (*elbv2.CreateLoadBalancerOutput, error) {
f.createClusterNLBExtras = append(f.createClusterNLBExtras, crossAccountENIs)
return f.CreateLoadBalancerSync(input, accountID)
}
@@ -7,8 +7,8 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -153,7 +153,7 @@ func TestEnsurePrivateEndpointENI_EmptyInputsRejected(t *testing.T) {
func TestEnsureClusterNLB_ThreadsCrossAccountENIToSyncCreate(t *testing.T) {
nlbp := newFakeNLBProvisioner()
extras := []sysinstance.ExtraENIInput{{
extras := []systeminstance.ExtraENIInput{{
ENIID: "eni-pe-001",
ENIMac: "02:0a:01:23:45:67",
ENIIP: "10.0.1.50",
+3 -3
View File
@@ -23,13 +23,13 @@ import (
"github.com/mulgadc/bluebottle/pkg/auth"
"github.com/mulgadc/spinifex/spinifex/admin"
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
resourcearn "github.com/mulgadc/spinifex/spinifex/foundation/aws/arn"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/lifecycle/idempotency"
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvlease"
handlers_dns "github.com/mulgadc/spinifex/spinifex/handlers/dns"
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
"github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
"github.com/mulgadc/spinifex/spinifex/providers/objectstore"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
@@ -792,7 +792,7 @@ func (s *EKSServiceImpl) launchClusterInfra(ctx context.Context, lc clusterLaunc
// extra NIC. Persist its refs immediately so teardown reclaims them on any later
// failure. nginx(L4) on the LB VM binds all addresses, so it answers the Set A
// NIC and proxies to the CP target group with no data-plane change.
var crossAccountENIs []sysinstance.ExtraENIInput
var crossAccountENIs []systeminstance.ExtraENIInput
if privateAccess {
pe, perr := EnsurePrivateEndpointENI(ctx, s.deps.VPCK3s, s.deps.VPCSG, s.deps.VPCSubnet, accountID, name, lc.subnetIDs[0], lc.vpcID)
if perr != nil {
@@ -805,7 +805,7 @@ func (s *EKSServiceImpl) launchClusterInfra(ctx context.Context, lc clusterLaunc
s.failClusterLaunch(ctx, acctKV, name, accountID, meta, "persist private endpoint refs", err)
return
}
crossAccountENIs = []sysinstance.ExtraENIInput{{
crossAccountENIs = []systeminstance.ExtraENIInput{{
ENIID: pe.ENIID,
ENIMac: pe.ENIMac,
ENIIP: pe.ENIIP,
+8 -8
View File
@@ -1,14 +1,14 @@
package handlers_elbv2
import "github.com/mulgadc/spinifex/spinifex/handlers/sysinstance"
import "github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
// These aliases re-export sysinstance types so ELBv2 and EKS share launch
// These aliases re-export systeminstance types so ELBv2 and EKS share launch
// logic without an eks→elbv2 dependency. ELBv2 always uses BootMode=BootDirect.
type (
SystemInstanceLauncher = sysinstance.SystemInstanceLauncher
SystemInstanceInput = sysinstance.SystemInstanceInput
ExtraENIInput = sysinstance.ExtraENIInput
NICConfig = sysinstance.NICConfig
RecoveryContext = sysinstance.RecoveryContext
SystemInstanceOutput = sysinstance.SystemInstanceOutput
SystemInstanceLauncher = systeminstance.SystemInstanceLauncher
SystemInstanceInput = systeminstance.SystemInstanceInput
ExtraENIInput = systeminstance.ExtraENIInput
NICConfig = systeminstance.NICConfig
RecoveryContext = systeminstance.RecoveryContext
SystemInstanceOutput = systeminstance.SystemInstanceOutput
)
+2 -2
View File
@@ -11,10 +11,10 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/rds"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"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/handlers/sysinstance"
)
var errFinalSnapshotInProgress = errors.New("rds: final DB snapshot creation is still in progress")
@@ -235,7 +235,7 @@ func (s *Service) terminateInstanceVM(ctx context.Context, instanceID string) er
return errors.New("rds: no system-instance launcher configured")
}
if err := launcher.TerminateSystemInstance(instanceID); err != nil &&
!errors.Is(err, sysinstance.ErrSystemInstanceNotFound) {
!errors.Is(err, systeminstance.ErrSystemInstanceNotFound) {
return err
}
return nil
+6 -6
View File
@@ -15,10 +15,10 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/contracts/ec2/v1"
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
awsami "github.com/mulgadc/spinifex/spinifex/foundation/aws/ami"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"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/nats-io/nats.go"
@@ -96,7 +96,7 @@ type launchVPCProvisioner interface {
// System-managed VMs get a mgmt-bridge NIC alongside their VPC NICs, which is
// how the agent reaches the gateway from a private subnet.
type launchInstanceLauncher interface {
LaunchSystemInstance(input *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error)
LaunchSystemInstance(input *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error)
TerminateSystemInstance(instanceID string) error
}
@@ -255,8 +255,8 @@ func LaunchDBInstanceVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (o
return nil, fmt.Errorf("rds: resolve customer subnet network for %s: %w", in.DBInstanceIdentifier, err)
}
sysOut, err := deps.Instance.LaunchSystemInstance(&sysinstance.SystemInstanceInput{
BootMode: sysinstance.BootAMI,
sysOut, err := deps.Instance.LaunchSystemInstance(&systeminstance.SystemInstanceInput{
BootMode: systeminstance.BootAMI,
ManagedBy: tags.ManagedByRDS,
InstanceType: in.InstanceType,
ImageID: amiID,
@@ -267,7 +267,7 @@ func LaunchDBInstanceVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (o
ENIID: systemENI.id,
ENIMac: systemENI.mac,
ENIIP: systemENI.ip,
ExtraENIs: []sysinstance.ExtraENIInput{{
ExtraENIs: []systeminstance.ExtraENIInput{{
ENIID: customerENI.id,
ENIMac: customerENI.mac,
ENIIP: customerENI.ip,
@@ -292,7 +292,7 @@ func LaunchDBInstanceVM(ctx context.Context, deps LaunchDeps, in LaunchInput) (o
instanceID := sysOut.InstanceID
terminateVM = func(ctx context.Context) {
if termErr := deps.Instance.TerminateSystemInstance(instanceID); termErr != nil &&
!errors.Is(termErr, sysinstance.ErrSystemInstanceNotFound) {
!errors.Is(termErr, systeminstance.ErrSystemInstanceNotFound) {
slog.WarnContext(ctx, "rds: rollback terminate of failed DB VM failed",
"dbInstance", in.DBInstanceIdentifier, "instanceId", instanceID, "err", termErr)
}
+6 -6
View File
@@ -13,9 +13,9 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/internal/testkit"
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
"github.com/mulgadc/spinifex/spinifex/domains/ec2/systeminstance"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/tags"
"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/nats-io/nats.go"
@@ -303,7 +303,7 @@ func (f *fakeENIs) CreateSecurityGroup(_ context.Context, in *ec2.CreateSecurity
// fakeLauncher stands in for the system-instance launcher.
type fakeLauncher struct {
input *sysinstance.SystemInstanceInput
input *systeminstance.SystemInstanceInput
instanceID string
err error
terminated []string
@@ -321,7 +321,7 @@ type fakeLauncher struct {
var _ launchInstanceLauncher = (*fakeLauncher)(nil)
func (f *fakeLauncher) LaunchSystemInstance(in *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) {
func (f *fakeLauncher) LaunchSystemInstance(in *systeminstance.SystemInstanceInput) (*systeminstance.SystemInstanceOutput, error) {
f.input = in
if f.err != nil {
return nil, f.err
@@ -333,7 +333,7 @@ func (f *fakeLauncher) LaunchSystemInstance(in *sysinstance.SystemInstanceInput)
if instanceID == "" {
instanceID = "i-rds0001"
}
return &sysinstance.SystemInstanceOutput{InstanceID: instanceID}, nil
return &systeminstance.SystemInstanceOutput{InstanceID: instanceID}, nil
}
func (f *fakeLauncher) TerminateSystemInstance(instanceID string) error {
@@ -603,14 +603,14 @@ func TestLaunchDBInstanceVMWiresBothNICs(t *testing.T) {
// customer ENI injected cross-account as an extra NIC.
in := h.launcher.input
require.NotNil(t, in)
assert.Equal(t, sysinstance.BootAMI, in.BootMode)
assert.Equal(t, systeminstance.BootAMI, in.BootMode)
assert.Equal(t, tags.ManagedByRDS, in.ManagedBy)
assert.Equal(t, testEngineAMI, in.ImageID)
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)
assert.Equal(t, sysinstance.ExtraENIInput{
assert.Equal(t, systeminstance.ExtraENIInput{
ENIID: out.CustomerENIID,
ENIMac: "02:00:00:00:00:02",
ENIIP: out.CustomerENIIP,