Skip to content
This repository was archived by the owner on Jun 29, 2022. It is now read-only.

Commit 5e69aac

Browse files
committed
pkg/components/util: refactor InstallComponent to make it shorter
This commit moves ensuring that release namespace exists code into separate function, so linter does not complain about function length and potentially allows to test this bit of code independently. Signed-off-by: Mateusz Gozdek <mateusz@kinvolk.io>
1 parent 7325ce8 commit 5e69aac

File tree

1 file changed

+67
-37
lines changed

1 file changed

+67
-37
lines changed

pkg/components/util/install.go

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020

2121
"helm.sh/helm/v3/pkg/action"
22+
"helm.sh/helm/v3/pkg/chart"
2223
"helm.sh/helm/v3/pkg/kube"
2324
"helm.sh/helm/v3/pkg/storage/driver"
2425
v1 "k8s.io/api/core/v1"
@@ -29,31 +30,38 @@ import (
2930
"github.com/kinvolk/lokomotive/pkg/k8sutil"
3031
)
3132

32-
// InstallComponent installs given component using given kubeconfig as a Helm release using a Helm client.
33-
func InstallComponent(c components.Component, kubeconfig string) error {
34-
name := c.Metadata().Name
35-
36-
cs, err := k8sutil.NewClientset(kubeconfig)
33+
func ensureNamespaceExists(name string, kubeconfigPath string) error {
34+
cs, err := k8sutil.NewClientset(kubeconfigPath)
3735
if err != nil {
38-
return err
36+
return fmt.Errorf("creating clientset: %w", err)
3937
}
4038

41-
// Get the namespace in which the component should be created.
42-
ns := c.Metadata().Namespace
43-
if ns == "" {
44-
return fmt.Errorf("component %s namespace is empty", name)
39+
if name == "" {
40+
return fmt.Errorf("namespace name can't be empty")
4541
}
4642

4743
// Ensure the namespace in which we create release and resources exists.
4844
_, err = cs.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{
4945
ObjectMeta: metav1.ObjectMeta{
50-
Name: ns,
46+
Name: name,
5147
},
5248
}, metav1.CreateOptions{})
5349
if err != nil && !errors.IsAlreadyExists(err) {
5450
return err
5551
}
5652

53+
return nil
54+
}
55+
56+
// InstallComponent installs given component using given kubeconfig as a Helm release using a Helm client.
57+
func InstallComponent(c components.Component, kubeconfig string) error {
58+
name := c.Metadata().Name
59+
ns := c.Metadata().Namespace
60+
61+
if err := ensureNamespaceExists(ns, kubeconfig); err != nil {
62+
return fmt.Errorf("failed ensuring that namespace %q for component %q exists: %w", ns, name, err)
63+
}
64+
5765
actionConfig, err := HelmActionConfig(ns, kubeconfig)
5866
if err != nil {
5967
return fmt.Errorf("failed preparing helm client: %w", err)
@@ -75,37 +83,59 @@ func InstallComponent(c components.Component, kubeconfig string) error {
7583

7684
wait := c.Metadata().Helm.Wait
7785

86+
helmAction := &helmAction{
87+
releaseName: name,
88+
chart: chart,
89+
actionConfig: actionConfig,
90+
wait: wait,
91+
}
92+
7893
if !exists {
79-
install := action.NewInstall(actionConfig)
80-
install.ReleaseName = name
81-
install.Namespace = ns
82-
83-
// Currently, we install components one-by-one, in the order how they are
84-
// defined in the configuration and we do not support any dependencies between
85-
// the components.
86-
//
87-
// If it is critical for component to have it's dependencies ready before it is
88-
// installed, all dependencies should set Wait field to 'true' in components.HelmMetadata
89-
// struct.
90-
//
91-
// The example of such dependency is between prometheus-operator and openebs-storage-class, where
92-
// both openebs-operator and openebs-storage-class components must be fully functional, before
93-
// prometheus-operator is deployed, otherwise it won't pick the default storage class.
94-
install.Wait = wait
95-
96-
if _, err := install.Run(chart, map[string]interface{}{}); err != nil {
97-
return fmt.Errorf("installing component '%s' as chart failed: %w", name, err)
98-
}
99-
100-
return nil
94+
return install(helmAction, ns)
10195
}
10296

103-
upgrade := action.NewUpgrade(actionConfig)
104-
upgrade.Wait = wait
97+
return upgrade(helmAction)
98+
}
99+
100+
type helmAction struct {
101+
releaseName string
102+
chart *chart.Chart
103+
actionConfig *action.Configuration
104+
wait bool
105+
}
106+
107+
func install(helmAction *helmAction, namespace string) error {
108+
install := action.NewInstall(helmAction.actionConfig)
109+
install.ReleaseName = helmAction.releaseName
110+
install.Namespace = namespace
111+
112+
// Currently, we install components one-by-one, in the order how they are
113+
// defined in the configuration and we do not support any dependencies between
114+
// the components.
115+
//
116+
// If it is critical for component to have it's dependencies ready before it is
117+
// installed, all dependencies should set Wait field to 'true' in components.HelmMetadata
118+
// struct.
119+
//
120+
// The example of such dependency is between prometheus-operator and openebs-storage-class, where
121+
// both openebs-operator and openebs-storage-class components must be fully functional, before
122+
// prometheus-operator is deployed, otherwise it won't pick the default storage class.
123+
install.Wait = helmAction.wait
124+
125+
if _, err := install.Run(helmAction.chart, map[string]interface{}{}); err != nil {
126+
return fmt.Errorf("installing release failed: %w", err)
127+
}
128+
129+
return nil
130+
}
131+
132+
func upgrade(helmAction *helmAction) error {
133+
upgrade := action.NewUpgrade(helmAction.actionConfig)
134+
upgrade.Wait = helmAction.wait
105135
upgrade.RecreateResources = true
106136

107-
if _, err := upgrade.Run(name, chart, map[string]interface{}{}); err != nil {
108-
return fmt.Errorf("updating chart failed: %w", err)
137+
if _, err := upgrade.Run(helmAction.releaseName, helmAction.chart, map[string]interface{}{}); err != nil {
138+
return fmt.Errorf("upgrading release failed: %w", err)
109139
}
110140

111141
return nil

0 commit comments

Comments
 (0)