github.com/cloudposse/helm@v2.2.3+incompatible/pkg/tiller/hooks.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tiller
    18  
    19  import (
    20  	"fmt"
    21  	"log"
    22  	"path"
    23  	"strings"
    24  
    25  	"github.com/ghodss/yaml"
    26  
    27  	"k8s.io/helm/pkg/chartutil"
    28  	"k8s.io/helm/pkg/hooks"
    29  	"k8s.io/helm/pkg/proto/hapi/release"
    30  	util "k8s.io/helm/pkg/releaseutil"
    31  )
    32  
    33  var events = map[string]release.Hook_Event{
    34  	hooks.PreInstall:         release.Hook_PRE_INSTALL,
    35  	hooks.PostInstall:        release.Hook_POST_INSTALL,
    36  	hooks.PreDelete:          release.Hook_PRE_DELETE,
    37  	hooks.PostDelete:         release.Hook_POST_DELETE,
    38  	hooks.PreUpgrade:         release.Hook_PRE_UPGRADE,
    39  	hooks.PostUpgrade:        release.Hook_POST_UPGRADE,
    40  	hooks.PreRollback:        release.Hook_PRE_ROLLBACK,
    41  	hooks.PostRollback:       release.Hook_POST_ROLLBACK,
    42  	hooks.ReleaseTestSuccess: release.Hook_RELEASE_TEST_SUCCESS,
    43  	hooks.ReleaseTestFailure: release.Hook_RELEASE_TEST_FAILURE,
    44  }
    45  
    46  // manifest represents a manifest file, which has a name and some content.
    47  type manifest struct {
    48  	name    string
    49  	content string
    50  	head    *util.SimpleHead
    51  }
    52  
    53  // sortManifests takes a map of filename/YAML contents and sorts them into hook types.
    54  //
    55  // The resulting hooks struct will be populated with all of the generated hooks.
    56  // Any file that does not declare one of the hook types will be placed in the
    57  // 'generic' bucket.
    58  //
    59  // To determine hook type, this looks for a YAML structure like this:
    60  //
    61  //  kind: SomeKind
    62  //  apiVersion: v1
    63  // 	metadata:
    64  //		annotations:
    65  //			helm.sh/hook: pre-install
    66  //
    67  // Where HOOK_NAME is one of the known hooks.
    68  //
    69  // If a file declares more than one hook, it will be copied into all of the applicable
    70  // hook buckets. (Note: label keys are not unique within the labels section).
    71  //
    72  // Files that do not parse into the expected format are simply placed into a map and
    73  // returned.
    74  func sortManifests(files map[string]string, apis chartutil.VersionSet, sort SortOrder) ([]*release.Hook, []manifest, error) {
    75  	hs := []*release.Hook{}
    76  	generic := []manifest{}
    77  
    78  	for n, c := range files {
    79  		// Skip partials. We could return these as a separate map, but there doesn't
    80  		// seem to be any need for that at this time.
    81  		if strings.HasPrefix(path.Base(n), "_") {
    82  			continue
    83  		}
    84  		// Skip empty files, and log this.
    85  		if len(strings.TrimSpace(c)) == 0 {
    86  			log.Printf("info: manifest %q is empty. Skipping.", n)
    87  			continue
    88  		}
    89  
    90  		var sh util.SimpleHead
    91  		err := yaml.Unmarshal([]byte(c), &sh)
    92  
    93  		if err != nil {
    94  			e := fmt.Errorf("YAML parse error on %s: %s", n, err)
    95  			return hs, generic, e
    96  		}
    97  
    98  		if sh.Version != "" && !apis.Has(sh.Version) {
    99  			return hs, generic, fmt.Errorf("apiVersion %q in %s is not available", sh.Version, n)
   100  		}
   101  
   102  		if sh.Metadata == nil || sh.Metadata.Annotations == nil || len(sh.Metadata.Annotations) == 0 {
   103  			generic = append(generic, manifest{name: n, content: c, head: &sh})
   104  			continue
   105  		}
   106  
   107  		hookTypes, ok := sh.Metadata.Annotations[hooks.HookAnno]
   108  		if !ok {
   109  			generic = append(generic, manifest{name: n, content: c, head: &sh})
   110  			continue
   111  		}
   112  		h := &release.Hook{
   113  			Name:     sh.Metadata.Name,
   114  			Kind:     sh.Kind,
   115  			Path:     n,
   116  			Manifest: c,
   117  			Events:   []release.Hook_Event{},
   118  		}
   119  
   120  		isHook := false
   121  		for _, hookType := range strings.Split(hookTypes, ",") {
   122  			hookType = strings.ToLower(strings.TrimSpace(hookType))
   123  			e, ok := events[hookType]
   124  			if ok {
   125  				isHook = true
   126  				h.Events = append(h.Events, e)
   127  			}
   128  		}
   129  
   130  		if !isHook {
   131  			log.Printf("info: skipping unknown hook: %q", hookTypes)
   132  			continue
   133  		}
   134  		hs = append(hs, h)
   135  	}
   136  	return hs, sortByKind(generic, sort), nil
   137  }