@@ -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