feat(refacto): move everything in internal package
This allows to install katenary with `go install` and to clean up the project folder.
This commit is contained in:
2
internal/generator/labels/doc.go
Normal file
2
internal/generator/labels/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package labels provides functionality to parse and manipulate labels.
|
||||
package labels
|
14
internal/generator/labels/help-template.md.tpl
Normal file
14
internal/generator/labels/help-template.md.tpl
Normal file
@@ -0,0 +1,14 @@
|
||||
## {{ .KatenaryPrefix }}/{{ .Name }}
|
||||
|
||||
{{ .Help.Short }}
|
||||
|
||||
**Type**: `{{ .Help.Type }}`
|
||||
|
||||
{{ .Help.Long }}
|
||||
|
||||
**Example:**
|
||||
|
||||
```yaml
|
||||
{{ .Help.Example }}
|
||||
```
|
||||
|
9
internal/generator/labels/help-template.tpl
Normal file
9
internal/generator/labels/help-template.tpl
Normal file
@@ -0,0 +1,9 @@
|
||||
{{ .KatenaryPrefix }}/{{ .Name }}: {{ .Help.Short }}
|
||||
Type: {{ .Help.Type }}
|
||||
|
||||
{{ .Help.Long }}
|
||||
|
||||
Example:
|
||||
|
||||
{{ .Help.Example }}
|
||||
|
237
internal/generator/labels/katenaryLabels.go
Normal file
237
internal/generator/labels/katenaryLabels.go
Normal file
@@ -0,0 +1,237 @@
|
||||
package labels
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"github.com/katenary/katenary/internal/utils"
|
||||
"log"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
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"
|
||||
LabelExchangeVolume Label = KatenaryLabelPrefix + "/exchange-volumes"
|
||||
LabelValuesFrom Label = KatenaryLabelPrefix + "/values-from"
|
||||
)
|
||||
|
||||
var (
|
||||
// Set the documentation of labels here
|
||||
//
|
||||
//go:embed katenaryLabelsDoc.yaml
|
||||
labelFullHelpYAML []byte
|
||||
|
||||
// parsed yaml
|
||||
labelFullHelp map[string]Help
|
||||
|
||||
//go:embed help-template.tpl
|
||||
helpTemplatePlain string
|
||||
|
||||
//go:embed help-template.md.tpl
|
||||
helpTemplateMarkdown string
|
||||
)
|
||||
|
||||
// Label is a katenary label to find in compose files.
|
||||
type Label = string
|
||||
|
||||
func LabelName(name string) Label {
|
||||
return Label(KatenaryLabelPrefix + "/" + name)
|
||||
}
|
||||
|
||||
// Help is the documentation of a label.
|
||||
type Help struct {
|
||||
Short string `yaml:"short"`
|
||||
Long string `yaml:"long"`
|
||||
Example string `yaml:"example"`
|
||||
Type string `yaml:"type"`
|
||||
}
|
||||
|
||||
// GetLabelNames returns a sorted list of all katenary label names.
|
||||
func GetLabelNames() []string {
|
||||
var names []string
|
||||
for name := range labelFullHelp {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
|
||||
func init() {
|
||||
if err := yaml.Unmarshal(labelFullHelpYAML, &labelFullHelp); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetLabelHelp return the help for the labels.
|
||||
func GetLabelHelp(asMarkdown bool) string {
|
||||
names := GetLabelNames() // sorted
|
||||
if !asMarkdown {
|
||||
return generatePlainHelp(names)
|
||||
}
|
||||
return generateMarkdownHelp(names)
|
||||
}
|
||||
|
||||
// GetLabelHelpFor returns the help for a specific label.
|
||||
func GetLabelHelpFor(labelname string, asMarkdown bool) string {
|
||||
help, ok := labelFullHelp[labelname]
|
||||
if !ok {
|
||||
return "No help available for " + labelname + "."
|
||||
}
|
||||
|
||||
help.Long = strings.TrimPrefix(help.Long, "\n")
|
||||
help.Example = strings.TrimPrefix(help.Example, "\n")
|
||||
help.Short = strings.TrimPrefix(help.Short, "\n")
|
||||
|
||||
if asMarkdown {
|
||||
// enclose templates in backticks
|
||||
help.Long = regexp.MustCompile(`\{\{(.*?)\}\}`).ReplaceAllString(help.Long, "`{{$1}}`")
|
||||
help.Long = strings.ReplaceAll(help.Long, "__APP__", "`__APP__`")
|
||||
} else {
|
||||
help.Long = strings.ReplaceAll(help.Long, " \n", "\n")
|
||||
help.Long = strings.ReplaceAll(help.Long, "`", "")
|
||||
help.Long = strings.ReplaceAll(help.Long, "<code>", "")
|
||||
help.Long = strings.ReplaceAll(help.Long, "</code>", "")
|
||||
help.Long = utils.WordWrap(help.Long, 80)
|
||||
}
|
||||
|
||||
// get help template
|
||||
var helpTemplate string
|
||||
switch asMarkdown {
|
||||
case true:
|
||||
helpTemplate = helpTemplateMarkdown
|
||||
case false:
|
||||
helpTemplate = helpTemplatePlain
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
var err error
|
||||
err = template.Must(template.New("shorthelp").Parse(help.Long)).Execute(&buf, struct {
|
||||
KatenaryPrefix string
|
||||
}{
|
||||
KatenaryPrefix: KatenaryLabelPrefix,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("Error executing template: %v", err)
|
||||
}
|
||||
help.Long = buf.String()
|
||||
buf.Reset()
|
||||
|
||||
err = template.Must(template.New("example").Parse(help.Example)).Execute(&buf, struct {
|
||||
KatenaryPrefix string
|
||||
}{
|
||||
KatenaryPrefix: KatenaryLabelPrefix,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("Error executing template: %v", err)
|
||||
}
|
||||
help.Example = buf.String()
|
||||
buf.Reset()
|
||||
|
||||
err = template.Must(template.New("complete").Parse(helpTemplate)).Execute(&buf, struct {
|
||||
Name string
|
||||
Help Help
|
||||
KatenaryPrefix string
|
||||
}{
|
||||
Name: labelname,
|
||||
Help: help,
|
||||
KatenaryPrefix: KatenaryLabelPrefix,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("Error executing template: %v", err)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func generateMarkdownHelp(names []string) string {
|
||||
var builder strings.Builder
|
||||
var maxNameLength, maxDescriptionLength, maxTypeLength int
|
||||
|
||||
max := func(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
for _, name := range names {
|
||||
help := labelFullHelp[name]
|
||||
maxNameLength = max(maxNameLength, len(name)+3+len(KatenaryLabelPrefix))
|
||||
maxDescriptionLength = max(maxDescriptionLength, len(help.Short))
|
||||
maxTypeLength = max(maxTypeLength, len(help.Type)+3)
|
||||
}
|
||||
|
||||
fmt.Fprintf(&builder, "%s\n", generateTableHeader(maxNameLength, maxDescriptionLength, maxTypeLength))
|
||||
fmt.Fprintf(&builder, "%s\n", generateTableHeaderSeparator(maxNameLength, maxDescriptionLength, maxTypeLength))
|
||||
|
||||
for _, name := range names {
|
||||
help := labelFullHelp[name]
|
||||
fmt.Fprintf(&builder, "| %-*s | %-*s | %-*s |\n",
|
||||
maxNameLength, "`"+LabelName(name)+"`", // enclose in backticks
|
||||
maxDescriptionLength, help.Short,
|
||||
maxTypeLength, "`"+help.Type+"`",
|
||||
)
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// use tabwriter to align the help text
|
||||
buf := new(strings.Builder)
|
||||
w := tabwriter.NewWriter(buf, 0, 8, 0, '\t', tabwriter.AlignRight)
|
||||
fmt.Fprintln(w, builder.String())
|
||||
w.Flush()
|
||||
|
||||
head := "To get more information about a label, use `katenary help-label <name_without_prefix>\ne.g. katenary help-label dependencies\n\n"
|
||||
return head + buf.String()
|
||||
}
|
||||
|
||||
func generateTableHeader(maxNameLength, maxDescriptionLength, maxTypeLength int) string {
|
||||
return fmt.Sprintf(
|
||||
"| %-*s | %-*s | %-*s |",
|
||||
maxNameLength, "Label name",
|
||||
maxDescriptionLength, "Description",
|
||||
maxTypeLength, "Type",
|
||||
)
|
||||
}
|
||||
|
||||
func generateTableHeaderSeparator(maxNameLength, maxDescriptionLength, maxTypeLength int) string {
|
||||
return fmt.Sprintf(
|
||||
"| %s | %s | %s |",
|
||||
strings.Repeat("-", maxNameLength),
|
||||
strings.Repeat("-", maxDescriptionLength),
|
||||
strings.Repeat("-", maxTypeLength),
|
||||
)
|
||||
}
|
||||
|
||||
func Prefix() string {
|
||||
return KatenaryLabelPrefix
|
||||
}
|
356
internal/generator/labels/katenaryLabelsDoc.yaml
Normal file
356
internal/generator/labels/katenaryLabelsDoc.yaml
Normal file
@@ -0,0 +1,356 @@
|
||||
# Labels documentation.
|
||||
#
|
||||
# To create a label documentation:
|
||||
#
|
||||
# "labelname":
|
||||
# type: the label type (bool, string, array, object...)
|
||||
# short: a short description
|
||||
# long: |-
|
||||
# A multiline description to explain the label behavior
|
||||
# example: |-
|
||||
# yamlsyntax: here
|
||||
#
|
||||
# This file is embed in the Katenary binary and parsed in kanetaryLabels.go init() function.
|
||||
#
|
||||
# Note:
|
||||
# - The short and long texts are parsed with text/template, so you can use template syntax.
|
||||
# That means that if you want to display double brackets, you need to enclose them to
|
||||
# prevent template to try to expand the content, for example :
|
||||
# This is an {{ "{{ example }}" }}.
|
||||
#
|
||||
# This will display "This is an {{ exemple }}" in the output.
|
||||
# - Use {{ .KatenaryPrefix }} to let Katenary replace it with the label prefix (e.g. "katenary.v3")
|
||||
|
||||
"main-app":
|
||||
short: "Mark the service as the main app."
|
||||
long: |-
|
||||
This makes the service to be the main application. Its image tag is
|
||||
considered to be the Chart appVersion and to be the defaultvalue in Pod
|
||||
container image attribute.
|
||||
|
||||
!!! Warning
|
||||
This label cannot be repeated in others services. If this label is
|
||||
set in more than one service as true, Katenary will return an error.
|
||||
example: |-
|
||||
ghost:
|
||||
image: ghost:1.25.5
|
||||
labels:
|
||||
# The chart is now named ghost, and the appVersion is 1.25.5.
|
||||
# In Deployment, the image attribute is set to ghost:1.25.5 if
|
||||
# you don't change the "tag" attribute in values.yaml
|
||||
{{ .KatenaryPrefix }}/main-app: true
|
||||
type: "bool"
|
||||
|
||||
"values":
|
||||
short: "Environment variables to be added to the values.yaml"
|
||||
long: |-
|
||||
By default, all environment variables in the "env" and environment
|
||||
files are added to configmaps with the static values set. This label
|
||||
allows adding environment variables to the values.yaml file.
|
||||
|
||||
Note that the value inside the configmap is {{ "{{ tpl vaname . }}" }}, so
|
||||
you can set the value to a template that will be rendered with the
|
||||
values.yaml file.
|
||||
|
||||
The value can be set with a documentation. This may help to understand
|
||||
the purpose of the variable.
|
||||
example: |-
|
||||
env:
|
||||
FOO: bar
|
||||
DB_NAME: mydb
|
||||
TO_CONFIGURE: something that can be changed in values.yaml
|
||||
A_COMPLEX_VALUE: example
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/values: |-
|
||||
# simple values, set as is in values.yaml
|
||||
- TO_CONFIGURE
|
||||
# complex values, set as a template in values.yaml with a documentation
|
||||
- A_COMPLEX_VALUE: |-
|
||||
This is the documentation for the variable to
|
||||
configure in values.yaml.
|
||||
It can be, of course, a multiline text.
|
||||
type: "[]string or map[string]string"
|
||||
|
||||
"secrets":
|
||||
short: "Env vars to be set as secrets."
|
||||
long: |-
|
||||
This label allows setting the environment variables as secrets. The variable
|
||||
is removed from the environment and added to a secret object.
|
||||
|
||||
The variable can be set to the {{ printf "%s/%s" .KatenaryPrefix "values"}} too,
|
||||
so the secret value can be configured in values.yaml
|
||||
example: |-
|
||||
env:
|
||||
PASSWORD: a very secret password
|
||||
NOT_A_SECRET: a public value
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/secrets: |-
|
||||
- PASSWORD
|
||||
type: "[]string"
|
||||
|
||||
"ports":
|
||||
short: "Ports to be added to the service."
|
||||
long: |-
|
||||
Only useful for services without exposed port. It is mandatory if the
|
||||
service is a dependency of another service.
|
||||
example: |-
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/ports: |-
|
||||
- 8080
|
||||
- 8081
|
||||
type: "[]uint32"
|
||||
|
||||
"ingress":
|
||||
short: "Ingress rules to be added to the service."
|
||||
long: |-
|
||||
Declare an ingress rule for the service. The port should be exposed or
|
||||
declared with {{ printf "%s/%s" .KatenaryPrefix "ports" }}.
|
||||
example: |-
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/ingress: |-
|
||||
port: 80
|
||||
hostname: mywebsite.com (optional)
|
||||
type: "object"
|
||||
|
||||
"map-env":
|
||||
short: "Map env vars from the service to the deployment."
|
||||
long: |-
|
||||
Because you may need to change the variable for Kubernetes, this label
|
||||
forces the value to another. It is also particullary helpful to use a template
|
||||
value instead. For example, you could bind the value to a service name
|
||||
with Helm attributes:
|
||||
{{ "{{ tpl .Release.Name . }}" }}.
|
||||
|
||||
If you use __APP__ in the value, it will be replaced by the Chart name.
|
||||
example: |-
|
||||
env:
|
||||
DB_HOST: database
|
||||
RUNNING: docker
|
||||
OTHER: value
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/map-env: |-
|
||||
RUNNING: kubernetes
|
||||
DB_HOST: '{{ "{{ include \"__APP__.fullname\" . }}" }}-database'
|
||||
type: "map[string]string"
|
||||
|
||||
"health-check":
|
||||
short: "Health check to be added to the deployment."
|
||||
long: "Health check to be added to the deployment."
|
||||
example: |-
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/health-check: |-
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
type: "object"
|
||||
|
||||
"same-pod":
|
||||
short: "Move the same-pod deployment to the target deployment."
|
||||
long: |-
|
||||
This will make the service to be included in another service pod. Some services
|
||||
must work together in the same pod, like a sidecar or a proxy or nginx + php-fpm.
|
||||
|
||||
Note that volume and VolumeMount are copied from the source to the target
|
||||
deployment.
|
||||
example: |-
|
||||
web:
|
||||
image: nginx:1.19
|
||||
|
||||
php:
|
||||
image: php:7.4-fpm
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/same-pod: web
|
||||
type: "string"
|
||||
|
||||
"description":
|
||||
short: "Description of the service"
|
||||
long: |-
|
||||
This replaces the default comment in values.yaml file to the given description.
|
||||
It is useful to document the service and configuration.
|
||||
|
||||
The value can be set with a documentation in multiline format.
|
||||
example: |-
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/description: |-
|
||||
This is a description of the service.
|
||||
It can be multiline.
|
||||
type: "string"
|
||||
|
||||
"ignore":
|
||||
short: "Ignore the service"
|
||||
long: "Ingoring a service to not be exported in helm chart."
|
||||
example: "labels:\n {{ .KatenaryPrefix }}/ignore: \"true\""
|
||||
type: "bool"
|
||||
|
||||
"dependencies":
|
||||
short: "Add Helm dependencies to the service."
|
||||
long: |-
|
||||
Set the service to be, actually, a Helm dependency. This means that the
|
||||
service will not be exported as template. The dependencies are added to
|
||||
the Chart.yaml file and the values are added to the values.yaml file.
|
||||
|
||||
It's a list of objects with the following attributes:
|
||||
|
||||
- name: the name of the dependency
|
||||
- repository: the repository of the dependency
|
||||
- alias: the name of the dependency in values.yaml (optional)
|
||||
- values: the values to be set in values.yaml (optional)
|
||||
|
||||
!!! Info
|
||||
Katenary doesn't update the helm depenedencies by default.
|
||||
|
||||
Use `--helm-update` (or `-u`) flag to update the dependencies.
|
||||
|
||||
example: <code>katenary convert -u</code>
|
||||
|
||||
By setting an alias, it is possible to change the name of the dependency
|
||||
in values.yaml.
|
||||
example: |-
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/dependencies: |-
|
||||
- name: mariadb
|
||||
repository: oci://registry-1.docker.io/bitnamicharts
|
||||
|
||||
## optional, it changes the name of the section in values.yaml
|
||||
# alias: mydatabase
|
||||
|
||||
## optional, it adds the values to values.yaml
|
||||
values:
|
||||
auth:
|
||||
database: mydatabasename
|
||||
username: myuser
|
||||
password: the secret password
|
||||
type: "[]object"
|
||||
|
||||
"configmap-files":
|
||||
short: "Inject files as Configmap."
|
||||
long: |-
|
||||
It makes a file or directory to be converted to one or more ConfigMaps
|
||||
and mounted in the pod. The file or directory is relative to the
|
||||
service directory.
|
||||
|
||||
If it is a directory, all files inside it are added to the ConfigMap.
|
||||
|
||||
If the directory as subdirectories, so one configmap per subpath are created.
|
||||
|
||||
!!! Warning
|
||||
It is not intended to be used to store an entire project in configmaps.
|
||||
It is intended to be used to store configuration files that are not managed
|
||||
by the application, like nginx configuration files. Keep in mind that your
|
||||
project sources should be stored in an application image or in a storage.
|
||||
example: |-
|
||||
volumes
|
||||
- ./conf.d:/etc/nginx/conf.d
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/configmap-files: |-
|
||||
- ./conf.d
|
||||
type: "[]string"
|
||||
|
||||
"cronjob":
|
||||
short: "Create a cronjob from the service."
|
||||
long: |-
|
||||
This adds a cronjob to the chart.
|
||||
|
||||
The label value is a YAML object with the following attributes:
|
||||
- command: the command to be executed
|
||||
- schedule: the cron schedule (cron format or @every where "every" is a
|
||||
duration like 1h30m, daily, hourly...)
|
||||
- rbac: false (optionnal), if true, it will create a role, a rolebinding and
|
||||
a serviceaccount to make your cronjob able to connect the Kubernetes API
|
||||
example: |-
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/cronjob: |-
|
||||
command: echo "hello world"
|
||||
schedule: "* */1 * * *" # or @hourly for example
|
||||
type: "object"
|
||||
|
||||
"env-from":
|
||||
short: "Add environment variables from another service."
|
||||
type: "[]string"
|
||||
long: |-
|
||||
It adds environment variables from another service to the current service.
|
||||
example: |-
|
||||
service1:
|
||||
image: nginx:1.19
|
||||
environment:
|
||||
FOO: bar
|
||||
|
||||
service2:
|
||||
image: php:7.4-fpm
|
||||
labels:
|
||||
# get the congigMap from service1 where FOO is
|
||||
# defined inside this service too
|
||||
{{ .KatenaryPrefix }}/env-from: |-
|
||||
- myservice1
|
||||
|
||||
"exchange-volumes":
|
||||
short: Add exchange volumes (empty directory on the node) to share data
|
||||
type: "[]object"
|
||||
long: |-
|
||||
This label allows sharing data between containres. The volume is created in
|
||||
the node and mounted in the pod. It is useful to share data between containers
|
||||
in a "same pod" logic. For example to let PHP-FPM and Nginx share the same direcotory.
|
||||
|
||||
This will create:
|
||||
|
||||
- an `emptyDir` volume in the deployment
|
||||
- a `voumeMount` in the pod for **each container**
|
||||
- a `initContainer` for each definition
|
||||
|
||||
Fields:
|
||||
- name: the name of the volume (manadatory)
|
||||
- mountPath: the path where the volume is mounted in the pod (optional, default is `/opt`)
|
||||
- init: a command to run to initialize the volume with data (optional)
|
||||
|
||||
!!! Warning
|
||||
This is highly experimental. This is mainly useful when using the "same-pod" label.
|
||||
|
||||
example: |-
|
||||
nginx:
|
||||
# ...
|
||||
labels;
|
||||
{{ .KatenaryPrefix }}/exchange-volumes: |-
|
||||
- name: php-fpm
|
||||
mountPath: /var/www/html
|
||||
php:
|
||||
# ...
|
||||
labels:
|
||||
{{ .KatenaryPrefix }}/exchange-volumes: |-
|
||||
- name: php-fpm
|
||||
mountPath: /opt
|
||||
init: cp -ra /var/www/html/* /opt
|
||||
|
||||
"values-from":
|
||||
short: "Add values from another service."
|
||||
long: |-
|
||||
This label allows adding values from another service to the current service.
|
||||
It avoid duplicating values, environment or secrets that should be the same.
|
||||
|
||||
The key is the value to be added, and the value is the "key" to fetch in the
|
||||
form `service_name.environment_name`.
|
||||
|
||||
type: "map[string]string"
|
||||
example: |-
|
||||
database:
|
||||
image: mariadb:10.5
|
||||
environment:
|
||||
MARIADB_USER: myuser
|
||||
MARIADB_PASSWORD: mypassword
|
||||
labels:
|
||||
# we can declare secrets
|
||||
{{ .KatenaryPrefix }}/secrets: |-
|
||||
- MARIADB_PASSWORD
|
||||
php:
|
||||
image: php:7.4-fpm
|
||||
environment:
|
||||
# it's duplicated in docker / podman
|
||||
DB_USER: myuser
|
||||
DB_PASSWORD: mypassword
|
||||
labels:
|
||||
# removes the duplicated, use the configMap and secrets from "database"
|
||||
{{ .KatenaryPrefix }}/values-from: |-
|
||||
DB_USER: database.MARIADB_USER
|
||||
DB_PASSWORD: database.MARIADB_PASSWORD
|
||||
|
||||
# vim: ft=gotmpl.yaml
|
78
internal/generator/labels/katenaryLabels_test.go
Normal file
78
internal/generator/labels/katenaryLabels_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package labels
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testingKatenaryPrefix = Prefix()
|
||||
|
||||
const mainAppLabel = "main-app"
|
||||
|
||||
func TestPrefix(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "TestPrefix",
|
||||
want: "katenary.v3",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := Prefix(); got != tt.want {
|
||||
t.Errorf("Prefix() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelName(t *testing.T) {
|
||||
type args struct {
|
||||
name string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want Label
|
||||
}{
|
||||
{
|
||||
name: "Test_labelName",
|
||||
args: args{
|
||||
name: mainAppLabel,
|
||||
},
|
||||
want: testingKatenaryPrefix + "/" + mainAppLabel,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := LabelName(tt.args.name); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("labelName() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLabelHelp(t *testing.T) {
|
||||
help := GetLabelHelp(false)
|
||||
if help == "" {
|
||||
t.Errorf("GetLabelHelp() = %v, want %v", help, "Help")
|
||||
}
|
||||
help = GetLabelHelp(true)
|
||||
if help == "" {
|
||||
t.Errorf("GetLabelHelp() = %v, want %v", help, "Help")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLabelHelpFor(t *testing.T) {
|
||||
help := GetLabelHelpFor(mainAppLabel, false)
|
||||
if help == "" {
|
||||
t.Errorf("GetLabelHelpFor() = %v, want %v", help, "Help")
|
||||
}
|
||||
help = GetLabelHelpFor("main-app", true)
|
||||
if help == "" {
|
||||
t.Errorf("GetLabelHelpFor() = %v, want %v", help, "Help")
|
||||
}
|
||||
}
|
13
internal/generator/labels/labelstructs/configMap.go
Normal file
13
internal/generator/labels/labelstructs/configMap.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package labelstructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type ConfigMapFiles []string
|
||||
|
||||
func ConfigMapFileFrom(data string) (ConfigMapFiles, error) {
|
||||
var mapping ConfigMapFiles
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
17
internal/generator/labels/labelstructs/configMap_test.go
Normal file
17
internal/generator/labels/labelstructs/configMap_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package labelstructs_test
|
||||
|
||||
import (
|
||||
"github.com/katenary/katenary/internal/generator/labels/labelstructs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfigMapFileFrom(t *testing.T) {
|
||||
ts := "- foo/bar"
|
||||
tc2, _ := labelstructs.ConfigMapFileFrom(ts)
|
||||
if len(tc2) != 1 {
|
||||
t.Errorf("Expected ConfigMapFile to have 1 item, got %d", len(tc2))
|
||||
}
|
||||
if tc2[0] != "foo/bar" {
|
||||
t.Errorf("Expected ConfigMapFile to contain 'foo/bar', got %s", tc2[0])
|
||||
}
|
||||
}
|
18
internal/generator/labels/labelstructs/cronJob.go
Normal file
18
internal/generator/labels/labelstructs/cronJob.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package labelstructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type CronJob struct {
|
||||
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) {
|
||||
var mapping CronJob
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mapping, nil
|
||||
}
|
25
internal/generator/labels/labelstructs/cronJob_test.go
Normal file
25
internal/generator/labels/labelstructs/cronJob_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package labelstructs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCronJobFrom(t *testing.T) {
|
||||
ts := `
|
||||
image: fooimage
|
||||
command: thecommand
|
||||
schedule: "0/3 0 * * *"
|
||||
Rbac: false
|
||||
`
|
||||
tc, _ := CronJobFrom(ts)
|
||||
if tc.Image != "fooimage" {
|
||||
t.Errorf("Expected CronJob image to be 'fooimage', got %s", tc.Image)
|
||||
}
|
||||
if tc.Command != "thecommand" {
|
||||
t.Errorf("Expected CronJob command to be 'thecommand', got %s", tc.Command)
|
||||
}
|
||||
if tc.Schedule != "0/3 0 * * *" {
|
||||
t.Errorf("Expected CronJob schedule to be '0/3 0 * * *', got %s", tc.Schedule)
|
||||
}
|
||||
if tc.Rbac != false {
|
||||
t.Errorf("Expected CronJob rbac to be false, got %t", tc.Rbac)
|
||||
}
|
||||
}
|
21
internal/generator/labels/labelstructs/dependencies.go
Normal file
21
internal/generator/labels/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 {
|
||||
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.
|
||||
func DependenciesFrom(data string) ([]Dependency, error) {
|
||||
var mapping []Dependency
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
14
internal/generator/labels/labelstructs/dependencies_test.go
Normal file
14
internal/generator/labels/labelstructs/dependencies_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package labelstructs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDependenciesLabel(t *testing.T) {
|
||||
ts := "- name: mongodb"
|
||||
tc, _ := DependenciesFrom(ts)
|
||||
if len(tc) != 1 {
|
||||
t.Errorf("Expected DependenciesLabel to have 1 item, got %d", len(tc))
|
||||
}
|
||||
if tc[0].Name != "mongodb" {
|
||||
t.Errorf("Expected DependenciesLabel to contain 'mongodb', got %s", tc[0].Name)
|
||||
}
|
||||
}
|
2
internal/generator/labels/labelstructs/doc.go
Normal file
2
internal/generator/labels/labelstructs/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package labelstructs is a package that contains the structs used to represent the labels in the yaml files.
|
||||
package labelstructs
|
14
internal/generator/labels/labelstructs/envFrom.go
Normal file
14
internal/generator/labels/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
|
||||
}
|
17
internal/generator/labels/labelstructs/envFrom_test.go
Normal file
17
internal/generator/labels/labelstructs/envFrom_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package labelstructs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEnvFromLabel(t *testing.T) {
|
||||
ts := "- foo\n- bar"
|
||||
tc, _ := EnvFromFrom(ts)
|
||||
if len(tc) != 2 {
|
||||
t.Errorf("Expected EnvFrom to have 2 items, got %d", len(tc))
|
||||
}
|
||||
if tc[0] != "foo" {
|
||||
t.Errorf("Expected EnvFrom to contain 'foo', got %s", tc[0])
|
||||
}
|
||||
if tc[1] != "bar" {
|
||||
t.Errorf("Expected EnvFrom to contain 'bar', got %s", tc[1])
|
||||
}
|
||||
}
|
20
internal/generator/labels/labelstructs/exchangeVolume.go
Normal file
20
internal/generator/labels/labelstructs/exchangeVolume.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package labelstructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type ExchangeVolume struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
MountPath string `yaml:"mountPath" json:"mountPath"`
|
||||
Type string `yaml:"type,omitempty" json:"type,omitempty"`
|
||||
Init string `yaml:"init,omitempty" json:"init,omitempty"`
|
||||
}
|
||||
|
||||
func NewExchangeVolumes(data string) ([]*ExchangeVolume, error) {
|
||||
mapping := []*ExchangeVolume{}
|
||||
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapping, nil
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package labelstructs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestExchangeVolumeLabel(t *testing.T) {
|
||||
ts := "- name: exchange-volume\n mountPath: /exchange\n readOnly: true"
|
||||
tc, _ := NewExchangeVolumes(ts)
|
||||
if len(tc) != 1 {
|
||||
t.Errorf("Expected ExchangeVolumeLabel to have 1 item, got %d", len(tc))
|
||||
}
|
||||
if tc[0].Name != "exchange-volume" {
|
||||
t.Errorf("Expected ExchangeVolumeLabel to contain 'exchange-volume', got %s", tc[0].Name)
|
||||
}
|
||||
if tc[0].MountPath != "/exchange" {
|
||||
t.Errorf("Expected MountPath to be '/exchange', got %s", tc[0].MountPath)
|
||||
}
|
||||
}
|
41
internal/generator/labels/labelstructs/ingress.go
Normal file
41
internal/generator/labels/labelstructs/ingress.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package labelstructs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/katenary/katenary/internal/utils"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type TLS struct {
|
||||
Enabled bool `yaml:"enabled" json:"enabled,omitempty"`
|
||||
}
|
||||
|
||||
type Ingress struct {
|
||||
Port *int32 `yaml:"port,omitempty" json:"port,omitempty"`
|
||||
Annotations map[string]string `yaml:"annotations,omitempty" jsonschema:"nullable" json:"annotations,omitempty"`
|
||||
Hostname string `yaml:"hostname,omitempty" json:"hostname,omitempty"`
|
||||
Path *string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
Class *string `yaml:"class,omitempty" json:"class,omitempty" jsonschema:"default:-"`
|
||||
Enabled bool `yaml:"enabled,omitempty" 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: utils.StrPtr("/"),
|
||||
Enabled: false,
|
||||
Class: utils.StrPtr("-"),
|
||||
Port: nil,
|
||||
TLS: &TLS{Enabled: true},
|
||||
}
|
||||
if err := yaml.Unmarshal([]byte(data), &mapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if mapping.Port == nil {
|
||||
return nil, fmt.Errorf("port is required in ingress definition")
|
||||
}
|
||||
return &mapping, nil
|
||||
}
|
31
internal/generator/labels/labelstructs/ingress_test.go
Normal file
31
internal/generator/labels/labelstructs/ingress_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package labelstructs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestIngressLabel(t *testing.T) {
|
||||
ts := "\nhostname: example.com\npath: /\nenabled: true\nport: 8888"
|
||||
tc, err := IngressFrom(ts)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing IngressLabel: %v", err)
|
||||
}
|
||||
if tc.Hostname != "example.com" {
|
||||
t.Errorf("Expected IngressLabel to contain 'example.com', got %s", tc.Hostname)
|
||||
}
|
||||
if tc.Path == nil || *tc.Path != "/" {
|
||||
t.Errorf("Expected IngressLabel to contain '/', got %v", tc.Path)
|
||||
}
|
||||
if tc.Enabled != true {
|
||||
t.Errorf("Expected IngressLabel to be enabled, got %v", tc.Enabled)
|
||||
}
|
||||
if tc.Port == nil || *tc.Port != 8888 {
|
||||
t.Errorf("Expected IngressLabel to have port 8888, got %d", tc.Port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressLabelNoPort(t *testing.T) {
|
||||
ts := "\nhostname: example.com\npath: /\nenabled: true"
|
||||
_, err := IngressFrom(ts)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error when parsing IngressLabel without port, got nil")
|
||||
}
|
||||
}
|
14
internal/generator/labels/labelstructs/mapenv.go
Normal file
14
internal/generator/labels/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
|
||||
}
|
11
internal/generator/labels/labelstructs/mapenv_test.go
Normal file
11
internal/generator/labels/labelstructs/mapenv_test.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package labelstructs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestConfigMapLabel(t *testing.T) {
|
||||
ts := "foo: bar"
|
||||
tc, _ := MapEnvFrom(ts)
|
||||
if len(tc) != 1 {
|
||||
t.Errorf("Expected ConfigMapFile to have 1 item, got %d", len(tc))
|
||||
}
|
||||
}
|
14
internal/generator/labels/labelstructs/ports.go
Normal file
14
internal/generator/labels/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
|
||||
}
|
23
internal/generator/labels/labelstructs/ports_test.go
Normal file
23
internal/generator/labels/labelstructs/ports_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package labelstructs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPortsFromLabel(t *testing.T) {
|
||||
data := "- 8080\n- 9090\n"
|
||||
expected := Ports{8080, 9090}
|
||||
|
||||
ports, err := PortsFrom(data)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
if len(ports) != len(expected) {
|
||||
t.Fatalf("expected length %d, got %d", len(expected), len(ports))
|
||||
}
|
||||
|
||||
for i, port := range ports {
|
||||
if port != expected[i] {
|
||||
t.Errorf("expected port %d at index %d, got %d", expected[i], i, port)
|
||||
}
|
||||
}
|
||||
}
|
56
internal/generator/labels/labelstructs/probes.go
Normal file
56
internal/generator/labels/labelstructs/probes.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package labelstructs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
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) (*HealthCheck, error) {
|
||||
mapping := HealthCheck{}
|
||||
tmp := map[string]any{}
|
||||
err := yaml.Unmarshal([]byte(data), &tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if livenessProbe, ok := tmp["livenessProbe"]; ok {
|
||||
livenessProbeBytes, err := json.Marshal(livenessProbe)
|
||||
if err != nil {
|
||||
log.Printf("Error marshalling livenessProbe: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
livenessProbe := &corev1.Probe{}
|
||||
err = json.Unmarshal(livenessProbeBytes, livenessProbe)
|
||||
if err != nil {
|
||||
log.Printf("Error unmarshalling livenessProbe: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
mapping.LivenessProbe = livenessProbe
|
||||
}
|
||||
|
||||
if readinessProbe, ok := tmp["readinessProbe"]; ok {
|
||||
readinessProbeBytes, err := json.Marshal(readinessProbe)
|
||||
if err != nil {
|
||||
log.Printf("Error marshalling readinessProbe: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
readinessProbe := &corev1.Probe{}
|
||||
err = json.Unmarshal(readinessProbeBytes, readinessProbe)
|
||||
if err != nil {
|
||||
log.Printf("Error unmarshalling readinessProbe: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
mapping.ReadinessProbe = readinessProbe
|
||||
|
||||
}
|
||||
|
||||
return &mapping, err
|
||||
}
|
16
internal/generator/labels/labelstructs/probes_test.go
Normal file
16
internal/generator/labels/labelstructs/probes_test.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package labelstructs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestProbesLabel(t *testing.T) {
|
||||
readiness := "readinessProbe:\n httpGet:\n path: /healthz\n port: 8080\n initialDelaySeconds: 5\n periodSeconds: 10"
|
||||
tc, err := ProbeFrom(readiness)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing ProbesLabel: %v %v", err, tc)
|
||||
}
|
||||
liveness := "livenessProbe:\n httpGet:\n path: /healthz\n port: 8080\n initialDelaySeconds: 5\n periodSeconds: 10"
|
||||
tc2, err := ProbeFrom(liveness)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing ProbesLabel: %v %v", err, tc2)
|
||||
}
|
||||
}
|
13
internal/generator/labels/labelstructs/secrets.go
Normal file
13
internal/generator/labels/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
|
||||
}
|
17
internal/generator/labels/labelstructs/secrets_test.go
Normal file
17
internal/generator/labels/labelstructs/secrets_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package labelstructs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSecretLabel(t *testing.T) {
|
||||
data := "- foo\n- bar"
|
||||
tc, err := SecretsFrom(data)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing SecretLabel: %v %v", err, tc)
|
||||
}
|
||||
items := []string{"foo", "bar"}
|
||||
for i, item := range tc {
|
||||
if item != items[i] {
|
||||
t.Errorf("Expected SecretLabel to contain '%s', got '%s'", items[i], item)
|
||||
}
|
||||
}
|
||||
}
|
13
internal/generator/labels/labelstructs/valueFrom.go
Normal file
13
internal/generator/labels/labelstructs/valueFrom.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package labelstructs
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type ValueFrom map[string]string
|
||||
|
||||
func GetValueFrom(data string) (*ValueFrom, error) {
|
||||
vf := ValueFrom{}
|
||||
if err := yaml.Unmarshal([]byte(data), &vf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &vf, nil
|
||||
}
|
25
internal/generator/labels/labelstructs/valueFrom_test.go
Normal file
25
internal/generator/labels/labelstructs/valueFrom_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package labelstructs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValueFromLabel(t *testing.T) {
|
||||
data := "data: foo\ndata2: bar"
|
||||
tc, err := GetValueFrom(data)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if tc == nil {
|
||||
t.Fatalf("expected non-nil map, got nil")
|
||||
}
|
||||
if len(*tc) != 2 {
|
||||
t.Errorf("expected 2 items, got %d", len(*tc))
|
||||
}
|
||||
if (*tc)["data"] != "foo" {
|
||||
t.Errorf("expected 'data' to be 'foo', got %s", (*tc)["data"])
|
||||
}
|
||||
if (*tc)["data2"] != "bar" {
|
||||
t.Errorf("expected 'data2' to be 'bar', got %s", (*tc)["data2"])
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user