Use real types to parse labels
We were using `yaml.Unmarshal` on basic types or inline structs. This was not efficient and not clear to defined what we expect in labels. We now use types to unmarshal the labels. Only the `values` label is, at this time, parsed by GetValuesFromLabel because this `utils` function is clearly a special case.
This commit is contained in:
@@ -1,13 +1,6 @@
|
||||
package generator
|
||||
|
||||
// Dependency is a dependency of a chart to other charts.
|
||||
type Dependency struct {
|
||||
Name string `yaml:"name"`
|
||||
Version string `yaml:"version"`
|
||||
Repository string `yaml:"repository"`
|
||||
Alias string `yaml:"alias,omitempty"`
|
||||
Values map[string]any `yaml:"-"` // do not export to Chart.yaml
|
||||
}
|
||||
import "katenary/generator/labelStructs"
|
||||
|
||||
// ChartTemplate is a template of a chart. It contains the content of the template and the name of the service.
|
||||
// This is used internally to generate the templates.
|
||||
@@ -26,7 +19,7 @@ type HelmChart struct {
|
||||
Version string `yaml:"version"`
|
||||
AppVersion string `yaml:"appVersion"`
|
||||
Description string `yaml:"description"`
|
||||
Dependencies []Dependency `yaml:"dependencies,omitempty"`
|
||||
Dependencies []labelStructs.Dependency `yaml:"dependencies,omitempty"`
|
||||
Templates map[string]*ChartTemplate `yaml:"-"` // do not export to yaml
|
||||
Helper string `yaml:"-"` // do not export to yaml
|
||||
Values map[string]any `yaml:"-"` // do not export to yaml
|
||||
|
@@ -7,10 +7,10 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"katenary/generator/labelStructs"
|
||||
"katenary/utils"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
goyaml "gopkg.in/yaml.v3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
@@ -56,7 +56,6 @@ type ConfigMap struct {
|
||||
func NewConfigMap(service types.ServiceConfig, appName string) *ConfigMap {
|
||||
done := map[string]bool{}
|
||||
drop := map[string]bool{}
|
||||
secrets := []string{}
|
||||
labelValues := []string{}
|
||||
|
||||
cm := &ConfigMap{
|
||||
@@ -76,11 +75,9 @@ func NewConfigMap(service types.ServiceConfig, appName string) *ConfigMap {
|
||||
}
|
||||
|
||||
// get the secrets from the labels
|
||||
if v, ok := service.Labels[LabelSecrets]; ok {
|
||||
err := yaml.Unmarshal([]byte(v), &secrets)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if secrets, err := labelStructs.SecretsFrom(service.Labels[LabelSecrets]); err != nil {
|
||||
log.Fatal(err)
|
||||
} else {
|
||||
// drop the secrets from the environment
|
||||
for _, secret := range secrets {
|
||||
drop[secret] = true
|
||||
@@ -105,8 +102,8 @@ func NewConfigMap(service types.ServiceConfig, appName string) *ConfigMap {
|
||||
|
||||
// remove the variables that are already defined in the environment
|
||||
if l, ok := service.Labels[LabelMapEnv]; ok {
|
||||
envmap := make(map[string]string)
|
||||
if err := goyaml.Unmarshal([]byte(l), &envmap); err != nil {
|
||||
envmap, err := labelStructs.MapEnvFrom(l)
|
||||
if err != nil {
|
||||
log.Fatal("Error parsing map-env", err)
|
||||
}
|
||||
for key, value := range envmap {
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"katenary/generator/extrafiles"
|
||||
"katenary/generator/labelStructs"
|
||||
"katenary/parser"
|
||||
"katenary/utils"
|
||||
|
||||
@@ -363,7 +364,7 @@ func addDescriptions(values []byte, project types.Project) []byte {
|
||||
return values
|
||||
}
|
||||
|
||||
func addDependencyDescription(values []byte, dependencies []Dependency) []byte {
|
||||
func addDependencyDescription(values []byte, dependencies []labelStructs.Dependency) []byte {
|
||||
for _, d := range dependencies {
|
||||
name := d.Name
|
||||
if d.Alias != "" {
|
||||
|
@@ -4,11 +4,10 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
labelstructs "katenary/generator/labelStructs"
|
||||
"katenary/generator/labelStructs"
|
||||
"katenary/utils"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
goyaml "gopkg.in/yaml.v3"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -32,19 +31,8 @@ func NewCronJob(service types.ServiceConfig, chart *HelmChart, appName string) (
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
//mapping := struct {
|
||||
// Image string `yaml:"image,omitempty"`
|
||||
// Command string `yaml:"command"`
|
||||
// Schedule string `yaml:"schedule"`
|
||||
// Rbac bool `yaml:"rbac"`
|
||||
//}{
|
||||
// Image: "",
|
||||
// Command: "",
|
||||
// Schedule: "",
|
||||
// Rbac: false,
|
||||
//}
|
||||
var mapping labelstructs.CronJob
|
||||
if err := goyaml.Unmarshal([]byte(labels), &mapping); err != nil {
|
||||
mapping, err := labelStructs.CronJobFrom(labels)
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing cronjob labels: %s", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"katenary/generator/labelStructs"
|
||||
"katenary/utils"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
@@ -187,8 +188,8 @@ func (d *Deployment) AddIngress(service types.ServiceConfig, appName string) *In
|
||||
func (d *Deployment) AddVolumes(service types.ServiceConfig, appName string) {
|
||||
tobind := map[string]bool{}
|
||||
if v, ok := service.Labels[LabelConfigMapFiles]; ok {
|
||||
binds := []string{}
|
||||
if err := yaml.Unmarshal([]byte(v), &binds); err != nil {
|
||||
binds, err := labelStructs.ConfigMapFileFrom(v)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, bind := range binds {
|
||||
@@ -353,12 +354,9 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string) {
|
||||
secrets := []string{}
|
||||
|
||||
// secrets from label
|
||||
labelSecrets := []string{}
|
||||
if v, ok := service.Labels[LabelSecrets]; ok {
|
||||
err := yaml.Unmarshal([]byte(v), &labelSecrets)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
labelSecrets, err := labelStructs.SecretsFrom(service.Labels[LabelSecrets])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// values from label
|
||||
@@ -442,11 +440,7 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string) {
|
||||
func (d *Deployment) AddHealthCheck(service types.ServiceConfig, container *corev1.Container) {
|
||||
// get the label for healthcheck
|
||||
if v, ok := service.Labels[LabelHealthCheck]; ok {
|
||||
probes := struct {
|
||||
LivenessProbe *corev1.Probe `yaml:"livenessProbe"`
|
||||
ReadinessProbe *corev1.Probe `yaml:"readinessProbe"`
|
||||
}{}
|
||||
err := yaml.Unmarshal([]byte(v), &probes)
|
||||
probes, err := labelStructs.ProbeFrom(v)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@@ -10,12 +10,11 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"katenary/generator/labelStructs"
|
||||
"katenary/utils"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
goyaml "gopkg.in/yaml.v3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Generate a chart from a compose project.
|
||||
@@ -275,8 +274,8 @@ func setChartVersion(chart *HelmChart, service types.ServiceConfig) {
|
||||
func fixPorts(service *types.ServiceConfig) error {
|
||||
// check the "ports" label from container and add it to the service
|
||||
if portsLabel, ok := service.Labels[LabelPorts]; ok {
|
||||
ports := []uint32{}
|
||||
if err := goyaml.Unmarshal([]byte(portsLabel), &ports); err != nil {
|
||||
ports, err := labelStructs.PortsFrom(portsLabel)
|
||||
if err != nil {
|
||||
// maybe it's a string, comma separated
|
||||
parts := strings.Split(portsLabel, ",")
|
||||
for _, part := range parts {
|
||||
@@ -337,8 +336,8 @@ func setCronJob(service types.ServiceConfig, chart *HelmChart, appName string) *
|
||||
func setDependencies(chart *HelmChart, service types.ServiceConfig) (bool, error) {
|
||||
// helm dependency
|
||||
if v, ok := service.Labels[LabelDependencies]; ok {
|
||||
d := []Dependency{}
|
||||
if err := yaml.Unmarshal([]byte(v), &d); err != nil {
|
||||
d, err := labelStructs.DependenciesFrom(v)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -462,8 +461,8 @@ func generateConfigMapsAndSecrets(project *types.Project, chart *HelmChart) erro
|
||||
}
|
||||
|
||||
if v, ok := s.Labels[LabelSecrets]; ok {
|
||||
list := []string{}
|
||||
if err := yaml.Unmarshal([]byte(v), &list); err != nil {
|
||||
list, err := labelStructs.SecretsFrom(v)
|
||||
if err != nil {
|
||||
log.Fatal("error unmarshaling secrets label:", err)
|
||||
}
|
||||
for _, secret := range list {
|
||||
@@ -558,8 +557,8 @@ func setSharedConf(service types.ServiceConfig, chart *HelmChart, deployments ma
|
||||
if _, ok := service.Labels[LabelEnvFrom]; !ok {
|
||||
return
|
||||
}
|
||||
fromservices := []string{}
|
||||
if err := yaml.Unmarshal([]byte(service.Labels[LabelEnvFrom]), &fromservices); err != nil {
|
||||
fromservices, err := labelStructs.EnvFromFrom(service.Labels[LabelEnvFrom])
|
||||
if err != nil {
|
||||
log.Fatal("error unmarshaling env-from label:", err)
|
||||
}
|
||||
// find the configmap in the chart templates
|
||||
|
@@ -4,10 +4,10 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"katenary/generator/labelStructs"
|
||||
"katenary/utils"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
goyaml "gopkg.in/yaml.v3"
|
||||
networkv1 "k8s.io/api/networking/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
@@ -33,49 +33,35 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
|
||||
return nil
|
||||
}
|
||||
|
||||
mapping := map[string]interface{}{
|
||||
"enabled": false,
|
||||
"host": service.Name + ".tld",
|
||||
"path": "/",
|
||||
"class": "-",
|
||||
}
|
||||
if err := goyaml.Unmarshal([]byte(label), &mapping); err != nil {
|
||||
mapping, err := labelStructs.IngressFrom(label)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse ingress label: %s\n", err)
|
||||
}
|
||||
if mapping.Hostname == "" {
|
||||
mapping.Hostname = service.Name + ".tld"
|
||||
}
|
||||
|
||||
// create the ingress
|
||||
pathType := networkv1.PathTypeImplementationSpecific
|
||||
serviceName := `{{ include "` + appName + `.fullname" . }}-` + service.Name
|
||||
if v, ok := mapping["port"]; ok {
|
||||
if port, ok := v.(int); ok {
|
||||
mapping["port"] = int32(port)
|
||||
}
|
||||
} else {
|
||||
log.Fatalf("No port provided for ingress target in service %s\n", service.Name)
|
||||
}
|
||||
|
||||
// Add the ingress host to the values.yaml
|
||||
if Chart.Values[service.Name] == nil {
|
||||
Chart.Values[service.Name] = &Value{}
|
||||
}
|
||||
|
||||
// fix the ingress host => hostname
|
||||
if hostname, ok := mapping["host"]; ok && hostname != "" {
|
||||
mapping["hostname"] = hostname
|
||||
}
|
||||
|
||||
Chart.Values[service.Name].(*Value).Ingress = &IngressValue{
|
||||
Enabled: mapping["enabled"].(bool),
|
||||
Path: mapping["path"].(string),
|
||||
Host: mapping["hostname"].(string),
|
||||
Class: mapping["class"].(string),
|
||||
Annotations: map[string]string{},
|
||||
Enabled: mapping.Enabled,
|
||||
Path: mapping.Path,
|
||||
Host: mapping.Hostname,
|
||||
Class: mapping.Class,
|
||||
Annotations: mapping.Annotations,
|
||||
}
|
||||
|
||||
// ingressClassName := `{{ .Values.` + service.Name + `.ingress.class }}`
|
||||
ingressClassName := utils.TplValue(service.Name, "ingress.class")
|
||||
|
||||
servicePortName := utils.GetServiceNameByPort(int(mapping["port"].(int32)))
|
||||
servicePortName := utils.GetServiceNameByPort(int(*mapping.Port))
|
||||
ingressService := &networkv1.IngressServiceBackend{
|
||||
Name: serviceName,
|
||||
Port: networkv1.ServiceBackendPort{},
|
||||
@@ -83,7 +69,7 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
|
||||
if servicePortName != "" {
|
||||
ingressService.Port.Name = servicePortName
|
||||
} else {
|
||||
ingressService.Port.Number = mapping["port"].(int32)
|
||||
ingressService.Port.Number = *mapping.Port
|
||||
}
|
||||
|
||||
ing := &Ingress{
|
||||
|
@@ -19,7 +19,7 @@ services:
|
||||
- 443:443
|
||||
labels:
|
||||
%s/ingress: |-
|
||||
host: my.test.tld
|
||||
hostname: my.test.tld
|
||||
port: 80
|
||||
`
|
||||
composeFile = fmt.Sprintf(composeFile, katenaryLabelPrefix)
|
||||
|
@@ -1,8 +1,13 @@
|
||||
package labelstructs
|
||||
package labelStructs
|
||||
|
||||
type CronJob struct {
|
||||
Image string `yaml:"image,omitempty"`
|
||||
Command string `yaml:"command"`
|
||||
Schedule string `yaml:"schedule"`
|
||||
Rbac bool `yaml:"rbac"`
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type ConfigMapFile []string
|
||||
|
||||
func ConfigMapFileFrom(data string) (ConfigMapFile, error) {
|
||||
var mapping ConfigMapFile
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
||||
|
18
generator/labelStructs/cronJob.go
Normal file
18
generator/labelStructs/cronJob.go
Normal file
@@ -0,0 +1,18 @@
|
||||
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"`
|
||||
}
|
||||
|
||||
func CronJobFrom(data string) (*CronJob, error) {
|
||||
var mapping CronJob
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mapping, nil
|
||||
}
|
21
generator/labelStructs/dependencies.go
Normal file
21
generator/labelStructs/dependencies.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package labelStructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
// Dependency is a dependency of a chart to other charts.
|
||||
type Dependency struct {
|
||||
Name string `yaml:"name"`
|
||||
Version string `yaml:"version"`
|
||||
Repository string `yaml:"repository"`
|
||||
Alias string `yaml:"alias,omitempty"`
|
||||
Values map[string]any `yaml:"-"` // do not export to Chart.yaml
|
||||
}
|
||||
|
||||
// DependenciesFrom returns a slice of dependencies from the given string.
|
||||
func DependenciesFrom(data string) ([]Dependency, error) {
|
||||
var mapping []Dependency
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
2
generator/labelStructs/doc.go
Normal file
2
generator/labelStructs/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// labelStructs is a package that contains the structs used to represent the labels in the yaml files.
|
||||
package labelStructs
|
14
generator/labelStructs/envFrom.go
Normal file
14
generator/labelStructs/envFrom.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package labelStructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type EnvFrom []string
|
||||
|
||||
// EnvFromFrom returns a EnvFrom from the given string.
|
||||
func EnvFromFrom(data string) (EnvFrom, error) {
|
||||
var mapping EnvFrom
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
33
generator/labelStructs/ingress.go
Normal file
33
generator/labelStructs/ingress.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package labelStructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type Ingress struct {
|
||||
// Hostname is the hostname to match against the request. It can contain wildcards.
|
||||
Hostname string `yaml:"hostname"`
|
||||
// Path is the path to match against the request. It can contain wildcards.
|
||||
Path string `yaml:"path"`
|
||||
// Enabled is a flag to enable or disable the ingress.
|
||||
Enabled bool `yaml:"enabled"`
|
||||
// Class is the ingress class to use.
|
||||
Class string `yaml:"class"`
|
||||
// Port is the port to use.
|
||||
Port *int32 `yaml:"port,omitempty"`
|
||||
// Annotations is a list of key-value pairs to add to the ingress.
|
||||
Annotations map[string]string `yaml:"annotations,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,
|
||||
}
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mapping, nil
|
||||
}
|
14
generator/labelStructs/mapenv.go
Normal file
14
generator/labelStructs/mapenv.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package labelStructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type MapEnv map[string]string
|
||||
|
||||
// MapEnvFrom returns a MapEnv from the given string.
|
||||
func MapEnvFrom(data string) (MapEnv, error) {
|
||||
var mapping MapEnv
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
14
generator/labelStructs/ports.go
Normal file
14
generator/labelStructs/ports.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package labelStructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type Ports []uint32
|
||||
|
||||
// PortsFrom returns a Ports from the given string.
|
||||
func PortsFrom(data string) (Ports, error) {
|
||||
var mapping Ports
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
19
generator/labelStructs/probes.go
Normal file
19
generator/labelStructs/probes.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package labelStructs
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
type Probe struct {
|
||||
LivenessProbe *corev1.Probe `yaml:"livenessProbe,omitempty"`
|
||||
ReadinessProbe *corev1.Probe `yaml:"readinessProbe,omitempty"`
|
||||
}
|
||||
|
||||
func ProbeFrom(data string) (*Probe, error) {
|
||||
var mapping Probe
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mapping, nil
|
||||
}
|
13
generator/labelStructs/secrets.go
Normal file
13
generator/labelStructs/secrets.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package labelStructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type Secrets []string
|
||||
|
||||
func SecretsFrom(data string) (Secrets, error) {
|
||||
var mapping Secrets
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
Reference in New Issue
Block a user