Skip to content

Commit 27f1ccb

Browse files
bug: version command should work without cluster access (#38)
* bug: version command should work without cluster access `helmvm version` should work even without having access to a cluster. prior to this commit version command required a kubernetes client to work properly, this is not a requirement. * Update e2e/version_test.go Co-authored-by: Andrew Lavery <[email protected]> --------- Co-authored-by: Andrew Lavery <[email protected]>
1 parent f7e1fb7 commit 27f1ccb

File tree

5 files changed

+89
-26
lines changed

5 files changed

+89
-26
lines changed

.github/workflows/e2e.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
- TestSingleNodeInstallationRockyLinux8
1717
- TestSingleNodeInstallationDebian12
1818
- TestSingleNodeInstallationCentos8Stream
19+
- TestVersion
1920
steps:
2021
- name: Move Docker aside
2122
run: |

e2e/version_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package e2e
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"testing"
7+
8+
"github.com/replicatedhq/helmvm/e2e/cluster"
9+
)
10+
11+
func TestVersion(t *testing.T) {
12+
t.Parallel()
13+
tc := cluster.NewTestCluster(&cluster.Input{
14+
T: t,
15+
Nodes: 1,
16+
Image: "ubuntu/jammy",
17+
SSHPublicKey: "../output/tmp/id_rsa.pub",
18+
SSHPrivateKey: "../output/tmp/id_rsa",
19+
HelmVMPath: "../output/bin/helmvm",
20+
})
21+
defer tc.Destroy()
22+
t.Log("validating helmvm version in node 0")
23+
line := []string{"helmvm", "version"}
24+
stdout, stderr, err := RunCommandOnNode(t, tc, 0, line)
25+
if err != nil {
26+
t.Fatalf("fail to install ssh on node %s: %v", tc.Nodes[0], err)
27+
}
28+
var failed bool
29+
output := fmt.Sprintf("%s\n%s", stdout, stderr)
30+
expected := []string{"Installer", "Kubernetes", "OpenEBS", "AdminConsole"}
31+
for _, component := range expected {
32+
if strings.Contains(output, component) {
33+
continue
34+
}
35+
t.Errorf("missing %q version in 'version' output", component)
36+
failed = true
37+
}
38+
if failed {
39+
t.Log(output)
40+
}
41+
}

pkg/addons/adminconsole/adminconsole.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"helm.sh/helm/v3/pkg/chart/loader"
1515
"helm.sh/helm/v3/pkg/cli"
1616
"helm.sh/helm/v3/pkg/release"
17-
"sigs.k8s.io/controller-runtime/pkg/client"
1817

1918
"github.com/replicatedhq/helmvm/pkg/addons/adminconsole/charts"
2019
)
@@ -167,7 +166,7 @@ func (a *AdminConsole) installedRelease(ctx context.Context) (*release.Release,
167166
return releases[0], nil
168167
}
169168

170-
func New(ns string, prompt bool, kcli client.Client, log action.DebugLog) (*AdminConsole, error) {
169+
func New(ns string, prompt bool, log action.DebugLog) (*AdminConsole, error) {
171170
env := cli.New()
172171
env.SetNamespace(ns)
173172
config := &action.Configuration{}
@@ -179,6 +178,6 @@ func New(ns string, prompt bool, kcli client.Client, log action.DebugLog) (*Admi
179178
config: config,
180179
logger: log,
181180
prompt: prompt,
182-
customization: AdminConsoleCustomization{kcli},
181+
customization: AdminConsoleCustomization{},
183182
}, nil
184183
}

pkg/addons/adminconsole/customize.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ import (
1616
"k8s.io/apimachinery/pkg/api/errors"
1717
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1818
"sigs.k8s.io/controller-runtime/pkg/client"
19+
"sigs.k8s.io/controller-runtime/pkg/client/config"
20+
"sigs.k8s.io/controller-runtime/pkg/log"
21+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
1922
)
2023

2124
// AdminConsoleCustomization is a struct that contains the actions to create and update
2225
// the admin console customization found inside the binary. This is necessary for
2326
// backwards compatibility with older versions of helmvm.
24-
type AdminConsoleCustomization struct {
25-
kubeclient client.Client
26-
}
27+
type AdminConsoleCustomization struct{}
2728

2829
// extractCustomization will extract the customization from the binary if it exists.
2930
// If it does not exist, it will return nil, nil. The customization is expected to
@@ -82,6 +83,19 @@ func (a *AdminConsoleCustomization) processSection(section *elf.Section) ([]byte
8283
}
8384
}
8485

86+
// kubeClient returns a new kubernetes client.
87+
func (a *AdminConsoleCustomization) kubeClient() (client.Client, error) {
88+
k8slogger := zap.New(func(o *zap.Options) {
89+
o.DestWriter = io.Discard
90+
})
91+
log.SetLogger(k8slogger)
92+
cfg, err := config.GetConfig()
93+
if err != nil {
94+
return nil, fmt.Errorf("unable to process kubernetes config: %w", err)
95+
}
96+
return client.New(cfg, client.Options{})
97+
}
98+
8599
// apply will attempt to read the helmvm binary and extract the kotsadm portal
86100
// customization from it. If it finds one, it will apply it to the cluster.
87101
func (a *AdminConsoleCustomization) apply(ctx context.Context) error {
@@ -98,10 +112,14 @@ func (a *AdminConsoleCustomization) apply(ctx context.Context) error {
98112
logrus.Infof("No admin console customization found")
99113
return nil
100114
}
115+
kubeclient, err := a.kubeClient()
116+
if err != nil {
117+
return fmt.Errorf("unable to create kubernetes client: %w", err)
118+
}
101119
logrus.Infof("Admin console customization found")
102120
nsn := client.ObjectKey{Namespace: "helmvm", Name: "kotsadm-application-metadata"}
103121
var cm corev1.ConfigMap
104-
if err := a.kubeclient.Get(ctx, nsn, &cm); err != nil {
122+
if err := kubeclient.Get(ctx, nsn, &cm); err != nil {
105123
if !errors.IsNotFound(err) {
106124
return fmt.Errorf("unable to get kotsadm-application configmap: %w", err)
107125
}
@@ -115,14 +133,14 @@ func (a *AdminConsoleCustomization) apply(ctx context.Context) error {
115133
"application.yaml": string(cust),
116134
},
117135
}
118-
if err := a.kubeclient.Create(ctx, &cm); err != nil {
136+
if err := kubeclient.Create(ctx, &cm); err != nil {
119137
return fmt.Errorf("unable to create kotsadm-application configmap: %w", err)
120138
}
121139
return nil
122140
}
123141
logrus.Infof("Updating admin console customization config map")
124142
cm.Data["application.yaml"] = string(cust)
125-
if err := a.kubeclient.Update(ctx, &cm); err != nil {
143+
if err := kubeclient.Update(ctx, &cm); err != nil {
126144
return fmt.Errorf("unable to update kotsadm-application configmap: %w", err)
127145
}
128146
return nil

pkg/addons/applier.go

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ import (
2424
)
2525

2626
type Applier struct {
27-
kubeclient client.Client
28-
addons map[string]AddOn
27+
addons map[string]AddOn
2928
}
3029

3130
// DoNotLog is a helper function to disable logging for addons.
@@ -76,6 +75,19 @@ func (a *Applier) Versions() (map[string]string, error) {
7675
return versions, nil
7776
}
7877

78+
// kubeClient returns a new kubernetes client.
79+
func (a *Applier) kubeClient() (client.Client, error) {
80+
k8slogger := zap.New(func(o *zap.Options) {
81+
o.DestWriter = io.Discard
82+
})
83+
log.SetLogger(k8slogger)
84+
cfg, err := config.GetConfig()
85+
if err != nil {
86+
return nil, fmt.Errorf("unable to process kubernetes config: %w", err)
87+
}
88+
return client.New(cfg, client.Options{})
89+
}
90+
7991
// waitForKubernetes waits until we manage to make a successful connection to the
8092
// Kubernetes API server.
8193
func (a *Applier) waitForKubernetes(ctx context.Context) error {
@@ -85,6 +97,10 @@ func (a *Applier) waitForKubernetes(ctx context.Context) error {
8597
pb.Close()
8698
<-end
8799
}()
100+
kcli, err := a.kubeClient()
101+
if err != nil {
102+
return fmt.Errorf("unable to create kubernetes client: %w", err)
103+
}
88104
ticker := time.NewTicker(3 * time.Second)
89105
defer ticker.Stop()
90106
counter := 1
@@ -96,7 +112,7 @@ func (a *Applier) waitForKubernetes(ctx context.Context) error {
96112
return ctx.Err()
97113
}
98114
counter++
99-
if err := a.kubeclient.List(ctx, &corev1.NamespaceList{}); err != nil {
115+
if err := kcli.List(ctx, &corev1.NamespaceList{}); err != nil {
100116
pb.Infof("%d/n Waiting for Kubernetes API server to be ready.", counter)
101117
continue
102118
}
@@ -106,25 +122,13 @@ func (a *Applier) waitForKubernetes(ctx context.Context) error {
106122

107123
// NewApplier creates a new Applier instance with all addons registered.
108124
func NewApplier(prompt, verbose bool) (*Applier, error) {
109-
k8slogger := zap.New(func(o *zap.Options) {
110-
o.DestWriter = io.Discard
111-
})
112-
log.SetLogger(k8slogger)
113-
cfg, err := config.GetConfig()
114-
if err != nil {
115-
return nil, fmt.Errorf("unable to process kubernetes config: %w", err)
116-
}
117-
kubecli, err := client.New(cfg, client.Options{})
118-
if err != nil {
119-
return nil, fmt.Errorf("unable to create kubernetes client: %w", err)
120-
}
121-
applier := &Applier{addons: map[string]AddOn{}, kubeclient: kubecli}
125+
applier := &Applier{addons: map[string]AddOn{}}
122126
obs, err := openebs.New("helmvm", getLogger("openebs", verbose))
123127
if err != nil {
124128
return nil, fmt.Errorf("unable to create admin console addon: %w", err)
125129
}
126130
applier.addons["openebs"] = obs
127-
aconsole, err := adminconsole.New("helmvm", prompt, kubecli, getLogger("adminconsole", verbose))
131+
aconsole, err := adminconsole.New("helmvm", prompt, getLogger("adminconsole", verbose))
128132
if err != nil {
129133
return nil, fmt.Errorf("unable to create admin console addon: %w", err)
130134
}

0 commit comments

Comments
 (0)