Skip to content

Commit 675ea51

Browse files
authored
Install k0s (#1573)
1 parent 91c5b14 commit 675ea51

File tree

4 files changed

+166
-24
lines changed

4 files changed

+166
-24
lines changed

cmd/installer/cli/install.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func InstallCmd(ctx context.Context, name string) *cobra.Command {
140140
license, err := getLicenseFromFilepath(licenseFile)
141141
if err != nil {
142142
metricErr := fmt.Errorf("unable to get license: %w", err)
143-
metrics.ReportApplyFinished(cmd.Context(), licenseFile, metricErr)
143+
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil, metricErr)
144144
return err // do not return the metricErr, as we want the user to see the error message without a prefix
145145
}
146146
isAirgap := false
@@ -157,7 +157,7 @@ func InstallCmd(ctx context.Context, name string) *cobra.Command {
157157
if !isAirgap {
158158
if err := maybePromptForAppUpdate(cmd.Context(), prompts.New(), license, assumeYes); err != nil {
159159
if errors.Is(err, ErrNothingElseToAdd) {
160-
metrics.ReportApplyFinished(cmd.Context(), licenseFile, err)
160+
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil, err)
161161
return err
162162
}
163163
// If we get an error other than ErrNothingElseToAdd, we warn and continue as
@@ -167,19 +167,19 @@ func InstallCmd(ctx context.Context, name string) *cobra.Command {
167167
}
168168

169169
if err := preflights.ValidateApp(); err != nil {
170-
metrics.ReportApplyFinished(cmd.Context(), licenseFile, err)
170+
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil, err)
171171
return err
172172
}
173173

174174
adminConsolePwd, err := maybeAskAdminConsolePassword(cmd, assumeYes)
175175
if err != nil {
176-
metrics.ReportApplyFinished(cmd.Context(), licenseFile, err)
176+
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil, err)
177177
return err
178178
}
179179

180180
logrus.Debugf("materializing binaries")
181181
if err := materializeFiles(airgapBundle); err != nil {
182-
metrics.ReportApplyFinished(cmd.Context(), licenseFile, err)
182+
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil, err)
183183
return err
184184
}
185185

@@ -193,7 +193,7 @@ func InstallCmd(ctx context.Context, name string) *cobra.Command {
193193
}
194194
applier, err := getAddonsApplier(cmd, opts, adminConsolePwd, proxy)
195195
if err != nil {
196-
metrics.ReportApplyFinished(cmd.Context(), licenseFile, err)
196+
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil, err)
197197
return err
198198
}
199199

@@ -210,7 +210,7 @@ func InstallCmd(ctx context.Context, name string) *cobra.Command {
210210
}
211211

212212
if err := RunHostPreflights(cmd, applier, replicatedAPIURL, proxyRegistryURL, isAirgap, proxy, fromCIDR, toCIDR, assumeYes); err != nil {
213-
metrics.ReportApplyFinished(cmd.Context(), licenseFile, err)
213+
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil, err)
214214
if err == ErrPreflightsHaveFail {
215215
return ErrNothingElseToAdd
216216
}
@@ -224,11 +224,11 @@ func InstallCmd(ctx context.Context, name string) *cobra.Command {
224224

225225
logrus.Debugf("running outro")
226226
if err := runOutro(cmd, applier, cfg); err != nil {
227-
metrics.ReportApplyFinished(cmd.Context(), licenseFile, err)
227+
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil, err)
228228
return err
229229
}
230230

231-
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil)
231+
metrics.ReportApplyFinished(cmd.Context(), licenseFile, nil, nil)
232232
return nil
233233
},
234234
}
@@ -445,13 +445,13 @@ func installAndWaitForK0s(cmd *cobra.Command, applier *addons.Applier, proxy *ec
445445
cfg, err := ensureK0sConfig(cmd, applier)
446446
if err != nil {
447447
err := fmt.Errorf("unable to create config file: %w", err)
448-
metrics.ReportApplyFinished(cmd.Context(), licenseFlag, err)
448+
metrics.ReportApplyFinished(cmd.Context(), licenseFlag, nil, err)
449449
return nil, err
450450
}
451451
logrus.Debugf("creating systemd unit files")
452452
if err := createSystemdUnitFiles(false, proxy); err != nil {
453453
err := fmt.Errorf("unable to create systemd unit files: %w", err)
454-
metrics.ReportApplyFinished(cmd.Context(), licenseFlag, err)
454+
metrics.ReportApplyFinished(cmd.Context(), licenseFlag, nil, err)
455455
return nil, err
456456
}
457457

@@ -462,14 +462,14 @@ func installAndWaitForK0s(cmd *cobra.Command, applier *addons.Applier, proxy *ec
462462
}
463463
if err := k0s.Install(networkInterface); err != nil {
464464
err := fmt.Errorf("unable to install cluster: %w", err)
465-
metrics.ReportApplyFinished(cmd.Context(), licenseFlag, err)
465+
metrics.ReportApplyFinished(cmd.Context(), licenseFlag, nil, err)
466466
return nil, err
467467
}
468468
loading.Infof("Waiting for %s node to be ready", runtimeconfig.BinaryName())
469469
logrus.Debugf("waiting for k0s to be ready")
470470
if err := waitForK0s(); err != nil {
471471
err := fmt.Errorf("unable to wait for node: %w", err)
472-
metrics.ReportApplyFinished(cmd.Context(), licenseFlag, err)
472+
metrics.ReportApplyFinished(cmd.Context(), licenseFlag, nil, err)
473473
return nil, err
474474
}
475475

cmd/installer/cli/install2.go

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"os"
88

9+
k0sconfig "github.com/k0sproject/k0s/pkg/apis/k0s/v1beta1"
910
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
1011
"github.com/replicatedhq/embedded-cluster/pkg/configutils"
1112
"github.com/replicatedhq/embedded-cluster/pkg/helpers"
@@ -15,6 +16,7 @@ import (
1516
"github.com/replicatedhq/embedded-cluster/pkg/prompts"
1617
"github.com/replicatedhq/embedded-cluster/pkg/release"
1718
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
19+
"github.com/replicatedhq/embedded-cluster/pkg/spinner"
1820
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
1921
"github.com/sirupsen/logrus"
2022
"github.com/spf13/cobra"
@@ -156,7 +158,7 @@ func runInstall2(cmd *cobra.Command, args []string, name string, flags Install2C
156158

157159
logrus.Debugf("materializing binaries")
158160
if err := materializeFiles(flags.airgapBundle); err != nil {
159-
metrics.ReportApplyFinished(cmd.Context(), flags.licenseFile, err)
161+
metrics.ReportApplyFinished(cmd.Context(), "", flags.license, err)
160162
return err
161163
}
162164

@@ -175,13 +177,17 @@ func runInstall2(cmd *cobra.Command, args []string, name string, flags Install2C
175177
return fmt.Errorf("unable to configure network manager: %w", err)
176178
}
177179

178-
if err := k0s.Install(flags.networkInterface); err != nil {
179-
return fmt.Errorf("unable to install cluster: %w", err)
180+
clusterConfig, err := installAndStartCluster(cmd.Context(), flags.networkInterface, flags.airgapBundle, flags.license, flags.proxy, flags.podCIDR, flags.serviceCIDR, flags.overrides)
181+
if err != nil {
182+
metrics.ReportApplyFinished(cmd.Context(), "", flags.license, err)
183+
return err
180184
}
181185

186+
fmt.Printf("%#v\n", clusterConfig)
187+
182188
logrus.Debugf("installing manager")
183189
if err := installAndEnableManager(); err != nil {
184-
metrics.ReportApplyFinished(cmd.Context(), flags.licenseFile, err)
190+
metrics.ReportApplyFinished(cmd.Context(), "", flags.license, err)
185191
return err
186192
}
187193

@@ -221,7 +227,7 @@ func runInstallVerifyAndPrompt(ctx context.Context, name string, flags *Install2
221227
license, err := getLicenseFromFilepath(flags.licenseFile)
222228
if err != nil {
223229
metricErr := fmt.Errorf("unable to get license: %w", err)
224-
metrics.ReportApplyFinished(ctx, flags.licenseFile, metricErr)
230+
metrics.ReportApplyFinished(ctx, "", flags.license, metricErr)
225231
return err // do not return the metricErr, as we want the user to see the error message without a prefix
226232
}
227233
isAirgap := false
@@ -238,7 +244,7 @@ func runInstallVerifyAndPrompt(ctx context.Context, name string, flags *Install2
238244
if !isAirgap {
239245
if err := maybePromptForAppUpdate(ctx, prompts.New(), license, flags.assumeYes); err != nil {
240246
if errors.Is(err, ErrNothingElseToAdd) {
241-
metrics.ReportApplyFinished(ctx, flags.licenseFile, err)
247+
metrics.ReportApplyFinished(ctx, "", flags.license, err)
242248
return err
243249
}
244250
// If we get an error other than ErrNothingElseToAdd, we warn and continue as
@@ -248,7 +254,7 @@ func runInstallVerifyAndPrompt(ctx context.Context, name string, flags *Install2
248254
}
249255

250256
if err := preflights.ValidateApp(); err != nil {
251-
metrics.ReportApplyFinished(ctx, flags.licenseFile, err)
257+
metrics.ReportApplyFinished(ctx, "", flags.license, err)
252258
return err
253259
}
254260

@@ -269,13 +275,14 @@ func runInstallVerifyAndPrompt(ctx context.Context, name string, flags *Install2
269275

270276
if validateAdminConsolePassword(promptA, promptB) {
271277
flags.adminConsolePassword = promptA
278+
break
272279
}
273280
}
274281
}
275282
}
276283
if flags.adminConsolePassword == "" {
277284
err := fmt.Errorf("no admin console password")
278-
metrics.ReportApplyFinished(ctx, flags.licenseFile, err)
285+
metrics.ReportApplyFinished(ctx, "", flags.license, err)
279286
return err
280287
}
281288

@@ -295,3 +302,40 @@ func runInstallPreflights(ctx context.Context, license *kotsv1beta1.License, pro
295302

296303
return nil
297304
}
305+
306+
func installAndStartCluster(ctx context.Context, networkInterface string, airgapBundle string, license *kotsv1beta1.License, proxy *ecv1beta1.ProxySpec, podCIDR string, serviceCIDR string, overrides string) (*k0sconfig.ClusterConfig, error) {
307+
loading := spinner.Start()
308+
defer loading.Close()
309+
loading.Infof("Installing %s node", runtimeconfig.BinaryName())
310+
logrus.Debugf("creating k0s configuration file")
311+
312+
cfg, err := k0s.WriteK0sConfig(ctx, networkInterface, airgapBundle, podCIDR, serviceCIDR, overrides)
313+
if err != nil {
314+
err := fmt.Errorf("unable to create config file: %w", err)
315+
metrics.ReportApplyFinished(ctx, "", license, err)
316+
return nil, err
317+
}
318+
logrus.Debugf("creating systemd unit files")
319+
if err := createSystemdUnitFiles(false, proxy); err != nil {
320+
err := fmt.Errorf("unable to create systemd unit files: %w", err)
321+
metrics.ReportApplyFinished(ctx, "", license, err)
322+
return nil, err
323+
}
324+
325+
logrus.Debugf("installing k0s")
326+
if err := k0s.Install(networkInterface); err != nil {
327+
err := fmt.Errorf("unable to install cluster: %w", err)
328+
metrics.ReportApplyFinished(ctx, "", license, err)
329+
return nil, err
330+
}
331+
loading.Infof("Waiting for %s node to be ready", runtimeconfig.BinaryName())
332+
logrus.Debugf("waiting for k0s to be ready")
333+
if err := waitForK0s(); err != nil {
334+
err := fmt.Errorf("unable to wait for node: %w", err)
335+
metrics.ReportApplyFinished(ctx, "", license, err)
336+
return nil, err
337+
}
338+
339+
loading.Infof("Node installation finished!")
340+
return cfg, nil
341+
}

pkg/k0s/install.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
package k0s
22

33
import (
4+
"context"
45
"fmt"
56
"os"
7+
"path/filepath"
68

9+
k0sconfig "github.com/k0sproject/k0s/pkg/apis/k0s/v1beta1"
10+
"github.com/replicatedhq/embedded-cluster/pkg/airgap"
711
"github.com/replicatedhq/embedded-cluster/pkg/config"
812
"github.com/replicatedhq/embedded-cluster/pkg/helpers"
913
"github.com/replicatedhq/embedded-cluster/pkg/netutils"
14+
"github.com/replicatedhq/embedded-cluster/pkg/release"
1015
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
16+
k8syaml "sigs.k8s.io/yaml"
1117
)
1218

1319
// Install runs the k0s install command and waits for it to finish. If no configuration
@@ -44,3 +50,91 @@ func IsInstalled() (bool, error) {
4450

4551
return false, fmt.Errorf("unable to check if already installed: %w", err)
4652
}
53+
54+
// WriteK0sConfig creates a new k0s.yaml configuration file. The file is saved in the
55+
// global location (as returned by runtimeconfig.PathToK0sConfig()). If a file already sits
56+
// there, this function returns an error.
57+
func WriteK0sConfig(ctx context.Context, networkInterface string, airgapBundle string, podCIDR string, serviceCIDR string, overrides string) (*k0sconfig.ClusterConfig, error) {
58+
cfgpath := runtimeconfig.PathToK0sConfig()
59+
if _, err := os.Stat(cfgpath); err == nil {
60+
return nil, fmt.Errorf("configuration file already exists")
61+
}
62+
if err := os.MkdirAll(filepath.Dir(cfgpath), 0755); err != nil {
63+
return nil, fmt.Errorf("unable to create directory: %w", err)
64+
}
65+
cfg := config.RenderK0sConfig()
66+
67+
address, err := netutils.FirstValidAddress(networkInterface)
68+
if err != nil {
69+
return nil, fmt.Errorf("unable to find first valid address: %w", err)
70+
}
71+
cfg.Spec.API.Address = address
72+
cfg.Spec.Storage.Etcd.PeerAddress = address
73+
74+
cfg.Spec.Network.PodCIDR = podCIDR
75+
cfg.Spec.Network.ServiceCIDR = serviceCIDR
76+
77+
cfg, err = applyUnsupportedOverrides(ctx, overrides, cfg)
78+
if err != nil {
79+
return nil, fmt.Errorf("unable to apply unsupported overrides: %w", err)
80+
}
81+
82+
if airgapBundle != "" {
83+
// update the k0s config to install with airgap
84+
airgap.RemapHelm(cfg)
85+
airgap.SetAirgapConfig(cfg)
86+
}
87+
// This is necessary to install the previous version of k0s in e2e tests
88+
// TODO: remove this once the previous version is > 1.29
89+
unstructured, err := helpers.K0sClusterConfigTo129Compat(cfg)
90+
if err != nil {
91+
return nil, fmt.Errorf("unable to convert cluster config to 1.29 compat: %w", err)
92+
}
93+
data, err := k8syaml.Marshal(unstructured)
94+
if err != nil {
95+
return nil, fmt.Errorf("unable to marshal config: %w", err)
96+
}
97+
if err := os.WriteFile(cfgpath, data, 0600); err != nil {
98+
return nil, fmt.Errorf("unable to write config file: %w", err)
99+
}
100+
return cfg, nil
101+
}
102+
103+
// applyUnsupportedOverrides applies overrides to the k0s configuration. Applies first the
104+
// overrides embedded into the binary and after the ones provided by the user (--overrides).
105+
// we first apply the k0s config override and then apply the built in overrides.
106+
func applyUnsupportedOverrides(ctx context.Context, overrides string, cfg *k0sconfig.ClusterConfig) (*k0sconfig.ClusterConfig, error) {
107+
embcfg, err := release.GetEmbeddedClusterConfig()
108+
if err != nil {
109+
return nil, fmt.Errorf("unable to get embedded cluster config: %w", err)
110+
}
111+
if embcfg != nil {
112+
overrides := embcfg.Spec.UnsupportedOverrides.K0s
113+
cfg, err = config.PatchK0sConfig(cfg, overrides)
114+
if err != nil {
115+
return nil, fmt.Errorf("unable to patch k0s config: %w", err)
116+
}
117+
cfg, err = config.ApplyBuiltInExtensionsOverrides(cfg, embcfg)
118+
if err != nil {
119+
return nil, fmt.Errorf("unable to release built in overrides: %w", err)
120+
}
121+
}
122+
123+
eucfg, err := helpers.ParseEndUserConfig(overrides)
124+
if err != nil {
125+
return nil, fmt.Errorf("unable to process overrides file: %w", err)
126+
}
127+
if eucfg != nil {
128+
overrides := eucfg.Spec.UnsupportedOverrides.K0s
129+
cfg, err = config.PatchK0sConfig(cfg, overrides)
130+
if err != nil {
131+
return nil, fmt.Errorf("unable to apply overrides: %w", err)
132+
}
133+
cfg, err = config.ApplyBuiltInExtensionsOverrides(cfg, eucfg)
134+
if err != nil {
135+
return nil, fmt.Errorf("unable to end user built in overrides: %w", err)
136+
}
137+
}
138+
139+
return cfg, nil
140+
}

pkg/metrics/reporter.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,16 @@ func ReportApplyStarted(ctx context.Context, licenseFlag string) {
150150
}
151151

152152
// ReportApplyFinished reports an InstallationSucceeded or an InstallationFailed.
153-
func ReportApplyFinished(ctx context.Context, licenseFlag string, err error) {
153+
func ReportApplyFinished(ctx context.Context, licenseFlag string, license *kotsv1beta1.License, err error) {
154+
if licenseFlag != "" {
155+
license = License(licenseFlag)
156+
}
157+
154158
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
155159
defer cancel()
156160
if err != nil {
157-
ReportInstallationFailed(ctx, License(licenseFlag), err)
161+
ReportInstallationFailed(ctx, license, err)
158162
return
159163
}
160-
ReportInstallationSucceeded(ctx, License(licenseFlag))
164+
ReportInstallationSucceeded(ctx, license)
161165
}

0 commit comments

Comments
 (0)