mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-21 19:56:33 +00:00
ec9f0e5f2d
* feat(ec2,ebs): harden volume attach/detach + instance lifecycle state machine Batch of related EBS/instance-lifecycle correctness fixes verified together. - u94vs: add compare-and-swap (casUpdate/casPut via nats KV Update revision) to the multi-writer lifecycle KV sites (WriteTerminatedInstance, WriteStoppedInstance, WriteClusterShutdown); make the teardown-reaper read-modify-write atomic via a merge callback so retries never re-run cleaner side effects. - yi2ed: add ClaimStoppedInstance, a revision-checked delete-as-claim on the stopped bucket performed before Allocate/Insert/Run, so a forwarded start and a local fallback cannot double-start one instance onto the same volume. - siv-473: make AttachVolume idempotent — return attached success when the volume is already attached to the requesting instance; a conflicting requested device returns InvalidParameterValue. - siv-462: reconnect now re-asserts in-use for all attached volumes (boot and non-boot data volumes), not just boot, so a daemon restart no longer leaves stateful-pod data volumes split-brain; EFI pflash is skipped. - 9w2mv: wait for the QMP DEVICE_DELETED event (bounded) before blockdev-del instead of a blind sleep, so a slow guest unplug no longer exhausts retries. - soyah: poll (50ms) instead of fixed 1s sleeps in KillProcess and the viperblockd nbdkit confirm-running path, cutting volume-lifecycle latency. - siv-481: a cross-node start forward that times out now falls back to a local start; this is safe because the yi2ed claim is the single serialization point. * fix(eks): create per-account and leader KV buckets with cluster replica count The EKS per-account KV bucket and the leader lease bucket were created at Replicas=1 and never upgraded, since they're created lazily after upgradeJetStreamReplicas runs at startup. On multi-node clusters this leaves their single-replica Raft group transiently leaderless during formation, causing KV timeouts that surface as a deterministic 503 on ListClusters. Thread clusterSize through GetOrCreateAccountBucket/InitLeaderBucket (backed by a new utils.GetOrCreateKVBucketWithReplicas) so both buckets are created at max(clusterSize,1) replicas, matching every other node-count-scaled JetStream stream.
56 lines
2.7 KiB
Go
56 lines
2.7 KiB
Go
package vm
|
|
|
|
import "errors"
|
|
|
|
// ErrInstanceNotFound is returned by manager methods that look up an
|
|
// instance by id when no entry exists in the running map.
|
|
var ErrInstanceNotFound = errors.New("instance not found")
|
|
|
|
// ErrInvalidTransition is returned when a lifecycle method cannot run
|
|
// because the instance's current state does not permit the target
|
|
// transition (e.g. Stop on an already-stopped instance).
|
|
var ErrInvalidTransition = errors.New("invalid state transition")
|
|
|
|
// ErrAttachmentLimitExceeded is returned by AttachVolume when the
|
|
// instance has no free /dev/sd[f-p] slot to assign.
|
|
var ErrAttachmentLimitExceeded = errors.New("attachment limit exceeded")
|
|
|
|
// ErrVolumeNotAttached is returned by DetachVolume when the supplied
|
|
// volumeID is not present in the instance's EBSRequests.
|
|
var ErrVolumeNotAttached = errors.New("volume not attached to instance")
|
|
|
|
// ErrVolumeNotDetachable is returned by DetachVolume when the target
|
|
// volume is a boot or EFI volume that cannot be hot-unplugged.
|
|
var ErrVolumeNotDetachable = errors.New("volume cannot be detached")
|
|
|
|
// ErrVolumeDeviceMismatch is returned by DetachVolume when the caller
|
|
// supplies a device name that does not match the recorded attachment.
|
|
var ErrVolumeDeviceMismatch = errors.New("volume device name mismatch")
|
|
|
|
// ErrMountAmbiguous is returned by VolumeMounter.MountOne when the
|
|
// backend acknowledged the mount but returned an empty URI. The mount may
|
|
// or may not have started serving NBD; AttachVolume must invoke UnmountOne
|
|
// defensively so a half-started backend mount is not orphaned.
|
|
var ErrMountAmbiguous = errors.New("ebs.mount succeeded with empty URI")
|
|
|
|
// ErrENINotAttached is returned by HotUnplugENI when the supplied ENI id
|
|
// is not present in the instance's ENIRequests.AttachedByENIID map.
|
|
var ErrENINotAttached = errors.New("ENI not attached to instance")
|
|
|
|
// ErrENIPipelineTimeout is returned by HotPlugENI / HotUnplugENI when the
|
|
// query-pci poll did not observe the expected materialization (attach) or
|
|
// removal (detach) within the configured budget.
|
|
var ErrENIPipelineTimeout = errors.New("ENI hot-plug pipeline timed out")
|
|
|
|
// ErrQMPUnavailable is returned by hot-plug entry points when the
|
|
// instance has no live QMPClient (daemon restart mid-launch, terminated
|
|
// VM, etc).
|
|
var ErrQMPUnavailable = errors.New("QMP unavailable for instance")
|
|
|
|
// ErrStoppedInstanceClaimed is returned by StateStore.ClaimStoppedInstance
|
|
// when a concurrent caller already claimed (or the record was otherwise
|
|
// removed from) the stopped-instance store for the given id. The caller
|
|
// lost the race and must not proceed to allocate resources or launch qemu
|
|
// for that instance.
|
|
var ErrStoppedInstanceClaimed = errors.New("stopped instance already claimed")
|