558 lines
13 KiB
Go
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)
|
|
}
|