chore(refacto): fix secret and use katenary schema

- add possibility to use a katenary.yaml file to setup values
- fix secret generation
This commit is contained in:
2024-11-18 17:12:12 +01:00
parent 14877fbfa3
commit cc1019b5a8
39 changed files with 375 additions and 155 deletions

View File

@@ -2,7 +2,8 @@ package generator
import (
"fmt"
"katenary/generator/labelStructs"
"katenary/generator/labels"
"katenary/generator/labels/labelStructs"
"katenary/utils"
"log"
"os"
@@ -136,7 +137,7 @@ func (chart *HelmChart) generateConfigMapsAndSecrets(project *types.Project) err
originalEnv[k] = v
}
if v, ok := s.Labels[LabelSecrets]; ok {
if v, ok := s.Labels[labels.LabelSecrets]; ok {
list, err := labelStructs.SecretsFrom(v)
if err != nil {
log.Fatal("error unmarshaling secrets label:", err)
@@ -210,7 +211,8 @@ func (chart *HelmChart) generateDeployment(service types.ServiceConfig, deployme
// get the same-pod label if exists, add it to the list.
// We later will copy some parts to the target deployment and remove this one.
if samePod, ok := service.Labels[LabelSamePod]; ok && samePod != "" {
if samePod, ok := service.Labels[labels.LabelSamePod]; ok && samePod != "" {
log.Printf("Found same-pod label for %s", service.Name)
podToMerge[samePod] = &service
}
@@ -247,7 +249,7 @@ func (chart *HelmChart) setChartVersion(service types.ServiceConfig) {
// setCronJob creates a cronjob from the service labels.
func (chart *HelmChart) setCronJob(service types.ServiceConfig, appName string) *CronJob {
if _, ok := service.Labels[LabelCronJob]; !ok {
if _, ok := service.Labels[labels.LabelCronJob]; !ok {
return nil
}
cronjob, rbac := NewCronJob(service, chart, appName)
@@ -281,7 +283,7 @@ func (chart *HelmChart) setCronJob(service types.ServiceConfig, appName string)
// setDependencies sets the dependencies from the service labels.
func (chart *HelmChart) setDependencies(service types.ServiceConfig) (bool, error) {
// helm dependency
if v, ok := service.Labels[LabelDependencies]; ok {
if v, ok := service.Labels[labels.LabelDependencies]; ok {
d, err := labelStructs.DependenciesFrom(v)
if err != nil {
return false, err
@@ -307,10 +309,10 @@ func (chart *HelmChart) setDependencies(service types.ServiceConfig) (bool, erro
func (chart *HelmChart) setSharedConf(service types.ServiceConfig, deployments map[string]*Deployment) {
// if the service has the "shared-conf" label, we need to add the configmap
// to the chart and add the env vars to the service
if _, ok := service.Labels[LabelEnvFrom]; !ok {
if _, ok := service.Labels[labels.LabelEnvFrom]; !ok {
return
}
fromservices, err := labelStructs.EnvFromFrom(service.Labels[LabelEnvFrom])
fromservices, err := labelStructs.EnvFromFrom(service.Labels[labels.LabelEnvFrom])
if err != nil {
log.Fatal("error unmarshaling env-from label:", err)
}

View File

@@ -1,7 +1,8 @@
package generator
import (
"katenary/generator/labelStructs"
"katenary/generator/labels"
"katenary/generator/labels/labelStructs"
"katenary/utils"
"log"
"os"
@@ -73,7 +74,7 @@ func NewConfigMap(service types.ServiceConfig, appName string, forFile bool) *Co
}
// get the secrets from the labels
secrets, err := labelStructs.SecretsFrom(service.Labels[LabelSecrets])
secrets, err := labelStructs.SecretsFrom(service.Labels[labels.LabelSecrets])
if err != nil {
log.Fatal(err)
}
@@ -82,7 +83,7 @@ func NewConfigMap(service types.ServiceConfig, appName string, forFile bool) *Co
drop[secret] = true
}
// get the label values from the labels
varDescriptons := utils.GetValuesFromLabel(service, LabelValues)
varDescriptons := utils.GetValuesFromLabel(service, labels.LabelValues)
for value := range varDescriptons {
labelValues = append(labelValues, value)
}
@@ -98,7 +99,7 @@ func NewConfigMap(service types.ServiceConfig, appName string, forFile bool) *Co
if !forFile {
// do not bind env variables to the configmap
// remove the variables that are already defined in the environment
if l, ok := service.Labels[LabelMapEnv]; ok {
if l, ok := service.Labels[labels.LabelMapEnv]; ok {
envmap, err := labelStructs.MapEnvFrom(l)
if err != nil {
log.Fatal("Error parsing map-env", err)

View File

@@ -5,7 +5,9 @@ import (
"errors"
"fmt"
"katenary/generator/extrafiles"
"katenary/generator/labelStructs"
"katenary/generator/katenaryfile"
"katenary/generator/labels"
"katenary/generator/labels/labelStructs"
"katenary/parser"
"katenary/utils"
"log"
@@ -125,6 +127,9 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
os.Exit(1)
}
// TODO: use katenary.yaml file here to set the labels
katenaryfile.OverrideWithConfig(project)
if !config.Force {
// check if the chart directory exists
// if yes, prevent the user from overwriting it and ask for confirmation
@@ -264,7 +269,7 @@ func addDependencyDescription(values []byte, dependencies []labelStructs.Depende
// of the service definition.
func addDescriptions(values []byte, project types.Project) []byte {
for _, service := range project.Services {
if description, ok := service.Labels[LabelDescription]; ok {
if description, ok := service.Labels[labels.LabelDescription]; ok {
// set it as comment
description = "\n# " + strings.ReplaceAll(description, "\n", "\n# ")
@@ -288,7 +293,7 @@ func addDescriptions(values []byte, project types.Project) []byte {
func addDocToVariable(service types.ServiceConfig, lines []string) []string {
currentService := ""
variables := utils.GetValuesFromLabel(service, LabelValues)
variables := utils.GetValuesFromLabel(service, labels.LabelValues)
for i, line := range lines {
// if the line is a service, it is a name followed by a colon
if regexp.MustCompile(`(?m)^` + service.Name + `:`).MatchString(line) {
@@ -378,7 +383,7 @@ func addMainTagAppDoc(values []byte, project *types.Project) []byte {
for _, service := range project.Services {
// read the label LabelMainApp
if v, ok := service.Labels[LabelMainApp]; !ok {
if v, ok := service.Labels[labels.LabelMainApp]; !ok {
continue
} else if v == "false" || v == "no" || v == "0" {
continue
@@ -651,7 +656,7 @@ func checkOldLabels(project *types.Project) error {
badServices := make([]string, 0)
for _, service := range project.Services {
for label := range service.Labels {
if strings.Contains(label, "katenary.") && !strings.Contains(label, katenaryLabelPrefix) {
if strings.Contains(label, "katenary.") && !strings.Contains(label, labels.KatenaryLabelPrefix) {
badServices = append(badServices, fmt.Sprintf("- %s: %s", service.Name, label))
}
}
@@ -667,7 +672,7 @@ func checkOldLabels(project *types.Project) error {
Services to upgrade:
%s`,
project.Name,
katenaryLabelPrefix[0:len(katenaryLabelPrefix)-1],
labels.KatenaryLabelPrefix[0:len(labels.KatenaryLabelPrefix)-1],
strings.Join(badServices, "\n"),
)

View File

@@ -1,7 +1,8 @@
package generator
import (
"katenary/generator/labelStructs"
"katenary/generator/labels"
"katenary/generator/labels/labelStructs"
"katenary/utils"
"log"
"strings"
@@ -25,7 +26,7 @@ type CronJob struct {
// NewCronJob creates a new CronJob from a compose service. The appName is the name of the application taken from the project name.
func NewCronJob(service types.ServiceConfig, chart *HelmChart, appName string) (*CronJob, *RBAC) {
labels, ok := service.Labels[LabelCronJob]
labels, ok := service.Labels[labels.LabelCronJob]
if !ok {
return nil, nil
}

View File

@@ -2,7 +2,8 @@ package generator
import (
"fmt"
"katenary/generator/labelStructs"
"katenary/generator/labels"
"katenary/generator/labels/labelStructs"
"katenary/utils"
"log"
"os"
@@ -44,7 +45,7 @@ type Deployment struct {
// It also creates the Values map that will be used to create the values.yaml file.
func NewDeployment(service types.ServiceConfig, chart *HelmChart) *Deployment {
isMainApp := false
if mainLabel, ok := service.Labels[LabelMainApp]; ok {
if mainLabel, ok := service.Labels[labels.LabelMainApp]; ok {
main := strings.ToLower(mainLabel)
isMainApp = main == "true" || main == "yes" || main == "1"
}
@@ -83,7 +84,7 @@ func NewDeployment(service types.ServiceConfig, chart *HelmChart) *Deployment {
},
Spec: corev1.PodSpec{
NodeSelector: map[string]string{
labelName("node-selector"): "replace",
labels.LabelName("node-selector"): "replace",
},
},
},
@@ -154,7 +155,7 @@ func (d *Deployment) AddContainer(service types.ServiceConfig) {
func (d *Deployment) AddHealthCheck(service types.ServiceConfig, container *corev1.Container) {
// get the label for healthcheck
if v, ok := service.Labels[LabelHealthCheck]; ok {
if v, ok := service.Labels[labels.LabelHealthCheck]; ok {
probes, err := labelStructs.ProbeFrom(v)
if err != nil {
log.Fatal(err)
@@ -189,7 +190,7 @@ func (d *Deployment) AddIngress(service types.ServiceConfig, appName string) *In
// If the volume is a bind volume it will warn the user that it is not supported yet.
func (d *Deployment) AddVolumes(service types.ServiceConfig, appName string) {
tobind := map[string]bool{}
if v, ok := service.Labels[LabelConfigMapFiles]; ok {
if v, ok := service.Labels[labels.LabelConfigMapFiles]; ok {
binds, err := labelStructs.ConfigMapFileFrom(v)
if err != nil {
log.Fatal(err)
@@ -200,7 +201,7 @@ func (d *Deployment) AddVolumes(service types.ServiceConfig, appName string) {
}
isSamePod := false
if v, ok := service.Labels[LabelSamePod]; !ok {
if v, ok := service.Labels[labels.LabelSamePod]; !ok {
isSamePod = false
} else {
isSamePod = v != ""
@@ -245,7 +246,12 @@ func (d *Deployment) DependsOn(to *Deployment, servicename string) error {
for _, container := range to.Spec.Template.Spec.Containers {
commands := []string{}
if len(container.Ports) == 0 {
utils.Warn("No ports found for service ", servicename, ". You should declare a port in the service or use "+LabelPorts+" label.")
utils.Warn("No ports found for service ",
servicename,
". You should declare a port in the service or use "+
labels.LabelPorts+
" label.",
)
os.Exit(1)
}
for _, port := range container.Ports {
@@ -279,13 +285,13 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string) {
secrets := []string{}
// secrets from label
labelSecrets, err := labelStructs.SecretsFrom(service.Labels[LabelSecrets])
labelSecrets, err := labelStructs.SecretsFrom(service.Labels[labels.LabelSecrets])
if err != nil {
log.Fatal(err)
}
// values from label
varDescriptons := utils.GetValuesFromLabel(service, LabelValues)
varDescriptons := utils.GetValuesFromLabel(service, labels.LabelValues)
labelValues := []string{}
for v := range varDescriptons {
labelValues = append(labelValues, v)
@@ -506,7 +512,7 @@ func (d *Deployment) Yaml() ([]byte, error) {
// find the katenary.v3/node-selector line, and remove it
for i, line := range content {
if strings.Contains(line, labelName("node-selector")) {
if strings.Contains(line, labels.LabelName("node-selector")) {
content = append(content[:i], content[i+1:]...)
continue
}
@@ -582,7 +588,7 @@ func (d *Deployment) bindVolumes(volume types.ServiceVolumeConfig, isSamePod boo
utils.Warn(
"Bind volumes are not supported yet, " +
"excepting for those declared as " +
LabelConfigMapFiles +
labels.LabelConfigMapFiles +
", skipping volume " + volume.Source +
" from service " + service.Name,
)
@@ -612,7 +618,7 @@ func (d *Deployment) bindVolumes(volume types.ServiceVolumeConfig, isSamePod boo
})
// Add volume to values.yaml only if it the service is not in the same pod that another service.
// If it is in the same pod, the volume will be added to the other service later
if _, ok := service.Labels[LabelSamePod]; !ok {
if _, ok := service.Labels[labels.LabelSamePod]; !ok {
d.chart.Values[service.Name].(*Value).AddPersistence(volume.Source)
}
// Add volume to deployment

View File

@@ -2,6 +2,7 @@ package generator
import (
"fmt"
"katenary/generator/labels"
"os"
"testing"
@@ -159,7 +160,7 @@ services:
version: 18.x.X
`
composeFile = fmt.Sprintf(composeFile, Prefix())
composeFile = fmt.Sprintf(composeFile, labels.Prefix())
tmpDir := setup(composeFile)
defer teardown(tmpDir)
@@ -249,7 +250,7 @@ services:
path: /ready
port: 80
`
composeFile = fmt.Sprintf(composeFile, Prefix())
composeFile = fmt.Sprintf(composeFile, labels.Prefix())
tmpDir := setup(composeFile)
defer teardown(tmpDir)
@@ -295,7 +296,7 @@ services:
- FOO
`
composeFile = fmt.Sprintf(composeFile, Prefix())
composeFile = fmt.Sprintf(composeFile, labels.Prefix())
tmpDir := setup(composeFile)
defer teardown(tmpDir)

View File

@@ -3,6 +3,7 @@ package generator
import (
"bytes"
"fmt"
"katenary/generator/labels"
"katenary/utils"
"log"
"regexp"
@@ -39,7 +40,7 @@ func Generate(project *types.Project) (*HelmChart, error) {
if err != nil {
return nil, err
}
Annotations[labelName("compose-hash")] = hash
Annotations[labels.LabelName("compose-hash")] = hash
chart.composeHash = &hash
// find the "main-app" label, and set chart.AppVersion to the tag if exists
@@ -81,14 +82,14 @@ func Generate(project *types.Project) (*HelmChart, error) {
// drop all "same-pod" deployments because the containers and volumes are already
// in the target deployment
for _, service := range podToMerge {
if samepod, ok := service.Labels[LabelSamePod]; ok && samepod != "" {
if samepod, ok := service.Labels[labels.LabelSamePod]; ok && samepod != "" {
// move this deployment volumes to the target deployment
if target, ok := deployments[samepod]; ok {
target.AddContainer(*service)
target.BindFrom(*service, deployments[service.Name])
delete(deployments, service.Name)
} else {
log.Printf("service %[1]s is declared as %[2]s, but %[2]s is not defined", service.Name, LabelSamePod)
log.Printf("service %[1]s is declared as %[2]s, but %[2]s is not defined", service.Name, labels.LabelSamePod)
}
}
}
@@ -163,7 +164,7 @@ func Generate(project *types.Project) (*HelmChart, error) {
// serviceIsMain returns true if the service is the main app.
func serviceIsMain(service types.ServiceConfig) bool {
if main, ok := service.Labels[LabelMainApp]; ok {
if main, ok := service.Labels[labels.LabelMainApp]; ok {
return main == "true" || main == "yes" || main == "1"
}
return false
@@ -276,7 +277,7 @@ func buildVolumes(service types.ServiceConfig, chart *HelmChart, deployments map
// if the service is integrated in another deployment, we need to add the volume
// to the target deployment
if override, ok := service.Labels[LabelSamePod]; ok {
if override, ok := service.Labels[labels.LabelSamePod]; ok {
pvc.nameOverride = override
pvc.Spec.StorageClassName = utils.StrPtr(`{{ .Values.` + override + `.persistence.` + v.Source + `.storageClass }}`)
chart.Values[override].(*Value).AddPersistence(v.Source)
@@ -308,7 +309,7 @@ func samePodVolume(service types.ServiceConfig, v types.ServiceVolumeConfig, dep
}
targetDeployment := ""
if targetName, ok := service.Labels[LabelSamePod]; !ok {
if targetName, ok := service.Labels[labels.LabelSamePod]; !ok {
return false
} else {
targetDeployment = targetName

View File

@@ -1,6 +1,9 @@
package generator
import "regexp"
import (
"katenary/generator/labels"
"regexp"
)
var (
// find all labels starting by __replace_ and ending with ":"
@@ -11,6 +14,6 @@ var (
// Standard annotationss
Annotations = map[string]string{
labelName("version"): Version,
labels.LabelName("version"): Version,
}
)

View File

@@ -2,6 +2,7 @@ package generator
import (
_ "embed"
"katenary/generator/labels"
"strings"
)
@@ -13,7 +14,7 @@ var helmHelper string
// Helper returns the _helpers.tpl file for a chart.
func Helper(name string) string {
helmHelper := strings.ReplaceAll(helmHelper, "__APP__", name)
helmHelper = strings.ReplaceAll(helmHelper, "__PREFIX__", katenaryLabelPrefix)
helmHelper = strings.ReplaceAll(helmHelper, "__PREFIX__", labels.KatenaryLabelPrefix)
helmHelper = strings.ReplaceAll(helmHelper, "__VERSION__", "0.1.0")
return helmHelper
}

View File

@@ -1,7 +1,8 @@
package generator
import (
"katenary/generator/labelStructs"
"katenary/generator/labels"
"katenary/generator/labels/labelStructs"
"katenary/utils"
"log"
"strings"
@@ -27,7 +28,7 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
}
var label string
var ok bool
if label, ok = service.Labels[LabelIngress]; !ok {
if label, ok = service.Labels[labels.LabelIngress]; !ok {
return nil
}

View File

@@ -2,6 +2,7 @@ package generator
import (
"fmt"
"katenary/generator/labels"
"os"
"testing"
@@ -22,7 +23,7 @@ services:
hostname: my.test.tld
port: 80
`
composeFile = fmt.Sprintf(composeFile, katenaryLabelPrefix)
composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix)
tmpDir := setup(composeFile)
defer teardown(tmpDir)

View File

@@ -0,0 +1,10 @@
/*
Package katenaryfile is a package for reading and writing katenary files.
A katenary file, named "katenary.yml" or "katenary.yaml", is a file where you can define the
configuration of the conversion avoiding the use of labels in the compose file.
Formely, the file describe the same structure as in labels, and so that can be validated and
completed by LSP. It also ease the use of katenary.
*/
package katenaryfile

View File

@@ -0,0 +1,142 @@
package katenaryfile
import (
"bytes"
"encoding/json"
"fmt"
"katenary/generator/labels"
"katenary/generator/labels/labelStructs"
"katenary/utils"
"log"
"os"
"reflect"
"strings"
"github.com/compose-spec/compose-go/types"
"github.com/invopop/jsonschema"
"gopkg.in/yaml.v3"
)
var allowedKatenaryYamlFileNames = []string{"katenary.yaml", "katenary.yml"}
// StringOrMap is a struct that can be either a string or a map of strings.
// It's a helper struct to unmarshal the katenary.yaml file and produce the schema
type StringOrMap any
// Service is a struct that contains the service configuration for katenary
type Service struct {
MainApp *bool `json:"main-app,omitempty" jsonschema:"title=Is this service the main application"`
Values []StringOrMap `json:"values,omitempty" jsonschema:"description=Environment variables to be set in values.yaml with or without a description"`
Secrets *labelStructs.Secrets `json:"secrets,omitempty" jsonschema:"title=Secrets,description=Environment variables to be set as secrets"`
Ports *labelStructs.Ports `json:"ports,omitempty" jsonschema:"title=Ports,description=Ports to be exposed in services"`
Ingress *labelStructs.Ingress `json:"ingress,omitempty" jsonschema:"title=Ingress,description=Ingress configuration"`
HealthCheck *labelStructs.HealthCheck `json:"health-check,omitempty" jsonschema:"title=Health Check,description=Health check configuration that respects the kubernetes api"`
SamePod *string `json:"same-pod,omitempty" jsonschema:"title=Same Pod,description=Service that should be in the same pod"`
Description *string `json:"description,omitempty" jsonschema:"title=Description,description=Description of the service that will be injected in the values.yaml file"`
Ignore *bool `json:"ignore,omitempty" jsonschema:"title=Ignore,description=Ignore the service in the conversion"`
Dependencies []labelStructs.Dependency `json:"dependencies,omitempty" jsonschema:"title=Dependencies,description=Services that should be injected in the Chart.yaml file"`
ConfigMapFile *labelStructs.ConfigMapFile `json:"configmap-files,omitempty" jsonschema:"title=ConfigMap Files,description=Files that should be injected as ConfigMap"`
MapEnv *labelStructs.MapEnv `json:"map-env,omitempty" jsonschema:"title=Map Env,description=Map environment variables to another value"`
CronJob *labelStructs.CronJob `json:"cron-job,omitempty" jsonschema:"title=Cron Job,description=Cron Job configuration"`
EnvFrom *labelStructs.EnvFrom `json:"env-from,omitempty" jsonschema:"title=Env From,description=Inject environment variables from another service"`
}
// OverrideWithConfig overrides the project with the katenary.yaml file. It
// will set the labels of the services with the values from the katenary.yaml file.
// It work in memory, so it will not modify the original project.
func OverrideWithConfig(project *types.Project) {
var yamlFile string
var err error
for _, yamlFile = range allowedKatenaryYamlFileNames {
_, err = os.Stat(yamlFile)
if err == nil {
break
}
}
if err != nil {
// no katenary file found
return
}
fmt.Println(utils.IconInfo, "Using katenary file", yamlFile)
services := make(map[string]Service)
fp, err := os.Open(yamlFile)
if err != nil {
return
}
if err := yaml.NewDecoder(fp).Decode(&services); err != nil {
log.Fatal(err)
return
}
for i, p := range project.Services {
name := p.Name
if project.Services[i].Labels == nil {
project.Services[i].Labels = make(map[string]string)
}
if s, ok := services[name]; ok {
getLabelContent(s.MainApp, &project.Services[i], labels.LabelMainApp)
getLabelContent(s.Values, &project.Services[i], labels.LabelValues)
getLabelContent(s.Secrets, &project.Services[i], labels.LabelSecrets)
getLabelContent(s.Ports, &project.Services[i], labels.LabelPorts)
getLabelContent(s.Ingress, &project.Services[i], labels.LabelIngress)
getLabelContent(s.HealthCheck, &project.Services[i], labels.LabelHealthCheck)
getLabelContent(s.SamePod, &project.Services[i], labels.LabelSamePod)
getLabelContent(s.Description, &project.Services[i], labels.LabelDescription)
getLabelContent(s.Ignore, &project.Services[i], labels.LabelIgnore)
getLabelContent(s.Dependencies, &project.Services[i], labels.LabelDependencies)
getLabelContent(s.ConfigMapFile, &project.Services[i], labels.LabelConfigMapFiles)
getLabelContent(s.MapEnv, &project.Services[i], labels.LabelMapEnv)
getLabelContent(s.CronJob, &project.Services[i], labels.LabelCronJob)
getLabelContent(s.EnvFrom, &project.Services[i], labels.LabelEnvFrom)
}
}
fmt.Println(utils.IconInfo, "Katenary file loaded successfully, the services are now configured.")
}
func getLabelContent(o any, service *types.ServiceConfig, labelName string) error {
if reflect.ValueOf(o).IsZero() {
return nil
}
c, err := yaml.Marshal(o)
if err != nil {
log.Println(err)
return err
}
val := strings.TrimSpace(string(c))
service.Labels[labelName] = val
return nil
}
// GenerateSchema generates the schema for the katenary.yaml file.
func GenerateSchema() string {
s := jsonschema.Reflect(map[string]Service{})
// redefine the IntOrString type from k8s
s.Definitions["IntOrString"] = &jsonschema.Schema{
OneOf: []*jsonschema.Schema{
{Type: "integer"},
{Type: "string"},
},
}
// same for the StringOrMap type, that can be either a string or a map of string:string
s.Definitions["StringOrMap"] = &jsonschema.Schema{
OneOf: []*jsonschema.Schema{
{Type: "string"},
{Type: "object", AdditionalProperties: &jsonschema.Schema{Type: "string"}},
},
}
c, _ := s.MarshalJSON()
// indent the json
var out bytes.Buffer
err := json.Indent(&out, c, "", " ")
if err != nil {
return err.Error()
}
return string(out.Bytes())
}

View File

@@ -1,33 +0,0 @@
package labelStructs
import "gopkg.in/yaml.v3"
type TLS struct {
Enabled bool `yaml:"enabled"`
}
type Ingress struct {
Port *int32 `yaml:"port,omitempty"`
Annotations map[string]string `yaml:"annotations,omitempty"`
Hostname string `yaml:"hostname"`
Path string `yaml:"path"`
Class string `yaml:"class"`
Enabled bool `yaml:"enabled"`
TLS TLS `yaml:"tls"`
}
// IngressFrom creates a new Ingress from a compose service.
func IngressFrom(data string) (*Ingress, error) {
mapping := Ingress{
Hostname: "",
Path: "/",
Enabled: false,
Class: "-",
Port: nil,
TLS: TLS{Enabled: true},
}
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
return nil, err
}
return &mapping, nil
}

View File

@@ -2,9 +2,10 @@ package generator
import (
"fmt"
"katenary/generator/labels"
)
var componentLabel = labelName("component")
var componentLabel = labels.LabelName("component")
// GetLabels returns the labels for a service. It uses the appName to replace the __replace__ in the labels.
// This is used to generate the labels in the templates.

View File

@@ -1,4 +1,4 @@
package generator
package labels
import (
"bytes"
@@ -14,24 +14,24 @@ import (
"sigs.k8s.io/yaml"
)
const katenaryLabelPrefix = "katenary.v3"
const KatenaryLabelPrefix = "katenary.v3"
// Known labels.
const (
LabelMainApp Label = katenaryLabelPrefix + "/main-app"
LabelValues Label = katenaryLabelPrefix + "/values"
LabelSecrets Label = katenaryLabelPrefix + "/secrets"
LabelPorts Label = katenaryLabelPrefix + "/ports"
LabelIngress Label = katenaryLabelPrefix + "/ingress"
LabelMapEnv Label = katenaryLabelPrefix + "/map-env"
LabelHealthCheck Label = katenaryLabelPrefix + "/health-check"
LabelSamePod Label = katenaryLabelPrefix + "/same-pod"
LabelDescription Label = katenaryLabelPrefix + "/description"
LabelIgnore Label = katenaryLabelPrefix + "/ignore"
LabelDependencies Label = katenaryLabelPrefix + "/dependencies"
LabelConfigMapFiles Label = katenaryLabelPrefix + "/configmap-files"
LabelCronJob Label = katenaryLabelPrefix + "/cronjob"
LabelEnvFrom Label = katenaryLabelPrefix + "/env-from"
LabelMainApp Label = KatenaryLabelPrefix + "/main-app"
LabelValues Label = KatenaryLabelPrefix + "/values"
LabelSecrets Label = KatenaryLabelPrefix + "/secrets"
LabelPorts Label = KatenaryLabelPrefix + "/ports"
LabelIngress Label = KatenaryLabelPrefix + "/ingress"
LabelMapEnv Label = KatenaryLabelPrefix + "/map-env"
LabelHealthCheck Label = KatenaryLabelPrefix + "/health-check"
LabelSamePod Label = KatenaryLabelPrefix + "/same-pod"
LabelDescription Label = KatenaryLabelPrefix + "/description"
LabelIgnore Label = KatenaryLabelPrefix + "/ignore"
LabelDependencies Label = KatenaryLabelPrefix + "/dependencies"
LabelConfigMapFiles Label = KatenaryLabelPrefix + "/configmap-files"
LabelCronJob Label = KatenaryLabelPrefix + "/cronjob"
LabelEnvFrom Label = KatenaryLabelPrefix + "/env-from"
)
var (
@@ -47,8 +47,8 @@ var (
// Label is a katenary label to find in compose files.
type Label = string
func labelName(name string) Label {
return Label(katenaryLabelPrefix + "/" + name)
func LabelName(name string) Label {
return Label(KatenaryLabelPrefix + "/" + name)
}
// Help is the documentation of a label.
@@ -114,7 +114,7 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string {
template.Must(template.New("shorthelp").Parse(help.Long)).Execute(&buf, struct {
KatenaryPrefix string
}{
KatenaryPrefix: katenaryLabelPrefix,
KatenaryPrefix: KatenaryLabelPrefix,
})
help.Long = buf.String()
buf.Reset()
@@ -122,7 +122,7 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string {
template.Must(template.New("example").Parse(help.Example)).Execute(&buf, struct {
KatenaryPrefix string
}{
KatenaryPrefix: katenaryLabelPrefix,
KatenaryPrefix: KatenaryLabelPrefix,
})
help.Example = buf.String()
buf.Reset()
@@ -134,7 +134,7 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string {
}{
Name: labelname,
Help: help,
KatenaryPrefix: katenaryLabelPrefix,
KatenaryPrefix: KatenaryLabelPrefix,
})
return buf.String()
@@ -152,7 +152,7 @@ func generateMarkdownHelp(names []string) string {
}
for _, name := range names {
help := labelFullHelp[name]
maxNameLength = max(maxNameLength, len(name)+2+len(katenaryLabelPrefix))
maxNameLength = max(maxNameLength, len(name)+2+len(KatenaryLabelPrefix))
maxDescriptionLength = max(maxDescriptionLength, len(help.Short))
maxTypeLength = max(maxTypeLength, len(help.Type))
}
@@ -163,7 +163,7 @@ func generateMarkdownHelp(names []string) string {
for _, name := range names {
help := labelFullHelp[name]
fmt.Fprintf(&builder, "| %-*s | %-*s | %-*s |\n",
maxNameLength, "`"+labelName(name)+"`", // enclose in backticks
maxNameLength, "`"+LabelName(name)+"`", // enclose in backticks
maxDescriptionLength, help.Short,
maxTypeLength, help.Type,
)
@@ -176,7 +176,7 @@ func generatePlainHelp(names []string) string {
var builder strings.Builder
for _, name := range names {
help := labelFullHelp[name]
fmt.Fprintf(&builder, "%s:\t%s\t%s\n", labelName(name), help.Type, help.Short)
fmt.Fprintf(&builder, "%s:\t%s\t%s\n", LabelName(name), help.Type, help.Short)
}
// use tabwriter to align the help text
@@ -231,5 +231,5 @@ Example:
}
func Prefix() string {
return katenaryLabelPrefix
return KatenaryLabelPrefix
}

View File

@@ -1,4 +1,4 @@
package generator
package labels
import (
_ "embed"
@@ -48,7 +48,7 @@ func TestLabelName(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := labelName(tt.args.name); !reflect.DeepEqual(got, tt.want) {
if got := LabelName(tt.args.name); !reflect.DeepEqual(got, tt.want) {
t.Errorf("labelName() = %v, want %v", got, tt.want)
}
})

View File

@@ -3,10 +3,10 @@ package labelStructs
import "gopkg.in/yaml.v3"
type CronJob struct {
Image string `yaml:"image,omitempty"`
Command string `yaml:"command"`
Schedule string `yaml:"schedule"`
Rbac bool `yaml:"rbac"`
Image string `yaml:"image,omitempty" json:"image,omitempty"`
Command string `yaml:"command" json:"command,omitempty"`
Schedule string `yaml:"schedule" json:"schedule,omitempty"`
Rbac bool `yaml:"rbac" json:"rbac,omitempty"`
}
func CronJobFrom(data string) (*CronJob, error) {

View File

@@ -4,11 +4,11 @@ import "gopkg.in/yaml.v3"
// Dependency is a dependency of a chart to other charts.
type Dependency struct {
Values map[string]any `yaml:"-"`
Name string `yaml:"name"`
Version string `yaml:"version"`
Repository string `yaml:"repository"`
Alias string `yaml:"alias,omitempty"`
Values map[string]any `yaml:"-" json:"values,omitempty"`
Name string `yaml:"name" json:"name"`
Version string `yaml:"version" json:"version"`
Repository string `yaml:"repository" json:"repository"`
Alias string `yaml:"alias,omitempty" json:"alias,omitempty"`
}
// DependenciesFrom returns a slice of dependencies from the given string.

View File

@@ -0,0 +1,33 @@
package labelStructs
import "gopkg.in/yaml.v3"
type TLS struct {
Enabled bool `yaml:"enabled" json:"enabled,omitempty"`
}
type Ingress struct {
Port *int32 `yaml:"port,omitempty" jsonschema:"nullable" json:"port,omitempty"`
Annotations map[string]string `yaml:"annotations,omitempty" jsonschema:"nullable" json:"annotations,omitempty"`
Hostname string `yaml:"hostname" json:"hostname,omitempty"`
Path string `yaml:"path" json:"path,omitempty"`
Class string `yaml:"class" json:"class,omitempty" jsonschema:"default:-"`
Enabled bool `yaml:"enabled" json:"enabled,omitempty"`
TLS *TLS `yaml:"tls,omitempty" json:"tls,omitempty"`
}
// IngressFrom creates a new Ingress from a compose service.
func IngressFrom(data string) (*Ingress, error) {
mapping := Ingress{
Hostname: "",
Path: "/",
Enabled: false,
Class: "-",
Port: nil,
TLS: &TLS{Enabled: true},
}
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
return nil, err
}
return &mapping, nil
}

View File

@@ -8,13 +8,13 @@ import (
corev1 "k8s.io/api/core/v1"
)
type Probe struct {
LivenessProbe *corev1.Probe `yaml:"livenessProbe,omitempty"`
ReadinessProbe *corev1.Probe `yaml:"readinessProbe,omitempty"`
type HealthCheck struct {
LivenessProbe *corev1.Probe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty"`
ReadinessProbe *corev1.Probe `yaml:"readinessProbe,omitempty" json:"readinessProbe,omitempty"`
}
func ProbeFrom(data string) (*Probe, error) {
mapping := Probe{}
func ProbeFrom(data string) (*HealthCheck, error) {
mapping := HealthCheck{}
tmp := map[string]any{}
err := yaml.Unmarshal([]byte(data), &tmp)
if err != nil {

View File

@@ -3,6 +3,7 @@ package generator
import (
"encoding/base64"
"fmt"
"katenary/generator/labels"
"katenary/utils"
"strings"
@@ -44,7 +45,7 @@ func NewSecret(service types.ServiceConfig, appName string) *Secret {
// check if the value should be in values.yaml
valueList := []string{}
varDescriptons := utils.GetValuesFromLabel(service, LabelValues)
varDescriptons := utils.GetValuesFromLabel(service, labels.LabelValues)
for value := range varDescriptons {
valueList = append(valueList, value)
}
@@ -79,7 +80,15 @@ func (s *Secret) AddData(key, value string) {
if value == "" {
return
}
s.Data[key] = []byte(`{{ tpl ` + value + ` $ | b64enc }}`)
valuesLabels := utils.GetValuesFromLabel(s.service, labels.LabelValues)
if _, ok := valuesLabels[key]; ok {
// the value should be in values.yaml
s.Data[key] = []byte(`{{ tpl .Values.` + s.service.Name + `.environment.` + key + ` $ | b64enc }}`)
} else {
encoded := base64.StdEncoding.EncodeToString([]byte(value))
s.Data[key] = []byte(encoded)
}
// s.Data[key] = []byte(`{{ tpl ` + value + ` $ | b64enc }}`)
}
// Filename returns the filename of the secret.

View File

@@ -2,6 +2,7 @@ package generator
import (
"fmt"
"katenary/generator/labels"
"os"
"testing"
@@ -21,7 +22,7 @@ services:
%s/secrets: |-
- BAR
`
composeFile = fmt.Sprintf(composeFile, katenaryLabelPrefix)
composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix)
tmpDir := setup(composeFile)
defer teardown(tmpDir)

View File

@@ -1,7 +1,8 @@
package generator
import (
"katenary/generator/labelStructs"
"katenary/generator/labels"
"katenary/generator/labels/labelStructs"
"katenary/utils"
"regexp"
"strconv"
@@ -46,7 +47,7 @@ func fixPorts(service *types.ServiceConfig) error {
// check the "ports" label from container and add it to the service
portsLabel := ""
ok := false
if portsLabel, ok = service.Labels[LabelPorts]; !ok {
if portsLabel, ok = service.Labels[labels.LabelPorts]; !ok {
return nil
}
ports, err := labelStructs.PortsFrom(portsLabel)
@@ -75,7 +76,7 @@ func fixPorts(service *types.ServiceConfig) error {
// isIgnored returns true if the service is ignored.
func isIgnored(service types.ServiceConfig) bool {
if v, ok := service.Labels[LabelIgnore]; ok {
if v, ok := service.Labels[labels.LabelIgnore]; ok {
return v == "true" || v == "yes" || v == "1"
}
return false

View File

@@ -2,6 +2,7 @@ package generator
import (
"fmt"
"katenary/generator/labels"
"os"
"testing"
@@ -52,7 +53,7 @@ services:
%s/configmap-files: |-
- ./static
`
composeFile = fmt.Sprintf(composeFile, katenaryLabelPrefix)
composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix)
tmpDir := setup(composeFile)
defer teardown(tmpDir)
@@ -112,7 +113,7 @@ services:
%s/configmap-files: |-
- ./static/index.html
`
composeFile = fmt.Sprintf(composeFile, katenaryLabelPrefix)
composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix)
tmpDir := setup(composeFile)
defer teardown(tmpDir)
@@ -169,7 +170,7 @@ volumes:
data:
`
composeFile = fmt.Sprintf(composeFile, katenaryLabelPrefix)
composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix)
tmpDir := setup(composeFile)
defer teardown(tmpDir)