github.com/brockwood/helm@v2.8.0-rc.1.0.20180112204834-077be881c4cc+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 // connect returns a gRPC connection to Tiller or error. The gRPC dial options 297 // are constructed here. 298 func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) { 299 opts := []grpc.DialOption{ 300 grpc.WithTimeout(5 * time.Second), 301 grpc.WithBlock(), 302 grpc.WithKeepaliveParams(keepalive.ClientParameters{ 303 // Send keepalive every 30 seconds to prevent the connection from 304 // getting closed by upstreams 305 Time: time.Duration(30) * time.Second, 306 }), 307 } 308 switch { 309 case h.opts.useTLS: 310 opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(h.opts.tlsConfig))) 311 default: 312 opts = append(opts, grpc.WithInsecure()) 313 } 314 if conn, err = grpc.Dial(h.opts.host, opts...); err != nil { 315 return nil, err 316 } 317 return conn, nil 318 } 319 320 // Executes tiller.ListReleases RPC. 321 func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.ListReleasesResponse, error) { 322 c, err := h.connect(ctx) 323 if err != nil { 324 return nil, err 325 } 326 defer c.Close() 327 328 rlc := rls.NewReleaseServiceClient(c) 329 s, err := rlc.ListReleases(ctx, req) 330 if err != nil { 331 return nil, err 332 } 333 334 return s.Recv() 335 } 336 337 // Executes tiller.InstallRelease RPC. 338 func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) { 339 c, err := h.connect(ctx) 340 if err != nil { 341 return nil, err 342 } 343 defer c.Close() 344 345 rlc := rls.NewReleaseServiceClient(c) 346 return rlc.InstallRelease(ctx, req) 347 } 348 349 // Executes tiller.UninstallRelease RPC. 350 func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) { 351 c, err := h.connect(ctx) 352 if err != nil { 353 return nil, err 354 } 355 defer c.Close() 356 357 rlc := rls.NewReleaseServiceClient(c) 358 return rlc.UninstallRelease(ctx, req) 359 } 360 361 // Executes tiller.UpdateRelease RPC. 362 func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) { 363 c, err := h.connect(ctx) 364 if err != nil { 365 return nil, err 366 } 367 defer c.Close() 368 369 rlc := rls.NewReleaseServiceClient(c) 370 return rlc.UpdateRelease(ctx, req) 371 } 372 373 // Executes tiller.RollbackRelease RPC. 374 func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) { 375 c, err := h.connect(ctx) 376 if err != nil { 377 return nil, err 378 } 379 defer c.Close() 380 381 rlc := rls.NewReleaseServiceClient(c) 382 return rlc.RollbackRelease(ctx, req) 383 } 384 385 // Executes tiller.GetReleaseStatus RPC. 386 func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) { 387 c, err := h.connect(ctx) 388 if err != nil { 389 return nil, err 390 } 391 defer c.Close() 392 393 rlc := rls.NewReleaseServiceClient(c) 394 return rlc.GetReleaseStatus(ctx, req) 395 } 396 397 // Executes tiller.GetReleaseContent RPC. 398 func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) (*rls.GetReleaseContentResponse, error) { 399 c, err := h.connect(ctx) 400 if err != nil { 401 return nil, err 402 } 403 defer c.Close() 404 405 rlc := rls.NewReleaseServiceClient(c) 406 return rlc.GetReleaseContent(ctx, req) 407 } 408 409 // Executes tiller.GetVersion RPC. 410 func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls.GetVersionResponse, error) { 411 c, err := h.connect(ctx) 412 if err != nil { 413 return nil, err 414 } 415 defer c.Close() 416 417 rlc := rls.NewReleaseServiceClient(c) 418 return rlc.GetVersion(ctx, req) 419 } 420 421 // Executes tiller.GetHistory RPC. 422 func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.GetHistoryResponse, error) { 423 c, err := h.connect(ctx) 424 if err != nil { 425 return nil, err 426 } 427 defer c.Close() 428 429 rlc := rls.NewReleaseServiceClient(c) 430 return rlc.GetHistory(ctx, req) 431 } 432 433 // Executes tiller.TestRelease RPC. 434 func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) { 435 errc := make(chan error, 1) 436 c, err := h.connect(ctx) 437 if err != nil { 438 errc <- err 439 return nil, errc 440 } 441 442 ch := make(chan *rls.TestReleaseResponse, 1) 443 go func() { 444 defer close(errc) 445 defer close(ch) 446 defer c.Close() 447 448 rlc := rls.NewReleaseServiceClient(c) 449 s, err := rlc.RunReleaseTest(ctx, req) 450 if err != nil { 451 errc <- err 452 return 453 } 454 455 for { 456 msg, err := s.Recv() 457 if err == io.EOF { 458 return 459 } 460 if err != nil { 461 errc <- err 462 return 463 } 464 ch <- msg 465 } 466 }() 467 468 return ch, errc 469 }