Skip to content

Commit 44bc365

Browse files
committed
Add webhook handler to ensure DevWorkspaces only have a single container contribution merge target
This commit adds a webhook handler to ensure: - A newly created DevWorkspace cannot have more than one container component with the controller.devfile.io/merge-contribution set to true. - An existing DevWorkspace cannot be modified to have more than one container component with the controller.devfile.io/merge-contribution set to true. Signed-off-by: Andrew Obuchowicz <[email protected]>
1 parent ce7b2be commit 44bc365

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// Copyright (c) 2019-2023 Red Hat, Inc.
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
package handler
17+
18+
import (
19+
"fmt"
20+
"strings"
21+
22+
"github.com/devfile/devworkspace-operator/pkg/constants"
23+
24+
dwv2 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
25+
)
26+
27+
// Checks whether the given DevWorkspace Template Spec has multiple container components with the
28+
// controller.devfile.io/merge-contribution attribute set to true.
29+
// If only a single container component has the controller.devfile.io/merge-contribution attribute set to true, nil is returned.
30+
// If multiple container component have the controller.devfile.io/merge-contribution attribute set to true, or an error occurs
31+
// while parsing the attribute, an error is returned.
32+
func checkMultipleContainerContributionTargets(devWorkspaceSpec dwv2.DevWorkspaceTemplateSpec) error {
33+
var componentNames []string
34+
for _, component := range devWorkspaceSpec.Components {
35+
if component.Container == nil {
36+
// Ignore attribute on non-container components as it's not clear what this would mean
37+
continue
38+
}
39+
if component.Attributes.Exists(constants.MergeContributionAttribute) {
40+
var errHolder error
41+
if component.Attributes.GetBoolean(constants.MergeContributionAttribute, &errHolder) {
42+
componentNames = append(componentNames, component.Name)
43+
}
44+
45+
if errHolder != nil {
46+
return fmt.Errorf("failed to parse %s attribute on component %s as true or false", constants.MergeContributionAttribute, component.Name)
47+
}
48+
}
49+
}
50+
51+
if len(componentNames) > 1 {
52+
return fmt.Errorf("only a single component may have the %s attribute set to true. The following %d components have the %s attribute set to true: %s", constants.MergeContributionAttribute, len(componentNames), constants.MergeContributionAttribute, strings.Join(componentNames, ", "))
53+
}
54+
55+
return nil
56+
}

webhook/workspace/handler/workspace.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ func (h *WebhookHandler) MutateWorkspaceV1alpha2OnCreate(ctx context.Context, re
6262
return admission.Denied(err.Error())
6363
}
6464

65+
if err := checkMultipleContainerContributionTargets(wksp.Spec.Template); err != nil {
66+
return admission.Denied(err.Error())
67+
}
68+
6569
if warnings := checkUnsupportedFeatures(wksp.Spec.Template); unsupportedWarningsPresent(warnings) {
6670
return h.returnPatched(req, wksp).WithWarnings(formatUnsupportedFeaturesWarning(warnings))
6771
}
@@ -170,6 +174,10 @@ func (h *WebhookHandler) MutateWorkspaceV1alpha2OnUpdate(ctx context.Context, re
170174
return admission.Denied(err.Error())
171175
}
172176

177+
if err := checkMultipleContainerContributionTargets(newWksp.Spec.Template); err != nil {
178+
return admission.Denied(err.Error())
179+
}
180+
173181
oldCreator, found := oldWksp.Labels[constants.DevWorkspaceCreatorLabel]
174182
if !found {
175183
return admission.Denied(fmt.Sprintf("label '%s' is missing. Please recreate devworkspace to get it initialized", constants.DevWorkspaceCreatorLabel))

0 commit comments

Comments
 (0)