From e902e94239004c5d05441944665b26497bf0174c Mon Sep 17 00:00:00 2001 From: Tim Gross Date: Wed, 2 Sep 2026 11:07:56 -0400 Subject: [PATCH 1/2] remove deprecated resource fields from Allocation struct As part of the "client v2" effort for Nomad 0.9 we changed how allocated resources were tracked, but we ended up leaving the existing struct fields around. All consumers of these fields have been updated to handle the newer fields for a very long time. Remove the fields from the `nomad/structs` package version of the object, and formally deprecate them in the `api` package. This also requires removing the upgrade path in the client state database, but the state database is automatically updated on agent upgrades and Nomad clients older than 1.6 have been non-functional since 1.9. So this only impacts users trying to restore from pre-0.9 backups of their state stores, which seems safe. --- .changelog/28486.txt | 7 + api/allocations.go | 30 ++- client/client.go | 10 - client/client_test.go | 1 - client/state/08types.go | 134 ---------- client/state/db_bolt.go | 10 +- client/state/testdata/state-0.7.1.db.gz | Bin 6163 -> 0 bytes client/state/testdata/state-0.8.6-empty.db.gz | Bin 153 -> 0 bytes .../testdata/state-0.8.6-no-deploy.db.gz | Bin 2802 -> 0 bytes client/state/upgrade.go | 247 +----------------- client/state/upgrade_int_test.go | 74 +----- client/state/upgrade_test.go | 117 +-------- command/alloc_status.go | 19 +- command/alloc_status_test.go | 4 +- command/node_status.go | 8 +- .../deployments_watcher_test.go | 2 - nomad/fsm_test.go | 12 +- nomad/mock/alloc.go | 79 ------ nomad/mock/connect.go | 42 --- nomad/mock/lifecycle.go | 76 ------ nomad/state/state_store.go | 36 --- nomad/state/state_store_test.go | 42 --- nomad/structs/alloc.go | 51 ---- nomad/structs/alloc_test.go | 53 ---- nomad/structs/network.go | 12 - nomad/structs/network_test.go | 40 ++- nomad/structs/plan.go | 10 - nomad/structs/plan_test.go | 2 - scheduler/generic_sched.go | 7 - scheduler/scheduler_sysbatch.go | 7 - scheduler/scheduler_system.go | 7 - scheduler/scheduler_system_test.go | 10 +- scheduler/scheduler_test.go | 11 - scheduler/tests/testing.go | 9 +- scheduler/util.go | 11 +- scheduler/util_test.go | 4 - 36 files changed, 91 insertions(+), 1093 deletions(-) create mode 100644 .changelog/28486.txt delete mode 100644 client/state/08types.go delete mode 100644 client/state/testdata/state-0.7.1.db.gz delete mode 100644 client/state/testdata/state-0.8.6-empty.db.gz delete mode 100644 client/state/testdata/state-0.8.6-no-deploy.db.gz diff --git a/.changelog/28486.txt b/.changelog/28486.txt new file mode 100644 index 00000000000..feb6214aa89 --- /dev/null +++ b/.changelog/28486.txt @@ -0,0 +1,7 @@ +```release-note:deprecation +api: the Allocation struct's Resources and TaskResources fields are deprecated. Use the AllocatedResources field instead +``` + +```release-note:deprecation +client: state databases restored from backups older than Nomad 0.9 are no longer compatible and will fail client startup. +``` diff --git a/api/allocations.go b/api/allocations.go index 42e45809ee9..6a4e6d6ea85 100644 --- a/api/allocations.go +++ b/api/allocations.go @@ -253,17 +253,22 @@ func (a *Allocations) Services(allocID string, q *QueryOptions) ([]*ServiceRegis // Allocation is used for serialization of allocations. type Allocation struct { - ID string - Namespace string - EvalID string - Name string - NodeID string - NodeName string - JobID string - Job *Job - TaskGroup string - Resources *Resources - TaskResources map[string]*Resources + ID string + Namespace string + EvalID string + Name string + NodeID string + NodeName string + JobID string + Job *Job + TaskGroup string + + // Deprecated: will be removed in a future version of the API. Use AllocatedResources. + Resources *Resources + + // Deprecated: will be removed in a future version of the API. Use AllocatedResources. + TaskResources map[string]*Resources + AllocatedResources *AllocatedResources Services map[string]string Metrics *AllocationMetric @@ -453,7 +458,8 @@ type PortMapping struct { } type AllocatedCpuResources struct { - CpuShares int64 + CpuShares int64 + ReservedCores []uint16 } type AllocatedMemoryResources struct { diff --git a/client/client.go b/client/client.go index dacb56bcdb1..1dae49e67d0 100644 --- a/client/client.go +++ b/client/client.go @@ -3471,16 +3471,6 @@ func (c *Client) getAllocatedResources(selfNode *structs.Node) *structs.Comparab } } } - } else if alloc.Resources != nil { - for _, allocatedNetwork := range alloc.Resources.Networks { - for cidr, dev := range cidrToDevice { - ip := net.ParseIP(allocatedNetwork.IP) - if cidr.Contains(ip) { - allocatedDeviceMbits[dev] += allocatedNetwork.MBits - break - } - } - } } } diff --git a/client/client_test.go b/client/client_test.go index f4d56fc24db..6e55f3c3eef 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -1015,7 +1015,6 @@ func TestClient_AddAllocError(t *testing.T) { // Set these two fields to nil to cause alloc runner creation to fail alloc1.AllocatedResources = nil - alloc1.TaskResources = nil state := s1.State() err := state.UpsertJob(structs.MsgTypeTestSetup, 100, nil, job) diff --git a/client/state/08types.go b/client/state/08types.go deleted file mode 100644 index f6eda63ef21..00000000000 --- a/client/state/08types.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright IBM Corp. 2015, 2026 -// SPDX-License-Identifier: BUSL-1.1 - -package state - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/hashicorp/nomad/client/allocrunner/taskrunner/state" - "github.com/hashicorp/nomad/helper/uuid" - "github.com/hashicorp/nomad/nomad/structs" - "github.com/hashicorp/nomad/plugins/drivers" - pstructs "github.com/hashicorp/nomad/plugins/shared/structs" -) - -// allocRunnerMutableState08 is state that had to be written on each save as it -// changed over the life-cycle of the alloc_runner in Nomad 0.8. -// -// https://github.com/hashicorp/nomad/blob/v0.8.6/client/alloc_runner.go#L146-L153 -type allocRunnerMutableState08 struct { - // AllocClientStatus does not need to be upgraded as it is computed - // from task states. - AllocClientStatus string - - // AllocClientDescription does not need to be upgraded as it is computed - // from task states. - AllocClientDescription string - - TaskStates map[string]*structs.TaskState - DeploymentStatus *structs.AllocDeploymentStatus -} - -// taskRunnerState08 was used to snapshot the state of the task runner in Nomad -// 0.8. -// -// https://github.com/hashicorp/nomad/blob/v0.8.6/client/task_runner.go#L188-L197 -// COMPAT(0.10): Allows upgrading from 0.8.X to 0.9.0. -type taskRunnerState08 struct { - Version string - HandleID string - ArtifactDownloaded bool - TaskDirBuilt bool - PayloadRendered bool - DriverNetwork *drivers.DriverNetwork - // Created Resources are no longer used. - //CreatedResources *driver.CreatedResources -} - -type TaskRunnerHandle08 struct { - // Docker specific handle info - ContainerID string `json:"ContainerID"` - Image string `json:"Image"` - - // LXC specific handle info - ContainerName string `json:"ContainerName"` - LxcPath string `json:"LxcPath"` - - // Executor reattach config - PluginConfig struct { - Pid int `json:"Pid"` - AddrNet string `json:"AddrNet"` - AddrName string `json:"AddrName"` - } `json:"PluginConfig"` -} - -func (t *TaskRunnerHandle08) ReattachConfig() *pstructs.ReattachConfig { - return &pstructs.ReattachConfig{ - Network: t.PluginConfig.AddrNet, - Addr: t.PluginConfig.AddrName, - Pid: t.PluginConfig.Pid, - } -} - -func (t *taskRunnerState08) Upgrade(allocID, taskName string) (*state.LocalState, error) { - ls := state.NewLocalState() - - // Reuse DriverNetwork - ls.DriverNetwork = t.DriverNetwork - - // Upgrade artifact state - ls.Hooks["artifacts"] = &state.HookState{ - PrestartDone: t.ArtifactDownloaded, - } - - // Upgrade task dir state - ls.Hooks["task_dir"] = &state.HookState{ - Data: map[string]string{ - // "is_done" is equivalent to task_dir_hook.TaskDirHookIsDoneKey - // Does not import to avoid import cycle - "is_done": fmt.Sprintf("%v", t.TaskDirBuilt), - }, - } - - // Upgrade dispatch payload state - ls.Hooks["dispatch_payload"] = &state.HookState{ - PrestartDone: t.PayloadRendered, - } - - // Add necessary fields to TaskConfig - ls.TaskHandle = drivers.NewTaskHandle(drivers.Pre09TaskHandleVersion) - ls.TaskHandle.Config = &drivers.TaskConfig{ - ID: fmt.Sprintf("pre09-%s", uuid.Generate()), - Name: taskName, - AllocID: allocID, - } - - ls.TaskHandle.State = drivers.TaskStateUnknown - - // The docker driver prefixed the handle with 'DOCKER:' - // Strip so that it can be unmarshalled - data := strings.TrimPrefix(t.HandleID, "DOCKER:") - - // The pre09 driver handle ID is given to the driver. It is unmarshalled - // here to check for errors - if _, err := UnmarshalPre09HandleID([]byte(data)); err != nil { - return nil, err - } - - ls.TaskHandle.DriverState = []byte(data) - - return ls, nil -} - -// UnmarshalPre09HandleID decodes the pre09 json encoded handle ID -func UnmarshalPre09HandleID(raw []byte) (*TaskRunnerHandle08, error) { - var handle TaskRunnerHandle08 - if err := json.Unmarshal(raw, &handle); err != nil { - return nil, fmt.Errorf("failed to decode 0.8 driver state: %v", err) - } - - return &handle, nil -} diff --git a/client/state/db_bolt.go b/client/state/db_bolt.go index c05ecfc9be0..0dbb81f4929 100644 --- a/client/state/db_bolt.go +++ b/client/state/db_bolt.go @@ -1215,11 +1215,11 @@ func (s *BoltStateDB) updateWithOptions(opts []WriteOption, updateFn func(tx *bo // 0.9 schema. Creates a backup before upgrading. func (s *BoltStateDB) Upgrade() error { // Check to see if the underlying DB needs upgrading. - upgrade09, upgrade13, err := NeedsUpgrade(s.db.BoltDB()) + upgrade13, err := NeedsUpgrade(s.db.BoltDB()) if err != nil { return err } - if !upgrade09 && !upgrade13 { + if !upgrade13 { // No upgrade needed! return nil } @@ -1232,12 +1232,6 @@ func (s *BoltStateDB) Upgrade() error { // Perform the upgrade if err := s.db.Update(func(tx *boltdd.Tx) error { - - if upgrade09 { - if err := UpgradeAllocs(s.logger, tx); err != nil { - return err - } - } if upgrade13 { if err := UpgradeDynamicPluginRegistry(s.logger, tx); err != nil { return err diff --git a/client/state/testdata/state-0.7.1.db.gz b/client/state/testdata/state-0.7.1.db.gz deleted file mode 100644 index f319821546c9c58aee327329ab25bb06f93c772a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6163 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 H06+i$$bvw9 diff --git a/client/state/testdata/state-0.8.6-no-deploy.db.gz b/client/state/testdata/state-0.8.6-no-deploy.db.gz deleted file mode 100644 index 917041eced42cacdf85702d31c36ad7c7786ec8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2802 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 diff --git a/client/state/upgrade.go b/client/state/upgrade.go index 09a62258eac..cfed8506e5a 100644 --- a/client/state/upgrade.go +++ b/client/state/upgrade.go @@ -10,17 +10,14 @@ import ( "os" hclog "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-msgpack/v2/codec" "github.com/hashicorp/nomad/client/dynamicplugins" "github.com/hashicorp/nomad/helper/boltdd" - "github.com/hashicorp/nomad/nomad/structs" "go.etcd.io/bbolt" ) // NeedsUpgrade returns true if the BoltDB needs upgrading or false if it is // already up to date. -func NeedsUpgrade(bdb *bbolt.DB) (upgradeTo09, upgradeTo13 bool, err error) { - upgradeTo09 = true +func NeedsUpgrade(bdb *bbolt.DB) (upgradeTo13 bool, err error) { upgradeTo13 = true err = bdb.View(func(tx *bbolt.Tx) error { b := tx.Bucket(metaBucketName) @@ -36,11 +33,10 @@ func NeedsUpgrade(bdb *bbolt.DB) (upgradeTo09, upgradeTo13 bool, err error) { } if bytes.Equal(v, []byte{'2'}) { - upgradeTo09 = false return nil } + if bytes.Equal(v, metaVersion) { - upgradeTo09 = false upgradeTo13 = false return nil } @@ -83,245 +79,6 @@ func backupDB(bdb *bbolt.DB, dst string) error { }) } -// UpgradeAllocs upgrades the boltdb schema. Example 0.8 schema: -// -// allocations -// 15d83e8a-74a2-b4da-3f17-ed5c12895ea8 -// echo -// simple-all (342 bytes) -// alloc (2827 bytes) -// alloc-dir (166 bytes) -// immutable (15 bytes) -// mutable (1294 bytes) -func UpgradeAllocs(logger hclog.Logger, tx *boltdd.Tx) error { - btx := tx.BoltTx() - allocationsBucket := btx.Bucket(allocationsBucketName) - if allocationsBucket == nil { - // No state! - return nil - } - - // Gather alloc buckets and remove unexpected key/value pairs - allocBuckets := [][]byte{} - cur := allocationsBucket.Cursor() - for k, v := cur.First(); k != nil; k, v = cur.Next() { - if v != nil { - logger.Warn("deleting unexpected key in state db", - "key", string(k), "value_bytes", len(v), - ) - - if err := cur.Delete(); err != nil { - return fmt.Errorf("error deleting unexpected key %q: %v", string(k), err) - } - continue - } - - allocBuckets = append(allocBuckets, k) - } - - for _, allocBucket := range allocBuckets { - allocID := string(allocBucket) - - bkt := allocationsBucket.Bucket(allocBucket) - if bkt == nil { - // This should never happen as we just read the bucket. - return fmt.Errorf("unexpected bucket missing %q", allocID) - } - - allocLogger := logger.With("alloc_id", allocID) - if err := upgradeAllocBucket(allocLogger, tx, bkt, allocID); err != nil { - // Log and drop invalid allocs - allocLogger.Error("dropping invalid allocation due to error while upgrading state", - "error", err, - ) - - // If we can't delete the bucket something is seriously - // wrong, fail hard. - if err := allocationsBucket.DeleteBucket(allocBucket); err != nil { - return fmt.Errorf("error deleting invalid allocation state: %v", err) - } - } - } - - return nil -} - -// upgradeAllocBucket upgrades an alloc bucket. -func upgradeAllocBucket(logger hclog.Logger, tx *boltdd.Tx, bkt *bbolt.Bucket, allocID string) error { - allocFound := false - taskBuckets := [][]byte{} - cur := bkt.Cursor() - for k, v := cur.First(); k != nil; k, v = cur.Next() { - switch string(k) { - case "alloc": - // Alloc has not changed; leave it be - allocFound = true - case "alloc-dir": - // Drop alloc-dir entries as they're no longer needed. - cur.Delete() - case "immutable": - // Drop immutable state. Nothing from it needs to be - // upgraded. - cur.Delete() - case "mutable": - // Decode and upgrade - if err := upgradeOldAllocMutable(tx, allocID, v); err != nil { - return err - } - cur.Delete() - default: - if v != nil { - logger.Warn("deleting unexpected state entry for allocation", - "key", string(k), "value_bytes", len(v), - ) - - if err := cur.Delete(); err != nil { - return err - } - - continue - } - - // Nested buckets are tasks - taskBuckets = append(taskBuckets, k) - } - } - - // If the alloc entry was not found, abandon this allocation as the - // state has been corrupted. - if !allocFound { - return fmt.Errorf("alloc entry not found") - } - - // Upgrade tasks - for _, taskBucket := range taskBuckets { - taskName := string(taskBucket) - taskLogger := logger.With("task_name", taskName) - - taskBkt := bkt.Bucket(taskBucket) - if taskBkt == nil { - // This should never happen as we just read the bucket. - return fmt.Errorf("unexpected bucket missing %q", taskName) - } - - oldState, err := upgradeTaskBucket(taskLogger, taskBkt) - if err != nil { - taskLogger.Warn("dropping invalid task due to error while upgrading state", - "error", err, - ) - - // Delete the invalid task bucket and treat failures - // here as unrecoverable errors. - if err := bkt.DeleteBucket(taskBucket); err != nil { - return fmt.Errorf("error deleting invalid task state for task %q: %v", - taskName, err, - ) - } - continue - } - - // Convert 0.8 task state to 0.9 task state - localTaskState, err := oldState.Upgrade(allocID, taskName) - if err != nil { - taskLogger.Warn("dropping invalid task due to error while upgrading state", - "error", err, - ) - - // Delete the invalid task bucket and treat failures - // here as unrecoverable errors. - if err := bkt.DeleteBucket(taskBucket); err != nil { - return fmt.Errorf("error deleting invalid task state for task %q: %v", - taskName, err, - ) - } - continue - } - - // Insert the new task state - if err := putTaskRunnerLocalStateImpl(tx, allocID, taskName, localTaskState); err != nil { - return err - } - - // Delete the old task bucket - if err := bkt.DeleteBucket(taskBucket); err != nil { - return err - } - - taskLogger.Trace("upgraded", "from", oldState.Version) - } - - return nil -} - -// upgradeTaskBucket iterates over keys in a task bucket, deleting invalid keys -// and returning the 0.8 version of the state. -func upgradeTaskBucket(logger hclog.Logger, bkt *bbolt.Bucket) (*taskRunnerState08, error) { - simpleFound := false - var trState taskRunnerState08 - - cur := bkt.Cursor() - for k, v := cur.First(); k != nil; k, v = cur.Next() { - if v == nil { - // value is nil: delete unexpected bucket - logger.Warn("deleting unexpected task state bucket", - "bucket", string(k), - ) - - if err := bkt.DeleteBucket(k); err != nil { - return nil, fmt.Errorf("error deleting unexpected task bucket %q: %v", string(k), err) - } - continue - } - - if !bytes.Equal(k, []byte("simple-all")) { - // value is non-nil: delete unexpected entry - logger.Warn("deleting unexpected task state entry", - "key", string(k), "value_bytes", len(v), - ) - - if err := cur.Delete(); err != nil { - return nil, fmt.Errorf("error delting unexpected task key %q: %v", string(k), err) - } - continue - } - - // Decode simple-all - simpleFound = true - if err := codec.NewDecoderBytes(v, structs.MsgpackHandle).Decode(&trState); err != nil { - return nil, fmt.Errorf("failed to decode task state from 'simple-all' entry: %v", err) - } - } - - if !simpleFound { - return nil, fmt.Errorf("task state entry not found") - } - - return &trState, nil -} - -// upgradeOldAllocMutable upgrades Nomad 0.8 alloc runner state. -func upgradeOldAllocMutable(tx *boltdd.Tx, allocID string, oldBytes []byte) error { - var oldMutable allocRunnerMutableState08 - err := codec.NewDecoderBytes(oldBytes, structs.MsgpackHandle).Decode(&oldMutable) - if err != nil { - return err - } - - // Upgrade Deployment Status - if err := putDeploymentStatusImpl(tx, allocID, oldMutable.DeploymentStatus); err != nil { - return err - } - - // Upgrade Task States - for taskName, taskState := range oldMutable.TaskStates { - if err := putTaskStateImpl(tx, allocID, taskName, taskState); err != nil { - return err - } - } - - return nil -} - func UpgradeDynamicPluginRegistry(logger hclog.Logger, tx *boltdd.Tx) error { dynamicBkt := tx.Bucket(dynamicPluginBucketName) diff --git a/client/state/upgrade_int_test.go b/client/state/upgrade_int_test.go index 69841fdff18..93cdecc52a8 100644 --- a/client/state/upgrade_int_test.go +++ b/client/state/upgrade_int_test.go @@ -19,17 +19,14 @@ import ( "github.com/hashicorp/nomad/client/config" clientconfig "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/client/devicemanager" - dmstate "github.com/hashicorp/nomad/client/devicemanager/state" "github.com/hashicorp/nomad/client/lib/cgroupslib" "github.com/hashicorp/nomad/client/lib/proclib" "github.com/hashicorp/nomad/client/pluginmanager/drivermanager" regMock "github.com/hashicorp/nomad/client/serviceregistration/mock" . "github.com/hashicorp/nomad/client/state" "github.com/hashicorp/nomad/client/vaultclient" - "github.com/hashicorp/nomad/helper/boltdd" "github.com/hashicorp/nomad/helper/testlog" "github.com/hashicorp/nomad/nomad/structs" - pstructs "github.com/hashicorp/nomad/plugins/shared/structs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.etcd.io/bbolt" @@ -69,71 +66,6 @@ func TestBoltStateDB_UpgradeOld_Ok(t *testing.T) { return db } - pre09files := []string{ - "testdata/state-0.7.1.db.gz", - "testdata/state-0.8.6-empty.db.gz", - "testdata/state-0.8.6-no-deploy.db.gz"} - - for _, fn := range pre09files { - t.Run(fn, func(t *testing.T) { - - dir := t.TempDir() - - db := dbFromTestFile(t, dir, fn) - defer db.Close() - - // Simply opening old files should *not* alter them - require.NoError(t, db.DB().View(func(tx *boltdd.Tx) error { - b := tx.Bucket([]byte("meta")) - if b != nil { - return fmt.Errorf("meta bucket found but should not exist yet!") - } - return nil - })) - - to09, to12, err := NeedsUpgrade(db.DB().BoltDB()) - require.NoError(t, err) - require.True(t, to09) - require.True(t, to12) - - // Attempt the upgrade - require.NoError(t, db.Upgrade()) - - to09, to12, err = NeedsUpgrade(db.DB().BoltDB()) - require.NoError(t, err) - require.False(t, to09) - require.False(t, to12) - - // Ensure Allocations can be restored and - // NewAR/AR.Restore do not error. - allocs, errs, err := db.GetAllAllocations() - require.NoError(t, err) - assert.Len(t, errs, 0) - - for _, alloc := range allocs { - checkUpgradedAlloc(t, dir, db, alloc) - } - - // Should be nil for all upgrades - ps, err := db.GetDevicePluginState() - require.NoError(t, err) - require.Nil(t, ps) - - ps = &dmstate.PluginState{ - ReattachConfigs: map[string]*pstructs.ReattachConfig{ - "test": {Pid: 1}, - }, - } - require.NoError(t, db.PutDevicePluginState(ps)) - - registry, err := db.GetDynamicPluginRegistryState() - require.Nil(t, registry) - - require.NoError(t, err) - require.NoError(t, db.Close()) - }) - } - t.Run("testdata/state-1.2.6.db.gz", func(t *testing.T) { fn := "testdata/state-1.2.6.db.gz" dir := t.TempDir() @@ -157,17 +89,15 @@ func TestBoltStateDB_UpgradeOld_Ok(t *testing.T) { return nil }) - to09, to12, err := NeedsUpgrade(db.DB().BoltDB()) + to12, err := NeedsUpgrade(db.DB().BoltDB()) require.NoError(t, err) - require.False(t, to09) require.True(t, to12) // Attempt the upgrade require.NoError(t, db.Upgrade()) - to09, to12, err = NeedsUpgrade(db.DB().BoltDB()) + to12, err = NeedsUpgrade(db.DB().BoltDB()) require.NoError(t, err) - require.False(t, to09) require.False(t, to12) registry, err := db.GetDynamicPluginRegistryState() diff --git a/client/state/upgrade_test.go b/client/state/upgrade_test.go index c06fb0495d5..67bb7275713 100644 --- a/client/state/upgrade_test.go +++ b/client/state/upgrade_test.go @@ -9,9 +9,7 @@ import ( "testing" "github.com/hashicorp/nomad/ci" - "github.com/hashicorp/nomad/helper/boltdd" - "github.com/hashicorp/nomad/helper/testlog" - "github.com/hashicorp/nomad/helper/uuid" + "github.com/shoenig/test/must" "github.com/stretchr/testify/require" "go.etcd.io/bbolt" ) @@ -36,10 +34,9 @@ func TestUpgrade_NeedsUpgrade_New(t *testing.T) { // Setting up a new StateDB should initialize it at the latest version. db := setupBoltStateDB(t) - to09, to12, err := NeedsUpgrade(db.DB().BoltDB()) - require.NoError(t, err) - require.False(t, to09) - require.False(t, to12) + to12, err := NeedsUpgrade(db.DB().BoltDB()) + must.NoError(t, err) + must.False(t, to12) } // TestUpgrade_NeedsUpgrade_Old asserts state dbs with just the alloctions @@ -51,23 +48,21 @@ func TestUpgrade_NeedsUpgrade_Old(t *testing.T) { // Create the allocations bucket which exists in both the old and 0.9 // schemas - require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + must.NoError(t, db.Update(func(tx *bbolt.Tx) error { _, err := tx.CreateBucket(allocationsBucketName) return err })) - to09, to12, err := NeedsUpgrade(db) - require.NoError(t, err) - require.True(t, to09) - require.True(t, to12) + to12, err := NeedsUpgrade(db) + must.NoError(t, err) + must.True(t, to12) // Adding meta should mark it as upgraded - require.NoError(t, db.Update(addMeta)) + must.NoError(t, db.Update(addMeta)) - to09, to12, err = NeedsUpgrade(db) - require.NoError(t, err) - require.False(t, to09) - require.False(t, to12) + to12, err = NeedsUpgrade(db) + must.NoError(t, err) + must.False(t, to12) } // TestUpgrade_NeedsUpgrade_Error asserts that an error is returned from @@ -93,94 +88,8 @@ func TestUpgrade_NeedsUpgrade_Error(t *testing.T) { return bkt.Put(metaVersionKey, tc) })) - _, _, err := NeedsUpgrade(db) + _, err := NeedsUpgrade(db) require.Error(t, err) }) } } - -// TestUpgrade_DeleteInvalidAllocs asserts invalid allocations are deleted -// during state upgades instead of failing the entire agent. -func TestUpgrade_DeleteInvalidAllocs_NoAlloc(t *testing.T) { - ci.Parallel(t) - - bdb := setupBoltDB(t) - - db := boltdd.New(bdb) - - allocID := []byte(uuid.Generate()) - - // Create an allocation bucket with no `alloc` key. This is an observed - // pre-0.9 state corruption that should result in the allocation being - // dropped while allowing the upgrade to continue. - require.NoError(t, db.Update(func(tx *boltdd.Tx) error { - parentBkt, err := tx.CreateBucket(allocationsBucketName) - if err != nil { - return err - } - - _, err = parentBkt.CreateBucket(allocID) - return err - })) - - // Perform the Upgrade - require.NoError(t, db.Update(func(tx *boltdd.Tx) error { - return UpgradeAllocs(testlog.HCLogger(t), tx) - })) - - // Assert invalid allocation bucket was removed - require.NoError(t, db.View(func(tx *boltdd.Tx) error { - parentBkt := tx.Bucket(allocationsBucketName) - if parentBkt == nil { - return fmt.Errorf("parent allocations bucket should not have been removed") - } - - if parentBkt.Bucket(allocID) != nil { - return fmt.Errorf("invalid alloc bucket should have been deleted") - } - - return nil - })) -} - -// TestUpgrade_DeleteInvalidTaskEntries asserts invalid entries under a task -// bucket are deleted. -func TestUpgrade_upgradeTaskBucket_InvalidEntries(t *testing.T) { - ci.Parallel(t) - - db := setupBoltDB(t) - - taskName := []byte("fake-task") - - // Insert unexpected bucket, unexpected key, and missing simple-all - require.NoError(t, db.Update(func(tx *bbolt.Tx) error { - bkt, err := tx.CreateBucket(taskName) - if err != nil { - return err - } - - _, err = bkt.CreateBucket([]byte("unexpectedBucket")) - if err != nil { - return err - } - - return bkt.Put([]byte("unexepectedKey"), []byte{'x'}) - })) - - require.NoError(t, db.Update(func(tx *bbolt.Tx) error { - bkt := tx.Bucket(taskName) - - // upgradeTaskBucket should fail - state, err := upgradeTaskBucket(testlog.HCLogger(t), bkt) - require.Nil(t, state) - require.Error(t, err) - - // Invalid entries should have been deleted - cur := bkt.Cursor() - for k, v := cur.First(); k != nil; k, v = cur.Next() { - t.Errorf("unexpected entry found: key=%q value=%q", k, v) - } - - return nil - })) -} diff --git a/command/alloc_status.go b/command/alloc_status.go index 8fc4ad7b8fa..02686b5f76c 100644 --- a/command/alloc_status.go +++ b/command/alloc_status.go @@ -602,8 +602,8 @@ func buildDisplayMessage(event *api.TaskEvent) string { // outputTaskResources prints the task resources for the passed task and if // displayStats is set, verbose resource usage statistics func (c *AllocStatusCommand) outputTaskResources(alloc *api.Allocation, task string, stats *api.AllocResourceUsage, displayStats bool) { - resource, ok := alloc.TaskResources[task] - if !ok { + resource, ok := alloc.AllocatedResources.Tasks[task] + if !ok || resource == nil { return } @@ -618,8 +618,8 @@ func (c *AllocStatusCommand) outputTaskResources(alloc *api.Allocation, task str var resourcesOutput []string cpuHeader := "CPU" - if resource.Cores != nil && *resource.Cores > 0 { - cpuHeader = fmt.Sprintf("CPU (%v cores)", *resource.Cores) + if len(resource.Cpu.ReservedCores) > 0 { + cpuHeader = fmt.Sprintf("CPU (%v cores)", len(resource.Cpu.ReservedCores)) } resourcesOutput = append(resourcesOutput, fmt.Sprintf("%s|Memory|Disk|Addresses", cpuHeader)) firstAddr := "" @@ -632,11 +632,11 @@ func (c *AllocStatusCommand) outputTaskResources(alloc *api.Allocation, task str } // Display the rolled up stats. If possible prefer the live statistics - cpuUsage := strconv.Itoa(*resource.CPU) - memUsage := humanize.IBytes(uint64(*resource.MemoryMB * bytesPerMegabyte)) + cpuUsage := strconv.Itoa(int(resource.Cpu.CpuShares)) + memUsage := humanize.IBytes(uint64(resource.Memory.MemoryMB * bytesPerMegabyte)) memMax := "" - if max := resource.MemoryMaxMB; max != nil && *max != 0 && *max != *resource.MemoryMB { - memMax = "Max: " + humanize.IBytes(uint64(*resource.MemoryMaxMB*bytesPerMegabyte)) + if resource.Memory.MemoryMaxMB != 0 && resource.Memory.MemoryMaxMB != resource.Memory.MemoryMB { + memMax = "Max: " + humanize.IBytes(uint64(resource.Memory.MemoryMaxMB*bytesPerMegabyte)) } var deviceStats []*api.DeviceGroupStats @@ -657,10 +657,11 @@ func (c *AllocStatusCommand) outputTaskResources(alloc *api.Allocation, task str deviceStats = ru.ResourceUsage.DeviceStats } } + resourcesOutput = append(resourcesOutput, fmt.Sprintf("%v MHz|%v|%v|%v", cpuUsage, memUsage, - humanize.IBytes(uint64(*alloc.Resources.DiskMB*bytesPerMegabyte)), + humanize.IBytes(uint64(alloc.AllocatedResources.Shared.DiskMB*bytesPerMegabyte)), firstAddr)) if memMax != "" || secondAddr != "" { resourcesOutput = append(resourcesOutput, fmt.Sprintf("|%v||%v", memMax, secondAddr)) diff --git a/command/alloc_status_test.go b/command/alloc_status_test.go index 7ef00c14b23..5ed433f2b3b 100644 --- a/command/alloc_status_test.go +++ b/command/alloc_status_test.go @@ -116,8 +116,8 @@ func TestAllocStatusCommand_LifecycleInfo(t *testing.T) { } tg.Tasks = append(tg.Tasks, initTask, prestartSidecarTask) - a.TaskResources["init_task"] = a.TaskResources["web"] - a.TaskResources["prestart_sidecar"] = a.TaskResources["web"] + a.AllocatedResources.Tasks["init_task"] = a.AllocatedResources.Tasks["web"] + a.AllocatedResources.Tasks["prestart_sidecar"] = a.AllocatedResources.Tasks["web"] a.TaskStates = map[string]*structs.TaskState{ "web": {State: "pending"}, "init_task": {State: "running"}, diff --git a/command/node_status.go b/command/node_status.go index 27a83213f2e..c14443e4464 100644 --- a/command/node_status.go +++ b/command/node_status.go @@ -949,9 +949,11 @@ func getAllocatedResources(client *api.Client, runningAllocs []*api.Allocation, // Get Resources var cpu, mem, disk int for _, alloc := range runningAllocs { - cpu += *alloc.Resources.CPU - mem += *alloc.Resources.MemoryMB - disk += *alloc.Resources.DiskMB + for _, taskResources := range alloc.AllocatedResources.Tasks { + cpu += int(taskResources.Cpu.CpuShares) + mem += int(taskResources.Memory.MemoryMB) + } + disk += int(alloc.AllocatedResources.Shared.DiskMB) } allocCount := strconv.Itoa(len(runningAllocs)) diff --git a/nomad/deploymentwatcher/deployments_watcher_test.go b/nomad/deploymentwatcher/deployments_watcher_test.go index 65d57714a1b..7d854f61089 100644 --- a/nomad/deploymentwatcher/deployments_watcher_test.go +++ b/nomad/deploymentwatcher/deployments_watcher_test.go @@ -495,8 +495,6 @@ func TestWatcher_AutoPromoteDeployment(t *testing.T) { a.TaskGroup = "api" a.AllocatedResources.Tasks["api"] = a.AllocatedResources.Tasks["web"].Copy() delete(a.AllocatedResources.Tasks, "web") - a.TaskResources["api"] = a.TaskResources["web"].Copy() - delete(a.TaskResources, "web") a.DeploymentStatus = &structs.AllocDeploymentStatus{ Canary: false, } diff --git a/nomad/fsm_test.go b/nomad/fsm_test.go index ae841b8a890..514e0ab213b 100644 --- a/nomad/fsm_test.go +++ b/nomad/fsm_test.go @@ -1617,7 +1617,6 @@ func TestFSM_ApplyPlanResults(t *testing.T) { fsm.evalBroker.SetEnabled(true) // Create the request and create a deployment alloc := mock.Alloc() - alloc.Resources = &structs.Resources{} // COMPAT(0.11): Remove in 0.11, used to bypass resource creation in state store job := alloc.Job alloc.Job = nil @@ -2453,9 +2452,6 @@ func TestFSM_SnapshotRestore_Allocs_Canonicalize(t *testing.T) { state := fsm.State() alloc := mock.Alloc() - // remove old versions to force migration path - alloc.AllocatedResources = nil - must.NoError(t, state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID))) must.NoError(t, state.UpsertJob(structs.MsgTypeTestSetup, 999, nil, alloc.Job)) must.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc})) @@ -2465,13 +2461,13 @@ func TestFSM_SnapshotRestore_Allocs_Canonicalize(t *testing.T) { state2 := fsm2.State() ws := memdb.NewWatchSet() out, err := state2.AllocByID(ws, alloc.ID) - require.NoError(t, err) + must.NoError(t, err) - require.NotNil(t, out.AllocatedResources) - require.Contains(t, out.AllocatedResources.Tasks, "web") + must.NotNil(t, out.AllocatedResources) + must.MapContainsKey(t, out.AllocatedResources.Tasks, "web") alloc.Canonicalize() - require.Equal(t, alloc, out) + must.Eq(t, alloc, out) } func TestFSM_SnapshotRestore_Indexes(t *testing.T) { diff --git a/nomad/mock/alloc.go b/nomad/mock/alloc.go index caf35085646..29a44a80980 100644 --- a/nomad/mock/alloc.go +++ b/nomad/mock/alloc.go @@ -18,41 +18,6 @@ func Alloc() *structs.Allocation { NodeID: "12345678-abcd-efab-cdef-123456789abc", Namespace: structs.DefaultNamespace, TaskGroup: "web", - - // TODO Remove once clientv2 gets merged - Resources: &structs.Resources{ - CPU: 500, - MemoryMB: 256, - DiskMB: 150, - Networks: []*structs.NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}}, - MBits: 50, - DynamicPorts: []structs.Port{{Label: "http"}}, - }, - }, - }, - TaskResources: map[string]*structs.Resources{ - "web": { - CPU: 500, - MemoryMB: 256, - Networks: []*structs.NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}}, - MBits: 50, - DynamicPorts: []structs.Port{{Label: "http", Value: 9876}}, - }, - }, - }, - }, - SharedResources: &structs.Resources{ - DiskMB: 150, - }, - AllocatedResources: &structs.AllocatedResources{ Tasks: map[string]*structs.AllocatedTaskResources{ "web": { @@ -123,10 +88,7 @@ func MinAllocForJob(job *structs.Job) *structs.Allocation { func AllocWithoutReservedPort() *structs.Allocation { alloc := Alloc() - alloc.Resources.Networks[0].ReservedPorts = nil - alloc.TaskResources["web"].Networks[0].ReservedPorts = nil alloc.AllocatedResources.Tasks["web"].Networks[0].ReservedPorts = nil - return alloc } @@ -140,12 +102,9 @@ func AllocForNode(n *structs.Node) *structs.Allocation { alloc.NodeID = n.ID // Set node IP address. - alloc.Resources.Networks[0].IP = nodeIP - alloc.TaskResources["web"].Networks[0].IP = nodeIP alloc.AllocatedResources.Tasks["web"].Networks[0].IP = nodeIP // Set dynamic port to a random value. - alloc.TaskResources["web"].Networks[0].DynamicPorts = []structs.Port{{Label: "http", Value: randomDynamicPort}} alloc.AllocatedResources.Tasks["web"].Networks[0].DynamicPorts = []structs.Port{{Label: "http", Value: randomDynamicPort}} return alloc @@ -162,12 +121,9 @@ func AllocForNodeWithoutReservedPort(n *structs.Node) *structs.Allocation { alloc.NodeID = n.ID // Set node IP address. - alloc.Resources.Networks[0].IP = nodeIP - alloc.TaskResources["web"].Networks[0].IP = nodeIP alloc.AllocatedResources.Tasks["web"].Networks[0].IP = nodeIP // Set dynamic port to a random value. - alloc.TaskResources["web"].Networks[0].DynamicPorts = []structs.Port{{Label: "http", Value: randomDynamicPort}} alloc.AllocatedResources.Tasks["web"].Networks[0].DynamicPorts = []structs.Port{{Label: "http", Value: randomDynamicPort}} return alloc @@ -208,41 +164,6 @@ func SystemAlloc() *structs.Allocation { NodeID: "12345678-abcd-efab-cdef-123456789abc", Namespace: structs.DefaultNamespace, TaskGroup: "web", - - // TODO Remove once clientv2 gets merged - Resources: &structs.Resources{ - CPU: 500, - MemoryMB: 256, - DiskMB: 150, - Networks: []*structs.NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}}, - MBits: 50, - DynamicPorts: []structs.Port{{Label: "http"}}, - }, - }, - }, - TaskResources: map[string]*structs.Resources{ - "web": { - CPU: 500, - MemoryMB: 256, - Networks: []*structs.NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}}, - MBits: 50, - DynamicPorts: []structs.Port{{Label: "http", Value: 9876}}, - }, - }, - }, - }, - SharedResources: &structs.Resources{ - DiskMB: 150, - }, - AllocatedResources: &structs.AllocatedResources{ Tasks: map[string]*structs.AllocatedTaskResources{ "web": { diff --git a/nomad/mock/connect.go b/nomad/mock/connect.go index f7112211ee0..55c231725f4 100644 --- a/nomad/mock/connect.go +++ b/nomad/mock/connect.go @@ -313,13 +313,6 @@ func BatchConnectAlloc() *structs.Allocation { NodeID: "12345678-abcd-efab-cdef-123456789abc", Namespace: structs.DefaultNamespace, TaskGroup: "mock-connect-batch-job", - TaskResources: map[string]*structs.Resources{ - "connect-proxy-testconnect": { - CPU: 500, - MemoryMB: 256, - }, - }, - AllocatedResources: &structs.AllocatedResources{ Tasks: map[string]*structs.AllocatedTaskResources{ "connect-proxy-testconnect": { @@ -355,41 +348,6 @@ func BatchAlloc() *structs.Allocation { NodeID: "12345678-abcd-efab-cdef-123456789abc", Namespace: structs.DefaultNamespace, TaskGroup: "web", - - // TODO Remove once clientv2 gets merged - Resources: &structs.Resources{ - CPU: 500, - MemoryMB: 256, - DiskMB: 150, - Networks: []*structs.NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}}, - MBits: 50, - DynamicPorts: []structs.Port{{Label: "http"}}, - }, - }, - }, - TaskResources: map[string]*structs.Resources{ - "web": { - CPU: 500, - MemoryMB: 256, - Networks: []*structs.NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}}, - MBits: 50, - DynamicPorts: []structs.Port{{Label: "http", Value: 9876}}, - }, - }, - }, - }, - SharedResources: &structs.Resources{ - DiskMB: 150, - }, - AllocatedResources: &structs.AllocatedResources{ Tasks: map[string]*structs.AllocatedTaskResources{ "web": { diff --git a/nomad/mock/lifecycle.go b/nomad/mock/lifecycle.go index 9a09822df5a..533e90c5b6f 100644 --- a/nomad/mock/lifecycle.go +++ b/nomad/mock/lifecycle.go @@ -90,7 +90,6 @@ func LifecycleAllocFromTasks(tasks []LifecycleTaskDef) *structs.Allocation { Resources: &structs.Resources{CPU: 100, MemoryMB: 256}, }, ) - alloc.TaskResources[task.Name] = &structs.Resources{CPU: 100, MemoryMB: 256} alloc.AllocatedResources.Tasks[task.Name] = &structs.AllocatedTaskResources{ Cpu: structs.AllocatedCpuResources{CpuShares: 100}, Memory: structs.AllocatedMemoryResources{MemoryMB: 256}, @@ -106,31 +105,6 @@ func LifecycleAlloc() *structs.Allocation { NodeID: "12345678-abcd-efab-cdef-123456789abc", Namespace: structs.DefaultNamespace, TaskGroup: "web", - - // TODO Remove once clientv2 gets merged - Resources: &structs.Resources{ - CPU: 500, - MemoryMB: 256, - }, - TaskResources: map[string]*structs.Resources{ - "web": { - CPU: 1000, - MemoryMB: 256, - }, - "init": { - CPU: 1000, - MemoryMB: 256, - }, - "side": { - CPU: 1000, - MemoryMB: 256, - }, - "poststart": { - CPU: 1000, - MemoryMB: 256, - }, - }, - AllocatedResources: &structs.AllocatedResources{ Tasks: map[string]*structs.AllocatedTaskResources{ "web": { @@ -390,31 +364,6 @@ func LifecycleAllocWithPoststopDeploy() *structs.Allocation { NodeID: "12345678-abcd-efab-cdef-123456789abc", Namespace: structs.DefaultNamespace, TaskGroup: "web", - - // TODO Remove once clientv2 gets merged - Resources: &structs.Resources{ - CPU: 500, - MemoryMB: 256, - }, - TaskResources: map[string]*structs.Resources{ - "web": { - CPU: 1000, - MemoryMB: 256, - }, - "init": { - CPU: 1000, - MemoryMB: 256, - }, - "side": { - CPU: 1000, - MemoryMB: 256, - }, - "post": { - CPU: 1000, - MemoryMB: 256, - }, - }, - AllocatedResources: &structs.AllocatedResources{ Tasks: map[string]*structs.AllocatedTaskResources{ "web": { @@ -466,31 +415,6 @@ func LifecycleAllocWithPoststartDeploy() *structs.Allocation { NodeID: "12345678-abcd-efab-cdef-123456789xyz", Namespace: structs.DefaultNamespace, TaskGroup: "web", - - // TODO Remove once clientv2 gets merged - Resources: &structs.Resources{ - CPU: 500, - MemoryMB: 256, - }, - TaskResources: map[string]*structs.Resources{ - "web": { - CPU: 1000, - MemoryMB: 256, - }, - "init": { - CPU: 1000, - MemoryMB: 256, - }, - "side": { - CPU: 1000, - MemoryMB: 256, - }, - "post": { - CPU: 1000, - MemoryMB: 256, - }, - }, - AllocatedResources: &structs.AllocatedResources{ Tasks: map[string]*structs.AllocatedTaskResources{ "web": { diff --git a/nomad/state/state_store.go b/nomad/state/state_store.go index c7b5fb92597..0237d5d1489 100644 --- a/nomad/state/state_store.go +++ b/nomad/state/state_store.go @@ -466,42 +466,6 @@ func (s *StateStore) UpsertPlanResults(msgType structs.MessageType, index uint64 // This method is used when an allocation is being denormalized. func addComputedAllocAttrs(allocs []*structs.Allocation, job *structs.Job) { structs.DenormalizeAllocationJobs(job, allocs) - - // COMPAT(0.11): Remove in 0.11 - // Calculate the total resources of allocations. It is pulled out in the - // payload to avoid encoding something that can be computed, but should be - // denormalized prior to being inserted into MemDB. - for _, alloc := range allocs { - if alloc.Resources != nil { - continue - } - - alloc.Resources = new(structs.Resources) - for _, task := range alloc.TaskResources { - alloc.Resources.Add(task) - } - - // While we still rely on alloc.Resources field for quotas, we have to add - // device info from AllocatedResources to alloc.Resources - for _, resources := range alloc.AllocatedResources.Tasks { - for _, d := range resources.Devices { - name := d.ID().String() - count := len(d.DeviceIDs) - - if count > 0 { - if alloc.Resources.Devices == nil { - alloc.Resources.Devices = make(structs.ResourceDevices, 0) - } - alloc.Resources.Devices = append( - alloc.Resources.Devices, &structs.RequestedDevice{Name: name, Count: uint64(count)}, - ) - } - } - } - - // Add the shared resources - alloc.Resources.Add(alloc.SharedResources) - } } // upsertDeploymentUpdates updates the deployments given the passed status diff --git a/nomad/state/state_store_test.go b/nomad/state/state_store_test.go index 0bc658cd075..11a89499d31 100644 --- a/nomad/state/state_store_test.go +++ b/nomad/state/state_store_test.go @@ -494,48 +494,6 @@ func TestStateStore_UpsertPlanResults_DeploymentUpdates(t *testing.T) { must.False(t, watchFired(ws), must.Sprint("watch should not have fired")) } -func TestStateStore_UpsertPlanResults_AllocationResources(t *testing.T) { - ci.Parallel(t) - - dev := &structs.RequestedDevice{Name: "nvidia/gpu/Tesla 60", Count: 1} - structuredDev := &structs.AllocatedDeviceResource{ - Vendor: "nvidia", - Type: "gpu", - Name: "Tesla 60", - DeviceIDs: []string{"GPU-0668fc92-f8d5-07f6-e3cc-c07d76f466a1"}, - } - - state := testStateStore(t) - alloc := mock.Alloc() - job := alloc.Job - alloc.Job = nil - alloc.Resources = nil - alloc.AllocatedResources.Tasks["web"].Devices = []*structs.AllocatedDeviceResource{structuredDev} - - must.NoError(t, state.UpsertJob(structs.MsgTypeTestSetup, 999, nil, job)) - - eval := mock.Eval() - eval.JobID = job.ID - - // Create an eval - must.NoError(t, state.UpsertEvals(structs.MsgTypeTestSetup, 1, []*structs.Evaluation{eval})) - - // Create a plan result - res := structs.ApplyPlanResultsRequest{ - AllocsUpdated: []*structs.Allocation{alloc}, - Job: job, - EvalID: eval.ID, - } - - must.NoError(t, state.UpsertPlanResults(structs.MsgTypeTestSetup, 1000, &res)) - - out, err := state.AllocByID(nil, alloc.ID) - must.NoError(t, err) - must.Eq(t, alloc, out) - - must.Eq(t, alloc.Resources.Devices[0], dev) -} - func TestStateStore_UpsertDeployment(t *testing.T) { ci.Parallel(t) diff --git a/nomad/structs/alloc.go b/nomad/structs/alloc.go index 57e64ff2cbe..195999e3c0c 100644 --- a/nomad/structs/alloc.go +++ b/nomad/structs/alloc.go @@ -75,25 +75,6 @@ type Allocation struct { // TaskGroup is the name of the task group that should be run TaskGroup string - // COMPAT(0.11): Remove in 0.11 - // Resources is the total set of resources allocated as part - // of this allocation of the task group. Dynamic ports will be set by - // the scheduler. - Resources *Resources - - // SharedResources are the resources that are shared by all the tasks in an - // allocation - // Deprecated: use AllocatedResources.Shared instead. - // Keep field to allow us to handle upgrade paths from old versions - SharedResources *Resources - - // TaskResources is the set of resources allocated to each - // task. These should sum to the total Resources. Dynamic ports will be - // set by the scheduler. - // Deprecated: use AllocatedResources.Tasks instead. - // Keep field to allow us to handle upgrade paths from old versions - TaskResources map[string]*Resources - // AllocatedResources is the total resources allocated for the task group. AllocatedResources *AllocatedResources @@ -289,28 +270,6 @@ func (a *Allocation) CopySkipJob() *Allocation { // Allocations or receiving Allocations from Nomad agents potentially on an // older version of Nomad. func (a *Allocation) Canonicalize() { - if a.AllocatedResources == nil && a.TaskResources != nil { - ar := AllocatedResources{} - - tasks := make(map[string]*AllocatedTaskResources, len(a.TaskResources)) - for name, tr := range a.TaskResources { - atr := AllocatedTaskResources{} - atr.Cpu.CpuShares = int64(tr.CPU) - atr.Memory.MemoryMB = int64(tr.MemoryMB) - atr.Networks = tr.Networks.Copy() - - tasks[name] = &atr - } - ar.Tasks = tasks - - if a.SharedResources != nil { - ar.Shared.DiskMB = int64(a.SharedResources.DiskMB) - ar.Shared.Networks = a.SharedResources.Networks.Copy() - } - - a.AllocatedResources = &ar - } - a.Job.Canonicalize() } @@ -326,16 +285,6 @@ func (a *Allocation) copyImpl(job bool) *Allocation { } na.AllocatedResources = na.AllocatedResources.Copy() - na.Resources = na.Resources.Copy() - na.SharedResources = na.SharedResources.Copy() - - if a.TaskResources != nil { - tr := make(map[string]*Resources, len(na.TaskResources)) - for task, resource := range na.TaskResources { - tr[task] = resource.Copy() - } - na.TaskResources = tr - } na.Metrics = na.Metrics.Copy() na.DeploymentStatus = na.DeploymentStatus.Copy() diff --git a/nomad/structs/alloc_test.go b/nomad/structs/alloc_test.go index e88db5dea4e..5c4f49cedfe 100644 --- a/nomad/structs/alloc_test.go +++ b/nomad/structs/alloc_test.go @@ -1546,56 +1546,3 @@ func TestAllocation_LastStartOfTask(t *testing.T) { }) } } - -func TestAllocation_Canonicalize_Old(t *testing.T) { - ci.Parallel(t) - - alloc := MockAlloc() - alloc.AllocatedResources = nil - alloc.TaskResources = map[string]*Resources{ - "web": { - CPU: 500, - MemoryMB: 256, - Networks: []*NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - ReservedPorts: []Port{{Label: "admin", Value: 5000}}, - MBits: 50, - DynamicPorts: []Port{{Label: "http", Value: 9876}}, - }, - }, - }, - } - alloc.SharedResources = &Resources{ - DiskMB: 150, - } - alloc.Canonicalize() - - expected := &AllocatedResources{ - Tasks: map[string]*AllocatedTaskResources{ - "web": { - Cpu: AllocatedCpuResources{ - CpuShares: 500, - }, - Memory: AllocatedMemoryResources{ - MemoryMB: 256, - }, - Networks: []*NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - ReservedPorts: []Port{{Label: "admin", Value: 5000}}, - MBits: 50, - DynamicPorts: []Port{{Label: "http", Value: 9876}}, - }, - }, - }, - }, - Shared: AllocatedSharedResources{ - DiskMB: 150, - }, - } - - must.Eq(t, expected, alloc.AllocatedResources) -} diff --git a/nomad/structs/network.go b/nomad/structs/network.go index 9cdab144d37..09e43995f76 100644 --- a/nomad/structs/network.go +++ b/nomad/structs/network.go @@ -346,18 +346,6 @@ func (idx *NetworkIndex) AddAllocs(allocs []*Allocation) (collide bool, reason s } } } - } else { - // COMPAT(0.11): Remove in 0.11 - for task, resources := range alloc.TaskResources { - if len(resources.Networks) == 0 { - continue - } - n := resources.Networks[0] - if c, r := idx.AddReserved(n); c { - collide = true - reason = fmt.Sprintf("(deprecated) collision when reserving port for network %s in task %s of alloc %s: %v", n.IP, task, alloc.ID, r) - } - } } } return diff --git a/nomad/structs/network_test.go b/nomad/structs/network_test.go index 4d02657cfdc..498b8ce9773 100644 --- a/nomad/structs/network_test.go +++ b/nomad/structs/network_test.go @@ -624,32 +624,24 @@ func TestNetworkIndex_AssignTaskNetwork(t *testing.T) { allocs := []*Allocation{ { - TaskResources: map[string]*Resources{ - "web": { - Networks: []*NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - MBits: 20, - ReservedPorts: []Port{{Label: "one", Value: 8000}, {Label: "two", Value: 9000}}, - }, + AllocatedResources: &AllocatedResources{Tasks: map[string]*AllocatedTaskResources{ + "web": {Networks: []*NetworkResource{ + { + Device: "eth0", + IP: "192.168.0.100", + MBits: 20, + ReservedPorts: []Port{{Label: "one", Value: 8000}, {Label: "two", Value: 9000}}, }, - }, - }, - }, - { - TaskResources: map[string]*Resources{ - "api": { - Networks: []*NetworkResource{ - { - Device: "eth0", - IP: "192.168.0.100", - MBits: 50, - ReservedPorts: []Port{{Label: "main", Value: 10000}}, - }, + }}, + "api": {Networks: []*NetworkResource{ + { + Device: "eth0", + IP: "192.168.0.100", + MBits: 50, + ReservedPorts: []Port{{Label: "main", Value: 10000}}, }, - }, - }, + }}, + }}, }, } idx.AddAllocs(allocs) diff --git a/nomad/structs/plan.go b/nomad/structs/plan.go index 7df679a6068..9e0576f1c1d 100644 --- a/nomad/structs/plan.go +++ b/nomad/structs/plan.go @@ -169,9 +169,6 @@ func (p *Plan) AppendStoppedAlloc(alloc *Allocation, desiredDesc, clientStatus, // Normalize the job newAlloc.Job = nil - // Strip the resources as it can be rebuilt. - newAlloc.Resources = nil - newAlloc.DesiredStatus = AllocDesiredStatusStop newAlloc.DesiredDescription = desiredDesc @@ -206,10 +203,6 @@ func (p *Plan) AppendPreemptedAlloc(alloc *Allocation, preemptingAllocID string) // after removing preempted allocations if alloc.AllocatedResources != nil { newAlloc.AllocatedResources = alloc.AllocatedResources - } else { - // COMPAT Remove in version 0.11 - newAlloc.TaskResources = alloc.TaskResources - newAlloc.SharedResources = alloc.SharedResources } // Append this alloc to slice for this node @@ -220,9 +213,6 @@ func (p *Plan) AppendPreemptedAlloc(alloc *Allocation, preemptingAllocID string) // AppendUnknownAlloc marks an allocation as unknown. func (p *Plan) AppendUnknownAlloc(alloc *Allocation) { - // Strip the resources as they can be rebuilt. - alloc.Resources = nil - existing := p.NodeAllocation[alloc.NodeID] p.NodeAllocation[alloc.NodeID] = append(existing, alloc) } diff --git a/nomad/structs/plan_test.go b/nomad/structs/plan_test.go index fff1d799279..e8cf7cb63c6 100644 --- a/nomad/structs/plan_test.go +++ b/nomad/structs/plan_test.go @@ -93,8 +93,6 @@ func TestPlan_AppendPreemptedAllocAppendsAllocWithUpdatedAttrs(t *testing.T) { DesiredStatus: AllocDesiredStatusEvict, DesiredDescription: fmt.Sprintf("Preempted by alloc ID %v", preemptingAllocID), AllocatedResources: alloc.AllocatedResources, - TaskResources: alloc.TaskResources, - SharedResources: alloc.SharedResources, } must.Eq(t, expectedAlloc, appendedAlloc) } diff --git a/scheduler/generic_sched.go b/scheduler/generic_sched.go index d6cab955730..35046a4d8be 100644 --- a/scheduler/generic_sched.go +++ b/scheduler/generic_sched.go @@ -650,16 +650,9 @@ func (s *GenericScheduler) computePlacements( NodeID: option.Node.ID, NodeName: option.Node.Name, DeploymentID: deploymentID, - TaskResources: resources.OldTaskResources(), AllocatedResources: resources, DesiredStatus: structs.AllocDesiredStatusRun, ClientStatus: structs.AllocClientStatusPending, - // SharedResources is considered deprecated, will be removed in 0.11. - // It is only set for compat reasons. - SharedResources: &structs.Resources{ - DiskMB: tg.EphemeralDisk.SizeMB, - Networks: resources.Shared.Networks, - }, } // If the new allocation is replacing an older allocation then we diff --git a/scheduler/scheduler_sysbatch.go b/scheduler/scheduler_sysbatch.go index 6cc7ab4e180..834eabadefc 100644 --- a/scheduler/scheduler_sysbatch.go +++ b/scheduler/scheduler_sysbatch.go @@ -428,16 +428,9 @@ func (s *SysBatchScheduler) computePlacements(place []reconciler.AllocTuple, exi Metrics: s.ctx.Metrics(), NodeID: option.Node.ID, NodeName: option.Node.Name, - TaskResources: resources.OldTaskResources(), AllocatedResources: resources, DesiredStatus: structs.AllocDesiredStatusRun, ClientStatus: structs.AllocClientStatusPending, - // SharedResources is considered deprecated, will be removed in 0.11. - // It is only set for compat reasons - SharedResources: &structs.Resources{ - DiskMB: missing.TaskGroup.EphemeralDisk.SizeMB, - Networks: resources.Shared.Networks, - }, } // If the new allocation is replacing an older allocation then we record the diff --git a/scheduler/scheduler_system.go b/scheduler/scheduler_system.go index c9c0f28bff0..0de45b3799f 100644 --- a/scheduler/scheduler_system.go +++ b/scheduler/scheduler_system.go @@ -597,16 +597,9 @@ func (s *SystemScheduler) computePlacements( NodeID: option.Node.ID, NodeName: option.Node.Name, DeploymentID: deploymentID, - TaskResources: resources.OldTaskResources(), AllocatedResources: resources, DesiredStatus: structs.AllocDesiredStatusRun, ClientStatus: structs.AllocClientStatusPending, - // SharedResources is considered deprecated, will be removed in 0.11. - // It is only set for compat reasons - SharedResources: &structs.Resources{ - DiskMB: missing.TaskGroup.EphemeralDisk.SizeMB, - Networks: resources.Shared.Networks, - }, } // If the new allocation is replacing an older allocation then we record the diff --git a/scheduler/scheduler_system_test.go b/scheduler/scheduler_system_test.go index 1c727d850d7..02954f2c2e7 100644 --- a/scheduler/scheduler_system_test.go +++ b/scheduler/scheduler_system_test.go @@ -766,8 +766,8 @@ func TestSystemSched_JobModify_InPlace(t *testing.T) { // Verify the network did not change rp := structs.Port{Label: "admin", Value: 5000} for _, alloc := range out { - for _, resources := range alloc.TaskResources { - must.Eq(t, rp, resources.Networks[0].ReservedPorts[0]) + for _, network := range alloc.AllocatedResources.Shared.Networks { + must.Eq(t, rp, network.ReservedPorts[0]) } } } @@ -4024,7 +4024,7 @@ func TestSystemSched_UpdateBlock(t *testing.T) { } else { // make sure alloc matches tg1.Networks alloc = mock.AllocForNode(nodes[nodeIdx]) - alloc.TaskResources["web"].Networks = nil + alloc.AllocatedResources.Shared.Networks = nil } alloc.Job = oldJob alloc.JobID = oldJob.ID @@ -4041,7 +4041,7 @@ func TestSystemSched_UpdateBlock(t *testing.T) { } else { // make sure alloc matches tg1.Networks alloc = mock.AllocForNode(nodes[nodeIdx]) - alloc.TaskResources["web"].Networks = nil + alloc.AllocatedResources.Shared.Networks = nil } alloc.Job = job alloc.JobID = job.ID @@ -4070,7 +4070,7 @@ func TestSystemSched_UpdateBlock(t *testing.T) { } else { // make sure alloc matches tg1.Networks alloc = mock.AllocForNode(nodes[nodeIdx]) - alloc.TaskResources["web"].Networks = nil + alloc.AllocatedResources.Shared.Networks = nil } alloc.Job = job alloc.JobID = job.ID diff --git a/scheduler/scheduler_test.go b/scheduler/scheduler_test.go index e48f10411cf..3f8dc12c36c 100644 --- a/scheduler/scheduler_test.go +++ b/scheduler/scheduler_test.go @@ -207,20 +207,9 @@ func TestScheduler_JobRegister_MemoryMaxHonored(t *testing.T) { must.Len(t, expectedAllocCount, allocs) alloc := allocs[0] - // checking new resources field deprecated Resources fields must.Eq(t, int64(c.cpu), alloc.AllocatedResources.Tasks[task].Cpu.CpuShares) must.Eq(t, int64(c.memory), alloc.AllocatedResources.Tasks[task].Memory.MemoryMB) must.Eq(t, int64(c.expectedTaskMemoryMax), alloc.AllocatedResources.Tasks[task].Memory.MemoryMaxMB) - - // checking old deprecated Resources fields - must.Eq(t, c.cpu, alloc.TaskResources[task].CPU) - must.Eq(t, c.memory, alloc.TaskResources[task].MemoryMB) - must.Eq(t, c.expectedTaskMemoryMax, alloc.TaskResources[task].MemoryMaxMB) - - // check total resource fields - alloc.Resources deprecated field, no modern equivalent - must.Eq(t, c.cpu, alloc.Resources.CPU) - must.Eq(t, c.memory, alloc.Resources.MemoryMB) - must.Eq(t, c.expectedTotalMemoryMax, alloc.Resources.MemoryMaxMB) }) } } diff --git a/scheduler/tests/testing.go b/scheduler/tests/testing.go index 8761b69ee05..edb925a4276 100644 --- a/scheduler/tests/testing.go +++ b/scheduler/tests/testing.go @@ -128,12 +128,9 @@ func CreateAllocWithDevice(id string, job *structs.Job, resource *structs.Resour func CreateAllocInner(id string, job *structs.Job, resource *structs.Resources, allocatedDevices *structs.AllocatedDeviceResource, tgNetwork *structs.NetworkResource) *structs.Allocation { alloc := &structs.Allocation{ - ID: id, - Job: job, - JobID: job.ID, - TaskResources: map[string]*structs.Resources{ - "web": resource, - }, + ID: id, + Job: job, + JobID: job.ID, Namespace: structs.DefaultNamespace, EvalID: uuid.Generate(), DesiredStatus: structs.AllocDesiredStatusRun, diff --git a/scheduler/util.go b/scheduler/util.go index 955da6a658b..3aea31072e9 100644 --- a/scheduler/util.go +++ b/scheduler/util.go @@ -655,8 +655,6 @@ func inplaceUpdate(ctx feasible.Context, eval *structs.Evaluation, job *structs. networks = tr.Networks devices = tr.Devices } - } else if tr, ok := update.Alloc.TaskResources[task]; ok { - networks = tr.Networks } // Add the networks and devices back @@ -670,8 +668,7 @@ func inplaceUpdate(ctx feasible.Context, eval *structs.Evaluation, job *structs. // Update the allocation newAlloc.EvalID = eval.ID - newAlloc.Job = nil // Use the Job in the Plan - newAlloc.Resources = nil // Computed in Plan Apply + newAlloc.Job = nil // Use the Job in the Plan newAlloc.AllocatedResources = &structs.AllocatedResources{ Tasks: option.TaskResources, TaskLifecycles: option.TaskLifecycles, @@ -850,7 +847,6 @@ func genericAllocUpdateFn(ctx feasible.Context, stack feasible.Stack, evalID str newAlloc := existing.Copy() newAlloc.EvalID = evalID newAlloc.Job = nil - newAlloc.Resources = nil newMax, newOK := newAlloc.MaxRunDuration() if oldOK != newOK || oldMax != newMax { @@ -892,8 +888,6 @@ func genericAllocUpdateFn(ctx feasible.Context, stack feasible.Stack, evalID str devices = tr.Devices cores = tr.Cpu.ReservedCores } - } else if tr, ok := existing.TaskResources[task]; ok { - networks = tr.Networks } // Add the networks back @@ -908,8 +902,7 @@ func genericAllocUpdateFn(ctx feasible.Context, stack feasible.Stack, evalID str // Update the allocation newAlloc.EvalID = evalID - newAlloc.Job = nil // Use the Job in the Plan - newAlloc.Resources = nil // Computed in Plan Apply + newAlloc.Job = nil // Use the Job in the Plan newAlloc.AllocatedResources = &structs.AllocatedResources{ Tasks: option.TaskResources, TaskLifecycles: option.TaskLifecycles, diff --git a/scheduler/util_test.go b/scheduler/util_test.go index 001bbbd802c..7b5c631eaff 100644 --- a/scheduler/util_test.go +++ b/scheduler/util_test.go @@ -700,7 +700,6 @@ func TestInplaceUpdate_ChangedTaskGroup(t *testing.T) { DesiredStatus: structs.AllocDesiredStatusRun, TaskGroup: "web", } - alloc.TaskResources = map[string]*structs.Resources{"web": alloc.Resources} must.NoError(t, state.UpsertJobSummary(1000, mock.JobSummary(alloc.JobID))) must.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1001, []*structs.Allocation{alloc})) @@ -756,7 +755,6 @@ func TestInplaceUpdate_AllocatedResources(t *testing.T) { DesiredStatus: structs.AllocDesiredStatusRun, TaskGroup: "web", } - alloc.TaskResources = map[string]*structs.Resources{"web": alloc.Resources} must.NoError(t, state.UpsertJobSummary(1000, mock.JobSummary(alloc.JobID))) must.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1001, []*structs.Allocation{alloc})) @@ -816,7 +814,6 @@ func TestInplaceUpdate_NoMatch(t *testing.T) { DesiredStatus: structs.AllocDesiredStatusRun, TaskGroup: "web", } - alloc.TaskResources = map[string]*structs.Resources{"web": alloc.Resources} must.NoError(t, state.UpsertJobSummary(1000, mock.JobSummary(alloc.JobID))) must.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1001, []*structs.Allocation{alloc})) @@ -869,7 +866,6 @@ func TestInplaceUpdate_Success(t *testing.T) { }, DesiredStatus: structs.AllocDesiredStatusRun, } - alloc.TaskResources = map[string]*structs.Resources{"web": alloc.Resources} must.NoError(t, state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))) must.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1001, []*structs.Allocation{alloc})) From ddef34683a28a9802f117b480bec1c75d9d04efd Mon Sep 17 00:00:00 2001 From: Tim Gross Date: Fri, 4 Sep 2026 13:50:38 -0400 Subject: [PATCH 2/2] remove OldTaskResources --- nomad/structs/structs.go | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 286b224dc5a..197168d0b5f 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -3841,23 +3841,6 @@ func (a *AllocatedResources) Comparable() *ComparableResources { return c } -// OldTaskResources returns the pre-0.9.0 map of task resources. This -// functionality is still used within the scheduling code. -func (a *AllocatedResources) OldTaskResources() map[string]*Resources { - m := make(map[string]*Resources, len(a.Tasks)) - for name, res := range a.Tasks { - m[name] = &Resources{ - Cores: len(res.Cpu.ReservedCores), - CPU: int(res.Cpu.CpuShares), - MemoryMB: int(res.Memory.MemoryMB), - MemoryMaxMB: int(res.Memory.MemoryMaxMB), - Networks: res.Networks, - } - } - - return m -} - func (a *AllocatedResources) Canonicalize() { a.Shared.Canonicalize()