Code cleaning

Using gofumpt. Add documentation.
Some fixes on type checking and const icon type declaration.
This commit is contained in:
2024-04-05 07:56:27 +02:00
parent 2aad5d4b9d
commit 441b30a570
16 changed files with 86 additions and 93 deletions

View File

@@ -2,11 +2,12 @@ package main
import (
"fmt"
"katenary/generator"
"katenary/utils"
"os"
"strings"
"katenary/generator"
"katenary/utils"
"github.com/compose-spec/compose-go/cli"
"github.com/spf13/cobra"
)
@@ -151,7 +152,6 @@ func generateConvertCommand() *cobra.Command {
convertCmd.Flags().StringVarP(&givenAppVersion, "app-version", "a", "", "Specify the app version (in Chart.yaml)")
convertCmd.Flags().StringVarP(&chartVersion, "chart-version", "v", chartVersion, "Specify the chart version (in Chart.yaml)")
return convertCmd
}
func generateVersionCommand() *cobra.Command {
@@ -165,7 +165,6 @@ func generateVersionCommand() *cobra.Command {
}
func generateLabelHelpCommand() *cobra.Command {
markdown := false
all := false
cmd := &cobra.Command{

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -4,9 +4,6 @@ import (
"bytes"
"errors"
"fmt"
"katenary/generator/extrafiles"
"katenary/parser"
"katenary/utils"
"log"
"os"
"os/exec"
@@ -15,6 +12,10 @@ import (
"strings"
"time"
"katenary/generator/extrafiles"
"katenary/parser"
"katenary/utils"
"github.com/compose-spec/compose-go/types"
goyaml "gopkg.in/yaml.v3"
)
@@ -34,7 +35,6 @@ const headerHelp = `# This file is autogenerated by katenary
// Convert a compose (docker, podman...) project to a helm chart.
// It calls Generate() to generate the chart and then write it to the disk.
func Convert(config ConvertOptions, dockerComposeFile ...string) {
var (
templateDir = filepath.Join(config.OutputDir, "templates")
helpersPath = filepath.Join(config.OutputDir, "templates", "_helpers.tpl")
@@ -103,7 +103,7 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
os.RemoveAll(config.OutputDir)
// create the chart directory
if err := os.MkdirAll(templateDir, 0755); err != nil {
if err := os.MkdirAll(templateDir, 0o755); err != nil {
fmt.Println(utils.IconFailure, err)
os.Exit(1)
}
@@ -134,7 +134,7 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
}
servicename := template.Servicename
if err := os.MkdirAll(filepath.Join(templateDir, servicename), 0755); err != nil {
if err := os.MkdirAll(filepath.Join(templateDir, servicename), 0o755); err != nil {
fmt.Println(utils.IconFailure, err)
os.Exit(1)
}
@@ -142,7 +142,7 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
// if the name is a path, create the directory
if strings.Contains(name, string(filepath.Separator)) {
name = filepath.Join(templateDir, name)
err := os.MkdirAll(filepath.Dir(name), 0755)
err := os.MkdirAll(filepath.Dir(name), 0o755)
if err != nil {
fmt.Println(utils.IconFailure, err)
os.Exit(1)
@@ -163,7 +163,6 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
}
// calculate the sha1 hash of the services
buf := bytes.NewBuffer(nil)
encoder := goyaml.NewEncoder(buf)
encoder.SetIndent(2)
@@ -437,7 +436,6 @@ func addChartDoc(values []byte, project *types.Project) []byte {
}
}
return []byte(chartDoc + strings.Join(lines, "\n"))
}
const imagePullPolicyHelp = `# imagePullPolicy allows you to specify a policy to cache or always pull an image.
@@ -466,7 +464,6 @@ func addImagePullPolicyHelp(values []byte) []byte {
}
func addVariablesDoc(values []byte, project *types.Project) []byte {
lines := strings.Split(string(values), "\n")
currentService := ""
@@ -550,7 +547,6 @@ func removeNewlinesInsideBrackets(values []byte) []byte {
replacement = regexp.MustCompile(`\s+`).ReplaceAll(replacement, []byte(" "))
// remove newlines inside brackets
return bytes.ReplaceAll(b, matches[1], replacement)
})
}
@@ -607,8 +603,8 @@ func checkOldLabels(project *types.Project) error {
return nil
}
// helmUpdate runs "helm dependency update" on the output directory.
func helmUpdate(config ConvertOptions) error {
// lookup for "helm" binary
fmt.Println(utils.IconInfo, "Updating helm dependencies...")
helm, err := exec.LookPath("helm")
@@ -623,8 +619,8 @@ func helmUpdate(config ConvertOptions) error {
return cmd.Run()
}
// helmLint runs "helm lint" on the output directory.
func helmLint(config ConvertOptions) error {
fmt.Println(utils.IconInfo, "Linting...")
helm, err := exec.LookPath("helm")
if err != nil {
@@ -635,5 +631,4 @@ func helmLint(config ConvertOptions) error {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}

View File

@@ -1,10 +1,11 @@
package generator
import (
"katenary/utils"
"log"
"strings"
"katenary/utils"
"github.com/compose-spec/compose-go/types"
goyaml "gopkg.in/yaml.v3"
batchv1 "k8s.io/api/batch/v1"
@@ -26,7 +27,7 @@ type CronJob struct {
// NewCronJob creates a new CronJob from a compose service. The appName is the name of the application taken from the project name.
func NewCronJob(service types.ServiceConfig, chart *HelmChart, appName string) (*CronJob, *RBAC) {
var labels, ok = service.Labels[LABEL_CRONJOB]
labels, ok := service.Labels[LABEL_CRONJOB]
if !ok {
return nil, nil
}

View File

@@ -2,7 +2,6 @@ package generator
import (
"fmt"
"katenary/utils"
"log"
"os"
"path/filepath"
@@ -10,6 +9,8 @@ import (
"strings"
"time"
"katenary/utils"
"github.com/compose-spec/compose-go/types"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
@@ -32,7 +33,6 @@ type Deployment struct {
// NewDeployment creates a new Deployment from a compose service. The appName is the name of the application taken from the project name.
// It also creates the Values map that will be used to create the values.yaml file.
func NewDeployment(service types.ServiceConfig, chart *HelmChart) *Deployment {
isMainApp := false
if mainLabel, ok := service.Labels[LABEL_MAIN_APP]; ok {
main := strings.ToLower(mainLabel)
@@ -163,7 +163,6 @@ func (d *Deployment) AddIngress(service types.ServiceConfig, appName string) *In
// AddVolumes adds a volume to the deployment. It does not create the PVC, it only adds the volumes to the deployment.
// If the volume is a bind volume it will warn the user that it is not supported yet.
func (d *Deployment) AddVolumes(service types.ServiceConfig, appName string) {
tobind := map[string]bool{}
if v, ok := service.Labels[LABEL_CM_FILES]; ok {
binds := []string{}
@@ -323,7 +322,6 @@ func (d *Deployment) BindFrom(service types.ServiceConfig, binded *Deployment) {
// SetEnvFrom sets the environment variables to a configmap. The configmap is created.
func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string) {
if len(service.Environment) == 0 {
return
}
@@ -419,7 +417,6 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string) {
}
func (d *Deployment) AddHealthCheck(service types.ServiceConfig, container *corev1.Container) {
// get the label for healthcheck
if v, ok := service.Labels[LABEL_HEALTHCHECK]; ok {
probes := struct {
@@ -473,7 +470,6 @@ func (d *Deployment) Yaml() ([]byte, error) {
volumeName = strings.TrimSpace(strings.Replace(content[i], "name: ", "", 1))
break
}
}
if volumeName == "" {
continue
@@ -561,6 +557,7 @@ func (d *Deployment) Yaml() ([]byte, error) {
return []byte(strings.Join(content, "\n")), nil
}
// Filename returns the filename of the deployment.
func (d *Deployment) Filename() string {
return d.service.Name + ".deployment.yaml"
}

View File

@@ -5,7 +5,6 @@ package generator
import (
"bytes"
"fmt"
"katenary/utils"
"log"
"os"
"path/filepath"
@@ -13,6 +12,8 @@ import (
"strconv"
"strings"
"katenary/utils"
"github.com/compose-spec/compose-go/types"
goyaml "gopkg.in/yaml.v3"
corev1 "k8s.io/api/core/v1"
@@ -24,23 +25,15 @@ import (
//
// The Generate function will create the HelmChart object this way:
//
// 1. Detect the service port name or leave the port number if not found.
//
// 2. Create a deployment for each service that are not ingnore.
//
// 3. Create a service and ingresses for each service that has ports and/or declared ingresses.
//
// 4. Create a PVC or Configmap volumes for each volume.
//
// 5. Create init containers for each service which has dependencies to other services.
//
// 6. Create a chart dependencies.
//
// 7. Create a configmap and secrets from the environment variables.
//
// 8. Merge the same-pod services.
// - Detect the service port name or leave the port number if not found.
// - Create a deployment for each service that are not ingnore.
// - Create a service and ingresses for each service that has ports and/or declared ingresses.
// - Create a PVC or Configmap volumes for each volume.
// - Create init containers for each service which has dependencies to other services.
// - Create a chart dependencies.
// - Create a configmap and secrets from the environment variables.
// - Merge the same-pod services.
func Generate(project *types.Project) (*HelmChart, error) {
var (
appName = project.Name
deployments = make(map[string]*Deployment, len(project.Services))
@@ -226,7 +219,6 @@ func computeNIndent(b []byte) []byte {
//
// we now want to replace it with {{ include "foo.labels" . }}, without the label name.
func removeReplaceString(b []byte) []byte {
// replace all matches with the value of the capture group
// and remove all new lines and repeated spaces
b = replaceLabelRegexp.ReplaceAllFunc(b, func(b []byte) []byte {
@@ -239,6 +231,7 @@ func removeReplaceString(b []byte) []byte {
return b
}
// serviceIsMain returns true if the service is the main app.
func serviceIsMain(service types.ServiceConfig) bool {
if main, ok := service.Labels[LABEL_MAIN_APP]; ok {
return main == "true" || main == "yes" || main == "1"
@@ -246,6 +239,7 @@ func serviceIsMain(service types.ServiceConfig) bool {
return false
}
// setChartVersion sets the chart version from the service image tag.
func setChartVersion(chart *HelmChart, service types.ServiceConfig) {
if chart.Version == "" {
image := service.Image
@@ -258,6 +252,7 @@ func setChartVersion(chart *HelmChart, service types.ServiceConfig) {
}
}
// fixPorts checks the "ports" label from container and add it to the service.
func fixPorts(service *types.ServiceConfig) error {
// check the "ports" label from container and add it to the service
if portsLabel, ok := service.Labels[LABEL_PORTS]; ok {
@@ -286,6 +281,7 @@ func fixPorts(service *types.ServiceConfig) error {
return nil
}
// setCronJob creates a cronjob from the service labels.
func setCronJob(service types.ServiceConfig, chart *HelmChart, appName string) *CronJob {
if _, ok := service.Labels[LABEL_CRONJOB]; !ok {
return nil
@@ -318,6 +314,7 @@ func setCronJob(service types.ServiceConfig, chart *HelmChart, appName string) *
return cronjob
}
// setDependencies sets the dependencies from the service labels.
func setDependencies(chart *HelmChart, service types.ServiceConfig) (bool, error) {
// helm dependency
if v, ok := service.Labels[LABEL_DEPENDENCIES]; ok {
@@ -342,6 +339,7 @@ func setDependencies(chart *HelmChart, service types.ServiceConfig) (bool, error
return false, nil
}
// isIgnored returns true if the service is ignored.
func isIgnored(service types.ServiceConfig) bool {
if v, ok := service.Labels[LABEL_IGNORE]; ok {
return v == "true" || v == "yes" || v == "1"
@@ -349,6 +347,7 @@ func isIgnored(service types.ServiceConfig) bool {
return false
}
// buildVolumes creates the volumes for the service.
func buildVolumes(service types.ServiceConfig, chart *HelmChart, deployments map[string]*Deployment) error {
appName := chart.Name
for _, v := range service.Volumes {
@@ -371,7 +370,7 @@ func buildVolumes(service types.ServiceConfig, chart *HelmChart, deployments map
y, _ := pvc.Yaml()
chart.Templates[pvc.Filename()] = &ChartTemplate{
Content: y,
Servicename: service.Name, //TODO, use name
Servicename: service.Name, // TODO, use name
}
case "bind":
@@ -437,6 +436,7 @@ func buildVolumes(service types.ServiceConfig, chart *HelmChart, deployments map
return nil
}
// generateConfigMapsAndSecrets creates the configmaps and secrets from the environment variables.
func generateConfigMapsAndSecrets(project *types.Project, chart *HelmChart) error {
appName := chart.Name
for _, s := range project.Services {
@@ -498,6 +498,7 @@ func generateConfigMapsAndSecrets(project *types.Project, chart *HelmChart) erro
return nil
}
// samePodVolume returns true if the volume is already in the target deployment.
func samePodVolume(service types.ServiceConfig, v types.ServiceVolumeConfig, deployments map[string]*Deployment) bool {
// if the service has volumes, and it has "same-pod" label
// - get the target deployment
@@ -541,6 +542,7 @@ func samePodVolume(service types.ServiceConfig, v types.ServiceVolumeConfig, dep
return false
}
// setSharedConf sets the shared configmap to the service.
func setSharedConf(service types.ServiceConfig, chart *HelmChart, deployments map[string]*Deployment) {
// if the service has the "shared-conf" label, we need to add the configmap
// to the chart and add the env vars to the service
@@ -583,5 +585,4 @@ func setSharedConf(service types.ServiceConfig, chart *HelmChart, deployments ma
target.Spec.Template.Spec.Containers[i] = c
}
}
}

View File

@@ -1,10 +1,11 @@
package generator
import (
"katenary/utils"
"log"
"strings"
"katenary/utils"
"github.com/compose-spec/compose-go/types"
goyaml "gopkg.in/yaml.v3"
networkv1 "k8s.io/api/networking/v1"
@@ -21,7 +22,6 @@ type Ingress struct {
// NewIngress creates a new Ingress from a compose service.
func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
appName := Chart.Name
// parse the KATENARY_PREFIX/ingress label from the service
@@ -73,7 +73,7 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
Annotations: map[string]string{},
}
//ingressClassName := `{{ .Values.` + service.Name + `.ingress.class }}`
// ingressClassName := `{{ .Values.` + service.Name + `.ingress.class }}`
ingressClassName := utils.TplValue(service.Name, "ingress.class")
servicePortName := utils.GetServiceNameByPort(int(mapping["port"].(int32)))
@@ -173,7 +173,6 @@ func (ingress *Ingress) Yaml() ([]byte, error) {
out = append(out, `{{- end -}}`)
ret = []byte(strings.Join(out, "\n"))
return ret, nil
}
func (ingress *Ingress) Filename() string {

View File

@@ -4,13 +4,14 @@ import (
"bytes"
_ "embed"
"fmt"
"katenary/utils"
"regexp"
"sort"
"strings"
"text/tabwriter"
"text/template"
"katenary/utils"
"sigs.k8s.io/yaml"
)
@@ -139,7 +140,6 @@ func generateTableHeaderSeparator(maxNameLength, maxDescriptionLength, maxTypeLe
// GetLabelHelpFor returns the help for a specific label.
func GetLabelHelpFor(labelname string, asMarkdown bool) string {
help, ok := labelFullHelp[labelname]
if !ok {
return "No help available for " + labelname + "."
@@ -225,5 +225,4 @@ Type: {{ .Help.Type }}
Example:
{{ .Help.Example }}
`
}

View File

@@ -13,6 +13,8 @@ const (
ServiceLabel
)
// GetLabels returns the labels for a service. It uses the appName to replace the __replace__ in the labels.
// This is used to generate the labels in the templates.
func GetLabels(serviceName, appName string) map[string]string {
labels := map[string]string{
KATENARY_PREFIX + "component": serviceName,
@@ -24,6 +26,8 @@ func GetLabels(serviceName, appName string) map[string]string {
return labels
}
// GetMatchLabels returns the matchLabels for a service. It uses the appName to replace the __replace__ in the labels.
// This is used to generate the matchLabels in the templates.
func GetMatchLabels(serviceName, appName string) map[string]string {
labels := map[string]string{
KATENARY_PREFIX + "component": serviceName,

View File

@@ -3,17 +3,20 @@ package generator
import (
"encoding/base64"
"fmt"
"katenary/utils"
"strings"
"katenary/utils"
"github.com/compose-spec/compose-go/types"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)
var _ DataMap = (*Secret)(nil)
var _ Yaml = (*Secret)(nil)
var (
_ DataMap = (*Secret)(nil)
_ Yaml = (*Secret)(nil)
)
// Secret is a kubernetes Secret.
//
@@ -78,7 +81,6 @@ func (s *Secret) SetData(data map[string]string) {
for key, value := range data {
s.AddData(key, value)
}
}
// AddData adds a key value pair to the secret.

View File

@@ -1,10 +1,11 @@
package generator
import (
"katenary/utils"
"regexp"
"strings"
"katenary/utils"
"github.com/compose-spec/compose-go/types"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -22,7 +23,6 @@ type Service struct {
// NewService creates a new Service from a compose service.
func NewService(service types.ServiceConfig, appName string) *Service {
ports := []v1.ServicePort{}
s := &Service{

View File

@@ -1,9 +1,10 @@
package generator
import (
"katenary/utils"
"strings"
"katenary/utils"
"github.com/compose-spec/compose-go/types"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
@@ -59,7 +60,6 @@ func (v *VolumeClaim) Yaml() ([]byte, error) {
}
volumeName := v.volumeName
out, err := yaml.Marshal(v)
if err != nil {
return nil, err
}

View File

@@ -8,7 +8,6 @@ import (
// Parse compose files and return a project. The project is parsed with dotenv, osenv and profiles.
func Parse(profiles []string, dockerComposeFile ...string) (*types.Project, error) {
cli.DefaultOverrideFileNames = append(cli.DefaultOverrideFileNames, "compose.katenary.yaml")
if len(dockerComposeFile) == 0 {
@@ -23,8 +22,6 @@ func Parse(profiles []string, dockerComposeFile ...string) (*types.Project, erro
cli.WithNormalization(true),
cli.WithInterpolation(true),
cli.WithResolvedPaths(false),
//cli.WithResolvedPaths(true),
)
if err != nil {
return nil, err

View File

@@ -14,8 +14,10 @@ import (
"golang.org/x/mod/semver"
)
var exe, _ = os.Executable()
var Version = "master" // reset by cmd/main.go
var (
exe, _ = os.Executable()
Version = "master" // reset by cmd/main.go
)
// Asset is a github asset from release url.
type Asset struct {
@@ -25,7 +27,6 @@ type Asset struct {
// CheckLatestVersion check katenary latest version from release and propose to download it
func CheckLatestVersion() (string, []Asset, error) {
githuburl := "https://api.github.com/repos/metal3d/katenary/releases/latest"
// Create a HTTP client with 1s timeout
client := &http.Client{
@@ -45,7 +46,7 @@ func CheckLatestVersion() (string, []Asset, error) {
defer resp.Body.Close()
// Get tag_name from the json response
var release = struct {
release := struct {
TagName string `json:"tag_name"`
Assets []Asset `json:"assets"`
PreRelease bool `json:"prerelease"`
@@ -57,19 +58,19 @@ func CheckLatestVersion() (string, []Asset, error) {
// if it's a prerelease, don't update
if release.PreRelease {
return "", nil, errors.New("Prerelease detected, not updating")
return "", nil, errors.New("prerelease detected, not updating")
}
// no tag, don't update
if release.TagName == "" {
return "", nil, errors.New("No release found")
return "", nil, errors.New("no release found")
}
// compare the current version, if the current version is the same or lower than the latest version, don't update
versions := []string{Version, release.TagName}
semver.Sort(versions)
if versions[1] == Version {
return "", nil, errors.New("Current version is the latest version")
return "", nil, errors.New("current version is the latest version")
}
return release.TagName, release.Assets, nil
@@ -77,7 +78,6 @@ func CheckLatestVersion() (string, []Asset, error) {
// DownloadLatestVersion will download the latest version of katenary.
func DownloadLatestVersion(assets []Asset) error {
defer func() {
if r := recover(); r != nil {
os.Rename(exe+".old", exe)
@@ -117,7 +117,7 @@ func DownloadLatestVersion(assets []Asset) error {
}
default:
fmt.Println("Unsupported OS")
err = errors.New("Unsupported OS")
err = errors.New("unsupported OS")
}
}
if err == nil {
@@ -138,7 +138,7 @@ func DownloadFile(url, exe string) error {
return err
}
defer resp.Body.Close()
fp, err := os.OpenFile(exe, os.O_WRONLY|os.O_CREATE, 0755)
fp, err := os.OpenFile(exe, os.O_WRONLY|os.O_CREATE, 0o755)
if err != nil {
return err
}

View File

@@ -8,17 +8,17 @@ type Icon string
// Icons used in katenary.
const (
IconSuccess Icon = "✅"
IconFailure = "❌"
IconWarning = "⚠️'"
IconNote = "📝"
IconWorld = "🌐"
IconPlug = "🔌"
IconPackage = "📦"
IconCabinet = "🗄️"
IconInfo = "❕"
IconSecret = "🔒"
IconConfig = "🔧"
IconDependency = "🔗"
IconFailure Icon = "❌"
IconWarning Icon = "⚠️'"
IconNote Icon = "📝"
IconWorld Icon = "🌐"
IconPlug Icon = "🔌"
IconPackage Icon = "📦"
IconCabinet Icon = "🗄️"
IconInfo Icon = "❕"
IconSecret Icon = "🔒"
IconConfig Icon = "🔧"
IconDependency Icon = "🔗"
)
// Warn prints a warning message

View File

@@ -90,7 +90,6 @@ func GetContainerByName(name string, containers []corev1.Container) (*corev1.Con
// GetContainerByName returns a container by name and its index in the array.
func TplValue(serviceName, variable string, pipes ...string) string {
if len(pipes) == 0 {
return `{{ tpl .Values.` + serviceName + `.` + variable + ` $ }}`
} else {
@@ -108,8 +107,8 @@ func PathToName(path string) string {
if path[0] == '/' || path[0] == '.' {
path = path[1:]
}
path = strings.Replace(path, "/", "_", -1)
path = strings.Replace(path, ".", "_", -1)
path = strings.ReplaceAll(path, "/", "_")
path = strings.ReplaceAll(path, ".", "_")
return path
}
@@ -130,9 +129,9 @@ func GetValuesFromLabel(service types.ServiceConfig, LabelValues string) map[str
log.Fatal(err)
}
for _, value := range labelContent {
switch value.(type) {
switch val := value.(type) {
case string:
descriptions[value.(string)] = nil
descriptions[val] = nil
case map[string]interface{}:
for k, v := range value.(map[string]interface{}) {
descriptions[k] = &EnvConfig{Service: service, Description: v.(string)}