From a7afa6dab0a3460d8cc5d711ef77ed87eb482960 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Mon, 29 Jan 2024 10:09:02 +0100 Subject: [PATCH] Introduce UUIDs for machine allocations. (#493) --- .../migrations/05_allocation_uuids.go | 42 +++++++++++++ .../migrate_integration_test.go | 60 +++++++++++++------ cmd/metal-api/internal/metal/machine.go | 1 + .../internal/service/machine-service.go | 2 + cmd/metal-api/internal/service/v1/machine.go | 2 + spec/metal-api.json | 5 ++ 6 files changed, 93 insertions(+), 19 deletions(-) create mode 100644 cmd/metal-api/internal/datastore/migrations/05_allocation_uuids.go diff --git a/cmd/metal-api/internal/datastore/migrations/05_allocation_uuids.go b/cmd/metal-api/internal/datastore/migrations/05_allocation_uuids.go new file mode 100644 index 000000000..563d01c8d --- /dev/null +++ b/cmd/metal-api/internal/datastore/migrations/05_allocation_uuids.go @@ -0,0 +1,42 @@ +package migrations + +import ( + r "gopkg.in/rethinkdb/rethinkdb-go.v6" + + "github.com/google/uuid" + "github.com/metal-stack/metal-api/cmd/metal-api/internal/datastore" +) + +func init() { + datastore.MustRegisterMigration(datastore.Migration{ + Name: "generate allocation uuids for already allocated machines", + Version: 5, + Up: func(db *r.Term, session r.QueryExecutor, rs *datastore.RethinkStore) error { + machines, err := rs.ListMachines() + if err != nil { + return err + } + + for _, m := range machines { + m := m + + if m.Allocation == nil { + continue + } + + if m.Allocation.UUID != "" { + continue + } + + newMachine := m + newMachine.Allocation.UUID = uuid.New().String() + + err = rs.UpdateMachine(&m, &newMachine) + if err != nil { + return err + } + } + return nil + }, + }) +} diff --git a/cmd/metal-api/internal/datastore/migrations_integration/migrate_integration_test.go b/cmd/metal-api/internal/datastore/migrations_integration/migrate_integration_test.go index 9637c5d33..d567fef30 100644 --- a/cmd/metal-api/internal/datastore/migrations_integration/migrate_integration_test.go +++ b/cmd/metal-api/internal/datastore/migrations_integration/migrate_integration_test.go @@ -39,32 +39,54 @@ func Test_Migration(t *testing.T) { err = rs.Initialize() require.NoError(t, err) - now := time.Now() - lastEventTime := now.Add(10 * time.Minute) - err = rs.UpsertProvisioningEventContainer(&metal.ProvisioningEventContainer{ - Base: metal.Base{ - ID: "1", - }, - Liveliness: "", - Events: []metal.ProvisioningEvent{ - { - Time: now, - Event: metal.ProvisioningEventPXEBooting, + var ( + now = time.Now() + lastEventTime = now.Add(10 * time.Minute) + ec = &metal.ProvisioningEventContainer{ + Base: metal.Base{ + ID: "1", }, - { - Time: lastEventTime, - Event: metal.ProvisioningEventPreparing, + Liveliness: "", + Events: []metal.ProvisioningEvent{ + { + Time: now, + Event: metal.ProvisioningEventPXEBooting, + }, + { + Time: lastEventTime, + Event: metal.ProvisioningEventPreparing, + }, }, - }, - CrashLoop: false, - FailedMachineReclaim: false, - }) + CrashLoop: false, + FailedMachineReclaim: false, + } + m = &metal.Machine{ + Base: metal.Base{ + ID: "1", + }, + } + ) + + err = rs.UpsertProvisioningEventContainer(ec) + require.NoError(t, err) + + err = rs.CreateMachine(m) + require.NoError(t, err) + + updateM := *m + updateM.Allocation = &metal.MachineAllocation{} + err = rs.UpdateMachine(m, &updateM) require.NoError(t, err) err = rs.Migrate(nil, false) require.NoError(t, err) - ec, err := rs.FindProvisioningEventContainer("1") + m, err = rs.FindMachineByID("1") + require.NoError(t, err) + + assert.NotEmpty(t, m.Allocation.UUID, "allocation uuid was not generated") + + ec, err = rs.FindProvisioningEventContainer("1") require.NoError(t, err) require.NoError(t, ec.Validate()) diff --git a/cmd/metal-api/internal/metal/machine.go b/cmd/metal-api/internal/metal/machine.go index 339e9cf85..ce862dae9 100644 --- a/cmd/metal-api/internal/metal/machine.go +++ b/cmd/metal-api/internal/metal/machine.go @@ -147,6 +147,7 @@ type MachineAllocation struct { MachineSetup *MachineSetup `rethinkdb:"setup" json:"setup"` Role Role `rethinkdb:"role" json:"role"` VPN *MachineVPN `rethinkdb:"vpn" json:"vpn"` + UUID string `rethinkdb:"uuid" json:"uuid"` } // A MachineSetup stores the data used for machine reinstallations. diff --git a/cmd/metal-api/internal/service/machine-service.go b/cmd/metal-api/internal/service/machine-service.go index 041d52ee7..c7f8488f6 100644 --- a/cmd/metal-api/internal/service/machine-service.go +++ b/cmd/metal-api/internal/service/machine-service.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/google/uuid" "github.com/metal-stack/metal-api/cmd/metal-api/internal/headscale" "github.com/metal-stack/metal-api/cmd/metal-api/internal/issues" "github.com/metal-stack/metal-lib/auditing" @@ -1170,6 +1171,7 @@ func allocateMachine(logger *zap.SugaredLogger, ds *datastore.RethinkStore, ipam MachineNetworks: []*metal.MachineNetwork{}, Role: allocationSpec.Role, VPN: allocationSpec.VPN, + UUID: uuid.New().String(), } rollbackOnError := func(err error) error { if err != nil { diff --git a/cmd/metal-api/internal/service/v1/machine.go b/cmd/metal-api/internal/service/v1/machine.go index d1cfbc9d4..b135b0bb3 100644 --- a/cmd/metal-api/internal/service/v1/machine.go +++ b/cmd/metal-api/internal/service/v1/machine.go @@ -42,6 +42,7 @@ type MachineAllocation struct { BootInfo *BootInfo `json:"boot_info" description:"information required for booting the machine from HD" optional:"true"` Role string `json:"role" enum:"machine|firewall" description:"the role of the machine"` VPN *MachineVPN `json:"vpn" description:"vpn connection info for machine" optional:"true"` + AllocationUUID string `json:"allocationuuid" description:"a unique identifier for this machine allocation, can be used to distinguish between machine allocations over time."` } type BootInfo struct { @@ -526,6 +527,7 @@ func NewMachineResponse(m *metal.Machine, s *metal.Size, p *metal.Partition, i * FilesystemLayout: NewFilesystemLayoutResponse(m.Allocation.FilesystemLayout), Role: string(m.Allocation.Role), VPN: NewMachineVPN(m.Allocation.VPN), + AllocationUUID: m.Allocation.UUID, } allocation.Reinstall = m.Allocation.Reinstall diff --git a/spec/metal-api.json b/spec/metal-api.json index 58c04be6a..4f68b7589 100644 --- a/spec/metal-api.json +++ b/spec/metal-api.json @@ -1998,6 +1998,10 @@ }, "v1.MachineAllocation": { "properties": { + "allocationuuid": { + "description": "a unique identifier for this machine allocation, can be used to distinguish between machine allocations over time.", + "type": "string" + }, "boot_info": { "$ref": "#/definitions/v1.BootInfo", "description": "information required for booting the machine from HD" @@ -2076,6 +2080,7 @@ } }, "required": [ + "allocationuuid", "created", "creator", "hostname",