github.com/vshn/k8ify@v1.1.2-0.20240502214202-6c9ed3ef0bf4/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"time"
     7  
     8  	composeLoader "github.com/compose-spec/compose-go/loader"
     9  	composeTypes "github.com/compose-spec/compose-go/types"
    10  	"github.com/joho/godotenv"
    11  	"github.com/sirupsen/logrus"
    12  	"github.com/spf13/pflag"
    13  	"github.com/vshn/k8ify/internal"
    14  	"github.com/vshn/k8ify/pkg/converter"
    15  	"github.com/vshn/k8ify/pkg/ir"
    16  	"github.com/vshn/k8ify/pkg/provider"
    17  	"github.com/vshn/k8ify/pkg/util"
    18  )
    19  
    20  var (
    21  	defaultConfig = internal.Config{
    22  		OutputDir: "manifests",
    23  		Env:       "dev",
    24  		Ref:       "",
    25  	}
    26  	modifiedImages   internal.ModifiedImagesFlag
    27  	shellEnvFiles    internal.ShellEnvFilesFlag
    28  	pflagInitialized = false
    29  )
    30  
    31  func InitPflag() {
    32  	// Main() may be called multiple times from tests, hence this kludge
    33  	if !pflagInitialized {
    34  		pflag.Var(&modifiedImages, "modified-image", "Image that has been modified during the build. Can be repeated.")
    35  		pflag.Var(&shellEnvFiles, "shell-env-file", "Shell environment file ('key=value' format) to be used in addition to the current shell environment. Can be repeated.")
    36  		pflagInitialized = true
    37  	}
    38  }
    39  
    40  func main() {
    41  	code := Main(os.Args)
    42  	os.Exit(code)
    43  }
    44  
    45  func Main(args []string) int {
    46  	InitPflag()
    47  	err := pflag.CommandLine.Parse(args[1:])
    48  	if err != nil {
    49  		logrus.Error(err)
    50  		return 1
    51  	}
    52  	plainArgs := pflag.Args()
    53  
    54  	config := defaultConfig // this code may run multiple times during testing, thus we can't modify the defaults and must create a copy
    55  	if len(plainArgs) > 0 {
    56  		config.Env = plainArgs[0]
    57  	}
    58  	if len(plainArgs) > 1 {
    59  		config.Ref = plainArgs[1]
    60  	}
    61  
    62  	if config.ConfigFiles == nil || len(config.ConfigFiles) == 0 {
    63  		config.ConfigFiles = []string{"compose.yml", "docker-compose.yml", "compose-" + config.Env + ".yml", "docker-compose-" + config.Env + ".yml"}
    64  	}
    65  
    66  	// Load the additional shell environment files. This will merge everything into the existing shell environment and
    67  	// all values can later be retrieved using os.Environ()
    68  	for _, shellEnvFile := range shellEnvFiles.Values {
    69  		err := godotenv.Load(shellEnvFile)
    70  		if err != nil {
    71  			logrus.Error(err)
    72  			return 1
    73  		}
    74  	}
    75  
    76  	composeConfigFiles := []composeTypes.ConfigFile{}
    77  	for _, configFile := range config.ConfigFiles {
    78  		if _, err := os.Stat(configFile); err == nil {
    79  			composeConfigFiles = append(composeConfigFiles, composeTypes.ConfigFile{
    80  				Filename: configFile,
    81  			})
    82  		}
    83  	}
    84  	env := util.GetEnv()
    85  	if _, ok := env["_ref_"]; ok {
    86  		logrus.Error("The environment variable '_ref_' must not be defined as it is needed for internal purposes")
    87  		return 1
    88  	}
    89  	env["_ref_"] = converter.SecretRefMagic
    90  	configDetails := composeTypes.ConfigDetails{
    91  		ConfigFiles: composeConfigFiles,
    92  		Environment: env,
    93  	}
    94  	project, err := composeLoader.Load(configDetails)
    95  	if err != nil {
    96  		logrus.Error(err)
    97  		return 1
    98  	}
    99  
   100  	inputs := ir.FromCompose(project)
   101  	internal.ComposeServicePrecheck(inputs)
   102  	internal.VolumesPrecheck(inputs)
   103  	internal.DomainLengthPrecheck(inputs)
   104  
   105  	objects := converter.Objects{}
   106  
   107  	for _, service := range inputs.Services {
   108  		objects = objects.Append(converter.ComposeServiceToK8s(config.Ref, service, inputs.Volumes, inputs.TargetCfg))
   109  	}
   110  
   111  	forceRestartAnnotation := make(map[string]string)
   112  	forceRestartAnnotation["k8ify.restart-trigger"] = fmt.Sprintf("%d", time.Now().Unix())
   113  	converter.PatchDeployments(objects.Deployments, modifiedImages.Values, forceRestartAnnotation)
   114  	converter.PatchStatefulSets(objects.StatefulSets, modifiedImages.Values, forceRestartAnnotation)
   115  
   116  	objects = provider.PatchEncryptedVolumeSchemeAppuioCloudscale(inputs.TargetCfg, config, objects)
   117  
   118  	err = internal.WriteManifests(config.OutputDir, objects)
   119  	if err != nil {
   120  		logrus.Error(err)
   121  		return 1
   122  	}
   123  
   124  	return 0
   125  }