Skip to content

Commit 44e86f4

Browse files
committed
Move duplicate volume merging functionality to separate file
Move logic for merging into a separate file and add a more abstract interface to allow adding additional merging later if necessary. Signed-off-by: Angel Misevski <[email protected]>
1 parent 63d80ac commit 44e86f4

File tree

2 files changed

+111
-84
lines changed

2 files changed

+111
-84
lines changed

pkg/library/flatten/flatten.go

Lines changed: 5 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ import (
2222
dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
2323
"github.com/devfile/api/v2/pkg/utils/overriding"
2424
"github.com/devfile/api/v2/pkg/validation/variables"
25+
"k8s.io/apimachinery/pkg/api/errors"
26+
"k8s.io/apimachinery/pkg/types"
27+
"sigs.k8s.io/controller-runtime/pkg/client"
28+
2529
"github.com/devfile/devworkspace-operator/pkg/library/annotate"
2630
registry "github.com/devfile/devworkspace-operator/pkg/library/flatten/internal_registry"
2731
"github.com/devfile/devworkspace-operator/pkg/library/flatten/network"
2832
"github.com/devfile/devworkspace-operator/pkg/library/flatten/web_terminal"
29-
"k8s.io/apimachinery/pkg/api/errors"
30-
"k8s.io/apimachinery/pkg/api/resource"
31-
"k8s.io/apimachinery/pkg/types"
32-
"sigs.k8s.io/controller-runtime/pkg/client"
3333
)
3434

3535
const (
@@ -123,7 +123,7 @@ func recursiveResolve(workspace *dw.DevWorkspaceTemplateSpec, tooling ResolverTo
123123
}
124124
}
125125

126-
if err := mergeVolumeComponents(resolvedContent, resolvedParent, pluginSpecContents...); err != nil {
126+
if err := mergeDevWorkspaceElements(resolvedContent, resolvedParent, pluginSpecContents...); err != nil {
127127
return nil, fmt.Errorf("failed to merge DevWorkspace volumes: %w", err)
128128
}
129129
resolvedContent, err := overriding.MergeDevWorkspaceTemplateSpec(resolvedContent, resolvedParent, pluginSpecContents...)
@@ -300,85 +300,6 @@ func resolveElementByURI(
300300
return dwt, nil
301301
}
302302

303-
// mergeVolumeComponents merges volume components sharing the same name according to the following rules
304-
// * If a volume is defined in main and duplicated in parent/plugins, the copy in parent/plugins is removed
305-
// * If a volume is defined in parent and duplicated in plugins, the copy in plugins is removed
306-
// * If a volume is defined in multiple plugins, all but the first definition is removed
307-
// * If a volume is defined as persistent, all duplicates will be persistent
308-
// * If duplicate volumes set a size, the larger size will be used.
309-
// Following the invocation of this function, there are no duplicate volumes defined across the main devworkspace, its
310-
// parent, and its plugins.
311-
func mergeVolumeComponents(main, parent *dw.DevWorkspaceTemplateSpecContent, plugins ...*dw.DevWorkspaceTemplateSpecContent) error {
312-
volumeComponents := map[string]dw.Component{}
313-
for _, component := range main.Components {
314-
if component.Volume == nil {
315-
continue
316-
}
317-
if _, exists := volumeComponents[component.Name]; exists {
318-
return fmt.Errorf("duplicate volume found in devfile: %s", component.Name)
319-
}
320-
volumeComponents[component.Name] = component
321-
}
322-
323-
mergeVolumeComponents := func(spec *dw.DevWorkspaceTemplateSpecContent) error {
324-
var newComponents []dw.Component
325-
for _, component := range spec.Components {
326-
if component.Volume == nil {
327-
newComponents = append(newComponents, component)
328-
continue
329-
}
330-
if existingVol, exists := volumeComponents[component.Name]; exists {
331-
if err := mergeVolume(existingVol.Volume, component.Volume); err != nil {
332-
return err
333-
}
334-
} else {
335-
newComponents = append(newComponents, component)
336-
volumeComponents[component.Name] = component
337-
}
338-
}
339-
spec.Components = newComponents
340-
return nil
341-
}
342-
if err := mergeVolumeComponents(parent); err != nil {
343-
return err
344-
}
345-
346-
for _, plugin := range plugins {
347-
if err := mergeVolumeComponents(plugin); err != nil {
348-
return err
349-
}
350-
}
351-
352-
return nil
353-
}
354-
355-
func mergeVolume(into, from *dw.VolumeComponent) error {
356-
// If the new volume is persistent, make the original persistent
357-
if !from.Ephemeral {
358-
into.Ephemeral = false
359-
}
360-
intoSize := into.Size
361-
if intoSize == "" {
362-
intoSize = "0"
363-
}
364-
intoSizeQty, err := resource.ParseQuantity(intoSize)
365-
if err != nil {
366-
return err
367-
}
368-
fromSize := from.Size
369-
if fromSize == "" {
370-
fromSize = "0"
371-
}
372-
fromSizeQty, err := resource.ParseQuantity(fromSize)
373-
if err != nil {
374-
return err
375-
}
376-
if fromSizeQty.Cmp(intoSizeQty) > 0 {
377-
into.Size = from.Size
378-
}
379-
return nil
380-
}
381-
382303
// canImportDW returns true if a DevWorkspace in dwNamespace is allowed to reference the provided DevWorkspaceTemplate
383304
// DevWorkspaces can by default only read DevWorkspaceTemplates in their own namespace, unless the DevWorkspaceTemplate
384305
// has the controller.devfile.io/allow-import-from annotation.

pkg/library/flatten/merge.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//
2+
// Copyright (c) 2019-2021 Red Hat, Inc.
3+
// This program and the accompanying materials are made
4+
// available under the terms of the Eclipse Public License 2.0
5+
// which is available at https://www.eclipse.org/legal/epl-2.0/
6+
//
7+
// SPDX-License-Identifier: EPL-2.0
8+
//
9+
// Contributors:
10+
// Red Hat, Inc. - initial API and implementation
11+
//
12+
13+
package flatten
14+
15+
import (
16+
"fmt"
17+
18+
dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
19+
"k8s.io/apimachinery/pkg/api/resource"
20+
)
21+
22+
// mergeDevWorkspaceElements merges elements that are duplicated between the DevWorkspace, its parent, and its plugins
23+
// where appropriate in order to avoid errors when merging elements via the devfile/api methods. Currently, only
24+
// volumes are merged.
25+
func mergeDevWorkspaceElements(main, parent *dw.DevWorkspaceTemplateSpecContent, plugins ...*dw.DevWorkspaceTemplateSpecContent) error {
26+
return mergeVolumeComponents(main, parent, plugins...)
27+
}
28+
29+
// mergeVolumeComponents merges volume components sharing the same name according to the following rules
30+
// * If a volume is defined in main and duplicated in parent/plugins, the copy in parent/plugins is removed
31+
// * If a volume is defined in parent and duplicated in plugins, the copy in plugins is removed
32+
// * If a volume is defined in multiple plugins, all but the first definition is removed
33+
// * If a volume is defined as persistent, all duplicates will be persistent
34+
// * If duplicate volumes set a size, the larger size will be used.
35+
// Following the invocation of this function, there are no duplicate volumes defined across the main devworkspace, its
36+
// parent, and its plugins.
37+
func mergeVolumeComponents(main, parent *dw.DevWorkspaceTemplateSpecContent, plugins ...*dw.DevWorkspaceTemplateSpecContent) error {
38+
volumeComponents := map[string]dw.Component{}
39+
for _, component := range main.Components {
40+
if component.Volume == nil {
41+
continue
42+
}
43+
if _, exists := volumeComponents[component.Name]; exists {
44+
return fmt.Errorf("duplicate volume found in devfile: %s", component.Name)
45+
}
46+
volumeComponents[component.Name] = component
47+
}
48+
49+
mergeVolumeComponents := func(spec *dw.DevWorkspaceTemplateSpecContent) error {
50+
var newComponents []dw.Component
51+
for _, component := range spec.Components {
52+
if component.Volume == nil {
53+
newComponents = append(newComponents, component)
54+
continue
55+
}
56+
if existingVol, exists := volumeComponents[component.Name]; exists {
57+
if err := mergeVolume(existingVol.Volume, component.Volume); err != nil {
58+
return err
59+
}
60+
} else {
61+
newComponents = append(newComponents, component)
62+
volumeComponents[component.Name] = component
63+
}
64+
}
65+
spec.Components = newComponents
66+
return nil
67+
}
68+
if err := mergeVolumeComponents(parent); err != nil {
69+
return err
70+
}
71+
72+
for _, plugin := range plugins {
73+
if err := mergeVolumeComponents(plugin); err != nil {
74+
return err
75+
}
76+
}
77+
78+
return nil
79+
}
80+
81+
func mergeVolume(into, from *dw.VolumeComponent) error {
82+
// If the new volume is persistent, make the original persistent
83+
if !from.Ephemeral {
84+
into.Ephemeral = false
85+
}
86+
intoSize := into.Size
87+
if intoSize == "" {
88+
intoSize = "0"
89+
}
90+
intoSizeQty, err := resource.ParseQuantity(intoSize)
91+
if err != nil {
92+
return err
93+
}
94+
fromSize := from.Size
95+
if fromSize == "" {
96+
fromSize = "0"
97+
}
98+
fromSizeQty, err := resource.ParseQuantity(fromSize)
99+
if err != nil {
100+
return err
101+
}
102+
if fromSizeQty.Cmp(intoSizeQty) > 0 {
103+
into.Size = from.Size
104+
}
105+
return nil
106+
}

0 commit comments

Comments
 (0)