Skip to content

Commit

Permalink
fix: do not allow deleting machine classes which are used anywhere
Browse files Browse the repository at this point in the history
Fixes: siderolabs#431

Signed-off-by: Artem Chernyshev <[email protected]>
  • Loading branch information
Unix4ever committed Jul 25, 2024
1 parent aeb9322 commit 6f6e1a6
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
4 changes: 4 additions & 0 deletions internal/backend/runtime/omni/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func MachineSetNodeValidationOptions(st state.State) []validated.StateOption {
return machineSetNodeValidationOptions(st)
}

func MachineClassValidationOptions(st state.State) []validated.StateOption {
return machineClassValidationOptions(st)
}

func IdentityValidationOptions(samlConfig config.SAMLParams) []validated.StateOption {
return identityValidationOptions(samlConfig)
}
Expand Down
1 change: 1 addition & 0 deletions internal/backend/runtime/omni/omni.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ func New(talosClientFactory *talos.ClientFactory, dnsService *dns.Service, workl
roleValidationOptions(),
machineSetNodeValidationOptions(resourceState),
machineSetValidationOptions(resourceState, storeFactory),
machineClassValidationOptions(resourceState),
identityValidationOptions(config.Config.Auth.SAML),
exposedServiceValidationOptions(),
configPatchValidationOptions(resourceState),
Expand Down
26 changes: 26 additions & 0 deletions internal/backend/runtime/omni/state_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,32 @@ func machineSetValidationOptions(st state.State, etcdBackupStoreFactory store.Fa
}
}

// machineClassValidationOptions returns the validation options for the machine class resource.
func machineClassValidationOptions(st state.State) []validated.StateOption {
return []validated.StateOption{
validated.WithDestroyValidations(validated.NewDestroyValidationForType(func(ctx context.Context, _ resource.Pointer, res *omni.MachineClass, _ ...state.DestroyOption) error {
machineSets, err := safe.ReaderListAll[*omni.MachineSet](ctx, st)
if err != nil {
return err
}

var inUseBy []string

machineSets.ForEach(func(r *omni.MachineSet) {
if r.TypedSpec().Value.MachineClass != nil && r.TypedSpec().Value.MachineClass.Name == res.Metadata().ID() {
inUseBy = append(inUseBy, r.Metadata().ID())
}
})

if len(inUseBy) > 0 {
return fmt.Errorf("can not delete the machine class as it is still in use by machine sets: %s", strings.Join(inUseBy, ", "))
}

return nil
})),
}
}

func validateBootstrapSpec(ctx context.Context, st state.State, etcdBackupStoreFactory store.Factory, oldres, res *omni.MachineSet) error {
bootstrapSpec := res.TypedSpec().Value.GetBootstrapSpec()
_, isControlPlane := res.Metadata().Labels().Get(omni.LabelControlPlaneRole)
Expand Down
36 changes: 36 additions & 0 deletions internal/backend/runtime/omni/state_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,42 @@ func TestMachineSetClassesValidation(t *testing.T) {
require.ErrorContains(t, err, "machine set is not empty")
}

func TestMachineClassValidation(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
t.Cleanup(cancel)

innerSt := state.WrapCore(namespaced.NewState(inmem.Build))

st := validated.NewState(innerSt,
omni.MachineClassValidationOptions(state.WrapCore(innerSt))...,
)

require.NoError(t, st.Create(ctx, omnires.NewCluster(resources.DefaultNamespace, "test-cluster")))

machineSet := omnires.NewMachineSet(resources.DefaultNamespace, "test-cluster-control-planes")

machineSet.Metadata().Labels().Set(omnires.LabelCluster, "test-cluster")
machineSet.Metadata().Labels().Set(omnires.LabelControlPlaneRole, "")

machineSet.TypedSpec().Value.MachineClass = &specs.MachineSetSpec_MachineClass{
Name: "test-class",
}

machineClass := omnires.NewMachineClass(resources.DefaultNamespace, "test-class")

require.NoError(t, st.Create(ctx, machineClass))
require.NoError(t, st.Create(ctx, machineSet))

err := st.Destroy(ctx, machineClass.Metadata())

require.True(t, validated.IsValidationError(err), "expected validation error")

require.NoError(t, st.Destroy(ctx, machineSet.Metadata()))
require.NoError(t, st.Destroy(ctx, machineClass.Metadata()))
}

func TestS3ConfigValidation(t *testing.T) {
t.Parallel()

Expand Down

0 comments on commit 6f6e1a6

Please sign in to comment.