Add validate to Install / Upgrade commands that use kubernets to validate the manifest before reifying

pull/1217/head
Ville Aikas 9 years ago
parent da768867a3
commit a5c8b9c401

@ -188,6 +188,10 @@ message UpdateReleaseRequest {
bool dry_run = 4;
// DisableHooks causes the server to skip running any hooks for the upgrade.
bool disable_hooks = 5;
// Validate requests that Tiller uses kubernetes validation logic on the
// manifest before handing it off for reification
bool validate = 6;
}
// UpdateReleaseResponse is the response to an update request.
@ -235,6 +239,10 @@ message InstallReleaseRequest {
// ReuseName requests that Tiller re-uses a name, instead of erroring out.
bool reuse_name = 7;
// Validate requests that Tiller uses kubernetes validation logic on the
// manifest before handing it off for reification
bool validate = 8;
}
// InstallReleaseResponse is the response from a release installation.

@ -90,6 +90,7 @@ type installCmd struct {
disableHooks bool
replace bool
verify bool
validate bool
keyring string
out io.Writer
client helm.Interface
@ -135,6 +136,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
f.Var(inst.values, "set", "set values on the command line. Separate values with commas: key1=val1,key2=val2")
f.StringVar(&inst.nameTemplate, "name-template", "", "specify template used to name the release")
f.BoolVar(&inst.verify, "verify", false, "verify the package before installing it")
f.BoolVar(&inst.validate, "validate", false, "validate manifest before reifying it")
f.StringVar(&inst.keyring, "keyring", defaultKeyring(), "location of public keys used for verification")
f.StringVar(&inst.version, "version", "", "specify the exact chart version to install. If this is not specified, the latest version is installed.")
return cmd
@ -167,6 +169,7 @@ func (i *installCmd) run() error {
helm.ReleaseName(i.name),
helm.InstallDryRun(i.dryRun),
helm.InstallReuseName(i.replace),
helm.InstallValidate(i.validate),
helm.InstallDisableHooks(i.disableHooks))
if err != nil {
return prettyError(err)

@ -51,6 +51,7 @@ type upgradeCmd struct {
valuesFile string
values *values
verify bool
validate bool
keyring string
install bool
namespace string
@ -89,6 +90,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
f.Var(upgrade.values, "set", "set values on the command line. Separate values with commas: key1=val1,key2=val2")
f.BoolVar(&upgrade.disableHooks, "disable-hooks", false, "disable pre/post upgrade hooks")
f.BoolVar(&upgrade.verify, "verify", false, "verify the provenance of the chart before upgrading")
f.BoolVar(&upgrade.validate, "validate", false, "validate manifest before reifying it")
f.StringVar(&upgrade.keyring, "keyring", defaultKeyring(), "the path to the keyring that contains public singing keys")
f.BoolVarP(&upgrade.install, "install", "i", false, "if a release by this name doesn't already exist, run an install")
f.StringVar(&upgrade.namespace, "namespace", "default", "the namespace to install the release into (only used if --install is set)")
@ -135,7 +137,7 @@ func (u *upgradeCmd) run() error {
return err
}
_, err = u.client.UpdateRelease(u.release, chartPath, helm.UpdateValueOverrides(rawVals), helm.UpgradeDryRun(u.dryRun), helm.UpgradeDisableHooks(u.disableHooks))
_, err = u.client.UpdateRelease(u.release, chartPath, helm.UpdateValueOverrides(rawVals), helm.UpgradeDryRun(u.dryRun), helm.UpgradeDisableHooks(u.disableHooks), helm.UpgradeValidate(u.validate))
if err != nil {
return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err))
}

@ -21,6 +21,7 @@ import (
"errors"
"fmt"
"log"
"os"
"regexp"
"strings"
@ -39,6 +40,9 @@ import (
"k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/timeconv"
"k8s.io/helm/pkg/version"
"k8s.io/kubernetes/pkg/api/unversioned"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
)
var srv *releaseServer
@ -305,6 +309,19 @@ func (s *releaseServer) performUpdate(originalRelease, updatedRelease *release.R
}
}
kubeCli := s.env.KubeClient
original := bytes.NewBufferString(originalRelease.Manifest)
modified := bytes.NewBufferString(updatedRelease.Manifest)
// Validate the manifest
if req.Validate {
log.Printf("Validating manifest: %s\n", modified)
err := validateResources(updatedRelease.Namespace, modified)
if err != nil {
return nil, err
}
}
if err := s.performKubeUpdate(originalRelease, updatedRelease); err != nil {
log.Printf("warning: Release Upgrade %q failed: %s", updatedRelease.Name, err)
originalRelease.Info.Status.Code = release.Status_SUPERSEDED
@ -736,6 +753,16 @@ func (s *releaseServer) performRelease(r *release.Release, req *services.Install
// regular manifests
kubeCli := s.env.KubeClient
b := bytes.NewBufferString(r.Manifest)
// Validate the manifest
if req.Validate {
log.Printf("Validating manifest: %s\n", b)
err := validateResources(r.Namespace, b)
if err != nil {
return res, err
}
}
if err := kubeCli.Create(r.Namespace, b); err != nil {
log.Printf("warning: Release %q failed: %s", r.Name, err)
r.Info.Status.Code = release.Status_FAILED
@ -885,8 +912,40 @@ func (s *releaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
if len(es) > 0 {
errs = fmt.Errorf("deletion error count %d: %s", len(es), strings.Join(es, "; "))
}
return res, nil
}
return res, errs
// validateResources takes a namespace and a manifest (fully expanded set of templates) and
// validates resources.
func validateResources(namespace string, manifest *bytes.Buffer) error {
f := cmdutil.NewFactory(nil)
schema, err := f.Validator(true, os.TempDir())
if err != nil {
return err
}
mapper, typer := f.Object(true)
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
Schema(schema).
NamespaceParam(namespace).DefaultNamespace().
Stream(manifest, "release").
Flatten().
Do()
err = r.Err()
if err != nil {
return err
}
err = r.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
return nil
})
if err != nil {
return err
}
return nil
}
func splitManifests(bigfile string) map[string]string {

@ -17,6 +17,7 @@ limitations under the License.
package main
import (
"bytes"
"errors"
"fmt"
"io"
@ -70,6 +71,23 @@ data:
name: value
`
var invalidResource = `apiVersion: v1
kind: ConfigMap
metadata:
naaame: test-cm
data:
name: value
`
var validResource = `apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
data:
name: value
`
func rsFixture() *releaseServer {
return &releaseServer{
env: mockEnvironment(),
@ -511,6 +529,148 @@ func TestInstallReleaseReuseName(t *testing.T) {
}
}
func TestInstallReleaseWithValidationFailsForInvalid(t *testing.T) {
c := context.Background()
rs := rsFixture()
// TODO: Refactor this into a mock.
req := &services.InstallReleaseRequest{
Namespace: "spaced",
Validate: true,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "invalid", Data: []byte(invalidResource)},
},
},
}
_, err := rs.InstallRelease(c, req)
if err == nil {
t.Fatalf("Install succeeded but was expected to fail")
}
if !strings.Contains(err.Error(), "naaame") {
t.Errorf("didn't fail with expected error")
}
}
func TestInstallReleaseWithValidationWorksForValid(t *testing.T) {
c := context.Background()
rs := rsFixture()
// TODO: Refactor this into a mock.
req := &services.InstallReleaseRequest{
Namespace: "spaced",
Validate: true,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "invalid", Data: []byte(validResource)},
},
},
}
res, err := rs.InstallRelease(c, req)
if err != nil {
t.Fatalf("Failed install: %s %s", err, req.Chart)
}
if res.Release.Name == "" {
t.Errorf("Expected release name.")
}
if res.Release.Namespace != "spaced" {
t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Release.Namespace)
}
rel, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
}
if len(rel.Manifest) == 0 {
t.Errorf("Expected manifest in %v", res)
}
}
func TestUpdateReleaseWithValidationFailsForInvalid(t *testing.T) {
c := context.Background()
rs := rsFixture()
req := &services.InstallReleaseRequest{
Name: "myspecialone",
Namespace: "spaced",
Validate: true,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "invalid", Data: []byte(validResource)},
},
},
}
_, err := rs.InstallRelease(c, req)
if err != nil {
t.Fatalf("Install failed: %v", err)
}
uReq := &services.UpdateReleaseRequest{
Name: "myspecialone",
Validate: true,
DisableHooks: true,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "invalid", Data: []byte(invalidResource)},
},
},
}
_, err = rs.UpdateRelease(c, uReq)
if err == nil {
t.Fatalf("Install succeeded but was expected to fail")
}
if !strings.Contains(err.Error(), "naaame") {
t.Errorf("didn't fail with expected error")
}
}
func TestUpdateReleaseWithValidationWorksForValid(t *testing.T) {
c := context.Background()
rs := rsFixture()
req := &services.InstallReleaseRequest{
Name: "myspecialone",
Namespace: "spaced",
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "invalid", Data: []byte(invalidResource)},
},
},
}
_, err := rs.InstallRelease(c, req)
if err != nil {
t.Fatalf("Install failed: %v", err)
}
uReq := &services.UpdateReleaseRequest{
Name: "myspecialone",
Validate: true,
DisableHooks: true,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "invalid", Data: []byte(validResource)},
},
},
}
_, err = rs.UpdateRelease(c, uReq)
if err != nil {
t.Fatalf("Install failed: %v", err)
}
}
func TestUpdateRelease(t *testing.T) {
c := helm.NewContext()
rs := rsFixture()
@ -1198,6 +1358,11 @@ func TestListReleasesFilter(t *testing.T) {
}
}
func testValidateResources(t *testing.T) {
b := bytes.NewBufferString("")
validateResources("default", b)
}
func mockEnvironment() *environment.Environment {
e := environment.New()
e.Releases = storage.Init(driver.NewMemory())

@ -38,6 +38,8 @@ type options struct {
host string
// if set dry-run helm client calls
dryRun bool
// if set validate manifest
validate bool
// if set, re-use an existing name
reuseName bool
// if set, skip running hooks
@ -219,6 +221,22 @@ func RollbackVersion(ver int32) RollbackOption {
}
}
// UpgradeValidate will (if true) instruct Tiller to validate manifest before
// reifying
func UpgradeValidate(validate bool) UpdateOption {
return func(opts *options) {
opts.validate = validate
}
}
// InstallValidate will (if true) instruct Tiller to validate manifest before
// reifying
func InstallValidate(validate bool) InstallOption {
return func(opts *options) {
opts.validate = validate
}
}
// UpgradeDisableHooks will disable hooks for an upgrade operation.
func UpgradeDisableHooks(disable bool) UpdateOption {
return func(opts *options) {
@ -278,6 +296,75 @@ type RollbackOption func(*options)
// issuing a GetHistory rpc.
type HistoryOption func(*options)
// RPC helpers defined on `options` type. Note: These actually execute the
// the corresponding tiller RPC. There is no particular reason why these
// are APIs are hung off `options`, they are internal to pkg/helm to remain
// malleable.
// Executes tiller.ListReleases RPC.
func (o *options) rpcListReleases(rlc rls.ReleaseServiceClient, opts ...ReleaseListOption) (*rls.ListReleasesResponse, error) {
// apply release list options
for _, opt := range opts {
opt(o)
}
s, err := rlc.ListReleases(context.TODO(), &o.listReq)
if err != nil {
return nil, err
}
return s.Recv()
}
// Executes tiller.InstallRelease RPC.
func (o *options) rpcInstallRelease(chr *cpb.Chart, rlc rls.ReleaseServiceClient, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
// apply the install options
for _, opt := range opts {
opt(o)
}
o.instReq.Chart = chr
o.instReq.Namespace = ns
o.instReq.DryRun = o.dryRun
o.instReq.DisableHooks = o.disableHooks
o.instReq.ReuseName = o.reuseName
o.instReq.Validate = o.validate
return rlc.InstallRelease(context.TODO(), &o.instReq)
}
// Executes tiller.UninstallRelease RPC.
func (o *options) rpcDeleteRelease(rlsName string, rlc rls.ReleaseServiceClient, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) {
for _, opt := range opts {
opt(o)
}
if o.dryRun {
// In the dry run case, just see if the release exists
r, err := o.rpcGetReleaseContent(rlsName, rlc)
if err != nil {
return &rls.UninstallReleaseResponse{}, err
}
return &rls.UninstallReleaseResponse{Release: r.Release}, nil
}
o.uninstallReq.Name = rlsName
o.uninstallReq.DisableHooks = o.disableHooks
return rlc.UninstallRelease(context.TODO(), &o.uninstallReq)
}
// Executes tiller.UpdateRelease RPC.
func (o *options) rpcUpdateRelease(rlsName string, chr *cpb.Chart, rlc rls.ReleaseServiceClient, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
for _, opt := range opts {
opt(o)
}
o.updateReq.Chart = chr
o.updateReq.DryRun = o.dryRun
o.updateReq.Name = rlsName
o.updateReq.Validate = o.validate
return rlc.UpdateRelease(context.TODO(), &o.updateReq)
}
// WithMaxHistory sets the max number of releases to return
// in a release history query.
func WithMaxHistory(max int32) HistoryOption {

@ -246,6 +246,9 @@ type UpdateReleaseRequest struct {
DryRun bool `protobuf:"varint,4,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"`
// DisableHooks causes the server to skip running any hooks for the upgrade.
DisableHooks bool `protobuf:"varint,5,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"`
// Validate requests that Tiller uses kubernetes validation logic on the
// manifest before handing it off for reification
Validate bool `protobuf:"varint,6,opt,name=validate" json:"validate,omitempty"`
}
func (m *UpdateReleaseRequest) Reset() { *m = UpdateReleaseRequest{} }
@ -337,6 +340,9 @@ type InstallReleaseRequest struct {
Namespace string `protobuf:"bytes,6,opt,name=namespace" json:"namespace,omitempty"`
// ReuseName requests that Tiller re-uses a name, instead of erroring out.
ReuseName bool `protobuf:"varint,7,opt,name=reuse_name,json=reuseName" json:"reuse_name,omitempty"`
// Validate requests that Tiller uses kubernetes validation logic on the
// manifest before handing it off for reification
Validate bool `protobuf:"varint,8,opt,name=validate" json:"validate,omitempty"`
}
func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} }
@ -878,6 +884,7 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
<<<<<<< 70b29a47d08628a6909964bcfc35f4a60507ea30
// 1004 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x57, 0xdf, 0x6f, 0xe3, 0xc4,
0x13, 0xaf, 0x93, 0x34, 0x3f, 0xa6, 0x3f, 0xbe, 0xe9, 0x5e, 0xda, 0xb8, 0xd6, 0x17, 0x14, 0x19,
@ -942,4 +949,64 @@ var fileDescriptor0 = []byte{
0xe7, 0x39, 0xb5, 0x13, 0x41, 0xa9, 0xc2, 0xde, 0x12, 0x54, 0xbc, 0x6b, 0x6c, 0x09, 0x2a, 0xd1,
0x23, 0xec, 0xbd, 0x17, 0xf0, 0x73, 0x55, 0xeb, 0xdd, 0x95, 0xc5, 0x5f, 0x85, 0xaf, 0xfe, 0x0d,
0x00, 0x00, 0xff, 0xff, 0x9a, 0xb0, 0xe9, 0x29, 0xfb, 0x0c, 0x00, 0x00,
=======
// 909 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x6e, 0xe3, 0x44,
0x14, 0xde, 0xfc, 0xd4, 0x71, 0x4e, 0x7f, 0xd4, 0xce, 0xf6, 0xc7, 0xb5, 0x00, 0xad, 0x8c, 0x60,
0xcb, 0x02, 0x29, 0x84, 0x5b, 0x84, 0xd4, 0xcd, 0x46, 0xdd, 0x6a, 0x43, 0x56, 0x9a, 0x50, 0x90,
0xb8, 0x20, 0x72, 0x93, 0xc9, 0xc6, 0xe0, 0xda, 0xc1, 0x33, 0x89, 0xe8, 0x23, 0xf0, 0x04, 0x5c,
0x70, 0xc7, 0x5b, 0xf1, 0x36, 0xcc, 0xaf, 0x1b, 0xbb, 0x36, 0xf5, 0xe6, 0x26, 0xf6, 0xcc, 0xf9,
0xe6, 0x3b, 0xe7, 0x7c, 0x67, 0xce, 0x71, 0xc0, 0x9d, 0xfb, 0x8b, 0xe0, 0x9c, 0x92, 0x64, 0x15,
0x4c, 0x08, 0x3d, 0x67, 0x41, 0x18, 0x92, 0xa4, 0xb3, 0x48, 0x62, 0x16, 0xa3, 0x43, 0x61, 0xeb,
0x18, 0x5b, 0x47, 0xd9, 0xdc, 0x63, 0x79, 0x62, 0x32, 0xf7, 0x13, 0xa6, 0x7e, 0x15, 0xda, 0x3d,
0x59, 0xdf, 0x8f, 0xa3, 0x59, 0xf0, 0x4e, 0x1b, 0x94, 0x8b, 0x84, 0x84, 0xc4, 0xa7, 0xc4, 0x3c,
0x33, 0x87, 0x8c, 0x2d, 0x88, 0x66, 0xb1, 0x36, 0x9c, 0x66, 0x0c, 0x94, 0xf9, 0x6c, 0x49, 0x33,
0x7c, 0x2b, 0x92, 0xd0, 0x20, 0x8e, 0xcc, 0x53, 0xd9, 0xbc, 0x7f, 0xea, 0xf0, 0x74, 0x10, 0x50,
0x86, 0xd5, 0x41, 0x8a, 0xc9, 0xef, 0x4b, 0x42, 0x19, 0x3a, 0x84, 0xad, 0x30, 0xb8, 0x0d, 0x98,
0x53, 0x7b, 0x56, 0x3b, 0x6b, 0x60, 0xb5, 0x40, 0xc7, 0x60, 0xc5, 0xb3, 0x19, 0x25, 0xcc, 0xa9,
0xf3, 0xed, 0x36, 0xd6, 0x2b, 0xf4, 0x1d, 0xb4, 0x68, 0x9c, 0xb0, 0xf1, 0xcd, 0x9d, 0xd3, 0xe0,
0x86, 0xbd, 0xee, 0x27, 0x9d, 0x22, 0x29, 0x3a, 0xc2, 0xd3, 0x88, 0x03, 0x3b, 0xe2, 0xe7, 0xe5,
0x1d, 0xb6, 0xa8, 0x7c, 0x0a, 0xde, 0x59, 0x10, 0x32, 0x92, 0x38, 0x4d, 0xc5, 0xab, 0x56, 0xe8,
0x12, 0x40, 0xf2, 0xc6, 0xc9, 0x94, 0xdb, 0xb6, 0x24, 0xf5, 0x59, 0x05, 0xea, 0xb7, 0x02, 0x8f,
0xdb, 0xd4, 0xbc, 0xa2, 0x6f, 0x61, 0x47, 0x49, 0x32, 0x9e, 0xc4, 0x53, 0x42, 0x1d, 0xeb, 0x59,
0x83, 0x53, 0x9d, 0x2a, 0x2a, 0xa3, 0xf0, 0x48, 0x89, 0xd6, 0xe3, 0x08, 0xbc, 0xad, 0xe0, 0xe2,
0x9d, 0x7a, 0xbf, 0x80, 0x6d, 0xe8, 0xbd, 0x2e, 0x58, 0x2a, 0x78, 0xb4, 0x0d, 0xad, 0xeb, 0xe1,
0x9b, 0xe1, 0xdb, 0x9f, 0x86, 0xfb, 0x4f, 0x90, 0x0d, 0xcd, 0xe1, 0xc5, 0xf7, 0xfd, 0xfd, 0x1a,
0x3a, 0x80, 0xdd, 0xc1, 0xc5, 0xe8, 0x87, 0x31, 0xee, 0x0f, 0xfa, 0x17, 0xa3, 0xfe, 0xab, 0xfd,
0xba, 0xf7, 0x11, 0xb4, 0xd3, 0xa8, 0x50, 0x0b, 0x1a, 0x17, 0xa3, 0x9e, 0x3a, 0xf2, 0xaa, 0xcf,
0xdf, 0x6a, 0xde, 0x9f, 0x35, 0x38, 0xcc, 0x16, 0x81, 0x2e, 0xe2, 0x88, 0x12, 0x51, 0x85, 0x49,
0xbc, 0x8c, 0xd2, 0x2a, 0xc8, 0x05, 0x42, 0xd0, 0x8c, 0xc8, 0x1f, 0xa6, 0x06, 0xf2, 0x5d, 0x20,
0x59, 0xcc, 0xfc, 0x50, 0xea, 0xcf, 0x91, 0x72, 0x81, 0xbe, 0x06, 0x5b, 0x27, 0x47, 0xb9, 0xb2,
0x8d, 0xb3, 0xed, 0xee, 0x51, 0x36, 0x65, 0xed, 0x11, 0xa7, 0x30, 0xef, 0x12, 0x4e, 0x2e, 0x89,
0x89, 0x44, 0x29, 0x62, 0xee, 0x84, 0xf0, 0xeb, 0xdf, 0x12, 0x19, 0x8c, 0xf0, 0xcb, 0xdf, 0x91,
0x03, 0x2d, 0x7d, 0xa1, 0x64, 0x38, 0x5b, 0xd8, 0x2c, 0x3d, 0x06, 0xce, 0x43, 0x22, 0x9d, 0x57,
0x11, 0xd3, 0xa7, 0xd0, 0x14, 0xd7, 0x59, 0xd2, 0x6c, 0x77, 0x51, 0x36, 0xce, 0x2b, 0x6e, 0xc1,
0xd2, 0x8e, 0x3e, 0x80, 0xb6, 0xc0, 0xd3, 0x85, 0x3f, 0x21, 0x32, 0xdb, 0x36, 0xbe, 0xdf, 0xf0,
0x5e, 0xaf, 0x7b, 0xed, 0xc5, 0x11, 0x23, 0x11, 0xdb, 0x2c, 0xfe, 0x01, 0x9c, 0x16, 0x30, 0xe9,
0x04, 0xce, 0xa1, 0xa5, 0x43, 0x93, 0x6c, 0xa5, 0xba, 0x1a, 0x94, 0xf7, 0x2f, 0x2f, 0xf1, 0xf5,
0x62, 0xea, 0x33, 0x62, 0x4c, 0xff, 0x13, 0xd4, 0x73, 0x5e, 0x76, 0x31, 0x16, 0xb4, 0x16, 0x07,
0x8a, 0x5b, 0xcd, 0x8e, 0x9e, 0xf8, 0xc5, 0xca, 0x8e, 0x5e, 0x80, 0xb5, 0xf2, 0x43, 0xce, 0x23,
0x85, 0x48, 0x55, 0xd3, 0x48, 0x39, 0x53, 0xb0, 0x46, 0xa0, 0x13, 0x68, 0x4d, 0x93, 0xbb, 0x71,
0xb2, 0x8c, 0x64, 0x93, 0xd9, 0xd8, 0xe2, 0x4b, 0xbc, 0x8c, 0xd0, 0xc7, 0xb0, 0x3b, 0x0d, 0xa8,
0x7f, 0x13, 0x92, 0xf1, 0x3c, 0x8e, 0x7f, 0xa3, 0xb2, 0xcf, 0x6c, 0xbc, 0xa3, 0x37, 0x5f, 0x8b,
0x3d, 0xe4, 0x82, 0xcd, 0x79, 0x02, 0x91, 0x00, 0x6f, 0x1e, 0x61, 0x4f, 0xd7, 0x5c, 0xf3, 0xa3,
0x5c, 0x6a, 0x9b, 0xaa, 0xf4, 0x57, 0x1d, 0x8e, 0xae, 0x22, 0xde, 0x7a, 0x61, 0x98, 0x93, 0x29,
0x95, 0xa4, 0x56, 0x59, 0x92, 0xfa, 0xfb, 0x48, 0xd2, 0xc8, 0x48, 0x62, 0x8a, 0xd2, 0x5c, 0x2b,
0x4a, 0x25, 0x99, 0x32, 0x97, 0xd3, 0xca, 0x5d, 0x4e, 0xf4, 0x21, 0x40, 0x42, 0x96, 0x94, 0x8c,
0x25, 0x79, 0x4b, 0x9e, 0x6f, 0xcb, 0x9d, 0xa1, 0xf0, 0xb0, 0xae, 0xb1, 0x9d, 0xd3, 0xf8, 0x0a,
0x8e, 0xf3, 0xc2, 0x6c, 0x2a, 0xf2, 0x1c, 0x4e, 0xae, 0xa3, 0xa0, 0x50, 0xe5, 0xa2, 0xcb, 0xf8,
0x20, 0xef, 0x7a, 0x41, 0xde, 0x7c, 0xfc, 0x2c, 0x96, 0xc9, 0x3b, 0xa2, 0x75, 0x54, 0x0b, 0xef,
0x0d, 0x38, 0x0f, 0x3d, 0x6d, 0x1a, 0xf6, 0x53, 0x38, 0xe0, 0xfd, 0xf8, 0xa3, 0xea, 0x4e, 0x1d,
0xb0, 0xd7, 0x07, 0xb4, 0xbe, 0x79, 0xcf, 0xad, 0xb7, 0xb2, 0xdc, 0xe6, 0xd3, 0x67, 0xf0, 0xa6,
0xd7, 0xbb, 0x7f, 0x5b, 0xb0, 0x67, 0x26, 0x95, 0xfa, 0xae, 0xa0, 0x00, 0x76, 0xd6, 0x47, 0x32,
0xfa, 0xac, 0xfc, 0xb3, 0x93, 0xfb, 0x76, 0xba, 0x2f, 0xaa, 0x40, 0x55, 0xa8, 0xde, 0x93, 0xaf,
0x6a, 0x88, 0xc2, 0x7e, 0x7e, 0x52, 0xa2, 0x2f, 0x8b, 0x39, 0x4a, 0x46, 0xb3, 0xdb, 0xa9, 0x0a,
0x37, 0x6e, 0xd1, 0x4a, 0xca, 0x99, 0x1d, 0x6f, 0xe8, 0x51, 0x9a, 0xec, 0x44, 0x75, 0xcf, 0x2b,
0xe3, 0x53, 0xbf, 0xbf, 0xc2, 0x6e, 0x66, 0x58, 0xa0, 0x12, 0xb5, 0x8a, 0x86, 0xa5, 0xfb, 0x79,
0x25, 0x6c, 0xea, 0xeb, 0x16, 0xf6, 0xb2, 0x4d, 0x83, 0x4a, 0x08, 0x0a, 0x67, 0x8e, 0xfb, 0x45,
0x35, 0x70, 0xea, 0x8e, 0xd7, 0x31, 0x7f, 0xdd, 0xcb, 0xea, 0x58, 0xd2, 0x80, 0x65, 0x75, 0x2c,
0xeb, 0x22, 0xee, 0xd4, 0x07, 0xb8, 0xef, 0x00, 0xf4, 0xbc, 0xb4, 0x20, 0xd9, 0xc6, 0x71, 0xcf,
0x1e, 0x07, 0x1a, 0x17, 0x2f, 0xe1, 0x67, 0xdb, 0xe0, 0x6e, 0x2c, 0xf9, 0xb7, 0xf1, 0x9b, 0xff,
0x02, 0x00, 0x00, 0xff, 0xff, 0x7b, 0x5d, 0x13, 0x1a, 0x07, 0x0b, 0x00, 0x00,
>>>>>>> Add validate to Install / Upgrade commands that use kubernets to validate the manifest before reifying
}

Loading…
Cancel
Save