Merge pull request #129 from metal3d/develop

Many fixes on code quality and CI
This commit is contained in:
2025-07-06 15:37:08 +02:00
committed by GitHub
49 changed files with 641 additions and 143 deletions

View File

@@ -2,12 +2,15 @@ name: Go-Tests
on: on:
pull_request: pull_request:
types: [opened, synchronize, reopened]
branches: branches:
- develop - develop
push: push:
branches: branches:
- master - master
- main
- develop - develop
- 'releases/**'
jobs: jobs:
tests: tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -16,12 +19,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: 1.23 go-version: 1.24
- name: Install Helm
run: |
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
- name: Launch Test - name: Launch Test
run: | run: |
go mod tidy go mod tidy
@@ -33,6 +31,9 @@ jobs:
coverprofile.out coverprofile.out
gotest.json gotest.json
sonar: sonar:
permissions:
contents: read
pull-requests: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: tests needs: tests
steps: steps:
@@ -40,8 +41,8 @@ jobs:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: tests-results name: tests-results
- name: SonarCloud Scan - name: SonarQube Scan
uses: SonarSource/sonarcloud-github-action@master uses: SonarSource/sonarqube-scan-action@v5.2.0
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}

View File

@@ -242,3 +242,16 @@ __label_doc:
gomarkdoc --repository.default-branch $(shell git branch --show-current) -o doc/docs/packages/$$pack.md $$pack gomarkdoc --repository.default-branch $(shell git branch --show-current) -o doc/docs/packages/$$pack.md $$pack
sed -i '/^## Index/,/^##/ { /## Index/d; /^##/! d }' doc/docs/packages/$$pack.md sed -i '/^## Index/,/^##/ { /## Index/d; /^##/! d }' doc/docs/packages/$$pack.md
done done
# Scan the source code.
# - we don't need detection of text/template as it's not a web application, and
# - we don't need sha1 detection as it is not used for cryptographic purposes.
# Note: metrics are actually not sent to anyone - it's a thing that is removed from the code in the future.
sast:
opengrep \
--config auto \
--exclude-rule go.lang.security.audit.xss.import-text-template.import-text-template \
--exclude-rule go.lang.security.audit.crypto.use_of_weak_crypto.use-of-sha1 \
--metrics=on \
.

View File

@@ -146,7 +146,7 @@ func generateConvertCommand() *cobra.Command {
Use: "convert", Use: "convert",
Short: "Converts a docker-compose file to a Helm Chart", Short: "Converts a docker-compose file to a Helm Chart",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if givenAppVersion != "" { if len(strings.TrimSpace(givenAppVersion)) > 0 {
appVersion = &givenAppVersion appVersion = &givenAppVersion
} }
return generator.Convert(generator.ConvertOptions{ return generator.Convert(generator.ConvertOptions{

View File

@@ -465,7 +465,7 @@ type HelmChart struct {
AppVersion string `yaml:"appVersion"` AppVersion string `yaml:"appVersion"`
Description string `yaml:"description"` Description string `yaml:"description"`
Helper string `yaml:"-"` Helper string `yaml:"-"`
Dependencies []labelStructs.Dependency `yaml:"dependencies,omitempty"` Dependencies []labelstructs.Dependency `yaml:"dependencies,omitempty"`
// contains filtered or unexported fields // contains filtered or unexported fields
} }
``` ```

View File

@@ -38,20 +38,20 @@ Service is a struct that contains the service configuration for katenary
type Service struct { type Service struct {
MainApp *bool `json:"main-app,omitempty" jsonschema:"title=Is this service the main application"` MainApp *bool `json:"main-app,omitempty" jsonschema:"title=Is this service the main application"`
Values []StringOrMap `json:"values,omitempty" jsonschema:"description=Environment variables to be set in values.yaml with or without a description"` Values []StringOrMap `json:"values,omitempty" jsonschema:"description=Environment variables to be set in values.yaml with or without a description"`
Secrets *labelStructs.Secrets `json:"secrets,omitempty" jsonschema:"title=Secrets,description=Environment variables to be set as secrets"` Secrets *labelstructs.Secrets `json:"secrets,omitempty" jsonschema:"title=Secrets,description=Environment variables to be set as secrets"`
Ports *labelStructs.Ports `json:"ports,omitempty" jsonschema:"title=Ports,description=Ports to be exposed in services"` Ports *labelstructs.Ports `json:"ports,omitempty" jsonschema:"title=Ports,description=Ports to be exposed in services"`
Ingress *labelStructs.Ingress `json:"ingress,omitempty" jsonschema:"title=Ingress,description=Ingress configuration"` Ingress *labelstructs.Ingress `json:"ingress,omitempty" jsonschema:"title=Ingress,description=Ingress configuration"`
HealthCheck *labelStructs.HealthCheck `json:"health-check,omitempty" jsonschema:"title=Health Check,description=Health check configuration that respects the kubernetes api"` HealthCheck *labelstructs.HealthCheck `json:"health-check,omitempty" jsonschema:"title=Health Check,description=Health check configuration that respects the kubernetes api"`
SamePod *string `json:"same-pod,omitempty" jsonschema:"title=Same Pod,description=Service that should be in the same pod"` SamePod *string `json:"same-pod,omitempty" jsonschema:"title=Same Pod,description=Service that should be in the same pod"`
Description *string `json:"description,omitempty" jsonschema:"title=Description,description=Description of the service that will be injected in the values.yaml file"` Description *string `json:"description,omitempty" jsonschema:"title=Description,description=Description of the service that will be injected in the values.yaml file"`
Ignore *bool `json:"ignore,omitempty" jsonschema:"title=Ignore,description=Ignore the service in the conversion"` Ignore *bool `json:"ignore,omitempty" jsonschema:"title=Ignore,description=Ignore the service in the conversion"`
Dependencies []labelStructs.Dependency `json:"dependencies,omitempty" jsonschema:"title=Dependencies,description=Services that should be injected in the Chart.yaml file"` Dependencies []labelstructs.Dependency `json:"dependencies,omitempty" jsonschema:"title=Dependencies,description=Services that should be injected in the Chart.yaml file"`
ConfigMapFile *labelStructs.ConfigMapFile `json:"configmap-files,omitempty" jsonschema:"title=ConfigMap Files,description=Files that should be injected as ConfigMap"` ConfigMapFile *labelstructs.ConfigMapFile `json:"configmap-files,omitempty" jsonschema:"title=ConfigMap Files,description=Files that should be injected as ConfigMap"`
MapEnv *labelStructs.MapEnv `json:"map-env,omitempty" jsonschema:"title=Map Env,description=Map environment variables to another value"` MapEnv *labelstructs.MapEnv `json:"map-env,omitempty" jsonschema:"title=Map Env,description=Map environment variables to another value"`
CronJob *labelStructs.CronJob `json:"cron-job,omitempty" jsonschema:"title=Cron Job,description=Cron Job configuration"` CronJob *labelstructs.CronJob `json:"cron-job,omitempty" jsonschema:"title=Cron Job,description=Cron Job configuration"`
EnvFrom *labelStructs.EnvFrom `json:"env-from,omitempty" jsonschema:"title=Env From,description=Inject environment variables from another service"` EnvFrom *labelstructs.EnvFrom `json:"env-from,omitempty" jsonschema:"title=Env From,description=Inject environment variables from another service"`
ExchangeVolumes []*labelStructs.ExchangeVolume `json:"exchange-volumes,omitempty" jsonschema:"title=Exchange Volumes,description=Exchange volumes between services"` ExchangeVolumes []*labelstructs.ExchangeVolume `json:"exchange-volumes,omitempty" jsonschema:"title=Exchange Volumes,description=Exchange volumes between services"`
ValuesFrom *labelStructs.ValueFrom `json:"values-from,omitempty" jsonschema:"title=Values From,description=Inject values from another service (secret or configmap environment variables)"` ValuesFrom *labelstructs.ValueFrom `json:"values-from,omitempty" jsonschema:"title=Values From,description=Inject values from another service (secret or configmap environment variables)"`
} }
``` ```

View File

@@ -6,6 +6,8 @@
import "katenary/generator/labels" import "katenary/generator/labels"
``` ```
Package labels provides functionality to parse and manipulate labels.
## Constants ## Constants
<a name="KatenaryLabelPrefix"></a> <a name="KatenaryLabelPrefix"></a>
@@ -21,7 +23,7 @@ const KatenaryLabelPrefix = "katenary.v3"
func GetLabelHelp(asMarkdown bool) string func GetLabelHelp(asMarkdown bool) string
``` ```
Generate the help for the labels. GetLabelHelp return the help for the labels.
<a name="GetLabelHelpFor"></a> <a name="GetLabelHelpFor"></a>
## func [GetLabelHelpFor](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L97>) ## func [GetLabelHelpFor](<https://github.com/metal3d/katenary/blob/develop/generator/labels/katenaryLabels.go#L97>)

View File

@@ -0,0 +1,246 @@
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# labelstructs
```go
import "katenary/generator/labels/labelstructs"
```
Package labelstructs is a package that contains the structs used to represent the labels in the yaml files.
## type [ConfigMapFile](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/configMap.go#L5>)
```go
type ConfigMapFile []string
```
<a name="ConfigMapFileFrom"></a>
### func [ConfigMapFileFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/configMap.go#L7>)
```go
func ConfigMapFileFrom(data string) (ConfigMapFile, error)
```
<a name="CronJob"></a>
## type [CronJob](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/cronJob.go#L5-L10>)
```go
type CronJob struct {
Image string `yaml:"image,omitempty" json:"image,omitempty"`
Command string `yaml:"command" json:"command,omitempty"`
Schedule string `yaml:"schedule" json:"schedule,omitempty"`
Rbac bool `yaml:"rbac" json:"rbac,omitempty"`
}
```
<a name="CronJobFrom"></a>
### func [CronJobFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/cronJob.go#L12>)
```go
func CronJobFrom(data string) (*CronJob, error)
```
<a name="Dependency"></a>
## type [Dependency](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/dependencies.go#L6-L12>)
Dependency is a dependency of a chart to other charts.
```go
type Dependency struct {
Values map[string]any `yaml:"-" json:"values,omitempty"`
Name string `yaml:"name" json:"name"`
Version string `yaml:"version" json:"version"`
Repository string `yaml:"repository" json:"repository"`
Alias string `yaml:"alias,omitempty" json:"alias,omitempty"`
}
```
<a name="DependenciesFrom"></a>
### func [DependenciesFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/dependencies.go#L15>)
```go
func DependenciesFrom(data string) ([]Dependency, error)
```
DependenciesFrom returns a slice of dependencies from the given string.
<a name="EnvFrom"></a>
## type [EnvFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/envFrom.go#L5>)
```go
type EnvFrom []string
```
<a name="EnvFromFrom"></a>
### func [EnvFromFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/envFrom.go#L8>)
```go
func EnvFromFrom(data string) (EnvFrom, error)
```
EnvFromFrom returns a EnvFrom from the given string.
<a name="ExchangeVolume"></a>
## type [ExchangeVolume](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/exchangeVolume.go#L5-L10>)
```go
type ExchangeVolume struct {
Name string `yaml:"name" json:"name"`
MountPath string `yaml:"mountPath" json:"mountPath"`
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Init string `yaml:"init,omitempty" json:"init,omitempty"`
}
```
<a name="NewExchangeVolumes"></a>
### func [NewExchangeVolumes](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/exchangeVolume.go#L12>)
```go
func NewExchangeVolumes(data string) ([]*ExchangeVolume, error)
```
<a name="HealthCheck"></a>
## type [HealthCheck](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/probes.go#L11-L14>)
```go
type HealthCheck struct {
LivenessProbe *corev1.Probe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty"`
ReadinessProbe *corev1.Probe `yaml:"readinessProbe,omitempty" json:"readinessProbe,omitempty"`
}
```
<a name="ProbeFrom"></a>
### func [ProbeFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/probes.go#L16>)
```go
func ProbeFrom(data string) (*HealthCheck, error)
```
<a name="Ingress"></a>
## type [Ingress](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/ingress.go#L14-L22>)
```go
type Ingress struct {
Port *int32 `yaml:"port,omitempty" json:"port,omitempty"`
Annotations map[string]string `yaml:"annotations,omitempty" jsonschema:"nullable" json:"annotations,omitempty"`
Hostname string `yaml:"hostname,omitempty" json:"hostname,omitempty"`
Path *string `yaml:"path,omitempty" json:"path,omitempty"`
Class *string `yaml:"class,omitempty" json:"class,omitempty" jsonschema:"default:-"`
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
TLS *TLS `yaml:"tls,omitempty" json:"tls,omitempty"`
}
```
<a name="IngressFrom"></a>
### func [IngressFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/ingress.go#L25>)
```go
func IngressFrom(data string) (*Ingress, error)
```
IngressFrom creates a new Ingress from a compose service.
<a name="MapEnv"></a>
## type [MapEnv](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/mapenv.go#L5>)
```go
type MapEnv map[string]string
```
<a name="MapEnvFrom"></a>
### func [MapEnvFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/mapenv.go#L8>)
```go
func MapEnvFrom(data string) (MapEnv, error)
```
MapEnvFrom returns a MapEnv from the given string.
<a name="Ports"></a>
## type [Ports](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/ports.go#L5>)
```go
type Ports []uint32
```
<a name="PortsFrom"></a>
### func [PortsFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/ports.go#L8>)
```go
func PortsFrom(data string) (Ports, error)
```
PortsFrom returns a Ports from the given string.
<a name="Secrets"></a>
## type [Secrets](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/secrets.go#L5>)
```go
type Secrets []string
```
<a name="SecretsFrom"></a>
### func [SecretsFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/secrets.go#L7>)
```go
func SecretsFrom(data string) (Secrets, error)
```
<a name="TLS"></a>
## type [TLS](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/ingress.go#L10-L12>)
```go
type TLS struct {
Enabled bool `yaml:"enabled" json:"enabled,omitempty"`
}
```
<a name="ValueFrom"></a>
## type [ValueFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/valueFrom.go#L5>)
```go
type ValueFrom map[string]string
```
<a name="GetValueFrom"></a>
### func [GetValueFrom](<https://github.com/metal3d/katenary/blob/develop/generator/labels/labelstructs/valueFrom.go#L7>)
```go
func GetValueFrom(data string) (*ValueFrom, error)
```
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)

View File

@@ -8,7 +8,16 @@ import "katenary/utils"
Package utils 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.
## func [AsResourceName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L193>) ## Constants
<a name="DirectoryPermission"></a>DirectoryPermission is the default values for permissions apply to created directories.
```go
const DirectoryPermission = 0o755
```
<a name="AsResourceName"></a>
## func [AsResourceName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L196>)
```go ```go
func AsResourceName(name string) string func AsResourceName(name string) string
@@ -17,7 +26,7 @@ func AsResourceName(name string) string
AsResourceName returns a resource name with underscores to respect the kubernetes naming convention. It's the opposite of FixedResourceName. AsResourceName returns a resource name with underscores to respect the kubernetes naming convention. It's the opposite of FixedResourceName.
<a name="Confirm"></a> <a name="Confirm"></a>
## func [Confirm](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L161>) ## func [Confirm](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L164>)
```go ```go
func Confirm(question string, icon ...Icon) bool func Confirm(question string, icon ...Icon) bool
@@ -26,7 +35,7 @@ func Confirm(question string, icon ...Icon) bool
Confirm asks a question and returns true if the answer is y. Confirm asks a question and returns true if the answer is y.
<a name="CountStartingSpaces"></a> <a name="CountStartingSpaces"></a>
## func [CountStartingSpaces](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L38>) ## func [CountStartingSpaces](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L41>)
```go ```go
func CountStartingSpaces(line string) int func CountStartingSpaces(line string) int
@@ -35,7 +44,7 @@ func CountStartingSpaces(line string) int
CountStartingSpaces counts the number of spaces at the beginning of a string. CountStartingSpaces counts the number of spaces at the beginning of a string.
<a name="EncodeBasicYaml"></a> <a name="EncodeBasicYaml"></a>
## func [EncodeBasicYaml](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L175>) ## func [EncodeBasicYaml](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L178>)
```go ```go
func EncodeBasicYaml(data any) ([]byte, error) func EncodeBasicYaml(data any) ([]byte, error)
@@ -44,7 +53,7 @@ func EncodeBasicYaml(data any) ([]byte, error)
EncodeBasicYaml encodes a basic yaml from an interface. EncodeBasicYaml encodes a basic yaml from an interface.
<a name="FixedResourceName"></a> <a name="FixedResourceName"></a>
## func [FixedResourceName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L187>) ## func [FixedResourceName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L190>)
```go ```go
func FixedResourceName(name string) string func FixedResourceName(name string) string
@@ -53,7 +62,7 @@ func FixedResourceName(name string) string
FixedResourceName returns a resource name without underscores to respect the kubernetes naming convention. FixedResourceName returns a resource name without underscores to respect the kubernetes naming convention.
<a name="GetContainerByName"></a> <a name="GetContainerByName"></a>
## func [GetContainerByName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L84>) ## func [GetContainerByName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L87>)
```go ```go
func GetContainerByName(name string, containers []corev1.Container) (*corev1.Container, int) func GetContainerByName(name string, containers []corev1.Container) (*corev1.Container, int)
@@ -62,7 +71,7 @@ func GetContainerByName(name string, containers []corev1.Container) (*corev1.Con
GetContainerByName returns a container by name and its index in the array. It returns nil, \-1 if not found. GetContainerByName returns a container by name and its index in the array. It returns nil, \-1 if not found.
<a name="GetKind"></a> <a name="GetKind"></a>
## func [GetKind](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L51>) ## func [GetKind](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L54>)
```go ```go
func GetKind(path string) (kind string) func GetKind(path string) (kind string)
@@ -71,7 +80,7 @@ func GetKind(path string) (kind string)
GetKind returns the kind of the resource from the file path. GetKind returns the kind of the resource from the file path.
<a name="GetServiceNameByPort"></a> <a name="GetServiceNameByPort"></a>
## func [GetServiceNameByPort](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L74>) ## func [GetServiceNameByPort](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L77>)
```go ```go
func GetServiceNameByPort(port int) string func GetServiceNameByPort(port int) string
@@ -80,7 +89,7 @@ func GetServiceNameByPort(port int) string
GetServiceNameByPort returns the service name for a port. It the service name is not found, it returns an empty string. GetServiceNameByPort returns the service name for a port. It the service name is not found, it returns an empty string.
<a name="GetValuesFromLabel"></a> <a name="GetValuesFromLabel"></a>
## func [GetValuesFromLabel](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L126>) ## func [GetValuesFromLabel](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L129>)
```go ```go
func GetValuesFromLabel(service types.ServiceConfig, LabelValues string) map[string]*EnvConfig func GetValuesFromLabel(service types.ServiceConfig, LabelValues string) map[string]*EnvConfig
@@ -98,7 +107,7 @@ func HashComposefiles(files []string) (string, error)
HashComposefiles returns a hash of the compose files. HashComposefiles returns a hash of the compose files.
<a name="Int32Ptr"></a> <a name="Int32Ptr"></a>
## func [Int32Ptr](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L32>) ## func [Int32Ptr](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L35>)
```go ```go
func Int32Ptr(i int32) *int32 func Int32Ptr(i int32) *int32
@@ -107,7 +116,7 @@ func Int32Ptr(i int32) *int32
Int32Ptr returns a pointer to an int32. Int32Ptr returns a pointer to an int32.
<a name="PathToName"></a> <a name="PathToName"></a>
## func [PathToName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L103>) ## func [PathToName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L106>)
```go ```go
func PathToName(path string) string func PathToName(path string) string
@@ -116,7 +125,7 @@ func PathToName(path string) string
PathToName converts a path to a kubernetes complient name. PathToName converts a path to a kubernetes complient name.
<a name="StrPtr"></a> <a name="StrPtr"></a>
## func [StrPtr](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L35>) ## func [StrPtr](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L38>)
```go ```go
func StrPtr(s string) *string func StrPtr(s string) *string
@@ -125,7 +134,7 @@ func StrPtr(s string) *string
StrPtr returns a pointer to a string. StrPtr returns a pointer to a string.
<a name="TplName"></a> <a name="TplName"></a>
## func [TplName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L19>) ## func [TplName](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L22>)
```go ```go
func TplName(serviceName, appname string, suffix ...string) string func TplName(serviceName, appname string, suffix ...string) string
@@ -134,7 +143,7 @@ func TplName(serviceName, appname string, suffix ...string) string
TplName returns the name of the kubernetes resource as a template string. It is used in the templates and defined in \_helper.tpl file. TplName returns the name of the kubernetes resource as a template string. It is used in the templates and defined in \_helper.tpl file.
<a name="TplValue"></a> <a name="TplValue"></a>
## func [TplValue](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L94>) ## func [TplValue](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L97>)
```go ```go
func TplValue(serviceName, variable string, pipes ...string) string func TplValue(serviceName, variable string, pipes ...string) string
@@ -152,7 +161,7 @@ func Warn(msg ...any)
Warn prints a warning message Warn prints a warning message
<a name="WordWrap"></a> <a name="WordWrap"></a>
## func [WordWrap](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L156>) ## func [WordWrap](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L159>)
```go ```go
func WordWrap(text string, lineWidth int) string func WordWrap(text string, lineWidth int) string
@@ -161,7 +170,7 @@ func WordWrap(text string, lineWidth int) string
WordWrap wraps a string to a given line width. Warning: it may break the string. You need to check the result. WordWrap wraps a string to a given line width. Warning: it may break the string. You need to check the result.
<a name="Wrap"></a> <a name="Wrap"></a>
## func [Wrap](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L68>) ## func [Wrap](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L71>)
```go ```go
func Wrap(src, above, below string) string func Wrap(src, above, below string) string
@@ -170,7 +179,7 @@ func Wrap(src, above, below string) string
Wrap wraps a string with a string above and below. It will respect the indentation of the src string. Wrap wraps a string with a string above and below. It will respect the indentation of the src string.
<a name="EnvConfig"></a> <a name="EnvConfig"></a>
## type [EnvConfig](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L120-L123>) ## type [EnvConfig](<https://github.com/metal3d/katenary/blob/develop/utils/utils.go#L123-L126>)
EnvConfig is a struct to hold the description of an environment variable. EnvConfig is a struct to hold the description of an environment variable.

View File

@@ -3,7 +3,7 @@ package generator
import ( import (
"fmt" "fmt"
"katenary/generator/labels" "katenary/generator/labels"
"katenary/generator/labels/labelStructs" "katenary/generator/labels/labelstructs"
"katenary/utils" "katenary/utils"
"log" "log"
"maps" "maps"
@@ -49,7 +49,7 @@ type HelmChart struct {
AppVersion string `yaml:"appVersion"` AppVersion string `yaml:"appVersion"`
Description string `yaml:"description"` Description string `yaml:"description"`
Helper string `yaml:"-"` Helper string `yaml:"-"`
Dependencies []labelStructs.Dependency `yaml:"dependencies,omitempty"` Dependencies []labelstructs.Dependency `yaml:"dependencies,omitempty"`
} }
// NewChart creates a new empty chart with the given name. // NewChart creates a new empty chart with the given name.
@@ -95,7 +95,7 @@ func (chart *HelmChart) SaveTemplates(templateDir string) {
} }
servicename := template.Servicename servicename := template.Servicename
if err := os.MkdirAll(filepath.Join(templateDir, servicename), 0o755); err != nil { if err := os.MkdirAll(filepath.Join(templateDir, servicename), utils.DirectoryPermission); err != nil {
fmt.Println(utils.IconFailure, err) fmt.Println(utils.IconFailure, err)
os.Exit(1) os.Exit(1)
} }
@@ -103,7 +103,7 @@ func (chart *HelmChart) SaveTemplates(templateDir string) {
// if the name is a path, create the directory // if the name is a path, create the directory
if strings.Contains(name, string(filepath.Separator)) { if strings.Contains(name, string(filepath.Separator)) {
name = filepath.Join(templateDir, name) name = filepath.Join(templateDir, name)
err := os.MkdirAll(filepath.Dir(name), 0o755) err := os.MkdirAll(filepath.Dir(name), utils.DirectoryPermission)
if err != nil { if err != nil {
fmt.Println(utils.IconFailure, err) fmt.Println(utils.IconFailure, err)
os.Exit(1) os.Exit(1)
@@ -141,7 +141,7 @@ func (chart *HelmChart) generateConfigMapsAndSecrets(project *types.Project) err
maps.Copy(originalEnv, s.Environment) maps.Copy(originalEnv, s.Environment)
if v, ok := s.Labels[labels.LabelSecrets]; ok { if v, ok := s.Labels[labels.LabelSecrets]; ok {
list, err := labelStructs.SecretsFrom(v) list, err := labelstructs.SecretsFrom(v)
if err != nil { if err != nil {
log.Fatal("error unmarshaling secrets label:", err) log.Fatal("error unmarshaling secrets label:", err)
} }
@@ -214,7 +214,7 @@ func (chart *HelmChart) generateDeployment(service types.ServiceConfig, deployme
if exchange, ok := service.Labels[labels.LabelExchangeVolume]; ok { if exchange, ok := service.Labels[labels.LabelExchangeVolume]; ok {
// we need to add a volume and a mount point // we need to add a volume and a mount point
ex, err := labelStructs.NewExchangeVolumes(exchange) ex, err := labelstructs.NewExchangeVolumes(exchange)
if err != nil { if err != nil {
return err return err
} }
@@ -298,7 +298,7 @@ func (chart *HelmChart) setCronJob(service types.ServiceConfig, appName string)
func (chart *HelmChart) setDependencies(service types.ServiceConfig) (bool, error) { func (chart *HelmChart) setDependencies(service types.ServiceConfig) (bool, error) {
// helm dependency // helm dependency
if v, ok := service.Labels[labels.LabelDependencies]; ok { if v, ok := service.Labels[labels.LabelDependencies]; ok {
d, err := labelStructs.DependenciesFrom(v) d, err := labelstructs.DependenciesFrom(v)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -326,7 +326,7 @@ func (chart *HelmChart) setSharedConf(service types.ServiceConfig, deployments m
if _, ok := service.Labels[labels.LabelEnvFrom]; !ok { if _, ok := service.Labels[labels.LabelEnvFrom]; !ok {
return return
} }
fromservices, err := labelStructs.EnvFromFrom(service.Labels[labels.LabelEnvFrom]) fromservices, err := labelstructs.EnvFromFrom(service.Labels[labels.LabelEnvFrom])
if err != nil { if err != nil {
log.Fatal("error unmarshaling env-from label:", err) log.Fatal("error unmarshaling env-from label:", err)
} }
@@ -351,7 +351,7 @@ func (chart *HelmChart) setEnvironmentValuesFrom(service types.ServiceConfig, de
if _, ok := service.Labels[labels.LabelValueFrom]; !ok { if _, ok := service.Labels[labels.LabelValueFrom]; !ok {
return return
} }
mapping, err := labelStructs.GetValueFrom(service.Labels[labels.LabelValueFrom]) mapping, err := labelstructs.GetValueFrom(service.Labels[labels.LabelValueFrom])
if err != nil { if err != nil {
log.Fatal("error unmarshaling values-from label:", err) log.Fatal("error unmarshaling values-from label:", err)
} }
@@ -383,7 +383,7 @@ func (chart *HelmChart) setEnvironmentValuesFrom(service types.ServiceConfig, de
// is it a secret? // is it a secret?
isSecret := false isSecret := false
secrets, err := labelStructs.SecretsFrom(dep.service.Labels[labels.LabelSecrets]) secrets, err := labelstructs.SecretsFrom(dep.service.Labels[labels.LabelSecrets])
if err == nil { if err == nil {
if slices.Contains(secrets, depName[1]) { if slices.Contains(secrets, depName[1]) {
isSecret = true isSecret = true

View File

@@ -3,7 +3,7 @@ package generator
import ( import (
"fmt" "fmt"
"katenary/generator/labels" "katenary/generator/labels"
"katenary/generator/labels/labelStructs" "katenary/generator/labels/labelstructs"
"katenary/utils" "katenary/utils"
"log" "log"
"os" "os"
@@ -65,7 +65,7 @@ func NewConfigMap(service types.ServiceConfig, appName string, forFile bool) *Co
} }
// get the secrets from the labels // get the secrets from the labels
secrets, err := labelStructs.SecretsFrom(service.Labels[labels.LabelSecrets]) secrets, err := labelstructs.SecretsFrom(service.Labels[labels.LabelSecrets])
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -91,7 +91,7 @@ func NewConfigMap(service types.ServiceConfig, appName string, forFile bool) *Co
// do not bind env variables to the configmap // do not bind env variables to the configmap
// remove the variables that are already defined in the environment // remove the variables that are already defined in the environment
if l, ok := service.Labels[labels.LabelMapEnv]; ok { if l, ok := service.Labels[labels.LabelMapEnv]; ok {
envmap, err := labelStructs.MapEnvFrom(l) envmap, err := labelstructs.MapEnvFrom(l)
if err != nil { if err != nil {
log.Fatal("Error parsing map-env", err) log.Fatal("Error parsing map-env", err)
} }

View File

@@ -7,7 +7,7 @@ import (
"katenary/generator/extrafiles" "katenary/generator/extrafiles"
"katenary/generator/katenaryfile" "katenary/generator/katenaryfile"
"katenary/generator/labels" "katenary/generator/labels"
"katenary/generator/labels/labelStructs" "katenary/generator/labels/labelstructs"
"katenary/parser" "katenary/parser"
"katenary/utils" "katenary/utils"
"log" "log"
@@ -173,9 +173,8 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) error {
os.RemoveAll(config.OutputDir) os.RemoveAll(config.OutputDir)
// create the chart directory // create the chart directory
if err := os.MkdirAll(templateDir, 0o755); err != nil { if err := os.MkdirAll(templateDir, utils.DirectoryPermission); err != nil {
fmt.Println(utils.IconFailure, err) return err
os.Exit(1)
} }
// add icon from the command line // add icon from the command line
@@ -259,7 +258,7 @@ func addCommentsToValues(values []byte) []byte {
return []byte(strings.Join(lines, "\n")) return []byte(strings.Join(lines, "\n"))
} }
func addDependencyDescription(values []byte, dependencies []labelStructs.Dependency) []byte { func addDependencyDescription(values []byte, dependencies []labelstructs.Dependency) []byte {
for _, d := range dependencies { for _, d := range dependencies {
name := d.Name name := d.Name
if d.Alias != "" { if d.Alias != "" {
@@ -522,16 +521,16 @@ func buildCharYamlFile(chart *HelmChart, project *types.Project, chartPath strin
os.Exit(1) os.Exit(1)
} }
// concat chart adding a comment with hash of services on top // concat chart adding a comment with hash of services on top
yamlChart = append([]byte(fmt.Sprintf("# compose hash (sha1): %s\n", *chart.composeHash)), yamlChart...) yamlChart = append(fmt.Appendf(nil, "# compose hash (sha1): %s\n", *chart.composeHash), yamlChart...)
// add the list of compose files // add the list of compose files
files := []string{} files := []string{}
for _, file := range project.ComposeFiles { for _, file := range project.ComposeFiles {
base := filepath.Base(file) base := filepath.Base(file)
files = append(files, base) files = append(files, base)
} }
yamlChart = append([]byte(fmt.Sprintf("# compose files: %s\n", strings.Join(files, ", "))), yamlChart...) yamlChart = append(fmt.Appendf(nil, "# compose files: %s\n", strings.Join(files, ", ")), yamlChart...)
// add generated date // add generated date
yamlChart = append([]byte(fmt.Sprintf("# generated at: %s\n", time.Now().Format(time.RFC3339))), yamlChart...) yamlChart = append(fmt.Appendf(nil, "# generated at: %s\n", time.Now().Format(time.RFC3339)), yamlChart...)
// document Chart.yaml file // document Chart.yaml file
yamlChart = addChartDoc(yamlChart, project) yamlChart = addChartDoc(yamlChart, project)

View File

@@ -2,7 +2,7 @@ package generator
import ( import (
"katenary/generator/labels" "katenary/generator/labels"
"katenary/generator/labels/labelStructs" "katenary/generator/labels/labelstructs"
"katenary/utils" "katenary/utils"
"log" "log"
"strings" "strings"
@@ -30,7 +30,7 @@ func NewCronJob(service types.ServiceConfig, chart *HelmChart, appName string) (
if !ok { if !ok {
return nil, nil return nil, nil
} }
mapping, err := labelStructs.CronJobFrom(labels) mapping, err := labelstructs.CronJobFrom(labels)
if err != nil { if err != nil {
log.Fatalf("Error parsing cronjob labels: %s", err) log.Fatalf("Error parsing cronjob labels: %s", err)
return nil, nil return nil, nil

View File

@@ -3,7 +3,7 @@ package generator
import ( import (
"fmt" "fmt"
"katenary/generator/labels" "katenary/generator/labels"
"katenary/generator/labels/labelStructs" "katenary/generator/labels/labelstructs"
"katenary/utils" "katenary/utils"
"log" "log"
"os" "os"
@@ -39,7 +39,7 @@ type Deployment struct {
service *types.ServiceConfig `yaml:"-"` service *types.ServiceConfig `yaml:"-"`
defaultTag string `yaml:"-"` defaultTag string `yaml:"-"`
isMainApp bool `yaml:"-"` isMainApp bool `yaml:"-"`
exchangesVolumes map[string]*labelStructs.ExchangeVolume `yaml:"-"` exchangesVolumes map[string]*labelstructs.ExchangeVolume `yaml:"-"`
boundEnvVar []string `yaml:"-"` // environement to remove boundEnvVar []string `yaml:"-"` // environement to remove
} }
@@ -94,7 +94,7 @@ func NewDeployment(service types.ServiceConfig, chart *HelmChart) *Deployment {
}, },
configMaps: make(map[string]*ConfigMapMount), configMaps: make(map[string]*ConfigMapMount),
volumeMap: make(map[string]string), volumeMap: make(map[string]string),
exchangesVolumes: map[string]*labelStructs.ExchangeVolume{}, exchangesVolumes: map[string]*labelstructs.ExchangeVolume{},
boundEnvVar: []string{}, boundEnvVar: []string{},
} }
@@ -160,7 +160,7 @@ func (d *Deployment) AddContainer(service types.ServiceConfig) {
func (d *Deployment) AddHealthCheck(service types.ServiceConfig, container *corev1.Container) { func (d *Deployment) AddHealthCheck(service types.ServiceConfig, container *corev1.Container) {
// get the label for healthcheck // get the label for healthcheck
if v, ok := service.Labels[labels.LabelHealthCheck]; ok { if v, ok := service.Labels[labels.LabelHealthCheck]; ok {
probes, err := labelStructs.ProbeFrom(v) probes, err := labelstructs.ProbeFrom(v)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -195,7 +195,7 @@ func (d *Deployment) AddIngress(service types.ServiceConfig, appName string) *In
func (d *Deployment) AddVolumes(service types.ServiceConfig, appName string) { func (d *Deployment) AddVolumes(service types.ServiceConfig, appName string) {
tobind := map[string]bool{} tobind := map[string]bool{}
if v, ok := service.Labels[labels.LabelConfigMapFiles]; ok { if v, ok := service.Labels[labels.LabelConfigMapFiles]; ok {
binds, err := labelStructs.ConfigMapFileFrom(v) binds, err := labelstructs.ConfigMapFileFrom(v)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -320,7 +320,7 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string, sam
}() }()
// secrets from label // secrets from label
labelSecrets, err := labelStructs.SecretsFrom(service.Labels[labels.LabelSecrets]) labelSecrets, err := labelstructs.SecretsFrom(service.Labels[labels.LabelSecrets])
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"katenary/generator/labels" "katenary/generator/labels"
"katenary/generator/labels/labelStructs" "katenary/generator/labels/labelstructs"
"katenary/utils" "katenary/utils"
"log" "log"
"regexp" "regexp"
@@ -227,7 +227,7 @@ func fixResourceNames(project *types.Project) error {
} }
// also, the value-from label should be updated // also, the value-from label should be updated
if valuefrom, ok := s.Labels[labels.LabelValueFrom]; ok { if valuefrom, ok := s.Labels[labels.LabelValueFrom]; ok {
vf, err := labelStructs.GetValueFrom(valuefrom) vf, err := labelstructs.GetValueFrom(valuefrom)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,7 +2,7 @@ package generator
import ( import (
"katenary/generator/labels" "katenary/generator/labels"
"katenary/generator/labels/labelStructs" "katenary/generator/labels/labelstructs"
"katenary/utils" "katenary/utils"
"log" "log"
"strings" "strings"
@@ -33,7 +33,7 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
return nil return nil
} }
mapping, err := labelStructs.IngressFrom(label) mapping, err := labelstructs.IngressFrom(label)
if err != nil { if err != nil {
log.Fatalf("Failed to parse ingress label: %s\n", err) log.Fatalf("Failed to parse ingress label: %s\n", err)
} }

View File

@@ -5,7 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"katenary/generator/labels" "katenary/generator/labels"
"katenary/generator/labels/labelStructs" "katenary/generator/labels/labelstructs"
"katenary/utils" "katenary/utils"
"log" "log"
"os" "os"
@@ -27,20 +27,20 @@ type StringOrMap any
type Service struct { type Service struct {
MainApp *bool `json:"main-app,omitempty" jsonschema:"title=Is this service the main application"` MainApp *bool `json:"main-app,omitempty" jsonschema:"title=Is this service the main application"`
Values []StringOrMap `json:"values,omitempty" jsonschema:"description=Environment variables to be set in values.yaml with or without a description"` Values []StringOrMap `json:"values,omitempty" jsonschema:"description=Environment variables to be set in values.yaml with or without a description"`
Secrets *labelStructs.Secrets `json:"secrets,omitempty" jsonschema:"title=Secrets,description=Environment variables to be set as secrets"` Secrets *labelstructs.Secrets `json:"secrets,omitempty" jsonschema:"title=Secrets,description=Environment variables to be set as secrets"`
Ports *labelStructs.Ports `json:"ports,omitempty" jsonschema:"title=Ports,description=Ports to be exposed in services"` Ports *labelstructs.Ports `json:"ports,omitempty" jsonschema:"title=Ports,description=Ports to be exposed in services"`
Ingress *labelStructs.Ingress `json:"ingress,omitempty" jsonschema:"title=Ingress,description=Ingress configuration"` Ingress *labelstructs.Ingress `json:"ingress,omitempty" jsonschema:"title=Ingress,description=Ingress configuration"`
HealthCheck *labelStructs.HealthCheck `json:"health-check,omitempty" jsonschema:"title=Health Check,description=Health check configuration that respects the kubernetes api"` HealthCheck *labelstructs.HealthCheck `json:"health-check,omitempty" jsonschema:"title=Health Check,description=Health check configuration that respects the kubernetes api"`
SamePod *string `json:"same-pod,omitempty" jsonschema:"title=Same Pod,description=Service that should be in the same pod"` SamePod *string `json:"same-pod,omitempty" jsonschema:"title=Same Pod,description=Service that should be in the same pod"`
Description *string `json:"description,omitempty" jsonschema:"title=Description,description=Description of the service that will be injected in the values.yaml file"` Description *string `json:"description,omitempty" jsonschema:"title=Description,description=Description of the service that will be injected in the values.yaml file"`
Ignore *bool `json:"ignore,omitempty" jsonschema:"title=Ignore,description=Ignore the service in the conversion"` Ignore *bool `json:"ignore,omitempty" jsonschema:"title=Ignore,description=Ignore the service in the conversion"`
Dependencies []labelStructs.Dependency `json:"dependencies,omitempty" jsonschema:"title=Dependencies,description=Services that should be injected in the Chart.yaml file"` Dependencies []labelstructs.Dependency `json:"dependencies,omitempty" jsonschema:"title=Dependencies,description=Services that should be injected in the Chart.yaml file"`
ConfigMapFile *labelStructs.ConfigMapFile `json:"configmap-files,omitempty" jsonschema:"title=ConfigMap Files,description=Files that should be injected as ConfigMap"` ConfigMapFile *labelstructs.ConfigMapFile `json:"configmap-files,omitempty" jsonschema:"title=ConfigMap Files,description=Files that should be injected as ConfigMap"`
MapEnv *labelStructs.MapEnv `json:"map-env,omitempty" jsonschema:"title=Map Env,description=Map environment variables to another value"` MapEnv *labelstructs.MapEnv `json:"map-env,omitempty" jsonschema:"title=Map Env,description=Map environment variables to another value"`
CronJob *labelStructs.CronJob `json:"cron-job,omitempty" jsonschema:"title=Cron Job,description=Cron Job configuration"` CronJob *labelstructs.CronJob `json:"cron-job,omitempty" jsonschema:"title=Cron Job,description=Cron Job configuration"`
EnvFrom *labelStructs.EnvFrom `json:"env-from,omitempty" jsonschema:"title=Env From,description=Inject environment variables from another service"` EnvFrom *labelstructs.EnvFrom `json:"env-from,omitempty" jsonschema:"title=Env From,description=Inject environment variables from another service"`
ExchangeVolumes []*labelStructs.ExchangeVolume `json:"exchange-volumes,omitempty" jsonschema:"title=Exchange Volumes,description=Exchange volumes between services"` ExchangeVolumes []*labelstructs.ExchangeVolume `json:"exchange-volumes,omitempty" jsonschema:"title=Exchange Volumes,description=Exchange volumes between services"`
ValuesFrom *labelStructs.ValueFrom `json:"values-from,omitempty" jsonschema:"title=Values From,description=Inject values from another service (secret or configmap environment variables)"` ValuesFrom *labelstructs.ValueFrom `json:"values-from,omitempty" jsonschema:"title=Values From,description=Inject values from another service (secret or configmap environment variables)"`
} }
// OverrideWithConfig overrides the project with the katenary.yaml file. It // OverrideWithConfig overrides the project with the katenary.yaml file. It
@@ -117,7 +117,7 @@ func getLabelContent(o any, service *types.ServiceConfig, labelName string) erro
val := strings.TrimSpace(string(c)) val := strings.TrimSpace(string(c))
if labelName == labels.LabelIngress { if labelName == labels.LabelIngress {
// special case, values must be set from some defaults // special case, values must be set from some defaults
ing, err := labelStructs.IngressFrom(val) ing, err := labelstructs.IngressFrom(val)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
return err return err

View File

@@ -57,6 +57,9 @@ webapp:
cli.WithDefaultConfigPath, cli.WithDefaultConfigPath,
) )
project, err := cli.ProjectFromOptions(options) project, err := cli.ProjectFromOptions(options)
if err != nil {
t.Fatalf("Failed to create project from options: %s", err.Error())
}
OverrideWithConfig(project) OverrideWithConfig(project)
w := project.Services[0].Labels w := project.Services[0].Labels
@@ -107,6 +110,9 @@ webapp:
cli.WithDefaultConfigPath, cli.WithDefaultConfigPath,
) )
project, err := cli.ProjectFromOptions(options) project, err := cli.ProjectFromOptions(options)
if err != nil {
t.Fatalf("Failed to create project from options: %s", err.Error())
}
OverrideWithConfig(project) OverrideWithConfig(project)
w := project.Services[0].Labels w := project.Services[0].Labels

2
generator/labels/doc.go Normal file
View File

@@ -0,0 +1,2 @@
// Package labels provides functionality to parse and manipulate labels.
package labels

View File

@@ -84,7 +84,7 @@ func init() {
} }
} }
// Generate the help for the labels. // GetLabelHelp return the help for the labels.
func GetLabelHelp(asMarkdown bool) string { func GetLabelHelp(asMarkdown bool) string {
names := GetLabelNames() // sorted names := GetLabelNames() // sorted
if !asMarkdown { if !asMarkdown {

View File

@@ -1,2 +0,0 @@
// labelStructs is a package that contains the structs used to represent the labels in the yaml files.
package labelStructs

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import "gopkg.in/yaml.v3" import "gopkg.in/yaml.v3"

View File

@@ -0,0 +1,17 @@
package labelstructs_test
import (
"katenary/generator/labels/labelstructs"
"testing"
)
func TestConfigMapFileFrom(t *testing.T) {
ts := "- foo/bar"
tc2, _ := labelstructs.ConfigMapFileFrom(ts)
if len(tc2) != 1 {
t.Errorf("Expected ConfigMapFile to have 1 item, got %d", len(tc2))
}
if tc2[0] != "foo/bar" {
t.Errorf("Expected ConfigMapFile to contain 'foo/bar', got %s", tc2[0])
}
}

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import "gopkg.in/yaml.v3" import "gopkg.in/yaml.v3"

View File

@@ -0,0 +1,25 @@
package labelstructs
import "testing"
func TestCronJobFrom(t *testing.T) {
ts := `
image: fooimage
command: thecommand
schedule: "0/3 0 * * *"
Rbac: false
`
tc, _ := CronJobFrom(ts)
if tc.Image != "fooimage" {
t.Errorf("Expected CronJob image to be 'fooimage', got %s", tc.Image)
}
if tc.Command != "thecommand" {
t.Errorf("Expected CronJob command to be 'thecommand', got %s", tc.Command)
}
if tc.Schedule != "0/3 0 * * *" {
t.Errorf("Expected CronJob schedule to be '0/3 0 * * *', got %s", tc.Schedule)
}
if tc.Rbac != false {
t.Errorf("Expected CronJob rbac to be false, got %t", tc.Rbac)
}
}

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import "gopkg.in/yaml.v3" import "gopkg.in/yaml.v3"

View File

@@ -0,0 +1,14 @@
package labelstructs
import "testing"
func TestDependenciesLabel(t *testing.T) {
ts := "- name: mongodb"
tc, _ := DependenciesFrom(ts)
if len(tc) != 1 {
t.Errorf("Expected DependenciesLabel to have 1 item, got %d", len(tc))
}
if tc[0].Name != "mongodb" {
t.Errorf("Expected DependenciesLabel to contain 'mongodb', got %s", tc[0].Name)
}
}

View File

@@ -0,0 +1,2 @@
// Package labelstructs is a package that contains the structs used to represent the labels in the yaml files.
package labelstructs

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import "gopkg.in/yaml.v3" import "gopkg.in/yaml.v3"

View File

@@ -0,0 +1,17 @@
package labelstructs
import "testing"
func TestEnvFromLabel(t *testing.T) {
ts := "- foo\n- bar"
tc, _ := EnvFromFrom(ts)
if len(tc) != 2 {
t.Errorf("Expected EnvFrom to have 2 items, got %d", len(tc))
}
if tc[0] != "foo" {
t.Errorf("Expected EnvFrom to contain 'foo', got %s", tc[0])
}
if tc[1] != "bar" {
t.Errorf("Expected EnvFrom to contain 'bar', got %s", tc[1])
}
}

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import "gopkg.in/yaml.v3" import "gopkg.in/yaml.v3"

View File

@@ -0,0 +1,17 @@
package labelstructs
import "testing"
func TestExchangeVolumeLabel(t *testing.T) {
ts := "- name: exchange-volume\n mountPath: /exchange\n readOnly: true"
tc, _ := NewExchangeVolumes(ts)
if len(tc) != 1 {
t.Errorf("Expected ExchangeVolumeLabel to have 1 item, got %d", len(tc))
}
if tc[0].Name != "exchange-volume" {
t.Errorf("Expected ExchangeVolumeLabel to contain 'exchange-volume', got %s", tc[0].Name)
}
if tc[0].MountPath != "/exchange" {
t.Errorf("Expected MountPath to be '/exchange', got %s", tc[0].MountPath)
}
}

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import ( import (
"fmt" "fmt"
@@ -14,10 +14,10 @@ type TLS struct {
type Ingress struct { type Ingress struct {
Port *int32 `yaml:"port,omitempty" json:"port,omitempty"` Port *int32 `yaml:"port,omitempty" json:"port,omitempty"`
Annotations map[string]string `yaml:"annotations,omitempty" jsonschema:"nullable" json:"annotations,omitempty"` Annotations map[string]string `yaml:"annotations,omitempty" jsonschema:"nullable" json:"annotations,omitempty"`
Hostname string `yaml:"hostname" json:"hostname,omitempty"` Hostname string `yaml:"hostname,omitempty" json:"hostname,omitempty"`
Path *string `yaml:"path,omitempty" json:"path,omitempty"` Path *string `yaml:"path,omitempty" json:"path,omitempty"`
Class *string `yaml:"class,omitempty" json:"class,omitempty" jsonschema:"default:-"` Class *string `yaml:"class,omitempty" json:"class,omitempty" jsonschema:"default:-"`
Enabled bool `yaml:"enabled" json:"enabled,omitempty"` Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
TLS *TLS `yaml:"tls,omitempty" json:"tls,omitempty"` TLS *TLS `yaml:"tls,omitempty" json:"tls,omitempty"`
} }

View File

@@ -0,0 +1,31 @@
package labelstructs
import "testing"
func TestIngressLabel(t *testing.T) {
ts := "\nhostname: example.com\npath: /\nenabled: true\nport: 8888"
tc, err := IngressFrom(ts)
if err != nil {
t.Errorf("Error parsing IngressLabel: %v", err)
}
if tc.Hostname != "example.com" {
t.Errorf("Expected IngressLabel to contain 'example.com', got %s", tc.Hostname)
}
if tc.Path == nil || *tc.Path != "/" {
t.Errorf("Expected IngressLabel to contain '/', got %v", tc.Path)
}
if tc.Enabled != true {
t.Errorf("Expected IngressLabel to be enabled, got %v", tc.Enabled)
}
if tc.Port == nil || *tc.Port != 8888 {
t.Errorf("Expected IngressLabel to have port 8888, got %d", tc.Port)
}
}
func TestIngressLabelNoPort(t *testing.T) {
ts := "\nhostname: example.com\npath: /\nenabled: true"
_, err := IngressFrom(ts)
if err == nil {
t.Errorf("Expected error when parsing IngressLabel without port, got nil")
}
}

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import "gopkg.in/yaml.v3" import "gopkg.in/yaml.v3"

View File

@@ -0,0 +1,11 @@
package labelstructs
import "testing"
func TestConfigMapLabel(t *testing.T) {
ts := "foo: bar"
tc, _ := MapEnvFrom(ts)
if len(tc) != 1 {
t.Errorf("Expected ConfigMapFile to have 1 item, got %d", len(tc))
}
}

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import "gopkg.in/yaml.v3" import "gopkg.in/yaml.v3"

View File

@@ -0,0 +1,23 @@
package labelstructs
import "testing"
func TestPortsFromLabel(t *testing.T) {
data := "- 8080\n- 9090\n"
expected := Ports{8080, 9090}
ports, err := PortsFrom(data)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if len(ports) != len(expected) {
t.Fatalf("expected length %d, got %d", len(expected), len(ports))
}
for i, port := range ports {
if port != expected[i] {
t.Errorf("expected port %d at index %d, got %d", expected[i], i, port)
}
}
}

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import ( import (
"encoding/json" "encoding/json"

View File

@@ -0,0 +1,16 @@
package labelstructs
import "testing"
func TestProbesLabel(t *testing.T) {
readiness := "readinessProbe:\n httpGet:\n path: /healthz\n port: 8080\n initialDelaySeconds: 5\n periodSeconds: 10"
tc, err := ProbeFrom(readiness)
if err != nil {
t.Errorf("Error parsing ProbesLabel: %v %v", err, tc)
}
liveness := "livenessProbe:\n httpGet:\n path: /healthz\n port: 8080\n initialDelaySeconds: 5\n periodSeconds: 10"
tc2, err := ProbeFrom(liveness)
if err != nil {
t.Errorf("Error parsing ProbesLabel: %v %v", err, tc2)
}
}

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import "gopkg.in/yaml.v3" import "gopkg.in/yaml.v3"

View File

@@ -0,0 +1,17 @@
package labelstructs
import "testing"
func TestSecretLabel(t *testing.T) {
data := "- foo\n- bar"
tc, err := SecretsFrom(data)
if err != nil {
t.Errorf("Error parsing SecretLabel: %v %v", err, tc)
}
items := []string{"foo", "bar"}
for i, item := range tc {
if item != items[i] {
t.Errorf("Expected SecretLabel to contain '%s', got '%s'", items[i], item)
}
}
}

View File

@@ -1,4 +1,4 @@
package labelStructs package labelstructs
import "gopkg.in/yaml.v3" import "gopkg.in/yaml.v3"

View File

@@ -0,0 +1,25 @@
package labelstructs
import (
"testing"
)
func TestValueFromLabel(t *testing.T) {
data := "data: foo\ndata2: bar"
tc, err := GetValueFrom(data)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if tc == nil {
t.Fatalf("expected non-nil map, got nil")
}
if len(*tc) != 2 {
t.Errorf("expected 2 items, got %d", len(*tc))
}
if (*tc)["data"] != "foo" {
t.Errorf("expected 'data' to be 'foo', got %s", (*tc)["data"])
}
if (*tc)["data2"] != "bar" {
t.Errorf("expected 'data2' to be 'bar', got %s", (*tc)["data2"])
}
}

View File

@@ -82,7 +82,9 @@ services:
AppVersion: appVersion, AppVersion: appVersion,
ChartVersion: chartVersion, ChartVersion: chartVersion,
} }
Convert(convertOptions, "compose.yml") if err := Convert(convertOptions, "compose.yml"); err != nil {
t.Fatalf("Failed to convert compose file: %s", err)
}
c, err := os.ReadFile("chart/values.yaml") c, err := os.ReadFile("chart/values.yaml")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@@ -2,7 +2,7 @@ package generator
import ( import (
"katenary/generator/labels" "katenary/generator/labels"
"katenary/generator/labels/labelStructs" "katenary/generator/labels/labelstructs"
"katenary/utils" "katenary/utils"
"regexp" "regexp"
"strconv" "strconv"
@@ -50,7 +50,7 @@ func fixPorts(service *types.ServiceConfig) error {
if portsLabel, ok = service.Labels[labels.LabelPorts]; !ok { if portsLabel, ok = service.Labels[labels.LabelPorts]; !ok {
return nil return nil
} }
ports, err := labelStructs.PortsFrom(portsLabel) ports, err := labelstructs.PortsFrom(portsLabel)
if err != nil { if err != nil {
// maybe it's a string, comma separated // maybe it's a string, comma separated
parts := strings.SplitSeq(portsLabel, ",") parts := strings.SplitSeq(portsLabel, ",")

View File

@@ -3,6 +3,7 @@ package generator
import ( import (
"fmt" "fmt"
"katenary/generator/labels" "katenary/generator/labels"
"katenary/utils"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@@ -25,7 +26,7 @@ services:
} }
composeFile := filepath.Join(tmpDir, "compose.yaml") composeFile := filepath.Join(tmpDir, "compose.yaml")
os.MkdirAll(tmpDir, 0755) os.MkdirAll(tmpDir, utils.DirectoryPermission)
if err := os.WriteFile(composeFile, []byte(composeFileContent), 0644); err != nil { if err := os.WriteFile(composeFile, []byte(composeFileContent), 0644); err != nil {
t.Log(err) t.Log(err)
} }
@@ -73,7 +74,7 @@ services:
} }
composeFile := filepath.Join(tmpDir, "compose.yaml") composeFile := filepath.Join(tmpDir, "compose.yaml")
os.MkdirAll(tmpDir, 0755) os.MkdirAll(tmpDir, utils.DirectoryPermission)
if err := os.WriteFile(composeFile, []byte(composeFileContent), 0644); err != nil { if err := os.WriteFile(composeFile, []byte(composeFileContent), 0644); err != nil {
t.Log(err) t.Log(err)
} }

View File

@@ -6,6 +6,7 @@ import (
"image/color" "image/color"
"image/png" "image/png"
"katenary/generator/labels" "katenary/generator/labels"
"katenary/utils"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
@@ -19,7 +20,7 @@ import (
const ( const (
htmlContent = "<html><body><h1>Hello, World!</h1></body></html>" htmlContent = "<html><body><h1>Hello, World!</h1></body></html>"
developementFile = "templates/web/deployment.yaml" developementFile = "templates/web/deployment.yaml"
indexHtmlFile = "index.html" indexHMLFile = "index.html"
) )
func TestGenerateWithBoundVolume(t *testing.T) { func TestGenerateWithBoundVolume(t *testing.T) {
@@ -68,7 +69,7 @@ services:
// create a static directory with an index.html file // create a static directory with an index.html file
staticDir := tmpDir + "/static" staticDir := tmpDir + "/static"
os.Mkdir(staticDir, 0o755) os.Mkdir(staticDir, utils.DirectoryPermission)
indexFile, err := os.Create(staticDir + "/index.html") indexFile, err := os.Create(staticDir + "/index.html")
if err != nil { if err != nil {
t.Errorf("Failed to create index.html: %s", err) t.Errorf("Failed to create index.html: %s", err)
@@ -106,8 +107,8 @@ services:
if len(data) != 1 { if len(data) != 1 {
t.Errorf("Expected 1 data, got %d", len(data)) t.Errorf("Expected 1 data, got %d", len(data))
} }
if data[indexHtmlFile] != htmlContent { if data[indexHMLFile] != htmlContent {
t.Errorf("Expected index.html to be "+htmlContent+", got %s", data[indexHtmlFile]) t.Errorf("Expected index.html to be "+htmlContent+", got %s", data[indexHMLFile])
} }
} }
@@ -128,7 +129,7 @@ services:
// create a static directory with an index.html file // create a static directory with an index.html file
staticDir := tmpDir + "/static" staticDir := tmpDir + "/static"
os.Mkdir(staticDir, 0o755) os.Mkdir(staticDir, utils.DirectoryPermission)
indexFile, err := os.Create(staticDir + "/index.html") indexFile, err := os.Create(staticDir + "/index.html")
if err != nil { if err != nil {
t.Errorf("Failed to create index.html: %s", err) t.Errorf("Failed to create index.html: %s", err)
@@ -153,7 +154,7 @@ services:
} }
// but this time, we need a subpath // but this time, we need a subpath
subPath := dt.Spec.Template.Spec.Containers[0].VolumeMounts[0].SubPath subPath := dt.Spec.Template.Spec.Containers[0].VolumeMounts[0].SubPath
if subPath != indexHtmlFile { if subPath != indexHMLFile {
t.Errorf("Expected subpath to be index.html, got %s", subPath) t.Errorf("Expected subpath to be index.html, got %s", subPath)
} }
} }
@@ -174,15 +175,15 @@ services:
log.Println(tmpDir) log.Println(tmpDir)
defer teardown(tmpDir) defer teardown(tmpDir)
os.Mkdir(filepath.Join(tmpDir, "images"), 0o755) os.Mkdir(filepath.Join(tmpDir, "images"), utils.DirectoryPermission)
// create a png image // create a png image
pngFile := tmpDir + "/images/foo.png" pngFile := tmpDir + "/images/foo.png"
w, h := 100, 100 w, h := 100, 100
img := image.NewRGBA(image.Rect(0, 0, w, h)) img := image.NewRGBA(image.Rect(0, 0, w, h))
red := color.RGBA{255, 0, 0, 255} red := color.RGBA{255, 0, 0, 255}
for y := 0; y < h; y++ { for y := range h {
for x := 0; x < w; x++ { for x := range w {
img.Set(x, y, red) img.Set(x, y, red)
} }
} }
@@ -244,15 +245,15 @@ services:
log.Println(tmpDir) log.Println(tmpDir)
defer teardown(tmpDir) defer teardown(tmpDir)
os.Mkdir(filepath.Join(tmpDir, "images"), 0o755) os.Mkdir(filepath.Join(tmpDir, "images"), utils.DirectoryPermission)
// create a png image // create a png image
pngFile := tmpDir + "/images/foo.png" pngFile := tmpDir + "/images/foo.png"
w, h := 100, 100 w, h := 100, 100
img := image.NewRGBA(image.Rect(0, 0, w, h)) img := image.NewRGBA(image.Rect(0, 0, w, h))
red := color.RGBA{255, 0, 0, 255} red := color.RGBA{255, 0, 0, 255}
for y := 0; y < h; y++ { for y := range h {
for x := 0; x < w; x++ { for x := range w {
img.Set(x, y, red) img.Set(x, y, red)
} }
} }

View File

@@ -35,8 +35,8 @@ if [ -z "$INSTALL_PATH" ]; then
fi fi
# ensure that $INSTALL_PATH is in the PATH # ensure that $INSTALL_PATH is in the PATH
if ! echo $PATH | grep -q $INSTALL_PATH; then if ! echo "$PATH" | grep -q "$INSTALL_PATH"; then
echo "Sorry, $INSTALL_PATH is not in the PATH" echo "Sorry, ${INSTALL_PATH} is not in the PATH"
echo "Please, add it to your PATH in your shell configuration file" echo "Please, add it to your PATH in your shell configuration file"
echo "then restart your shell and run this script again" echo "then restart your shell and run this script again"
exit 1 exit 1
@@ -58,8 +58,8 @@ echo "Downloading $BIN_URL"
T=$(mktemp -u) T=$(mktemp -u)
curl -SL -# $BIN_URL -o $T || (echo "Failed to download katenary" && rm -f $T && exit 1) curl -SL -# $BIN_URL -o $T || (echo "Failed to download katenary" && rm -f $T && exit 1)
mv $T $INSTALL_PATH/katenary mv "$T" "${INSTALL_PATH}/katenary"
chmod +x $INSTALL_PATH/katenary chmod +x "${INSTALL_PATH}/katenary"
echo echo
echo "Installed to $INSTALL_PATH/katenary" echo "Installed to $INSTALL_PATH/katenary"
echo "Installation complete! Run 'katenary help' to get started." echo "Installation complete! Run 'katenary help' to get started."

View File

@@ -14,6 +14,9 @@ import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
) )
// DirectoryPermission is the default values for permissions apply to created directories.
const DirectoryPermission = 0o755
// TplName returns the name of the kubernetes resource as a template string. // TplName returns the name of the kubernetes resource as a template string.
// It is used in the templates and defined in _helper.tpl file. // It is used in the templates and defined in _helper.tpl file.
func TplName(serviceName, appname string, suffix ...string) string { func TplName(serviceName, appname string, suffix ...string) string {