Skip to content
This repository was archived by the owner on Mar 22, 2022. It is now read-only.

Commit f8dd351

Browse files
gloursndeloof
authored andcommitted
Move Volume functions to a dedicated file into internal directory
Signed-off-by: Guillaume Lours <[email protected]>
1 parent 0c59f0e commit f8dd351

File tree

2 files changed

+167
-147
lines changed

2 files changed

+167
-147
lines changed

internal/volume.go

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package internal
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"path/filepath"
7+
"strings"
8+
9+
compose "github.com/compose-spec/compose-go/types"
10+
"github.com/docker/docker/api/types"
11+
"github.com/docker/docker/api/types/filters"
12+
"github.com/docker/docker/api/types/mount"
13+
"github.com/docker/docker/api/types/volume"
14+
"github.com/docker/docker/client"
15+
"github.com/docker/docker/errdefs"
16+
)
17+
18+
func GetVolumesFromConfig(cli *client.Client, project string, config *compose.Config) error {
19+
for defaultVolumeName, volumeConfig := range config.Volumes {
20+
err := CreateVolume(cli, project, defaultVolumeName, volumeConfig)
21+
if err != nil {
22+
return err
23+
}
24+
}
25+
return nil
26+
}
27+
28+
func CreateVolume(cli *client.Client, project string, volumeDefaultName string, volumeConfig compose.VolumeConfig) error {
29+
name := volumeDefaultName
30+
if volumeConfig.Name != "" {
31+
name = volumeConfig.Name
32+
}
33+
volumeID := fmt.Sprintf("%s_%s", strings.Trim(project, "-_"), name)
34+
35+
ctx := context.Background()
36+
37+
// If volume already exists, return here
38+
if volumeConfig.External.Name != "" {
39+
fmt.Printf("Volume %s declared as external. No new volume will be created.\n", name)
40+
}
41+
_, err := cli.VolumeInspect(ctx, volumeID)
42+
if err == nil {
43+
return nil
44+
}
45+
if !errdefs.IsNotFound(err) {
46+
return err
47+
}
48+
49+
// If volume is marked as external but doesn't already exist then return an error
50+
if volumeConfig.External.Name != "" {
51+
return fmt.Errorf("Volume %s declared as external, but could not be found. "+
52+
"Please create the volume manually using `docker volume create --name=%s` and try again.\n", name, name)
53+
}
54+
55+
fmt.Printf("Creating volume %q with %s driver\n", name, volumeConfig.Driver)
56+
_, err = cli.VolumeCreate(ctx, volume.VolumeCreateBody{
57+
Name: volumeID,
58+
Driver: volumeConfig.Driver,
59+
DriverOpts: volumeConfig.DriverOpts,
60+
Labels: map[string]string{
61+
LabelProject: project,
62+
LabelVolume: name,
63+
},
64+
})
65+
66+
return err
67+
}
68+
69+
func RemoveVolumes(cli *client.Client, project string) error {
70+
volumes, err := collectVolumes(cli, project)
71+
if err != nil {
72+
return err
73+
}
74+
for volumeName, volume := range volumes {
75+
err = destroyVolume(cli, volume, volumeName)
76+
if err != nil {
77+
return err
78+
}
79+
}
80+
return nil
81+
}
82+
83+
func destroyVolume(cli *client.Client, volume []types.Volume, volumeName string) error {
84+
ctx := context.Background()
85+
for _, v := range volume {
86+
fmt.Printf("Deleting volume %s ... ", volumeName)
87+
err := cli.VolumeRemove(ctx, v.Name, false)
88+
if err != nil {
89+
return err
90+
}
91+
fmt.Println(v.Name)
92+
}
93+
return nil
94+
}
95+
96+
func collectVolumes(cli *client.Client, project string) (map[string][]types.Volume, error) {
97+
filter := filters.NewArgs(filters.Arg("label", LabelProject+"="+project))
98+
list, err := cli.VolumeList(context.Background(), filter)
99+
if err != nil {
100+
return nil, err
101+
}
102+
volumes := map[string][]types.Volume{}
103+
for _, v := range list.Volumes {
104+
resource := v.Labels[LabelVolume]
105+
l, ok := volumes[resource]
106+
if !ok {
107+
l = []types.Volume{*v}
108+
} else {
109+
l = append(l, *v)
110+
}
111+
volumes[resource] = l
112+
}
113+
return volumes, nil
114+
}
115+
116+
func CreateContainerMounts(s compose.ServiceConfig, prjDir string) ([]mount.Mount, error) {
117+
var mounts []mount.Mount
118+
for _, v := range s.Volumes {
119+
source := v.Source
120+
if !filepath.IsAbs(source) {
121+
source = filepath.Join(prjDir, source)
122+
}
123+
mounts = append(mounts, mount.Mount{
124+
Type: mount.Type(v.Type),
125+
Source: source,
126+
Target: v.Target,
127+
ReadOnly: v.ReadOnly,
128+
Consistency: mount.Consistency(v.Consistency),
129+
BindOptions: buildBindOption(v.Bind),
130+
VolumeOptions: buildVolumeOptions(v.Volume),
131+
TmpfsOptions: buildTmpfsOptions(v.Tmpfs),
132+
})
133+
}
134+
return mounts, nil
135+
}
136+
137+
func buildBindOption(bind *compose.ServiceVolumeBind) *mount.BindOptions {
138+
if bind == nil {
139+
return nil
140+
}
141+
return &mount.BindOptions{
142+
Propagation: mount.Propagation(bind.Propagation),
143+
}
144+
}
145+
146+
func buildVolumeOptions(vol *compose.ServiceVolumeVolume) *mount.VolumeOptions {
147+
if vol == nil {
148+
return nil
149+
}
150+
return &mount.VolumeOptions{
151+
NoCopy: vol.NoCopy,
152+
}
153+
}
154+
155+
func buildTmpfsOptions(tmpfs *compose.ServiceVolumeTmpfs) *mount.TmpfsOptions {
156+
if tmpfs == nil {
157+
return nil
158+
}
159+
return &mount.TmpfsOptions{
160+
SizeBytes: tmpfs.Size,
161+
}
162+
}

main.go

Lines changed: 5 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,16 @@ import (
77
"log"
88
"os"
99
"path/filepath"
10-
"strings"
1110

1211
"github.com/compose-spec/compose-ref/internal"
1312
"github.com/docker/docker/api/types/filters"
14-
"github.com/docker/docker/api/types/mount"
15-
"github.com/docker/docker/errdefs"
1613
"gopkg.in/yaml.v2"
1714

1815
"github.com/compose-spec/compose-go/loader"
1916
compose "github.com/compose-spec/compose-go/types"
2017
"github.com/docker/docker/api/types"
2118
"github.com/docker/docker/api/types/container"
2219
"github.com/docker/docker/api/types/strslice"
23-
"github.com/docker/docker/api/types/volume"
2420
"github.com/docker/docker/client"
2521
"github.com/docker/go-units"
2622
commandLine "github.com/urfave/cli/v2"
@@ -128,11 +124,9 @@ func doUp(project string, config *compose.Config) error {
128124
return err
129125
}
130126

131-
for defaultVolumeName, volumeConfig := range config.Volumes {
132-
err = createVolume(cli, project, defaultVolumeName, volumeConfig)
133-
if err != nil {
134-
return err
135-
}
127+
err = internal.GetVolumesFromConfig(cli, project, config)
128+
if err != nil {
129+
return err
136130
}
137131

138132
observedState, err := collectContainers(cli, project)
@@ -242,7 +236,7 @@ func createService(cli *client.Client, project string, prjDir string, s compose.
242236

243237
fmt.Printf("Creating container for service %s ... ", s.Name)
244238
networkMode := internal.NetworkMode(s, networks)
245-
mounts, err := createContainerMounts(s, prjDir)
239+
mounts, err := internal.CreateContainerMounts(s, prjDir)
246240
if err != nil {
247241
return err
248242
}
@@ -302,95 +296,6 @@ func createService(cli *client.Client, project string, prjDir string, s compose.
302296
return nil
303297
}
304298

305-
func createVolume(cli *client.Client, project string, volumeDefaultName string, volumeConfig compose.VolumeConfig) error {
306-
name := volumeDefaultName
307-
if volumeConfig.Name != "" {
308-
name = volumeConfig.Name
309-
}
310-
volumeID := fmt.Sprintf("%s_%s", strings.Trim(project, "-_"), name)
311-
312-
ctx := context.Background()
313-
314-
// If volume already exists, return here
315-
if volumeConfig.External.Name != "" {
316-
fmt.Printf("Volume %s declared as external. No new volume will be created.\n", name)
317-
}
318-
_, err := cli.VolumeInspect(ctx, volumeID)
319-
if err == nil {
320-
return nil
321-
}
322-
if !errdefs.IsNotFound(err) {
323-
return err
324-
}
325-
326-
// If volume is marked as external but doesn't already exist then return an error
327-
if volumeConfig.External.Name != "" {
328-
return fmt.Errorf("Volume %s declared as external, but could not be found. "+
329-
"Please create the volume manually using `docker volume create --name=%s` and try again.\n", name, name)
330-
}
331-
332-
fmt.Printf("Creating volume %q with %s driver\n", name, volumeConfig.Driver)
333-
_, err = cli.VolumeCreate(ctx, volume.VolumeCreateBody{
334-
Name: volumeID,
335-
Driver: volumeConfig.Driver,
336-
DriverOpts: volumeConfig.DriverOpts,
337-
Labels: map[string]string{
338-
internal.LabelProject: project,
339-
internal.LabelVolume: name,
340-
},
341-
})
342-
343-
return err
344-
}
345-
346-
func createContainerMounts(s compose.ServiceConfig, prjDir string) ([]mount.Mount, error) {
347-
var mounts []mount.Mount
348-
for _, v := range s.Volumes {
349-
source := v.Source
350-
if !filepath.IsAbs(source) {
351-
source = filepath.Join(prjDir, source)
352-
}
353-
mounts = append(mounts, mount.Mount{
354-
Type: mount.Type(v.Type),
355-
Source: source,
356-
Target: v.Target,
357-
ReadOnly: v.ReadOnly,
358-
Consistency: mount.Consistency(v.Consistency),
359-
BindOptions: buildBindOption(v.Bind),
360-
VolumeOptions: buildVolumeOptions(v.Volume),
361-
TmpfsOptions: buildTmpfsOptions(v.Tmpfs),
362-
})
363-
}
364-
return mounts, nil
365-
}
366-
367-
func buildBindOption(bind *compose.ServiceVolumeBind) *mount.BindOptions {
368-
if bind == nil {
369-
return nil
370-
}
371-
return &mount.BindOptions{
372-
Propagation: mount.Propagation(bind.Propagation),
373-
}
374-
}
375-
376-
func buildVolumeOptions(vol *compose.ServiceVolumeVolume) *mount.VolumeOptions {
377-
if vol == nil {
378-
return nil
379-
}
380-
return &mount.VolumeOptions{
381-
NoCopy: vol.NoCopy,
382-
}
383-
}
384-
385-
func buildTmpfsOptions(tmpfs *compose.ServiceVolumeTmpfs) *mount.TmpfsOptions {
386-
if tmpfs == nil {
387-
return nil
388-
}
389-
return &mount.TmpfsOptions{
390-
SizeBytes: tmpfs.Size,
391-
}
392-
}
393-
394299
func collectContainers(cli *client.Client, project string) (map[string][]types.Container, error) {
395300
containerList, err := cli.ContainerList(context.Background(), types.ContainerListOptions{
396301
All: true,
@@ -413,26 +318,6 @@ func collectContainers(cli *client.Client, project string) (map[string][]types.C
413318
return containers, nil
414319
}
415320

416-
func collectVolumes(cli *client.Client, project string) (map[string][]types.Volume, error) {
417-
filter := filters.NewArgs(filters.Arg("label", internal.LabelProject+"="+project))
418-
list, err := cli.VolumeList(context.Background(), filter)
419-
if err != nil {
420-
return nil, err
421-
}
422-
volumes := map[string][]types.Volume{}
423-
for _, v := range list.Volumes {
424-
resource := v.Labels[internal.LabelVolume]
425-
l, ok := volumes[resource]
426-
if !ok {
427-
l = []types.Volume{*v}
428-
} else {
429-
l = append(l, *v)
430-
}
431-
volumes[resource] = l
432-
}
433-
return volumes, nil
434-
}
435-
436321
func doDown(project string, config *compose.Config) error {
437322
cli, err := getClient()
438323
if err != nil {
@@ -442,7 +327,7 @@ func doDown(project string, config *compose.Config) error {
442327
if err != nil {
443328
return err
444329
}
445-
err = destroyVolumes(cli, project)
330+
err = internal.RemoveVolumes(cli, project)
446331
if err != nil {
447332
return err
448333
}
@@ -468,33 +353,6 @@ func removeServices(cli *client.Client, project string) error {
468353
return nil
469354
}
470355

471-
func destroyVolumes(cli *client.Client, project string) error {
472-
volumes, err := collectVolumes(cli, project)
473-
if err != nil {
474-
return err
475-
}
476-
for volumeName, volume := range volumes {
477-
err = destroyVolume(cli, volume, volumeName)
478-
if err != nil {
479-
return err
480-
}
481-
}
482-
return nil
483-
}
484-
485-
func destroyVolume(cli *client.Client, volume []types.Volume, volumeName string) error {
486-
ctx := context.Background()
487-
for _, v := range volume {
488-
fmt.Printf("Deleting volume %s ... ", volumeName)
489-
err := cli.VolumeRemove(ctx, v.Name, false)
490-
if err != nil {
491-
return err
492-
}
493-
fmt.Println(v.Name)
494-
}
495-
return nil
496-
}
497-
498356
func load(file string) (*compose.Config, error) {
499357
b, err := ioutil.ReadFile(file)
500358
if err != nil {

0 commit comments

Comments
 (0)