Merge branch 'master' into fix/zshFlagBug

Signed-off-by: Marc Khouzam <marc.khouzam@montreal.ca>
pull/5680/head
Marc Khouzam 5 years ago
commit eb838bff3a

@ -75,3 +75,6 @@ ${HOME}/google-cloud-sdk/bin/gsutil cp ./_dist/* "gs://${PROJECT_NAME}"
echo "Pushing binaries to Azure"
az storage blob upload-batch -s _dist/ -d "$AZURE_STORAGE_CONTAINER_NAME" --pattern 'helm-*' --connection-string "$AZURE_STORAGE_CONNECTION_STRING"
echo "Pushing KEYS file to Azure"
az storage blob upload -f "KEYS" -n "KEYS" -c "$AZURE_STORAGE_CONTAINER_NAME" --connection-string "$AZURE_STORAGE_CONNECTION_STRING"

@ -263,6 +263,8 @@ Like any good open source project, we use Pull Requests (PRs) to track code chan
- PRs should stay open until merged or if they have not been active for more than 30 days.
This will help keep the PR queue to a manageable size and reduce noise. Should the PR need
to stay open (like in the case of a WIP), the `keep open` label can be added.
- Before merging a PR, refer to the topic on [Size Labels](#size-labels) below to determine if
the PR requires more than one LGTM to merge.
- If the owner of the PR is listed in `OWNERS`, that user **must** merge their own PRs or explicitly
request another OWNER do that for them.
- If the owner of a PR is _not_ listed in `OWNERS`, any maintainer may merge the PR once it is approved.
@ -320,11 +322,15 @@ The following tables define all label types used for Helm. It is split up by cat
Size labels are used to indicate how "dangerous" a PR is. The guidelines below are used to assign the
labels, but ultimately this can be changed by the maintainers. For example, even if a PR only makes
30 lines of changes in 1 file, but it changes key functionality, it will likely be labeled as `size/large`
30 lines of changes in 1 file, but it changes key functionality, it will likely be labeled as `size/L`
because it requires sign off from multiple people. Conversely, a PR that adds a small feature, but requires
another 150 lines of tests to cover all cases, could be labeled as `size/small` even though the number
another 150 lines of tests to cover all cases, could be labeled as `size/S` even though the number
lines is greater than defined below.
PRs submitted by a core maintainer, regardless of size, only requires approval from one additional
maintainer. This ensures there are at least two maintainers who are aware of any significant PRs
introduced to the codebase.
| Label | Description |
| ----- | ----------- |
| `size/XS` | Anything less than or equal to 9 lines ignoring generated files. Only small amounts of manual testing may be required. |

271
KEYS

@ -0,0 +1,271 @@
This file contains the PGP keys of developers who have signed releases of Helm.
For your convenience, commands are provided for those who use pgp and gpg.
For users to import keys:
pgp < KEYS
or
gpg --import KEYS
Developers to add their keys:
pgp -kxa <your name> and append it to this file.
or
(pgpk -ll <your name> && pgpk -xa <your name>) >> KEYS
or
(gpg --list-sigs <your name>
&& gpg --armor --export <your name>) >> KEYS
pub rsa4096/0x461449C25E36B98E 2017-11-10 [SC]
672C657BE06B4B30969C4A57461449C25E36B98E
uid [ultimate] Matthew Farina <matt@mattfarina.com>
sig 3 0x461449C25E36B98E 2017-11-10 Matthew Farina <matt@mattfarina.com>
sig 0x2CDBBFBB37AE822A 2018-12-12 Adnan Abdulhussein <prydonius@gmail.com>
sig 0x1EF612347F8A9958 2018-12-12 Adam Reese <adam@reese.io>
sig 0x62F49E747D911B60 2018-12-12 Matt Butcher <matt.butcher@microsoft.com>
sub rsa4096/0xCCCE67689DF05738 2017-11-10 [E]
sig 0x461449C25E36B98E 2017-11-10 Matthew Farina <matt@mattfarina.com>
sub rsa4096/0x9436E80BFBA46909 2017-11-10 [S] [expires: 2022-11-09]
sig 0x461449C25E36B98E 2017-11-10 Matthew Farina <matt@mattfarina.com>
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
+YMbPW0/IQ==
=g11H
-----END PGP PUBLIC KEY BLOCK-----
pub rsa4096 2019-05-15 [SC]
F1261BDE929012C8FF2E501D6EA5D7598529A53E
uid [ultimate] Martin Hickey <martin.hickey@ie.ibm.com>
sig 3 6EA5D7598529A53E 2019-05-15 Martin Hickey <martin.hickey@ie.ibm.com>
sub rsa4096 2019-05-15 [E]
sig 6EA5D7598529A53E 2019-05-15 Martin Hickey <martin.hickey@ie.ibm.com>
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFzcLlgBEACsmjtsbfMuKiKBl3yV5FsQBxvmNyhIwUJMtjgm5CMFcOLD+jDw
mExfsE8sM5fqfS5P7NFHn3V6NY/GyKNH3DZHGhYwDw/vG6JfHo1s9IzhjySuWEtL
7GUCJBKXk2cDfk4p0lHRgEtoYjG/sRMgk3y7WTR/W0McxllcrQQBB3RREbz8y7r7
atJCeec36SSZgXqsyXAESx5dx7qRTdIwObPTCGxBdj2ZkgzT3D35EExdi9I8oM6L
bYOyUPy0aEj/FX6HVBOIWNGB0z8TYXjwY6/3gJG1JhaFZK1zvYogJ3p8jO07bTwo
/AzYAG4NoV4TqTyFPmb0d0+wE+lZOWA3FfF0YtYnNe3KPmPJZ/TXdTO6kle24UTy
Q9GK2s8QB3V9NA09/YoSF1qdjRfL5jo7XnRJztfFgIqW118I4EKSF+kz3hCMxH1Y
iCvHIHFQs+WX6g1bXHDI8JWe7VDiCVYwMxap8o/vtEKoETH9fjOEO/f/YF68hqpX
7eYTacDEV72qikHz/O0hNyeS1m/AnavPrd5RQi53vOT/KhwM+wC4a1bAywQUDZDW
KkSEkTqjzcSryj3DJR6EZ9y4F11Kt4TZoxHvh59UCcVyaTZPl/YdcRWom6eGo/5U
K1MFeF7fTK9ZVuJnvG6av2/W7Sbz9KaJxLHhUNAQ+ytdVkN9xfXrx1HP7QARAQAB
tChNYXJ0aW4gSGlja2V5IDxtYXJ0aW4uaGlja2V5QGllLmlibS5jb20+iQJOBBMB
CgA4FiEE8SYb3pKQEsj/LlAdbqXXWYUppT4FAlzcLlgCGwMFCwkIBwIGFQoJCAsC
BBYCAwECHgECF4AACgkQbqXXWYUppT5IFA//b64QqKN/ookqqeKEUMUOMoZUTi2t
4HPtzX/nqOXDb0zyIyaJaJlgxz+LuoN8CrSrwnmTY/ibKsFS7xkFRIeKYSb9b2no
NPb8F0SVtxYFQJ8d4WU1snAWFJd8aMe3+z8w15Mqz1Sd1lS/sN5s101rbh8jtFZD
NnAZqyfUgIhVq243XfhP4/mHPinpXjjF+APlMbdsOqnWgxzp8E9hpCd/YLb6KY0j
JbwryzH52ha9ZDMdMipH557+Xutcl4Wyn8RsJy38J0qBvy2p8AMZIYotw6pSCedi
7Iva+EitGSXXgRWbR6O68JvUgrFDOjcPKSQy7AlwhTase+b4OA9c3DgSxR5SMBR6
OLYaIuDeVY2Zjr0ydFdxrfQzlHget7axRH0aaMimyCNfRa3HJea8ffF/Ssv2meUF
IPIhYLn7SBrVoTISu38S6WkhBBkDiHAW7nqV+mWR3cnVjIzIjW56bI06NZ4kqtvk
D9TX7b+KV20cSjjbSGI70023oHFoJSpLsj9+otvPwNrYC2oD0qTLBfNMkpcktnnw
I2uynQrPNbQVeA+cKrECJeyl2yAC4WXvP4ZefvFZX6RnL9HiiZ+pDyBt6Yq3A9AA
NhRd8zEAKNwH88tFmWMinTzCZz04bKvql+E7A3MAaR8WS3BG3JfLXMqOKiMfCHr5
4Gn3rD4UGtFfxoy5Ag0EXNwuWAEQAKuxVJDOjG+xuaaO2Z/6BQfTaz6/zgzql/pR
UHInKSt5ts2LGdRhfvsNBzGBhoneLWZ8PivHRGSZFsFj5Nzy9/DIkopdHSZhP/zB
aqihHgFJTKxKBfrhP60bYQGBkHNMVwqbFuck24DUCzrMyJXG15f252aY7ByCIIem
SHbmPww5q6HPEPS+hHE4ka4N4s+vqL+oK8ktq7lnZCX+AZ4jIuMAoh/C851hLcr5
EK+a6tXa2yRJtJfj44GX6+nBVm2w+3eHqOpD7JM7NqWmo41+qg3t2J3zHQf/0ejP
ej+OcVdEBD5zlJL+CNZ9PCMBUOrb+IbqY3ybmJieipOJtOCY8nwUyCueyTmq1tso
OwUsGB9hIsVY11wNgoNgrA6PhExGxcM5S/0Rt4+y/pwFjnqYLXBXyBSjXzzmpjhn
zERjmANlI8QLKHDdShgboDUt3Ynw+D/peTS9iJMIPuUTrcGcKgw4+6FNKACnJ5l7
Wvz7apgD8QmxnSZMquul23bGihhbQMITWvdF5KEHE06Ah1bOzB3KXBEVx00Y0tO/
hsY8XH4T/pEKv9FsIF6R4o2k/xm6jR9eZutABVIrizMHkZzjjo1ZC8b15olrZvLa
/DtNHzV5nPPSvGZPcey9BYk6b5GGCfT/EiWtJz8Nxm7/cCYRvuuZnGCxriH6XPww
v8kPNihfABEBAAGJAjYEGAEKACAWIQTxJhvekpASyP8uUB1upddZhSmlPgUCXNwu
WAIbDAAKCRBupddZhSmlPikmD/9UrspSeSjwaXSj2vCpO1pWm6ryVQc2ZzyMnXvq
j5HLwzaVsN8HM/YADK5FL6qqhxrROOZdSHjS92sxk2Rab23gGRKbwDUJmerheZ4B
ZXG40fDOPv45PZ8V0Kn9bzliNpPBFPjoaI8X1AKoIXyUqEy98Y/zhnLDhW/+yPrO
gznPfO5ds75+u4xOx9pTfGpdwt6qhfCdNHUoZWsAw/6pafqrCIvbHjGvmMJyYENS
dl6sPYBeiDkJkH67sGvJghjedhNznnXJ8+sm701eTqZkmpxzc0jvzwgnnYb0rAzS
uU3QNj9w5HcGQd/pk29Ui8A4VWLJOUcDCVa/CIQMQqQDPYJKxaj7XgE+dQ9MxQ3a
O0wgpEo2+4BaZ4I/qP8CgaE9q4IopMhNKPR1IeEFUmTsIzLVAktS/InshFWWUp5e
mEss8kiqxU9bAGZvWopllCaPJQTDZElQpW84Z0afyVLPp47CoKcXBSMsITFt3mRf
ZXAA6h8UlSgC7FV1YT4p6qsHqQ3cLERdTSrQFLmaCb2yRCR2V9d0RiMaIwUmnbld
g1jeR4weO3LLghuWpfZHruDrDU2ZvOAObQIQdHBFmCHejA/gilf0MUdJ1h2gApuJ
m3MUub704EDCTSqz9LJc+4/NbA2esZj7mExCtsMEqaoHW7BU4ws6BRHTyeHgi+Le
1qneNQ==
=oCPv
-----END PGP PUBLIC KEY BLOCK-----
pub rsa4096 2018-03-14 [SC]
967F8AC5E2216F9F4FD270AD92AA783CBAAE8E3B
uid [ultimate] Matthew Fisher <matt.fisher@microsoft.com>
sig 3 92AA783CBAAE8E3B 2018-03-14 Matthew Fisher <matt.fisher@microsoft.com>
sub rsa4096 2018-03-14 [E]
sig 92AA783CBAAE8E3B 2018-03-14 Matthew Fisher <matt.fisher@microsoft.com>
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
Qknjx8fW
=jz9T
-----END PGP PUBLIC KEY BLOCK-----

@ -141,6 +141,10 @@ docker-test-style: check-docker
protoc:
$(MAKE) -C _proto/ all
.PHONY: generate
generate:
$(GO) generate ./...
.PHONY: docs
docs: build
@scripts/update-docs.sh

@ -3,6 +3,7 @@ maintainers:
- bacongobbler
- fibonacci1729
- hickeyma
- jdolitsky
- mattfarina
- michelleN
- prydonius

@ -43,6 +43,8 @@ If you want to use a package manager:
- [Chocolatey](https://chocolatey.org/) users can use `choco install kubernetes-helm`.
- [Scoop](https://scoop.sh/) users can use `scoop install helm`.
- [GoFish](https://gofi.sh/) users can use `gofish install helm`.
- [Snap](https://snapcraft.io/) users can use `sudo snap install helm
--classic`.
To rapidly get Helm up and running, start with the [Quick Start Guide](https://docs.helm.sh/using_helm/#quickstart-guide).

@ -56,4 +56,6 @@ message Hook {
int32 weight = 7;
// DeletePolicies are the policies that indicate when to delete the hook
repeated DeletePolicy delete_policies = 8;
// DeleteTimeout indicates how long to wait for a resource to be deleted before timing out
int64 delete_timeout = 9;
}

@ -41,7 +41,7 @@ message Status {
PENDING_INSTALL = 6;
// Status_PENDING_UPGRADE indicates that an upgrade operation is underway.
PENDING_UPGRADE = 7;
// Status_PENDING_ROLLBACK indicates that an rollback operation is underway.
// Status_PENDING_ROLLBACK indicates that a rollback operation is underway.
PENDING_ROLLBACK = 8;
}

@ -187,7 +187,7 @@ autoload -U +X bashcompinit && bashcompinit
# use word boundary patterns for BSD or GNU sed
LWORD='[[:<:]]'
RWORD='[[:>:]]'
if sed --help 2>&1 | grep -q GNU; then
if sed --help 2>&1 | grep -q 'GNU\|BusyBox'; then
LWORD='\<'
RWORD='\>'
fi

@ -88,7 +88,7 @@ func newCreateCmd(out io.Writer) *cobra.Command {
},
}
cmd.Flags().StringVarP(&cc.starter, "starter", "p", "", "The named Helm starter scaffold")
cmd.Flags().StringVarP(&cc.starter, "starter", "p", "", "The name or absolute path to Helm starter scaffold")
return cmd
}
@ -106,6 +106,10 @@ func (c *createCmd) run() error {
if c.starter != "" {
// Create from the starter
lstarter := filepath.Join(c.home.Starters(), c.starter)
// If path is absolute, we dont want to prefix it with helm starters folder
if filepath.IsAbs(c.starter) {
lstarter = c.starter
}
return chartutil.CreateFrom(cfile, filepath.Dir(c.name), lstarter)
}

@ -143,7 +143,99 @@ func TestCreateStarterCmd(t *testing.T) {
t.Errorf("Wrong API version: %q", c.Metadata.ApiVersion)
}
expectedTemplateCount := 7
expectedTemplateCount := 8
if l := len(c.Templates); l != expectedTemplateCount {
t.Errorf("Expected %d templates, got %d", expectedTemplateCount, l)
}
found := false
for _, tpl := range c.Templates {
if tpl.Name == "templates/foo.tpl" {
found = true
data := tpl.Data
if string(data) != "test" {
t.Errorf("Expected template 'test', got %q", string(data))
}
}
}
if !found {
t.Error("Did not find foo.tpl")
}
}
func TestCreateStarterAbsoluteCmd(t *testing.T) {
cname := "testchart"
// Make a temp dir
tdir, err := ioutil.TempDir("", "helm-create-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tdir)
thome, err := tempHelmHome(t)
if err != nil {
t.Fatal(err)
}
cleanup := resetEnv()
defer func() {
os.RemoveAll(thome.String())
cleanup()
}()
settings.Home = thome
// Create a starter.
starterchart := filepath.Join(tdir, "starters")
os.Mkdir(starterchart, 0755)
if dest, err := chartutil.Create(&chart.Metadata{Name: "starterchart"}, starterchart); err != nil {
t.Fatalf("Could not create chart: %s", err)
} else {
t.Logf("Created %s", dest)
}
tplpath := filepath.Join(starterchart, "starterchart", "templates", "foo.tpl")
if err := ioutil.WriteFile(tplpath, []byte("test"), 0755); err != nil {
t.Fatalf("Could not write template: %s", err)
}
// CD into it
pwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
if err := os.Chdir(tdir); err != nil {
t.Fatal(err)
}
defer os.Chdir(pwd)
// Run a create
cmd := newCreateCmd(ioutil.Discard)
cmd.ParseFlags([]string{"--starter", filepath.Join(starterchart, "starterchart")})
if err := cmd.RunE(cmd, []string{cname}); err != nil {
t.Errorf("Failed to run create: %s", err)
return
}
// Test that the chart is there
if fi, err := os.Stat(cname); err != nil {
t.Fatalf("no chart directory: %s", err)
} else if !fi.IsDir() {
t.Fatalf("chart is not directory")
}
c, err := chartutil.LoadDir(cname)
if err != nil {
t.Fatal(err)
}
if c.Metadata.Name != cname {
t.Errorf("Expected %q name, got %q", cname, c.Metadata.Name)
}
if c.Metadata.ApiVersion != chartutil.ApiVersionV1 {
t.Errorf("Wrong API version: %q", c.Metadata.ApiVersion)
}
expectedTemplateCount := 8
if l := len(c.Templates); l != expectedTemplateCount {
t.Errorf("Expected %d templates, got %d", expectedTemplateCount, l)
}

@ -41,7 +41,7 @@ import (
const (
bashCompletionFunc = `
__helm_override_flag_list=(--kubeconfig --kube-context --host --tiller-namespace)
__helm_override_flag_list=(--kubeconfig --kube-context --host --tiller-namespace --home)
__helm_override_flags()
{
local ${__helm_override_flag_list[*]##*-} two_word_of of var
@ -80,6 +80,28 @@ __helm_list_releases()
fi
}
__helm_list_repos()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local out oflags
oflags=$(__helm_override_flags)
__helm_debug "${FUNCNAME[0]}: __helm_override_flags are ${oflags}"
if out=$(helm repo list ${oflags} | tail +2 | cut -f1 2>/dev/null); then
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
fi
}
__helm_list_plugins()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local out oflags
oflags=$(__helm_override_flags)
__helm_debug "${FUNCNAME[0]}: __helm_override_flags are ${oflags}"
if out=$(helm plugin list ${oflags} | tail +2 | cut -f1 2>/dev/null); then
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
fi
}
__helm_custom_func()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[@] is ${words[@]}"
@ -89,6 +111,14 @@ __helm_custom_func()
__helm_list_releases
return
;;
helm_repo_remove | helm_repo_update)
__helm_list_repos
return
;;
helm_plugin_remove | helm_plugin_update)
__helm_list_plugins
return
;;
*)
;;
esac

@ -284,6 +284,7 @@ func (i *initCmd) run() error {
}
fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been upgraded to the current version.")
} else {
debug("The error received while trying to init: %s", err)
fmt.Fprintln(i.out, "Warning: Tiller is already installed in the cluster.\n"+
"(Use --client-only to suppress this message, or --upgrade to upgrade Tiller to the current version.)")
}

@ -17,6 +17,7 @@ limitations under the License.
package installer // import "k8s.io/helm/cmd/helm/installer"
import (
"encoding/json"
"os"
"path/filepath"
"reflect"
@ -716,9 +717,32 @@ func TestDeployment_WithSetValues(t *testing.T) {
// convert our expected value to match the result type for comparison
ev := tt.expect
intType := reflect.TypeOf(int64(0))
floatType := reflect.TypeOf(float64(0))
switch pvt := pv.(type) {
case json.Number:
evv := reflect.ValueOf(ev)
evv = reflect.Indirect(evv)
switch ev.(type) {
case float32, float64:
evv = evv.Convert(floatType)
if fpv, err := pv.(json.Number).Float64(); err != nil {
t.Errorf("Failed to convert json number to float: %s", err)
} else if fpv != evv.Float() {
t.Errorf("%s: expected float value %q, got %f", tt.name, tt.expect, fpv)
}
case byte, int, int32, int64:
evv = evv.Convert(intType)
if ipv, err := pv.(json.Number).Int64(); err != nil {
t.Errorf("Failed to convert json number to int: %s", err)
} else if ipv != evv.Int() {
t.Errorf("%s: expected int value %q, got %d", tt.name, tt.expect, ipv)
}
default:
t.Errorf("Unknown primitive type: %s", reflect.TypeOf(ev))
}
case float64:
floatType := reflect.TypeOf(float64(0))
v := reflect.ValueOf(ev)
v = reflect.Indirect(v)
if !v.Type().ConvertibleTo(floatType) {

@ -17,16 +17,20 @@ limitations under the License.
package main
import (
"context"
"fmt"
"io"
"syscall"
"time"
"golang.org/x/crypto/ssh/terminal"
"github.com/gofrs/flock"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/repo"
"syscall"
)
type repoAddCmd struct {
@ -131,6 +135,25 @@ func addRepository(name, url, username, password string, home helmpath.Home, cer
return fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", url, err.Error())
}
// Lock the repository file for concurrent goroutines or processes synchronization
fileLock := flock.New(home.RepositoryFile())
lockCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
locked, err := fileLock.TryLockContext(lockCtx, time.Second)
if err == nil && locked {
defer fileLock.Unlock()
}
if err != nil {
return err
}
// Re-read the repositories file before updating it as its content may have been changed
// by a concurrent execution after the first read and before being locked
f, err = repo.LoadRepositoriesFile(home.RepositoryFile())
if err != nil {
return err
}
f.Update(&c)
return f.WriteFile(home.RepositoryFile(), 0644)

@ -17,13 +17,18 @@ limitations under the License.
package main
import (
"fmt"
"io"
"os"
"os/exec"
"strings"
"sync"
"testing"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/repo"
"k8s.io/helm/pkg/repo/repotest"
)
@ -101,3 +106,111 @@ func TestRepoAdd(t *testing.T) {
t.Errorf("Duplicate repository name was added")
}
}
func TestRepoAddConcurrentGoRoutines(t *testing.T) {
ts, thome, err := repotest.NewTempServer("testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
cleanup := resetEnv()
defer func() {
ts.Stop()
os.RemoveAll(thome.String())
cleanup()
}()
settings.Home = thome
if err := ensureTestHome(settings.Home, t); err != nil {
t.Fatal(err)
}
var wg sync.WaitGroup
wg.Add(3)
for i := 0; i < 3; i++ {
go func(name string) {
defer wg.Done()
if err := addRepository(name, ts.URL(), "", "", settings.Home, "", "", "", true); err != nil {
t.Error(err)
}
}(fmt.Sprintf("%s-%d", testName, i))
}
wg.Wait()
f, err := repo.LoadRepositoriesFile(settings.Home.RepositoryFile())
if err != nil {
t.Error(err)
}
var name string
for i := 0; i < 3; i++ {
name = fmt.Sprintf("%s-%d", testName, i)
if !f.Has(name) {
t.Errorf("%s was not successfully inserted into %s", name, settings.Home.RepositoryFile())
}
}
}
// Same as TestRepoAddConcurrentGoRoutines but with repository additions in sub-processes
func TestRepoAddConcurrentSubProcesses(t *testing.T) {
goWantHelperProcess := os.Getenv("GO_WANT_HELPER_PROCESS")
if goWantHelperProcess == "" {
// parent
ts, thome, err := repotest.NewTempServer("testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
settings.Home = thome
cleanup := resetEnv()
defer func() {
ts.Stop()
os.RemoveAll(thome.String())
cleanup()
}()
if err := ensureTestHome(settings.Home, t); err != nil {
t.Fatal(err)
}
var wg sync.WaitGroup
wg.Add(2)
for i := 0; i < 2; i++ {
go func(name string) {
defer wg.Done()
cmd := exec.Command(os.Args[0], "-test.run=^TestRepoAddConcurrentSubProcesses$")
cmd.Env = append(os.Environ(), fmt.Sprintf("GO_WANT_HELPER_PROCESS=%s,%s", name, ts.URL()), fmt.Sprintf("HELM_HOME=%s", settings.Home))
out, err := cmd.CombinedOutput()
if len(out) > 0 || err != nil {
t.Fatalf("child process: %q, %v", out, err)
}
}(fmt.Sprintf("%s-%d", testName, i))
}
wg.Wait()
f, err := repo.LoadRepositoriesFile(settings.Home.RepositoryFile())
if err != nil {
t.Error(err)
}
var name string
for i := 0; i < 2; i++ {
name = fmt.Sprintf("%s-%d", testName, i)
if !f.Has(name) {
t.Errorf("%s was not successfully inserted into %s", name, settings.Home.RepositoryFile())
}
}
} else {
// child
s := strings.Split(goWantHelperProcess, ",")
settings.Home = helmpath.Home(os.Getenv("HELM_HOME"))
repoName := s[0]
tsURL := s[1]
if err := addRepository(repoName, tsURL, "", "", settings.Home, "", "", "", true); err != nil {
t.Fatal(err)
}
os.Exit(0)
}
}

@ -36,15 +36,24 @@ Information is cached locally, where it is used by commands like 'helm search'.
'helm update' is the deprecated form of 'helm repo update'. It will be removed in
future releases.
You can specify the name of a repository you want to update.
$ helm repo update <repo_name>
To update all the repositories, use 'helm repo update'.
`
var errNoRepositories = errors.New("no repositories found. You must add one before updating")
var errNoRepositoriesMatchingRepoName = errors.New("no repositories found matching the provided name. Verify if the repo exists")
type repoUpdateCmd struct {
update func([]*repo.ChartRepository, io.Writer, helmpath.Home, bool) error
home helmpath.Home
out io.Writer
strict bool
name string
}
func newRepoUpdateCmd(out io.Writer) *cobra.Command {
@ -53,12 +62,15 @@ func newRepoUpdateCmd(out io.Writer) *cobra.Command {
update: updateCharts,
}
cmd := &cobra.Command{
Use: "update",
Use: "update [REPO_NAME]",
Aliases: []string{"up"},
Short: "Update information of available charts locally from chart repositories",
Long: updateDesc,
RunE: func(cmd *cobra.Command, args []string) error {
u.home = settings.Home
if len(args) != 0 {
u.name = args[0]
}
return u.run()
},
}
@ -84,8 +96,22 @@ func (u *repoUpdateCmd) run() error {
if err != nil {
return err
}
if len(u.name) != 0 {
if cfg.Name == u.name {
repos = append(repos, r)
break
} else {
continue
}
} else {
repos = append(repos, r)
}
}
if len(repos) == 0 {
return errNoRepositoriesMatchingRepoName
}
return u.update(repos, u.out, u.home, u.strict)
}

@ -132,3 +132,78 @@ func TestUpdateCmdStrictFlag(t *testing.T) {
t.Errorf("Expected 'Unable to get an update', got %q", got)
}
}
func TestUpdateCmdWithSingleRepoNameWhichDoesntExist(t *testing.T) {
thome, err := tempHelmHome(t)
if err != nil {
t.Fatal(err)
}
cleanup := resetEnv()
defer func() {
os.RemoveAll(thome.String())
cleanup()
}()
settings.Home = thome
out := bytes.NewBuffer(nil)
cmd := newRepoUpdateCmd(out)
if err = cmd.RunE(cmd, []string{"randomRepo"}); err == nil {
t.Fatal("expected error due to wrong repo name")
}
if got := fmt.Sprintf("%v", err); !strings.Contains(got, "no repositories found matching the provided name. Verify if the repo exists") {
t.Errorf("Expected 'no repositories found matching the provided name. Verify if the repo exists', got %q", got)
}
}
func TestUpdateRepo(t *testing.T) {
ts, thome, err := repotest.NewTempServer("testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
hh := helmpath.Home(thome)
cleanup := resetEnv()
defer func() {
ts.Stop()
os.RemoveAll(thome.String())
cleanup()
}()
if err := ensureTestHome(hh, t); err != nil {
t.Fatal(err)
}
settings.Home = thome
if err := addRepository("repo1", ts.URL(), "", "", hh, "", "", "", true); err != nil {
t.Error(err)
}
if err := addRepository("repo2", ts.URL(), "", "", hh, "", "", "", true); err != nil {
t.Error(err)
}
out := bytes.NewBuffer(nil)
cmd := newRepoUpdateCmd(out)
if err = cmd.RunE(cmd, []string{"repo1"}); err != nil {
t.Fatal("expected to update repo1 correctly")
}
got := out.String()
if !strings.Contains(got, "Successfully got an update from the \"repo1\"") {
t.Errorf("Expected to successfully update \"repo1\" repository, got %q", got)
}
if strings.Contains(got, "Successfully got an update from the \"repo2\"") {
t.Errorf("Shouldn't have updated \"repo2\" repository, got %q", got)
}
if !strings.Contains(got, "Update Complete.") {
t.Error("Update was not successful")
}
}

@ -115,7 +115,7 @@ func (d *resetCmd) run() error {
}
if err := installer.Uninstall(d.kubeClient, &installer.Options{Namespace: d.namespace}); err != nil {
return fmt.Errorf("error unstalling Tiller: %s", err)
return fmt.Errorf("error uninstalling Tiller: %s", err)
}
if d.removeHelmHome {

@ -26,7 +26,7 @@ are recommended, and _should_ be placed onto a chart for global consistency. Tho
Name|Status|Description
-----|------|----------
`app.kubernetes.io/name` | REC | This should be the app name, reflecting the entire app. Usually `{{ template "name" . }}` is used for this. This is used by many Kubernetes manifests, and is not Helm-specific.
`helm.sh/chart` | REC | This should be the chart name and version: `{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}`.
`helm.sh/chart` | REC | This should be the chart name and version: `{{ .Chart.Name }}-{{ .Chart.Version \| replace "+" "_" }}`.
`app.kubernetes.io/managed-by` | REC | This should always be set to `{{ .Release.Service }}`. It is for finding all things managed by Tiller.
`app.kubernetes.io/instance` | REC | This should be the `{{ .Release.Name }}`. It aids in differentiating between different instances of the same application.
`app.kubernetes.io/version` | OPT | The version of the app and can be set to `{{ .Chart.AppVersion }}`.

@ -38,7 +38,7 @@ Building synchronization state...
Starting synchronization
Would copy file://fantastic-charts/alpine-0.1.0.tgz to gs://fantastic-charts/alpine-0.1.0.tgz
Would copy file://fantastic-charts/index.yaml to gs://fantastic-charts/index.yaml
Are you sure you would like to continue with these changes?? [y/N]} y
Are you sure you would like to continue with these changes? [y/N]} y
Building synchronization state...
Starting synchronization
Copying file://fantastic-charts/alpine-0.1.0.tgz [Content-Type=application/x-tar]...

@ -54,13 +54,13 @@ metadata:
name: {{ .Release.Name }}-configmap
data:
{{- $files := .Files }}
{{- range tuple "config1.toml" "config2.toml" "config3.toml" }}
{{- range list "config1.toml" "config2.toml" "config3.toml" }}
{{ . }}: |-
{{ $files.Get . }}
{{- end }}
```
This config map uses several of the techniques discussed in previous sections. For example, we create a `$files` variable to hold a reference to the `.Files` object. We also use the `tuple` function to create a list of files that we loop through. Then we print each file name (`{{.}}: |-`) followed by the contents of the file `{{ $files.Get . }}`.
This config map uses several of the techniques discussed in previous sections. For example, we create a `$files` variable to hold a reference to the `.Files` object. We also use the `list` function to create a list of files that we loop through. Then we print each file name (`{{.}}: |-`) followed by the contents of the file `{{ $files.Get . }}`.
Running this template will produce a single ConfigMap with the contents of all three files:

@ -1,6 +1,6 @@
# Built-in Objects
Objects are passed into a template from the template engine. And your code can pass objects around (we'll see examples when we look at the `with` and `range` statements). There are even a few ways to create new objects within your templates, like with the `tuple` function we'll see later.
Objects are passed into a template from the template engine. And your code can pass objects around (we'll see examples when we look at the `with` and `range` statements). There are even a few ways to create new objects within your templates, like with the `list` function we'll see later.
Objects can be simple, and have just one value. Or they can contain other objects or functions. For example. the `Release` object contains several objects (like `Release.Name`) and the `Files` object has a few functions.
@ -22,7 +22,7 @@ In the previous section, we use `{{.Release.Name}}` to insert the name of a rele
- `Files.GetBytes` is a function for getting the contents of a file as an array of bytes instead of as a string. This is useful for things like images.
- `Capabilities`: This provides information about what capabilities the Kubernetes cluster supports.
- `Capabilities.APIVersions` is a set of versions.
- `Capabilities.APIVersions.Has $version` indicates whether a version (`batch/v1`) is enabled on the cluster.
- `Capabilities.APIVersions.Has $version` indicates whether a version (e.g., `batch/v1`) or resource (e.g., `apps/v1/Deployment`) is available on the cluster. Note, resources were not available before Helm v2.15.
- `Capabilities.KubeVersion` provides a way to look up the Kubernetes version. It has the following values: `Major`, `Minor`, `GitVersion`, `GitCommit`, `GitTreeState`, `BuildDate`, `GoVersion`, `Compiler`, and `Platform`.
- `Capabilities.TillerVersion` provides a way to look up the Tiller version. It has the following values: `SemVer`, `GitCommit`, and `GitTreeState`.
- `Template`: Contains information about the current template that is being executed

@ -333,11 +333,11 @@ Now, in this example we've done something tricky. The `toppings: |-` line is dec
> The `|-` marker in YAML takes a multi-line string. This can be a useful technique for embedding big blocks of data inside of your manifests, as exemplified here.
Sometimes it's useful to be able to quickly make a list inside of your template, and then iterate over that list. Helm templates have a function to make this easy: `tuple`. In computer science, a tuple is a list-like collection of fixed size, but with arbitrary data types. This roughly conveys the way a `tuple` is used.
Sometimes it's useful to be able to quickly make a list inside of your template, and then iterate over that list. Helm templates have a function that's called just that: `list`.
```yaml
sizes: |-
{{- range tuple "small" "medium" "large" }}
{{- range list "small" "medium" "large" }}
- {{ . }}
{{- end }}
```
@ -351,4 +351,4 @@ The above will produce this:
- large
```
In addition to lists and tuples, `range` can be used to iterate over collections that have a key and a value (like a `map` or `dict`). We'll see how to do that in the next section when we introduce template variables.
In addition to lists, `range` can be used to iterate over collections that have a key and a value (like a `map` or `dict`). We'll see how to do that in the next section when we introduce template variables.

@ -159,7 +159,7 @@ Operators are implemented as functions that return a boolean value. To use `eq`,
{{ end }}
{{/* do not include the body of this if statement because unset variables evaluate to false and .Values.setVariable was negated with the not function. */}}
{{/* include the body of this if statement when the variable .Values.anUnsetVariable is set or .values.aSetVariable is not set */}}
{{ if or .Values.anUnsetVariable (not .Values.aSetVariable) }}
{{ ... }}
{{ end }}

@ -187,10 +187,10 @@ instead of `mychart-configmap`.
You can run `helm get manifest clunky-serval` to see the entire generated YAML.
At this point, we've seen templates at their most basic: YAML files that have template directives embedded in `{{` and `}}`. In the next part, we'll take a deeper look into templates. But before moving on, there's one quick trick that can make building templates faster: When you want to test the template rendering, but not actually install anything, you can use `helm install --debug --dry-run ./mychart`. This will send the chart to the Tiller server, which will render the templates. But instead of installing the chart, it will return the rendered template to you so you can see the output:
At this point, we've seen templates at their most basic: YAML files that have template directives embedded in `{{` and `}}`. In the next part, we'll take a deeper look into templates. But before moving on, there's one quick trick that can make building templates faster: When you want to test the template rendering, but not actually install anything, you can use `helm install ./mychart --debug --dry-run`. This will send the chart to the Tiller server, which will render the templates. But instead of installing the chart, it will return the rendered template to you so you can see the output:
```console
$ helm install --debug --dry-run ./mychart
$ helm install ./mychart --debug --dry-run
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/k8s.io/helm/_scratch/mychart
NAME: goodly-guppy

@ -302,7 +302,7 @@ In the above example all charts with the tag `front-end` would be disabled but s
`front-end` tag and `subchart1` will be enabled.
Since `subchart2` is tagged with `back-end` and that tag evaluates to `true`, `subchart2` will be
enabled. Also notes that although `subchart2` has a condition specified in `requirements.yaml`, there
enabled. Also note that although `subchart2` has a condition specified in `requirements.yaml`, there
is no corresponding path and value in the parent's values so that condition has no effect.
##### Using the CLI with Tags and Conditions
@ -479,7 +479,7 @@ Furthermore, A is dependent on chart B that creates objects
- replicaset "B-ReplicaSet"
- service "B-Service"
After installation/upgrade of chart A a single Helm release is created/modified. The release will
After installation/upgrade of chart A, a single Helm release is created/modified. The release will
create/update all of the above Kubernetes objects in the following order:
- A-Namespace

@ -203,6 +203,10 @@ You can choose one or more defined annotation values:
* `"hook-failed"` specifies Tiller should delete the hook if the hook failed during execution.
* `"before-hook-creation"` specifies Tiller should delete the previous hook before the new hook is launched.
By default Tiller will wait for 60 seconds for a deleted hook to no longer exist in the API server before timing out. This
behavior can be changed using the `helm.sh/hook-delete-timeout` annotation. The value is the number of seconds Tiller
should wait for the hook to be fully deleted. A value of 0 means Tiller does not wait at all.
### Defining a CRD with the `crd-install` Hook
Custom Resource Definitions (CRDs) are a special kind in Kubernetes. They provide

@ -103,7 +103,7 @@ helm init --canary-image
For developing on Tiller, it is sometimes more expedient to run Tiller locally
instead of packaging it into an image and running it in-cluster. You can do
this by telling the Helm client to us a local instance.
this by telling the Helm client to use a local instance.
```console
$ make build

@ -19,6 +19,10 @@ metadata:
app.kubernetes.io/name: {{ template "nginx.name" . }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ template "nginx.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
{{- if .Values.podAnnotations }}

@ -44,7 +44,7 @@ helm create NAME [flags]
```
-h, --help help for create
-p, --starter string The named Helm starter scaffold
-p, --starter string The name or absolute path to Helm starter scaffold
```
### Options inherited from parent commands
@ -63,4 +63,4 @@ helm create NAME [flags]
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 5-Jun-2019
###### Auto generated by spf13/cobra on 7-Jul-2019

@ -11,9 +11,16 @@ Information is cached locally, where it is used by commands like 'helm search'.
'helm update' is the deprecated form of 'helm repo update'. It will be removed in
future releases.
You can specify the name of a repository you want to update.
$ helm repo update <repo_name>
To update all the repositories, use 'helm repo update'.
```
helm repo update [flags]
helm repo update [REPO_NAME] [flags]
```
### Options
@ -39,4 +46,4 @@ helm repo update [flags]
* [helm repo](helm_repo.md) - Add, list, remove, update, and index chart repositories
###### Auto generated by spf13/cobra on 16-May-2019
###### Auto generated by spf13/cobra on 7-Jun-2019

@ -27,7 +27,7 @@ helm template [flags] CHART
-x, --execute stringArray Only execute the given templates
-h, --help help for template
--is-upgrade Set .Release.IsUpgrade instead of .Release.IsInstall
--kube-version string Kubernetes version used as Capabilities.KubeVersion.Major/Minor (default "1.9")
--kube-version string Kubernetes version used as Capabilities.KubeVersion.Major/Minor (default "1.14")
-n, --name string Release name (default "release-name")
--name-template string Specify template used to name the release
--namespace string Namespace to install the release into
@ -55,4 +55,4 @@ helm template [flags] CHART
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 16-May-2019
###### Auto generated by spf13/cobra on 17-Jun-2019

@ -30,7 +30,7 @@ The Snap package for Helm is maintained by
[Snapcrafters](https://github.com/snapcrafters/helm).
```
$ sudo snap install helm --classic
sudo snap install helm --classic
```
### From Homebrew (macOS)
@ -123,7 +123,7 @@ configured to talk to a remote Kubernetes cluster.
Most cloud providers enable a feature called Role-Based Access Control - RBAC for short. If your cloud provider enables this feature, you will need to create a service account for Tiller with the right roles and permissions to access resources.
Check the [Kubernetes Distribution Guide](kubernetes_distros.md) to see if there's any further points of interest on using Helm with your cloud provider. Also check out the guide on [Tiller and Role-Based Access Control](rbac.md) for more information on how to run Tiller in an RBAC-enabled Kubernetes cluster.
Check the [Kubernetes Distribution Guide](#kubernetes-distribution-guide) to see if there's any further points of interest on using Helm with your cloud provider. Also check out the guide on [Tiller and Role-Based Access Control](rbac.md) for more information on how to run Tiller in an RBAC-enabled Kubernetes cluster.
### Easy In-Cluster Installation

@ -22,6 +22,10 @@ Google's GKE hosted Kubernetes platform enables RBAC by default. You will need t
See [Tiller and role-based access control](https://docs.helm.sh/using_helm/#role-based-access-control) for more information.
## AKS
Helm works with [Azure Kubernetes Service](https://docs.microsoft.com/en-us/azure/aks/kubernetes-helm). If using an RBAC-enabled AKS cluster, you need [a service account and role binding for the Tiller service](https://docs.microsoft.com/en-us/azure/aks/kubernetes-helm#create-a-service-account).
## Ubuntu with 'kubeadm'
Kubernetes bootstrapped with `kubeadm` is known to work on the following Linux

@ -144,6 +144,11 @@ The defined command will be invoked with the following scheme:
repo definition, stored in `$HELM_HOME/repository/repositories.yaml`. Downloader
plugin is expected to dump the raw content to stdout and report errors on stderr.
The downloader command also supports sub-commands or arguments, allowing you to specify
for example `bin/mydownloader subcommand -d` in the `plugin.yaml`. This is useful
if you want to use the same executable for the main plugin command and the downloader
command, but with a different sub-command for each.
## Environment Variables
When Helm executes a plugin, it passes the outer environment to the plugin, and

@ -107,7 +107,7 @@ $HELM_HOME has been configured at /Users/awesome-user/.helm.
Tiller (the Helm server side component) has been installed into your Kubernetes Cluster.
$ helm install nginx --tiller-namespace tiller-world --namespace tiller-world
$ helm install stable/lamp --tiller-namespace tiller-world --namespace tiller-world
NAME: wayfaring-yak
LAST DEPLOYED: Mon Aug 7 16:00:16 2017
NAMESPACE: tiller-world

@ -14,7 +14,7 @@ or [pull request](https://github.com/helm/helm/pulls).
- [GitLab, Consumer Driven Contracts, Helm and Kubernetes](https://medium.com/@enxebre/gitlab-consumer-driven-contracts-helm-and-kubernetes-b7235a60a1cb#.xwp1y4tgi)
- [Honestbee's Helm Chart Conventions](https://gist.github.com/so0k/f927a4b60003cedd101a0911757c605a)
- [Releasing backward-incompatible changes: Kubernetes, Jenkins, Prometheus Operator, Helm and Traefik](https://medium.com/@enxebre/releasing-backward-incompatible-changes-kubernetes-jenkins-plugin-prometheus-operator-helm-self-6263ca61a1b1#.e0c7elxhq)
- [The Missing CI/CD Kubernetes Component: Helm package manager](https://hackernoon.com/the-missing-ci-cd-kubernetes-component-helm-package-manager-1fe002aac680#.691sk2zhu)
- [The Missing CI/CD Kubernetes Component: Helm package manager](https://medium.com/@gajus/the-missing-ci-cd-kubernetes-component-helm-package-manager-1fe002aac680)
- [Using Helm to Deploy to Kubernetes](https://daemonza.github.io/2017/02/20/using-helm-to-deploy-to-kubernetes/)
- [Writing a Helm Chart](https://www.influxdata.com/packaged-kubernetes-deployments-writing-helm-chart/)
- [A basic walk through Kubernetes Helm](https://github.com/muffin87/helm-tutorial)
@ -92,6 +92,7 @@ Tools layered on top of Helm or Tiller.
Platforms, distributions, and services that include Helm support.
- [Codefresh](https://codefresh.io/) - A CI/CD solution designed specifically for Docker/Kubernetes/Helm. Includes a private Helm repository and graphical dashboards for Helm charts, Helm releases and Helm environments.
- [Fabric8](https://fabric8.io) - Integrated development platform for Kubernetes
- [Jenkins X](https://jenkins-x.io/) - open source automated CI/CD for Kubernetes which uses Helm for [promoting](https://jenkins-x.io/about/features/#promotion) applications through [environments via GitOps](https://jenkins-x.io/about/features/#environments)
- [Kubernetic](https://kubernetic.com/) - Kubernetes Desktop Client

@ -86,6 +86,11 @@ If you do not have GPG already setup you can follow these steps:
3. [Add key to GitHub account](https://help.github.com/en/articles/adding-a-new-gpg-key-to-your-github-account)
4. [Set signing key in Git](https://help.github.com/en/articles/telling-git-about-your-signing-key)
Once you have a signing key you need to add it to the KEYS file at the root of
the repository. The instructions for adding it to the KEYS file are in the file.
If you have not done so already, you need to add your public key to the keyserver
network. If you use GnuPG you can follow the [instructions provided by Debian](https://debian-administration.org/article/451/Submitting_your_GPG_key_to_a_keyserver).
## 1. Create the Release Branch
### Major/Minor Releases

@ -312,6 +312,6 @@ If your tiller certificate has expired, you'll need to sign a new certificate, b
## References
https://github.com/denji/golang-tls
https://www.openssl.org/docs/
https://jamielinux.com/docs/openssl-certificate-authority/sign-server-and-client-certificates.html
- https://github.com/denji/golang-tls
- https://www.openssl.org/docs/
- https://jamielinux.com/docs/openssl-certificate-authority/sign-server-and-client-certificates.html

197
glide.lock generated

@ -1,11 +1,10 @@
hash: d633cc94d6f7fd656b85a64cd1eccffdeed7c45848369ce55ed9a4ae731dd843
updated: 2019-06-04T12:50:58.563587342-07:00
hash: 277f7be1b21149bc06b361fa61c0a2ff81a7f00c59a6e35c21b6516f6ddfd9f7
updated: 2019-07-03T21:59:06.87934+02:00
imports:
- name: cloud.google.com/go
version: 3b1ae45394a234c385be014e9a488f2bb6eef821
version: 0ebda48a7f143b1cce9eb37a8c1106ac762a3430
subpackages:
- compute/metadata
- internal
- name: github.com/asaskevich/govalidator
version: 7664702784775e51966f0885f5cd27435916517b
- name: github.com/Azure/go-ansiterm
@ -13,7 +12,7 @@ imports:
subpackages:
- winterm
- name: github.com/Azure/go-autorest
version: ea233b6412b0421a65dc6160e16c893364664a95
version: 1ffcc8896ef6dfe022d90a4317d866f925cf0f9e
subpackages:
- autorest
- autorest/adal
@ -22,7 +21,7 @@ imports:
- logger
- version
- name: github.com/beorn7/perks
version: 3ac7bf7a47d159a033b107610db8a1b6575507a4
version: 3a771d992973f24aa725d07868b467d1ddfceafb
subpackages:
- quantile
- name: github.com/BurntSushi/toml
@ -41,7 +40,7 @@ imports:
- name: github.com/cyphar/filepath-securejoin
version: a261ee33d7a517f054effbf451841abaafe3e0fd
- name: github.com/davecgh/go-spew
version: 782f4967f2dc4564575ca782fe2d04090b5faca8
version: 8991bc29aa16c548c550c7ff78260e27b9ab7c73
subpackages:
- spew
- name: github.com/dgrijalva/jwt-go
@ -52,32 +51,8 @@ imports:
- digestset
- reference
- name: github.com/docker/docker
version: a9fbbdc8dd8794b20af358382ab780559bca589d
subpackages:
- api
- api/types
- api/types/blkiodev
- api/types/container
- api/types/events
- api/types/filters
- api/types/image
- api/types/mount
- api/types/network
- api/types/registry
- api/types/strslice
- api/types/swarm
- api/types/swarm/runtime
- api/types/time
- api/types/versions
- api/types/volume
- client
- daemon/logger/jsonfilelog/jsonlog
- pkg/jsonmessage
- pkg/mount
- pkg/parsers
- pkg/parsers/operatingsystem
- pkg/stdcopy
- pkg/sysinfo
version: be7ac8be2ae072032a4005e8f232be3fc57e4127
subpackages:
- pkg/term
- pkg/term/windows
- name: github.com/docker/spdystream
@ -114,6 +89,8 @@ imports:
- syntax/lexer
- util/runes
- util/strings
- name: github.com/gofrs/flock
version: 392e7fae8f1b0bdbd67dad7237d23f618feb6dbb
- name: github.com/gogo/protobuf
version: 342cbe0a04158f6dcb03ca0079991a51a4248c02
subpackages:
@ -133,6 +110,14 @@ imports:
- ptypes/timestamp
- name: github.com/google/btree
version: 7d79101e329e5a3adf994758c578dab82b90c017
- name: github.com/google/go-cmp
version: 6f77996f0c42f7b84e5a2b252227263f93432e9b
subpackages:
- cmp
- cmp/internal/diff
- cmp/internal/flags
- cmp/internal/function
- cmp/internal/value
- name: github.com/google/gofuzz
version: 24818f796faf91cd76ec7bddd72458fbced7a6c1
- name: github.com/google/uuid
@ -179,6 +164,8 @@ imports:
- reflectx
- name: github.com/json-iterator/go
version: ab8a2e0c74be9d3be70b3184d9acc634935ded82
- name: github.com/konsorten/go-windows-terminal-sequences
version: 5c8c8bd35d3832f5d134ae1e1e375b69a4d25242
- name: github.com/lib/pq
version: 88edab0803230a3898347e77b474f8c1820a1f20
subpackages:
@ -186,7 +173,7 @@ imports:
- name: github.com/liggitt/tabwriter
version: 89fcab3d43de07060e4fd4c1547430ed57e87f24
- name: github.com/mailru/easyjson
version: 2f5df55504ebc322e4d52d34df6a1f5b503bf26d
version: 60711f1a8329503b04e1c88535f419d0bb440bff
subpackages:
- buffer
- jlexer
@ -198,7 +185,7 @@ imports:
- name: github.com/Masterminds/semver
version: c7af12943936e8c39859482e61f0574c2fd7fc75
- name: github.com/Masterminds/sprig
version: 9f8fceff796fb9f4e992cd2bece016be0121ab74
version: 258b00ffa7318e8b109a141349980ffbd30a35db
- name: github.com/Masterminds/vcs
version: 3084677c2c188840777bff30054f2b553729d329
- name: github.com/mattn/go-runewidth
@ -230,19 +217,21 @@ imports:
subpackages:
- go
- name: github.com/prometheus/common
version: cfeb6f9992ffa54aaa4f2170ade4067ee478b250
version: 4724e9255275ce38f7179b2478abeae4e28c904f
subpackages:
- expfmt
- internal/bitbucket.org/ww/goautoneg
- model
- name: github.com/prometheus/procfs
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
version: 1dc9a6cbc91aacc3e8b2d63db4d2e957a5394ac4
subpackages:
- internal/util
- nfs
- xfs
- name: github.com/PuerkitoBio/purell
version: 8a290539e2e8629dbc4e6bad948158f790ec31f4
version: 0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4
- name: github.com/PuerkitoBio/urlesc
version: 5bd2802263f21d8788851d5305584c82a5c75d7e
version: de5bf2ad457846296e2031421a34e2568e304e35
- name: github.com/rubenv/sql-migrate
version: 1007f53448d75fe14190968f5de4d95ed63ebb83
subpackages:
@ -252,9 +241,9 @@ imports:
- name: github.com/shurcooL/sanitized_anchor_name
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
- name: github.com/sirupsen/logrus
version: 89742aefa4b206dcf400792f3bd35b542998eb3b
version: bcd833dfe83d3cebad139e4a29ed79cb2318bf95
- name: github.com/spf13/cobra
version: fe5e611709b0c57fa4a89136deaa8e1d4004d053
version: f2b07da1e2c38d5f12845a4f607e2e1018cbb1f5
subpackages:
- doc
- name: github.com/spf13/pflag
@ -262,7 +251,7 @@ imports:
- name: github.com/technosophos/moniker
version: a5dbd03a2245d554160e3ae6bfdcf969fe58b431
- name: golang.org/x/crypto
version: de0752318171da717af4ce24d0a2e8626afaeb11
version: e84da0312774c21d64ee2317962ef669b27ffb41
subpackages:
- cast5
- ed25519
@ -289,7 +278,7 @@ imports:
- internal/timeseries
- trace
- name: golang.org/x/oauth2
version: a6bd8cefa1811bd24b86f8902872e4e8225f74c4
version: 9f3314589c9a9136388751d9adae6b0ed400978a
subpackages:
- google
- internal
@ -305,20 +294,15 @@ imports:
- unix
- windows
- name: golang.org/x/text
version: b19bf474d317b857955b12035d2c5acb57ce8b01
version: e6919f6577db79269a6443b9dc46d18f2238fb5d
subpackages:
- cases
- encoding
- encoding/internal
- encoding/internal/identifier
- encoding/unicode
- internal
- internal/tag
- internal/utf8internal
- language
- runes
- secure/bidirule
- secure/precis
- transform
- unicode/bidi
- unicode/norm
@ -328,7 +312,7 @@ imports:
subpackages:
- rate
- name: google.golang.org/appengine
version: 12d5545dc1cfa6047a286d5e853841b6471f4c19
version: 54a98f90d1c46b7731eb8fb305d2a321c30ef610
subpackages:
- internal
- internal/app_identity
@ -391,7 +375,7 @@ imports:
- name: gopkg.in/yaml.v2
version: 5420a8b6744d3b0345ab293f6fcba19c978f1183
- name: k8s.io/api
version: a675ac48af67cf21d815b5f8df288462096eb9c9
version: 7cf5895f2711098d7d9527db0a4a49fb0dff7de2
subpackages:
- admission/v1beta1
- admissionregistration/v1beta1
@ -432,13 +416,13 @@ imports:
- storage/v1alpha1
- storage/v1beta1
- name: k8s.io/apiextensions-apiserver
version: bf6753f2aa24fe1d69a2abeea1c106042bcf3f5f
version: 14e95df34f1f469647f494f5185a036e26fddcab
subpackages:
- pkg/apis/apiextensions
- pkg/apis/apiextensions/v1beta1
- pkg/features
- name: k8s.io/apimachinery
version: 6a84e37a896db9780c75367af8d2ed2bb944022e
version: 1799e75a07195de9460b8ef7300883499f12127b
subpackages:
- pkg/api/equality
- pkg/api/errors
@ -494,7 +478,7 @@ imports:
- third_party/forked/golang/netutil
- third_party/forked/golang/reflect
- name: k8s.io/apiserver
version: f89599b3f64533b7e94fa4d169acbc861b464f2e
version: 47dc9a115b1874c96c20cea91d02b36e4faa1bb1
subpackages:
- pkg/authentication/authenticator
- pkg/authentication/serviceaccount
@ -502,7 +486,7 @@ imports:
- pkg/features
- pkg/util/feature
- name: k8s.io/cli-runtime
version: 17bc0b7fcef59215541144136f75284656a789fb
version: 2090e6d8f84c1db3e23968b0ee97fb677b363fcf
subpackages:
- pkg/genericclioptions
- pkg/kustomize
@ -517,13 +501,66 @@ imports:
- pkg/printers
- pkg/resource
- name: k8s.io/client-go
version: ae8359b20417914b73a4b514b7a3d642597700bb
version: 78d2af792babf2dd937ba2e2a8d99c753a5eda89
subpackages:
- discovery
- discovery/cached/disk
- discovery/fake
- dynamic
- dynamic/dynamicinformer
- dynamic/dynamiclister
- dynamic/fake
- informers
- informers/admissionregistration
- informers/admissionregistration/v1beta1
- informers/apps
- informers/apps/v1
- informers/apps/v1beta1
- informers/apps/v1beta2
- informers/auditregistration
- informers/auditregistration/v1alpha1
- informers/autoscaling
- informers/autoscaling/v1
- informers/autoscaling/v2beta1
- informers/autoscaling/v2beta2
- informers/batch
- informers/batch/v1
- informers/batch/v1beta1
- informers/batch/v2alpha1
- informers/certificates
- informers/certificates/v1beta1
- informers/coordination
- informers/coordination/v1
- informers/coordination/v1beta1
- informers/core
- informers/core/v1
- informers/events
- informers/events/v1beta1
- informers/extensions
- informers/extensions/v1beta1
- informers/internalinterfaces
- informers/networking
- informers/networking/v1
- informers/networking/v1beta1
- informers/node
- informers/node/v1alpha1
- informers/node/v1beta1
- informers/policy
- informers/policy/v1beta1
- informers/rbac
- informers/rbac/v1
- informers/rbac/v1alpha1
- informers/rbac/v1beta1
- informers/scheduling
- informers/scheduling/v1
- informers/scheduling/v1alpha1
- informers/scheduling/v1beta1
- informers/settings
- informers/settings/v1alpha1
- informers/storage
- informers/storage/v1
- informers/storage/v1alpha1
- informers/storage/v1beta1
- kubernetes
- kubernetes/fake
- kubernetes/scheme
@ -599,6 +636,38 @@ imports:
- kubernetes/typed/storage/v1alpha1/fake
- kubernetes/typed/storage/v1beta1
- kubernetes/typed/storage/v1beta1/fake
- listers/admissionregistration/v1beta1
- listers/apps/v1
- listers/apps/v1beta1
- listers/apps/v1beta2
- listers/auditregistration/v1alpha1
- listers/autoscaling/v1
- listers/autoscaling/v2beta1
- listers/autoscaling/v2beta2
- listers/batch/v1
- listers/batch/v1beta1
- listers/batch/v2alpha1
- listers/certificates/v1beta1
- listers/coordination/v1
- listers/coordination/v1beta1
- listers/core/v1
- listers/events/v1beta1
- listers/extensions/v1beta1
- listers/networking/v1
- listers/networking/v1beta1
- listers/node/v1alpha1
- listers/node/v1beta1
- listers/policy/v1beta1
- listers/rbac/v1
- listers/rbac/v1alpha1
- listers/rbac/v1beta1
- listers/scheduling/v1
- listers/scheduling/v1alpha1
- listers/scheduling/v1beta1
- listers/settings/v1alpha1
- listers/storage/v1
- listers/storage/v1alpha1
- listers/storage/v1beta1
- pkg/apis/clientauthentication
- pkg/apis/clientauthentication/v1alpha1
- pkg/apis/clientauthentication/v1beta1
@ -647,12 +716,12 @@ imports:
- util/jsonpath
- util/keyutil
- util/retry
- name: k8s.io/cloud-provider
version: 9c9d72d1bf90eb62005f5112f3eea019b272c44b
- name: k8s.io/component-base
version: 185d68e6e6ea654214f444cab8f645ec3af3092e
subpackages:
- features
- featuregate
- name: k8s.io/klog
version: 8e90cee79f823779174776412c13478955131846
version: 89e63fd5117f8c20208186ef85f096703a280c20
- name: k8s.io/kube-openapi
version: b3a7cee44a305be0a69e1b9ac03018307287e1b0
subpackages:
@ -661,7 +730,7 @@ imports:
- pkg/util/proto/testing
- pkg/util/proto/validation
- name: k8s.io/kubernetes
version: 66049e3b21efe110454d67df4fa62b08ea79a19b
version: e8462b5b5dc2584fdcd18e6bcfe9f1e4d970a529
subpackages:
- pkg/api/legacyscheme
- pkg/api/service
@ -756,6 +825,7 @@ imports:
- pkg/kubectl/util/event
- pkg/kubectl/util/fieldpath
- pkg/kubectl/util/i18n
- pkg/kubectl/util/interrupt
- pkg/kubectl/util/podutils
- pkg/kubectl/util/printers
- pkg/kubectl/util/qos
@ -766,6 +836,7 @@ imports:
- pkg/kubectl/util/templates
- pkg/kubectl/util/term
- pkg/kubectl/validation
- pkg/kubectl/version
- pkg/kubelet/types
- pkg/master/ports
- pkg/printers
@ -773,12 +844,10 @@ imports:
- pkg/security/apparmor
- pkg/serviceaccount
- pkg/util/hash
- pkg/util/interrupt
- pkg/util/labels
- pkg/util/node
- pkg/util/parsers
- pkg/util/taints
- pkg/version
- name: k8s.io/utils
version: c2654d5206da6b7b6ace12841e8f359bb89b443c
subpackages:
@ -824,7 +893,7 @@ testImports:
- name: github.com/DATA-DOG/go-sqlmock
version: 472e287dbafe67e526a3797165b64cb14f34705a
- name: github.com/pmezard/go-difflib
version: 5d4384ee4fb2527b0a1256a821ebfc92f91efefc
version: 792786c7400a136282c1664665ae0a8db921c6c2
subpackages:
- difflib
- name: github.com/stretchr/testify

@ -12,14 +12,14 @@ import:
- unix
- windows
- package: github.com/spf13/cobra
version: fe5e611709b0c57fa4a89136deaa8e1d4004d053
version: ^0.0.4
- package: github.com/spf13/pflag
version: ~1.0.1
- package: github.com/Masterminds/vcs
- package: github.com/imdario/mergo
version: v0.3.5
- package: github.com/Masterminds/sprig
version: ^2.19.0
version: ^2.20.0
- package: github.com/ghodss/yaml
- package: github.com/Masterminds/semver
version: ~1.4.2
@ -49,24 +49,26 @@ import:
version: 0.9.2
- package: github.com/grpc-ecosystem/go-grpc-prometheus
- package: k8s.io/kubernetes
version: v1.14.2
version: v1.15.0
- package: k8s.io/client-go
version: kubernetes-1.14.2
version: kubernetes-1.15.0
- package: k8s.io/api
version: kubernetes-1.14.2
version: kubernetes-1.15.0
- package: k8s.io/apimachinery
version: kubernetes-1.14.2
version: kubernetes-1.15.0
- package: k8s.io/apiserver
version: kubernetes-1.14.2
version: kubernetes-1.15.0
- package: k8s.io/cli-runtime
version: kubernetes-1.14.2
version: kubernetes-1.15.0
- package: k8s.io/apiextensions-apiserver
version: kubernetes-1.14.2
version: kubernetes-1.15.0
- package: github.com/cyphar/filepath-securejoin
version: ^0.2.1
- package: github.com/jmoiron/sqlx
version: ^1.2.0
- package: github.com/rubenv/sql-migrate
- package: github.com/gofrs/flock
version: v0.7.1
testImports:
- package: github.com/stretchr/testify

@ -12,6 +12,7 @@ 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.
*/
//go:generate go run generator/capabilities_default_versions_generate.go
package chartutil
@ -24,14 +25,15 @@ import (
)
var (
// DefaultVersionSet is the default version set, which includes only Core V1 ("v1").
DefaultVersionSet = NewVersionSet("v1")
// DefaultVersionSet is the default version set in included in Kubernetes for workloads
// Default versions as of Kubernetes 1.14
DefaultVersionSet = NewVersionSet(defaultVersions()...)
// DefaultKubeVersion is the default kubernetes version
DefaultKubeVersion = &version.Info{
Major: "1",
Minor: "9",
GitVersion: "v1.9.0",
Minor: "14",
GitVersion: "v1.14.0",
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),

@ -38,9 +38,6 @@ func TestDefaultVersionSet(t *testing.T) {
if !DefaultVersionSet.Has("v1") {
t.Error("Expected core v1 version set")
}
if d := len(DefaultVersionSet); d != 1 {
t.Errorf("Expected only one version, got %d", d)
}
}
func TestCapabilities(t *testing.T) {
@ -51,4 +48,8 @@ func TestCapabilities(t *testing.T) {
if !cap.APIVersions.Has("v1") {
t.Error("APIVersions should have v1")
}
if !cap.APIVersions.Has("apps/v1/Deployment") {
t.Error("APIVersions should have apps/v1/Deployment")
}
}

@ -0,0 +1,575 @@
/*
Copyright The Helm 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.
*/
// Code generated by capabilities_default_versions_generate.go; DO NOT EDIT.
package chartutil
func defaultVersions() []string {
return []string{
"__internal",
"__internal/WatchEvent",
"admissionregistration.k8s.io/__internal",
"admissionregistration.k8s.io/__internal/WatchEvent",
"admissionregistration.k8s.io/v1beta1",
"admissionregistration.k8s.io/v1beta1/CreateOptions",
"admissionregistration.k8s.io/v1beta1/DeleteOptions",
"admissionregistration.k8s.io/v1beta1/ExportOptions",
"admissionregistration.k8s.io/v1beta1/GetOptions",
"admissionregistration.k8s.io/v1beta1/ListOptions",
"admissionregistration.k8s.io/v1beta1/MutatingWebhookConfiguration",
"admissionregistration.k8s.io/v1beta1/MutatingWebhookConfigurationList",
"admissionregistration.k8s.io/v1beta1/PatchOptions",
"admissionregistration.k8s.io/v1beta1/UpdateOptions",
"admissionregistration.k8s.io/v1beta1/ValidatingWebhookConfiguration",
"admissionregistration.k8s.io/v1beta1/ValidatingWebhookConfigurationList",
"admissionregistration.k8s.io/v1beta1/WatchEvent",
"apps/__internal",
"apps/__internal/WatchEvent",
"apps/v1",
"apps/v1/ControllerRevision",
"apps/v1/ControllerRevisionList",
"apps/v1/CreateOptions",
"apps/v1/DaemonSet",
"apps/v1/DaemonSetList",
"apps/v1/DeleteOptions",
"apps/v1/Deployment",
"apps/v1/DeploymentList",
"apps/v1/ExportOptions",
"apps/v1/GetOptions",
"apps/v1/ListOptions",
"apps/v1/PatchOptions",
"apps/v1/ReplicaSet",
"apps/v1/ReplicaSetList",
"apps/v1/StatefulSet",
"apps/v1/StatefulSetList",
"apps/v1/UpdateOptions",
"apps/v1/WatchEvent",
"apps/v1beta1",
"apps/v1beta1/ControllerRevision",
"apps/v1beta1/ControllerRevisionList",
"apps/v1beta1/CreateOptions",
"apps/v1beta1/DeleteOptions",
"apps/v1beta1/Deployment",
"apps/v1beta1/DeploymentList",
"apps/v1beta1/DeploymentRollback",
"apps/v1beta1/ExportOptions",
"apps/v1beta1/GetOptions",
"apps/v1beta1/ListOptions",
"apps/v1beta1/PatchOptions",
"apps/v1beta1/Scale",
"apps/v1beta1/StatefulSet",
"apps/v1beta1/StatefulSetList",
"apps/v1beta1/UpdateOptions",
"apps/v1beta1/WatchEvent",
"apps/v1beta2",
"apps/v1beta2/ControllerRevision",
"apps/v1beta2/ControllerRevisionList",
"apps/v1beta2/CreateOptions",
"apps/v1beta2/DaemonSet",
"apps/v1beta2/DaemonSetList",
"apps/v1beta2/DeleteOptions",
"apps/v1beta2/Deployment",
"apps/v1beta2/DeploymentList",
"apps/v1beta2/ExportOptions",
"apps/v1beta2/GetOptions",
"apps/v1beta2/ListOptions",
"apps/v1beta2/PatchOptions",
"apps/v1beta2/ReplicaSet",
"apps/v1beta2/ReplicaSetList",
"apps/v1beta2/Scale",
"apps/v1beta2/StatefulSet",
"apps/v1beta2/StatefulSetList",
"apps/v1beta2/UpdateOptions",
"apps/v1beta2/WatchEvent",
"auditregistration.k8s.io/__internal",
"auditregistration.k8s.io/__internal/WatchEvent",
"auditregistration.k8s.io/v1alpha1",
"auditregistration.k8s.io/v1alpha1/AuditSink",
"auditregistration.k8s.io/v1alpha1/AuditSinkList",
"auditregistration.k8s.io/v1alpha1/CreateOptions",
"auditregistration.k8s.io/v1alpha1/DeleteOptions",
"auditregistration.k8s.io/v1alpha1/ExportOptions",
"auditregistration.k8s.io/v1alpha1/GetOptions",
"auditregistration.k8s.io/v1alpha1/ListOptions",
"auditregistration.k8s.io/v1alpha1/PatchOptions",
"auditregistration.k8s.io/v1alpha1/UpdateOptions",
"auditregistration.k8s.io/v1alpha1/WatchEvent",
"authentication.k8s.io/__internal",
"authentication.k8s.io/__internal/WatchEvent",
"authentication.k8s.io/v1",
"authentication.k8s.io/v1/CreateOptions",
"authentication.k8s.io/v1/DeleteOptions",
"authentication.k8s.io/v1/ExportOptions",
"authentication.k8s.io/v1/GetOptions",
"authentication.k8s.io/v1/ListOptions",
"authentication.k8s.io/v1/PatchOptions",
"authentication.k8s.io/v1/TokenRequest",
"authentication.k8s.io/v1/TokenReview",
"authentication.k8s.io/v1/UpdateOptions",
"authentication.k8s.io/v1/WatchEvent",
"authentication.k8s.io/v1beta1",
"authentication.k8s.io/v1beta1/CreateOptions",
"authentication.k8s.io/v1beta1/DeleteOptions",
"authentication.k8s.io/v1beta1/ExportOptions",
"authentication.k8s.io/v1beta1/GetOptions",
"authentication.k8s.io/v1beta1/ListOptions",
"authentication.k8s.io/v1beta1/PatchOptions",
"authentication.k8s.io/v1beta1/TokenReview",
"authentication.k8s.io/v1beta1/UpdateOptions",
"authentication.k8s.io/v1beta1/WatchEvent",
"authorization.k8s.io/__internal",
"authorization.k8s.io/__internal/WatchEvent",
"authorization.k8s.io/v1",
"authorization.k8s.io/v1/CreateOptions",
"authorization.k8s.io/v1/DeleteOptions",
"authorization.k8s.io/v1/ExportOptions",
"authorization.k8s.io/v1/GetOptions",
"authorization.k8s.io/v1/ListOptions",
"authorization.k8s.io/v1/LocalSubjectAccessReview",
"authorization.k8s.io/v1/PatchOptions",
"authorization.k8s.io/v1/SelfSubjectAccessReview",
"authorization.k8s.io/v1/SelfSubjectRulesReview",
"authorization.k8s.io/v1/SubjectAccessReview",
"authorization.k8s.io/v1/UpdateOptions",
"authorization.k8s.io/v1/WatchEvent",
"authorization.k8s.io/v1beta1",
"authorization.k8s.io/v1beta1/CreateOptions",
"authorization.k8s.io/v1beta1/DeleteOptions",
"authorization.k8s.io/v1beta1/ExportOptions",
"authorization.k8s.io/v1beta1/GetOptions",
"authorization.k8s.io/v1beta1/ListOptions",
"authorization.k8s.io/v1beta1/LocalSubjectAccessReview",
"authorization.k8s.io/v1beta1/PatchOptions",
"authorization.k8s.io/v1beta1/SelfSubjectAccessReview",
"authorization.k8s.io/v1beta1/SelfSubjectRulesReview",
"authorization.k8s.io/v1beta1/SubjectAccessReview",
"authorization.k8s.io/v1beta1/UpdateOptions",
"authorization.k8s.io/v1beta1/WatchEvent",
"autoscaling/__internal",
"autoscaling/__internal/WatchEvent",
"autoscaling/v1",
"autoscaling/v1/CreateOptions",
"autoscaling/v1/DeleteOptions",
"autoscaling/v1/ExportOptions",
"autoscaling/v1/GetOptions",
"autoscaling/v1/HorizontalPodAutoscaler",
"autoscaling/v1/HorizontalPodAutoscalerList",
"autoscaling/v1/ListOptions",
"autoscaling/v1/PatchOptions",
"autoscaling/v1/Scale",
"autoscaling/v1/UpdateOptions",
"autoscaling/v1/WatchEvent",
"autoscaling/v2beta1",
"autoscaling/v2beta1/CreateOptions",
"autoscaling/v2beta1/DeleteOptions",
"autoscaling/v2beta1/ExportOptions",
"autoscaling/v2beta1/GetOptions",
"autoscaling/v2beta1/HorizontalPodAutoscaler",
"autoscaling/v2beta1/HorizontalPodAutoscalerList",
"autoscaling/v2beta1/ListOptions",
"autoscaling/v2beta1/PatchOptions",
"autoscaling/v2beta1/UpdateOptions",
"autoscaling/v2beta1/WatchEvent",
"autoscaling/v2beta2",
"autoscaling/v2beta2/CreateOptions",
"autoscaling/v2beta2/DeleteOptions",
"autoscaling/v2beta2/ExportOptions",
"autoscaling/v2beta2/GetOptions",
"autoscaling/v2beta2/HorizontalPodAutoscaler",
"autoscaling/v2beta2/HorizontalPodAutoscalerList",
"autoscaling/v2beta2/ListOptions",
"autoscaling/v2beta2/PatchOptions",
"autoscaling/v2beta2/UpdateOptions",
"autoscaling/v2beta2/WatchEvent",
"batch/__internal",
"batch/__internal/WatchEvent",
"batch/v1",
"batch/v1/CreateOptions",
"batch/v1/DeleteOptions",
"batch/v1/ExportOptions",
"batch/v1/GetOptions",
"batch/v1/Job",
"batch/v1/JobList",
"batch/v1/ListOptions",
"batch/v1/PatchOptions",
"batch/v1/UpdateOptions",
"batch/v1/WatchEvent",
"batch/v1beta1",
"batch/v1beta1/CreateOptions",
"batch/v1beta1/CronJob",
"batch/v1beta1/CronJobList",
"batch/v1beta1/DeleteOptions",
"batch/v1beta1/ExportOptions",
"batch/v1beta1/GetOptions",
"batch/v1beta1/JobTemplate",
"batch/v1beta1/ListOptions",
"batch/v1beta1/PatchOptions",
"batch/v1beta1/UpdateOptions",
"batch/v1beta1/WatchEvent",
"batch/v2alpha1",
"batch/v2alpha1/CreateOptions",
"batch/v2alpha1/CronJob",
"batch/v2alpha1/CronJobList",
"batch/v2alpha1/DeleteOptions",
"batch/v2alpha1/ExportOptions",
"batch/v2alpha1/GetOptions",
"batch/v2alpha1/JobTemplate",
"batch/v2alpha1/ListOptions",
"batch/v2alpha1/PatchOptions",
"batch/v2alpha1/UpdateOptions",
"batch/v2alpha1/WatchEvent",
"certificates.k8s.io/__internal",
"certificates.k8s.io/__internal/WatchEvent",
"certificates.k8s.io/v1beta1",
"certificates.k8s.io/v1beta1/CertificateSigningRequest",
"certificates.k8s.io/v1beta1/CertificateSigningRequestList",
"certificates.k8s.io/v1beta1/CreateOptions",
"certificates.k8s.io/v1beta1/DeleteOptions",
"certificates.k8s.io/v1beta1/ExportOptions",
"certificates.k8s.io/v1beta1/GetOptions",
"certificates.k8s.io/v1beta1/ListOptions",
"certificates.k8s.io/v1beta1/PatchOptions",
"certificates.k8s.io/v1beta1/UpdateOptions",
"certificates.k8s.io/v1beta1/WatchEvent",
"coordination.k8s.io/__internal",
"coordination.k8s.io/__internal/WatchEvent",
"coordination.k8s.io/v1",
"coordination.k8s.io/v1/CreateOptions",
"coordination.k8s.io/v1/DeleteOptions",
"coordination.k8s.io/v1/ExportOptions",
"coordination.k8s.io/v1/GetOptions",
"coordination.k8s.io/v1/Lease",
"coordination.k8s.io/v1/LeaseList",
"coordination.k8s.io/v1/ListOptions",
"coordination.k8s.io/v1/PatchOptions",
"coordination.k8s.io/v1/UpdateOptions",
"coordination.k8s.io/v1/WatchEvent",
"coordination.k8s.io/v1beta1",
"coordination.k8s.io/v1beta1/CreateOptions",
"coordination.k8s.io/v1beta1/DeleteOptions",
"coordination.k8s.io/v1beta1/ExportOptions",
"coordination.k8s.io/v1beta1/GetOptions",
"coordination.k8s.io/v1beta1/Lease",
"coordination.k8s.io/v1beta1/LeaseList",
"coordination.k8s.io/v1beta1/ListOptions",
"coordination.k8s.io/v1beta1/PatchOptions",
"coordination.k8s.io/v1beta1/UpdateOptions",
"coordination.k8s.io/v1beta1/WatchEvent",
"events.k8s.io/__internal",
"events.k8s.io/__internal/WatchEvent",
"events.k8s.io/v1beta1",
"events.k8s.io/v1beta1/CreateOptions",
"events.k8s.io/v1beta1/DeleteOptions",
"events.k8s.io/v1beta1/Event",
"events.k8s.io/v1beta1/EventList",
"events.k8s.io/v1beta1/ExportOptions",
"events.k8s.io/v1beta1/GetOptions",
"events.k8s.io/v1beta1/ListOptions",
"events.k8s.io/v1beta1/PatchOptions",
"events.k8s.io/v1beta1/UpdateOptions",
"events.k8s.io/v1beta1/WatchEvent",
"extensions/__internal",
"extensions/__internal/WatchEvent",
"extensions/v1beta1",
"extensions/v1beta1/CreateOptions",
"extensions/v1beta1/DaemonSet",
"extensions/v1beta1/DaemonSetList",
"extensions/v1beta1/DeleteOptions",
"extensions/v1beta1/Deployment",
"extensions/v1beta1/DeploymentList",
"extensions/v1beta1/DeploymentRollback",
"extensions/v1beta1/ExportOptions",
"extensions/v1beta1/GetOptions",
"extensions/v1beta1/Ingress",
"extensions/v1beta1/IngressList",
"extensions/v1beta1/ListOptions",
"extensions/v1beta1/NetworkPolicy",
"extensions/v1beta1/NetworkPolicyList",
"extensions/v1beta1/PatchOptions",
"extensions/v1beta1/PodSecurityPolicy",
"extensions/v1beta1/PodSecurityPolicyList",
"extensions/v1beta1/ReplicaSet",
"extensions/v1beta1/ReplicaSetList",
"extensions/v1beta1/ReplicationControllerDummy",
"extensions/v1beta1/Scale",
"extensions/v1beta1/UpdateOptions",
"extensions/v1beta1/WatchEvent",
"networking.k8s.io/__internal",
"networking.k8s.io/__internal/WatchEvent",
"networking.k8s.io/v1",
"networking.k8s.io/v1/CreateOptions",
"networking.k8s.io/v1/DeleteOptions",
"networking.k8s.io/v1/ExportOptions",
"networking.k8s.io/v1/GetOptions",
"networking.k8s.io/v1/ListOptions",
"networking.k8s.io/v1/NetworkPolicy",
"networking.k8s.io/v1/NetworkPolicyList",
"networking.k8s.io/v1/PatchOptions",
"networking.k8s.io/v1/UpdateOptions",
"networking.k8s.io/v1/WatchEvent",
"networking.k8s.io/v1beta1",
"networking.k8s.io/v1beta1/CreateOptions",
"networking.k8s.io/v1beta1/DeleteOptions",
"networking.k8s.io/v1beta1/ExportOptions",
"networking.k8s.io/v1beta1/GetOptions",
"networking.k8s.io/v1beta1/Ingress",
"networking.k8s.io/v1beta1/IngressList",
"networking.k8s.io/v1beta1/ListOptions",
"networking.k8s.io/v1beta1/PatchOptions",
"networking.k8s.io/v1beta1/UpdateOptions",
"networking.k8s.io/v1beta1/WatchEvent",
"node.k8s.io/__internal",
"node.k8s.io/__internal/WatchEvent",
"node.k8s.io/v1alpha1",
"node.k8s.io/v1alpha1/CreateOptions",
"node.k8s.io/v1alpha1/DeleteOptions",
"node.k8s.io/v1alpha1/ExportOptions",
"node.k8s.io/v1alpha1/GetOptions",
"node.k8s.io/v1alpha1/ListOptions",
"node.k8s.io/v1alpha1/PatchOptions",
"node.k8s.io/v1alpha1/RuntimeClass",
"node.k8s.io/v1alpha1/RuntimeClassList",
"node.k8s.io/v1alpha1/UpdateOptions",
"node.k8s.io/v1alpha1/WatchEvent",
"node.k8s.io/v1beta1",
"node.k8s.io/v1beta1/CreateOptions",
"node.k8s.io/v1beta1/DeleteOptions",
"node.k8s.io/v1beta1/ExportOptions",
"node.k8s.io/v1beta1/GetOptions",
"node.k8s.io/v1beta1/ListOptions",
"node.k8s.io/v1beta1/PatchOptions",
"node.k8s.io/v1beta1/RuntimeClass",
"node.k8s.io/v1beta1/RuntimeClassList",
"node.k8s.io/v1beta1/UpdateOptions",
"node.k8s.io/v1beta1/WatchEvent",
"policy/__internal",
"policy/__internal/WatchEvent",
"policy/v1beta1",
"policy/v1beta1/CreateOptions",
"policy/v1beta1/DeleteOptions",
"policy/v1beta1/Eviction",
"policy/v1beta1/ExportOptions",
"policy/v1beta1/GetOptions",
"policy/v1beta1/ListOptions",
"policy/v1beta1/PatchOptions",
"policy/v1beta1/PodDisruptionBudget",
"policy/v1beta1/PodDisruptionBudgetList",
"policy/v1beta1/PodSecurityPolicy",
"policy/v1beta1/PodSecurityPolicyList",
"policy/v1beta1/UpdateOptions",
"policy/v1beta1/WatchEvent",
"rbac.authorization.k8s.io/__internal",
"rbac.authorization.k8s.io/__internal/WatchEvent",
"rbac.authorization.k8s.io/v1",
"rbac.authorization.k8s.io/v1/ClusterRole",
"rbac.authorization.k8s.io/v1/ClusterRoleBinding",
"rbac.authorization.k8s.io/v1/ClusterRoleBindingList",
"rbac.authorization.k8s.io/v1/ClusterRoleList",
"rbac.authorization.k8s.io/v1/CreateOptions",
"rbac.authorization.k8s.io/v1/DeleteOptions",
"rbac.authorization.k8s.io/v1/ExportOptions",
"rbac.authorization.k8s.io/v1/GetOptions",
"rbac.authorization.k8s.io/v1/ListOptions",
"rbac.authorization.k8s.io/v1/PatchOptions",
"rbac.authorization.k8s.io/v1/Role",
"rbac.authorization.k8s.io/v1/RoleBinding",
"rbac.authorization.k8s.io/v1/RoleBindingList",
"rbac.authorization.k8s.io/v1/RoleList",
"rbac.authorization.k8s.io/v1/UpdateOptions",
"rbac.authorization.k8s.io/v1/WatchEvent",
"rbac.authorization.k8s.io/v1alpha1",
"rbac.authorization.k8s.io/v1alpha1/ClusterRole",
"rbac.authorization.k8s.io/v1alpha1/ClusterRoleBinding",
"rbac.authorization.k8s.io/v1alpha1/ClusterRoleBindingList",
"rbac.authorization.k8s.io/v1alpha1/ClusterRoleList",
"rbac.authorization.k8s.io/v1alpha1/CreateOptions",
"rbac.authorization.k8s.io/v1alpha1/DeleteOptions",
"rbac.authorization.k8s.io/v1alpha1/ExportOptions",
"rbac.authorization.k8s.io/v1alpha1/GetOptions",
"rbac.authorization.k8s.io/v1alpha1/ListOptions",
"rbac.authorization.k8s.io/v1alpha1/PatchOptions",
"rbac.authorization.k8s.io/v1alpha1/Role",
"rbac.authorization.k8s.io/v1alpha1/RoleBinding",
"rbac.authorization.k8s.io/v1alpha1/RoleBindingList",
"rbac.authorization.k8s.io/v1alpha1/RoleList",
"rbac.authorization.k8s.io/v1alpha1/UpdateOptions",
"rbac.authorization.k8s.io/v1alpha1/WatchEvent",
"rbac.authorization.k8s.io/v1beta1",
"rbac.authorization.k8s.io/v1beta1/ClusterRole",
"rbac.authorization.k8s.io/v1beta1/ClusterRoleBinding",
"rbac.authorization.k8s.io/v1beta1/ClusterRoleBindingList",
"rbac.authorization.k8s.io/v1beta1/ClusterRoleList",
"rbac.authorization.k8s.io/v1beta1/CreateOptions",
"rbac.authorization.k8s.io/v1beta1/DeleteOptions",
"rbac.authorization.k8s.io/v1beta1/ExportOptions",
"rbac.authorization.k8s.io/v1beta1/GetOptions",
"rbac.authorization.k8s.io/v1beta1/ListOptions",
"rbac.authorization.k8s.io/v1beta1/PatchOptions",
"rbac.authorization.k8s.io/v1beta1/Role",
"rbac.authorization.k8s.io/v1beta1/RoleBinding",
"rbac.authorization.k8s.io/v1beta1/RoleBindingList",
"rbac.authorization.k8s.io/v1beta1/RoleList",
"rbac.authorization.k8s.io/v1beta1/UpdateOptions",
"rbac.authorization.k8s.io/v1beta1/WatchEvent",
"scheduling.k8s.io/__internal",
"scheduling.k8s.io/__internal/WatchEvent",
"scheduling.k8s.io/v1",
"scheduling.k8s.io/v1/CreateOptions",
"scheduling.k8s.io/v1/DeleteOptions",
"scheduling.k8s.io/v1/ExportOptions",
"scheduling.k8s.io/v1/GetOptions",
"scheduling.k8s.io/v1/ListOptions",
"scheduling.k8s.io/v1/PatchOptions",
"scheduling.k8s.io/v1/PriorityClass",
"scheduling.k8s.io/v1/PriorityClassList",
"scheduling.k8s.io/v1/UpdateOptions",
"scheduling.k8s.io/v1/WatchEvent",
"scheduling.k8s.io/v1alpha1",
"scheduling.k8s.io/v1alpha1/CreateOptions",
"scheduling.k8s.io/v1alpha1/DeleteOptions",
"scheduling.k8s.io/v1alpha1/ExportOptions",
"scheduling.k8s.io/v1alpha1/GetOptions",
"scheduling.k8s.io/v1alpha1/ListOptions",
"scheduling.k8s.io/v1alpha1/PatchOptions",
"scheduling.k8s.io/v1alpha1/PriorityClass",
"scheduling.k8s.io/v1alpha1/PriorityClassList",
"scheduling.k8s.io/v1alpha1/UpdateOptions",
"scheduling.k8s.io/v1alpha1/WatchEvent",
"scheduling.k8s.io/v1beta1",
"scheduling.k8s.io/v1beta1/CreateOptions",
"scheduling.k8s.io/v1beta1/DeleteOptions",
"scheduling.k8s.io/v1beta1/ExportOptions",
"scheduling.k8s.io/v1beta1/GetOptions",
"scheduling.k8s.io/v1beta1/ListOptions",
"scheduling.k8s.io/v1beta1/PatchOptions",
"scheduling.k8s.io/v1beta1/PriorityClass",
"scheduling.k8s.io/v1beta1/PriorityClassList",
"scheduling.k8s.io/v1beta1/UpdateOptions",
"scheduling.k8s.io/v1beta1/WatchEvent",
"settings.k8s.io/__internal",
"settings.k8s.io/__internal/WatchEvent",
"settings.k8s.io/v1alpha1",
"settings.k8s.io/v1alpha1/CreateOptions",
"settings.k8s.io/v1alpha1/DeleteOptions",
"settings.k8s.io/v1alpha1/ExportOptions",
"settings.k8s.io/v1alpha1/GetOptions",
"settings.k8s.io/v1alpha1/ListOptions",
"settings.k8s.io/v1alpha1/PatchOptions",
"settings.k8s.io/v1alpha1/PodPreset",
"settings.k8s.io/v1alpha1/PodPresetList",
"settings.k8s.io/v1alpha1/UpdateOptions",
"settings.k8s.io/v1alpha1/WatchEvent",
"storage.k8s.io/__internal",
"storage.k8s.io/__internal/WatchEvent",
"storage.k8s.io/v1",
"storage.k8s.io/v1/CreateOptions",
"storage.k8s.io/v1/DeleteOptions",
"storage.k8s.io/v1/ExportOptions",
"storage.k8s.io/v1/GetOptions",
"storage.k8s.io/v1/ListOptions",
"storage.k8s.io/v1/PatchOptions",
"storage.k8s.io/v1/StorageClass",
"storage.k8s.io/v1/StorageClassList",
"storage.k8s.io/v1/UpdateOptions",
"storage.k8s.io/v1/VolumeAttachment",
"storage.k8s.io/v1/VolumeAttachmentList",
"storage.k8s.io/v1/WatchEvent",
"storage.k8s.io/v1alpha1",
"storage.k8s.io/v1alpha1/CreateOptions",
"storage.k8s.io/v1alpha1/DeleteOptions",
"storage.k8s.io/v1alpha1/ExportOptions",
"storage.k8s.io/v1alpha1/GetOptions",
"storage.k8s.io/v1alpha1/ListOptions",
"storage.k8s.io/v1alpha1/PatchOptions",
"storage.k8s.io/v1alpha1/UpdateOptions",
"storage.k8s.io/v1alpha1/VolumeAttachment",
"storage.k8s.io/v1alpha1/VolumeAttachmentList",
"storage.k8s.io/v1alpha1/WatchEvent",
"storage.k8s.io/v1beta1",
"storage.k8s.io/v1beta1/CSIDriver",
"storage.k8s.io/v1beta1/CSIDriverList",
"storage.k8s.io/v1beta1/CSINode",
"storage.k8s.io/v1beta1/CSINodeList",
"storage.k8s.io/v1beta1/CreateOptions",
"storage.k8s.io/v1beta1/DeleteOptions",
"storage.k8s.io/v1beta1/ExportOptions",
"storage.k8s.io/v1beta1/GetOptions",
"storage.k8s.io/v1beta1/ListOptions",
"storage.k8s.io/v1beta1/PatchOptions",
"storage.k8s.io/v1beta1/StorageClass",
"storage.k8s.io/v1beta1/StorageClassList",
"storage.k8s.io/v1beta1/UpdateOptions",
"storage.k8s.io/v1beta1/VolumeAttachment",
"storage.k8s.io/v1beta1/VolumeAttachmentList",
"storage.k8s.io/v1beta1/WatchEvent",
"v1",
"v1/APIGroup",
"v1/APIGroupList",
"v1/APIResourceList",
"v1/APIVersions",
"v1/Binding",
"v1/ComponentStatus",
"v1/ComponentStatusList",
"v1/ConfigMap",
"v1/ConfigMapList",
"v1/CreateOptions",
"v1/DeleteOptions",
"v1/Endpoints",
"v1/EndpointsList",
"v1/Event",
"v1/EventList",
"v1/ExportOptions",
"v1/GetOptions",
"v1/LimitRange",
"v1/LimitRangeList",
"v1/List",
"v1/ListOptions",
"v1/Namespace",
"v1/NamespaceList",
"v1/Node",
"v1/NodeList",
"v1/NodeProxyOptions",
"v1/PatchOptions",
"v1/PersistentVolume",
"v1/PersistentVolumeClaim",
"v1/PersistentVolumeClaimList",
"v1/PersistentVolumeList",
"v1/Pod",
"v1/PodAttachOptions",
"v1/PodExecOptions",
"v1/PodList",
"v1/PodLogOptions",
"v1/PodPortForwardOptions",
"v1/PodProxyOptions",
"v1/PodStatusResult",
"v1/PodTemplate",
"v1/PodTemplateList",
"v1/RangeAllocation",
"v1/ReplicationController",
"v1/ReplicationControllerList",
"v1/ResourceQuota",
"v1/ResourceQuotaList",
"v1/Secret",
"v1/SecretList",
"v1/SerializedReference",
"v1/Service",
"v1/ServiceAccount",
"v1/ServiceAccountList",
"v1/ServiceList",
"v1/ServiceProxyOptions",
"v1/Status",
"v1/UpdateOptions",
"v1/WatchEvent",
}
}

@ -42,6 +42,8 @@ const (
DeploymentName = "deployment.yaml"
// ServiceName is the name of the example service file.
ServiceName = "service.yaml"
// ServiceAccountName is the name of the example serviceaccount file.
ServiceAccountName = "serviceaccount.yaml"
// NotesName is the name of the example NOTES.txt file.
NotesName = "NOTES.txt"
// HelpersName is the name of the example helpers file.
@ -67,6 +69,24 @@ imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name:
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 80
@ -189,8 +209,13 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ template "<CHARTNAME>.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
@ -238,6 +263,15 @@ spec:
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
`
const defaultServiceAccount = `{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ template "<CHARTNAME>.serviceAccountName" . }}
labels:
{{ include "<CHARTNAME>.labels" . | indent 4 }}
{{- end -}}
`
const defaultNotes = `1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
@ -253,7 +287,7 @@ const defaultNotes = `1. Get the application URL by running these commands:
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "<CHARTNAME>.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "<CHARTNAME>.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "<CHARTNAME>.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "<CHARTNAME>.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
@ -307,6 +341,17 @@ app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
{{- define "<CHARTNAME>.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "<CHARTNAME>.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}
`
const defaultTestConnection = `apiVersion: v1
@ -425,6 +470,11 @@ func Create(chartfile *chart.Metadata, dir string) (string, error) {
path: filepath.Join(cdir, TemplatesDir, ServiceName),
content: Transform(defaultService, "<CHARTNAME>", chartfile.Name),
},
{
// serviceaccount.yaml
path: filepath.Join(cdir, TemplatesDir, ServiceAccountName),
content: Transform(defaultServiceAccount, "<CHARTNAME>", chartfile.Name),
},
{
// NOTES.txt
path: filepath.Join(cdir, TemplatesDir, NotesName),

@ -0,0 +1,106 @@
/*
Copyright The Helm 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.
*/
// Generates the default versions to use with capabilities. This cannot be loaded
// dynamically as it uses enough memory to cause out of memory issues in CI.
//
// +build ignore
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path"
"sort"
"k8s.io/client-go/kubernetes/scheme"
)
const licenseHeader = `/*
Copyright The Helm 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.
*/`
func main() {
v := getVersions()
o := createOutput(v)
err := ioutil.WriteFile("capabilities_versions_generated.go", o, 0644)
if err != nil {
fmt.Printf("writing output: %s", err)
os.Exit(1)
}
}
func createOutput(v []string) []byte {
var out bytes.Buffer
fmt.Fprintln(&out, licenseHeader)
fmt.Fprintln(&out, "// Code generated by capabilities_default_versions_generate.go; DO NOT EDIT.")
fmt.Fprint(&out, "package chartutil\n\n")
fmt.Fprintln(&out, "func defaultVersions() []string {")
fmt.Fprintln(&out, "\treturn []string{")
for _, v := range v {
fmt.Fprintf(&out, "\t\t\"%s\",\n", v)
}
fmt.Fprintln(&out, "\t}")
fmt.Fprintln(&out, "}")
return out.Bytes()
}
func getVersions() []string {
var s []string
var gv string
var gvk string
// Check is used so that we only add an item once to the return
check := make(map[string]struct{})
// Client go has a default scheme set with everything in it
// This includes over 500 group versions and group versioned kinds
for k := range scheme.Scheme.AllKnownTypes() {
gv = path.Join(k.Group, k.Version)
gvk = path.Join(k.Group, k.Version, k.Kind)
if _, ok := check[gv]; !ok {
check[gv] = struct{}{}
s = append(s, gv)
}
if _, ok := check[gvk]; !ok {
check[gvk] = struct{}{}
s = append(s, gvk)
}
}
// Put the names in a consistent order
sort.Strings(s)
return s
}

@ -171,6 +171,10 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
return c, err
}
c.Metadata = m
var apiVersion = c.Metadata.ApiVersion
if apiVersion != "" && apiVersion != ApiVersionV1 {
return c, fmt.Errorf("apiVersion '%s' is not valid. The value must be \"v1\"", apiVersion)
}
} else if f.Name == "values.toml" {
return c, errors.New("values.toml is illegal as of 2.0.0-alpha.2")
} else if f.Name == "values.yaml" {

@ -23,6 +23,7 @@ import (
"os"
"path"
"path/filepath"
"strings"
"testing"
"time"
@ -39,6 +40,17 @@ func TestLoadDir(t *testing.T) {
verifyRequirements(t, c)
}
func TestLoadNonV1Chart(t *testing.T) {
_, err := Load("testdata/frobnitz.v2")
if err != nil {
if strings.Compare(err.Error(), "apiVersion 'v2' is not valid. The value must be \"v1\"") != 0 {
t.Errorf("Unexpected message: %s", err)
}
return
}
t.Fatalf("chart with v2 apiVersion should not load")
}
func TestLoadFile(t *testing.T) {
c, err := Load("testdata/frobnitz-1.2.3.tgz")
if err != nil {

@ -391,7 +391,7 @@ func processImportValues(c *chart.Chart) error {
if err != nil {
return err
}
b := make(map[string]interface{}, 0)
b := cvals.AsMap()
// import values from each dependency if specified in import-values
for _, r := range reqs.Dependencies {
// only process raw requirement that is found in chart's dependencies (enabled)
@ -428,7 +428,7 @@ func processImportValues(c *chart.Chart) error {
}
// create value map from child to be merged into parent
vm := pathToMap(nm["parent"], vv.AsMap())
b = coalesceTables(cvals, vm, c.Metadata.Name)
b = coalesceTables(b, vm, c.Metadata.Name)
case string:
nm := map[string]string{
"child": "exports." + iv,
@ -448,7 +448,6 @@ func processImportValues(c *chart.Chart) error {
r.ImportValues = outiv
}
}
b = coalesceTables(b, cvals, c.Metadata.Name)
y, err := yaml.Marshal(b)
if err != nil {
return err

@ -15,6 +15,7 @@ limitations under the License.
package chartutil
import (
"encoding/json"
"os"
"path/filepath"
"sort"
@ -302,6 +303,10 @@ func verifyRequirementsImportValues(t *testing.T, c *chart.Chart, v *chart.Confi
}
switch pv.(type) {
case json.Number:
if s := pv.(json.Number).String(); s != vv {
t.Errorf("Failed to match imported number value %v with expected %v", s, vv)
}
case float64:
s := strconv.FormatFloat(pv.(float64), 'f', -1, 64)
if s != vv {

@ -10,3 +10,4 @@ water:
water:
where: "everywhere"
nor: "any drop to drink"
temperature: 1234567890

@ -0,0 +1,20 @@
apiVersion: v2
name: frobnitz
description: This is a frobnitz as a v2 chart
version: "1.2.3"
keywords:
- frobnitz
- sprocket
- dodad
maintainers:
- name: The Helm Team
email: helm@example.com
- name: Someone Else
email: nobody@example.com
sources:
- https://example.com/foo/bar
home: http://example.com
icon: https://example.com/64x64.png
annotations:
extrakey: extravalue
anotherkey: anothervalue

@ -0,0 +1 @@
This is an install document. The client may display this.

@ -0,0 +1 @@
LICENSE placeholder.

@ -0,0 +1,11 @@
# Frobnitz
This is an example chart.
## Usage
This is an example. It has no usage.
## Development
For developer info, see the top-level repository.

@ -0,0 +1 @@
This should be ignored by the loader, but may be included in a chart.

@ -0,0 +1,4 @@
name: alpine
description: Deploy a basic Alpine Linux pod
version: 0.1.0
home: https://k8s.io/helm

@ -0,0 +1,9 @@
This example was generated using the command `helm create alpine`.
The `templates/` directory contains a very simple pod resource with a
couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.

@ -0,0 +1,4 @@
name: mast1
description: A Helm chart for Kubernetes
version: 0.1.0
home: ""

@ -0,0 +1,4 @@
# Default values for mast1.
# This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates.
# name = "value"

@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
name: {{.Release.Name}}-{{.Chart.Name}}
labels:
app.kubernetes.io/managed-by: {{.Release.Service}}
chartName: {{.Chart.Name}}
chartVersion: {{.Chart.Version | quote}}
annotations:
"helm.sh/created": "{{.Release.Time.Seconds}}"
spec:
restartPolicy: {{default "Never" .restart_policy}}
containers:
- name: waiter
image: "alpine:3.3"
command: ["/bin/sleep","9000"]

@ -0,0 +1,2 @@
# The pod name
name: "my-alpine"

@ -0,0 +1 @@
This is a placeholder for documentation.

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.0" width="256" height="256" id="test">
<desc>Example icon</desc>
<rect id="first" x="2" y="2" width="40" height="60" fill="navy"/>
<rect id="second" x="15" y="4" width="40" height="60" fill="red"/>
</svg>

After

Width:  |  Height:  |  Size: 374 B

@ -0,0 +1,8 @@
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts
digest: invalid

@ -0,0 +1,7 @@
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts

@ -0,0 +1 @@
Hello {{.Name | default "world"}}

@ -0,0 +1,6 @@
# A values file contains configuration.
name: "Some Name"
section:
name: "Name in a section"

@ -1 +1,2 @@
scope: spouter
foo: bar

@ -22,3 +22,7 @@ web:
httpGet:
path: /api/v1/info
port: atc
# for testing deleting default values in sub charts
spouter:
foo: null

@ -17,6 +17,7 @@ limitations under the License.
package chartutil
import (
"encoding/json"
"errors"
"fmt"
"io"
@ -132,7 +133,10 @@ func tableLookup(v Values, simple string) (Values, error) {
// ReadValues will parse YAML byte data into a Values.
func ReadValues(data []byte) (vals Values, err error) {
err = yaml.Unmarshal(data, &vals)
err = yaml.Unmarshal(data, &vals, func(d *json.Decoder) *json.Decoder {
d.UseNumber()
return d
})
if len(vals) == 0 {
vals = Values{}
}
@ -166,15 +170,10 @@ func CoalesceValues(chrt *chart.Chart, vals *chart.Config) (Values, error) {
if err != nil {
return cvals, err
}
cvals, err = coalesce(chrt, evals)
if err != nil {
return cvals, err
}
return coalesce(chrt, evals)
}
var err error
cvals, err = coalesceDeps(chrt, cvals)
return cvals, err
return coalesceDeps(chrt, cvals)
}
// coalesce coalesces the dest values and the chart values, giving priority to the dest values.
@ -186,8 +185,7 @@ func coalesce(ch *chart.Chart, dest map[string]interface{}) (map[string]interfac
if err != nil {
return dest, err
}
coalesceDeps(ch, dest)
return dest, nil
return coalesceDeps(ch, dest)
}
// coalesceDeps coalesces the dependencies of the given chart.
@ -203,7 +201,7 @@ func coalesceDeps(chrt *chart.Chart, dest map[string]interface{}) (map[string]in
dvmap := dv.(map[string]interface{})
// Get globals out of dest and merge them into dvmap.
coalesceGlobals(dvmap, dest, chrt.Metadata.Name)
dvmap = coalesceGlobals(dvmap, dest, chrt.Metadata.Name)
var err error
// Now coalesce the rest of the values.
@ -236,45 +234,20 @@ func coalesceGlobals(dest, src map[string]interface{}, chartName string) map[str
return dg
}
rv := make(map[string]interface{})
for k, v := range dest {
rv[k] = v
}
// EXPERIMENTAL: In the past, we have disallowed globals to test tables. This
// reverses that decision. It may somehow be possible to introduce a loop
// here, but I haven't found a way. So for the time being, let's allow
// tables in globals.
for key, val := range sg {
if istable(val) {
vv := copyMap(val.(map[string]interface{}))
if destv, ok := dg[key]; ok {
if destvmap, ok := destv.(map[string]interface{}); ok {
// Basically, we reverse order of coalesce here to merge
// top-down.
coalesceTables(vv, destvmap, chartName)
dg[key] = vv
continue
} else {
log.Printf("Warning: For chart '%s', cannot merge map onto non-map for key '%q'. Skipping.", chartName, key)
}
} else {
// Here there is no merge. We're just adding.
dg[key] = vv
}
} else if dv, ok := dg[key]; ok && istable(dv) {
// It's not clear if this condition can actually ever trigger.
log.Printf("Warning: For chart '%s', key '%s' is a table. Skipping.", chartName, key)
continue
}
// TODO: Do we need to do any additional checking on the value?
dg[key] = val
}
dest[GlobalKey] = dg
return dest
}
func copyMap(src map[string]interface{}) map[string]interface{} {
dest := make(map[string]interface{}, len(src))
for k, v := range src {
dest[k] = v
}
return dest
rv[GlobalKey] = coalesceTables(sg, dg, chartName)
return rv
}
// coalesceValues builds up a values map for a particular chart.
@ -294,30 +267,7 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) (map[string]interf
return v, fmt.Errorf("Error: Reading chart '%s' default values (%s): %s", c.Metadata.Name, c.Values.Raw, err)
}
for key, val := range nv {
if value, ok := v[key]; ok {
if value == nil {
// When the YAML value is null, we remove the value's key.
// This allows Helm's various sources of values (value files or --set) to
// remove incompatible keys from any previous chart, file, or set values.
delete(v, key)
} else if dest, ok := value.(map[string]interface{}); ok {
// if v[key] is a table, merge nv's val table into v[key].
src, ok := val.(map[string]interface{})
if !ok {
log.Printf("Warning: Building values map for chart '%s'. Skipped value (%+v) for '%s', as it is not a table.", c.Metadata.Name, src, key)
continue
}
// Because v has higher precedence than nv, dest values override src
// values.
coalesceTables(dest, src, c.Metadata.Name)
}
} else {
// If the key is not in v, copy it from nv.
v[key] = val
}
}
return v, nil
return coalesceTables(v, nv.AsMap(), c.Metadata.Name), nil
}
// coalesceTables merges a source map into a destination map.
@ -326,36 +276,49 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) (map[string]interf
func coalesceTables(dst, src map[string]interface{}, chartName string) map[string]interface{} {
// Because dest has higher precedence than src, dest values override src
// values.
rv := make(map[string]interface{})
for key, val := range src {
dv, ok := dst[key]
if ok && dv == nil {
// skip here, we delete at end
if !ok { // if not in dst, then copy from src
rv[key] = val
continue
}
if istable(val) {
if !ok {
dst[key] = val
} else if istable(dv) {
coalesceTables(dv.(map[string]interface{}), val.(map[string]interface{}), chartName)
} else {
log.Printf("Warning: Merging destination map for chart '%s'. Cannot overwrite table item '%s', with non table value: %v", chartName, key, val)
}
if dv == nil { // if set to nil in dst, then ignore
// When the YAML value is null, we skip the value's key.
// This allows Helm's various sources of values (value files or --set) to
// remove incompatible keys from any previous chart, file, or set values.
continue
} else if ok && istable(dv) {
}
srcTable, srcIsTable := val.(map[string]interface{})
dstTable, dstIsTable := dv.(map[string]interface{})
switch {
case srcIsTable && dstIsTable: // both tables, we coalesce
rv[key] = coalesceTables(dstTable, srcTable, chartName)
case srcIsTable && !dstIsTable:
log.Printf("Warning: Merging destination map for chart '%s'. Overwriting table item '%s', with non table value: %v", chartName, key, dv)
rv[key] = dv
case !srcIsTable && dstIsTable:
log.Printf("Warning: Merging destination map for chart '%s'. The destination item '%s' is a table and ignoring the source '%s' as it has a non-table value of: %v", chartName, key, key, val)
continue
} else if !ok { // <- ok is still in scope from preceding conditional.
dst[key] = val
continue
rv[key] = dv
default: // neither are tables, simply take the dst value
rv[key] = dv
}
}
// never return a nil value, rather delete the key
for k, v := range dst {
if v == nil {
delete(dst, k)
// do we have anything in dst that wasn't processed already that we need to copy across?
for key, val := range dst {
if val == nil {
continue
}
_, ok := rv[key]
if !ok {
rv[key] = val
}
return dst
}
return rv
}
// ReleaseOptions represents the additional release options needed

@ -53,6 +53,7 @@ water:
water:
where: "everywhere"
nor: "any drop to drink"
temperature: 1234567890
`
data, err := ReadValues([]byte(doc))
@ -266,6 +267,12 @@ func matchValues(t *testing.T, data map[string]interface{}) {
} else if o != "everywhere" {
t.Errorf("Expected water water everywhere")
}
if o, err := ttpl("{{.water.water.temperature}}", data); err != nil {
t.Errorf(".water.water.temperature: %s", err)
} else if o != "1234567890" {
t.Errorf("Expected water water temperature: 1234567890, got: %s", o)
}
}
func ttpl(tpl string, v map[string]interface{}) (string, error) {
@ -468,6 +475,33 @@ func TestCoalesceTables(t *testing.T) {
t.Errorf("Expected boat string, got %v", dst["boat"])
}
}
func TestCoalesceSubchart(t *testing.T) {
tchart := "testdata/moby"
c, err := LoadDir(tchart)
if err != nil {
t.Fatal(err)
}
tvals := &chart.Config{}
v, err := CoalesceValues(c, tvals)
if err != nil {
t.Fatal(err)
}
j, _ := json.MarshalIndent(v, "", " ")
t.Logf("Coalesced Values: %s", string(j))
subchartValues, ok := v["spouter"].(map[string]interface{})
if !ok {
t.Errorf("Subchart values not found")
}
if _, ok := subchartValues["foo"]; ok {
t.Errorf("Expected key foo to be removed, still present")
}
}
func TestPathValue(t *testing.T) {
doc := `
title: "Moby Dick"
@ -585,3 +619,59 @@ anotherNewKey:
}
}
}
func TestOverriteTableItemWithNonTableValue(t *testing.T) {
// src has a table value for "foo"
src := map[string]interface{}{
"foo": map[string]interface{}{
"baz": "boz",
},
}
// dst has a non-table value for "foo"
dst := map[string]interface{}{
"foo": "bar",
}
// result - this may print a warning, but we has always "worked"
result := coalesceTables(dst, src, "")
expected := map[string]interface{}{
"foo": "bar",
}
if !reflect.DeepEqual(result, expected) {
t.Errorf("Expected %v, but got %v", expected, result)
}
}
func TestSubchartCoaleseWithNullValue(t *testing.T) {
v, err := CoalesceValues(&chart.Chart{
Metadata: &chart.Metadata{Name: "demo"},
Dependencies: []*chart.Chart{
{
Metadata: &chart.Metadata{Name: "logstash"},
Values: &chart.Config{
Raw: `livenessProbe: {httpGet: {path: "/", port: monitor}}`,
},
},
},
Values: &chart.Config{
Raw: `logstash: {livenessProbe: {httpGet: null, exec: "/bin/true"}}`,
},
}, &chart.Config{})
if err != nil {
t.Errorf("Failed with %s", err)
}
result := v.AsMap()
expected := map[string]interface{}{
"logstash": map[string]interface{}{
"global": map[string]interface{}{},
"livenessProbe": map[string]interface{}{
"exec": "/bin/true",
},
},
}
if !reflect.DeepEqual(result, expected) {
t.Errorf("got %+v, expected %+v", result, expected)
}
}

@ -205,6 +205,11 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge
}
c.setCredentials(r)
// Skip if dependency not contain name
if len(r.Config.Name) == 0 {
return u, r.Client, nil
}
// Next, we need to load the index, and actually look up the chart.
i, err := repo.LoadIndexFile(c.HelmHome.CacheIndex(r.Config.Name))
if err != nil {

@ -233,7 +233,7 @@ func (m *Manager) downloadAll(deps []*chartutil.Dependency) error {
// Any failure to resolve/download a chart should fail:
// https://github.com/kubernetes/helm/issues/1439
churl, username, password, err := findChartURL(dep.Name, dep.Version, dep.Repository, repos)
churl, username, password, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos)
if err != nil {
saveError = fmt.Errorf("could not find %s: %s", churl, err)
break
@ -357,7 +357,7 @@ func (m *Manager) hasAllRepos(deps []*chartutil.Dependency) error {
return nil
}
// getRepoNames returns the repo names of the referenced deps which can be used to fetch the cahced index file.
// getRepoNames returns the repo names of the referenced deps which can be used to fetch the cached index file.
func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string, error) {
rf, err := repo.LoadRepositoriesFile(m.HelmHome.RepositoryFile())
if err != nil {
@ -403,10 +403,17 @@ func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string,
}
}
if !found {
missing = append(missing, dd.Repository)
repository := dd.Repository
// Add if URL
_, err := url.ParseRequestURI(repository)
if err == nil {
reposMap[repository] = repository
continue
}
missing = append(missing, repository)
}
if len(missing) > 0 {
}
if len(missing) > 0 {
errorMessage := fmt.Sprintf("no repository definition for %s. Please add them via 'helm repo add'", strings.Join(missing, ", "))
// It is common for people to try to enter "stable" as a repository instead of the actual URL.
@ -425,7 +432,7 @@ repository, use "https://kubernetes-charts.storage.googleapis.com/" or "@stable"
}
return nil, errors.New(errorMessage)
}
}
return reposMap, nil
}
@ -477,7 +484,7 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error {
// repoURL is the repository to search
//
// If it finds a URL that is "relative", it will prepend the repoURL.
func findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, err error) {
func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, err error) {
for _, cr := range repos {
if urlutil.Equal(repoURL, cr.Config.URL) {
var entry repo.ChartVersions
@ -499,6 +506,10 @@ func findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRep
return
}
}
url, err = repo.FindChartInRepoURL(repoURL, name, version, "", "", "", m.Getters)
if err == nil {
return
}
err = fmt.Errorf("chart %s not found in %s", name, repoURL)
return
}

@ -78,7 +78,7 @@ func TestFindChartURL(t *testing.T) {
version := "0.1.0"
repoURL := "http://example.com/charts"
churl, username, password, err := findChartURL(name, version, repoURL, repos)
churl, username, password, err := m.findChartURL(name, version, repoURL, repos)
if err != nil {
t.Fatal(err)
}
@ -106,13 +106,6 @@ func TestGetRepoNames(t *testing.T) {
err bool
expectedErr string
}{
{
name: "no repo definition failure",
req: []*chartutil.Dependency{
{Name: "oedipus-rex", Repository: "http://example.com/test"},
},
err: true,
},
{
name: "no repo definition failure -- stable repo",
req: []*chartutil.Dependency{
@ -128,6 +121,13 @@ func TestGetRepoNames(t *testing.T) {
err: true,
expectedErr: "no 'repository' field specified for dependency: \"dependency-missing-repository-field\"",
},
{
name: "dependency repository is url but not exist in repos",
req: []*chartutil.Dependency{
{Name: "oedipus-rex", Repository: "http://example.com/test"},
},
expect: map[string]string{"http://example.com/test": "http://example.com/test"},
},
{
name: "no repo definition failure",
req: []*chartutil.Dependency{

@ -26,7 +26,7 @@ import (
"k8s.io/helm/pkg/version"
)
//HttpGetter is the efault HTTP(/S) backend handler
//HttpGetter is the default HTTP(/S) backend handler
// TODO: change the name to HTTPGetter in Helm 3
type HttpGetter struct { //nolint
client *http.Client

@ -21,6 +21,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/plugin"
@ -62,8 +63,9 @@ type pluginGetter struct {
// Get runs downloader plugin command
func (p *pluginGetter) Get(href string) (*bytes.Buffer, error) {
argv := []string{p.certFile, p.keyFile, p.cAFile, href}
prog := exec.Command(filepath.Join(p.base, p.command), argv...)
commands := strings.Split(p.command, " ")
argv := append(commands[1:], p.certFile, p.keyFile, p.cAFile, href)
prog := exec.Command(filepath.Join(p.base, commands[0]), argv...)
plugin.SetupPluginEnv(p.settings, p.name, p.base)
prog.Env = os.Environ()
buf := bytes.NewBuffer(nil)

@ -94,3 +94,30 @@ func TestPluginGetter(t *testing.T) {
t.Errorf("Expected %q, got %q", expect, got)
}
}
func TestPluginSubCommands(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("TODO: refactor this test to work on windows")
}
oldhh := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
env := hh(false)
pg := newPluginGetter("echo -n", env, "test", ".")
g, err := pg("test://foo/bar", "", "", "")
if err != nil {
t.Fatal(err)
}
data, err := g.Get("test://foo/bar")
if err != nil {
t.Fatal(err)
}
expect := " test://foo/bar"
got := data.String()
if got != expect {
t.Errorf("Expected %q, got %q", expect, got)
}
}

@ -27,6 +27,8 @@ const (
HookWeightAnno = "helm.sh/hook-weight"
// HookDeleteAnno is the label name for the delete policy for a hook
HookDeleteAnno = "helm.sh/hook-delete-policy"
// HookDeleteTimeoutAnno is the label name for the timeout value for delete policies
HookDeleteTimeoutAnno = "helm.sh/hook-delete-timeout"
)
// Types of hooks

@ -41,6 +41,7 @@ import (
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -51,6 +52,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/kubernetes/scheme"
cachetools "k8s.io/client-go/tools/cache"
watchtools "k8s.io/client-go/tools/watch"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/core"
@ -314,7 +316,14 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
return buf.String(), nil
}
// Deprecated; use UpdateWithOptions instead
// Update reads the current configuration and a target configuration from io.reader
// and creates resources that don't already exist, updates resources that have been modified
// in the target configuration and deletes resources from the current configuration that are
// not present in the target configuration.
//
// Namespace will set the namespaces.
//
// Deprecated: use UpdateWithOptions instead.
func (c *Client) Update(namespace string, originalReader, targetReader io.Reader, force bool, recreate bool, timeout int64, shouldWait bool) error {
return c.UpdateWithOptions(namespace, originalReader, targetReader, UpdateOptions{
Force: force,
@ -334,12 +343,13 @@ type UpdateOptions struct {
CleanupOnFail bool
}
// UpdateWithOptions reads in the current configuration and a target configuration from io.reader
// and creates resources that don't already exists, updates resources that have been modified
// UpdateWithOptions reads the current configuration and a target configuration from io.reader
// and creates resources that don't already exist, updates resources that have been modified
// in the target configuration and deletes resources from the current configuration that are
// not present in the target configuration.
//
// Namespace will set the namespaces.
// Namespace will set the namespaces. UpdateOptions provides additional parameters to control
// update behavior.
func (c *Client) UpdateWithOptions(namespace string, originalReader, targetReader io.Reader, opts UpdateOptions) error {
original, err := c.BuildUnstructured(namespace, originalReader)
if err != nil {
@ -465,15 +475,34 @@ func (c *Client) cleanup(newlyCreatedResources []*resource.Info) (cleanupErrors
//
// Namespace will set the namespace.
func (c *Client) Delete(namespace string, reader io.Reader) error {
return c.DeleteWithTimeout(namespace, reader, 0, false)
}
// DeleteWithTimeout deletes Kubernetes resources from an io.reader. If shouldWait is true, the function
// will wait for all resources to be deleted from etcd before returning, or when the timeout
// has expired.
//
// Namespace will set the namespace.
func (c *Client) DeleteWithTimeout(namespace string, reader io.Reader, timeout int64, shouldWait bool) error {
infos, err := c.BuildUnstructured(namespace, reader)
if err != nil {
return err
}
return perform(infos, func(info *resource.Info) error {
err = perform(infos, func(info *resource.Info) error {
c.Log("Starting delete for %q %s", info.Name, info.Mapping.GroupVersionKind.Kind)
err := deleteResource(info)
return c.skipIfNotFound(err)
})
if err != nil {
return err
}
if shouldWait {
c.Log("Waiting for %d seconds for delete to be completed", timeout)
return waitUntilAllResourceDeleted(infos, time.Duration(timeout)*time.Second)
}
return nil
}
func (c *Client) skipIfNotFound(err error) error {
@ -484,6 +513,27 @@ func (c *Client) skipIfNotFound(err error) error {
return err
}
func waitUntilAllResourceDeleted(infos Result, timeout time.Duration) error {
return wait.Poll(2*time.Second, timeout, func() (bool, error) {
allDeleted := true
err := perform(infos, func(info *resource.Info) error {
innerErr := info.Get()
if errors.IsNotFound(innerErr) {
return nil
}
if innerErr != nil {
return innerErr
}
allDeleted = false
return nil
})
if err != nil {
return false, err
}
return allDeleted, nil
})
}
func (c *Client) watchTimeout(t time.Duration) ResourceActorFunc {
return func(info *resource.Info) error {
return c.watchUntilReady(t, info)
@ -512,7 +562,7 @@ func (c *Client) WatchUntilReady(namespace string, reader io.Reader, timeout int
return perform(infos, c.watchTimeout(time.Duration(timeout)*time.Second))
}
// WatchUntilCRDEstablished polls the given CRD until it reaches the established
// WaitUntilCRDEstablished polls the given CRD until it reaches the established
// state. A CRD needs to reach the established state before CRs can be created.
//
// If a naming conflict condition is found, this function will return an error.
@ -608,24 +658,33 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P
}
// Get a versioned object
versionedObject := asVersioned(target)
versionedObject, err := asVersioned(target)
// Unstructured objects, such as CRDs, may not have an not registered error
// Unstructured objects, such as CRDs, may not have a not registered error
// returned from ConvertToVersion. Anything that's unstructured should
// use the jsonpatch.CreateMergePatch. Strategic Merge Patch is not supported
// on objects like CRDs.
_, isUnstructured := versionedObject.(runtime.Unstructured)
// On newer K8s versions, CRDs aren't unstructured but has this dedicated type
_, isCRD := versionedObject.(*apiextv1beta1.CustomResourceDefinition)
switch {
case runtime.IsNotRegisteredError(err), isUnstructured:
case runtime.IsNotRegisteredError(err), isUnstructured, isCRD:
// fall back to generic JSON merge patch
patch, err := jsonpatch.CreateMergePatch(oldData, newData)
return patch, types.MergePatchType, err
if err != nil {
return nil, types.MergePatchType, fmt.Errorf("failed to create merge patch: %v", err)
}
return patch, types.MergePatchType, nil
case err != nil:
return nil, types.StrategicMergePatchType, fmt.Errorf("failed to get versionedObject: %s", err)
default:
patch, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, versionedObject)
return patch, types.StrategicMergePatchType, err
if err != nil {
return nil, types.StrategicMergePatchType, fmt.Errorf("failed to create two-way merge patch: %v", err)
}
return patch, types.StrategicMergePatchType, nil
}
}
@ -680,7 +739,7 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object,
return nil
}
versioned := asVersioned(target)
versioned := asVersionedOrUnstructured(target)
selector, ok := getSelectorFromObject(versioned)
if !ok {
return nil
@ -753,10 +812,7 @@ func getSelectorFromObject(obj runtime.Object) (map[string]string, bool) {
}
func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) error {
w, err := resource.NewHelper(info.Client, info.Mapping).WatchSingle(info.Namespace, info.Name, info.ResourceVersion)
if err != nil {
return err
}
lw := cachetools.NewListWatchFromClient(info.Client, info.Mapping.Resource.Resource, info.Namespace, fields.Everything())
kind := info.Mapping.GroupVersionKind.Kind
c.Log("Watching for changes to %s %s with timeout of %v", kind, info.Name, timeout)
@ -769,7 +825,7 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout)
defer cancel()
_, err = watchtools.UntilWithoutRetry(ctx, w, func(e watch.Event) (bool, error) {
_, err := watchtools.ListWatchUntil(ctx, lw, func(e watch.Event) (bool, error) {
switch e.Type {
case watch.Added, watch.Modified:
// For things like a secret or a config map, this is the best indicator
@ -857,15 +913,12 @@ func (c *Client) WaitAndGetCompletedPodPhase(namespace string, reader io.Reader,
}
func (c *Client) watchPodUntilComplete(timeout time.Duration, info *resource.Info) error {
w, err := resource.NewHelper(info.Client, info.Mapping).WatchSingle(info.Namespace, info.Name, info.ResourceVersion)
if err != nil {
return err
}
lw := cachetools.NewListWatchFromClient(info.Client, info.Mapping.Resource.Resource, info.Namespace, fields.Everything())
c.Log("Watching pod %s for completion with timeout of %v", info.Name, timeout)
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout)
defer cancel()
_, err = watchtools.UntilWithoutRetry(ctx, w, func(e watch.Event) (bool, error) {
_, err := watchtools.ListWatchUntil(ctx, lw, func(e watch.Event) (bool, error) {
return isPodComplete(e)
})
@ -896,7 +949,7 @@ func (c *Client) getSelectRelationPod(info *resource.Info, objPods map[string][]
c.Log("get relation pod of object: %s/%s/%s", info.Namespace, info.Mapping.GroupVersionKind.Kind, info.Name)
versioned := asVersioned(info)
versioned := asVersionedOrUnstructured(info)
selector, ok := getSelectorFromObject(versioned)
if !ok {
return objPods, nil
@ -929,17 +982,23 @@ func isFoundPod(podItem []v1.Pod, pod v1.Pod) bool {
return false
}
func asVersioned(info *resource.Info) runtime.Object {
func asVersionedOrUnstructured(info *resource.Info) runtime.Object {
obj, _ := asVersioned(info)
return obj
}
func asVersioned(info *resource.Info) (runtime.Object, error) {
converter := runtime.ObjectConvertor(scheme.Scheme)
groupVersioner := runtime.GroupVersioner(schema.GroupVersions(scheme.Scheme.PrioritizedVersionsAllGroups()))
if info.Mapping != nil {
groupVersioner = info.Mapping.GroupVersionKind.GroupVersion()
}
if obj, err := converter.ConvertToVersion(info.Object, groupVersioner); err == nil {
return obj
obj, err := converter.ConvertToVersion(info.Object, groupVersioner)
if err != nil {
return info.Object, err
}
return info.Object
return obj, nil
}
func asInternal(info *resource.Info) (runtime.Object, error) {

@ -283,6 +283,54 @@ func TestUpdateNonManagedResourceError(t *testing.T) {
}
}
func TestDeleteWithTimeout(t *testing.T) {
testCases := map[string]struct {
deleteTimeout int64
deleteAfter time.Duration
success bool
}{
"resource is deleted within timeout period": {
int64((2 * time.Minute).Seconds()),
10 * time.Second,
true,
},
"resource is not deleted within the timeout period": {
int64((10 * time.Second).Seconds()),
20 * time.Second,
false,
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
c := newTestClient()
defer c.Cleanup()
service := newService("my-service")
startTime := time.Now()
c.TestFactory.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
currentTime := time.Now()
if startTime.Add(tc.deleteAfter).Before(currentTime) {
return newResponse(404, notFoundBody())
}
return newResponse(200, &service)
}),
}
err := c.DeleteWithTimeout(metav1.NamespaceDefault, strings.NewReader(testServiceManifest), tc.deleteTimeout, true)
if err != nil && tc.success {
t.Errorf("expected no error, but got %v", err)
}
if err == nil && !tc.success {
t.Errorf("expected error, but didn't get one")
}
})
}
}
func TestBuild(t *testing.T) {
tests := []struct {
name string
@ -510,7 +558,7 @@ func TestWaitUntilCRDEstablished(t *testing.T) {
} else {
crd = crdWithConditions
}
requestCount += 1
requestCount++
return newResponse(200, &crd)
}),
}

@ -53,7 +53,7 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error {
pvc := []v1.PersistentVolumeClaim{}
deployments := []deployment{}
for _, v := range created {
switch value := asVersioned(v).(type) {
switch value := asVersionedOrUnstructured(v).(type) {
case *v1.ReplicationController:
list, err := getPods(kcs, value.Namespace, value.Spec.Selector)
if err != nil {

@ -51,7 +51,7 @@ func Chartfile(linter *support.Linter) {
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartNameDirMatch(linter.ChartDir, chartFile))
// Chart metadata
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartApiVersion(chartFile))
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartAPIVersion(chartFile))
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartVersion(chartFile))
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartEngine(chartFile))
linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartMaintainer(chartFile))
@ -97,7 +97,7 @@ func validateChartNameDirMatch(chartDir string, cf *chart.Metadata) error {
return nil
}
func validateChartApiVersion(cf *chart.Metadata) error {
func validateChartAPIVersion(cf *chart.Metadata) error {
if cf.ApiVersion == "" {
return errors.New("apiVersion is required")
}

@ -99,20 +99,13 @@ func Templates(linter *support.Linter, values []byte, namespace string, strict b
fileName, _ := template.Name, template.Data
path = fileName
linter.RunLinterRule(support.ErrorSev, path, validateAllowedExtension(fileName))
linter.RunLinterRule(support.WarningSev, path, validateAllowedExtension(fileName))
// We only apply the following lint rules to yaml files
if filepath.Ext(fileName) != ".yaml" || filepath.Ext(fileName) == ".yml" {
continue
}
// NOTE: disabled for now, Refs https://github.com/kubernetes/helm/issues/1463
// Check that all the templates have a matching value
//linter.RunLinterRule(support.WarningSev, path, validateNoMissingValues(templatesPath, valuesToRender, preExecutedTemplate))
// NOTE: disabled for now, Refs https://github.com/kubernetes/helm/issues/1037
// linter.RunLinterRule(support.WarningSev, path, validateQuotes(string(preExecutedTemplate)))
renderedContent := renderedContentMap[filepath.Join(chart.GetMetadata().Name, fileName)]
var yamlStruct K8sYamlStruct
// Even though K8sYamlStruct only defines Metadata namespace, an error in any other

@ -136,7 +136,7 @@ func (i *VCSInstaller) solveVersion(repo vcs.Repo) (string, error) {
sort.Sort(sort.Reverse(semver.Collection(semvers)))
for _, v := range semvers {
if constraint.Check(v) {
// If the constrint passes get the original reference
// If the constraint passes get the original reference
ver := v.Original()
debug("setting to %s", ver)
return ver, nil

@ -69,7 +69,7 @@ func (x Hook_Event) String() string {
return proto.EnumName(Hook_Event_name, int32(x))
}
func (Hook_Event) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_hook_8076b1a80af16030, []int{0, 0}
return fileDescriptor_hook_e64400ca8195038e, []int{0, 0}
}
type Hook_DeletePolicy int32
@ -95,7 +95,7 @@ func (x Hook_DeletePolicy) String() string {
return proto.EnumName(Hook_DeletePolicy_name, int32(x))
}
func (Hook_DeletePolicy) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_hook_8076b1a80af16030, []int{0, 1}
return fileDescriptor_hook_e64400ca8195038e, []int{0, 1}
}
// Hook defines a hook object.
@ -115,6 +115,8 @@ type Hook struct {
Weight int32 `protobuf:"varint,7,opt,name=weight,proto3" json:"weight,omitempty"`
// DeletePolicies are the policies that indicate when to delete the hook
DeletePolicies []Hook_DeletePolicy `protobuf:"varint,8,rep,packed,name=delete_policies,json=deletePolicies,proto3,enum=hapi.release.Hook_DeletePolicy" json:"delete_policies,omitempty"`
// DeleteTimeout indicates how long to wait for a resource to be deleted before timing out
DeleteTimeout int64 `protobuf:"varint,9,opt,name=delete_timeout,json=deleteTimeout,proto3" json:"delete_timeout,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -124,7 +126,7 @@ func (m *Hook) Reset() { *m = Hook{} }
func (m *Hook) String() string { return proto.CompactTextString(m) }
func (*Hook) ProtoMessage() {}
func (*Hook) Descriptor() ([]byte, []int) {
return fileDescriptor_hook_8076b1a80af16030, []int{0}
return fileDescriptor_hook_e64400ca8195038e, []int{0}
}
func (m *Hook) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Hook.Unmarshal(m, b)
@ -200,43 +202,51 @@ func (m *Hook) GetDeletePolicies() []Hook_DeletePolicy {
return nil
}
func (m *Hook) GetDeleteTimeout() int64 {
if m != nil {
return m.DeleteTimeout
}
return 0
}
func init() {
proto.RegisterType((*Hook)(nil), "hapi.release.Hook")
proto.RegisterEnum("hapi.release.Hook_Event", Hook_Event_name, Hook_Event_value)
proto.RegisterEnum("hapi.release.Hook_DeletePolicy", Hook_DeletePolicy_name, Hook_DeletePolicy_value)
}
func init() { proto.RegisterFile("hapi/release/hook.proto", fileDescriptor_hook_8076b1a80af16030) }
var fileDescriptor_hook_8076b1a80af16030 = []byte{
// 453 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x51, 0x8f, 0x9a, 0x40,
0x10, 0x80, 0x8f, 0x53, 0x41, 0x47, 0xcf, 0xdb, 0x6e, 0x9a, 0x76, 0xe3, 0xcb, 0x19, 0x9f, 0x7c,
0xc2, 0xe6, 0x9a, 0xfe, 0x00, 0x84, 0xb9, 0x6a, 0x24, 0x60, 0x16, 0x4c, 0x93, 0xbe, 0x10, 0xae,
0xee, 0x29, 0x11, 0x81, 0x08, 0xb6, 0xe9, 0x1f, 0xed, 0x3f, 0xe8, 0xff, 0x68, 0x76, 0x45, 0x7a,
0x49, 0xfb, 0x36, 0xf3, 0xcd, 0xb7, 0xb3, 0x33, 0xbb, 0xf0, 0x7e, 0x1f, 0x17, 0xc9, 0xec, 0x24,
0x52, 0x11, 0x97, 0x62, 0xb6, 0xcf, 0xf3, 0x83, 0x59, 0x9c, 0xf2, 0x2a, 0xa7, 0x03, 0x59, 0x30,
0xeb, 0xc2, 0xe8, 0x61, 0x97, 0xe7, 0xbb, 0x54, 0xcc, 0x54, 0xed, 0xf9, 0xfc, 0x32, 0xab, 0x92,
0xa3, 0x28, 0xab, 0xf8, 0x58, 0x5c, 0xf4, 0xc9, 0xaf, 0x36, 0xb4, 0x17, 0x79, 0x7e, 0xa0, 0x14,
0xda, 0x59, 0x7c, 0x14, 0x4c, 0x1b, 0x6b, 0xd3, 0x1e, 0x57, 0xb1, 0x64, 0x87, 0x24, 0xdb, 0xb2,
0xdb, 0x0b, 0x93, 0xb1, 0x64, 0x45, 0x5c, 0xed, 0x59, 0xeb, 0xc2, 0x64, 0x4c, 0x47, 0xd0, 0x3d,
0xc6, 0x59, 0xf2, 0x22, 0xca, 0x8a, 0xb5, 0x15, 0x6f, 0x72, 0xfa, 0x01, 0x74, 0xf1, 0x5d, 0x64,
0x55, 0xc9, 0x3a, 0xe3, 0xd6, 0x74, 0xf8, 0xc8, 0xcc, 0xd7, 0x03, 0x9a, 0xf2, 0x6e, 0x13, 0xa5,
0xc0, 0x6b, 0x8f, 0x7e, 0x82, 0x6e, 0x1a, 0x97, 0x55, 0x74, 0x3a, 0x67, 0x4c, 0x1f, 0x6b, 0xd3,
0xfe, 0xe3, 0xc8, 0xbc, 0xac, 0x61, 0x5e, 0xd7, 0x30, 0xc3, 0xeb, 0x1a, 0xdc, 0x90, 0x2e, 0x3f,
0x67, 0xf4, 0x1d, 0xe8, 0x3f, 0x44, 0xb2, 0xdb, 0x57, 0xcc, 0x18, 0x6b, 0xd3, 0x0e, 0xaf, 0x33,
0xba, 0x80, 0xfb, 0xad, 0x48, 0x45, 0x25, 0xa2, 0x22, 0x4f, 0x93, 0x6f, 0x89, 0x28, 0x59, 0x57,
0x4d, 0xf2, 0xf0, 0x9f, 0x49, 0x1c, 0x65, 0xae, 0xa5, 0xf8, 0x93, 0x0f, 0xb7, 0x7f, 0xb3, 0x44,
0x94, 0x93, 0xdf, 0x1a, 0x74, 0xd4, 0xa8, 0xb4, 0x0f, 0xc6, 0xc6, 0x5b, 0x79, 0xfe, 0x17, 0x8f,
0xdc, 0xd0, 0x7b, 0xe8, 0xaf, 0x39, 0x46, 0x4b, 0x2f, 0x08, 0x2d, 0xd7, 0x25, 0x1a, 0x25, 0x30,
0x58, 0xfb, 0x41, 0xd8, 0x90, 0x5b, 0x3a, 0x04, 0x90, 0x8a, 0x83, 0x2e, 0x86, 0x48, 0x5a, 0xea,
0x88, 0x34, 0x6a, 0xd0, 0xbe, 0xf6, 0xd8, 0xac, 0x3f, 0x73, 0xcb, 0x41, 0xd2, 0x69, 0x7a, 0x5c,
0x89, 0xae, 0x08, 0xc7, 0x88, 0xfb, 0xae, 0x3b, 0xb7, 0xec, 0x15, 0x31, 0xe8, 0x1b, 0xb8, 0x53,
0x4e, 0x83, 0xba, 0x94, 0xc1, 0x5b, 0x8e, 0x2e, 0x5a, 0x01, 0x46, 0x21, 0x06, 0x61, 0x14, 0x6c,
0x6c, 0x1b, 0x83, 0x80, 0xf4, 0xfe, 0xa9, 0x3c, 0x59, 0x4b, 0x77, 0xc3, 0x91, 0x80, 0xbc, 0xdb,
0xe6, 0x4e, 0x33, 0x6d, 0x7f, 0x62, 0xc3, 0xe0, 0xf5, 0x3b, 0xd0, 0x3b, 0xe8, 0xa9, 0x3e, 0xe8,
0xa0, 0x43, 0x6e, 0x28, 0x80, 0x2e, 0x0f, 0xa3, 0x43, 0x34, 0xd9, 0x75, 0x8e, 0x4f, 0x3e, 0xc7,
0x68, 0xe1, 0xfb, 0xab, 0xc8, 0xe6, 0x68, 0x85, 0x4b, 0xdf, 0x23, 0xb7, 0xf3, 0xde, 0x57, 0xa3,
0x7e, 0xd9, 0x67, 0x5d, 0x7d, 0xdb, 0xc7, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x3b, 0xcf, 0xed,
0xd9, 0xb4, 0x02, 0x00, 0x00,
func init() { proto.RegisterFile("hapi/release/hook.proto", fileDescriptor_hook_e64400ca8195038e) }
var fileDescriptor_hook_e64400ca8195038e = []byte{
// 473 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xdb, 0x8e, 0xda, 0x3c,
0x10, 0x80, 0x37, 0x1c, 0x02, 0x0c, 0x87, 0xf5, 0x6f, 0xfd, 0x6a, 0x2d, 0x6e, 0x16, 0x21, 0x55,
0xe2, 0x2a, 0x54, 0x5b, 0xf5, 0x01, 0x42, 0xe2, 0x2d, 0x88, 0x88, 0x20, 0x27, 0xa8, 0x52, 0x6f,
0xa2, 0x6c, 0xf1, 0x42, 0x44, 0x88, 0x23, 0x62, 0x5a, 0xf5, 0x81, 0xfb, 0x18, 0x95, 0x2a, 0x3b,
0x21, 0x5d, 0xa9, 0xbd, 0x9b, 0xf9, 0xe6, 0xf3, 0x78, 0xc6, 0x86, 0xb7, 0xc7, 0x38, 0x4f, 0xe6,
0x17, 0x9e, 0xf2, 0xb8, 0xe0, 0xf3, 0xa3, 0x10, 0x27, 0x2b, 0xbf, 0x08, 0x29, 0xf0, 0x40, 0x15,
0xac, 0xaa, 0x30, 0x7e, 0x38, 0x08, 0x71, 0x48, 0xf9, 0x5c, 0xd7, 0x9e, 0xaf, 0x2f, 0x73, 0x99,
0x9c, 0x79, 0x21, 0xe3, 0x73, 0x5e, 0xea, 0xd3, 0x5f, 0x2d, 0x68, 0x2d, 0x85, 0x38, 0x61, 0x0c,
0xad, 0x2c, 0x3e, 0x73, 0x62, 0x4c, 0x8c, 0x59, 0x8f, 0xe9, 0x58, 0xb1, 0x53, 0x92, 0xed, 0x49,
0xa3, 0x64, 0x2a, 0x56, 0x2c, 0x8f, 0xe5, 0x91, 0x34, 0x4b, 0xa6, 0x62, 0x3c, 0x86, 0xee, 0x39,
0xce, 0x92, 0x17, 0x5e, 0x48, 0xd2, 0xd2, 0xbc, 0xce, 0xf1, 0x7b, 0x30, 0xf9, 0x37, 0x9e, 0xc9,
0x82, 0xb4, 0x27, 0xcd, 0xd9, 0xe8, 0x91, 0x58, 0xaf, 0x07, 0xb4, 0xd4, 0xdd, 0x16, 0x55, 0x02,
0xab, 0x3c, 0xfc, 0x11, 0xba, 0x69, 0x5c, 0xc8, 0xe8, 0x72, 0xcd, 0x88, 0x39, 0x31, 0x66, 0xfd,
0xc7, 0xb1, 0x55, 0xae, 0x61, 0xdd, 0xd6, 0xb0, 0xc2, 0xdb, 0x1a, 0xac, 0xa3, 0x5c, 0x76, 0xcd,
0xf0, 0x1b, 0x30, 0xbf, 0xf3, 0xe4, 0x70, 0x94, 0xa4, 0x33, 0x31, 0x66, 0x6d, 0x56, 0x65, 0x78,
0x09, 0xf7, 0x7b, 0x9e, 0x72, 0xc9, 0xa3, 0x5c, 0xa4, 0xc9, 0xd7, 0x84, 0x17, 0xa4, 0xab, 0x27,
0x79, 0xf8, 0xc7, 0x24, 0xae, 0x36, 0xb7, 0x4a, 0xfc, 0xc1, 0x46, 0xfb, 0x3f, 0x59, 0xc2, 0x0b,
0xfc, 0x0e, 0x2a, 0x12, 0xa9, 0x57, 0x14, 0x57, 0x49, 0x7a, 0x13, 0x63, 0xd6, 0x64, 0xc3, 0x92,
0x86, 0x25, 0x9c, 0xfe, 0x34, 0xa0, 0xad, 0x37, 0xc2, 0x7d, 0xe8, 0xec, 0x36, 0xeb, 0x8d, 0xff,
0x79, 0x83, 0xee, 0xf0, 0x3d, 0xf4, 0xb7, 0x8c, 0x46, 0xab, 0x4d, 0x10, 0xda, 0x9e, 0x87, 0x0c,
0x8c, 0x60, 0xb0, 0xf5, 0x83, 0xb0, 0x26, 0x0d, 0x3c, 0x02, 0x50, 0x8a, 0x4b, 0x3d, 0x1a, 0x52,
0xd4, 0xd4, 0x47, 0x94, 0x51, 0x81, 0xd6, 0xad, 0xc7, 0x6e, 0xfb, 0x89, 0xd9, 0x2e, 0x45, 0xed,
0xba, 0xc7, 0x8d, 0x98, 0x9a, 0x30, 0x1a, 0x31, 0xdf, 0xf3, 0x16, 0xb6, 0xb3, 0x46, 0x1d, 0xfc,
0x1f, 0x0c, 0xb5, 0x53, 0xa3, 0x2e, 0x26, 0xf0, 0x3f, 0xa3, 0x1e, 0xb5, 0x03, 0x1a, 0x85, 0x34,
0x08, 0xa3, 0x60, 0xe7, 0x38, 0x34, 0x08, 0x50, 0xef, 0xaf, 0xca, 0x93, 0xbd, 0xf2, 0x76, 0x8c,
0x22, 0x50, 0x77, 0x3b, 0xcc, 0xad, 0xa7, 0xed, 0x4f, 0x1d, 0x18, 0xbc, 0x7e, 0x2e, 0x3c, 0x84,
0x9e, 0xee, 0x43, 0x5d, 0xea, 0xa2, 0x3b, 0x0c, 0x60, 0xaa, 0xc3, 0xd4, 0x45, 0x86, 0xea, 0xba,
0xa0, 0x4f, 0x3e, 0xa3, 0xd1, 0xd2, 0xf7, 0xd7, 0x91, 0xc3, 0xa8, 0x1d, 0xae, 0xfc, 0x0d, 0x6a,
0x2c, 0x7a, 0x5f, 0x3a, 0xd5, 0x07, 0x3c, 0x9b, 0xfa, 0x77, 0x3f, 0xfc, 0x0e, 0x00, 0x00, 0xff,
0xff, 0xce, 0x84, 0xd9, 0x98, 0xdb, 0x02, 0x00, 0x00,
}

@ -38,7 +38,7 @@ const (
Status_PENDING_INSTALL Status_Code = 6
// Status_PENDING_UPGRADE indicates that an upgrade operation is underway.
Status_PENDING_UPGRADE Status_Code = 7
// Status_PENDING_ROLLBACK indicates that an rollback operation is underway.
// Status_PENDING_ROLLBACK indicates that a rollback operation is underway.
Status_PENDING_ROLLBACK Status_Code = 8
)

@ -71,7 +71,18 @@ func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]st
return nil, fmt.Errorf("dependency %q has an invalid version/constraint format: %s", d.Name, err)
}
repoIndex, err := repo.LoadIndexFile(r.helmhome.CacheIndex(repoNames[d.Name]))
// repo does not exist in cache but has url info
cacheRepoName := repoNames[d.Name]
if cacheRepoName == "" && d.Repository != "" {
locked[i] = &chartutil.Dependency{
Name: d.Name,
Repository: d.Repository,
Version: d.Version,
}
continue
}
repoIndex, err := repo.LoadIndexFile(r.helmhome.CacheIndex(cacheRepoName))
if err != nil {
return nil, fmt.Errorf("no cached repo found. (try 'helm repo update'). %s", err)
}

@ -37,15 +37,6 @@ func TestResolve(t *testing.T) {
},
err: true,
},
{
name: "cache index failure",
req: &chartutil.Requirements{
Dependencies: []*chartutil.Dependency{
{Name: "oedipus-rex", Repository: "http://example.com", Version: "1.0.0"},
},
},
err: true,
},
{
name: "chart not found failure",
req: &chartutil.Requirements{

@ -25,7 +25,7 @@ import (
"github.com/jmoiron/sqlx"
migrate "github.com/rubenv/sql-migrate"
// Import pq for potgres dialect
// Import pq for postgres dialect
_ "github.com/lib/pq"
rspb "k8s.io/helm/pkg/proto/hapi/release"
@ -199,7 +199,7 @@ func (s *SQL) Query(labels map[string]string) ([]*rspb.Release, error) {
sqlFilter[dbField] = val
} else {
s.Log("unknown label %s", key)
return nil, fmt.Errorf("unknow label %s", key)
return nil, fmt.Errorf("unknown label %s", key)
}
}
sort.Strings(sqlFilterKeys)

@ -50,7 +50,7 @@ func (s *Storage) Get(name string, version int32) (*rspb.Release, error) {
// Create creates a new storage entry holding the release. An
// error is returned if the storage driver failed to store the
// release, or a release with identical an key already exists.
// release, or a release with identical key already exists.
func (s *Storage) Create(rls *rspb.Release) error {
s.Log("creating release %q", makeKey(rls.Name, rls.Version))
if s.MaxHistory > 0 {

@ -127,6 +127,16 @@ type KubeClient interface {
// by "\n---\n").
Delete(namespace string, reader io.Reader) error
// DeleteWithTimeout destroys one or more resources. If shouldWait is true, the function
// will not return until all the resources have been fully deleted or the provided
// timeout has expired.
//
// namespace must contain a valid existing namespace.
//
// reader must contain a YAML stream (one or more YAML documents separated
// by "\n---\n").
DeleteWithTimeout(namespace string, reader io.Reader, timeout int64, shouldWait bool) error
// WatchUntilReady watch the resource in reader until it is "ready".
//
// For Jobs, "ready" means the job ran to completion (excited without error).
@ -150,7 +160,7 @@ type KubeClient interface {
// BuildUnstructured reads a stream of manifests from a reader and turns them into
// info objects. Manifests are not validated against the schema, but it will fail if
// any resoures types are not known by the apiserver.
// any resources types are not known by the apiserver.
//
// reader must contain a YAML stream (one or more YAML documents separated by "\n---\n").
BuildUnstructured(namespace string, reader io.Reader) (kube.Result, error)
@ -194,6 +204,14 @@ func (p *PrintingKubeClient) Delete(ns string, r io.Reader) error {
return err
}
// DeleteWithTimeout implements KubeClient DeleteWithTimeout.
//
// It only prints out the content to be deleted.
func (p *PrintingKubeClient) DeleteWithTimeout(ns string, r io.Reader, timeout int64, shouldWait bool) error {
_, err := io.Copy(p.Out, r)
return err
}
// WatchUntilReady implements KubeClient WatchUntilReady.
func (p *PrintingKubeClient) WatchUntilReady(ns string, r io.Reader, timeout int64, shouldWait bool) error {
_, err := io.Copy(p.Out, r)
@ -237,6 +255,7 @@ func (p *PrintingKubeClient) WaitAndGetCompletedPodPhase(namespace string, reade
return v1.PodUnknown, err
}
// WaitUntilCRDEstablished implements KubeClient WaitUntilCRDEstablished.
func (p *PrintingKubeClient) WaitUntilCRDEstablished(reader io.Reader, timeout time.Duration) error {
_, err := io.Copy(p.Out, reader)
return err

@ -49,6 +49,9 @@ func (k *mockKubeClient) Get(ns string, r io.Reader) (string, error) {
func (k *mockKubeClient) Delete(ns string, r io.Reader) error {
return nil
}
func (k *mockKubeClient) DeleteWithTimeout(ns string, r io.Reader, timeout int64, shouldWait bool) error {
return nil
}
func (k *mockKubeClient) Update(ns string, currentReader, modifiedReader io.Reader, force bool, recreate bool, timeout int64, shouldWait bool) error {
return nil
}

@ -53,6 +53,9 @@ var deletePolices = map[string]release.Hook_DeletePolicy{
hooks.BeforeHookCreation: release.Hook_BEFORE_HOOK_CREATION,
}
// Timeout used when deleting resources with a hook-delete-policy.
const defaultHookDeleteTimeoutInSeconds = int64(60)
// Manifest represents a manifest file, which has a name and some content.
type Manifest = manifest.Manifest
@ -192,6 +195,18 @@ func (file *manifestFile) sort(result *result) error {
log.Printf("info: skipping unknown hook delete policy: %q", value)
}
})
// Only check for delete timeout annotation if there is a deletion policy.
if len(h.DeletePolicies) > 0 {
h.DeleteTimeout = defaultHookDeleteTimeoutInSeconds
operateAnnotationValues(entry, hooks.HookDeleteTimeoutAnno, func(value string) {
timeout, err := strconv.ParseInt(value, 10, 64)
if err != nil || timeout < 0 {
log.Printf("info: ignoring invalid hook delete timeout value: %q", value)
}
h.DeleteTimeout = timeout
})
}
}
return nil
}

@ -17,8 +17,10 @@ limitations under the License.
package tiller
import (
"bytes"
"reflect"
"testing"
"text/template"
"github.com/ghodss/yaml"
@ -229,6 +231,110 @@ metadata:
}
}
var manifestTemplate = `
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: example.com
labels:
app: example-crd
annotations:
helm.sh/hook: crd-install
{{- if .HookDeletePolicy}}
{{ .HookDeletePolicy }}
{{- end }}
{{- if .HookDeleteTimeout}}
{{ .HookDeleteTimeout }}
{{- end }}
spec:
group: example.com
version: v1alpha1
names:
kind: example
plural: examples
scope: Cluster
`
type manifestTemplateData struct {
HookDeletePolicy, HookDeleteTimeout string
}
func TestSortManifestsHookDeletion(t *testing.T) {
testCases := map[string]struct {
templateData manifestTemplateData
hasDeletePolicy bool
deletePolicy release.Hook_DeletePolicy
deleteTimeout int64
}{
"No delete policy": {
templateData: manifestTemplateData{},
hasDeletePolicy: false,
deletePolicy: release.Hook_BEFORE_HOOK_CREATION,
deleteTimeout: 0,
},
"Delete policy, no delete timeout": {
templateData: manifestTemplateData{
HookDeletePolicy: "helm.sh/hook-delete-policy: before-hook-creation",
},
hasDeletePolicy: true,
deletePolicy: release.Hook_BEFORE_HOOK_CREATION,
deleteTimeout: defaultHookDeleteTimeoutInSeconds,
},
"Delete policy and delete timeout": {
templateData: manifestTemplateData{
HookDeletePolicy: "helm.sh/hook-delete-policy: hook-succeeded",
HookDeleteTimeout: `helm.sh/hook-delete-timeout: "420"`,
},
hasDeletePolicy: true,
deletePolicy: release.Hook_SUCCEEDED,
deleteTimeout: 420,
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
tmpl := template.Must(template.New("manifest").Parse(manifestTemplate))
var buf bytes.Buffer
err := tmpl.Execute(&buf, tc.templateData)
if err != nil {
t.Error(err)
}
manifests := map[string]string{
"exampleManifest": buf.String(),
}
hs, _, err := sortManifests(manifests, chartutil.NewVersionSet("v1", "v1beta1"), InstallOrder)
if err != nil {
t.Error(err)
}
if got, want := len(hs), 1; got != want {
t.Errorf("expected %d hooks, but got %d", want, got)
}
hook := hs[0]
if len(hook.DeletePolicies) == 0 {
if tc.hasDeletePolicy {
t.Errorf("expected a policy, but got zero")
}
} else {
if !tc.hasDeletePolicy {
t.Errorf("expected no delete policies, but got one")
}
policy := hook.DeletePolicies[0]
if got, want := policy, tc.deletePolicy; got != want {
t.Errorf("expected delete policy %q, but got %q", want, got)
}
}
if got, want := hook.DeleteTimeout, tc.deleteTimeout; got != want {
t.Errorf("expected timeout %d, but got %d", want, got)
}
})
}
}
func TestVersionSet(t *testing.T) {
vs := chartutil.NewVersionSet("v1", "v1beta1", "extensions/alpha5", "batch/v1")

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save