Compare commits
39 Commits
feat-compo
...
3.0.0-rc3
Author | SHA1 | Date | |
---|---|---|---|
8c509b5bff | |||
28b22a0b30 | |||
748d0bf1ea | |||
130e6d4e24 | |||
a66fec07e1 | |||
a3d1e9342f | |||
72bc88661a | |||
e2b897eb9d | |||
9fcce059e5 | |||
36f6413917 | |||
8c729f3c57 | |||
063cc9d439 | |||
ac5317e600 | |||
bc0b65006d | |||
933f04bf5e | |||
7d46435ba2 | |||
d94bb8ac32 | |||
b143f743ef | |||
a8341a9b44 | |||
def5d097a4 | |||
ba0ae1bc60 | |||
d77029b597 | |||
b5f62d43af | |||
9220dc3278 | |||
36c72fb665 | |||
|
c90504f4f1 | ||
9ef961ae7c | |||
fe6663f9f4 | |||
1190b316bb | |||
7068dc229c | |||
|
61ce6fb25b | ||
116ef658d8 | |||
d7b354de8c | |||
|
d06c0574fb | ||
|
bcd7894e3b | ||
80aba05f66 | |||
c97b398914 | |||
0986f73f06 | |||
72ddb8aa74 |
26
.golangci.yml
Normal file
26
.golangci.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
version: "2"
|
||||
run:
|
||||
issues-exit-code: 1
|
||||
linters:
|
||||
enabled:
|
||||
- unused
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
- "(.+)_test.go"
|
||||
formatters:
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
- "(.+)_test.go"
|
24
Makefile
24
Makefile
@@ -4,7 +4,7 @@ VERSION=$(shell git describe --exact-match --tags $(CUR_SHA) 2>/dev/null || echo
|
||||
CTN:=$(shell which podman 2>&1 1>/dev/null && echo "podman" || echo "docker")
|
||||
PREFIX=~/.local
|
||||
|
||||
GOVERSION=1.23
|
||||
GOVERSION=1.24
|
||||
GO=container
|
||||
OUT=katenary
|
||||
RELEASE=""
|
||||
@@ -12,6 +12,8 @@ BLD_CMD=go build -ldflags="-X 'katenary/generator.Version=$(RELEASE)$(VERSION)'"
|
||||
GOOS=linux
|
||||
GOARCH=amd64
|
||||
SIGNER=metal3d@gmail.com
|
||||
UPX_OPTS =
|
||||
UPX ?= upx $(UPX_OPTS)
|
||||
|
||||
BUILD_IMAGE=docker.io/golang:$(GOVERSION)-alpine
|
||||
# SHELL=/bin/bash
|
||||
@@ -33,7 +35,7 @@ SHELL := bash
|
||||
.DELETE_ON_ERROR:
|
||||
MAKEFLAGS += --warn-undefined-variables
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
.PHONY: help clean build install tests test
|
||||
.PHONY: help clean build install tests test doc
|
||||
|
||||
all: build
|
||||
|
||||
@@ -95,17 +97,17 @@ ifeq ($(GO),local)
|
||||
$(BLD_CMD)
|
||||
else ifeq ($(CTN),podman)
|
||||
@podman run -e CGO_ENABLED=0 -e GOOS=$(GOOS) -e GOARCH=$(GOARCH) \
|
||||
--rm -v $(PWD):/go/src/katenary:z -w /go/src/katenary --userns keep-id -it $(BUILD_IMAGE) $(BLD_CMD)
|
||||
--rm -v $(PWD):/go/src/katenary:z -w /go/src/katenary --userns keep-id $(BUILD_IMAGE) $(BLD_CMD)
|
||||
else
|
||||
@docker run -e CGO_ENABLED=0 -e GOOS=$(GOOS) -e GOARCH=$(GOARCH) \
|
||||
--rm -v $(PWD):/go/src/katenary:z -w /go/src/katenary --user $(shell id -u):$(shell id -g) -e HOME=/tmp -it $(BUILD_IMAGE) $(BLD_CMD)
|
||||
--rm -v $(PWD):/go/src/katenary:z -w /go/src/katenary --user $(shell id -u):$(shell id -g) -e HOME=/tmp $(BUILD_IMAGE) $(BLD_CMD)
|
||||
endif
|
||||
echo "=> Stripping if possible"
|
||||
strip $(OUT) 2>/dev/null || echo "=> No strip available"
|
||||
|
||||
|
||||
## Release build
|
||||
dist: prepare $(BINARIES) $(ASC_BINARIES)
|
||||
dist: prepare $(BINARIES) upx $(ASC_BINARIES)
|
||||
|
||||
prepare: pull
|
||||
mkdir -p dist
|
||||
@@ -147,6 +149,13 @@ gpg-sign:
|
||||
dist/%.asc: dist/%
|
||||
gpg --armor --detach-sign --default-key $(SIGNER) $< &>/dev/null || exit 1
|
||||
|
||||
|
||||
upx:
|
||||
$(UPX) dist/katenary-linux-amd64
|
||||
$(UPX) dist/katenary-linux-arm64
|
||||
$(UPX) dist/katenary.exe
|
||||
$(UPX) dist/katenary-darwin-amd64 --force-macos
|
||||
|
||||
install: build
|
||||
install -Dm755 katenary $(PREFIX)/bin/katenary
|
||||
|
||||
@@ -204,6 +213,11 @@ push-release: build-all
|
||||
@rm -f release.id
|
||||
|
||||
|
||||
doc:
|
||||
@echo "=> Generating documentation..."
|
||||
# generate the labels doc and code doc
|
||||
$(MAKE) __label_doc
|
||||
|
||||
__label_doc:
|
||||
@command -v gomarkdoc || (echo "==> We need to install gomarkdoc..." && \
|
||||
go install github.com/princjef/gomarkdoc/cmd/gomarkdoc@latest)
|
||||
|
@@ -179,7 +179,7 @@ services:
|
||||
# this will use the database secrets and environment,
|
||||
# see the "database" service to see the values
|
||||
katenary.v3/values-from: |-
|
||||
DB_USER: databse.MARIADB_USER
|
||||
DB_USER: database.MARIADB_USER
|
||||
DB_PASSWORD: database.MARIADB_PASSWORD
|
||||
|
||||
database:
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"katenary/generator/katenaryfile"
|
||||
"katenary/generator/labels"
|
||||
"katenary/utils"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@@ -24,7 +25,10 @@ Each [command] and subcommand has got an "help" and "--help" flag to show more i
|
||||
|
||||
func main() {
|
||||
rootCmd := buildRootCmd()
|
||||
rootCmd.Execute()
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func buildRootCmd() *cobra.Command {
|
||||
@@ -97,26 +101,26 @@ func generateCompletionCommand(name string) *cobra.Command {
|
||||
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
|
||||
Short: "Generates completion scripts",
|
||||
Long: fmt.Sprintf(completionHelp, name),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
cmd.Help()
|
||||
return
|
||||
return cmd.Help()
|
||||
}
|
||||
switch args[0] {
|
||||
case "bash":
|
||||
// get the bash version
|
||||
if cmd.Flags().Changed("bash-v1") {
|
||||
cmd.Root().GenBashCompletion(os.Stdout)
|
||||
return
|
||||
return cmd.Root().GenBashCompletion(os.Stdout)
|
||||
}
|
||||
cmd.Root().GenBashCompletionV2(os.Stdout, true)
|
||||
return cmd.Root().GenBashCompletionV2(os.Stdout, true)
|
||||
case "zsh":
|
||||
cmd.Root().GenZshCompletion(os.Stdout)
|
||||
return cmd.Root().GenZshCompletion(os.Stdout)
|
||||
case "fish":
|
||||
cmd.Root().GenFishCompletion(os.Stdout, true)
|
||||
return cmd.Root().GenFishCompletion(os.Stdout, true)
|
||||
case "powershell":
|
||||
cmd.Root().GenPowerShellCompletion(os.Stdout)
|
||||
return cmd.Root().GenPowerShellCompletion(os.Stdout)
|
||||
}
|
||||
|
||||
return fmt.Errorf("unknown completion type: %s", args[0])
|
||||
},
|
||||
}
|
||||
|
||||
|
5
doc/docs/.markdownlint.yaml
Normal file
5
doc/docs/.markdownlint.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
MD012: false
|
||||
MD013: false
|
||||
MD022: false
|
||||
MD033: false
|
||||
MD046: false
|
@@ -460,9 +460,9 @@ database:
|
||||
MARIADB_USER: myuser
|
||||
MARIADB_PASSWORD: mypassword
|
||||
labels:
|
||||
# it can be a secret
|
||||
# we can declare secrets
|
||||
katenary.v3/secrets: |-
|
||||
- DB_PASSWORD
|
||||
- MARIADB_PASSWORD
|
||||
php:
|
||||
image: php:7.4-fpm
|
||||
environment:
|
||||
|
@@ -35,7 +35,7 @@ var Version = "master" // changed at compile time
|
||||
```
|
||||
|
||||
<a name="Convert"></a>
|
||||
## func [Convert](<https://github.com/metal3d/katenary/blob/develop/generator/converter.go#L93>)
|
||||
## func [Convert](<https://github.com/metal3d/katenary/blob/develop/generator/converter.go#L99>)
|
||||
|
||||
```go
|
||||
func Convert(config ConvertOptions, dockerComposeFile ...string) error
|
||||
@@ -92,7 +92,7 @@ NewCronJob creates a new CronJob from a compose service. The appName is the name
|
||||
## func [ToK8SYaml](<https://github.com/metal3d/katenary/blob/develop/generator/utils.go#L90>)
|
||||
|
||||
```go
|
||||
func ToK8SYaml(obj interface{}) ([]byte, error)
|
||||
func ToK8SYaml(obj any) ([]byte, error)
|
||||
```
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ func NewConfigMapFromDirectory(service types.ServiceConfig, appName, path string
|
||||
NewConfigMapFromDirectory creates a new ConfigMap from a compose service. This path is the path to the file or directory. If the path is a directory, all files in the directory are added to the ConfigMap. Each subdirectory are ignored. Note that the Generate\(\) function will create the subdirectories ConfigMaps.
|
||||
|
||||
<a name="ConfigMap.AddBinaryData"></a>
|
||||
### func \(\*ConfigMap\) [AddBinaryData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L155>)
|
||||
### func \(\*ConfigMap\) [AddBinaryData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L157>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) AddBinaryData(key string, value []byte)
|
||||
@@ -158,7 +158,7 @@ func (c *ConfigMap) AddBinaryData(key string, value []byte)
|
||||
AddBinaryData adds binary data to the configmap. Append or overwrite the value if the key already exists.
|
||||
|
||||
<a name="ConfigMap.AddData"></a>
|
||||
### func \(\*ConfigMap\) [AddData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L150>)
|
||||
### func \(\*ConfigMap\) [AddData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L152>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) AddData(key, value string)
|
||||
@@ -167,7 +167,7 @@ func (c *ConfigMap) AddData(key, value string)
|
||||
AddData adds a key value pair to the configmap. Append or overwrite the value if the key already exists.
|
||||
|
||||
<a name="ConfigMap.AppendDir"></a>
|
||||
### func \(\*ConfigMap\) [AppendDir](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L164>)
|
||||
### func \(\*ConfigMap\) [AppendDir](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L166>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) AppendDir(path string) error
|
||||
@@ -176,7 +176,7 @@ func (c *ConfigMap) AppendDir(path string) error
|
||||
AddFile adds files from given path to the configmap. It is not recursive, to add all files in a directory, you need to call this function for each subdirectory.
|
||||
|
||||
<a name="ConfigMap.AppendFile"></a>
|
||||
### func \(\*ConfigMap\) [AppendFile](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L211>)
|
||||
### func \(\*ConfigMap\) [AppendFile](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L213>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) AppendFile(path string) error
|
||||
@@ -185,7 +185,7 @@ func (c *ConfigMap) AppendFile(path string) error
|
||||
|
||||
|
||||
<a name="ConfigMap.Filename"></a>
|
||||
### func \(\*ConfigMap\) [Filename](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L235>)
|
||||
### func \(\*ConfigMap\) [Filename](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L237>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) Filename() string
|
||||
@@ -194,7 +194,7 @@ func (c *ConfigMap) Filename() string
|
||||
Filename returns the filename of the configmap. If the configmap is used for files, the filename contains the path.
|
||||
|
||||
<a name="ConfigMap.SetData"></a>
|
||||
### func \(\*ConfigMap\) [SetData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L245>)
|
||||
### func \(\*ConfigMap\) [SetData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L247>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) SetData(data map[string]string)
|
||||
@@ -203,7 +203,7 @@ func (c *ConfigMap) SetData(data map[string]string)
|
||||
SetData sets the data of the configmap. It replaces the entire data.
|
||||
|
||||
<a name="ConfigMap.Yaml"></a>
|
||||
### func \(\*ConfigMap\) [Yaml](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L250>)
|
||||
### func \(\*ConfigMap\) [Yaml](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L252>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) Yaml() ([]byte, error)
|
||||
@@ -275,7 +275,7 @@ Yaml returns the yaml representation of the cronjob.
|
||||
Implements the Yaml interface.
|
||||
|
||||
<a name="CronJobValue"></a>
|
||||
## type [CronJobValue](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L113-L118>)
|
||||
## type [CronJobValue](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L118-L123>)
|
||||
|
||||
CronJobValue is a cronjob configuration that will be saved in values.yaml.
|
||||
|
||||
@@ -376,7 +376,7 @@ func (d *Deployment) BindFrom(service types.ServiceConfig, binded *Deployment)
|
||||
|
||||
|
||||
<a name="Deployment.BindMapFilesToContainer"></a>
|
||||
### func \(\*Deployment\) [BindMapFilesToContainer](<https://github.com/metal3d/katenary/blob/develop/generator/deployment.go#L377>)
|
||||
### func \(\*Deployment\) [BindMapFilesToContainer](<https://github.com/metal3d/katenary/blob/develop/generator/deployment.go#L374>)
|
||||
|
||||
```go
|
||||
func (d *Deployment) BindMapFilesToContainer(service types.ServiceConfig, secrets []string, appName string) (*corev1.Container, int)
|
||||
@@ -403,7 +403,7 @@ func (d *Deployment) Filename() string
|
||||
Filename returns the filename of the deployment.
|
||||
|
||||
<a name="Deployment.MountExchangeVolumes"></a>
|
||||
### func \(\*Deployment\) [MountExchangeVolumes](<https://github.com/metal3d/katenary/blob/develop/generator/deployment.go#L428>)
|
||||
### func \(\*Deployment\) [MountExchangeVolumes](<https://github.com/metal3d/katenary/blob/develop/generator/deployment.go#L425>)
|
||||
|
||||
```go
|
||||
func (d *Deployment) MountExchangeVolumes()
|
||||
@@ -421,7 +421,7 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string, sam
|
||||
SetEnvFrom sets the environment variables to a configmap. The configmap is created.
|
||||
|
||||
<a name="Deployment.Yaml"></a>
|
||||
### func \(\*Deployment\) [Yaml](<https://github.com/metal3d/katenary/blob/develop/generator/deployment.go#L452>)
|
||||
### func \(\*Deployment\) [Yaml](<https://github.com/metal3d/katenary/blob/develop/generator/deployment.go#L449>)
|
||||
|
||||
```go
|
||||
func (d *Deployment) Yaml() ([]byte, error)
|
||||
@@ -471,7 +471,7 @@ type HelmChart struct {
|
||||
```
|
||||
|
||||
<a name="Generate"></a>
|
||||
### func [Generate](<https://github.com/metal3d/katenary/blob/develop/generator/generator.go#L29>)
|
||||
### func [Generate](<https://github.com/metal3d/katenary/blob/develop/generator/generator.go#L31>)
|
||||
|
||||
```go
|
||||
func Generate(project *types.Project) (*HelmChart, error)
|
||||
@@ -509,7 +509,7 @@ func (chart *HelmChart) SaveTemplates(templateDir string)
|
||||
SaveTemplates the templates of the chart to the given directory.
|
||||
|
||||
<a name="Ingress"></a>
|
||||
## type [Ingress](<https://github.com/metal3d/katenary/blob/develop/generator/ingress.go#L17-L20>)
|
||||
## type [Ingress](<https://github.com/metal3d/katenary/blob/develop/generator/ingress.go#L17-L21>)
|
||||
|
||||
|
||||
|
||||
@@ -521,7 +521,7 @@ type Ingress struct {
|
||||
```
|
||||
|
||||
<a name="NewIngress"></a>
|
||||
### func [NewIngress](<https://github.com/metal3d/katenary/blob/develop/generator/ingress.go#L23>)
|
||||
### func [NewIngress](<https://github.com/metal3d/katenary/blob/develop/generator/ingress.go#L24>)
|
||||
|
||||
```go
|
||||
func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress
|
||||
@@ -530,7 +530,7 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress
|
||||
NewIngress creates a new Ingress from a compose service.
|
||||
|
||||
<a name="Ingress.Filename"></a>
|
||||
### func \(\*Ingress\) [Filename](<https://github.com/metal3d/katenary/blob/develop/generator/ingress.go#L122>)
|
||||
### func \(\*Ingress\) [Filename](<https://github.com/metal3d/katenary/blob/develop/generator/ingress.go#L128>)
|
||||
|
||||
```go
|
||||
func (ingress *Ingress) Filename() string
|
||||
@@ -539,7 +539,7 @@ func (ingress *Ingress) Filename() string
|
||||
|
||||
|
||||
<a name="Ingress.Yaml"></a>
|
||||
### func \(\*Ingress\) [Yaml](<https://github.com/metal3d/katenary/blob/develop/generator/ingress.go#L126>)
|
||||
### func \(\*Ingress\) [Yaml](<https://github.com/metal3d/katenary/blob/develop/generator/ingress.go#L132>)
|
||||
|
||||
```go
|
||||
func (ingress *Ingress) Yaml() ([]byte, error)
|
||||
@@ -548,7 +548,7 @@ func (ingress *Ingress) Yaml() ([]byte, error)
|
||||
|
||||
|
||||
<a name="IngressValue"></a>
|
||||
## type [IngressValue](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L28-L35>)
|
||||
## type [IngressValue](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L29-L36>)
|
||||
|
||||
IngressValue is a ingress configuration that will be saved in values.yaml.
|
||||
|
||||
@@ -809,18 +809,19 @@ func (r *ServiceAccount) Yaml() ([]byte, error)
|
||||
|
||||
|
||||
<a name="TLS"></a>
|
||||
## type [TLS](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L23-L25>)
|
||||
## type [TLS](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L23-L26>)
|
||||
|
||||
|
||||
|
||||
```go
|
||||
type TLS struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
SecretName string `yaml:"secretName"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Value"></a>
|
||||
## type [Value](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L38-L49>)
|
||||
## type [Value](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L39-L50>)
|
||||
|
||||
Value will be saved in values.yaml. It contains configuration for all deployment and services.
|
||||
|
||||
@@ -840,7 +841,7 @@ type Value struct {
|
||||
```
|
||||
|
||||
<a name="NewValue"></a>
|
||||
### func [NewValue](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L56>)
|
||||
### func [NewValue](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L57>)
|
||||
|
||||
```go
|
||||
func NewValue(service types.ServiceConfig, main ...bool) *Value
|
||||
@@ -851,7 +852,7 @@ NewValue creates a new Value from a compose service. The value contains the nece
|
||||
If \`main\` is true, the tag will be empty because it will be set in the helm chart appVersion.
|
||||
|
||||
<a name="Value.AddIngress"></a>
|
||||
### func \(\*Value\) [AddIngress](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L89>)
|
||||
### func \(\*Value\) [AddIngress](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L90>)
|
||||
|
||||
```go
|
||||
func (v *Value) AddIngress(host, path string)
|
||||
@@ -860,7 +861,7 @@ func (v *Value) AddIngress(host, path string)
|
||||
|
||||
|
||||
<a name="Value.AddPersistence"></a>
|
||||
### func \(\*Value\) [AddPersistence](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L99>)
|
||||
### func \(\*Value\) [AddPersistence](<https://github.com/metal3d/katenary/blob/develop/generator/values.go#L104>)
|
||||
|
||||
```go
|
||||
func (v *Value) AddPersistence(volumeName string)
|
||||
|
@@ -17,7 +17,7 @@ func NotesFile(services []string) string
|
||||
NotesFile returns the content of the note.txt file.
|
||||
|
||||
<a name="ReadMeFile"></a>
|
||||
## func [ReadMeFile](<https://github.com/metal3d/katenary/blob/develop/generator/extrafiles/readme.go#L45>)
|
||||
## func [ReadMeFile](<https://github.com/metal3d/katenary/blob/develop/generator/extrafiles/readme.go#L46>)
|
||||
|
||||
```go
|
||||
func ReadMeFile(charname, description string, values map[string]any) string
|
||||
|
@@ -12,7 +12,7 @@ A katenary file, named "katenary.yml" or "katenary.yaml", is a file where you ca
|
||||
|
||||
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.
|
||||
|
||||
## func [GenerateSchema](<https://github.com/metal3d/katenary/blob/develop/generator/katenaryfile/main.go#L131>)
|
||||
## func [GenerateSchema](<https://github.com/metal3d/katenary/blob/develop/generator/katenaryfile/main.go#L137>)
|
||||
|
||||
```go
|
||||
func GenerateSchema() string
|
||||
|
@@ -15,7 +15,7 @@ const KatenaryLabelPrefix = "katenary.v3"
|
||||
```
|
||||
|
||||
<a name="GetLabelHelp"></a>
|
||||
## func [GetLabelHelp](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L87>)
|
||||
## func [GetLabelHelp](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L88>)
|
||||
|
||||
```go
|
||||
func GetLabelHelp(asMarkdown bool) string
|
||||
@@ -24,7 +24,7 @@ func GetLabelHelp(asMarkdown bool) string
|
||||
Generate the help for the labels.
|
||||
|
||||
<a name="GetLabelHelpFor"></a>
|
||||
## func [GetLabelHelpFor](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L96>)
|
||||
## func [GetLabelHelpFor](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L97>)
|
||||
|
||||
```go
|
||||
func GetLabelHelpFor(labelname string, asMarkdown bool) string
|
||||
@@ -33,7 +33,7 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string
|
||||
GetLabelHelpFor returns the help for a specific label.
|
||||
|
||||
<a name="GetLabelNames"></a>
|
||||
## func [GetLabelNames](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L71>)
|
||||
## func [GetLabelNames](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L72>)
|
||||
|
||||
```go
|
||||
func GetLabelNames() []string
|
||||
@@ -42,7 +42,7 @@ func GetLabelNames() []string
|
||||
GetLabelNames returns a sorted list of all katenary label names.
|
||||
|
||||
<a name="Prefix"></a>
|
||||
## func [Prefix](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L224>)
|
||||
## func [Prefix](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L235>)
|
||||
|
||||
```go
|
||||
func Prefix() string
|
||||
@@ -51,7 +51,7 @@ func Prefix() string
|
||||
|
||||
|
||||
<a name="Help"></a>
|
||||
## type [Help](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L63-L68>)
|
||||
## type [Help](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L64-L69>)
|
||||
|
||||
Help is the documentation of a label.
|
||||
|
||||
@@ -65,7 +65,7 @@ type Help struct {
|
||||
```
|
||||
|
||||
<a name="Label"></a>
|
||||
## type [Label](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L56>)
|
||||
## type [Label](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L57>)
|
||||
|
||||
Label is a katenary label to find in compose files.
|
||||
|
||||
@@ -97,7 +97,7 @@ const (
|
||||
```
|
||||
|
||||
<a name="LabelName"></a>
|
||||
### func [LabelName](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L58>)
|
||||
### func [LabelName](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L59>)
|
||||
|
||||
```go
|
||||
func LabelName(name string) Label
|
||||
|
@@ -1,60 +0,0 @@
|
||||
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||
|
||||
# update
|
||||
|
||||
```go
|
||||
import "katenary/update"
|
||||
```
|
||||
|
||||
Update package is used to check if a new version of katenary is available.
|
||||
|
||||
## Variables
|
||||
|
||||
<a name="Version"></a>
|
||||
|
||||
```go
|
||||
var (
|
||||
Version = "master" // reset by cmd/main.go
|
||||
)
|
||||
```
|
||||
|
||||
<a name="DownloadFile"></a>
|
||||
## func [DownloadFile](<https://github.com/metal3d/katenary/blob/develop/update/main.go#L134>)
|
||||
|
||||
```go
|
||||
func DownloadFile(url, exe string) error
|
||||
```
|
||||
|
||||
DownloadFile will download a url to a local file. It also ensure that the file is executable.
|
||||
|
||||
<a name="DownloadLatestVersion"></a>
|
||||
## func [DownloadLatestVersion](<https://github.com/metal3d/katenary/blob/develop/update/main.go#L80>)
|
||||
|
||||
```go
|
||||
func DownloadLatestVersion(assets []Asset) error
|
||||
```
|
||||
|
||||
DownloadLatestVersion will download the latest version of katenary.
|
||||
|
||||
<a name="Asset"></a>
|
||||
## type [Asset](<https://github.com/metal3d/katenary/blob/develop/update/main.go#L23-L26>)
|
||||
|
||||
Asset is a github asset from release url.
|
||||
|
||||
```go
|
||||
type Asset struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"browser_download_url"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="CheckLatestVersion"></a>
|
||||
### func [CheckLatestVersion](<https://github.com/metal3d/katenary/blob/develop/update/main.go#L29>)
|
||||
|
||||
```go
|
||||
func CheckLatestVersion() (string, []Asset, error)
|
||||
```
|
||||
|
||||
CheckLatestVersion check katenary latest version from release and propose to download it
|
||||
|
||||
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
|
@@ -8,7 +8,7 @@ import "katenary/utils"
|
||||
|
||||
Utils package provides some utility functions used in katenary. It defines some constants and functions used in the whole project.
|
||||
|
||||
## func [AsResourceName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L191>)
|
||||
## func [AsResourceName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L193>)
|
||||
|
||||
```go
|
||||
func AsResourceName(name string) string
|
||||
@@ -35,7 +35,7 @@ func CountStartingSpaces(line string) int
|
||||
CountStartingSpaces counts the number of spaces at the beginning of a string.
|
||||
|
||||
<a name="EncodeBasicYaml"></a>
|
||||
## func [EncodeBasicYaml](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L173>)
|
||||
## func [EncodeBasicYaml](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L175>)
|
||||
|
||||
```go
|
||||
func EncodeBasicYaml(data any) ([]byte, error)
|
||||
@@ -44,7 +44,7 @@ func EncodeBasicYaml(data any) ([]byte, error)
|
||||
EncodeBasicYaml encodes a basic yaml from an interface.
|
||||
|
||||
<a name="FixedResourceName"></a>
|
||||
## func [FixedResourceName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L185>)
|
||||
## func [FixedResourceName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L187>)
|
||||
|
||||
```go
|
||||
func FixedResourceName(name string) string
|
||||
@@ -146,7 +146,7 @@ GetContainerByName returns a container by name and its index in the array.
|
||||
## func [Warn](<https://github.com/metal3d/katenary/blob/develop/utils/icons.go#L25>)
|
||||
|
||||
```go
|
||||
func Warn(msg ...interface{})
|
||||
func Warn(msg ...any)
|
||||
```
|
||||
|
||||
Warn prints a warning message
|
||||
|
@@ -54,7 +54,6 @@ nav:
|
||||
- Go Packages:
|
||||
- packages/cmd/katenary.md
|
||||
- packages/parser.md
|
||||
- packages/update.md
|
||||
- packages/utils.md
|
||||
- Generator:
|
||||
- Index: packages/generator.md
|
||||
|
@@ -6,8 +6,10 @@ import (
|
||||
"katenary/generator/labels/labelStructs"
|
||||
"katenary/utils"
|
||||
"log"
|
||||
"maps"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
@@ -42,7 +44,7 @@ type HelmChart struct {
|
||||
composeHash *string `yaml:"-"`
|
||||
Name string `yaml:"name"`
|
||||
Icon string `yaml:"icon,omitempty"`
|
||||
ApiVersion string `yaml:"apiVersion"`
|
||||
APIVersion string `yaml:"apiVersion"`
|
||||
Version string `yaml:"version"`
|
||||
AppVersion string `yaml:"appVersion"`
|
||||
Description string `yaml:"description"`
|
||||
@@ -56,7 +58,7 @@ func NewChart(name string) *HelmChart {
|
||||
Name: name,
|
||||
Templates: make(map[string]*ChartTemplate, 0),
|
||||
Description: "A Helm chart for " + name,
|
||||
ApiVersion: "v2",
|
||||
APIVersion: "v2",
|
||||
Version: "",
|
||||
AppVersion: "", // set to 0.1.0 by default if no "main-app" label is found
|
||||
Values: map[string]any{
|
||||
@@ -116,9 +118,11 @@ func (chart *HelmChart) SaveTemplates(templateDir string) {
|
||||
fmt.Println(utils.IconFailure, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := f.Write(t); err != nil {
|
||||
log.Fatal("error writing template file:", err)
|
||||
}
|
||||
|
||||
f.Write(t)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +130,7 @@ func (chart *HelmChart) SaveTemplates(templateDir string) {
|
||||
func (chart *HelmChart) generateConfigMapsAndSecrets(project *types.Project) error {
|
||||
appName := chart.Name
|
||||
for _, s := range project.Services {
|
||||
if s.Environment == nil || len(s.Environment) == 0 {
|
||||
if len(s.Environment) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -134,9 +138,7 @@ func (chart *HelmChart) generateConfigMapsAndSecrets(project *types.Project) err
|
||||
secretsVar := types.MappingWithEquals{}
|
||||
|
||||
// copy env to originalEnv
|
||||
for k, v := range s.Environment {
|
||||
originalEnv[k] = v
|
||||
}
|
||||
maps.Copy(originalEnv, s.Environment)
|
||||
|
||||
if v, ok := s.Labels[labels.LabelSecrets]; ok {
|
||||
list, err := labelStructs.SecretsFrom(v)
|
||||
@@ -372,7 +374,7 @@ func (chart *HelmChart) setEnvironmentValuesFrom(service types.ServiceConfig, de
|
||||
if dep == nil || target == nil {
|
||||
log.Fatalf("deployment %s or %s not found", depName[0], service.Name)
|
||||
}
|
||||
container, index := utils.GetContainerByName(target.service.Name, target.Spec.Template.Spec.Containers)
|
||||
container, index := utils.GetContainerByName(target.service.ContainerName, target.Spec.Template.Spec.Containers)
|
||||
if container == nil {
|
||||
log.Fatalf("Container %s not found", target.GetName())
|
||||
}
|
||||
@@ -383,11 +385,8 @@ func (chart *HelmChart) setEnvironmentValuesFrom(service types.ServiceConfig, de
|
||||
isSecret := false
|
||||
secrets, err := labelStructs.SecretsFrom(dep.service.Labels[labels.LabelSecrets])
|
||||
if err == nil {
|
||||
for _, secret := range secrets {
|
||||
if secret == depName[1] {
|
||||
if slices.Contains(secrets, depName[1]) {
|
||||
isSecret = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -142,7 +142,9 @@ func NewConfigMapFromDirectory(service types.ServiceConfig, appName, path string
|
||||
// cumulate the path to the WorkingDir
|
||||
path = filepath.Join(service.WorkingDir, path)
|
||||
path = filepath.Clean(path)
|
||||
cm.AppendDir(path)
|
||||
if err := cm.AppendDir(path); err != nil {
|
||||
log.Fatal("Error adding files to configmap:", err)
|
||||
}
|
||||
return cm
|
||||
}
|
||||
|
||||
@@ -159,13 +161,13 @@ func (c *ConfigMap) AddBinaryData(key string, value []byte) {
|
||||
c.BinaryData[key] = value
|
||||
}
|
||||
|
||||
// AddFile adds files from given path to the configmap. It is not recursive, to add all files in a directory,
|
||||
// AppendDir adds files from given path to the configmap. It is not recursive, to add all files in a directory,
|
||||
// you need to call this function for each subdirectory.
|
||||
func (c *ConfigMap) AppendDir(path string) error {
|
||||
// read all files in the path and add them to the configmap
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Path %s does not exist, %w\n", path, err)
|
||||
return fmt.Errorf("path %s does not exist, %w", path, err)
|
||||
}
|
||||
// recursively read all files in the path and add them to the configmap
|
||||
if stat.IsDir() {
|
||||
@@ -212,7 +214,7 @@ func (c *ConfigMap) AppendFile(path string) error {
|
||||
// read all files in the path and add them to the configmap
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Path %s doesn not exists, %w", path, err)
|
||||
return fmt.Errorf("path %s doesn not exists, %w", path, err)
|
||||
}
|
||||
// recursively read all files in the path and add them to the configmap
|
||||
if !stat.IsDir() {
|
||||
|
@@ -113,7 +113,11 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) error {
|
||||
fmt.Println(utils.IconFailure, err)
|
||||
return err
|
||||
}
|
||||
defer os.Chdir(currentDir) // after the generation, go back to the original directory
|
||||
defer func() {
|
||||
if err := os.Chdir(currentDir); err != nil { // after the generation, go back to the original directory
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// repove the directory part of the docker-compose files
|
||||
for i, f := range dockerComposeFile {
|
||||
@@ -627,7 +631,11 @@ func writeContent(path string, content []byte) {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
f.Write(content)
|
||||
defer func() {
|
||||
if _, err := f.Write(content); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// helmLint runs "helm lint" on the output directory.
|
||||
|
@@ -131,7 +131,7 @@ func (d *Deployment) AddContainer(service types.ServiceConfig) {
|
||||
Image: utils.TplValue(service.Name, "repository.image") + ":" +
|
||||
utils.TplValue(service.Name, "repository.tag", d.defaultTag),
|
||||
Ports: ports,
|
||||
Name: service.Name,
|
||||
Name: service.ContainerName,
|
||||
ImagePullPolicy: corev1.PullIfNotPresent,
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{},
|
||||
@@ -253,8 +253,8 @@ func (d *Deployment) BindFrom(service types.ServiceConfig, binded *Deployment) {
|
||||
// get the container
|
||||
}
|
||||
// add volume mount to the container
|
||||
targetContainer, ti := utils.GetContainerByName(service.Name, d.Spec.Template.Spec.Containers)
|
||||
sourceContainer, _ := utils.GetContainerByName(service.Name, binded.Spec.Template.Spec.Containers)
|
||||
targetContainer, ti := utils.GetContainerByName(service.ContainerName, d.Spec.Template.Spec.Containers)
|
||||
sourceContainer, _ := utils.GetContainerByName(service.ContainerName, binded.Spec.Template.Spec.Containers)
|
||||
for _, bindedMount := range sourceContainer.VolumeMounts {
|
||||
if bindedMount.Name == bindedVolume.Name {
|
||||
targetContainer.VolumeMounts = append(targetContainer.VolumeMounts, bindedMount)
|
||||
@@ -305,10 +305,7 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string, sam
|
||||
if len(service.Environment) == 0 {
|
||||
return
|
||||
}
|
||||
inSamePod := false
|
||||
if len(samePod) > 0 && samePod[0] {
|
||||
inSamePod = true
|
||||
}
|
||||
inSamePod := len(samePod) > 0 && samePod[0]
|
||||
|
||||
drop := []string{}
|
||||
secrets := []string{}
|
||||
@@ -411,7 +408,7 @@ func (d *Deployment) BindMapFilesToContainer(service types.ServiceConfig, secret
|
||||
})
|
||||
}
|
||||
|
||||
container, index := utils.GetContainerByName(service.Name, d.Spec.Template.Spec.Containers)
|
||||
container, index := utils.GetContainerByName(service.ContainerName, d.Spec.Template.Spec.Containers)
|
||||
if container == nil {
|
||||
utils.Warn("Container not found for service " + service.Name)
|
||||
return nil, -1
|
||||
@@ -660,11 +657,13 @@ func (d *Deployment) appendFileToConfigMap(service types.ServiceConfig, appName
|
||||
d.configMaps[pathname].mountPath = mp
|
||||
|
||||
}
|
||||
cm.AppendFile(volume.Source)
|
||||
if err := cm.AppendFile(volume.Source); err != nil {
|
||||
log.Fatal("Error adding file to configmap:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Deployment) bindVolumes(volume types.ServiceVolumeConfig, isSamePod bool, tobind map[string]bool, service types.ServiceConfig, appName string) {
|
||||
container, index := utils.GetContainerByName(service.Name, d.Spec.Template.Spec.Containers)
|
||||
container, index := utils.GetContainerByName(service.ContainerName, d.Spec.Template.Spec.Containers)
|
||||
|
||||
defer func(d *Deployment, container *corev1.Container, index int) {
|
||||
d.Spec.Template.Spec.Containers[index] = *container
|
||||
|
@@ -4,8 +4,10 @@ import (
|
||||
"fmt"
|
||||
"katenary/generator/labels"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
yaml3 "gopkg.in/yaml.v3"
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
@@ -324,14 +326,172 @@ services:
|
||||
Environment map[string]string `yaml:"environment"`
|
||||
} `yaml:"web"`
|
||||
}{}
|
||||
if err := yaml.Unmarshal(valuesContent, &mapping); err != nil {
|
||||
if err := yaml3.Unmarshal(valuesContent, &mapping); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
}
|
||||
|
||||
if _, ok := mapping.Web.Environment["FOO"]; !ok {
|
||||
if v, ok := mapping.Web.Environment["FOO"]; !ok {
|
||||
t.Errorf("Expected FOO in web environment")
|
||||
if v != "bar" {
|
||||
t.Errorf("Expected FOO to be bar, got %s", v)
|
||||
}
|
||||
if _, ok := mapping.Web.Environment["BAZ"]; ok {
|
||||
}
|
||||
if v, ok := mapping.Web.Environment["BAZ"]; ok {
|
||||
t.Errorf("Expected BAZ not in web environment")
|
||||
if v != "qux" {
|
||||
t.Errorf("Expected BAZ to be qux, got %s", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithUnderscoreInContainerName(t *testing.T) {
|
||||
composeFile := `
|
||||
services:
|
||||
web-app:
|
||||
image: nginx:1.29
|
||||
container_name: web_app_container
|
||||
environment:
|
||||
FOO: BAR
|
||||
labels:
|
||||
%s/values: |
|
||||
- FOO
|
||||
`
|
||||
composeFile = fmt.Sprintf(composeFile, labels.Prefix())
|
||||
tmpDir := setup(composeFile)
|
||||
defer teardown(tmpDir)
|
||||
|
||||
currentDir, _ := os.Getwd()
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(t, "-s", "templates/web_app/deployment.yaml")
|
||||
dt := v1.Deployment{}
|
||||
if err := yaml.Unmarshal([]byte(output), &dt); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
}
|
||||
// find container.name
|
||||
containerName := dt.Spec.Template.Spec.Containers[0].Name
|
||||
if strings.Contains(containerName, "_") {
|
||||
t.Errorf("Expected container name to not contain underscores, got %s", containerName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithDashes(t *testing.T) {
|
||||
composeFile := `
|
||||
services:
|
||||
web-app:
|
||||
image: nginx:1.29
|
||||
environment:
|
||||
FOO: BAR
|
||||
labels:
|
||||
%s/values: |
|
||||
- FOO
|
||||
`
|
||||
|
||||
composeFile = fmt.Sprintf(composeFile, labels.Prefix())
|
||||
tmpDir := setup(composeFile)
|
||||
defer teardown(tmpDir)
|
||||
|
||||
currentDir, _ := os.Getwd()
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(t, "-s", "templates/web_app/deployment.yaml")
|
||||
dt := v1.Deployment{}
|
||||
if err := yaml.Unmarshal([]byte(output), &dt); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
}
|
||||
|
||||
valuesFile := "./chart/values.yaml"
|
||||
if _, err := os.Stat(valuesFile); os.IsNotExist(err) {
|
||||
t.Errorf("values.yaml does not exist")
|
||||
}
|
||||
valuesContent, err := os.ReadFile(valuesFile)
|
||||
if err != nil {
|
||||
t.Errorf("Error reading values.yaml: %s", err)
|
||||
}
|
||||
mapping := struct {
|
||||
Web struct {
|
||||
Environment map[string]string `yaml:"environment"`
|
||||
} `yaml:"web_app"`
|
||||
}{}
|
||||
if err := yaml3.Unmarshal(valuesContent, &mapping); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
}
|
||||
|
||||
// we must have FOO in web_app environment (not web-app)
|
||||
// this validates that the service name is converted to a valid k8s name
|
||||
if v, ok := mapping.Web.Environment["FOO"]; !ok {
|
||||
t.Errorf("Expected FOO in web_app environment")
|
||||
if v != "BAR" {
|
||||
t.Errorf("Expected FOO to be BAR, got %s", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDashesWithValueFrom(t *testing.T) {
|
||||
composeFile := `
|
||||
services:
|
||||
web-app:
|
||||
image: nginx:1.29
|
||||
environment:
|
||||
FOO: BAR
|
||||
labels:
|
||||
%[1]s/values: |
|
||||
- FOO
|
||||
web2:
|
||||
image: nginx:1.29
|
||||
labels:
|
||||
%[1]s/values-from: |
|
||||
BAR: web-app.FOO
|
||||
`
|
||||
|
||||
composeFile = fmt.Sprintf(composeFile, labels.Prefix())
|
||||
tmpDir := setup(composeFile)
|
||||
defer teardown(tmpDir)
|
||||
|
||||
currentDir, _ := os.Getwd()
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(t, "-s", "templates/web2/deployment.yaml")
|
||||
dt := v1.Deployment{}
|
||||
if err := yaml.Unmarshal([]byte(output), &dt); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
}
|
||||
|
||||
valuesFile := "./chart/values.yaml"
|
||||
if _, err := os.Stat(valuesFile); os.IsNotExist(err) {
|
||||
t.Errorf("values.yaml does not exist")
|
||||
}
|
||||
valuesContent, err := os.ReadFile(valuesFile)
|
||||
if err != nil {
|
||||
t.Errorf("Error reading values.yaml: %s", err)
|
||||
}
|
||||
mapping := struct {
|
||||
Web struct {
|
||||
Environment map[string]string `yaml:"environment"`
|
||||
} `yaml:"web_app"`
|
||||
}{}
|
||||
if err := yaml3.Unmarshal(valuesContent, &mapping); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
}
|
||||
|
||||
// we must have FOO in web_app environment (not web-app)
|
||||
// this validates that the service name is converted to a valid k8s name
|
||||
if v, ok := mapping.Web.Environment["FOO"]; !ok {
|
||||
t.Errorf("Expected FOO in web_app environment")
|
||||
if v != "BAR" {
|
||||
t.Errorf("Expected FOO to be BAR, got %s", v)
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that the deployment has the value from the other service
|
||||
barenv := dt.Spec.Template.Spec.Containers[0].Env[0]
|
||||
if barenv.Value != "" {
|
||||
t.Errorf("Expected value to be empty")
|
||||
}
|
||||
if barenv.ValueFrom == nil {
|
||||
t.Errorf("Expected valueFrom to be set")
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,17 @@
|
||||
/*
|
||||
The generator package generates kubernetes objects from a "compose" file and transforms them into a helm chart.
|
||||
Package generator generates kubernetes objects from a "compose" file and transforms them into a helm chart.
|
||||
|
||||
The generator package is the core of katenary. It is responsible for generating kubernetes objects from a compose file and transforming them into a helm chart.
|
||||
Conversion manipulates Yaml representation of kubernetes object to add conditions, labels, annotations, etc. to the objects. It also create the values to be set to
|
||||
the values.yaml file.
|
||||
The generator package is the core of katenary. It is responsible for generating kubernetes objects from a compose file
|
||||
and transforming them into a helm chart.
|
||||
Conversion manipulates Yaml representation of kubernetes object to add conditions, labels, annotations, etc. to the
|
||||
objects. It also create the values to be set to the values.yaml file.
|
||||
|
||||
The generate.Convert() create an HelmChart object and call "Generate()" method to convert from a compose file to a helm chart.
|
||||
It saves the helm chart in the given directory.
|
||||
The generate.Convert() create an HelmChart object and call "Generate()" method to convert from a compose file to a helm
|
||||
chart. It saves the helm chart in the given directory.
|
||||
|
||||
If you want to change or override the write behavior, you can use the HelmChart.Generate() function and implement your own write function. This function returns
|
||||
the helm chart object containing all kubernetes objects and helm chart ingormation. It does not write the helm chart to the disk.
|
||||
If you want to change or override the write behavior, you can use the HelmChart.Generate() function and implement your
|
||||
own write function. This function returns
|
||||
the helm chart object containing all kubernetes objects and helm chart ingormation. It does not write the helm chart to
|
||||
the disk.
|
||||
*/
|
||||
package generator
|
||||
|
@@ -1,2 +1,2 @@
|
||||
/* extrafiles package provides function to generate the Chart files that are not objects. Like README.md and notes.txt... */
|
||||
/* Package extrafiles provides function to generate the Chart files that are not objects. Like README.md and notes.txt... */
|
||||
package extrafiles
|
||||
|
40
generator/extrafiles/notes_test.go
Normal file
40
generator/extrafiles/notes_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package extrafiles
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// override the embedded template for testing
|
||||
var testTemplate = `
|
||||
Some header
|
||||
{{ ingress_list }}
|
||||
Some footer
|
||||
`
|
||||
|
||||
func init() {
|
||||
notesTemplate = testTemplate
|
||||
}
|
||||
|
||||
func TestNotesFile_NoServices(t *testing.T) {
|
||||
result := NotesFile([]string{})
|
||||
if !strings.Contains(result, "Some header") || !strings.Contains(result, "Some footer") {
|
||||
t.Errorf("Expected template header/footer in output, got: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotesFile_WithServices(t *testing.T) {
|
||||
services := []string{"svc1", "svc2"}
|
||||
result := NotesFile(services)
|
||||
|
||||
for _, svc := range services {
|
||||
cond := "{{- if and .Values." + svc + ".ingress .Values." + svc + ".ingress.enabled }}"
|
||||
line := "{{- $count = add1 $count -}}{{- $listOfURL = printf \"%s\\n- http://%s\" $listOfURL (tpl .Values." + svc + ".ingress.host .) -}}"
|
||||
if !strings.Contains(result, cond) {
|
||||
t.Errorf("Expected condition for service %s in output", svc)
|
||||
}
|
||||
if !strings.Contains(result, line) {
|
||||
t.Errorf("Expected line for service %s in output", svc)
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
@@ -20,7 +21,7 @@ type chart struct {
|
||||
Values []string
|
||||
}
|
||||
|
||||
func parseValues(prefix string, values map[string]interface{}, result map[string]string) {
|
||||
func parseValues(prefix string, values map[string]any, result map[string]string) {
|
||||
for key, value := range values {
|
||||
path := key
|
||||
if prefix != "" {
|
||||
@@ -28,11 +29,11 @@ func parseValues(prefix string, values map[string]interface{}, result map[string
|
||||
}
|
||||
|
||||
switch v := value.(type) {
|
||||
case []interface{}:
|
||||
case []any:
|
||||
for i, u := range v {
|
||||
parseValues(fmt.Sprintf("%s[%d]", path, i), map[string]interface{}{"value": u}, result)
|
||||
parseValues(fmt.Sprintf("%s[%d]", path, i), map[string]any{"value": u}, result)
|
||||
}
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
parseValues(path, v, result)
|
||||
default:
|
||||
strValue := fmt.Sprintf("`%v`", value)
|
||||
@@ -48,7 +49,9 @@ func ReadMeFile(charname, description string, values map[string]any) string {
|
||||
|
||||
vv := map[string]any{}
|
||||
out, _ := yaml.Marshal(values)
|
||||
yaml.Unmarshal(out, &vv)
|
||||
if err := yaml.Unmarshal(out, &vv); err != nil {
|
||||
log.Printf("Error parsing values: %s", err)
|
||||
}
|
||||
|
||||
result := make(map[string]string)
|
||||
parseValues("", vv, result)
|
||||
|
33
generator/extrafiles/readme_test.go
Normal file
33
generator/extrafiles/readme_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package extrafiles
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadMeFile_Basic(t *testing.T) {
|
||||
values := map[string]any{
|
||||
"replicas": 2,
|
||||
"image": map[string]any{
|
||||
"repository": "nginx",
|
||||
"tag": "latest",
|
||||
},
|
||||
}
|
||||
|
||||
result := ReadMeFile("testchart", "A test chart", values)
|
||||
t.Logf("Generated README content:\n%s", result)
|
||||
paramerRegExp := regexp.MustCompile(`\|\s+` + "`" + `(.*?)` + "`" + `\s+\|\s+` + "`" + `(.*?)` + "`" + `\s+\|`)
|
||||
matches := paramerRegExp.FindAllStringSubmatch(result, -1)
|
||||
if len(matches) != 3 {
|
||||
t.Errorf("Expected 5 lines in the table for headers and parameters, got %d", len(matches))
|
||||
}
|
||||
if matches[0][1] != "image.repository" || matches[0][2] != "nginx" {
|
||||
t.Errorf("Expected third line to be image.repository, got %s", matches[1])
|
||||
}
|
||||
if matches[1][1] != "image.tag" || matches[1][2] != "latest" {
|
||||
t.Errorf("Expected fourth line to be image.tag, got %s", matches[2])
|
||||
}
|
||||
if matches[2][1] != "replicas" || matches[2][2] != "2" {
|
||||
t.Errorf("Expected second line to be replicas, got %s", matches[0])
|
||||
}
|
||||
}
|
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"katenary/generator/labels"
|
||||
"katenary/generator/labels/labelStructs"
|
||||
"katenary/utils"
|
||||
"log"
|
||||
"regexp"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Generate a chart from a compose project.
|
||||
@@ -43,6 +45,16 @@ func Generate(project *types.Project) (*HelmChart, error) {
|
||||
Annotations[labels.LabelName("compose-hash")] = hash
|
||||
chart.composeHash = &hash
|
||||
|
||||
// drop all services with the "ignore" label
|
||||
dropIngoredServices(project)
|
||||
|
||||
fixContainerNames(project)
|
||||
|
||||
// rename all services name to remove dashes
|
||||
if err := fixResourceNames(project); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// find the "main-app" label, and set chart.AppVersion to the tag if exists
|
||||
mainCount := 0
|
||||
for _, service := range project.Services {
|
||||
@@ -107,7 +119,10 @@ func Generate(project *types.Project) (*HelmChart, error) {
|
||||
for _, s := range project.Services {
|
||||
for _, d := range s.GetDependencies() {
|
||||
if dep, ok := deployments[d]; ok {
|
||||
deployments[s.Name].DependsOn(dep, d)
|
||||
err := deployments[s.Name].DependsOn(dep, d)
|
||||
if err != nil {
|
||||
log.Printf("error creating init container for service %[1]s: %[2]s", s.Name, err)
|
||||
}
|
||||
} else {
|
||||
log.Printf("service %[1]s depends on %[2]s, but %[2]s is not defined", s.Name, d)
|
||||
}
|
||||
@@ -119,7 +134,9 @@ func Generate(project *types.Project) (*HelmChart, error) {
|
||||
}
|
||||
|
||||
// generate configmaps with environment variables
|
||||
chart.generateConfigMapsAndSecrets(project)
|
||||
if err := chart.generateConfigMapsAndSecrets(project); err != nil {
|
||||
log.Fatalf("error generating configmaps and secrets: %s", err)
|
||||
}
|
||||
|
||||
// if the env-from label is set, we need to add the env vars from the configmap
|
||||
// to the environment of the service
|
||||
@@ -187,6 +204,52 @@ func Generate(project *types.Project) (*HelmChart, error) {
|
||||
return chart, nil
|
||||
}
|
||||
|
||||
// dropIngoredServices removes all services with the "ignore" label set to true (or yes).
|
||||
func dropIngoredServices(project *types.Project) {
|
||||
for i, service := range project.Services {
|
||||
if isIgnored(service) {
|
||||
project.Services = append(project.Services[:i], project.Services[i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fixResourceNames renames all services and related resources to remove dashes.
|
||||
func fixResourceNames(project *types.Project) error {
|
||||
// rename all services name to remove dashes
|
||||
for i, service := range project.Services {
|
||||
if service.Name != utils.AsResourceName(service.Name) {
|
||||
fixed := utils.AsResourceName(service.Name)
|
||||
for j, s := range project.Services {
|
||||
// for the same-pod services, we need to keep the original name
|
||||
if samepod, ok := s.Labels[labels.LabelSamePod]; ok && samepod == service.Name {
|
||||
s.Labels[labels.LabelSamePod] = fixed
|
||||
project.Services[j] = s
|
||||
}
|
||||
// also, the value-from label should be updated
|
||||
if valuefrom, ok := s.Labels[labels.LabelValueFrom]; ok {
|
||||
vf, err := labelStructs.GetValueFrom(valuefrom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for varname, bind := range *vf {
|
||||
log.Printf("service %s, varname %s, bind %s", service.Name, varname, bind)
|
||||
bind := strings.ReplaceAll(bind, service.Name, fixed)
|
||||
(*vf)[varname] = bind
|
||||
}
|
||||
output, err := yaml.Marshal(vf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Labels[labels.LabelValueFrom] = string(output)
|
||||
}
|
||||
}
|
||||
service.Name = fixed
|
||||
project.Services[i] = service
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// serviceIsMain returns true if the service is the main app.
|
||||
func serviceIsMain(service types.ServiceConfig) bool {
|
||||
if main, ok := service.Labels[labels.LabelMainApp]; ok {
|
||||
@@ -204,7 +267,7 @@ func addStaticVolumes(deployments map[string]*Deployment, service types.ServiceC
|
||||
return
|
||||
}
|
||||
|
||||
container, index := utils.GetContainerByName(service.Name, d.Spec.Template.Spec.Containers)
|
||||
container, index := utils.GetContainerByName(service.ContainerName, d.Spec.Template.Spec.Containers)
|
||||
if container == nil { // may append for the same-pod services
|
||||
return
|
||||
}
|
||||
@@ -256,7 +319,7 @@ func computeNIndent(b []byte) []byte {
|
||||
startSpaces = spaces[0]
|
||||
}
|
||||
line = []byte(startSpaces + strings.TrimLeft(string(line), " "))
|
||||
line = bytes.ReplaceAll(line, []byte("__indent__"), []byte(fmt.Sprintf("%d", len(startSpaces))))
|
||||
line = bytes.ReplaceAll(line, []byte("__indent__"), fmt.Appendf(nil, "%d", len(startSpaces)))
|
||||
lines[i] = line
|
||||
}
|
||||
return bytes.Join(lines, []byte("\n"))
|
||||
@@ -329,7 +392,7 @@ func samePodVolume(service types.ServiceConfig, v types.ServiceVolumeConfig, dep
|
||||
return false
|
||||
}
|
||||
|
||||
if service.Volumes == nil || len(service.Volumes) == 0 {
|
||||
if len(service.Volumes) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -355,3 +418,15 @@ func samePodVolume(service types.ServiceConfig, v types.ServiceVolumeConfig, dep
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fixContainerNames(project *types.Project) {
|
||||
// fix container names to be unique
|
||||
for i, service := range project.Services {
|
||||
if service.ContainerName == "" {
|
||||
service.ContainerName = utils.FixedResourceName(service.Name)
|
||||
} else {
|
||||
service.ContainerName = utils.FixedResourceName(service.ContainerName)
|
||||
}
|
||||
project.Services[i] = service
|
||||
}
|
||||
}
|
||||
|
@@ -75,24 +75,30 @@ func OverrideWithConfig(project *types.Project) {
|
||||
if project.Services[i].Labels == nil {
|
||||
project.Services[i].Labels = make(map[string]string)
|
||||
}
|
||||
mustGetLabelContent := func(o any, s *types.ServiceConfig, labelName string) {
|
||||
err := getLabelContent(o, s, labelName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
getLabelContent(s.ExchangeVolumes, &project.Services[i], labels.LabelExchangeVolume)
|
||||
getLabelContent(s.ValuesFrom, &project.Services[i], labels.LabelValueFrom)
|
||||
mustGetLabelContent(s.MainApp, &project.Services[i], labels.LabelMainApp)
|
||||
mustGetLabelContent(s.Values, &project.Services[i], labels.LabelValues)
|
||||
mustGetLabelContent(s.Secrets, &project.Services[i], labels.LabelSecrets)
|
||||
mustGetLabelContent(s.Ports, &project.Services[i], labels.LabelPorts)
|
||||
mustGetLabelContent(s.Ingress, &project.Services[i], labels.LabelIngress)
|
||||
mustGetLabelContent(s.HealthCheck, &project.Services[i], labels.LabelHealthCheck)
|
||||
mustGetLabelContent(s.SamePod, &project.Services[i], labels.LabelSamePod)
|
||||
mustGetLabelContent(s.Description, &project.Services[i], labels.LabelDescription)
|
||||
mustGetLabelContent(s.Ignore, &project.Services[i], labels.LabelIgnore)
|
||||
mustGetLabelContent(s.Dependencies, &project.Services[i], labels.LabelDependencies)
|
||||
mustGetLabelContent(s.ConfigMapFile, &project.Services[i], labels.LabelConfigMapFiles)
|
||||
mustGetLabelContent(s.MapEnv, &project.Services[i], labels.LabelMapEnv)
|
||||
mustGetLabelContent(s.CronJob, &project.Services[i], labels.LabelCronJob)
|
||||
mustGetLabelContent(s.EnvFrom, &project.Services[i], labels.LabelEnvFrom)
|
||||
mustGetLabelContent(s.ExchangeVolumes, &project.Services[i], labels.LabelExchangeVolume)
|
||||
mustGetLabelContent(s.ValuesFrom, &project.Services[i], labels.LabelValueFrom)
|
||||
}
|
||||
}
|
||||
fmt.Println(utils.IconInfo, "Katenary file loaded successfully, the services are now configured.")
|
||||
@@ -155,5 +161,5 @@ func GenerateSchema() string {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return string(out.Bytes())
|
||||
return out.String()
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ webapp:
|
||||
// create /tmp/katenary-test-override directory, save the compose.yaml file
|
||||
tmpDir, err := os.MkdirTemp("", "katenary-test-override")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
t.Fatalf("Failed to create temp directory: %s", err.Error())
|
||||
}
|
||||
composeFile := filepath.Join(tmpDir, "compose.yaml")
|
||||
katenaryFile := filepath.Join(tmpDir, "katenary.yaml")
|
||||
@@ -83,7 +83,7 @@ webapp:
|
||||
// create /tmp/katenary-test-override directory, save the compose.yaml file
|
||||
tmpDir, err := os.MkdirTemp("", "katenary-test-override")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
t.Fatalf("Failed to create temp directory: %s", err.Error())
|
||||
}
|
||||
composeFile := filepath.Join(tmpDir, "compose.yaml")
|
||||
katenaryFile := filepath.Join(tmpDir, "katenary.yaml")
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"katenary/utils"
|
||||
"log"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -125,23 +126,30 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string {
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
template.Must(template.New("shorthelp").Parse(help.Long)).Execute(&buf, struct {
|
||||
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()
|
||||
|
||||
template.Must(template.New("example").Parse(help.Example)).Execute(&buf, struct {
|
||||
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()
|
||||
|
||||
template.Must(template.New("complete").Parse(helpTemplate)).Execute(&buf, struct {
|
||||
err = template.Must(template.New("complete").Parse(helpTemplate)).Execute(&buf, struct {
|
||||
Name string
|
||||
Help Help
|
||||
KatenaryPrefix string
|
||||
@@ -150,6 +158,9 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string {
|
||||
Help: help,
|
||||
KatenaryPrefix: KatenaryLabelPrefix,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("Error executing template: %v", err)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
@@ -49,6 +49,7 @@ func internalCompileTest(t *testing.T, options ...string) string {
|
||||
ChartVersion: chartVersion,
|
||||
}
|
||||
if err := Convert(convertOptions, "compose.yml"); err != nil {
|
||||
log.Printf("Failed to convert: %s", err)
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
|
@@ -53,8 +53,8 @@ func fixPorts(service *types.ServiceConfig) error {
|
||||
ports, err := labelStructs.PortsFrom(portsLabel)
|
||||
if err != nil {
|
||||
// maybe it's a string, comma separated
|
||||
parts := strings.Split(portsLabel, ",")
|
||||
for _, part := range parts {
|
||||
parts := strings.SplitSeq(portsLabel, ",")
|
||||
for part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if part == "" {
|
||||
continue
|
||||
@@ -87,7 +87,7 @@ func UnWrapTPL(in []byte) []byte {
|
||||
return regexpLineWrap.ReplaceAll(in, []byte(" }}"))
|
||||
}
|
||||
|
||||
func ToK8SYaml(obj interface{}) ([]byte, error) {
|
||||
func ToK8SYaml(obj any) ([]byte, error) {
|
||||
if o, err := yaml.Marshal(obj); err != nil {
|
||||
return nil, nil
|
||||
} else {
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
func TestVersion(t *testing.T) {
|
||||
// we build on "devel" branch
|
||||
v := GetVersion()
|
||||
if strings.Contains(v, "(devel)") {
|
||||
if !strings.Contains(v, "(devel)") {
|
||||
t.Errorf("Expected version to be set, got %s", v)
|
||||
}
|
||||
|
||||
|
38
go.mod
38
go.mod
@@ -1,19 +1,19 @@
|
||||
module katenary // github.com/metal3d/katenary
|
||||
|
||||
go 1.23.0
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.23.4
|
||||
toolchain go1.24.3
|
||||
|
||||
require (
|
||||
github.com/compose-spec/compose-go v1.20.2
|
||||
github.com/invopop/jsonschema v0.12.0
|
||||
github.com/invopop/jsonschema v0.13.0
|
||||
github.com/mitchellh/go-wordwrap v1.0.1
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/thediveo/netdb v1.1.2
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.32.0
|
||||
k8s.io/apimachinery v0.32.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
k8s.io/api v0.33.2
|
||||
k8s.io/apimachinery v0.33.2
|
||||
sigs.k8s.io/yaml v1.5.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -22,10 +22,10 @@ require (
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
@@ -38,20 +38,22 @@ require (
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
|
||||
golang.org/x/net v0.32.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||
)
|
||||
|
97
go.sum
97
go.sum
@@ -4,41 +4,37 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/compose-spec/compose-go v1.20.2 h1:u/yfZHn4EaHGdidrZycWpxXgFffjYULlTbRfJ51ykjQ=
|
||||
github.com/compose-spec/compose-go v1.20.2/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
|
||||
github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
|
||||
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
@@ -68,23 +64,22 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/thediveo/netdb v1.1.2 h1:XdLx/YJPutxrSkPYtmCAIY5sgAvxtkS1Tz+Z0UX2I+U=
|
||||
github.com/thediveo/netdb v1.1.2/go.mod h1:KJczM//7VIIiovQO1qDooHvM8+0pt6RdRt3rVDZxEGM=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||
@@ -100,40 +95,44 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
|
||||
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -148,17 +147,21 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
||||
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
|
||||
k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE=
|
||||
k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0=
|
||||
k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg=
|
||||
k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
|
||||
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
|
||||
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
|
||||
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
|
||||
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Parser package is a wrapper around compose-go to parse compose files.
|
||||
// Package parser is a wrapper around compose-go to parse compose files.
|
||||
package parser
|
||||
|
||||
import (
|
||||
|
60
parser/main_test.go
Normal file
60
parser/main_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const composeFile = `
|
||||
services:
|
||||
app:
|
||||
image: nginx:latest
|
||||
`
|
||||
|
||||
func setupTest() (string, error) {
|
||||
// write the composeFile to a temporary file
|
||||
tmpDir, err := os.MkdirTemp("", "katenary-test-parse")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
writeFile := filepath.Join(tmpDir, "compose.yaml")
|
||||
writeErr := os.WriteFile(writeFile, []byte(composeFile), 0644)
|
||||
return writeFile, writeErr
|
||||
}
|
||||
|
||||
func tearDownTest(tmpDir string) {
|
||||
if tmpDir != "" {
|
||||
if err := os.RemoveAll(tmpDir); err != nil {
|
||||
log.Fatalf("Failed to remove temporary directory %s: %s", tmpDir, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
file, err := setupTest()
|
||||
dirname := filepath.Dir(file)
|
||||
currentDir, _ := os.Getwd()
|
||||
if err := os.Chdir(dirname); err != nil {
|
||||
t.Fatalf("Failed to change directory to %s: %s", dirname, err.Error())
|
||||
}
|
||||
defer func() {
|
||||
tearDownTest(dirname)
|
||||
if err := os.Chdir(currentDir); err != nil {
|
||||
t.Fatalf("Failed to change back to original directory %s: %s", currentDir, err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup test: %s", err.Error())
|
||||
}
|
||||
|
||||
Project, err := Parse(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse compose file: %s", err.Error())
|
||||
}
|
||||
if Project == nil {
|
||||
t.Fatal("Expected project to be not nil")
|
||||
}
|
||||
}
|
@@ -1,2 +1,3 @@
|
||||
// Utils package provides some utility functions used in katenary. It defines some constants and functions used in the whole project.
|
||||
// Package utils provides some utility functions used in katenary.
|
||||
// It defines some constants and functions used in the whole project.
|
||||
package utils
|
||||
|
13
utils/hash_test.go
Normal file
13
utils/hash_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package utils
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestHash(t *testing.T) {
|
||||
h, err := HashComposefiles([]string{"./hash.go"})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to hash compose files: %v", err)
|
||||
}
|
||||
if len(h) == 0 {
|
||||
t.Fatal("hash should not be empty")
|
||||
}
|
||||
}
|
@@ -22,7 +22,7 @@ const (
|
||||
)
|
||||
|
||||
// Warn prints a warning message
|
||||
func Warn(msg ...interface{}) {
|
||||
func Warn(msg ...any) {
|
||||
orange := "\033[38;5;214m"
|
||||
reset := "\033[0m"
|
||||
fmt.Print(IconWarning, orange, " ")
|
||||
|
@@ -90,7 +90,7 @@ func GetContainerByName(name string, containers []corev1.Container) (*corev1.Con
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
// GetContainerByName returns a container by name and its index in the array.
|
||||
// TplValue returns a container by name and its index in the array.
|
||||
func TplValue(serviceName, variable string, pipes ...string) string {
|
||||
if len(pipes) == 0 {
|
||||
return `{{ tpl .Values.` + serviceName + `.` + variable + ` $ }}`
|
||||
@@ -136,12 +136,12 @@ func GetValuesFromLabel(service types.ServiceConfig, LabelValues string) map[str
|
||||
switch val := value.(type) {
|
||||
case string:
|
||||
descriptions[val] = nil
|
||||
case map[string]interface{}:
|
||||
for k, v := range value.(map[string]interface{}) {
|
||||
case map[string]any:
|
||||
for k, v := range value.(map[string]any) {
|
||||
descriptions[k] = &EnvConfig{Service: service, Description: v.(string)}
|
||||
}
|
||||
case map[interface{}]interface{}:
|
||||
for k, v := range value.(map[interface{}]interface{}) {
|
||||
case map[any]any:
|
||||
for k, v := range value.(map[any]any) {
|
||||
descriptions[k.(string)] = &EnvConfig{Service: service, Description: v.(string)}
|
||||
}
|
||||
default:
|
||||
@@ -165,7 +165,9 @@ func Confirm(question string, icon ...Icon) bool {
|
||||
fmt.Print(question + " [y/N] ")
|
||||
}
|
||||
var response string
|
||||
fmt.Scanln(&response)
|
||||
if _, err := fmt.Scanln(&response); err != nil {
|
||||
log.Fatalf("Error parsing response: %s", err.Error())
|
||||
}
|
||||
return strings.ToLower(response) == "y"
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user