Fix issue with concurrent CR creation
[demo.git] / vnfs / DAaaS / microservices / collectd-operator / pkg / controller / utils / collectdutils.go
1 package utils
2
3 import (
4         "context"
5         "crypto/sha256"
6         "fmt"
7         "os"
8         "sync"
9
10         "github.com/go-logr/logr"
11
12         onapv1alpha1 "collectd-operator/pkg/apis/onap/v1alpha1"
13
14         appsv1 "k8s.io/api/apps/v1"
15         corev1 "k8s.io/api/core/v1"
16         "k8s.io/apimachinery/pkg/api/errors"
17         "sigs.k8s.io/controller-runtime/pkg/client"
18 )
19
20 // Define the collectdPlugin finalizer for handling deletion
21 const (
22         defaultWatchLabel = "app=collectd"
23         CollectdFinalizer = "finalizer.collectd.onap.org"
24
25         // WatchLabelsEnvVar is the constant for env variable WATCH_LABELS
26         // which is the labels where the watch activity happens.
27         // this value is empty if the operator is running with clusterScope.
28         WatchLabelsEnvVar = "WATCH_LABELS"
29 )
30
31 var lock sync.Mutex
32
33 // ResourceMap to hold objects to update/reload
34 type ResourceMap struct {
35         ConfigMap       *corev1.ConfigMap
36         DaemonSet       *appsv1.DaemonSet
37         CollectdPlugins *[]onapv1alpha1.CollectdPlugin
38 }
39
40 // ComputeSHA256  returns hash of data as string
41 func ComputeSHA256(data []byte) string {
42         hash := sha256.Sum256(data)
43         return fmt.Sprintf("%x", hash)
44 }
45
46 // Contains checks if a string is contained in a list of strings
47 func Contains(list []string, s string) bool {
48         for _, v := range list {
49                 if v == s {
50                         return true
51                 }
52         }
53         return false
54 }
55
56 // Remove removes a string from a list of string
57 func Remove(list []string, s string) []string {
58         for i, v := range list {
59                 if v == s {
60                         list = append(list[:i], list[i+1:]...)
61                 }
62         }
63         return list
64 }
65
66 // GetWatchLabels returns the labels the operator should be watching for changes
67 func GetWatchLabels() (string, error) {
68         labelSelector, found := os.LookupEnv(WatchLabelsEnvVar)
69         if !found {
70                 return defaultWatchLabel, fmt.Errorf("%s must be set", WatchLabelsEnvVar)
71         }
72         return labelSelector, nil
73 }
74
75 // GetCollectdPluginList returns the list of CollectdPlugin instances in the namespace ns
76 func GetCollectdPluginList(rc client.Client, ns string) (*onapv1alpha1.CollectdPluginList, error) {
77         // Get all collectd plugins in the current namespace to rebuild conf.
78         collectdPlugins := &onapv1alpha1.CollectdPluginList{}
79         cpOpts := &client.ListOptions{}
80         cpOpts.InNamespace(ns)
81         err := rc.List(context.TODO(), cpOpts, collectdPlugins)
82         if err != nil {
83                 return nil, err
84         }
85         return collectdPlugins, nil
86 }
87
88 // GetConfigMap returns the GetConfigMap in the namespace ns
89 func GetConfigMap(rc client.Client, reqLogger logr.Logger, ns string) (*corev1.ConfigMap, error) {
90         lock.Lock()
91         defer lock.Unlock()
92
93         reqLogger.Info("Get ConfigMap for collectd.conf")
94         // Get all collectd plugins in the current namespace to rebuild conf.
95         cmList := &corev1.ConfigMapList{}
96         opts := &client.ListOptions{}
97         // Select ConfigMaps with label
98         labelSelector, err := GetWatchLabels()
99         if err != nil {
100                 reqLogger.Error(err, "Failed to get watch labels, continuing with default label")
101         }
102         opts.SetLabelSelector(labelSelector)
103         opts.InNamespace(ns)
104
105         err = rc.List(context.TODO(), opts, cmList)
106         if err != nil {
107                 return nil, err
108         }
109
110         if cmList.Items == nil || len(cmList.Items) == 0 {
111                 return nil, errors.NewNotFound(corev1.Resource("configmap"), "ConfigMap")
112         }
113
114         cm := &cmList.Items[0]
115         return cm, nil
116 }
117
118 // GetCollectdGlobal returns the CollectdGlobal instance in the namespace ns
119 func GetCollectdGlobal(rc client.Client, ns string) (*onapv1alpha1.CollectdGlobal, error) {
120         // Get the CollectdGlobal instance in current namespace to rebuild conf.
121         cgList := &onapv1alpha1.CollectdGlobalList{}
122         cpOpts := &client.ListOptions{}
123         cpOpts.InNamespace(ns)
124         err := rc.List(context.TODO(), cpOpts, cgList)
125         if err != nil {
126                 return nil, err
127         }
128         if cgList.Items == nil || len(cgList.Items) == 0 {
129                 return nil, err
130         }
131         collectdGlobals := &cgList.Items[0]
132         return collectdGlobals, nil
133 }
134
135 // GetPodList returns the list of pods in the namespace ns
136 func GetPodList(rc client.Client, ns string) ([]string, error) {
137         var pods []string
138         podList := &corev1.PodList{}
139         opts := &client.ListOptions{}
140         // Select ConfigMaps with label
141         labelSelector, _ := GetWatchLabels()
142         opts.SetLabelSelector(labelSelector)
143         opts.InNamespace(ns)
144         err := rc.List(context.TODO(), opts, podList)
145         if err != nil {
146                 return nil, err
147         }
148
149         if podList.Items == nil || len(podList.Items) == 0 {
150                 return nil, err
151         }
152
153         for _, pod := range podList.Items {
154                 pods = append(pods, pod.Name)
155         }
156         return pods, nil
157 }
158
159 // RebuildCollectdConf Get all collectd plugins and reconstruct, compute Hash and check for changes
160 func RebuildCollectdConf(rc client.Client, ns string, isDelete bool, delPlugin string) (string, error) {
161         var collectdConf, collectdGlobalConf string
162         // Get the collectd global in the current namespace to rebuild conf.
163         cg, err := GetCollectdGlobal(rc, ns)
164         if err != nil {
165                 return "", err
166         }
167
168         if cg != nil {
169                 collectdGlobalConf += cg.Spec.GlobalOptions + "\n"
170         }
171
172         // Get all collectd plugins in the current namespace to rebuild conf.
173         cp, err := GetCollectdPluginList(rc, ns)
174         if err != nil {
175                 return "", err
176         }
177         cpList := &cp.Items
178         loadPlugin := make(map[string]string)
179         if *cpList != nil && len(*cpList) > 0 {
180                 for _, cp := range *cpList {
181                         // using CollectdPlugin to set global options. If CollectdGlobal CRD is defined do not check for this
182                         if cp.Spec.PluginName == "global" {
183                                 if cg == nil {
184                                         collectdGlobalConf += cp.Spec.PluginConf + "\n"
185                                 }
186                         } else {
187                                 loadPlugin[cp.Spec.PluginName] = cp.Spec.PluginConf
188                         }
189                 }
190         }
191
192         if isDelete {
193                 delete(loadPlugin, delPlugin)
194         } else {
195                 collectdConf += collectdGlobalConf
196         }
197
198         for cpName, cpConf := range loadPlugin {
199                 collectdConf += "LoadPlugin" + " " + cpName + "\n"
200                 collectdConf += cpConf + "\n"
201         }
202
203         collectdConf += "#Last line (collectd requires ā€˜\\nā€™ at the last line)\n"
204
205         return collectdConf, nil
206 }