Skip to content

Commit

Permalink
Embed the KOTS CLI binary and use it to install the app (#456)
Browse files Browse the repository at this point in the history
* Embed the KOTS CLI binary and use it to install the app
  • Loading branch information
sgalsaleh authored Mar 26, 2024
1 parent 569098f commit 9515491
Show file tree
Hide file tree
Showing 20 changed files with 290 additions and 638 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
output
bundle
pkg/goods/bins
pkg/goods/internal/bins
pkg/goods/images
*tgz
.pre-commit-config.yaml
Expand Down
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ARCH := $(shell uname -m)
APP_NAME = embedded-cluster
ADMIN_CONSOLE_CHART_URL = oci://registry.replicated.com/library
ADMIN_CONSOLE_CHART_NAME = admin-console
ADMIN_CONSOLE_CHART_VERSION = 1.108.1
ADMIN_CONSOLE_CHART_VERSION = 1.108.3
ADMIN_CONSOLE_IMAGE_OVERRIDE =
ADMIN_CONSOLE_MIGRATIONS_IMAGE_OVERRIDE =
EMBEDDED_OPERATOR_CHART_URL = oci://registry.replicated.com/library
Expand All @@ -21,6 +21,7 @@ KUBECTL_VERSION = v1.29.3
K0S_VERSION = v1.29.2+k0s.0
K0S_BINARY_SOURCE_OVERRIDE =
TROUBLESHOOT_VERSION = v0.84.1
KOTS_VERSION = v$(shell echo $(ADMIN_CONSOLE_CHART_VERSION) | sed 's/\([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/')
LD_FLAGS = -X github.com/replicatedhq/embedded-cluster/pkg/defaults.K0sVersion=$(K0S_VERSION) \
-X github.com/replicatedhq/embedded-cluster/pkg/defaults.Version=$(VERSION) \
-X github.com/replicatedhq/embedded-cluster/pkg/defaults.K0sBinaryURL=$(K0S_BINARY_SOURCE_OVERRIDE) \
Expand Down Expand Up @@ -81,6 +82,14 @@ pkg/goods/bins/local-artifact-mirror: Makefile
mkdir -p pkg/goods/bins
CGO_ENABLED=0 go build -o pkg/goods/bins/local-artifact-mirror ./cmd/local-artifact-mirror

pkg/goods/internal/bins/kubectl-kots: Makefile
mkdir -p pkg/goods/internal/bins
mkdir -p output/tmp/kots
curl -L -o output/tmp/kots/kots.tar.gz https://github.com/replicatedhq/kots/releases/download/$(KOTS_VERSION)/kots_linux_amd64.tar.gz
tar -xzf output/tmp/kots/kots.tar.gz -C output/tmp/kots
mv output/tmp/kots/kots pkg/goods/internal/bins/kubectl-kots
touch pkg/goods/internal/bins/kubectl-kots

output/tmp/release.tar.gz: e2e/kots-release-install/*
mkdir -p output/tmp
tar -czf output/tmp/release.tar.gz -C e2e/kots-release-install .
Expand All @@ -102,7 +111,8 @@ static: pkg/goods/bins/k0s \
pkg/goods/bins/kubectl-preflight \
pkg/goods/bins/kubectl \
pkg/goods/bins/kubectl-support_bundle \
pkg/goods/bins/local-artifact-mirror
pkg/goods/bins/local-artifact-mirror \
pkg/goods/internal/bins/kubectl-kots

.PHONY: embedded-cluster-linux-amd64
embedded-cluster-linux-amd64: static go.mod
Expand Down
95 changes: 15 additions & 80 deletions cmd/embedded-cluster/install.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package main

import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"time"

Expand All @@ -19,7 +17,6 @@ import (
"github.com/replicatedhq/embedded-cluster/pkg/defaults"
"github.com/replicatedhq/embedded-cluster/pkg/goods"
"github.com/replicatedhq/embedded-cluster/pkg/helpers"
"github.com/replicatedhq/embedded-cluster/pkg/kubeutils"
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
"github.com/replicatedhq/embedded-cluster/pkg/preflights"
"github.com/replicatedhq/embedded-cluster/pkg/prompts"
Expand All @@ -33,26 +30,6 @@ import (
// necessary data to the screen).
var ErrNothingElseToAdd = fmt.Errorf("")

// runCommand spawns a command and capture its output. Outputs are logged using the
// logrus package and stdout is returned as a string.
func runCommand(bin string, args ...string) (string, error) {
fullcmd := append([]string{bin}, args...)
logrus.Debugf("running command: %v", fullcmd)

stdout := bytes.NewBuffer(nil)
stderr := bytes.NewBuffer(nil)
cmd := exec.Command(bin, args...)
cmd.Stdout = stdout
cmd.Stderr = stderr
if err := cmd.Run(); err != nil {
logrus.Debugf("failed to run command:")
logrus.Debugf("stdout: %s", stdout.String())
logrus.Debugf("stderr: %s", stderr.String())
return "", err
}
return stdout.String(), nil
}

// installAndEnableLocalArtifactMirror installs and enables the local artifact mirror. This
// service is responsible for serving on localhost, through http, all files that are used
// during a cluster upgrade.
Expand All @@ -65,13 +42,13 @@ func installAndEnableLocalArtifactMirror() error {
if err := goods.MaterializeLocalArtifactMirrorUnitFile(); err != nil {
return fmt.Errorf("failed to materialize artifact mirror unit: %w", err)
}
if _, err := runCommand("systemctl", "daemon-reload"); err != nil {
if _, err := helpers.RunCommand("systemctl", "daemon-reload"); err != nil {
return fmt.Errorf("unable to get reload systemctl daemon: %w", err)
}
if _, err := runCommand("systemctl", "start", "local-artifact-mirror"); err != nil {
if _, err := helpers.RunCommand("systemctl", "start", "local-artifact-mirror"); err != nil {
return fmt.Errorf("unable to start the local artifact mirror: %w", err)
}
if _, err := runCommand("systemctl", "enable", "local-artifact-mirror"); err != nil {
if _, err := helpers.RunCommand("systemctl", "enable", "local-artifact-mirror"); err != nil {
return fmt.Errorf("unable to start the local artifact mirror: %w", err)
}
return nil
Expand All @@ -85,7 +62,7 @@ func runPostInstall() error {
if err := os.Symlink(src, dst); err != nil {
return fmt.Errorf("failed to create symlink: %w", err)
}
if _, err := runCommand("systemctl", "daemon-reload"); err != nil {
if _, err := helpers.RunCommand("systemctl", "daemon-reload"); err != nil {
return fmt.Errorf("unable to get reload systemctl daemon: %w", err)
}
return installAndEnableLocalArtifactMirror()
Expand Down Expand Up @@ -266,15 +243,11 @@ func ensureK0sConfig(c *cli.Context) error {
if c.Bool("no-prompt") {
opts = append(opts, addons.WithoutPrompt())
}
if c.String("license") != "" {
license, err := helpers.ParseLicense(c.String("license"))
if err != nil {
return fmt.Errorf("unable to parse license: %w", err)
}
opts = append(opts, addons.WithLicense(license))
if l := c.String("license"); l != "" {
opts = append(opts, addons.WithLicense(l))
}
if c.String("airgap-bundle") != "" {
opts = append(opts, addons.Airgap())
if ab := c.String("airgap-bundle"); ab != "" {
opts = append(opts, addons.WithAirgapBundle(ab))
}
if err := config.UpdateHelmConfigs(cfg, opts...); err != nil {
return fmt.Errorf("unable to update helm configs: %w", err)
Expand Down Expand Up @@ -337,10 +310,10 @@ func installK0s() error {
if err := helpers.MoveFile(ourbin, hstbin); err != nil {
return fmt.Errorf("unable to move k0s binary: %w", err)
}
if _, err := runCommand(hstbin, config.InstallFlags()...); err != nil {
if _, err := helpers.RunCommand(hstbin, config.InstallFlags()...); err != nil {
return fmt.Errorf("unable to install: %w", err)
}
if _, err := runCommand(hstbin, "start"); err != nil {
if _, err := helpers.RunCommand(hstbin, "start"); err != nil {
return fmt.Errorf("unable to start: %w", err)
}
return nil
Expand All @@ -365,49 +338,19 @@ func waitForK0s() error {
if !success {
return fmt.Errorf("timeout waiting for %s", defaults.BinaryName())
}
if _, err := runCommand(defaults.K0sBinaryPath(), "status"); err != nil {
if _, err := helpers.RunCommand(defaults.K0sBinaryPath(), "status"); err != nil {
return fmt.Errorf("unable to get status: %w", err)
}
loading.Infof("Node installation finished")
return nil
}

// createAirgapConfigMaps creates the airgap configmaps in the k8s cluster from the airgap file.
func createAirgapConfigMaps(c *cli.Context) error {
loading := spinner.Start()
defer loading.Close()
loading.Infof("Creating airgap configmaps")
// create k8s client
os.Setenv("KUBECONFIG", defaults.PathToKubeConfig())
cli, err := kubeutils.KubeClient()
if err != nil {
return fmt.Errorf("failed to create k8s client: %w", err)
}

// read file from path
rawfile, err := os.Open(c.String("airgap-bundle"))
if err != nil {
return fmt.Errorf("failed to open airgap file: %w", err)
}
defer rawfile.Close()

if err = airgap.CreateAppConfigMaps(c.Context, cli, rawfile); err != nil {
return fmt.Errorf("unable to create airgap configmaps: %w", err)
}
loading.Infof("Airgap configmaps created")
return nil
}

// runOutro calls Outro() in all enabled addons by means of Applier.
func runOutro(c *cli.Context) error {
os.Setenv("KUBECONFIG", defaults.PathToKubeConfig())
opts := []addons.Option{}
if c.String("license") != "" {
license, err := helpers.ParseLicense(c.String("license"))
if err != nil {
return fmt.Errorf("unable to parse license: %w", err)
}
opts = append(opts, addons.WithLicense(license))
if l := c.String("license"); l != "" {
opts = append(opts, addons.WithLicense(l))
}
if c.String("overrides") != "" {
eucfg, err := helpers.ParseEndUserConfig(c.String("overrides"))
Expand All @@ -416,8 +359,8 @@ func runOutro(c *cli.Context) error {
}
opts = append(opts, addons.WithEndUserConfig(eucfg))
}
if c.String("airgap-bundle") != "" {
opts = append(opts, addons.Airgap())
if ab := c.String("airgap-bundle"); ab != "" {
opts = append(opts, addons.WithAirgapBundle(ab))
}
return addons.NewApplier(opts...).Outro(c.Context)
}
Expand All @@ -432,7 +375,6 @@ var installCommand = &cli.Command{
if os.Getuid() != 0 {
return fmt.Errorf("install command must be run as root")
}

if c.String("airgap-bundle") != "" {
metrics.DisableMetrics()
}
Expand Down Expand Up @@ -520,13 +462,6 @@ var installCommand = &cli.Command{
metrics.ReportApplyFinished(c, err)
return err
}
if c.String("airgap-bundle") != "" {
err := createAirgapConfigMaps(c)
if err != nil {
err = fmt.Errorf("unable to create airgap configmaps: %w", err)
return err
}
}
logrus.Debugf("running outro")
if err := runOutro(c); err != nil {
metrics.ReportApplyFinished(c, err)
Expand Down
6 changes: 3 additions & 3 deletions cmd/embedded-cluster/join.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ func installK0sBinary() error {

// startK0sService starts the k0s service.
func startK0sService() error {
if _, err := runCommand(defaults.K0sBinaryPath(), "start"); err != nil {
if _, err := helpers.RunCommand(defaults.K0sBinaryPath(), "start"); err != nil {
return fmt.Errorf("unable to start: %w", err)
}
return nil
Expand All @@ -339,7 +339,7 @@ func createSystemdUnitFiles(fullcmd string) error {
if err := os.Symlink(src, dst); err != nil {
return err
}
if _, err := runCommand("systemctl", "daemon-reload"); err != nil {
if _, err := helpers.RunCommand("systemctl", "daemon-reload"); err != nil {
return err
}
return installAndEnableLocalArtifactMirror()
Expand All @@ -353,7 +353,7 @@ func runK0sInstallCommand(fullcmd string) error {
if strings.Contains(fullcmd, "controller") {
args = append(args, "--disable-components", "konnectivity-server", "--enable-dynamic-config")
}
if _, err := runCommand(args[0], args[1:]...); err != nil {
if _, err := helpers.RunCommand(args[0], args[1:]...); err != nil {
return err
}
return nil
Expand Down
3 changes: 2 additions & 1 deletion cmd/embedded-cluster/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/replicatedhq/embedded-cluster/pkg/defaults"
"github.com/replicatedhq/embedded-cluster/pkg/helpers"
"github.com/replicatedhq/embedded-cluster/pkg/prompts"
)

Expand Down Expand Up @@ -395,7 +396,7 @@ var resetCommand = &cli.Command{

lamPath := "/etc/systemd/system/local-artifact-mirror.service"
if _, err := os.Stat(lamPath); err == nil {
if _, err := runCommand("systemctl", "stop", "local-artifact-mirror"); err != nil {
if _, err := helpers.RunCommand("systemctl", "stop", "local-artifact-mirror"); err != nil {
return err
}
if err := os.RemoveAll(lamPath); err != nil {
Expand Down
6 changes: 3 additions & 3 deletions e2e/scripts/default-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ main() {
exit 1
fi
if ! grep -q "Admin Console is ready!" /tmp/log; then
echo "Failed to install embedded-cluster"
echo "Failed to validate that the Admin Console is ready"
exit 1
fi
if ! wait_for_healthy_node; then
echo "Failed to install embedded-cluster"
echo "Failed to wait for healthy node"
exit 1
fi
if ! wait_for_pods_running 900; then
echo "Failed to install embedded-cluster"
echo "Failed to wait for pods to be running"
exit 1
fi
if ! check_openebs_storage_class; then
Expand Down
4 changes: 2 additions & 2 deletions e2e/scripts/embedded-preflight.sh
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ main() {
exit 1
fi
if ! grep -q "Admin Console is ready!" /tmp/log; then
echo "Failed to install embedded-cluster"
echo "Failed to validate that the Admin Console is ready"
exit 1
fi
if ! has_applied_host_preflight; then
Expand All @@ -178,7 +178,7 @@ main() {
exit 1
fi
if ! wait_for_healthy_node; then
echo "Failed to install embedded-cluster"
echo "Failed to wait for healthy node"
exit 1
fi
if ! systemctl restart embedded-cluster; then
Expand Down
6 changes: 3 additions & 3 deletions e2e/scripts/pre-minio-removal-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,15 @@ main() {
exit 1
fi
if ! grep -q "Admin Console is ready!" /tmp/log; then
echo "Failed to install embedded-cluster"
echo "Failed to validate that the Admin Console is ready"
exit 1
fi
if ! install_kots_cli; then
echo "Failed to install kots cli"
exit 1
fi
if ! wait_for_healthy_node; then
echo "Failed to install embedded-cluster"
echo "Failed to wait for healthy node"
exit 1
fi
if ! ensure_node_config; then
Expand All @@ -238,7 +238,7 @@ main() {
fi
fi
if ! wait_for_pods_running 900; then
echo "Failed to install embedded-cluster"
echo "Failed to wait for pods to be running"
exit 1
fi
if ! check_openebs_storage_class; then
Expand Down
10 changes: 7 additions & 3 deletions e2e/scripts/single-node-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ deploy_app() {

echo "kotsadm logs"
kubectl logs -n kotsadm -l app=kotsadm --tail=50
kubectl logs -n kotsadm -l app=kotsadm --tail=50 --previous

echo "all pods"
kubectl get pods -A
}

wait_for_nginx_pods() {
Expand Down Expand Up @@ -216,15 +220,15 @@ main() {
exit 1
fi
if ! grep -q "Admin Console is ready!" /tmp/log; then
echo "Failed to install embedded-cluster"
echo "Failed to validate that the Admin Console is ready"
exit 1
fi
if ! install_kots_cli; then
echo "Failed to install kots cli"
exit 1
fi
if ! wait_for_healthy_node; then
echo "Failed to install embedded-cluster"
echo "Failed to wait for healthy node"
exit 1
fi
if ! ensure_node_config; then
Expand All @@ -238,7 +242,7 @@ main() {
fi
fi
if ! wait_for_pods_running 900; then
echo "Failed to install embedded-cluster"
echo "Failed to wait for pods to be running"
exit 1
fi
if ! check_openebs_storage_class; then
Expand Down
Loading

0 comments on commit 9515491

Please sign in to comment.