github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/operators/internal/alongside/alongside.go (about) 1 // Package alongside provides a mechanism for recording the fact that 2 // one object was installed alongside another object as part of the 3 // installation of the same operator version. 4 package alongside 5 6 import ( 7 "fmt" 8 "hash/fnv" 9 "strings" 10 ) 11 12 const ( 13 AnnotationPrefix = "operatorframework.io/installed-alongside-" 14 ) 15 16 // NamespacedName is a reference to an object by namespace and name. 17 type NamespacedName struct { 18 Namespace string 19 Name string 20 } 21 22 type Annotatable interface { 23 GetAnnotations() map[string]string 24 SetAnnotations(map[string]string) 25 } 26 27 // Annotator translates installed-alongside references to and from 28 // object annotations. 29 type Annotator struct{} 30 31 // FromObject returns a slice containing each namespaced name 32 // referenced by an alongside annotation on the provided Object. 33 func (a Annotator) FromObject(o Annotatable) []NamespacedName { 34 var result []NamespacedName 35 for k, v := range o.GetAnnotations() { 36 if !strings.HasPrefix(k, AnnotationPrefix) { 37 continue 38 } 39 tokens := strings.Split(v, "/") 40 if len(tokens) != 2 { 41 continue 42 } 43 result = append(result, NamespacedName{ 44 Namespace: tokens[0], 45 Name: tokens[1], 46 }) 47 } 48 return result 49 } 50 51 // ToObject removes all existing alongside annotations on the provided 52 // Object and adds one new annotation per entry in the provided slice 53 // of namespaced names. 54 func (a Annotator) ToObject(o Annotatable, nns []NamespacedName) { 55 annotations := o.GetAnnotations() 56 57 for key := range annotations { 58 if strings.HasPrefix(key, AnnotationPrefix) { 59 delete(annotations, key) 60 } 61 } 62 63 if len(nns) == 0 { 64 if len(annotations) == 0 { 65 annotations = nil 66 } 67 o.SetAnnotations(annotations) 68 return 69 } 70 71 if annotations == nil { 72 annotations = make(map[string]string, len(nns)) 73 } 74 for _, nn := range nns { 75 annotations[key(nn)] = fmt.Sprintf("%s/%s", nn.Namespace, nn.Name) 76 } 77 o.SetAnnotations(annotations) 78 } 79 80 func key(n NamespacedName) string { 81 hasher := fnv.New64a() 82 hasher.Write([]byte(n.Namespace)) 83 hasher.Write([]byte{'/'}) 84 hasher.Write([]byte(n.Name)) 85 return fmt.Sprintf("%s%x", AnnotationPrefix, hasher.Sum64()) 86 }