mirror of https://github.com/kubernetes/kops.git
kube-scheduler: MVP configuration validation
We check that users haven't specified the kubeconfig file path, as this file is created / managed by kOps. We don't try to reuse the upstream configuration validation, as this allows the user to specify a partial configuration, and this means that we don't have to pull in the upstream libraries. We could in future accept the "correct" value or just treat providing a value as a signal that kOps should not manage the file; for now we are starting with the most restrictive configuration, as we can then relax it in future if needed.
This commit is contained in:
parent
c82c30d8aa
commit
e4d8dff835
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package validation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ValidateAdditionalObject(ctx context.Context, fieldPath *field.Path, u *unstructured.Unstructured) field.ErrorList {
|
||||||
|
var errors field.ErrorList
|
||||||
|
|
||||||
|
gvk := u.GroupVersionKind()
|
||||||
|
|
||||||
|
// Note: we use unstructured because:
|
||||||
|
// 1) it means we don't have to depend on types / validation code from multiple projects
|
||||||
|
// 2) we can more easily differentiate whether a field is set.
|
||||||
|
// 3) we can support partial configuration specification - just the fields we care about.
|
||||||
|
//
|
||||||
|
// It would be nice to be able to consume validation code e.g. via a container,
|
||||||
|
// so we could be more extensible.
|
||||||
|
errors = append(errors, validateAdditionalObjectKubescheduler(ctx, fieldPath, gvk, u)...)
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateAdditionalObjectKubescheduler(ctx context.Context, fieldPath *field.Path, gvk schema.GroupVersionKind, u *unstructured.Unstructured) field.ErrorList {
|
||||||
|
var errors field.ErrorList
|
||||||
|
|
||||||
|
if gvk.Kind == "KubeSchedulerConfiguration" && gvk.Group == "kubescheduler.config.k8s.io" {
|
||||||
|
kubeconfig, found, err := unstructured.NestedString(u.Object, "clientConnection", "kubeconfig")
|
||||||
|
if err != nil {
|
||||||
|
errors = append(errors, field.Invalid(fieldPath.Child("clientConnection", "kubeconfig"), u, fmt.Sprintf("error reading field: %v", err)))
|
||||||
|
}
|
||||||
|
if found && kubeconfig != "" {
|
||||||
|
errors = append(errors, field.Invalid(fieldPath.Child("clientConnection", "kubeconfig"), kubeconfig, "value is controlled by kOps and should not be set"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
|
@ -18,12 +18,15 @@ package vfsclientset
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
"k8s.io/kops/pkg/acls"
|
"k8s.io/kops/pkg/acls"
|
||||||
"k8s.io/kops/pkg/apis/kops"
|
"k8s.io/kops/pkg/apis/kops"
|
||||||
|
"k8s.io/kops/pkg/apis/kops/validation"
|
||||||
"k8s.io/kops/pkg/client/simple"
|
"k8s.io/kops/pkg/client/simple"
|
||||||
"k8s.io/kops/pkg/kubemanifest"
|
"k8s.io/kops/pkg/kubemanifest"
|
||||||
"k8s.io/kops/util/pkg/vfs"
|
"k8s.io/kops/util/pkg/vfs"
|
||||||
|
@ -56,6 +59,23 @@ func newAddonsVFS(c *VFSClientset, cluster *kops.Cluster) *vfsAddonsClient {
|
||||||
|
|
||||||
// TODO: Offer partial replacement?
|
// TODO: Offer partial replacement?
|
||||||
func (c *vfsAddonsClient) Replace(addons kubemanifest.ObjectList) error {
|
func (c *vfsAddonsClient) Replace(addons kubemanifest.ObjectList) error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
for _, addon := range addons {
|
||||||
|
fieldPath := field.NewPath("addons")
|
||||||
|
if kind := addon.Kind(); kind != "" {
|
||||||
|
fieldPath = fieldPath.Child("kind=" + kind)
|
||||||
|
}
|
||||||
|
if name := addon.GetName(); name != "" {
|
||||||
|
fieldPath = fieldPath.Child("name=" + name)
|
||||||
|
}
|
||||||
|
|
||||||
|
errors := validation.ValidateAdditionalObject(ctx, fieldPath, addon.ToUnstructured())
|
||||||
|
if len(errors) != 0 {
|
||||||
|
return errors.ToAggregate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b, err := addons.ToYAML()
|
b, err := addons.ToYAML()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Reference in New Issue