Skip to content

Commit

Permalink
Add asset generation generate cmd
Browse files Browse the repository at this point in the history
Signed-off-by: Jordi Gil <jgil@redhat.com>
Signed-off-by: Gloria Ciavarrini <gciavarrini@redhat.com>
  • Loading branch information
gciavarrini committed Feb 20, 2025
1 parent ddc7da7 commit 34f75c3
Show file tree
Hide file tree
Showing 17 changed files with 893 additions and 1 deletion.
21 changes: 21 additions & 0 deletions cmd/asset_generation/generate/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package generate

import (
"github.com/go-logr/logr"
"github.com/konveyor-ecosystem/kantra/cmd/asset_generation/generate/helm"
"github.com/spf13/cobra"
)

func NewGenerateCommand(log logr.Logger) *cobra.Command {
cmd := &cobra.Command{
Use: "generate",
GroupID: "assetGeneration",
Short: "Analyze the source platform and/or application and output discovery manifest.",
Run: func(cmd *cobra.Command, _ []string) {
cmd.Help()
},
}
cmd.AddCommand(helm.NewGenerateHelmCommand(log))

return cmd
}
13 changes: 13 additions & 0 deletions cmd/asset_generation/generate/generate_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package generate_test

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestGenerate(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Generate Suite")
}
68 changes: 68 additions & 0 deletions cmd/asset_generation/generate/generate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package generate_test

import (
"bufio"
"bytes"

"github.com/bombsimon/logrusr/v3"
"github.com/go-logr/logr"
"github.com/konveyor-ecosystem/kantra/cmd/asset_generation/generate"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var _ = Describe("Generate Command", func() {

var _ = Context("Flag Behavior Verification", func() {

var (
logger logr.Logger
out bytes.Buffer
err bytes.Buffer
writer *bufio.Writer = bufio.NewWriter(&out)
c *cobra.Command
)

var _ = BeforeEach(func() {
// Reset buffers before each test
writer.Reset(&out)

// Set up logger
logrusLog := logrus.New()
logrusLog.SetOutput(&out)
logrusLog.SetFormatter(&logrus.TextFormatter{})
logger = logrusr.New(logrusLog)

// Create command instance
c = generate.NewGenerateCommand(logger)
c.SetOut(writer)
c.SetErr(&err)
})

DescribeTable("Command Flag Behavior",
func(args []string, expectedOutput string, expectError bool, expectedError string) {
c.SetArgs(args)
err := c.Execute()
writer.Flush()
if expectError {
Expect(err).To(HaveOccurred())
Expect(err).Should(MatchError(expectedError))
} else {
Expect(err).NotTo(HaveOccurred())
}
Expect(out.String()).To(ContainSubstring(expectedOutput))

},
Entry("should print the help message when no flags are used containing entries for each template engine",
[]string{}, "helm generate the helm template manifests", false, ""),

Entry("should return an error message for an invalid command",
[]string{"invalid-command"}, "", true, "unknown command \"invalid-command\" for \"generate\""),

Entry("should return an error message for an invalid flag",
[]string{"--invalid-flag"}, "Usage:\n", true, "unknown flag: --invalid-flag"),
)
})
})
192 changes: 192 additions & 0 deletions cmd/asset_generation/generate/helm/helm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package helm

import (
"fmt"
"io"
"maps"
"os"
"path/filepath"
"strings"

"github.com/go-logr/logr"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
"k8s.io/helm/pkg/strvals"

"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/engine"
)

const (
konveyorDirectoryName = "files/konveyor"
)

var (
input string
outputDir string
chartDir string
nonK8SOnly bool
setValues []string
)

func NewGenerateHelmCommand(log logr.Logger) *cobra.Command {
cmd := &cobra.Command{
Use: "helm",
Short: "generate the helm template manifests",
RunE: func(cmd *cobra.Command, args []string) error {
return helm(cmd.OutOrStdout())
},
}
cmd.Flags().StringVar(&chartDir, "chart-dir", "", "Directory to the Helm chart to use for chart generation.")
cmd.Flags().StringVar(&input, "input", "", "Specifies the discover manifest file")
cmd.Flags().StringVar(&outputDir, "output-dir", "", "Directory to save the generated Helm chart. Defaults to stdout")
cmd.Flags().BoolVar(&nonK8SOnly, "non-k8s-only", false, "Render only the non-Kubernetes templates located in the files/konveyor directory of the chart")
cmd.Flags().StringArrayVar(&setValues, "set", []string{}, "Set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")

// Validation
cmd.MarkFlagDirname("chart-dir")
cmd.MarkFlagDirname("output-dir")
cmd.MarkFlagFilename("input")
// Required
cmd.MarkFlagRequired("chart-dir")
cmd.MarkFlagRequired("input")

return cmd
}

func helm(out io.Writer) error {
chart, err := loadChart()
if err != nil {
return err
}
values, err := loadDiscoverManifest()
if err != nil {
return err
}
if len(setValues) > 0 {
v, err := parseValues()
if err != nil {
return err
}
maps.Copy(values, v)
}
chart.Values = values
rendered := make(map[string]string)
if !nonK8SOnly {
rendered, err = generateK8sTemplates(*chart)
if err != nil {
return err
}
}
r, err := generateNonK8sTemplates(*chart)
if err != nil {
return err
}
maps.Copy(rendered, r)

o := output{out: out}
print := o.toStdout
if outputDir != "" {
err = os.MkdirAll(outputDir, 0755)
if err != nil {
return err
}
print = toFile
}
for f, c := range rendered {
err = print(f, c)
if err != nil {
return err
}
}
return nil
}

type output struct {
out io.Writer
}

func (o output) toStdout(filename, contents string) error {
fmt.Fprintf(o.out, "---\n# Source: %s\n%s", filename, contents)
return nil
}

func toFile(filename, contents string) error {
fn := filepath.Base(filename)
dst := filepath.Join(outputDir, fn)
// Add an extra line to make it yaml compliant since helm doesn't seem to do it.
contents = fmt.Sprintln(contents)
return os.WriteFile(dst, []byte(contents), 0644)
}

func loadChart() (*chart.Chart, error) {
l, err := loader.Loader(chartDir)
if err != nil {
return nil, fmt.Errorf("unable to load chart: %s", err)
}
return l.Load()
}

func loadDiscoverManifest() (map[string]interface{}, error) {
d, err := os.ReadFile(input)
if err != nil {
return nil, fmt.Errorf("unable to load discover manifest: %s", err)
}
var m map[string]interface{}
err = yaml.Unmarshal(d, &m)
return m, err
}

func generateK8sTemplates(chart chart.Chart) (map[string]string, error) {
return generateTemplates(chart)
}

func generateNonK8sTemplates(chart chart.Chart) (map[string]string, error) {
chart.Templates = filterTemplatesByPath(konveyorDirectoryName, chart.Files)
return generateTemplates(chart)
}

func generateTemplates(chart chart.Chart) (map[string]string, error) {
e := engine.Engine{}
options := chartutil.ReleaseOptions{
Name: chart.Name(),
Namespace: "",
Revision: 1,
IsInstall: false,
IsUpgrade: false,
}
valuesToRender, err := chartutil.ToRenderValues(&chart, chart.Values, options, chartutil.DefaultCapabilities.Copy())
if err != nil {
return nil, fmt.Errorf("failed to render the values for chart %s: %s", chart.Name(), err)
}
chart.Values = valuesToRender
rendered, err := e.Render(&chart, valuesToRender)
if err != nil {
return nil, fmt.Errorf("failed to render the templates for chart %s: %s", chart.Name(), err)
}
return rendered, nil

}

func filterTemplatesByPath(pathPrefix string, files []*chart.File) []*chart.File {
ret := []*chart.File{}
for _, f := range files {
if strings.HasPrefix(f.Name, pathPrefix) {
ret = append(ret, f)
}
}
return ret
}

func parseValues() (map[string]interface{}, error) {
// User specified a value via --set
base := make(map[string]interface{})
for _, value := range setValues {
if err := strvals.ParseInto(value, base); err != nil {
return nil, fmt.Errorf("failed parsing --set data:%s", err)
}
}
return base, nil
}
13 changes: 13 additions & 0 deletions cmd/asset_generation/generate/helm/helm_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package helm_test

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestHelm(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Helm Suite")
}
Loading

0 comments on commit 34f75c3

Please sign in to comment.