diff --git a/go.mod b/go.mod index f025ca9..b4a3473 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/meltred/meltcd -go 1.21.0 +go 1.21 require ( github.com/docker/docker v24.0.7+incompatible diff --git a/internal/core/application/app.go b/internal/core/application/app.go index 8c0d59b..f1e1a88 100644 --- a/internal/core/application/app.go +++ b/internal/core/application/app.go @@ -237,7 +237,7 @@ func (app *Application) Apply(targetState string) error { for volName, volOpts := range swarmSpec.Volumes { labels := make(map[string]string) for _, l := range volOpts.Labels { - tokens := strings.Split(l, "=") + tokens := strings.SplitN(l, "=", 2) if len(tokens) != 2 { return errors.New("invalid labels in volume") } @@ -253,7 +253,12 @@ func (app *Application) Apply(targetState string) error { }) } - services, err := swarmSpec.GetServiceSpec(app.Name) + networkId, err := createNetwork(cli, app.Name) + if err != nil { + return err + } + + services, err := swarmSpec.GetServiceSpec(app.Name, networkId) if err != nil { return err } @@ -282,6 +287,7 @@ func (app *Application) Apply(targetState string) error { app.LastSyncedAt = time.Now() continue } + log.Info("Creating new service") res, err := cli.ServiceCreate(context.Background(), service, types.ServiceCreateOptions{}) if err != nil { @@ -317,3 +323,40 @@ func checkServiceAlreadyExist(serviceName string, allServices *[]swarm.Service) } return swarm.Service{}, false } + +func createNetwork(cli *client.Client, appName string) (string, error) { + log.Info("Creating network") + networkName := appName + "_default" + + nets, err := cli.NetworkList(context.Background(), types.NetworkListOptions{}) + if err != nil { + return "", err + } + + for _, network := range nets { + if network.Name == networkName { + log.Info("Network already exists") + return network.ID, nil + } + } + + net, err := cli.NetworkCreate(context.Background(), networkName, types.NetworkCreate{ + Scope: "swarm", + Labels: map[string]string{ + "com.docker.stack.namespace": appName, + }, + Driver: "overlay", + }) + + log.Info("Created network", "id", net.ID) + + if err != nil { + return "", err + } + + if net.Warning != "" { + log.Warn(net.Warning) + } + + return net.ID, nil +} diff --git a/internal/core/registry.go b/internal/core/registry.go index 0ca2a6b..eea9757 100644 --- a/internal/core/registry.go +++ b/internal/core/registry.go @@ -20,7 +20,6 @@ import ( "context" "encoding/json" "fmt" - "strings" "time" "github.com/docker/docker/api/types" @@ -176,11 +175,27 @@ func RemoveApplication(appName string) error { return err } + // set (unique) of network to remove + networksToRemove := map[string]bool{} + for _, svc := range runningService { - if strings.HasPrefix(svc.Spec.Name, appName) { + name := svc.Spec.Labels["com.docker.stack.namespace"] + + if name == appName { if err := cli.ServiceRemove(context.Background(), svc.ID); err != nil { return err } + + for _, nets := range svc.Spec.TaskTemplate.Networks { + // nets.Target is the network ID + networksToRemove[nets.Target] = true + } + } + } + + for networkID := range networksToRemove { + if err := cli.NetworkRemove(context.Background(), networkID); err != nil { + return err } } diff --git a/spec/dockerSwarm.go b/spec/dockerSwarm.go index 7d8e638..f27dca7 100644 --- a/spec/dockerSwarm.go +++ b/spec/dockerSwarm.go @@ -68,7 +68,7 @@ type Volume struct { Options map[string]string `yaml:"options"` } -func (d *DockerSwarm) GetServiceSpec(appName string) ([]swarm.ServiceSpec, error) { +func (d *DockerSwarm) GetServiceSpec(appName string, networkID string) ([]swarm.ServiceSpec, error) { log.Info("Getting service spec for app", "app name", appName) specs := make([]swarm.ServiceSpec, 0) @@ -91,9 +91,20 @@ func (d *DockerSwarm) GetServiceSpec(appName string) ([]swarm.ServiceSpec, error targetSpec.TaskTemplate = swarm.TaskSpec{ ContainerSpec: &swarm.ContainerSpec{ Image: spec.Image, + Labels: map[string]string{ + "com.docker.stack.namespace": appName, + }, }, } + // Connection the service with the network + targetSpec.TaskTemplate.Networks = append(targetSpec.TaskTemplate.Networks, swarm.NetworkAttachmentConfig{ + Target: networkID, + Aliases: []string{ + serviceName, + }, + }) + for _, envFile := range spec.EnvFile { log.Info("Using environment variable from files", "file", envFile)