Skip to content

Commit 0247324

Browse files
committed
fix: wait for mount status to be proper mode
Wait for the mount status to be read-write if we requested read-write while it is being promoted to read-write from read-only. Fixes #11969 Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
1 parent 825622d commit 0247324

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

internal/app/machined/pkg/automaton/blockautomaton/volume_mount.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ func waitForMountStatus(ctx context.Context, r controller.ReaderWriter, logger *
109109
return nil, xerrors.NewTaggedf[automaton.Continue]("waiting for mount status to be established")
110110
}
111111

112+
if mountStatus.TypedSpec().ReadOnly && !mountContext.options.ReadOnly {
113+
return nil, xerrors.NewTaggedf[automaton.Continue]("volume is mounted read-only, but read-write was requested")
114+
}
115+
112116
if !mountStatus.Metadata().Finalizers().Has(mountContext.requester) {
113117
if err = r.AddFinalizer(ctx, mountStatus.Metadata(), mountContext.requester); err != nil {
114118
return nil, fmt.Errorf("error adding finalizer: %w", err)

internal/app/machined/pkg/automaton/blockautomaton/volume_mount_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,54 @@ func TestVolumeMounter(t *testing.T) {
121121

122122
assert.True(t, finished)
123123
}
124+
125+
func TestVolumeMounterReadWrite(t *testing.T) {
126+
t.Parallel()
127+
128+
logger := zaptest.NewLogger(t)
129+
st := state.WrapCore(namespaced.NewState(inmem.Build))
130+
ctx, cancel := context.WithTimeout(t.Context(), 10*time.Second)
131+
t.Cleanup(cancel)
132+
133+
mountedCh := make(chan struct{})
134+
135+
volumeMounter := blockautomaton.NewVolumeMounter("rw", "volumeID", func(ctx context.Context, rw controller.ReaderWriter, l *zap.Logger, vms *block.VolumeMountStatus) error {
136+
close(mountedCh)
137+
138+
return nil
139+
})
140+
141+
const mountID = "rw-volumeID"
142+
143+
adapter := owned.New(st, "automaton")
144+
145+
// 1st run, should create the volume mount request
146+
require.NoError(t, volumeMounter.Run(ctx, adapter, logger))
147+
148+
rtestutils.AssertResource(ctx, t, st, mountID, func(vmr *block.VolumeMountRequest, asrt *assert.Assertions) {
149+
asrt.Equal("rw", vmr.TypedSpec().Requester)
150+
asrt.Equal("volumeID", vmr.TypedSpec().VolumeID)
151+
asrt.False(vmr.TypedSpec().ReadOnly)
152+
})
153+
154+
require.NoError(t, st.AddFinalizer(ctx, block.NewVolumeMountRequest(block.NamespaceName, mountID).Metadata(), "test"))
155+
156+
vms := block.NewVolumeMountStatus(block.NamespaceName, mountID)
157+
vms.TypedSpec().ReadOnly = true // volume is mounted read-only (from some other request)
158+
require.NoError(t, st.Create(ctx, vms))
159+
160+
// no-op run, as the volume mount status is read-only
161+
require.NoError(t, volumeMounter.Run(ctx, adapter, logger))
162+
163+
vms.TypedSpec().ReadOnly = false // volume is now mounted read-write
164+
require.NoError(t, st.Update(ctx, vms))
165+
166+
// 2nd run, should put a finalizer on the volume mount status and call the callback 1st time, finishing the whole sequence
167+
require.NoError(t, volumeMounter.Run(ctx, adapter, logger))
168+
169+
select {
170+
case <-mountedCh:
171+
case <-ctx.Done():
172+
t.Fatal("timed out waiting for mount status callback")
173+
}
174+
}

0 commit comments

Comments
 (0)