mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
refactor: move the default-VPC subject into contracts/ec2/v1
utils.SubjectEnsureDefaultVpc becomes ec2v1.EnsureDefaultVpcSubject, the request/reply route between gateway account creation and the daemon. Only the subject moves; the request and reply bodies are still anonymous structs on each side and are recorded as such in the contract README. The layering freeze now allows two utils files.
This commit is contained in:
@@ -42,7 +42,7 @@ var frozenLegacyPackages = []string{
|
||||
|
||||
// frozenUtilsFiles are the only production files utils may hold; each awaits
|
||||
// the owner named in the migration record's close-out table.
|
||||
var frozenUtilsFiles = []string{"ec2_subject.go", "encryption.go", "vpcd_event.go"}
|
||||
var frozenUtilsFiles = []string{"encryption.go", "vpcd_event.go"}
|
||||
|
||||
// TestADR0001_LegacyRootsFrozen: the current-to-target map gives every legacy
|
||||
// root a destination, so none may gain a package and utils no new file.
|
||||
|
||||
@@ -42,3 +42,9 @@ the AWS-visible attachment semantics; the network domain owns the OVN work.
|
||||
The event intentionally contains only the gateway and VPC identifiers. It is
|
||||
not permission to read EC2's private VPC or IGW state. The JSON and both
|
||||
subjects are compatibility-tested in `igw_test.go`.
|
||||
|
||||
## Default VPC request
|
||||
|
||||
`EnsureDefaultVpcSubject` (`ec2.EnsureDefaultVpc`) is the request/reply route on which the gateway's account creation asks a daemon in the `spinifex-workers` queue group to build the account's default VPC.
|
||||
Only the subject is owned here today.
|
||||
The request (`account_id`) and reply (`vpc_id`, `error`) bodies are still declared as anonymous structs on each side; moving them into this package is a contract change that needs its own characterization first.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package ec2v1
|
||||
|
||||
// EnsureDefaultVpcSubject is the request/reply subject on which the daemon
|
||||
// builds an account's default VPC and acknowledges, so the gateway and the
|
||||
// daemon share the route without importing each other.
|
||||
const EnsureDefaultVpcSubject = "ec2.EnsureDefaultVpc"
|
||||
@@ -0,0 +1,15 @@
|
||||
package ec2v1_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ec2v1 "github.com/mulgadc/spinifex/contracts/ec2/v1"
|
||||
)
|
||||
|
||||
// The gateway's CreateAccount request and the daemon's subscription meet on
|
||||
// this literal; a deployed daemon and gateway of different builds must agree.
|
||||
func TestEnsureDefaultVpcSubject(t *testing.T) {
|
||||
require.Equal(t, "ec2.EnsureDefaultVpc", ec2v1.EnsureDefaultVpcSubject)
|
||||
}
|
||||
@@ -398,7 +398,7 @@ These residuals were recorded by individual slices and must be resolved once the
|
||||
- ACM control-plane registration: `domains/acm/awsapi.Deps.NATS` (`registration.go`) is likewise a raw `*nats.Conn` carried by every `Handler`, for the same reason; it must not be broadened further meanwhile.
|
||||
- `cmd/aws-model-coverage` imports `ingress/aws/dispatch`, `domains/ecr/awsapi`, `domains/acm/awsapi` and `gateway` to read ECR's and ACM's declared inventories. It is a non-serving tool and the only named exception to the ADR-0002 composition invariant; it must not construct a registration.
|
||||
- Ingress pipeline (ADR-0002 phase 4): the request-audit record, the trace action enricher, the throttle key functions and the gateway request-context keys stay in `gateway` until the auth/IAM and request-context boundary is designed. SigV4 authentication writes the audit record and context keys from four places, so moving them now would export exactly the setters ADR-0002 says must not be exported solely to make a directory move possible.
|
||||
- `utils`: `vpcd_event.go` (vpcd request/ack protocol and NAT helpers) awaits a network contract, `ec2_subject.go` awaits an EC2 contract, and `encryption.go` (the Viperblock master-key loader) awaits a Viperblock adapter owner, since `providers/ebs` is provider-neutral. Importers: `domains/ec2/{eip,instance,vpc}` and `handlers/elbv2/service_impl.go` use the `vpcd_event.go` helpers (`PublishNATEvent`, `AddNAT`, `RequestEvent`), and `domains/ec2/{image,instance,volume}` use `LoadViperblockMasterKey`; each edge clears when its file moves to its owner.
|
||||
- `utils`: `vpcd_event.go` (vpcd request/ack protocol and NAT helpers) awaits a network contract, and `encryption.go` (the Viperblock master-key loader) awaits a Viperblock adapter owner, since `providers/ebs` is provider-neutral. Importers: `domains/ec2/{eip,instance,vpc}` and `handlers/elbv2/service_impl.go` use the `vpcd_event.go` helpers (`PublishNATEvent`, `AddNAT`, `RequestEvent`), and `domains/ec2/{image,instance,volume}` use `LoadViperblockMasterKey`; each edge clears when its file moves to its owner.
|
||||
- `runtime/compute/cache.New`: two construction-time panics carry a lint exemption pending a constructor that returns an error.
|
||||
- `domains/ec2/systeminstance`: managed-service parent metadata is only the `ManagedBy` tag value.
|
||||
- `gateway/bedrock`: holds the Ochre domain core (model catalogue, provisioned throughput, guardrail, access, credential, usage, price, logging and weights stores), the inference engine (provider, vLLM, Anthropic, embeddings, reranker, admission) and the Bedrock action layer in one package with internal cycles. `domains/ochre` imports it, which is the ADR step 7 Ochre gateway import. Splitting it needs a plan: domain core and stores to `domains/ochre/<resource>`, inference to an Ochre-owned package, and only the action layer to `domains/ochre/awsapi`. The top-level `gateway/bedrock*.go` HTTP handlers additionally wait for the ingress registration seam.
|
||||
@@ -503,7 +503,7 @@ series above; "needs decision" is open.
|
||||
| `gateway/spx` | `promote_image.go` and `spx.go` dispatch (`storage.go` already consumes `contracts/operator/v1`). | Needs decision: which package owns operator-plane action dispatch registration — an `ingress/aws`-style seam for the operator plane, or `gateway` stays its home. |
|
||||
| `gateway/tagging` | The cross-service tagging API (`GetResources`) and its authorization. | Decided: a new `domains/tagging` boundary owns the cross-resource tagging API and aggregation; individual resource domains keep ownership of their own tag storage and expose narrow tagging capabilities. Stays debt until those per-domain capabilities exist; clears when `domains/tagging` aggregates only through them. |
|
||||
| `services/viperblockd` | Role supervision and the Viperblock EBS provider adapter in one package. | Decided: the adapter moves to `providers/ebs/viperblock`; `services/viperblockd` keeps only role supervision. EC2 volume code continues to depend only on `providers/ebs`. Clears when the adapter lives at `providers/ebs/viperblock`. |
|
||||
| `utils` | `vpcd_event.go`, `ec2_subject.go`, `encryption.go`. | Decided: `vpcd_event.go` is a serialised cross-process contract (its `natEvent` payload crosses a NATS request-reply boundary on `vpc.add-nat`/`vpc.delete-nat`), so `domains/network` owns its meaning and its versioned wire form goes under `contracts/network/v1`. `ec2_subject.go` (`SubjectEnsureDefaultVpc`, a NATS request/reply subject between the gateway and the daemon) has `domains/ec2` as its subject-semantics owner, with `contracts/ec2/v1` as its eventual home since it crosses a process boundary. `encryption.go` (the Viperblock master-key loader) joins the Viperblock adapter at `providers/ebs/viperblock`, not generic EBS or foundation code. |
|
||||
| `utils` | `vpcd_event.go`, `encryption.go` (`ec2_subject.go` moved to `contracts/ec2/v1` as `EnsureDefaultVpcSubject`; its request and reply bodies are still anonymous structs on each side). | Decided: `vpcd_event.go` is a serialised cross-process contract (its `natEvent` payload crosses a NATS request-reply boundary on `vpc.add-nat`/`vpc.delete-nat`), so `domains/network` owns its meaning and its versioned wire form goes under `contracts/network/v1`. `ec2_subject.go` (`SubjectEnsureDefaultVpc`, a NATS request/reply subject between the gateway and the daemon) has `domains/ec2` as its subject-semantics owner, with `contracts/ec2/v1` as its eventual home since it crosses a process boundary. `encryption.go` (the Viperblock master-key loader) joins the Viperblock adapter at `providers/ebs/viperblock`, not generic EBS or foundation code. |
|
||||
| `vpcd` | `imds_instance_state.go` reads `daemon.LocalState`, `ReadLocalState`, `LocalStatePath`, `NewJetStreamManager` and `InstanceStateBucket` directly (recorded above). | Needs a daemon-owned local-state capability or contract vpcd can consume instead of the `daemon` package. |
|
||||
| `daemon` | Reserved as `runtime/daemon`'s home only; not split or moved. | Deferred: Q-28's write-side consolidation is a prerequisite ADR-0001 names explicitly. |
|
||||
| `admin` | `DefaultAccountID`/`DefaultAccountName`, `GenerateAWSAccessKey`/`GenerateAWSSecretKey`, `PromoteSystemImage`, `GenerateCACert`/`GenerateSignedCert` (recorded above). | Deferred: each needs its target owner first — IAM/account bootstrap, IAM credentials, the EC2 image domain, and Spinifex certificate issuance respectively. |
|
||||
|
||||
@@ -86,7 +86,6 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/runtime/compute/vm"
|
||||
hostprocess "github.com/mulgadc/spinifex/spinifex/runtime/host/process"
|
||||
"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"
|
||||
)
|
||||
@@ -1035,7 +1034,7 @@ func (d *Daemon) subscribeAll() error {
|
||||
{"spinifex.image.promote", d.handleSpinifexPromoteImage, "spinifex-workers"},
|
||||
// Account creation → create default VPC for new account
|
||||
{"iam.account.created", d.handleAccountCreated, "spinifex-workers"},
|
||||
{utils.SubjectEnsureDefaultVpc, d.handleEnsureDefaultVpc, "spinifex-workers"},
|
||||
{ec2v1.EnsureDefaultVpcSubject, d.handleEnsureDefaultVpc, "spinifex-workers"},
|
||||
// Coordinated cluster shutdown phases (fan-out, no queue group)
|
||||
{"spinifex.cluster.shutdown.gate", d.handleShutdownGate, ""},
|
||||
{"spinifex.cluster.shutdown.drain", d.handleShutdownDrain, ""},
|
||||
|
||||
@@ -12,10 +12,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mulgadc/spinifex/contracts/ec2/v1"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
)
|
||||
|
||||
@@ -316,7 +316,7 @@ func (gw *GatewayConfig) ensureDefaultVPC(ctx context.Context, accountID string)
|
||||
reqCtx, cancel := context.WithTimeout(ctx, ensureDefaultVpcTimeout)
|
||||
defer cancel()
|
||||
|
||||
msg, err := gw.NATSConn.RequestWithContext(reqCtx, utils.SubjectEnsureDefaultVpc, payload)
|
||||
msg, err := gw.NATSConn.RequestWithContext(reqCtx, ec2v1.EnsureDefaultVpcSubject, payload)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("request default VPC: %w", err)
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mulgadc/spinifex/contracts/ec2/v1"
|
||||
"github.com/mulgadc/spinifex/internal/testkit"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/state/kvutil"
|
||||
handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -244,7 +244,7 @@ func newCreateAccountGateway(t *testing.T) *GatewayConfig {
|
||||
svc, err := handlers_iam.NewIAMServiceImpl(t.Context(), nc, masterKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
sub, err := nc.Subscribe(utils.SubjectEnsureDefaultVpc, func(msg *nats.Msg) {
|
||||
sub, err := nc.Subscribe(ec2v1.EnsureDefaultVpcSubject, func(msg *nats.Msg) {
|
||||
_ = msg.Respond([]byte(`{"vpc_id":"vpc-0a1b2c3d"}`))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
// Package utils holds the helpers still shared across Spinifex services: the
|
||||
// default-VPC subject, the Viperblock master key loader and vpcd events.
|
||||
package utils
|
||||
|
||||
// SubjectEnsureDefaultVpc is the request/reply subject on which the daemon
|
||||
// builds an account's default VPC and acknowledges. It lives here rather than
|
||||
// beside either party so the gateway does not import the daemon, nor the
|
||||
// reverse.
|
||||
const SubjectEnsureDefaultVpc = "ec2.EnsureDefaultVpc"
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package utils holds the helpers still shared across Spinifex services: the
|
||||
// Viperblock master key loader and vpcd events.
|
||||
package utils
|
||||
|
||||
import (
|
||||
|
||||
Reference in New Issue
Block a user