open-nomad/nomad/state/state_store_restore_test.go
hc-github-team-nomad-core 4ebd0d251f
backport of commit f7a336d2ba95a362504d6094e581b8aeedbd554e (#18323)
Co-authored-by: James Rasell <jrasell@users.noreply.github.com>
2023-08-25 09:37:13 +01:00

558 lines
13 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package state
import (
"testing"
"time"
"github.com/hashicorp/go-memdb"
"github.com/hashicorp/nomad/ci"
"github.com/hashicorp/nomad/helper/uuid"
"github.com/hashicorp/nomad/nomad/mock"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/shoenig/test/must"
)
func TestStateStore_RestoreNode(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
node := mock.Node()
restore, err := state.Restore()
must.NoError(t, err)
must.NoError(t, restore.NodeRestore(node))
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.NodeByID(ws, node.ID)
must.NoError(t, err)
must.Eq(t, node, out)
}
func TestStateStore_RestoreJob(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
mockJob1 := mock.Job()
restore, err := state.Restore()
must.NoError(t, err)
err = restore.JobRestore(mockJob1)
must.NoError(t, err)
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.JobByID(ws, mockJob1.Namespace, mockJob1.ID)
must.NoError(t, err)
must.Eq(t, mockJob1, out)
// Test upgrade to 1.6 or greater to simulate restoring a job which does
// not have a node pool set.
mockJob2 := mock.Job()
mockJob2.NodePool = ""
restore, err = state.Restore()
must.NoError(t, err)
err = restore.JobRestore(mockJob2)
must.NoError(t, err)
must.NoError(t, restore.Commit())
ws = memdb.NewWatchSet()
out, err = state.JobByID(ws, mockJob2.Namespace, mockJob2.ID)
must.NoError(t, err)
must.Eq(t, structs.NodePoolDefault, out.NodePool)
}
func TestStateStore_RestorePeriodicLaunch(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
job := mock.Job()
launch := &structs.PeriodicLaunch{
ID: job.ID,
Namespace: job.Namespace,
Launch: time.Now(),
}
restore, err := state.Restore()
must.NoError(t, err)
must.NoError(t, restore.PeriodicLaunchRestore(launch))
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.PeriodicLaunchByID(ws, job.Namespace, job.ID)
must.NoError(t, err)
must.Eq(t, launch, out)
must.False(t, watchFired(ws))
}
func TestStateStore_RestoreJobVersion(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
job := mock.Job()
restore, err := state.Restore()
must.NoError(t, err)
must.NoError(t, restore.JobVersionRestore(job))
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.JobByIDAndVersion(ws, job.Namespace, job.ID, job.Version)
must.NoError(t, err)
must.Eq(t, job, out)
must.False(t, watchFired(ws))
}
func TestStateStore_RestoreDeployment(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
d := mock.Deployment()
restore, err := state.Restore()
must.NoError(t, err)
must.NoError(t, restore.DeploymentRestore(d))
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.DeploymentByID(ws, d.ID)
must.NoError(t, err)
must.Eq(t, d, out)
must.False(t, watchFired(ws))
}
func TestStateStore_RestoreJobSummary(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
job := mock.Job()
jobSummary := &structs.JobSummary{
JobID: job.ID,
Namespace: job.Namespace,
Summary: map[string]structs.TaskGroupSummary{
"web": {
Starting: 10,
},
},
}
restore, err := state.Restore()
must.NoError(t, err)
must.NoError(t, restore.JobSummaryRestore(jobSummary))
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.JobSummaryByID(ws, job.Namespace, job.ID)
must.NoError(t, err)
must.Eq(t, jobSummary, out)
must.False(t, watchFired(ws))
}
func TestStateStore_RestoreCSIPlugin(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
plugin := mock.CSIPlugin()
restore, err := state.Restore()
must.NoError(t, err)
err = restore.CSIPluginRestore(plugin)
must.NoError(t, err)
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.CSIPluginByID(ws, plugin.ID)
must.NoError(t, err)
must.Eq(t, plugin, out)
must.False(t, watchFired(ws))
}
func TestStateStore_RestoreCSIVolume(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
plugin := mock.CSIPlugin()
volume := mock.CSIVolume(plugin)
restore, err := state.Restore()
must.NoError(t, err)
err = restore.CSIVolumeRestore(volume)
must.NoError(t, err)
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.CSIVolumeByID(ws, "default", volume.ID)
must.NoError(t, err)
must.Eq(t, volume, out)
}
func TestStateStore_RestoreIndex(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
restore, err := state.Restore()
must.NoError(t, err)
index := &IndexEntry{"jobs", 1000}
must.NoError(t, restore.IndexRestore(index))
must.NoError(t, restore.Commit())
out, err := state.Index("jobs")
must.NoError(t, err)
must.Eq(t, 1000, out)
}
func TestStateStore_RestoreEval(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
eval := mock.Eval()
restore, err := state.Restore()
must.NoError(t, err)
must.NoError(t, restore.EvalRestore(eval))
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.EvalByID(ws, eval.ID)
must.NoError(t, err)
must.Eq(t, eval, out)
}
func TestStateStore_RestoreAlloc(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
alloc := mock.Alloc()
restore, err := state.Restore()
must.NoError(t, err)
must.NoError(t, restore.AllocRestore(alloc))
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.AllocByID(ws, alloc.ID)
must.NoError(t, err)
must.Eq(t, alloc, out)
must.False(t, watchFired(ws))
}
func TestStateStore_RestoreVaultAccessor(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
a := mock.VaultAccessor()
restore, err := state.Restore()
must.NoError(t, err)
err = restore.VaultAccessorRestore(a)
must.NoError(t, err)
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.VaultAccessor(ws, a.Accessor)
must.NoError(t, err)
must.Eq(t, a, out)
must.False(t, watchFired(ws))
}
func TestStateStore_RestoreSITokenAccessor(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
a1 := mock.SITokenAccessor()
restore, err := state.Restore()
must.NoError(t, err)
must.NoError(t, restore.SITokenAccessorRestore(a1))
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
result, err := state.SITokenAccessor(ws, a1.AccessorID)
must.NoError(t, err)
must.Eq(t, a1, result)
must.False(t, watchFired(ws))
}
func TestStateStore_RestoreACLPolicy(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
policy := mock.ACLPolicy()
restore, err := state.Restore()
must.NoError(t, err)
err = restore.ACLPolicyRestore(policy)
must.NoError(t, err)
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.ACLPolicyByName(ws, policy.Name)
must.NoError(t, err)
must.Eq(t, policy, out)
}
func TestStateStore_RestoreACLToken(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
token := mock.ACLToken()
restore, err := state.Restore()
must.NoError(t, err)
err = restore.ACLTokenRestore(token)
must.NoError(t, err)
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.ACLTokenByAccessorID(ws, token.AccessorID)
must.NoError(t, err)
must.Eq(t, token, out)
}
func TestStateStore_ClusterMetadataRestore(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
clusterID := "12345678-1234-1234-1234-1234567890"
now := time.Now().UnixNano()
meta := &structs.ClusterMetadata{ClusterID: clusterID, CreateTime: now}
restore, err := state.Restore()
must.NoError(t, err)
err = restore.ClusterMetadataRestore(meta)
must.NoError(t, err)
must.NoError(t, restore.Commit())
out, err := state.ClusterMetadata(nil)
must.NoError(t, err)
must.Eq(t, clusterID, out.ClusterID)
must.Eq(t, now, out.CreateTime)
}
func TestStateStore_RestoreScalingPolicy(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
scalingPolicy := mock.ScalingPolicy()
restore, err := state.Restore()
must.NoError(t, err)
err = restore.ScalingPolicyRestore(scalingPolicy)
must.NoError(t, err)
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, err := state.ScalingPolicyByID(ws, scalingPolicy.ID)
must.NoError(t, err)
must.Eq(t, scalingPolicy, out)
}
func TestStateStore_RestoreScalingEvents(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
jobScalingEvents := &structs.JobScalingEvents{
Namespace: uuid.Generate(),
JobID: uuid.Generate(),
ScalingEvents: map[string][]*structs.ScalingEvent{
uuid.Generate(): {
structs.NewScalingEvent(uuid.Generate()),
},
},
}
restore, err := state.Restore()
must.NoError(t, err)
err = restore.ScalingEventsRestore(jobScalingEvents)
must.NoError(t, err)
must.NoError(t, restore.Commit())
ws := memdb.NewWatchSet()
out, _, err := state.ScalingEventsByJob(ws, jobScalingEvents.Namespace,
jobScalingEvents.JobID)
must.NoError(t, err)
must.NotNil(t, out)
must.Eq(t, jobScalingEvents.ScalingEvents, out)
}
func TestStateStore_RestoreSchedulerConfig(t *testing.T) {
ci.Parallel(t)
state := testStateStore(t)
schedConfig := &structs.SchedulerConfiguration{
PreemptionConfig: structs.PreemptionConfig{
SystemSchedulerEnabled: false,
},
CreateIndex: 100,
ModifyIndex: 200,
}
restore, err := state.Restore()
must.NoError(t, err)
err = restore.SchedulerConfigRestore(schedConfig)
must.NoError(t, err)
must.NoError(t, restore.Commit())
modIndex, out, err := state.SchedulerConfig()
must.NoError(t, err)
must.Eq(t, schedConfig.ModifyIndex, modIndex)
must.Eq(t, schedConfig, out)
}
func TestStateStore_ServiceRegistrationRestore(t *testing.T) {
ci.Parallel(t)
testState := testStateStore(t)
// Set up our test registrations and index.
expectedIndex := uint64(13)
serviceRegs := mock.ServiceRegistrations()
restore, err := testState.Restore()
must.NoError(t, err)
// Iterate the service registrations, restore, and commit. Set the indexes
// on the objects, so we can check these.
for i := range serviceRegs {
serviceRegs[i].ModifyIndex = expectedIndex
serviceRegs[i].CreateIndex = expectedIndex
must.NoError(t, restore.ServiceRegistrationRestore(serviceRegs[i]))
}
must.NoError(t, restore.Commit())
// Check the state is now populated as we expect and that we can find the
// restored registrations.
ws := memdb.NewWatchSet()
for i := range serviceRegs {
out, err := testState.GetServiceRegistrationByID(ws, serviceRegs[i].Namespace, serviceRegs[i].ID)
must.NoError(t, err)
must.Eq(t, serviceRegs[i], out)
}
}
func TestStateStore_VariablesRestore(t *testing.T) {
ci.Parallel(t)
testState := testStateStore(t)
// Set up our test variables and index.
expectedIndex := uint64(13)
svs := mock.VariablesEncrypted(5, 5)
restore, err := testState.Restore()
must.NoError(t, err)
// Iterate the variables, restore, and commit. Set the indexes
// on the objects, so we can check these.
for i := range svs {
svs[i].ModifyIndex = expectedIndex
svs[i].CreateIndex = expectedIndex
must.NoError(t, restore.VariablesRestore(svs[i]))
}
must.NoError(t, restore.Commit())
// Check the state is now populated as we expect and that we can find the
// restored variables.
ws := memdb.NewWatchSet()
for i := range svs {
out, err := testState.GetVariable(ws, svs[i].Namespace, svs[i].Path)
must.NoError(t, err)
must.Eq(t, svs[i], out)
}
}
func TestStateStore_ACLRoleRestore(t *testing.T) {
ci.Parallel(t)
testState := testStateStore(t)
// Set up our test registrations and index.
expectedIndex := uint64(13)
aclRole := mock.ACLRole()
aclRole.CreateIndex = expectedIndex
aclRole.ModifyIndex = expectedIndex
restore, err := testState.Restore()
must.NoError(t, err)
must.NoError(t, restore.ACLRoleRestore(aclRole))
must.NoError(t, restore.Commit())
// Check the state is now populated as we expect and that we can find the
// restored registrations.
ws := memdb.NewWatchSet()
out, err := testState.GetACLRoleByName(ws, aclRole.Name)
must.NoError(t, err)
must.Eq(t, aclRole, out)
}
func TestStateStore_ACLAuthMethodRestore(t *testing.T) {
ci.Parallel(t)
testState := testStateStore(t)
// Set up our test registrations and index.
expectedIndex := uint64(13)
authMethod := mock.ACLOIDCAuthMethod()
authMethod.CreateIndex = expectedIndex
authMethod.ModifyIndex = expectedIndex
restore, err := testState.Restore()
must.NoError(t, err)
must.NoError(t, restore.ACLAuthMethodRestore(authMethod))
must.NoError(t, restore.Commit())
// Check the state is now populated as we expect and that we can find the
// restored registrations.
ws := memdb.NewWatchSet()
out, err := testState.GetACLAuthMethodByName(ws, authMethod.Name)
must.NoError(t, err)
must.Eq(t, authMethod, out)
}
func TestStateStore_ACLBindingRuleRestore(t *testing.T) {
ci.Parallel(t)
testState := testStateStore(t)
// Set up our test ACL binding rule and index.
expectedIndex := uint64(13)
aclBindingRule := mock.ACLBindingRule()
aclBindingRule.CreateIndex = expectedIndex
aclBindingRule.ModifyIndex = expectedIndex
restore, err := testState.Restore()
must.NoError(t, err)
must.NoError(t, restore.ACLBindingRuleRestore(aclBindingRule))
must.NoError(t, restore.Commit())
// Check the state is now populated as we expect and that we can find the
// restored ACL binding rule.
ws := memdb.NewWatchSet()
out, err := testState.GetACLBindingRule(ws, aclBindingRule.ID)
must.NoError(t, err)
must.Eq(t, aclBindingRule, out)
}