Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repair 'helm init --wait': context deadline exceeded #3506

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions _proto/hapi/chart/metadata.proto
Expand Up @@ -88,6 +88,6 @@ message Metadata {
// made available for inspection by other applications.
map<string,string> annotations = 16;

// KubeVersion is a SemVer constraint specifying the version of Kubernetes required.
string kubeVersion = 17;
// KubeVersion is a SemVer constraints on what version of Kubernetes is required.
string kubeVersion = 17;
}
10 changes: 10 additions & 0 deletions _proto/hapi/services/tiller.proto
Expand Up @@ -83,6 +83,10 @@ service ReleaseService {
// RunReleaseTest executes the tests defined of a named release
rpc RunReleaseTest(TestReleaseRequest) returns (stream TestReleaseResponse) {
}

// PingTiller sends a test/pingTiller signal to Tiller to ensure that it's up
rpc PingTiller(PingTillerRequest) returns (PingTillerResponse) {
}
}

// ListReleasesRequest requests a list of releases.
Expand Down Expand Up @@ -335,3 +339,9 @@ message TestReleaseResponse {
hapi.release.TestRun.Status status = 2;

}

message PingTillerRequest {
}

message PingTillerResponse {
}
2 changes: 1 addition & 1 deletion cmd/helm/delete.go
Expand Up @@ -57,7 +57,7 @@ func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command {
SuggestFor: []string{"remove", "rm"},
Short: "given a release name, delete the release from Kubernetes",
Long: deleteDesc,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New("command 'delete' requires a release name")
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/get.go
Expand Up @@ -57,7 +57,7 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
Use: "get [flags] RELEASE_NAME",
Short: "download a named release",
Long: getHelp,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/get_hooks.go
Expand Up @@ -47,7 +47,7 @@ func newGetHooksCmd(client helm.Interface, out io.Writer) *cobra.Command {
Use: "hooks [flags] RELEASE_NAME",
Short: "download all hooks for a named release",
Long: getHooksHelp,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/get_manifest.go
Expand Up @@ -49,7 +49,7 @@ func newGetManifestCmd(client helm.Interface, out io.Writer) *cobra.Command {
Use: "manifest [flags] RELEASE_NAME",
Short: "download the manifest for a named release",
Long: getManifestHelp,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/get_values.go
Expand Up @@ -47,7 +47,7 @@ func newGetValuesCmd(client helm.Interface, out io.Writer) *cobra.Command {
Use: "values [flags] RELEASE_NAME",
Short: "download the values file for a named release",
Long: getValuesHelp,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
Expand Down
32 changes: 26 additions & 6 deletions cmd/helm/helm.go
Expand Up @@ -165,14 +165,34 @@ func markDeprecated(cmd *cobra.Command, notice string) *cobra.Command {
return cmd
}

func setupConnection(c *cobra.Command, args []string) error {
if settings.TillerHost == "" {
config, client, err := getKubeClient(settings.KubeContext)
if err != nil {
func waitTillerPodAndSetupConnection(waitTimeout int) error {
kubeConfig, kubeClient, err := getKubeClient(settings.KubeContext)
if err != nil {
return err
}

if portforwarder.WaitTillerPod(kubeClient.CoreV1(), settings.TillerNamespace, waitTimeout) {
if err = setupConnection(kubeClient, kubeConfig); err != nil {
return err
}
} else {
return fmt.Errorf("tiller pod not found, polling deadline exceeded")
}

return nil
}

tunnel, err := portforwarder.New(settings.TillerNamespace, client, config)
func setupConnectionCobraPreRunHook(_ *cobra.Command, _ []string) error {
kubeConfig, kubeClient, err := getKubeClient(settings.KubeContext)
if err != nil {
return err
}
return setupConnection(kubeClient, kubeConfig)
}

func setupConnection(kubeClient kubernetes.Interface, kubeConfig *rest.Config) error {
if settings.TillerHost == "" {
tunnel, err := portforwarder.New(settings.TillerNamespace, kubeClient, kubeConfig)
if err != nil {
return err
}
Expand All @@ -181,7 +201,7 @@ func setupConnection(c *cobra.Command, args []string) error {
debug("Created tunnel using local port: '%d'\n", tunnel.Local)
}

// Set up the gRPC config.
// Set up the gRPC kubeConfig.
debug("SERVER: %q\n", settings.TillerHost)

// Plugin support.
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/history.go
Expand Up @@ -61,7 +61,7 @@ func newHistoryCmd(c helm.Interface, w io.Writer) *cobra.Command {
Long: historyHelp,
Short: "fetch release history",
Aliases: []string{"hist"},
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
switch {
case len(args) == 0:
Expand Down
18 changes: 11 additions & 7 deletions cmd/helm/init.go
Expand Up @@ -31,7 +31,6 @@ import (
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/helm/cmd/helm/installer"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/repo"
)
Expand Down Expand Up @@ -80,14 +79,14 @@ type initCmd struct {
forceUpgrade bool
skipRefresh bool
out io.Writer
client helm.Interface
home helmpath.Home
opts installer.Options
kubeClient kubernetes.Interface
serviceAccount string
maxHistory int
replicas int
wait bool
waitTimeout int
}

func newInitCmd(out io.Writer) *cobra.Command {
Expand All @@ -103,7 +102,6 @@ func newInitCmd(out io.Writer) *cobra.Command {
}
i.namespace = settings.TillerNamespace
i.home = settings.Home
i.client = ensureHelmClient(i.client)

return i.run()
},
Expand All @@ -118,6 +116,7 @@ func newInitCmd(out io.Writer) *cobra.Command {
f.BoolVar(&i.dryRun, "dry-run", false, "do not install local or remote")
f.BoolVar(&i.skipRefresh, "skip-refresh", false, "do not refresh (download) the local repository cache")
f.BoolVar(&i.wait, "wait", false, "block until Tiller is running and ready to receive requests")
f.IntVar(&i.waitTimeout, "wait-timeout", 300, "time in seconds to wait for tiller pod readiness")

f.BoolVar(&tlsEnable, "tiller-tls", false, "install Tiller with TLS enabled")
f.BoolVar(&tlsVerify, "tiller-tls-verify", false, "install Tiller with TLS enabled and to verify remote certificates")
Expand Down Expand Up @@ -301,7 +300,7 @@ func (i *initCmd) run() error {
if err := installer.Upgrade(i.kubeClient, &i.opts); err != nil {
return fmt.Errorf("error when upgrading: %s", err)
}
if err := i.ping(); err != nil {
if err := i.ensureTillerReady(); err != nil {
return err
}
fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been upgraded to the current version.")
Expand All @@ -310,7 +309,7 @@ func (i *initCmd) run() error {
"(Use --client-only to suppress this message, or --upgrade to upgrade Tiller to the current version.)")
}
} else {
if err := i.ping(); err != nil {
if err := i.ensureTillerReady(); err != nil {
return err
}
fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been installed into your Kubernetes Cluster.\n\n"+
Expand All @@ -325,9 +324,14 @@ func (i *initCmd) run() error {
return nil
}

func (i *initCmd) ping() error {
func (i *initCmd) ensureTillerReady() error {
if i.wait {
if err := i.client.PingTiller(); err != nil {
if err := waitTillerPodAndSetupConnection(i.waitTimeout); err != nil {
return err
}

client := newClient()
if err := client.PingTiller(); err != nil {
return fmt.Errorf("could not ping Tiller: %s", err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/install.go
Expand Up @@ -153,7 +153,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
Use: "install [CHART]",
Short: "install a chart archive",
Long: installDesc,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(len(args), "chart name"); err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/list.go
Expand Up @@ -88,7 +88,7 @@ func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
Short: "list releases",
Long: listHelp,
Aliases: []string{"ls"},
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
list.filter = strings.Join(args, " ")
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/load_plugins.go
Expand Up @@ -103,7 +103,7 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) {
if _, err := processParent(cmd, args); err != nil {
return err
}
return setupConnection(cmd, args)
return setupConnectionCobraPreRunHook(cmd, args)
}
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/release_testing.go
Expand Up @@ -51,7 +51,7 @@ func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command {
Use: "test [RELEASE]",
Short: "test a release",
Long: releaseTestDesc,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(len(args), "release name"); err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/reset.go
Expand Up @@ -58,7 +58,7 @@ func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command {
Short: "uninstalls Tiller from a cluster",
Long: resetDesc,
PreRunE: func(cmd *cobra.Command, args []string) error {
if err := setupConnection(cmd, args); !d.force && err != nil {
if err := setupConnectionCobraPreRunHook(cmd, args); !d.force && err != nil {
return err
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/rollback.go
Expand Up @@ -57,7 +57,7 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command {
Use: "rollback [flags] [RELEASE] [REVISION]",
Short: "roll back a release to a previous revision",
Long: rollbackDesc,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(len(args), "release name", "revision number"); err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/status.go
Expand Up @@ -63,7 +63,7 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command {
Use: "status [flags] RELEASE_NAME",
Short: "displays the status of the named release",
Long: statusHelp,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/upgrade.go
Expand Up @@ -91,7 +91,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
Use: "upgrade [RELEASE] [CHART]",
Short: "upgrade a release",
Long: upgradeDesc,
PreRunE: setupConnection,
PreRunE: setupConnectionCobraPreRunHook,
RunE: func(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(len(args), "release name", "chart path"); err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/version.go
Expand Up @@ -76,7 +76,7 @@ func newVersionCmd(c helm.Interface, out io.Writer) *cobra.Command {
if version.showServer {
// We do this manually instead of in PreRun because we only
// need a tunnel if server version is requested.
setupConnection(cmd, args)
setupConnectionCobraPreRunHook(cmd, args)
}
version.client = ensureHelmClient(version.client)
return version.run()
Expand Down
1 change: 1 addition & 0 deletions docs/helm/helm_init.md
Expand Up @@ -55,6 +55,7 @@ helm init
--tls-ca-cert string path to CA root certificate
--upgrade upgrade if Tiller is already installed
--wait block until Tiller is running and ready to receive requests
--wait-timeout int time in seconds to wait for tiller pod readiness (default 300)
```

### Options inherited from parent commands
Expand Down
6 changes: 3 additions & 3 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion glide.yaml
Expand Up @@ -19,7 +19,7 @@ import:
version: ~1.3.1
- package: github.com/technosophos/moniker
- package: github.com/golang/protobuf
version: 4bd1920723d7b7c925de087aa32e2187708897f7
version: 47eb67eaf5cab63c58956d4d4ce86b03ad5eaa03
subpackages:
- proto
- ptypes/any
Expand Down
10 changes: 6 additions & 4 deletions pkg/helm/client.go
Expand Up @@ -300,7 +300,7 @@ func (h *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-ch
// PingTiller pings the Tiller pod and ensure's that it is up and running
func (h *Client) PingTiller() error {
ctx := NewContext()
return h.ping(ctx)
return h.pingTiller(ctx)
}

// connect returns a gRPC connection to Tiller or error. The gRPC dial options
Expand Down Expand Up @@ -480,14 +480,16 @@ func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan
return ch, errc
}

// Executes tiller.Ping RPC.
func (h *Client) ping(ctx context.Context) error {
// Executes tiller.PingTiller RPC.
func (h *Client) pingTiller(ctx context.Context) error {
c, err := h.connect(ctx)
if err != nil {
return err
}
defer c.Close()

rlc := rls.NewReleaseServiceClient(c)
return rlc.PingTiller(ctx)
_, err = rlc.PingTiller(ctx, &rls.PingTillerRequest{})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @theoriginalalex, would you mind taking a look at this? Was there a way in proto code that we could actually send a request over gRPC without the need to send a request body? That would retain backwards compatibility, but I'm not too concerned given that this is a relatively new feature to Helm.

Thanks!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just sending a "Ping" string earlier, sending this empty struct does the same job, I think.
https://github.com/kubernetes/helm/blob/master/pkg/proto/hapi/services/tiller.pb.go#L1084

And the server currently just returns "Pong" no matter what the input is, so I don't think this breaks backwards compatibility.
https://github.com/kubernetes/helm/blob/master/pkg/proto/hapi/services/tiller.pb.go#L1314


return err
}
33 changes: 33 additions & 0 deletions pkg/helm/portforwarder/portforwarder.go
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/client-go/rest"

"k8s.io/helm/pkg/kube"
"time"
)

var (
Expand All @@ -53,6 +54,38 @@ func getTillerPodName(client corev1.PodsGetter, namespace string) (string, error
return pod.ObjectMeta.GetName(), nil
}

func WaitTillerPod(client corev1.PodsGetter, namespace string, waitTimeout int) bool {
deadlinePollingChan := time.NewTimer(time.Duration(waitTimeout) * time.Second).C
checkTillerPodTicker := time.NewTicker(500 * time.Millisecond)
doneChan := make(chan bool)

go func() {
for range checkTillerPodTicker.C {
_, err := getTillerPodName(client, namespace)
if err == nil {
doneChan <- true
break
}
}
}()

podExists := false
loop:
for {
select {
case <-deadlinePollingChan:
break loop
case <-doneChan:
podExists = true
break loop
}
}

checkTillerPodTicker.Stop()

return podExists
}

func getFirstRunningPod(client corev1.PodsGetter, namespace string, selector labels.Selector) (*v1.Pod, error) {
options := metav1.ListOptions{LabelSelector: selector.String()}
pods, err := client.Pods(namespace).List(options)
Expand Down