Skip to content

Commit

Permalink
Validation for defaultConfigOverwrite for NovaCompute
Browse files Browse the repository at this point in the history
  • Loading branch information
gibizer authored and openshift-merge-bot[bot] committed Feb 12, 2024
1 parent a92859a commit 5b06cbf
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 4 deletions.
20 changes: 16 additions & 4 deletions api/v1beta1/common_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,28 @@ package v1beta1

import (
"fmt"
"path/filepath"
"strings"

"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/utils/strings/slices"
)

// ValidateDefaultConfigOverwrite checks if the file names in the overwrite map
// are allowed and return an error for each unsupported files. The allowedKeys
// list supports direct string match and globs like provider*.yaml
func ValidateDefaultConfigOverwrite(
basePath *field.Path,
defaultConfigOverwrite map[string]string,
allowedKeys []string,
) field.ErrorList {
var errors field.ErrorList
for k := range defaultConfigOverwrite {
if !slices.Contains(allowedKeys, k) {
for requested := range defaultConfigOverwrite {
if !matchAny(requested, allowedKeys) {
errors = append(
errors,
field.Invalid(
basePath,
k,
requested,
fmt.Sprintf(
"Only the following keys are valid: %s",
strings.Join(allowedKeys, ", ")),
Expand All @@ -46,3 +49,12 @@ func ValidateDefaultConfigOverwrite(
}
return errors
}

func matchAny(requested string, allowed []string) bool {
for _, a := range allowed {
if matched, _ := filepath.Match(a, requested); matched {
return true
}
}
return false
}
4 changes: 4 additions & 0 deletions api/v1beta1/nova_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ func (r *NovaSpec) ValidateCellTemplates(basePath *field.Path) field.ErrorList {
errors, ValidateNovaComputeName(
cellPath.Child("novaComputeTemplates").Key(computeName), computeName)...,
)
errors = append(
errors, computeTemplate.ValidateDefaultConfigOverwrite(
cellPath.Child("novaComputeTemplates").Key(computeName))...,
)
}
}

Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/novacell_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ func (r *NovaCellSpec) validate(basePath *field.Path) field.ErrorList {
errors, ValidateNovaComputeName(
basePath.Child("novaComputeTemplates").Key(computeName), computeName)...,
)
errors = append(
errors, computeTemplate.ValidateDefaultConfigOverwrite(
basePath.Child("novaComputeTemplates").Key(computeName))...,
)

}

errors = append(
Expand Down
17 changes: 17 additions & 0 deletions api/v1beta1/novacompute_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ func (r *NovaComputeSpec) validate(basePath *field.Path) field.ErrorList {
basePath.Child("replicas"), *r.NovaServiceBase.Replicas, "should be max 1 for ironic.IronicDriver"),
)
}
errors = append(
errors,
ValidateComputeDefaultConfigOverwrite(
basePath.Child("defaultConfigOverwrite"), r.DefaultConfigOverwrite)...)

return errors
}
Expand All @@ -159,6 +163,19 @@ func (r *NovaComputeTemplate) ValidateIronicDriverReplicas(basePath *field.Path)
return errors
}

func (r *NovaComputeTemplate) ValidateDefaultConfigOverwrite(basePath *field.Path) field.ErrorList {
return ValidateComputeDefaultConfigOverwrite(
basePath.Child("defaultConfigOverwrite"), r.DefaultConfigOverwrite)
}

func ValidateComputeDefaultConfigOverwrite(
basePath *field.Path,
defaultConfigOverwrite map[string]string,
) field.ErrorList {
return ValidateDefaultConfigOverwrite(
basePath, defaultConfigOverwrite, []string{"provider*.yaml"})
}

// ValidateNovaComputeName validates the compute name. It is expected to be called
// from various webhooks.
func ValidateNovaComputeName(path *field.Path, computeName string) field.ErrorList {
Expand Down
108 changes: 108 additions & 0 deletions test/functional/validation_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -819,4 +819,112 @@ var _ = Describe("Nova validation", func() {
"keys are valid: api-paste.ini"),
)
})
It("rejects NovaCompute with wrong defaultConfigOverwrite", func() {
spec := GetDefaultNovaComputeSpec(cell1)
spec["defaultConfigOverwrite"] = map[string]interface{}{
"policy.yaml": "custom policy not supported",
"provider123.yaml": "provider*.yaml is supported",
}
raw := map[string]interface{}{
"apiVersion": "nova.openstack.org/v1beta1",
"kind": "NovaCompute",
"metadata": map[string]interface{}{
"name": cell1.NovaComputeName.Name,
"namespace": novaNames.Namespace,
},
"spec": spec,
}

unstructuredObj := &unstructured.Unstructured{Object: raw}
_, err := controllerutil.CreateOrPatch(
ctx, k8sClient, unstructuredObj, func() error { return nil })

Expect(err).Should(HaveOccurred())
var statusError *k8s_errors.StatusError
Expect(errors.As(err, &statusError)).To(BeTrue())
Expect(statusError.ErrStatus.Details.Kind).To(Equal("NovaCompute"))
Expect(statusError.ErrStatus.Message).To(
ContainSubstring(
"invalid: spec.defaultConfigOverwrite: " +
"Invalid value: \"policy.yaml\": " +
"Only the following keys are valid: provider*.yaml",
),
)
})
It("rejects NovaCell with wrong defaultConfigOverwrite in computeTemplates", func() {
spec := GetDefaultNovaCellSpec(cell1)
novaCompute := GetDefaultNovaComputeTemplate()
novaCompute["defaultConfigOverwrite"] = map[string]interface{}{
"policy.yaml": "custom policy not supported",
"provider123.yaml": "provider*.yaml is supported",
}
spec["novaComputeTemplates"] = map[string]interface{}{
ironicComputeName: novaCompute,
}

raw := map[string]interface{}{
"apiVersion": "nova.openstack.org/v1beta1",
"kind": "NovaCell",
"metadata": map[string]interface{}{
"name": cell1.CellCRName.Name,
"namespace": novaNames.Namespace,
},
"spec": spec,
}

unstructuredObj := &unstructured.Unstructured{Object: raw}
_, err := controllerutil.CreateOrPatch(
ctx, k8sClient, unstructuredObj, func() error { return nil })

Expect(err).Should(HaveOccurred())
var statusError *k8s_errors.StatusError
Expect(errors.As(err, &statusError)).To(BeTrue())
Expect(statusError.ErrStatus.Details.Kind).To(Equal("NovaCell"))
Expect(statusError.ErrStatus.Message).To(
ContainSubstring(
"invalid: spec.novaComputeTemplates[ironic-compute].defaultConfigOverwrite: " +
"Invalid value: \"policy.yaml\": " +
"Only the following keys are valid: provider*.yaml",
),
)
})
It("rejects Nova with wrong defaultConfigOverwrite in computeTemplates", func() {
spec := GetDefaultNovaSpec()
cell0 := GetDefaultNovaCellTemplate()
cell1 := GetDefaultNovaCellTemplate()
novaCompute := GetDefaultNovaComputeTemplate()
novaCompute["defaultConfigOverwrite"] = map[string]interface{}{
"policy.yaml": "custom policy not supported",
"provider123.yaml": "provider*.yaml is supported",
}
cell1["novaComputeTemplates"] = map[string]interface{}{
ironicComputeName: novaCompute,
}
spec["cellTemplates"] = map[string]interface{}{"cell0": cell0, "cell1": cell1}
raw := map[string]interface{}{
"apiVersion": "nova.openstack.org/v1beta1",
"kind": "Nova",
"metadata": map[string]interface{}{
"name": novaNames.NovaName.Name,
"namespace": novaNames.Namespace,
},
"spec": spec,
}
unstructuredObj := &unstructured.Unstructured{Object: raw}
_, err := controllerutil.CreateOrPatch(
ctx, k8sClient, unstructuredObj, func() error { return nil })

Expect(err).Should(HaveOccurred())
var statusError *k8s_errors.StatusError
Expect(errors.As(err, &statusError)).To(BeTrue())
Expect(statusError.ErrStatus.Details.Kind).To(Equal("Nova"))
Expect(statusError.ErrStatus.Message).To(
ContainSubstring(
"invalid: spec.cellTemplates[cell1]." +
"novaComputeTemplates[ironic-compute].defaultConfigOverwrite: " +
"Invalid value: \"policy.yaml\": " +
"Only the following keys are valid: provider*.yaml",
),
)
})
})

0 comments on commit 5b06cbf

Please sign in to comment.