Added a --wait flag for helm init which pings the Tiller server and ensures that it is ready to receive requests

Fixes #2114

Signed-off-by: Alex Johnson <ajohnson@bombora.com>
pull/3238/head
Alex Johnson 7 years ago
parent 512bfee98e
commit b29d25ef0b

@ -31,6 +31,7 @@ import (
"k8s.io/apimachinery/pkg/util/yaml" "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/helm/cmd/helm/installer" "k8s.io/helm/cmd/helm/installer"
"k8s.io/helm/pkg/getter" "k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
@ -79,11 +80,13 @@ type initCmd struct {
forceUpgrade bool forceUpgrade bool
skipRefresh bool skipRefresh bool
out io.Writer out io.Writer
client helm.Interface
home helmpath.Home home helmpath.Home
opts installer.Options opts installer.Options
kubeClient kubernetes.Interface kubeClient kubernetes.Interface
serviceAccount string serviceAccount string
maxHistory int maxHistory int
wait bool
} }
func newInitCmd(out io.Writer) *cobra.Command { func newInitCmd(out io.Writer) *cobra.Command {
@ -99,6 +102,8 @@ func newInitCmd(out io.Writer) *cobra.Command {
} }
i.namespace = settings.TillerNamespace i.namespace = settings.TillerNamespace
i.home = settings.Home i.home = settings.Home
i.client = ensureHelmClient(i.client)
return i.run() return i.run()
}, },
} }
@ -111,6 +116,7 @@ func newInitCmd(out io.Writer) *cobra.Command {
f.BoolVarP(&i.clientOnly, "client-only", "c", false, "if set does not install Tiller") f.BoolVarP(&i.clientOnly, "client-only", "c", false, "if set does not install Tiller")
f.BoolVar(&i.dryRun, "dry-run", false, "do not install local or remote") 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.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.BoolVar(&tlsEnable, "tiller-tls", false, "install Tiller with TLS enabled") 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") f.BoolVar(&tlsVerify, "tiller-tls-verify", false, "install Tiller with TLS enabled and to verify remote certificates")
@ -292,12 +298,18 @@ func (i *initCmd) run() error {
if err := installer.Upgrade(i.kubeClient, &i.opts); err != nil { if err := installer.Upgrade(i.kubeClient, &i.opts); err != nil {
return fmt.Errorf("error when upgrading: %s", err) return fmt.Errorf("error when upgrading: %s", err)
} }
if err := i.ping(); err != nil {
return err
}
fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been upgraded to the current version.") fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been upgraded to the current version.")
} else { } else {
fmt.Fprintln(i.out, "Warning: Tiller is already installed in the cluster.\n"+ 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.)") "(Use --client-only to suppress this message, or --upgrade to upgrade Tiller to the current version.)")
} }
} else { } else {
if err := i.ping(); err != nil {
return err
}
fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been installed into your Kubernetes Cluster.") fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been installed into your Kubernetes Cluster.")
} }
} else { } else {
@ -308,6 +320,16 @@ func (i *initCmd) run() error {
return nil return nil
} }
func (i *initCmd) ping() error {
if i.wait {
if err := i.client.PingTiller(); err != nil {
return fmt.Errorf("could not ping Tiller: %s", err)
}
}
return nil
}
// ensureDirectories checks to see if $HELM_HOME exists. // ensureDirectories checks to see if $HELM_HOME exists.
// //
// If $HELM_HOME does not exist, this function will create it. // If $HELM_HOME does not exist, this function will create it.

@ -53,6 +53,7 @@ helm init
--tiller-tls-verify install Tiller with TLS enabled and to verify remote certificates --tiller-tls-verify install Tiller with TLS enabled and to verify remote certificates
--tls-ca-cert string path to CA root certificate --tls-ca-cert string path to CA root certificate
--upgrade upgrade if Tiller is already installed --upgrade upgrade if Tiller is already installed
--wait block until Tiller is running and ready to receive requests
``` ```
### Options inherited from parent commands ### Options inherited from parent commands

@ -293,6 +293,12 @@ func (h *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-ch
return h.test(ctx, req) return h.test(ctx, req)
} }
// PingTiller pings the Tiller pod and ensure's that it is up and runnning
func (h *Client) PingTiller() error {
ctx := NewContext()
return h.ping(ctx)
}
// connect returns a gRPC connection to Tiller or error. The gRPC dial options // connect returns a gRPC connection to Tiller or error. The gRPC dial options
// are constructed here. // are constructed here.
func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) { func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) {
@ -467,3 +473,15 @@ func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan
return ch, errc return ch, errc
} }
// Executes tiller.Ping RPC.
func (h *Client) ping(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)
}

@ -184,6 +184,11 @@ func (c *FakeClient) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (
return results, errc return results, errc
} }
// PingTiller pings the Tiller pod and ensure's that it is up and runnning
func (c *FakeClient) PingTiller() error {
return nil
}
// MockHookTemplate is the hook template used for all mock release objects. // MockHookTemplate is the hook template used for all mock release objects.
var MockHookTemplate = `apiVersion: v1 var MockHookTemplate = `apiVersion: v1
kind: Job kind: Job

@ -35,4 +35,5 @@ type Interface interface {
ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error)
GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error)
RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error)
PingTiller() error
} }

@ -949,6 +949,8 @@ type ReleaseServiceClient interface {
GetHistory(ctx context.Context, in *GetHistoryRequest, opts ...grpc.CallOption) (*GetHistoryResponse, error) GetHistory(ctx context.Context, in *GetHistoryRequest, opts ...grpc.CallOption) (*GetHistoryResponse, error)
// RunReleaseTest executes the tests defined of a named release // RunReleaseTest executes the tests defined of a named release
RunReleaseTest(ctx context.Context, in *TestReleaseRequest, opts ...grpc.CallOption) (ReleaseService_RunReleaseTestClient, error) RunReleaseTest(ctx context.Context, in *TestReleaseRequest, opts ...grpc.CallOption) (ReleaseService_RunReleaseTestClient, error)
// PingTiller sends a test/ping signal to Tiller to ensure that it's up
PingTiller(ctx context.Context) error
} }
type releaseServiceClient struct { type releaseServiceClient struct {
@ -1078,6 +1080,14 @@ func (c *releaseServiceClient) RunReleaseTest(ctx context.Context, in *TestRelea
return x, nil return x, nil
} }
func (c *releaseServiceClient) PingTiller(ctx context.Context) error {
err := grpc.Invoke(ctx, "/hapi.services.tiller.ReleaseService/PingTiller", "Ping", nil, c.cc, grpc.FailFast(false))
if err != nil {
return err
}
return nil
}
type ReleaseService_RunReleaseTestClient interface { type ReleaseService_RunReleaseTestClient interface {
Recv() (*TestReleaseResponse, error) Recv() (*TestReleaseResponse, error)
grpc.ClientStream grpc.ClientStream
@ -1300,6 +1310,10 @@ func _ReleaseService_RunReleaseTest_Handler(srv interface{}, stream grpc.ServerS
return srv.(ReleaseServiceServer).RunReleaseTest(m, &releaseServiceRunReleaseTestServer{stream}) return srv.(ReleaseServiceServer).RunReleaseTest(m, &releaseServiceRunReleaseTestServer{stream})
} }
func _ReleaseService_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
return "Pong", nil
}
type ReleaseService_RunReleaseTestServer interface { type ReleaseService_RunReleaseTestServer interface {
Send(*TestReleaseResponse) error Send(*TestReleaseResponse) error
grpc.ServerStream grpc.ServerStream
@ -1349,6 +1363,10 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
MethodName: "GetHistory", MethodName: "GetHistory",
Handler: _ReleaseService_GetHistory_Handler, Handler: _ReleaseService_GetHistory_Handler,
}, },
{
MethodName: "PingTiller",
Handler: _ReleaseService_Ping_Handler,
},
}, },
Streams: []grpc.StreamDesc{ Streams: []grpc.StreamDesc{
{ {

Loading…
Cancel
Save