This repository has been archived by the owner on Dec 22, 2021. It is now read-only.
/
catalog.go
162 lines (143 loc) · 4.75 KB
/
catalog.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package catalog
import (
"sort"
"strings"
"sync"
"github.com/Masterminds/semver/v3"
"github.com/fluxcd/pkg/version"
"github.com/go-logr/logr"
profilesv1 "github.com/weaveworks/profiles/api/v1alpha1"
)
// Catalog provides an in-memory cache of profiles from the cluster which can be queried easily.
//type Catalog map[string][]profilesv1.ProfileCatalogEntry
type Catalog struct {
m sync.Map
}
// New creates a new, empty catalog.
func New() *Catalog {
return &Catalog{
m: sync.Map{},
}
}
// Append the existing profiles with new profiles
func (c *Catalog) Append(sourceName string, profiles ...profilesv1.ProfileCatalogEntry) {
existingProfiles, ok := c.m.Load(sourceName)
if !ok {
c.AddOrReplace(sourceName, profiles...)
return
}
c.AddOrReplace(sourceName, append(existingProfiles.([]profilesv1.ProfileCatalogEntry), profiles...)...)
}
// AddOrReplace replaces the catalog by replacing existing profiles with new profiles if it exists
// otherwise it creates it
func (c *Catalog) AddOrReplace(sourceName string, profiles ...profilesv1.ProfileCatalogEntry) {
for i := range profiles {
profiles[i].CatalogSource = sourceName
}
c.m.Store(sourceName, profiles)
}
// Remove removes the specified catalog.
func (c *Catalog) Remove(sourceName string) {
c.m.Delete(sourceName)
}
// Search returns profile descriptions that contain `name` in their names.
func (c *Catalog) Search(name string) []profilesv1.ProfileCatalogEntry {
var ret []profilesv1.ProfileCatalogEntry
c.m.Range(func(key, value interface{}) bool {
for _, p := range value.([]profilesv1.ProfileCatalogEntry) {
if strings.Contains(p.Name, name) {
ret = append(ret, p)
}
}
return true
})
return ret
}
// SearchAll returns `all` profile descriptions.
func (c *Catalog) SearchAll() []profilesv1.ProfileCatalogEntry {
var ret []profilesv1.ProfileCatalogEntry
c.m.Range(func(key, value interface{}) bool {
ret = append(ret, value.([]profilesv1.ProfileCatalogEntry)...)
return true
})
return ret
}
// Get returns the profile description `profileName`.
func (c *Catalog) Get(sourceName, profileName string) *profilesv1.ProfileCatalogEntry {
profiles, ok := c.m.Load(sourceName)
if !ok {
return nil
}
for _, p := range profiles.([]profilesv1.ProfileCatalogEntry) {
if p.Name == profileName && p.CatalogSource == sourceName {
return &p
}
}
return nil
}
// CatalogExists checks if the catalog exists
func (c *Catalog) CatalogExists(sourceName string) bool {
_, ok := c.m.Load(sourceName)
return ok
}
// GetWithVersion returns the profile description `profileName` with the given version.
func (c *Catalog) GetWithVersion(logger logr.Logger, sourceName, profileName, profileVersion string) *profilesv1.ProfileCatalogEntry {
profiles, ok := c.m.Load(sourceName)
if !ok {
return nil
}
if profileVersion == "latest" {
versions := c.ProfilesGreaterThanVersion(logger, sourceName, profileName, profileVersion)
if len(versions) == 0 {
return nil
}
return &versions[0]
}
for _, p := range profiles.([]profilesv1.ProfileCatalogEntry) {
if p.Name == profileName && p.CatalogSource == sourceName && profilesv1.GetVersionFromTag(p.Tag) == profileVersion {
return &p
}
}
return nil
}
type profileDescriptionWithVersion struct {
profileDescription profilesv1.ProfileCatalogEntry
semverVersion *semver.Version
}
// ProfilesGreaterThanVersion returns all profiles which are of a greater version for a given profile with a version.
// If set to "latest" all versions are returned. Versions are ordered in descending order
func (c *Catalog) ProfilesGreaterThanVersion(logger logr.Logger, sourceName, profileName, profileVersion string) []profilesv1.ProfileCatalogEntry {
var profilesWithValidVersion []profileDescriptionWithVersion
profiles, ok := c.m.Load(sourceName)
if !ok {
return nil
}
cv, err := version.ParseVersion(profileVersion)
if err != nil && profileVersion != "latest" {
return nil
}
for _, p := range profiles.([]profilesv1.ProfileCatalogEntry) {
tag := profilesv1.GetVersionFromTag(p.Tag)
v, err := version.ParseVersion(tag)
if err != nil {
logger.Error(err, "failed to parse profile version", "profile", p, "tag", tag, "pTag", p.Tag)
continue
}
if p.Name == profileName {
if profileVersion == "latest" || v.GreaterThan(cv) {
profilesWithValidVersion = append(profilesWithValidVersion, profileDescriptionWithVersion{profileDescription: p, semverVersion: v})
}
}
}
if len(profilesWithValidVersion) == 0 {
return nil
}
sort.SliceStable(profilesWithValidVersion, func(i, j int) bool {
return profilesWithValidVersion[j].semverVersion.LessThan(profilesWithValidVersion[i].semverVersion)
})
var result []profilesv1.ProfileCatalogEntry
for _, p := range profilesWithValidVersion {
result = append(result, p.profileDescription)
}
return result
}