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