All checks were successful
continuous-integration/drone/push Build is passing
This implements proper modifier support in the env file using this new fork of the godotenv library. The modifier implementation is quite basic for but can be improved later if needed. See this commit for the actual implementation. Because we are now using proper modifer parsing, it does not affect the parsing of value, so this is possible again: ``` MY_VAR="#foo" ``` Closes coop-cloud/organising#535
159 lines
4.0 KiB
Go
159 lines
4.0 KiB
Go
package compose
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"coopcloud.tech/abra/pkg/config"
|
|
"coopcloud.tech/abra/pkg/formatter"
|
|
"coopcloud.tech/abra/pkg/upstream/stack"
|
|
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
|
composetypes "github.com/docker/cli/cli/compose/types"
|
|
"github.com/docker/distribution/reference"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// UpdateTag updates an image tag in-place on file system local compose files.
|
|
func UpdateTag(pattern, image, tag, recipeName string) (bool, error) {
|
|
composeFiles, err := filepath.Glob(pattern)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
logrus.Debugf("considering %s config(s) for tag update", strings.Join(composeFiles, ", "))
|
|
|
|
for _, composeFile := range composeFiles {
|
|
opts := stack.Deploy{Composefiles: []string{composeFile}}
|
|
|
|
envSamplePath := path.Join(config.RECIPES_DIR, recipeName, ".env.sample")
|
|
sampleEnv, err := config.ReadEnv(envSamplePath)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
compose, err := loader.LoadComposefile(opts, sampleEnv)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
for _, service := range compose.Services {
|
|
if service.Image == "" {
|
|
continue // may be a compose.$optional.yml file
|
|
}
|
|
|
|
img, _ := reference.ParseNormalizedNamed(service.Image)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
var composeTag string
|
|
switch img.(type) {
|
|
case reference.NamedTagged:
|
|
composeTag = img.(reference.NamedTagged).Tag()
|
|
default:
|
|
logrus.Debugf("unable to parse %s, skipping", img)
|
|
continue
|
|
}
|
|
|
|
composeImage := formatter.StripTagMeta(reference.Path(img))
|
|
|
|
logrus.Debugf("parsed %s from %s", composeTag, service.Image)
|
|
|
|
if image == composeImage {
|
|
bytes, err := ioutil.ReadFile(composeFile)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
old := fmt.Sprintf("%s:%s", composeImage, composeTag)
|
|
new := fmt.Sprintf("%s:%s", composeImage, tag)
|
|
replacedBytes := strings.Replace(string(bytes), old, new, -1)
|
|
|
|
logrus.Debugf("updating %s to %s in %s", old, new, compose.Filename)
|
|
|
|
if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0764); err != nil {
|
|
return false, err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
// UpdateLabel updates a label in-place on file system local compose files.
|
|
func UpdateLabel(pattern, serviceName, label, recipeName string) error {
|
|
composeFiles, err := filepath.Glob(pattern)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
logrus.Debugf("considering %s config(s) for label update", strings.Join(composeFiles, ", "))
|
|
|
|
for _, composeFile := range composeFiles {
|
|
opts := stack.Deploy{Composefiles: []string{composeFile}}
|
|
|
|
envSamplePath := path.Join(config.RECIPES_DIR, recipeName, ".env.sample")
|
|
sampleEnv, err := config.ReadEnv(envSamplePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
compose, err := loader.LoadComposefile(opts, sampleEnv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
serviceExists := false
|
|
var service composetypes.ServiceConfig
|
|
for _, s := range compose.Services {
|
|
if s.Name == serviceName {
|
|
service = s
|
|
serviceExists = true
|
|
}
|
|
}
|
|
|
|
if !serviceExists {
|
|
continue
|
|
}
|
|
|
|
discovered := false
|
|
for oldLabel, value := range service.Deploy.Labels {
|
|
if strings.HasPrefix(oldLabel, "coop-cloud") && strings.Contains(oldLabel, "version") {
|
|
discovered = true
|
|
|
|
bytes, err := ioutil.ReadFile(composeFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
old := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", value)
|
|
replacedBytes := strings.Replace(string(bytes), old, label, -1)
|
|
|
|
if old == label {
|
|
logrus.Warnf("%s is already set, nothing to do?", label)
|
|
return nil
|
|
}
|
|
|
|
logrus.Debugf("updating %s to %s in %s", old, label, compose.Filename)
|
|
|
|
if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0764); err != nil {
|
|
return err
|
|
}
|
|
|
|
logrus.Infof("synced label %s to service %s", label, serviceName)
|
|
}
|
|
}
|
|
|
|
if !discovered {
|
|
logrus.Warn("no existing label found, automagic insertion not supported yet")
|
|
logrus.Fatalf("add '- \"%s\"' manually to the 'app' service in %s", label, composeFile)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|