feat: auto-provision volumes on all machines for global services (#243)

* feat: auto-provision volumes on all machines for global services

* fix: schedule global service volumes only on machines that need them

* fix: use union of eligible machines for volumes shared by global services

* test: restore global with missing volume fails test

* refactor: simplify volume scheduler by removing redundant check

Move isVolumeSharedBetweenGlobalAndReplicated check earlier to fail
fast, then use isVolumeForGlobalService instead of the now-redundant
isVolumeOnlyForGlobalServices function.
This commit is contained in:
Zasda Yusuf Mikail
2026-02-02 12:30:57 +01:00
committed by GitHub
parent a4a8e70f9c
commit 15d9ceb4d1
4 changed files with 562 additions and 28 deletions
+41
View File
@@ -558,4 +558,45 @@ volumes:
assert.Len(t, plan.Operations, 2, "Expected 1 volume creation and 1 service to deploy")
})
t.Run("global service auto-creates volumes on all machines", func(t *testing.T) {
t.Parallel()
serviceName := "test-compose-global-volume"
volumeName := serviceName
t.Cleanup(func() {
removeServices(t, cli, serviceName)
for _, machine := range c.Machines {
_ = cli.RemoveVolume(ctx, machine.Name, volumeName, false)
}
})
project, err := compose.LoadProject(ctx, []string{"fixtures/compose-global-volume.yaml"})
require.NoError(t, err)
deployment, err := compose.NewDeployment(ctx, cli, project)
require.NoError(t, err)
err = deployment.Run(ctx)
require.NoError(t, err, "Global deployment should auto-create volumes on all machines")
// Verify volumes were created on all machines.
volumes, err := cli.ListVolumes(ctx, &api.VolumeFilter{Names: []string{volumeName}})
require.NoError(t, err)
assert.Len(t, volumes, len(c.Machines), "Volume should be created on all machines")
// Verify containers are running on all machines.
svc, err := cli.InspectService(ctx, serviceName)
require.NoError(t, err)
assert.Equal(t, api.ServiceModeGlobal, svc.Mode)
assert.Len(t, svc.Containers, len(c.Machines), "Container should be running on all machines")
machines := serviceMachines(svc)
expectedMachines := make([]string, len(c.Machines))
for i, m := range c.Machines {
expectedMachines[i] = m.ID
}
assert.ElementsMatch(t, machines.ToSlice(), expectedMachines,
"Containers should be distributed across all machines")
})
}
@@ -0,0 +1,10 @@
services:
test-compose-global-volume:
image: portainer/pause:latest
deploy:
mode: global
volumes:
- test-compose-global-volume:/data
volumes:
test-compose-global-volume: