Merge pull request #118 from metal3d/develop

Develop
This commit is contained in:
2025-06-04 15:22:09 +02:00
committed by GitHub
27 changed files with 346 additions and 200 deletions

26
.golangci.yml Normal file
View 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"

View File

@@ -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])
},
}

View File

@@ -0,0 +1,5 @@
MD012: false
MD013: false
MD022: false
MD033: false
MD046: false

View File

@@ -37,8 +37,8 @@ Add files to the configmap.
**Type**: `[]string`
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
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.
@@ -47,7 +47,7 @@ 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
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.
@@ -61,7 +61,6 @@ labels:
- ./conf.d
```
### katenary.v3/cronjob
Create a cronjob from the service.
@@ -71,8 +70,9 @@ Create a cronjob from the service.
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
- 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
@@ -86,15 +86,14 @@ labels:
schedule: "* */1 * * *" # or @hourly for example
```
### katenary.v3/dependencies
Add Helm dependencies to the service.
**Type**: `[]object`
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
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:
@@ -106,12 +105,12 @@ It's a list of objects with the following attributes:
!!! 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
By setting an alias, it is possible to change the name of the dependency
in values.yaml.
**Example:**
@@ -133,14 +132,13 @@ labels:
password: the secret password
```
### katenary.v3/description
Description of the service
**Type**: `string`
This replaces the default comment in values.yaml file to the given description.
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.
@@ -154,7 +152,6 @@ labels:
It can be multiline.
```
### katenary.v3/env-from
Add environment variables from antoher service.
@@ -180,14 +177,13 @@ service2:
- myservice1
```
### katenary.v3/exchange-volumes
Add exchange volumes (empty directory on the node) to share data
**Type**: `[]object`
This label allows sharing data between containres. The volume is created in
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.
@@ -198,9 +194,10 @@ This will create:
- 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)
- 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.
@@ -223,7 +220,6 @@ php:
init: cp -ra /var/www/html/* /opt
```
### katenary.v3/health-check
Health check to be added to the deployment.
@@ -243,7 +239,6 @@ labels:
port: 8080
```
### katenary.v3/ignore
Ignore the service
@@ -259,14 +254,13 @@ labels:
katenary.v3/ignore: "true"
```
### katenary.v3/ingress
Ingress rules to be added to the service.
**Type**: `object`
Declare an ingress rule for the service. The port should be exposed or
Declare an ingress rule for the service. The port should be exposed or
declared with `katenary.v3/ports`.
**Example:**
@@ -278,14 +272,13 @@ labels:
hostname: mywebsite.com (optional)
```
### katenary.v3/main-app
Mark the service as the main app.
**Type**: `bool`
This makes the service to be the main application. Its image tag is
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.
@@ -305,7 +298,6 @@ ghost:
katenary.v3/main-app: true
```
### katenary.v3/map-env
Map env vars from the service to the deployment.
@@ -313,8 +305,8 @@ Map env vars from the service to the deployment.
**Type**: `map[string]string`
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
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 . }}`.
@@ -333,14 +325,13 @@ labels:
DB_HOST: '{{ include "__APP__.fullname" . }}-database'
```
### katenary.v3/ports
Ports to be added to the service.
**Type**: `[]uint32`
Only useful for services without exposed port. It is mandatory if the
Only useful for services without exposed port. It is mandatory if the
service is a dependency of another service.
**Example:**
@@ -352,17 +343,16 @@ labels:
- 8081
```
### katenary.v3/same-pod
Move the same-pod deployment to the target deployment.
**Type**: `string`
This will make the service to be included in another service pod. Some services
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
Note that volume and VolumeMount are copied from the source to the target
deployment.
**Example:**
@@ -377,14 +367,13 @@ php:
katenary.v3/same-pod: web
```
### katenary.v3/secrets
Env vars to be set as secrets.
**Type**: `[]string`
This label allows setting the environment variables as secrets. The variable
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 `katenary.v3/values` too,
@@ -401,7 +390,6 @@ labels:
- PASSWORD
```
### katenary.v3/values
Environment variables to be added to the values.yaml
@@ -412,11 +400,11 @@ 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
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 value can be set with a documentation. This may help to understand
the purpose of the variable.
**Example:**
@@ -438,7 +426,6 @@ labels:
It can be, of course, a multiline text.
```
### katenary.v3/values-from
Add values from another service.
@@ -460,9 +447,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:
@@ -476,5 +463,4 @@ php:
DB_PASSWORD: database.MARIADB_PASSWORD
```
<!-- STOP_DETAILED_DOC : do not remove this tag !-->

View File

@@ -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"`
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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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>)

View File

@@ -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

View File

@@ -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

View File

@@ -116,9 +116,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 +128,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
}

View File

@@ -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
}
@@ -165,7 +167,7 @@ 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() {

View File

@@ -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.

View File

@@ -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{}
@@ -660,7 +657,9 @@ 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) {

View 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)
}
}
}

View File

@@ -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)

View 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])
}
}

View File

@@ -117,7 +117,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)
}
@@ -129,7 +132,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
@@ -385,7 +390,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
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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 {

60
parser/main_test.go Normal file
View 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")
}
}

13
utils/hash_test.go Normal file
View 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")
}
}

View File

@@ -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, " ")

View File

@@ -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"
}