Skip to content

Commit 3e99eba

Browse files
committed
fix(ha): make more resilient with a job
1 parent be79ef2 commit 3e99eba

File tree

25 files changed

+1123
-361
lines changed

25 files changed

+1123
-361
lines changed

cmd/installer/cli/enable_ha.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/replicatedhq/embedded-cluster/pkg/addons"
9+
"github.com/replicatedhq/embedded-cluster/pkg/helm"
10+
"github.com/replicatedhq/embedded-cluster/pkg/kubeutils"
11+
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
12+
rcutil "github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig/util"
13+
"github.com/replicatedhq/embedded-cluster/pkg/versions"
14+
"github.com/sirupsen/logrus"
15+
"github.com/spf13/cobra"
16+
)
17+
18+
// EnableHACmd is the command for enabling HA mode.
19+
func EnableHACmd(ctx context.Context, name string) *cobra.Command {
20+
cmd := &cobra.Command{
21+
Use: "enable-ha",
22+
Short: fmt.Sprintf("Enable high availability for the %s cluster", name),
23+
Hidden: true,
24+
PreRunE: func(cmd *cobra.Command, args []string) error {
25+
if os.Getuid() != 0 {
26+
return fmt.Errorf("enable-ha command must be run as root")
27+
}
28+
29+
rcutil.InitBestRuntimeConfig(cmd.Context())
30+
31+
os.Setenv("KUBECONFIG", runtimeconfig.PathToKubeConfig())
32+
os.Setenv("TMPDIR", runtimeconfig.EmbeddedClusterTmpSubDir())
33+
34+
return nil
35+
},
36+
PostRun: func(cmd *cobra.Command, args []string) {
37+
runtimeconfig.Cleanup()
38+
},
39+
RunE: func(cmd *cobra.Command, args []string) error {
40+
if err := runEnableHA(cmd.Context()); err != nil {
41+
return err
42+
}
43+
44+
return nil
45+
},
46+
}
47+
48+
return cmd
49+
}
50+
51+
func runEnableHA(ctx context.Context) error {
52+
kcli, err := kubeutils.KubeClient()
53+
if err != nil {
54+
return fmt.Errorf("unable to get kube client: %w", err)
55+
}
56+
57+
canEnableHA, reason, err := addons.CanEnableHA(ctx, kcli)
58+
if err != nil {
59+
return fmt.Errorf("unable to check if HA can be enabled: %w", err)
60+
}
61+
if !canEnableHA {
62+
logrus.Warnf("High availability cannot be enabled: %s", reason)
63+
return NewErrorNothingElseToAdd(fmt.Errorf("high availability cannot be enabled: %s", reason))
64+
}
65+
66+
kclient, err := kubeutils.GetClientset()
67+
if err != nil {
68+
return fmt.Errorf("unable to create kubernetes client: %w", err)
69+
}
70+
71+
in, err := kubeutils.GetLatestInstallation(ctx, kcli)
72+
if err != nil {
73+
return fmt.Errorf("unable to get latest installation: %w", err)
74+
}
75+
76+
airgapChartsPath := ""
77+
if in.Spec.AirGap {
78+
airgapChartsPath = runtimeconfig.EmbeddedClusterChartsSubDir()
79+
}
80+
81+
hcli, err := helm.NewClient(helm.HelmOptions{
82+
KubeConfig: runtimeconfig.PathToKubeConfig(),
83+
K0sVersion: versions.K0sVersion,
84+
AirgapPath: airgapChartsPath,
85+
})
86+
if err != nil {
87+
return fmt.Errorf("unable to create helm client: %w", err)
88+
}
89+
defer hcli.Close()
90+
91+
return addons.EnableHA(ctx, kcli, kclient, hcli, in.Spec.AirGap, in.Spec.Network.ServiceCIDR, in.Spec.Proxy, in.Spec.Config)
92+
}

cmd/installer/cli/install.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,6 @@ type InstallCmdFlags struct {
7878
}
7979

8080
// InstallCmd returns a cobra command for installing the embedded cluster.
81-
// This is the upcoming version of install without the operator and where
82-
// install does all of the work. This is a hidden command until it's tested
83-
// and ready.
8481
func InstallCmd(ctx context.Context, name string) *cobra.Command {
8582
var flags InstallCmdFlags
8683

cmd/installer/cli/join.go

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/sirupsen/logrus"
2828
"github.com/spf13/cobra"
2929
"gopkg.in/yaml.v2"
30+
"k8s.io/client-go/kubernetes"
3031
"sigs.k8s.io/controller-runtime/pkg/client"
3132
k8syaml "sigs.k8s.io/yaml"
3233
)
@@ -41,9 +42,7 @@ type JoinCmdFlags struct {
4142
ignoreHostPreflights bool
4243
}
4344

44-
// This is the upcoming version of join without the operator and where
45-
// join does all of the work. This is a hidden command until it's tested
46-
// and ready.
45+
// JoinCmd returns a cobra command for joining a node to the cluster.
4746
func JoinCmd(ctx context.Context, name string) *cobra.Command {
4847
var flags JoinCmdFlags
4948

@@ -202,23 +201,28 @@ func runJoin(ctx context.Context, name string, flags JoinCmdFlags, jcmd *kotsadm
202201
return nil
203202
}
204203

205-
airgapChartsPath := ""
206-
if flags.isAirgap {
207-
airgapChartsPath = runtimeconfig.EmbeddedClusterChartsSubDir()
208-
}
204+
if flags.enableHighAvailability {
205+
kclient, err := kubeutils.GetClientset()
206+
if err != nil {
207+
return fmt.Errorf("unable to create kubernetes client: %w", err)
208+
}
209209

210-
hcli, err := helm.NewClient(helm.HelmOptions{
211-
KubeConfig: runtimeconfig.PathToKubeConfig(),
212-
K0sVersion: versions.K0sVersion,
213-
AirgapPath: airgapChartsPath,
214-
})
215-
if err != nil {
216-
return fmt.Errorf("unable to create helm client: %w", err)
217-
}
218-
defer hcli.Close()
210+
airgapChartsPath := ""
211+
if flags.isAirgap {
212+
airgapChartsPath = runtimeconfig.EmbeddedClusterChartsSubDir()
213+
}
219214

220-
if flags.enableHighAvailability {
221-
if err := maybeEnableHA(ctx, kcli, hcli, flags.isAirgap, cidrCfg.ServiceCIDR, jcmd.InstallationSpec.Proxy, jcmd.InstallationSpec.Config); err != nil {
215+
hcli, err := helm.NewClient(helm.HelmOptions{
216+
KubeConfig: runtimeconfig.PathToKubeConfig(),
217+
K0sVersion: versions.K0sVersion,
218+
AirgapPath: airgapChartsPath,
219+
})
220+
if err != nil {
221+
return fmt.Errorf("unable to create helm client: %w", err)
222+
}
223+
defer hcli.Close()
224+
225+
if err := maybeEnableHA(ctx, kcli, kclient, hcli, flags.isAirgap, cidrCfg.ServiceCIDR, jcmd.InstallationSpec.Proxy, jcmd.InstallationSpec.Config); err != nil {
222226
return fmt.Errorf("unable to enable high availability: %w", err)
223227
}
224228
}
@@ -493,8 +497,8 @@ func waitForNodeToJoin(ctx context.Context, kcli client.Client, hostname string,
493497
return nil
494498
}
495499

496-
func maybeEnableHA(ctx context.Context, kcli client.Client, hcli helm.Client, isAirgap bool, serviceCIDR string, proxy *ecv1beta1.ProxySpec, cfgspec *ecv1beta1.ConfigSpec) error {
497-
canEnableHA, err := addons.CanEnableHA(ctx, kcli)
500+
func maybeEnableHA(ctx context.Context, kcli client.Client, kclient kubernetes.Interface, hcli helm.Client, isAirgap bool, serviceCIDR string, proxy *ecv1beta1.ProxySpec, cfgspec *ecv1beta1.ConfigSpec) error {
501+
canEnableHA, _, err := addons.CanEnableHA(ctx, kcli)
498502
if err != nil {
499503
return fmt.Errorf("unable to check if HA can be enabled: %w", err)
500504
}
@@ -509,5 +513,5 @@ func maybeEnableHA(ctx context.Context, kcli client.Client, hcli helm.Client, is
509513
return nil
510514
}
511515
logrus.Info("")
512-
return addons.EnableHA(ctx, kcli, hcli, isAirgap, serviceCIDR, proxy, cfgspec)
516+
return addons.EnableHA(ctx, kcli, kclient, hcli, isAirgap, serviceCIDR, proxy, cfgspec)
513517
}

cmd/installer/cli/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ func RootCmd(ctx context.Context, name string) *cobra.Command {
100100
cmd.AddCommand(JoinCmd(ctx, name))
101101
cmd.AddCommand(ShellCmd(ctx, name))
102102
cmd.AddCommand(NodeCmd(ctx, name))
103+
cmd.AddCommand(EnableHACmd(ctx, name))
103104
cmd.AddCommand(VersionCmd(ctx, name))
104105
cmd.AddCommand(ResetCmd(ctx, name))
105106
cmd.AddCommand(MaterializeCmd(ctx, name))

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ require (
4141
github.com/vmware-tanzu/velero v1.15.2
4242
go.uber.org/multierr v1.11.0
4343
golang.org/x/crypto v0.33.0
44-
golang.org/x/sync v0.11.0
4544
golang.org/x/term v0.29.0
4645
gopkg.in/yaml.v2 v2.4.0
4746
gopkg.in/yaml.v3 v3.0.1
@@ -272,6 +271,7 @@ require (
272271
go.opentelemetry.io/otel/trace v1.34.0 // indirect
273272
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
274273
golang.org/x/mod v0.23.0 // indirect
274+
golang.org/x/sync v0.11.0 // indirect
275275
golang.org/x/tools v0.28.0 // indirect
276276
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
277277
google.golang.org/api v0.197.0 // indirect

operator/pkg/cli/migrate.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/replicatedhq/embedded-cluster/pkg/addons/registry/migrate"
7+
"github.com/replicatedhq/embedded-cluster/pkg/kubeutils"
8+
"github.com/spf13/cobra"
9+
)
10+
11+
func MigrateCmd() *cobra.Command {
12+
cmd := &cobra.Command{
13+
Use: "migrate",
14+
Short: "Run the specified migration",
15+
}
16+
17+
cmd.AddCommand(
18+
MigrateRegistryDataCmd(),
19+
)
20+
21+
return cmd
22+
}
23+
24+
func MigrateRegistryDataCmd() *cobra.Command {
25+
cmd := &cobra.Command{
26+
Use: "registry-data",
27+
Short: "Run the registry-data migration",
28+
SilenceUsage: true,
29+
RunE: func(cmd *cobra.Command, args []string) error {
30+
ctx := cmd.Context()
31+
32+
cli, err := kubeutils.KubeClient()
33+
if err != nil {
34+
return fmt.Errorf("failed to create kubernetes client: %w", err)
35+
}
36+
37+
err = migrate.RegistryData(ctx, cli)
38+
if err != nil {
39+
return fmt.Errorf("failed to migrate registry data: %w", err)
40+
}
41+
return nil
42+
},
43+
}
44+
45+
return cmd
46+
}

operator/pkg/cli/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ func addSubcommands(cmd *cobra.Command) {
117117
cmd.AddCommand(
118118
UpgradeCmd(),
119119
UpgradeJobCmd(),
120+
MigrateCmd(),
120121
MigrateV2Cmd(),
121122
VersionCmd(),
122123
)

pkg/addons/embeddedclusteroperator/upgrade.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ package embeddedclusteroperator
22

33
import (
44
"context"
5-
"log/slog"
65

76
"github.com/pkg/errors"
87
"github.com/replicatedhq/embedded-cluster/pkg/helm"
8+
"github.com/sirupsen/logrus"
99
"sigs.k8s.io/controller-runtime/pkg/client"
1010
)
1111

@@ -15,7 +15,7 @@ func (e *EmbeddedClusterOperator) Upgrade(ctx context.Context, kcli client.Clien
1515
return errors.Wrap(err, "check if release exists")
1616
}
1717
if !exists {
18-
slog.Info("Release not found, installing", "release", releaseName, "namespace", namespace)
18+
logrus.Debugf("Release not found, installing release %s in namespace %s", releaseName, namespace)
1919
if err := e.Install(ctx, kcli, hcli, overrides, nil); err != nil {
2020
return errors.Wrap(err, "install")
2121
}

0 commit comments

Comments
 (0)