github.com/lrills/helm@v2.8.1+incompatible/pkg/helm/client.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package helm // import "k8s.io/helm/pkg/helm" 18 19 import ( 20 "io" 21 "time" 22 23 "golang.org/x/net/context" 24 "google.golang.org/grpc" 25 "google.golang.org/grpc/credentials" 26 "google.golang.org/grpc/keepalive" 27 28 "k8s.io/helm/pkg/chartutil" 29 "k8s.io/helm/pkg/proto/hapi/chart" 30 rls "k8s.io/helm/pkg/proto/hapi/services" 31 ) 32 33 // Client manages client side of the Helm-Tiller protocol. 34 type Client struct { 35 opts options 36 } 37 38 // NewClient creates a new client. 39 func NewClient(opts ...Option) *Client { 40 var c Client 41 return c.Option(opts...) 42 } 43 44 // Option configures the Helm client with the provided options. 45 func (h *Client) Option(opts ...Option) *Client { 46 for _, opt := range opts { 47 opt(&h.opts) 48 } 49 return h 50 } 51 52 // ListReleases lists the current releases. 53 func (h *Client) ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error) { 54 reqOpts := h.opts 55 for _, opt := range opts { 56 opt(&reqOpts) 57 } 58 req := &reqOpts.listReq 59 ctx := NewContext() 60 61 if reqOpts.before != nil { 62 if err := reqOpts.before(ctx, req); err != nil { 63 return nil, err 64 } 65 } 66 return h.list(ctx, req) 67 } 68 69 // InstallRelease loads a chart from chstr, installs it, and returns the release response. 70 func (h *Client) InstallRelease(chstr, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) { 71 // load the chart to install 72 chart, err := chartutil.Load(chstr) 73 if err != nil { 74 return nil, err 75 } 76 77 return h.InstallReleaseFromChart(chart, ns, opts...) 78 } 79 80 // InstallReleaseFromChart installs a new chart and returns the release response. 81 func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) { 82 // apply the install options 83 reqOpts := h.opts 84 for _, opt := range opts { 85 opt(&reqOpts) 86 } 87 req := &reqOpts.instReq 88 req.Chart = chart 89 req.Namespace = ns 90 req.DryRun = reqOpts.dryRun 91 req.DisableHooks = reqOpts.disableHooks 92 req.ReuseName = reqOpts.reuseName 93 ctx := NewContext() 94 95 if reqOpts.before != nil { 96 if err := reqOpts.before(ctx, req); err != nil { 97 return nil, err 98 } 99 } 100 err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values) 101 if err != nil { 102 return nil, err 103 } 104 err = chartutil.ProcessRequirementsImportValues(req.Chart) 105 if err != nil { 106 return nil, err 107 } 108 109 return h.install(ctx, req) 110 } 111 112 // DeleteRelease uninstalls a named release and returns the response. 113 func (h *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) { 114 // apply the uninstall options 115 reqOpts := h.opts 116 for _, opt := range opts { 117 opt(&reqOpts) 118 } 119 120 if reqOpts.dryRun { 121 // In the dry run case, just see if the release exists 122 r, err := h.ReleaseContent(rlsName) 123 if err != nil { 124 return &rls.UninstallReleaseResponse{}, err 125 } 126 return &rls.UninstallReleaseResponse{Release: r.Release}, nil 127 } 128 129 req := &reqOpts.uninstallReq 130 req.Name = rlsName 131 req.DisableHooks = reqOpts.disableHooks 132 ctx := NewContext() 133 134 if reqOpts.before != nil { 135 if err := reqOpts.before(ctx, req); err != nil { 136 return nil, err 137 } 138 } 139 return h.delete(ctx, req) 140 } 141 142 // UpdateRelease loads a chart from chstr and updates a release to a new/different chart. 143 func (h *Client) UpdateRelease(rlsName string, chstr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) { 144 // load the chart to update 145 chart, err := chartutil.Load(chstr) 146 if err != nil { 147 return nil, err 148 } 149 150 return h.UpdateReleaseFromChart(rlsName, chart, opts...) 151 } 152 153 // UpdateReleaseFromChart updates a release to a new/different chart. 154 func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) { 155 // apply the update options 156 reqOpts := h.opts 157 for _, opt := range opts { 158 opt(&reqOpts) 159 } 160 req := &reqOpts.updateReq 161 req.Chart = chart 162 req.DryRun = reqOpts.dryRun 163 req.Name = rlsName 164 req.DisableHooks = reqOpts.disableHooks 165 req.Recreate = reqOpts.recreate 166 req.Force = reqOpts.force 167 req.ResetValues = reqOpts.resetValues 168 req.ReuseValues = reqOpts.reuseValues 169 ctx := NewContext() 170 171 if reqOpts.before != nil { 172 if err := reqOpts.before(ctx, req); err != nil { 173 return nil, err 174 } 175 } 176 err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values) 177 if err != nil { 178 return nil, err 179 } 180 err = chartutil.ProcessRequirementsImportValues(req.Chart) 181 if err != nil { 182 return nil, err 183 } 184 185 return h.update(ctx, req) 186 } 187 188 // GetVersion returns the server version. 189 func (h *Client) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error) { 190 reqOpts := h.opts 191 for _, opt := range opts { 192 opt(&reqOpts) 193 } 194 req := &rls.GetVersionRequest{} 195 ctx := NewContext() 196 197 if reqOpts.before != nil { 198 if err := reqOpts.before(ctx, req); err != nil { 199 return nil, err 200 } 201 } 202 return h.version(ctx, req) 203 } 204 205 // RollbackRelease rolls back a release to the previous version. 206 func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) { 207 reqOpts := h.opts 208 for _, opt := range opts { 209 opt(&reqOpts) 210 } 211 req := &reqOpts.rollbackReq 212 req.Recreate = reqOpts.recreate 213 req.Force = reqOpts.force 214 req.DisableHooks = reqOpts.disableHooks 215 req.DryRun = reqOpts.dryRun 216 req.Name = rlsName 217 ctx := NewContext() 218 219 if reqOpts.before != nil { 220 if err := reqOpts.before(ctx, req); err != nil { 221 return nil, err 222 } 223 } 224 return h.rollback(ctx, req) 225 } 226 227 // ReleaseStatus returns the given release's status. 228 func (h *Client) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) { 229 reqOpts := h.opts 230 for _, opt := range opts { 231 opt(&reqOpts) 232 } 233 req := &reqOpts.statusReq 234 req.Name = rlsName 235 ctx := NewContext() 236 237 if reqOpts.before != nil { 238 if err := reqOpts.before(ctx, req); err != nil { 239 return nil, err 240 } 241 } 242 return h.status(ctx, req) 243 } 244 245 // ReleaseContent returns the configuration for a given release. 246 func (h *Client) ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) { 247 reqOpts := h.opts 248 for _, opt := range opts { 249 opt(&reqOpts) 250 } 251 req := &reqOpts.contentReq 252 req.Name = rlsName 253 ctx := NewContext() 254 255 if reqOpts.before != nil { 256 if err := reqOpts.before(ctx, req); err != nil { 257 return nil, err 258 } 259 } 260 return h.content(ctx, req) 261 } 262 263 // ReleaseHistory returns a release's revision history. 264 func (h *Client) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) { 265 reqOpts := h.opts 266 for _, opt := range opts { 267 opt(&reqOpts) 268 } 269 270 req := &reqOpts.histReq 271 req.Name = rlsName 272 ctx := NewContext() 273 274 if reqOpts.before != nil { 275 if err := reqOpts.before(ctx, req); err != nil { 276 return nil, err 277 } 278 } 279 return h.history(ctx, req) 280 } 281 282 // RunReleaseTest executes a pre-defined test on a release. 283 func (h *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error) { 284 reqOpts := h.opts 285 for _, opt := range opts { 286 opt(&reqOpts) 287 } 288 289 req := &reqOpts.testReq 290 req.Name = rlsName 291 ctx := NewContext() 292 293 return h.test(ctx, req) 294 } 295 296 // PingTiller pings the Tiller pod and ensure's that it is up and runnning 297 func (h *Client) PingTiller() error { 298 ctx := NewContext() 299 return h.ping(ctx) 300 } 301 302 // connect returns a gRPC connection to Tiller or error. The gRPC dial options 303 // are constructed here. 304 func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) { 305 opts := []grpc.DialOption{ 306 grpc.WithTimeout(5 * time.Second), 307 grpc.WithBlock(), 308 grpc.WithKeepaliveParams(keepalive.ClientParameters{ 309 // Send keepalive every 30 seconds to prevent the connection from 310 // getting closed by upstreams 311 Time: time.Duration(30) * time.Second, 312 }), 313 } 314 switch { 315 case h.opts.useTLS: 316 opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(h.opts.tlsConfig))) 317 default: 318 opts = append(opts, grpc.WithInsecure()) 319 } 320 if conn, err = grpc.Dial(h.opts.host, opts...); err != nil { 321 return nil, err 322 } 323 return conn, nil 324 } 325 326 // Executes tiller.ListReleases RPC. 327 func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.ListReleasesResponse, error) { 328 c, err := h.connect(ctx) 329 if err != nil { 330 return nil, err 331 } 332 defer c.Close() 333 334 rlc := rls.NewReleaseServiceClient(c) 335 s, err := rlc.ListReleases(ctx, req) 336 if err != nil { 337 return nil, err 338 } 339 340 return s.Recv() 341 } 342 343 // Executes tiller.InstallRelease RPC. 344 func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) { 345 c, err := h.connect(ctx) 346 if err != nil { 347 return nil, err 348 } 349 defer c.Close() 350 351 rlc := rls.NewReleaseServiceClient(c) 352 return rlc.InstallRelease(ctx, req) 353 } 354 355 // Executes tiller.UninstallRelease RPC. 356 func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) { 357 c, err := h.connect(ctx) 358 if err != nil { 359 return nil, err 360 } 361 defer c.Close() 362 363 rlc := rls.NewReleaseServiceClient(c) 364 return rlc.UninstallRelease(ctx, req) 365 } 366 367 // Executes tiller.UpdateRelease RPC. 368 func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) { 369 c, err := h.connect(ctx) 370 if err != nil { 371 return nil, err 372 } 373 defer c.Close() 374 375 rlc := rls.NewReleaseServiceClient(c) 376 return rlc.UpdateRelease(ctx, req) 377 } 378 379 // Executes tiller.RollbackRelease RPC. 380 func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) { 381 c, err := h.connect(ctx) 382 if err != nil { 383 return nil, err 384 } 385 defer c.Close() 386 387 rlc := rls.NewReleaseServiceClient(c) 388 return rlc.RollbackRelease(ctx, req) 389 } 390 391 // Executes tiller.GetReleaseStatus RPC. 392 func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) { 393 c, err := h.connect(ctx) 394 if err != nil { 395 return nil, err 396 } 397 defer c.Close() 398 399 rlc := rls.NewReleaseServiceClient(c) 400 return rlc.GetReleaseStatus(ctx, req) 401 } 402 403 // Executes tiller.GetReleaseContent RPC. 404 func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) (*rls.GetReleaseContentResponse, error) { 405 c, err := h.connect(ctx) 406 if err != nil { 407 return nil, err 408 } 409 defer c.Close() 410 411 rlc := rls.NewReleaseServiceClient(c) 412 return rlc.GetReleaseContent(ctx, req) 413 } 414 415 // Executes tiller.GetVersion RPC. 416 func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls.GetVersionResponse, error) { 417 c, err := h.connect(ctx) 418 if err != nil { 419 return nil, err 420 } 421 defer c.Close() 422 423 rlc := rls.NewReleaseServiceClient(c) 424 return rlc.GetVersion(ctx, req) 425 } 426 427 // Executes tiller.GetHistory RPC. 428 func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.GetHistoryResponse, error) { 429 c, err := h.connect(ctx) 430 if err != nil { 431 return nil, err 432 } 433 defer c.Close() 434 435 rlc := rls.NewReleaseServiceClient(c) 436 return rlc.GetHistory(ctx, req) 437 } 438 439 // Executes tiller.TestRelease RPC. 440 func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) { 441 errc := make(chan error, 1) 442 c, err := h.connect(ctx) 443 if err != nil { 444 errc <- err 445 return nil, errc 446 } 447 448 ch := make(chan *rls.TestReleaseResponse, 1) 449 go func() { 450 defer close(errc) 451 defer close(ch) 452 defer c.Close() 453 454 rlc := rls.NewReleaseServiceClient(c) 455 s, err := rlc.RunReleaseTest(ctx, req) 456 if err != nil { 457 errc <- err 458 return 459 } 460 461 for { 462 msg, err := s.Recv() 463 if err == io.EOF { 464 return 465 } 466 if err != nil { 467 errc <- err 468 return 469 } 470 ch <- msg 471 } 472 }() 473 474 return ch, errc 475 } 476 477 // Executes tiller.Ping RPC. 478 func (h *Client) ping(ctx context.Context) error { 479 c, err := h.connect(ctx) 480 if err != nil { 481 return err 482 } 483 defer c.Close() 484 485 rlc := rls.NewReleaseServiceClient(c) 486 return rlc.PingTiller(ctx) 487 }