2023-04-10 15:36:59 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2020-04-30 13:13:00 +00:00
|
|
|
package volumewatcher
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
|
2022-03-15 12:42:43 +00:00
|
|
|
"github.com/hashicorp/nomad/ci"
|
2020-04-30 13:13:00 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/testlog"
|
|
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
|
|
|
"github.com/hashicorp/nomad/nomad/state"
|
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
2020-08-06 18:31:18 +00:00
|
|
|
func TestVolumeWatch_Reap(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2020-04-30 13:13:00 +00:00
|
|
|
require := require.New(t)
|
|
|
|
|
2020-08-06 18:31:18 +00:00
|
|
|
srv := &MockRPCServer{
|
|
|
|
state: state.TestStateStore(t),
|
2020-04-30 13:13:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
plugin := mock.CSIPlugin()
|
2020-08-06 18:31:18 +00:00
|
|
|
node := testNode(plugin, srv.State())
|
2020-04-30 13:13:00 +00:00
|
|
|
alloc := mock.Alloc()
|
2020-08-06 18:31:18 +00:00
|
|
|
alloc.NodeID = node.ID
|
2020-04-30 13:13:00 +00:00
|
|
|
alloc.ClientStatus = structs.AllocClientStatusComplete
|
2020-08-06 18:31:18 +00:00
|
|
|
vol := testVolume(plugin, alloc, node.ID)
|
|
|
|
vol.PastClaims = vol.ReadClaims
|
2020-04-30 13:13:00 +00:00
|
|
|
|
2020-08-06 18:31:18 +00:00
|
|
|
ctx, exitFn := context.WithCancel(context.Background())
|
2020-04-30 13:13:00 +00:00
|
|
|
w := &volumeWatcher{
|
2020-08-06 18:31:18 +00:00
|
|
|
v: vol,
|
|
|
|
rpc: srv,
|
|
|
|
state: srv.State(),
|
|
|
|
ctx: ctx,
|
|
|
|
exitFn: exitFn,
|
|
|
|
logger: testlog.HCLogger(t),
|
2020-04-30 13:13:00 +00:00
|
|
|
}
|
|
|
|
|
2022-01-27 15:39:08 +00:00
|
|
|
vol, _ = srv.State().CSIVolumeDenormalize(nil, vol.Copy())
|
2020-04-30 13:13:00 +00:00
|
|
|
err := w.volumeReapImpl(vol)
|
2020-08-06 18:31:18 +00:00
|
|
|
require.NoError(err)
|
2020-04-30 13:13:00 +00:00
|
|
|
|
2020-08-06 18:31:18 +00:00
|
|
|
// past claim from a previous pass
|
|
|
|
vol.PastClaims = map[string]*structs.CSIVolumeClaim{
|
|
|
|
alloc.ID: {
|
|
|
|
NodeID: node.ID,
|
2020-11-11 18:06:30 +00:00
|
|
|
Mode: structs.CSIVolumeClaimRead,
|
2020-08-06 18:31:18 +00:00
|
|
|
State: structs.CSIVolumeClaimStateNodeDetached,
|
|
|
|
},
|
|
|
|
}
|
2022-01-27 15:39:08 +00:00
|
|
|
vol, _ = srv.State().CSIVolumeDenormalize(nil, vol.Copy())
|
2020-04-30 13:13:00 +00:00
|
|
|
err = w.volumeReapImpl(vol)
|
2020-08-06 18:31:18 +00:00
|
|
|
require.NoError(err)
|
|
|
|
require.Len(vol.PastClaims, 1)
|
2020-04-30 13:13:00 +00:00
|
|
|
|
2020-08-06 18:31:18 +00:00
|
|
|
// claim emitted by a GC event
|
|
|
|
vol.PastClaims = map[string]*structs.CSIVolumeClaim{
|
|
|
|
"": {
|
|
|
|
NodeID: node.ID,
|
2020-11-11 18:06:30 +00:00
|
|
|
Mode: structs.CSIVolumeClaimGC,
|
2020-08-06 18:31:18 +00:00
|
|
|
},
|
|
|
|
}
|
2022-01-27 15:39:08 +00:00
|
|
|
vol, _ = srv.State().CSIVolumeDenormalize(nil, vol.Copy())
|
2020-08-06 18:31:18 +00:00
|
|
|
err = w.volumeReapImpl(vol)
|
|
|
|
require.NoError(err)
|
|
|
|
require.Len(vol.PastClaims, 2) // alloc claim + GC claim
|
|
|
|
|
|
|
|
// release claims of a previously GC'd allocation
|
|
|
|
vol.ReadAllocs[alloc.ID] = nil
|
|
|
|
vol.PastClaims = map[string]*structs.CSIVolumeClaim{
|
|
|
|
"": {
|
|
|
|
NodeID: node.ID,
|
2020-11-11 18:06:30 +00:00
|
|
|
Mode: structs.CSIVolumeClaimRead,
|
2020-08-06 18:31:18 +00:00
|
|
|
},
|
|
|
|
}
|
2022-01-27 15:39:08 +00:00
|
|
|
vol, _ = srv.State().CSIVolumeDenormalize(nil, vol.Copy())
|
2020-04-30 13:13:00 +00:00
|
|
|
err = w.volumeReapImpl(vol)
|
|
|
|
require.NoError(err)
|
2020-08-06 18:31:18 +00:00
|
|
|
require.Len(vol.PastClaims, 2) // alloc claim + GC claim
|
2020-04-30 13:13:00 +00:00
|
|
|
}
|
2022-01-27 14:30:03 +00:00
|
|
|
|
|
|
|
func TestVolumeReapBadState(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2022-01-27 14:30:03 +00:00
|
|
|
|
|
|
|
store := state.TestStateStore(t)
|
|
|
|
err := state.TestBadCSIState(t, store)
|
|
|
|
require.NoError(t, err)
|
|
|
|
srv := &MockRPCServer{
|
|
|
|
state: store,
|
|
|
|
}
|
|
|
|
|
|
|
|
vol, err := srv.state.CSIVolumeByID(nil,
|
|
|
|
structs.DefaultNamespace, "csi-volume-nfs0")
|
|
|
|
require.NoError(t, err)
|
|
|
|
srv.state.CSIVolumeDenormalize(nil, vol)
|
|
|
|
|
|
|
|
ctx, exitFn := context.WithCancel(context.Background())
|
|
|
|
w := &volumeWatcher{
|
|
|
|
v: vol,
|
|
|
|
rpc: srv,
|
|
|
|
state: srv.State(),
|
|
|
|
ctx: ctx,
|
|
|
|
exitFn: exitFn,
|
|
|
|
logger: testlog.HCLogger(t),
|
|
|
|
}
|
|
|
|
|
|
|
|
err = w.volumeReapImpl(vol)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, srv.countCSIUnpublish)
|
|
|
|
}
|