Skip to content

Commit

Permalink
remove dependency on multierror
Browse files Browse the repository at this point in the history
Signed-off-by: warpcomdev <[email protected]>
  • Loading branch information
warpcomdev committed Mar 6, 2022
1 parent 01cab16 commit 86b5120
Showing 1 changed file with 98 additions and 14 deletions.
112 changes: 98 additions & 14 deletions pkg/configmap/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"context"
"encoding/json"
"fmt"
"hash/fnv"
"sort"
"strings"
"time"

Expand Down Expand Up @@ -186,19 +188,30 @@ func (s *Sync) add(obj interface{}) {
}

func (s *Sync) update(oldObj, obj interface{}) {
cm := obj.(*v1.ConfigMap)
oldCm, cm := oldObj.(*v1.ConfigMap), obj.(*v1.ConfigMap)
if match, isPolicy := s.matcher(cm); match {
// avoid processing new versions of the ConfigMap that don't actually
// change policy, data or labels
// (issue https://github.com/open-policy-agent/kube-mgmt/issues/131)
if cm.GetResourceVersion() != oldCm.GetResourceVersion() {
fp, oldFp := fingerprint(cm), fingerprint(oldCm)
if fp == oldFp {
return
}
}
s.syncAdd(cm, isPolicy)
} else {
// check if the label was removed
oldCm := oldObj.(*v1.ConfigMap)
if match, isPolicy := s.matcher(oldCm); match {
s.syncRemove(oldCm, isPolicy)
}
}
}

func (s *Sync) delete(obj interface{}) {
if d, ok := obj.(cache.DeletedFinalStateUnknown); ok {
obj = d.Obj
}
cm := obj.(*v1.ConfigMap)
if match, isPolicy := s.matcher(cm); match {
s.syncRemove(cm, isPolicy)
Expand All @@ -207,7 +220,15 @@ func (s *Sync) delete(obj interface{}) {

func (s *Sync) syncAdd(cm *v1.ConfigMap, isPolicy bool) {
path := fmt.Sprintf("%v/%v", cm.Namespace, cm.Name)
for key, value := range cm.Data {
// sort keys so that errors, if any, are always in the same order
sortedKeys := make([]string, 0, len(cm.Data))
for key := range cm.Data {
sortedKeys = append(sortedKeys, key)
}
sort.Strings(sortedKeys)
var syncErr errList
for _, key := range sortedKeys {
value := cm.Data[key]
id := fmt.Sprintf("%v/%v", path, key)

var err error
Expand All @@ -225,16 +246,19 @@ func (s *Sync) syncAdd(cm *v1.ConfigMap, isPolicy bool) {
}

if err != nil {
s.setStatusAnnotation(cm, status{
Status: "error",
Error: err,
}, isPolicy)
} else {
s.setStatusAnnotation(cm, status{
Status: "ok",
}, isPolicy)
syncErr = append(syncErr, err)
}
}
if syncErr != nil {
s.setStatusAnnotation(cm, status{
Status: "error",
Error: syncErr,
}, isPolicy)
} else {
s.setStatusAnnotation(cm, status{
Status: "ok",
}, isPolicy)
}
}

func (s *Sync) syncRemove(cm *v1.ConfigMap, isPolicy bool) {
Expand Down Expand Up @@ -265,10 +289,20 @@ func (s *Sync) setStatusAnnotation(cm *v1.ConfigMap, st status, isPolicy bool) {
if err != nil {
logrus.Errorf("Failed to serialize %v for %v/%v: %v", statusAnnotationKey, cm.Namespace, cm.Name, err)
}
annotation := string(bs)
if cm.Annotations != nil {
if existing, ok := cm.Annotations[policyStatusAnnotationKey]; ok {
if existing == annotation {
// If the annotation did not change, do not write it.
// (issue https://github.com/open-policy-agent/kube-mgmt/issues/90)
return
}
}
}
patch := map[string]interface{}{
"metadata": map[string]interface{}{
"annotations": map[string]interface{}{
policyStatusAnnotationKey: string(bs),
policyStatusAnnotationKey: annotation,
},
},
}
Expand Down Expand Up @@ -298,7 +332,57 @@ func (s *Sync) syncReset(id string) {
}
}

// fingerprint for the labels and data of a configmap.
func fingerprint(cm *v1.ConfigMap) uint64 {
hash := fnv.New64a()
data := json.NewEncoder(hash)
data.Encode(cm.Labels)
data.Encode(cm.Data)
return hash.Sum64()
}

// errList is an error type that can marshal a list of errors to json
type errList []error

var (
// Make sure we implement the proper interfaces
_ error = errList{}
_ json.Marshaler = errList{}
)

type status struct {
Status string `json:"status"`
Error error `json:"error,omitempty"`
Status string `json:"status"`
Error errList `json:"error,omitempty"`
}

// MarshalJSON implements json.Marshaler
func (m errList) MarshalJSON() ([]byte, error) {
if m == nil || len(m) <= 0 {
return []byte(`""`), nil
}
list := make([]json.RawMessage, 0, len(m))
for _, err := range m {
if b, marshalErr := json.Marshal(err); marshalErr == nil {
list = append(list, b)
} else {
// fallback to quoted .Error() string if marshalling fails
list = append(list, []byte(fmt.Sprintf("%q", err.Error())))
}
}
if len(list) == 1 {
return list[0], nil // for backward compatibility
}
return json.Marshal(list)
}

// Error implements error
func (m errList) Error() string {
if m == nil || len(m) <= 0 {
return ""
}
text := make([]string, 0, len(m))
for _, err := range m {
text = append(text, err.Error())
}
return strings.Join(text, "\n")
}

0 comments on commit 86b5120

Please sign in to comment.