Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ jobs:
tests:
- TestBuildBundle
- TestEmbedAndInstall
- TestInstallSingleNodeAndUpgradeToEmbed
- TestMultiNodeInstallation
- TestSingleNodeInstallation
- TestTokenBasedMultiNodeInstallation
- TestSingleNodeInstallationRockyLinux8
- TestSingleNodeInstallationDebian12
- TestSingleNodeInstallationCentos8Stream
- TestVersion
- TestMultiNodeInteractiveInstallation
steps:
- name: Move Docker aside
run: |
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ e2e-test: helmvm-linux-amd64
mkdir -p output/tmp
rm -rf output/tmp/id_rsa*
ssh-keygen -t rsa -N "" -C "Integration Test Key" -f output/tmp/id_rsa
go test -timeout 10m -v ./e2e -run $(TEST_NAME)$
go test -timeout 30m -v ./e2e -run $(TEST_NAME)$

.PHONY: create-e2e-workflows
create-e2e-workflows:
Expand Down
54 changes: 20 additions & 34 deletions cmd/helmvm/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"strings"
"time"

"github.com/AlecAivazis/survey/v2"
"github.com/k0sproject/k0sctl/pkg/apis/k0sctl.k0sproject.io/v1beta1/cluster"
"github.com/k0sproject/rig"
"github.com/k0sproject/rig/log"
Expand All @@ -26,6 +25,7 @@ import (
"github.com/replicatedhq/helmvm/pkg/goods"
"github.com/replicatedhq/helmvm/pkg/infra"
pb "github.com/replicatedhq/helmvm/pkg/progressbar"
"github.com/replicatedhq/helmvm/pkg/prompts"
)

// runPostApply is meant to run things that can't be run automatically with
Expand Down Expand Up @@ -150,25 +150,19 @@ func copyUserProvidedConfig(c *cli.Context) error {

// overwriteExistingConfig asks user if they want to overwrite the existing cluster
// configuration file.
func overwriteExistingConfig() (bool, error) {
var useCurrent = &survey.Confirm{
Message: "Do you want to create a new cluster configuration ?",
Default: false,
}
func overwriteExistingConfig() bool {
logrus.Warn("A cluster configuration file was found. This means you already")
logrus.Warn("have created a cluster configured. You can either use the existing")
logrus.Warn("configuration or create a new one (the original configuration will")
logrus.Warn("be backed up).")
var answer bool
if err := survey.AskOne(useCurrent, &answer); err != nil {
return false, err
}
return answer, nil
logrus.Warn("have created and configured a cluster. You can either use the")
logrus.Warn("existing configuration or create a new one (the original config")
logrus.Warn("will be backed up).")
return prompts.New().Confirm(
"Do you want to create a new cluster configuration ?", false,
)
}

// ensureK0sctlConfig ensures that a k0sctl.yaml file exists in the configuration
// directory. If none exists then this directs the user to a wizard to create one.
func ensureK0sctlConfig(c *cli.Context, nodes []infra.Node, prompt bool) error {
func ensureK0sctlConfig(c *cli.Context, nodes []infra.Node, useprompt bool) error {
multi := c.Bool("multi-node") || len(nodes) > 0
if !multi && runtime.GOOS != "linux" {
return fmt.Errorf("single node clusters only supported on linux")
Expand All @@ -182,12 +176,10 @@ func ensureK0sctlConfig(c *cli.Context, nodes []infra.Node, prompt bool) error {
}
if _, err := os.Stat(cfgpath); err == nil {
if len(nodes) == 0 {
if !prompt {
if !useprompt {
return updateConfigBundle(c.Context, bundledir)
}
if over, err := overwriteExistingConfig(); err != nil {
return fmt.Errorf("unable to process answers: %w", err)
} else if !over {
if !overwriteExistingConfig() {
return updateConfigBundle(c.Context, bundledir)
}
}
Expand Down Expand Up @@ -276,26 +268,20 @@ func dumpApplyLogs() {

// applyK0sctl runs the k0sctl apply command and waits for it to finish. If
// no configuration is found one is generated.
func applyK0sctl(c *cli.Context, prompt bool, nodes []infra.Node) error {
func applyK0sctl(c *cli.Context, useprompt bool, nodes []infra.Node) error {
logrus.Infof("Processing cluster configuration")
if err := ensureK0sctlConfig(c, nodes, prompt); err != nil {
if err := ensureK0sctlConfig(c, nodes, useprompt); err != nil {
return fmt.Errorf("unable to create config file: %w", err)
}
logrus.Infof("Applying cluster configuration")
if err := runK0sctlApply(c.Context); err != nil {
logrus.Errorf("Installation or upgrade failed.")
if !prompt {
if !useprompt {
dumpApplyLogs()
return fmt.Errorf("unable to apply cluster: %w", err)
}
var useCurrent = &survey.Confirm{
Message: "Do you wish to visualize the logs?",
Default: true,
}
var answer bool
if err := survey.AskOne(useCurrent, &answer); err != nil {
return fmt.Errorf("unable to process answers: %w", err)
} else if answer {
msg := "Do you wish to visualize the logs?"
if prompts.New().Confirm(msg, true) {
dumpApplyLogs()
}
return fmt.Errorf("unable to apply cluster: %w", err)
Expand Down Expand Up @@ -348,7 +334,7 @@ var installCommand = &cli.Command{
logrus.Warnf("Run '%s node --help' for more information.", defaults.BinaryName())
return fmt.Errorf("decentralized install detected")
}
prompt := !c.Bool("no-prompt")
useprompt := !c.Bool("no-prompt")
logrus.Infof("Materializing binaries")
if err := goods.Materialize(); err != nil {
return fmt.Errorf("unable to materialize binaries: %w", err)
Expand All @@ -358,11 +344,11 @@ var installCommand = &cli.Command{
var nodes []infra.Node
if dir := c.String("infra"); dir != "" {
logrus.Infof("Processing infrastructure manifests")
if nodes, err = infra.Apply(c.Context, dir, prompt); err != nil {
if nodes, err = infra.Apply(c.Context, dir, useprompt); err != nil {
return fmt.Errorf("unable to create infra: %w", err)
}
}
if err := applyK0sctl(c, prompt, nodes); err != nil {
if err := applyK0sctl(c, useprompt, nodes); err != nil {
return fmt.Errorf("unable update cluster: %w", err)
}
}
Expand All @@ -374,7 +360,7 @@ var installCommand = &cli.Command{
ccfg := defaults.PathToConfig("k0sctl.yaml")
kcfg := defaults.PathToConfig("kubeconfig")
os.Setenv("KUBECONFIG", kcfg)
if applier, err := addons.NewApplier(prompt, true); err != nil {
if applier, err := addons.NewApplier(useprompt, true); err != nil {
return fmt.Errorf("unable to create applier: %w", err)
} else if err := applier.Apply(c.Context); err != nil {
return fmt.Errorf("unable to apply addons: %w", err)
Expand Down
17 changes: 4 additions & 13 deletions cmd/helmvm/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import (
"runtime"
"time"

"github.com/AlecAivazis/survey/v2"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"

"github.com/replicatedhq/helmvm/pkg/defaults"
"github.com/replicatedhq/helmvm/pkg/prompts"
)

var tokenCommands = &cli.Command{
Expand Down Expand Up @@ -53,7 +53,7 @@ var tokenCreateCommand = &cli.Command{
if role != "worker" && role != "controller" {
return fmt.Errorf("invalid role %q", role)
}
prompt := !c.Bool("no-prompt")
useprompt := !c.Bool("no-prompt")
cfgpath := defaults.PathToConfig("k0sctl.yaml")
if _, err := os.Stat(cfgpath); err != nil {
if os.IsNotExist(err) {
Expand All @@ -69,17 +69,8 @@ var tokenCreateCommand = &cli.Command{
logrus.Warn("Through the centralized management you can manage all your")
logrus.Warn("cluster nodes from a single location. If you decide to move")
logrus.Warn("on the centralized management won't be available anymore")
if prompt {
question := &survey.Confirm{
Message: "Do you want to use continue ?",
Default: true,
}
var moveOn bool
if err := survey.AskOne(question, &moveOn); err != nil {
return fmt.Errorf("unable to ask for confirmation: %w", err)
} else if !moveOn {
return nil
}
if useprompt && !prompts.New().Confirm("Do you want to continue ?", true) {
return nil
}
}
dur := c.Duration("expiry").String()
Expand Down
3 changes: 1 addition & 2 deletions e2e/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ lxc.mount.entry = /dev/kmsg dev/kmsg none defaults,bind,create=file`
const checkInternet = `#!/bin/bash
timeout 5 bash -c 'cat < /dev/null > /dev/tcp/www.replicated.com/80'
if [ $? == 0 ]; then
echo "Internet connectivity is up"
exit 0
fi
echo "Internet connectivity is down"
echo "Internet connection is down"
exit 1
`

Expand Down
33 changes: 0 additions & 33 deletions e2e/embed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,3 @@ func TestEmbedAndInstall(t *testing.T) {
t.Fatalf("fail to create deployment with pvc: %v", err)
}
}

func TestInstallSingleNodeAndUpgradeToEmbed(t *testing.T) {
t.Parallel()
tc := cluster.NewTestCluster(&cluster.Input{
T: t,
Nodes: 1,
Image: "ubuntu/jammy",
SSHPublicKey: "../output/tmp/id_rsa.pub",
SSHPrivateKey: "../output/tmp/id_rsa",
HelmVMPath: "../output/bin/helmvm",
})
defer tc.Destroy()
t.Log("installing ssh in node 0")
line := []string{"apt", "install", "openssh-server", "-y"}
if _, _, err := RunCommandOnNode(t, tc, 0, line); err != nil {
t.Fatalf("fail to install ssh on node %s: %v", tc.Nodes[0], err)
}
t.Log("installing helmvm on node 0")
line = []string{"single-node-install.sh"}
if _, _, err := RunCommandOnNode(t, tc, 0, line); err != nil {
t.Fatalf("fail to install helmvm on node 0: %v", err)
}
t.Log("installing helmvm embed with memcached on node 0")
line = []string{"embed-and-install.sh"}
if _, _, err := RunCommandOnNode(t, tc, 0, line); err != nil {
t.Fatalf("fail to install embed helmvm on node 0: %v", err)
}
t.Log("creating deployment mounting pvc")
line = []string{"deploy-with-pvc.sh"}
if _, _, err := RunCommandOnNode(t, tc, 0, line); err != nil {
t.Fatalf("fail to create deployment with pvc: %v", err)
}
}
36 changes: 36 additions & 0 deletions e2e/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,39 @@ func TestSingleNodeInstallationCentos8Stream(t *testing.T) {
t.Fatalf("fail to create deployment with pvc: %v", err)
}
}

func TestMultiNodeInteractiveInstallation(t *testing.T) {
t.Parallel()
t.Log("creating cluster")
tc := cluster.NewTestCluster(&cluster.Input{
T: t,
Nodes: 3,
Image: "ubuntu/jammy",
SSHPublicKey: "../output/tmp/id_rsa.pub",
SSHPrivateKey: "../output/tmp/id_rsa",
HelmVMPath: "../output/bin/helmvm",
})
defer tc.Destroy()
for i := range tc.Nodes {
t.Logf("installing ssh on node %d", i)
line := []string{"apt", "install", "openssh-server", "-y"}
if _, _, err := RunCommandOnNode(t, tc, i, line); err != nil {
t.Fatalf("fail to install ssh on node %d: %v", i, err)
}
}
t.Logf("installing expect on node 0")
line := []string{"apt", "install", "expect", "-y"}
if _, _, err := RunCommandOnNode(t, tc, 0, line); err != nil {
t.Fatalf("fail to install expect on node 0: %v", err)
}
t.Log("running multi node interactive install from node 0")
line = []string{"interactive-multi-node-install.exp"}
if _, _, err := RunCommandOnNode(t, tc, 0, line); err != nil {
t.Fatalf("fail to install helmvm from node 0: %v", err)
}
t.Log("waiting for cluster nodes to report ready")
line = []string{"wait-for-ready-nodes.sh", "3"}
if _, _, err := RunCommandOnNode(t, tc, 0, line); err != nil {
t.Fatalf("nodes not reporting ready: %v", err)
}
}
23 changes: 23 additions & 0 deletions e2e/scripts/interactive-multi-node-install.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env expect

proc configure_node {address} {
set timeout 30
expect "Node address:" { send "$address\r" }
expect "SSH user:" { send "root\r" }
expect "SSH port:" { send "22\r" }
expect "Type one of the options above:" { send "controller+worker\r" }
expect "Type one of the options above:" { send "/root/.ssh/id_rsa\r" }
}

set env(HELMVM_PLAIN_PROMPTS) "true"
spawn helmvm install --multi-node
configure_node "10.0.0.2"
expect -re "Add another node?.*:" { send "y\r" }
configure_node "10.0.0.3"
expect -re "Add another node?.*:" { send "y\r" }
configure_node "10.0.0.4"
expect -re "Add another node?.*:" { send "n\r" }
set timeout 600
expect "Load balancer address:" { send "\r" }
expect "Enter a new Admin Console password:" { send "password\r" }
expect "You can now access your cluster with kubectl"
2 changes: 1 addition & 1 deletion e2e/scripts/zz-scripts.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ package scripts

import "embed"

//go:embed *.sh
//go:embed *
var FS embed.FS
21 changes: 6 additions & 15 deletions pkg/addons/adminconsole/adminconsole.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"strings"

"github.com/AlecAivazis/survey/v2"
"github.com/sirupsen/logrus"
"golang.org/x/mod/semver"
"helm.sh/helm/v3/pkg/action"
Expand All @@ -16,6 +15,7 @@ import (
"helm.sh/helm/v3/pkg/release"

"github.com/replicatedhq/helmvm/pkg/addons/adminconsole/charts"
"github.com/replicatedhq/helmvm/pkg/prompts"
)

const (
Expand All @@ -37,24 +37,15 @@ type AdminConsole struct {
config *action.Configuration
logger action.DebugLog
namespace string
prompt bool
useprompt bool
}

func (a *AdminConsole) askPassword() (string, error) {
if !a.prompt {
if !a.useprompt {
logrus.Warnf("Admin Console password set to: password")
return "password", nil
}
question := &survey.Password{Message: "Enter a new Admin Console password:"}
var pass string
for pass == "" {
if err := survey.AskOne(question, &pass); err != nil {
return "", fmt.Errorf("unable to ask for password: %w", err)
} else if pass == "" {
logrus.Warn("Password cannot be empty")
}
}
return pass, nil
return prompts.New().Password("Enter a new Admin Console password:"), nil
}

func (a *AdminConsole) Version() (map[string]string, error) {
Expand Down Expand Up @@ -166,7 +157,7 @@ func (a *AdminConsole) installedRelease(ctx context.Context) (*release.Release,
return releases[0], nil
}

func New(ns string, prompt bool, log action.DebugLog) (*AdminConsole, error) {
func New(ns string, useprompt bool, log action.DebugLog) (*AdminConsole, error) {
env := cli.New()
env.SetNamespace(ns)
config := &action.Configuration{}
Expand All @@ -177,7 +168,7 @@ func New(ns string, prompt bool, log action.DebugLog) (*AdminConsole, error) {
namespace: ns,
config: config,
logger: log,
prompt: prompt,
useprompt: useprompt,
customization: AdminConsoleCustomization{},
}, nil
}
Loading