Skip to content

Commit

Permalink
Merge pull request #554 from sighupio/feat/use-kapp-instead
Browse files Browse the repository at this point in the history
feat: enable `kapp` support
  • Loading branch information
kriive authored Nov 20, 2024
2 parents cc24274 + e2df617 commit 91e9f18
Show file tree
Hide file tree
Showing 15 changed files with 427 additions and 9 deletions.
4 changes: 4 additions & 0 deletions internal/cluster/phase.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ type OperationPhase struct {
YqPath string
HelmPath string
HelmfilePath string
KappPath string
TerraformPlanPath string
TerraformLogsPath string
TerraformOutputsPath string
Expand All @@ -181,6 +182,7 @@ func NewOperationPhase(folder string, kfdTools config.KFDTools, binPath string)
yqPath := path.Join(binPath, "yq", kfdTools.Common.Yq.Version, "yq")
helmPath := path.Join(binPath, "helm", kfdTools.Common.Helm.Version, "helm")
helmfilePath := path.Join(binPath, "helmfile", kfdTools.Common.Helmfile.Version, "helmfile")
kappPath := path.Join(binPath, "kapp", kfdTools.Common.Kapp.Version, "kapp")

planPath := path.Join(basePath, "terraform", "plan")
logsPath := path.Join(basePath, "terraform", "logs")
Expand All @@ -200,6 +202,7 @@ func NewOperationPhase(folder string, kfdTools config.KFDTools, binPath string)
YqPath: yqPath,
HelmPath: helmPath,
HelmfilePath: helmfilePath,
KappPath: kappPath,
}
}

Expand Down Expand Up @@ -300,6 +303,7 @@ func (op *OperationPhase) CopyPathsToConfig(cfg *template.Config) {
"terraform": op.TerraformPath,
"vendorPath": path.Join(op.Path, "..", "vendor"),
"yq": op.YqPath,
"kapp": op.KappPath,
}
}

Expand Down
74 changes: 74 additions & 0 deletions internal/dependencies/tools/kapp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tools

import (
"fmt"
"path/filepath"
"regexp"
"runtime"
"strings"

"github.com/sighupio/furyctl/internal/semver"
"github.com/sighupio/furyctl/internal/tool/kapp"
iox "github.com/sighupio/furyctl/internal/x/io"
)

func NewKapp(runner *kapp.Runner, version string) *Kapp {
return &Kapp{
arch: runtime.GOARCH,
os: runtime.GOOS,
version: version,
checker: &checker{
regex: regexp.MustCompile("kapp version " + semver.Regex),
runner: runner,
splitFn: func(version string) []string {
return strings.Split(version, " ")
},
trimFn: func(tokens []string) string {
return tokens[len(tokens)-1]
},
},
}
}

type Kapp struct {
arch string
checker *checker
os string
version string
}

func (*Kapp) SupportsDownload() bool {
return true
}

func (k *Kapp) SrcPath() string {
return fmt.Sprintf(
"https://github.com/carvel-dev/kapp/releases/download/%s/kapp-%s-%s",
semver.EnsurePrefix(k.version),
k.os,
k.arch,
)
}

func (k *Kapp) Rename(basePath string) error {
oldPath := filepath.Join(basePath, fmt.Sprintf("kapp-%s-%s", k.os, k.arch))
newPath := filepath.Join(basePath, "kapp")

if err := iox.CopyFile(oldPath, newPath); err != nil {
return fmt.Errorf("error while renaming kapp: %w", err)
}

return nil
}

func (k *Kapp) CheckBinVersion() error {
if err := k.checker.version(k.version); err != nil {
return fmt.Errorf("kapp: %w", err)
}

return nil
}
137 changes: 137 additions & 0 deletions internal/dependencies/tools/kapp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build unit

package tools_test

import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"testing"

"github.com/sighupio/furyctl/internal/dependencies/tools"
"github.com/sighupio/furyctl/internal/tool/kapp"
execx "github.com/sighupio/furyctl/internal/x/exec"
)

func Test_Kapp_SupportsDownload(t *testing.T) {
a := tools.NewKapp(newKappRunner(), "3.5.3")

if a.SupportsDownload() != true {
t.Errorf("kapp download must be supported")
}
}

func Test_Kapp_SrcPath(t *testing.T) {
wantSrcPath := fmt.Sprintf(
"https://github.com/carvel-dev/kapp/releases/download/v3.5.3/kapp-%s-%s",
runtime.GOOS,
runtime.GOARCH,
)

testCases := []struct {
desc string
version string
}{
{
desc: "3.5.3",
version: "3.5.3",
},
{
desc: "v3.5.3",
version: "v3.5.3",
},
}
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
fa := tools.NewKapp(newKappRunner(), tC.version)
if fa.SrcPath() != wantSrcPath {
t.Errorf("Wrong kapp src path: want = %s, got = %s", wantSrcPath, fa.SrcPath())
}
})
}
}

func Test_Kapp_Rename(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "furyctl-test-")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}

binaryName := fmt.Sprintf("kapp-%s-%s", runtime.GOOS, runtime.GOARCH)

if _, err := os.Create(filepath.Join(tmpDir, binaryName)); err != nil {
t.Fatalf("error creating temp file: %v", err)
}

fa := tools.NewKapp(newKappRunner(), "3.5.3")

if err := fa.Rename(tmpDir); err != nil {
t.Fatalf("Error renaming kapp binary: %v", err)
}

info, err := os.Stat(filepath.Join(tmpDir, "kapp"))
if err != nil {
t.Fatalf("Error stating kapp binary: %v", err)
}

if info.IsDir() {
t.Errorf("kapp binary is a directory")
}
}

func Test_Kapp_CheckBinVersion(t *testing.T) {
t.Parallel()

testCases := []struct {
desc string
wantVersion string
wantErrMsg string
wantErr bool
}{
{
desc: "correct version installed",
wantVersion: "0.62.0",
},
{
desc: "wrong version installed",
wantVersion: "3.5.3",
wantErr: true,
wantErrMsg: "installed = 0.62.0, expected = 3.5.3",
},
}
for _, tC := range testCases {
tC := tC

t.Run(tC.desc, func(t *testing.T) {
t.Parallel()

fa := tools.NewKapp(newKappRunner(), tC.wantVersion)

err := fa.CheckBinVersion()

if tC.wantErr && err == nil {
t.Errorf("expected error, got nil")
}

if !tC.wantErr && err != nil {
t.Errorf("expected no error, got %v", err)
}

if tC.wantErr && err != nil && !strings.Contains(err.Error(), tC.wantErrMsg) {
t.Errorf("expected error message '%s' to contain '%s'", err.Error(), tC.wantErrMsg)
}
})
}
}

func newKappRunner() *kapp.Runner {
return kapp.NewRunner(execx.NewFakeExecutor("TestHelperProcess"), kapp.Paths{
Kapp: "kapp",
}, false)
}
7 changes: 7 additions & 0 deletions internal/dependencies/tools/test_data/kapp/0.61.0/kapp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

cat <<EOF
kapp version 0.61.0
Succeeded
EOF
7 changes: 7 additions & 0 deletions internal/dependencies/tools/test_data/kapp/0.62.0/kapp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

cat <<EOF
kapp version 0.62.0
Succeeded
EOF
9 changes: 9 additions & 0 deletions internal/dependencies/tools/tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/sighupio/furyctl/internal/tool/git"
"github.com/sighupio/furyctl/internal/tool/helm"
"github.com/sighupio/furyctl/internal/tool/helmfile"
"github.com/sighupio/furyctl/internal/tool/kapp"
"github.com/sighupio/furyctl/internal/tool/kubectl"
"github.com/sighupio/furyctl/internal/tool/kustomize"
"github.com/sighupio/furyctl/internal/tool/openvpn"
Expand Down Expand Up @@ -173,6 +174,14 @@ func (f *Factory) Create(name tool.Name, version string) Tool {

return NewHelmfile(hfr, version)

case tool.Kapp:
ka, ok := t.(*kapp.Runner)
if !ok {
panic(fmt.Sprintf("expected kapp.Runner, got %T", t))
}

return NewKapp(ka, version)

default:
return nil
}
Expand Down
11 changes: 11 additions & 0 deletions internal/dependencies/tools/tool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ func Test_Factory_Create(t *testing.T) {
desc: "kubectl",
wantTool: true,
},
{
desc: "kapp",
wantTool: true,
},
{
desc: "kustomize",
wantTool: true,
Expand Down Expand Up @@ -175,6 +179,13 @@ func TestHelperProcess(t *testing.T) {
case "version":
fmt.Fprintf(os.Stdout, "v0.156.0")
}
case "kapp":
switch subcmd {
case "version":
fmt.Fprintf(os.Stdout, "kapp version 0.62.0\n"+
"\n"+
"Succeeded\n")
}
default:
fmt.Fprintf(os.Stdout, "command not found")
}
Expand Down
4 changes: 4 additions & 0 deletions internal/dependencies/tools/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ func (tv *Validator) validateTools(i any, kfdManifest config.KFD) ([]string, []e
continue
}

if (toolName == "kapp") && !distribution.HasFeature(kfdManifest, distribution.FeatureKappSupport) {
continue
}

tool := tv.toolFactory.Create(itool.Name(toolName), toolCfg.Version)
if err := tool.CheckBinVersion(); err != nil {
errs = append(errs, err)
Expand Down
12 changes: 9 additions & 3 deletions internal/dependencies/tools/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func Test_Validator_Validate(t *testing.T) {
{
desc: "all tools are installed in their correct version",
manifest: config.KFD{
Version: "1.27.0",
Version: "1.29.0",
Tools: config.KFDTools{
Common: config.KFDToolsCommon{
Kubectl: config.KFDTool{Version: "1.21.1"},
Expand All @@ -38,6 +38,7 @@ func Test_Validator_Validate(t *testing.T) {
Yq: config.KFDTool{Version: "4.34.1"},
Helm: config.KFDTool{Version: "3.12.3"},
Helmfile: config.KFDTool{Version: "0.156.0"},
Kapp: config.KFDTool{Version: "0.62.0"},
},
},
},
Expand All @@ -52,12 +53,13 @@ func Test_Validator_Validate(t *testing.T) {
"yq",
"helm",
"helmfile",
"kapp",
},
},
{
desc: "all tools are installed in their wrong version",
manifest: config.KFD{
Version: "1.27.0",
Version: "1.29.0",
Tools: config.KFDTools{
Common: config.KFDToolsCommon{
Kubectl: config.KFDTool{Version: "1.22.0"},
Expand All @@ -67,6 +69,7 @@ func Test_Validator_Validate(t *testing.T) {
Yq: config.KFDTool{Version: "4.33.0"},
Helm: config.KFDTool{Version: "3.11.3"},
Helmfile: config.KFDTool{Version: "0.155.0"},
Kapp: config.KFDTool{Version: "0.61.0"},
},
},
},
Expand All @@ -81,12 +84,13 @@ func Test_Validator_Validate(t *testing.T) {
errors.New("yq: wrong tool version - installed = 4.34.1, expected = 4.33.0"),
errors.New("helm: wrong tool version - installed = 3.12.3, expected = 3.11.3"),
errors.New("helmfile: wrong tool version - installed = 0.156.0, expected = 0.155.0"),
errors.New("kapp: wrong tool version - installed = 0.62.0, expected = 0.61.0"),
},
},
{
desc: "all tools for EKSCluster kind are installed",
manifest: config.KFD{
Version: "1.27.0",
Version: "1.29.0",
Tools: config.KFDTools{
Common: config.KFDToolsCommon{
Kubectl: config.KFDTool{Version: "1.21.1"},
Expand All @@ -96,6 +100,7 @@ func Test_Validator_Validate(t *testing.T) {
Yq: config.KFDTool{Version: "4.34.1"},
Helm: config.KFDTool{Version: "3.12.3"},
Helmfile: config.KFDTool{Version: "0.156.0"},
Kapp: config.KFDTool{Version: "0.62.0"},
},
Eks: config.KFDToolsEks{
Awscli: config.KFDTool{Version: "2.8.12"},
Expand All @@ -117,6 +122,7 @@ func Test_Validator_Validate(t *testing.T) {
"helmfile",
"awscli",
"openvpn",
"kapp",
},
},
}
Expand Down
Loading

0 comments on commit 91e9f18

Please sign in to comment.