mirror of https://github.com/helm/helm.git
feat(pkg/kube): add openapi validation for k8s objects
Add back OpenAPI validation for kubernetes objects. Fixes: #6382 Signed-off-by: Adam Reese <adam@reese.io>
This commit is contained in:
parent
5e2071caef
commit
572b92dc8a
|
@ -44,7 +44,7 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent,
|
|||
return err
|
||||
}
|
||||
|
||||
resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest))
|
||||
resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to build kubernetes object for %s hook %s", hook, h.Path)
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ func (x hookByWeight) Less(i, j int) bool {
|
|||
// deleteHookByPolicy deletes a hook if the hook policy instructs it to
|
||||
func (cfg *Configuration) deleteHookByPolicy(h *release.Hook, policy release.HookDeletePolicy) error {
|
||||
if hookHasDeletePolicy(h, policy) {
|
||||
resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest))
|
||||
resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to build kubernetes object for deleting hook %s", h.Path)
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ func (i *Install) installCRDs(crds []*chart.File) error {
|
|||
totalItems := []*resource.Info{}
|
||||
for _, obj := range crds {
|
||||
// Read in the resources
|
||||
res, err := i.cfg.KubeClient.Build(bytes.NewBuffer(obj.Data))
|
||||
res, err := i.cfg.KubeClient.Build(bytes.NewBuffer(obj.Data), false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to install CRD %s", obj.Name)
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
|
|||
// Mark this release as in-progress
|
||||
rel.SetStatus(release.StatusPendingInstall, "Initial install underway")
|
||||
|
||||
resources, err := i.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest))
|
||||
resources, err := i.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest), false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to build kubernetes objects from release manifest")
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func (r *ReleaseTesting) Run(name string) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
hooks, err := r.cfg.KubeClient.Build(bytes.NewBufferString(manifestsToDelete.String()))
|
||||
hooks, err := r.cfg.KubeClient.Build(bytes.NewBufferString(manifestsToDelete.String()), false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to build test hooks: %v", err)
|
||||
}
|
||||
|
|
|
@ -140,11 +140,11 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
|
|||
return targetRelease, nil
|
||||
}
|
||||
|
||||
current, err := r.cfg.KubeClient.Build(bytes.NewBufferString(currentRelease.Manifest))
|
||||
current, err := r.cfg.KubeClient.Build(bytes.NewBufferString(currentRelease.Manifest), false)
|
||||
if err != nil {
|
||||
return targetRelease, errors.Wrap(err, "unable to build kubernetes objects from current release manifest")
|
||||
}
|
||||
target, err := r.cfg.KubeClient.Build(bytes.NewBufferString(targetRelease.Manifest))
|
||||
target, err := r.cfg.KubeClient.Build(bytes.NewBufferString(targetRelease.Manifest), false)
|
||||
if err != nil {
|
||||
return targetRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest")
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ func (u *Uninstall) deleteRelease(rel *release.Release) (string, []error) {
|
|||
for _, file := range filesToDelete {
|
||||
builder.WriteString("\n---\n" + file.Content)
|
||||
}
|
||||
resources, err := u.cfg.KubeClient.Build(strings.NewReader(builder.String()))
|
||||
resources, err := u.cfg.KubeClient.Build(strings.NewReader(builder.String()), false)
|
||||
if err != nil {
|
||||
return "", []error{errors.Wrap(err, "unable to build kubernetes objects for delete")}
|
||||
}
|
||||
|
|
|
@ -189,11 +189,11 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin
|
|||
}
|
||||
|
||||
func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Release) (*release.Release, error) {
|
||||
current, err := u.cfg.KubeClient.Build(bytes.NewBufferString(originalRelease.Manifest))
|
||||
current, err := u.cfg.KubeClient.Build(bytes.NewBufferString(originalRelease.Manifest), false)
|
||||
if err != nil {
|
||||
return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from current release manifest")
|
||||
}
|
||||
target, err := u.cfg.KubeClient.Build(bytes.NewBufferString(upgradedRelease.Manifest))
|
||||
target, err := u.cfg.KubeClient.Build(bytes.NewBufferString(upgradedRelease.Manifest), true)
|
||||
if err != nil {
|
||||
return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest")
|
||||
}
|
||||
|
@ -372,7 +372,7 @@ func (u *Upgrade) reuseValues(chart *chart.Chart, current *release.Release, newV
|
|||
}
|
||||
|
||||
func validateManifest(c kube.Interface, manifest []byte) error {
|
||||
_, err := c.Build(bytes.NewReader(manifest))
|
||||
_, err := c.Build(bytes.NewReader(manifest), true)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -122,9 +122,14 @@ func (c *Client) newBuilder() *resource.Builder {
|
|||
}
|
||||
|
||||
// Build validates for Kubernetes objects and returns unstructured infos.
|
||||
func (c *Client) Build(reader io.Reader) (ResourceList, error) {
|
||||
func (c *Client) Build(reader io.Reader, validate bool) (ResourceList, error) {
|
||||
schema, err := c.Factory.Validator(validate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := c.newBuilder().
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
Stream(reader, "").
|
||||
Do().Infos()
|
||||
return result, scrubValidationError(err)
|
||||
|
|
|
@ -153,11 +153,11 @@ func TestUpdate(t *testing.T) {
|
|||
}
|
||||
}),
|
||||
}
|
||||
first, err := c.Build(objBody(&listA))
|
||||
first, err := c.Build(objBody(&listA), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
second, err := c.Build(objBody(&listB))
|
||||
second, err := c.Build(objBody(&listB), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ func TestBuild(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Test for an invalid manifest
|
||||
infos, err := c.Build(tt.reader)
|
||||
infos, err := c.Build(tt.reader, false)
|
||||
if err != nil && !tt.err {
|
||||
t.Errorf("Got error message when no error should have occurred: %v", err)
|
||||
} else if err != nil && strings.Contains(err.Error(), "--validate=false") {
|
||||
|
@ -266,7 +266,7 @@ func TestPerform(t *testing.T) {
|
|||
}
|
||||
|
||||
c := newTestClient()
|
||||
infos, err := c.Build(tt.reader)
|
||||
infos, err := c.Build(tt.reader, false)
|
||||
if err != nil && err.Error() != tt.errMessage {
|
||||
t.Errorf("Error while building manifests: %v", err)
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ func TestPerform(t *testing.T) {
|
|||
func TestReal(t *testing.T) {
|
||||
t.Skip("This is a live test, comment this line to run")
|
||||
c := New(nil)
|
||||
resources, err := c.Build(strings.NewReader(guestbookManifest))
|
||||
resources, err := c.Build(strings.NewReader(guestbookManifest), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ func TestReal(t *testing.T) {
|
|||
|
||||
testSvcEndpointManifest := testServiceManifest + "\n---\n" + testEndpointManifest
|
||||
c = New(nil)
|
||||
resources, err = c.Build(strings.NewReader(testSvcEndpointManifest))
|
||||
resources, err = c.Build(strings.NewReader(testSvcEndpointManifest), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ func TestReal(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resources, err = c.Build(strings.NewReader(testEndpointManifest))
|
||||
resources, err = c.Build(strings.NewReader(testEndpointManifest), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ func TestReal(t *testing.T) {
|
|||
t.Fatal(errs)
|
||||
}
|
||||
|
||||
resources, err = c.Build(strings.NewReader(testSvcEndpointManifest))
|
||||
resources, err = c.Build(strings.NewReader(testSvcEndpointManifest), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -83,11 +83,11 @@ func (f *FailingKubeClient) Update(r, modified kube.ResourceList, ignoreMe bool)
|
|||
}
|
||||
|
||||
// Build returns the configured error if set or prints
|
||||
func (f *FailingKubeClient) Build(r io.Reader) (kube.ResourceList, error) {
|
||||
func (f *FailingKubeClient) Build(r io.Reader, _ bool) (kube.ResourceList, error) {
|
||||
if f.BuildError != nil {
|
||||
return []*resource.Info{}, f.BuildError
|
||||
}
|
||||
return f.PrintingKubeClient.Build(r)
|
||||
return f.PrintingKubeClient.Build(r, false)
|
||||
}
|
||||
|
||||
// WaitAndGetCompletedPodPhase returns the configured error if set or prints
|
||||
|
|
|
@ -82,7 +82,7 @@ func (p *PrintingKubeClient) Update(_, modified kube.ResourceList, _ bool) (*kub
|
|||
}
|
||||
|
||||
// Build implements KubeClient Build.
|
||||
func (p *PrintingKubeClient) Build(_ io.Reader) (kube.ResourceList, error) {
|
||||
func (p *PrintingKubeClient) Build(_ io.Reader, _ bool) (kube.ResourceList, error) {
|
||||
return []*resource.Info{}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,9 @@ type Interface interface {
|
|||
//
|
||||
// reader must contain a YAML stream (one or more YAML documents separated
|
||||
// by "\n---\n")
|
||||
Build(reader io.Reader) (ResourceList, error)
|
||||
//
|
||||
// Validates against OpenAPI schema if validate is true.
|
||||
Build(reader io.Reader, validate bool) (ResourceList, error)
|
||||
|
||||
// WaitAndGetCompletedPodPhase waits up to a timeout until a pod enters a completed phase
|
||||
// and returns said phase (PodSucceeded or PodFailed qualify).
|
||||
|
|
Loading…
Reference in New Issue