Skip to content

Commit 8b41a86

Browse files
subhashish-devtronadi6859gireesh-naidu
authored
chore: Resource mapping refactoring (#4813)
* change sync * vars * refactor * fix: use JoinCookie method (#4892) * sql file merged --------- Co-authored-by: adi6859 <[email protected]> Co-authored-by: Gireesh Naidu <[email protected]>
1 parent 3b56719 commit 8b41a86

15 files changed

+659
-63
lines changed

pkg/resourceQualifiers/QualifierMappingService.go

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
package resourceQualifiers
22

33
import (
4+
"fmt"
5+
mapset "github.com/deckarep/golang-set"
46
"github.com/devtron-labs/devtron/pkg/devtronResource"
7+
"github.com/devtron-labs/devtron/pkg/devtronResource/bean"
58
"github.com/devtron-labs/devtron/pkg/sql"
69
"github.com/go-pg/pg"
10+
"github.com/pkg/errors"
711
"go.uber.org/zap"
12+
"golang.org/x/exp/maps"
13+
"golang.org/x/exp/slices"
14+
"time"
815
)
916

1017
type QualifierMappingService interface {
1118
CreateQualifierMappings(qualifierMappings []*QualifierMapping, tx *pg.Tx) ([]*QualifierMapping, error)
1219
GetQualifierMappings(resourceType ResourceType, scope *Scope, resourceIds []int) ([]*QualifierMapping, error)
1320
DeleteAllQualifierMappings(resourceType ResourceType, auditLog sql.AuditLog, tx *pg.Tx) error
1421
DeleteByIdentifierKeyValue(resourceType ResourceType, identifierKey int, identifierValue int, auditLog sql.AuditLog, tx *pg.Tx) error
22+
DeleteAllByIds(qualifierMappingIds []int, userId int32, tx *pg.Tx) error
23+
DeleteResourceMappingsForScopes(tx *pg.Tx, userId int32, resourceType ResourceType, qualifierSelector QualifierSelector, scopes []*SelectionIdentifier) error
24+
CreateMappingsForSelections(tx *pg.Tx, userId int32, resourceMappingSelections []*ResourceMappingSelection) ([]*ResourceMappingSelection, error)
25+
CreateMappings(tx *pg.Tx, userId int32, resourceType ResourceType, resourceIds []int, qualifierSelector QualifierSelector, selectionIdentifiers []*SelectionIdentifier) error
26+
GetResourceMappingsForSelections(resourceType ResourceType, qualifierSelector QualifierSelector, selectionIdentifiers []*SelectionIdentifier) ([]ResourceQualifierMappings, error)
27+
GetResourceMappingsForResources(resourceType ResourceType, resourceIds []int, qualifierSelector QualifierSelector) ([]ResourceQualifierMappings, error)
1528
}
1629

1730
type QualifierMappingServiceImpl struct {
@@ -44,3 +57,237 @@ func (impl QualifierMappingServiceImpl) DeleteAllQualifierMappings(resourceType
4457
func (impl QualifierMappingServiceImpl) DeleteByIdentifierKeyValue(resourceType ResourceType, identifierKey int, identifierValue int, auditLog sql.AuditLog, tx *pg.Tx) error {
4558
return impl.qualifierMappingRepository.DeleteByResourceTypeIdentifierKeyAndValue(resourceType, identifierKey, identifierValue, auditLog, tx)
4659
}
60+
61+
func (impl QualifierMappingServiceImpl) DeleteAllByIds(qualifierMappingIds []int, userId int32, tx *pg.Tx) error {
62+
auditLog := sql.AuditLog{
63+
CreatedOn: time.Now(),
64+
CreatedBy: userId,
65+
UpdatedOn: time.Now(),
66+
UpdatedBy: userId,
67+
}
68+
return impl.qualifierMappingRepository.DeleteAllByIds(qualifierMappingIds, auditLog, tx)
69+
}
70+
71+
func (impl QualifierMappingServiceImpl) CreateMappingsForSelections(tx *pg.Tx, userId int32, resourceMappingSelections []*ResourceMappingSelection) ([]*ResourceMappingSelection, error) {
72+
73+
resourceKeyMap := impl.devtronResourceSearchableKeyService.GetAllSearchableKeyNameIdMap()
74+
75+
parentMappings := make([]*QualifierMapping, 0)
76+
childrenMappings := make([]*QualifierMapping, 0)
77+
parentMappingsMap := make(map[string]*QualifierMapping)
78+
79+
mappingsToSelection := make(map[*QualifierMapping]*ResourceMappingSelection)
80+
for _, selection := range resourceMappingSelections {
81+
82+
var parent *QualifierMapping
83+
children := make([]*QualifierMapping, 0)
84+
if selection.QualifierSelector.isCompound() {
85+
parent, children = GetQualifierMappingsForCompoundQualifier(selection, resourceKeyMap, userId)
86+
parentMappingsMap[parent.CompositeKey] = parent
87+
} else {
88+
intValue, stringValue := GetValuesFromSelectionIdentifier(selection.QualifierSelector, selection.SelectionIdentifier)
89+
parent = selection.toResourceMapping(selection.QualifierSelector, resourceKeyMap, intValue, stringValue, "", userId)
90+
}
91+
mappingsToSelection[parent] = selection
92+
parentMappings = append(parentMappings, parent)
93+
childrenMappings = append(childrenMappings, children...)
94+
}
95+
96+
if len(parentMappings) > 0 {
97+
_, err := impl.qualifierMappingRepository.CreateQualifierMappings(parentMappings, tx)
98+
if err != nil {
99+
impl.logger.Errorw("error in getting parent mappings", "mappings", parentMappings, "err", err)
100+
return nil, err
101+
}
102+
}
103+
104+
for _, mapping := range parentMappings {
105+
if selection, ok := mappingsToSelection[mapping]; ok {
106+
selection.Id = mapping.Id
107+
}
108+
}
109+
110+
for _, childrenMapping := range childrenMappings {
111+
if mapping, ok := parentMappingsMap[childrenMapping.CompositeKey]; ok {
112+
childrenMapping.ParentIdentifier = mapping.Id
113+
}
114+
}
115+
116+
if len(childrenMappings) > 0 {
117+
_, err := impl.qualifierMappingRepository.CreateQualifierMappings(childrenMappings, tx)
118+
if err != nil {
119+
impl.logger.Errorw("error in getting mappings", "err", err, "mappings", childrenMappings)
120+
return nil, err
121+
}
122+
}
123+
124+
return maps.Values(mappingsToSelection), nil
125+
}
126+
127+
func (impl QualifierMappingServiceImpl) CreateMappings(tx *pg.Tx, userId int32, resourceType ResourceType, resourceIds []int, qualifierSelector QualifierSelector, selectionIdentifiers []*SelectionIdentifier) error {
128+
mappings := make([]*ResourceMappingSelection, 0)
129+
for _, id := range resourceIds {
130+
for _, selectionIdentifier := range selectionIdentifiers {
131+
mapping := &ResourceMappingSelection{
132+
ResourceType: resourceType,
133+
ResourceId: id,
134+
QualifierSelector: qualifierSelector,
135+
SelectionIdentifier: selectionIdentifier,
136+
}
137+
mappings = append(mappings, mapping)
138+
}
139+
}
140+
_, err := impl.CreateMappingsForSelections(tx, userId, mappings)
141+
return err
142+
}
143+
144+
func (impl *QualifierMappingServiceImpl) filterAndGroupMappings(mappings []*QualifierMapping, selector QualifierSelector, composites mapset.Set) [][]*QualifierMapping {
145+
146+
numQualifiers := GetNumOfChildQualifiers(selector.toQualifier())
147+
parentIdToChildMappings := make(map[int][]*QualifierMapping)
148+
parentIdToMapping := make(map[int]*QualifierMapping, 0)
149+
parentMappingIds := make([]int, 0)
150+
for _, mapping := range mappings {
151+
// is not parent so append it to the list in the map with key as its parent ID
152+
if mapping.ParentIdentifier > 0 {
153+
parentIdToChildMappings[mapping.ParentIdentifier] = append(parentIdToChildMappings[mapping.ParentIdentifier], mapping)
154+
} else {
155+
// is parent so collect IDs and put it in a map for easy retrieval
156+
parentMappingIds = append(parentMappingIds, mapping.Id)
157+
parentIdToMapping[mapping.Id] = mapping
158+
}
159+
}
160+
161+
for parentMappingId, _ := range parentIdToChildMappings {
162+
// this deletes the keys in the map where the key does not exist in the collected IDs for parent
163+
if !slices.Contains(parentMappingIds, parentMappingId) {
164+
delete(parentIdToChildMappings, parentMappingId)
165+
}
166+
}
167+
168+
groupedMappings := make([][]*QualifierMapping, 0)
169+
for parentId, childMappings := range parentIdToChildMappings {
170+
if len(childMappings) == numQualifiers {
171+
selectedParentMapping := parentIdToMapping[parentId]
172+
composite := getCompositeString(selectedParentMapping.IdentifierValueInt, childMappings[0].IdentifierValueInt)
173+
if composites.Cardinality() > 0 && !composites.Contains(composite) {
174+
break
175+
}
176+
mappingsGroup := []*QualifierMapping{selectedParentMapping}
177+
mappingsGroup = append(mappingsGroup, childMappings...)
178+
groupedMappings = append(groupedMappings, mappingsGroup)
179+
}
180+
}
181+
return groupedMappings
182+
}
183+
184+
func (impl QualifierMappingServiceImpl) getAppEnvIdentifierFromGroup(group []*QualifierMapping) *SelectionIdentifier {
185+
resourceKeyToName := impl.devtronResourceSearchableKeyService.GetAllSearchableKeyIdNameMap()
186+
var appId, envId int
187+
var appName, envName string
188+
for _, mapping := range group {
189+
field := resourceKeyToName[mapping.IdentifierKey]
190+
switch field {
191+
case bean.DEVTRON_RESOURCE_SEARCHABLE_KEY_APP_ID:
192+
appId, appName = mapping.GetIdValueAndName()
193+
case bean.DEVTRON_RESOURCE_SEARCHABLE_KEY_ENV_ID:
194+
envId, envName = mapping.GetIdValueAndName()
195+
}
196+
}
197+
return getSelectionIdentifierForAppEnv(appId, envId, getIdentifierNamesForAppEnv(envName, appName))
198+
}
199+
200+
func (impl QualifierMappingServiceImpl) getSelectionIdentifierForAppEnvSelector(mappingGroups [][]*QualifierMapping) map[int][]*SelectionIdentifier {
201+
202+
resourceIdToIdentifier := make(map[int][]*SelectionIdentifier)
203+
for _, group := range mappingGroups {
204+
identifier := impl.getAppEnvIdentifierFromGroup(group)
205+
resourceId := group[0].ResourceId
206+
207+
if _, ok := resourceIdToIdentifier[resourceId]; ok {
208+
resourceIdToIdentifier[resourceId] = append(resourceIdToIdentifier[resourceId], identifier)
209+
} else {
210+
resourceIdToIdentifier[resourceId] = []*SelectionIdentifier{identifier}
211+
}
212+
}
213+
return resourceIdToIdentifier
214+
}
215+
216+
func (impl QualifierMappingServiceImpl) DeleteResourceMappingsForScopes(tx *pg.Tx, userId int32, resourceType ResourceType, qualifierSelector QualifierSelector, scopes []*SelectionIdentifier) error {
217+
if qualifierSelector != ApplicationEnvironmentSelector {
218+
return fmt.Errorf("selector currently not implemented")
219+
}
220+
221+
keyMap := impl.devtronResourceSearchableKeyService.GetAllSearchableKeyNameIdMap()
222+
223+
valuesMap := make(map[Qualifier][][]int)
224+
appIds := make([]int, 0)
225+
envIds := make([]int, 0)
226+
for _, scope := range scopes {
227+
appIds = append(appIds, scope.AppId)
228+
envIds = append(envIds, scope.EnvId)
229+
}
230+
valuesMap[qualifierSelector.toQualifier()] = [][]int{appIds, envIds}
231+
mappings, err := impl.qualifierMappingRepository.GetQualifierMappingsForListOfQualifierValues(resourceType, valuesMap, keyMap, []int{})
232+
if err != nil {
233+
return errors.Wrap(err, fmt.Sprintf("error fetching resource mappings %v %v", resourceType, valuesMap))
234+
}
235+
mappingIds := make([]int, 0, len(mappings))
236+
for _, mapping := range mappings {
237+
mappingIds = append(mappingIds, mapping.Id)
238+
}
239+
return impl.DeleteAllByIds(mappingIds, userId, tx)
240+
241+
}
242+
243+
func (impl QualifierMappingServiceImpl) GetResourceMappingsForSelections(resourceType ResourceType, qualifierSelector QualifierSelector, selectionIdentifiers []*SelectionIdentifier) ([]ResourceQualifierMappings, error) {
244+
if qualifierSelector != ApplicationEnvironmentSelector {
245+
return nil, fmt.Errorf("selector currently not implemented")
246+
}
247+
248+
keyMap := impl.devtronResourceSearchableKeyService.GetAllSearchableKeyNameIdMap()
249+
250+
valuesMap := make(map[Qualifier][][]int)
251+
appIds := make([]int, 0)
252+
envIds := make([]int, 0)
253+
for _, selectionIdentifier := range selectionIdentifiers {
254+
appIds = append(appIds, selectionIdentifier.AppId)
255+
envIds = append(envIds, selectionIdentifier.EnvId)
256+
}
257+
valuesMap[qualifierSelector.toQualifier()] = [][]int{appIds, envIds}
258+
mappings, err := impl.qualifierMappingRepository.GetQualifierMappingsForListOfQualifierValues(resourceType, valuesMap, keyMap, []int{})
259+
if err != nil {
260+
return nil, errors.Wrap(err, fmt.Sprintf("error fetching resource mappings %v %v", resourceType, valuesMap))
261+
}
262+
263+
return impl.processMappings(resourceType, mappings, qualifierSelector, getCompositeStringsAppEnvSelection(selectionIdentifiers))
264+
}
265+
func (impl QualifierMappingServiceImpl) GetResourceMappingsForResources(resourceType ResourceType, resourceIds []int, qualifierSelector QualifierSelector) ([]ResourceQualifierMappings, error) {
266+
mappings, err := impl.qualifierMappingRepository.GetMappingsByResourceTypeAndIdsAndQualifierId(resourceType, resourceIds, int(qualifierSelector.toQualifier()))
267+
if err != nil {
268+
return nil, err
269+
}
270+
271+
return impl.processMappings(resourceType, mappings, qualifierSelector, mapset.NewSet())
272+
}
273+
274+
func (impl QualifierMappingServiceImpl) processMappings(resourceType ResourceType, mappings []*QualifierMapping, qualifierSelector QualifierSelector, composites mapset.Set) ([]ResourceQualifierMappings, error) {
275+
groups := impl.filterAndGroupMappings(mappings, qualifierSelector, composites)
276+
if qualifierSelector != ApplicationEnvironmentSelector {
277+
return nil, fmt.Errorf("selector currently not implemented")
278+
}
279+
resourceIdToIdentifiers := impl.getSelectionIdentifierForAppEnvSelector(groups)
280+
281+
qualifierMappings := make([]ResourceQualifierMappings, 0)
282+
283+
for resourceId, identifier := range resourceIdToIdentifiers {
284+
for _, identifier := range identifier {
285+
qualifierMappings = append(qualifierMappings, ResourceQualifierMappings{
286+
ResourceId: resourceId,
287+
ResourceType: resourceType,
288+
SelectionIdentifier: identifier,
289+
})
290+
}
291+
}
292+
return qualifierMappings, nil
293+
}

pkg/resourceQualifiers/ResourceQualifiersMappingDto.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ const (
1010
ImageDigest = 2
1111
ImageDigestResourceId = -1 // for ImageDigest resource id will is constant unlike filter and variables
1212
InfraProfile = 3
13+
ImagePromotionPolicy ResourceType = 4
14+
DeploymentWindow ResourceType = 5
1315
)
1416

17+
type ResourceQualifierMappings struct {
18+
ResourceId int
19+
ResourceType ResourceType
20+
SelectionIdentifier *SelectionIdentifier
21+
}
22+
1523
type QualifierMapping struct {
1624
tableName struct{} `sql:"resource_qualifier_mapping" pg:",discard_unknown_columns"`
1725
Id int `sql:"id,pk"`
@@ -28,3 +36,28 @@ type QualifierMapping struct {
2836
// VariableData *VariableData
2937
sql.AuditLog
3038
}
39+
40+
type ResourceMappingSelection struct {
41+
ResourceType ResourceType
42+
ResourceId int
43+
QualifierSelector QualifierSelector
44+
SelectionIdentifier *SelectionIdentifier
45+
Id int
46+
}
47+
48+
type SelectionIdentifier struct {
49+
AppId int `json:"appId"`
50+
EnvId int `json:"envId"`
51+
ClusterId int `json:"clusterId"`
52+
SelectionIdentifierName *SelectionIdentifierName `json:"-"`
53+
}
54+
55+
type SelectionIdentifierName struct {
56+
AppName string
57+
EnvironmentName string
58+
ClusterName string
59+
}
60+
61+
func (mapping *QualifierMapping) GetIdValueAndName() (int, string) {
62+
return mapping.IdentifierValueInt, mapping.IdentifierValueString
63+
}

0 commit comments

Comments
 (0)