github.com/darkowlzz/helm@v2.5.1-0.20171213183701-6707fe0468d4+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 for _, opt := range opts { 55 opt(&h.opts) 56 } 57 req := &h.opts.listReq 58 ctx := NewContext() 59 60 if h.opts.before != nil { 61 if err := h.opts.before(ctx, req); err != nil { 62 return nil, err 63 } 64 } 65 return h.list(ctx, req) 66 } 67 68 // InstallRelease loads a chart from chstr, installs it, and returns the release response. 69 func (h *Client) InstallRelease(chstr, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) { 70 // load the chart to install 71 chart, err := chartutil.Load(chstr) 72 if err != nil { 73 return nil, err 74 } 75 76 return h.InstallReleaseFromChart(chart, ns, opts...) 77 } 78 79 // InstallReleaseFromChart installs a new chart and returns the release response. 80 func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) { 81 // apply the install options 82 for _, opt := range opts { 83 opt(&h.opts) 84 } 85 req := &h.opts.instReq 86 req.Chart = chart 87 req.Namespace = ns 88 req.DryRun = h.opts.dryRun 89 req.DisableHooks = h.opts.disableHooks 90 req.ReuseName = h.opts.reuseName 91 ctx := NewContext() 92 93 if h.opts.before != nil { 94 if err := h.opts.before(ctx, req); err != nil { 95 return nil, err 96 } 97 } 98 err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values) 99 if err != nil { 100 return nil, err 101 } 102 err = chartutil.ProcessRequirementsImportValues(req.Chart) 103 if err != nil { 104 return nil, err 105 } 106 107 return h.install(ctx, req) 108 } 109 110 // DeleteRelease uninstalls a named release and returns the response. 111 func (h *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) { 112 // apply the uninstall options 113 for _, opt := range opts { 114 opt(&h.opts) 115 } 116 117 if h.opts.dryRun { 118 // In the dry run case, just see if the release exists 119 r, err := h.ReleaseContent(rlsName) 120 if err != nil { 121 return &rls.UninstallReleaseResponse{}, err 122 } 123 return &rls.UninstallReleaseResponse{Release: r.Release}, nil 124 } 125 126 req := &h.opts.uninstallReq 127 req.Name = rlsName 128 req.DisableHooks = h.opts.disableHooks 129 ctx := NewContext() 130 131 if h.opts.before != nil { 132 if err := h.opts.before(ctx, req); err != nil { 133 return nil, err 134 } 135 } 136 return h.delete(ctx, req) 137 } 138 139 // UpdateRelease loads a chart from chstr and updates a release to a new/different chart. 140 func (h *Client) UpdateRelease(rlsName string, chstr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) { 141 // load the chart to update 142 chart, err := chartutil.Load(chstr) 143 if err != nil { 144 return nil, err 145 } 146 147 return h.UpdateReleaseFromChart(rlsName, chart, opts...) 148 } 149 150 // UpdateReleaseFromChart updates a release to a new/different chart. 151 func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) { 152 153 // apply the update options 154 for _, opt := range opts { 155 opt(&h.opts) 156 } 157 req := &h.opts.updateReq 158 req.Chart = chart 159 req.DryRun = h.opts.dryRun 160 req.Name = rlsName 161 req.DisableHooks = h.opts.disableHooks 162 req.Recreate = h.opts.recreate 163 req.Force = h.opts.force 164 req.ResetValues = h.opts.resetValues 165 req.ReuseValues = h.opts.reuseValues 166 ctx := NewContext() 167 168 if h.opts.before != nil { 169 if err := h.opts.before(ctx, req); err != nil { 170 return nil, err 171 } 172 } 173 err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values) 174 if err != nil { 175 return nil, err 176 } 177 err = chartutil.ProcessRequirementsImportValues(req.Chart) 178 if err != nil { 179 return nil, err 180 } 181 182 return h.update(ctx, req) 183 } 184 185 // GetVersion returns the server version. 186 func (h *Client) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error) { 187 for _, opt := range opts { 188 opt(&h.opts) 189 } 190 req := &rls.GetVersionRequest{} 191 ctx := NewContext() 192 193 if h.opts.before != nil { 194 if err := h.opts.before(ctx, req); err != nil { 195 return nil, err 196 } 197 } 198 return h.version(ctx, req) 199 } 200 201 // RollbackRelease rolls back a release to the previous version. 202 func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) { 203 for _, opt := range opts { 204 opt(&h.opts) 205 } 206 req := &h.opts.rollbackReq 207 req.Recreate = h.opts.recreate 208 req.Force = h.opts.force 209 req.DisableHooks = h.opts.disableHooks 210 req.DryRun = h.opts.dryRun 211 req.Name = rlsName 212 ctx := NewContext() 213 214 if h.opts.before != nil { 215 if err := h.opts.before(ctx, req); err != nil { 216 return nil, err 217 } 218 } 219 return h.rollback(ctx, req) 220 } 221 222 // ReleaseStatus returns the given release's status. 223 func (h *Client) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) { 224 for _, opt := range opts { 225 opt(&h.opts) 226 } 227 req := &h.opts.statusReq 228 req.Name = rlsName 229 ctx := NewContext() 230 231 if h.opts.before != nil { 232 if err := h.opts.before(ctx, req); err != nil { 233 return nil, err 234 } 235 } 236 return h.status(ctx, req) 237 } 238 239 // ReleaseContent returns the configuration for a given release. 240 func (h *Client) ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) { 241 for _, opt := range opts { 242 opt(&h.opts) 243 } 244 req := &h.opts.contentReq 245 req.Name = rlsName 246 ctx := NewContext() 247 248 if h.opts.before != nil { 249 if err := h.opts.before(ctx, req); err != nil { 250 return nil, err 251 } 252 } 253 return h.content(ctx, req) 254 } 255 256 // ReleaseHistory returns a release's revision history. 257 func (h *Client) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) { 258 for _, opt := range opts { 259 opt(&h.opts) 260 } 261 262 req := &h.opts.histReq 263 req.Name = rlsName 264 ctx := NewContext() 265 266 if h.opts.before != nil { 267 if err := h.opts.before(ctx, req); err != nil { 268 return nil, err 269 } 270 } 271 return h.history(ctx, req) 272 } 273 274 // RunReleaseTest executes a pre-defined test on a release. 275 func (h *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error) { 276 for _, opt := range opts { 277 opt(&h.opts) 278 } 279 280 req := &h.opts.testReq 281 req.Name = rlsName 282 ctx := NewContext() 283 284 return h.test(ctx, req) 285 } 286 287 // connect returns a gRPC connection to Tiller or error. The gRPC dial options 288 // are constructed here. 289 func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) { 290 opts := []grpc.DialOption{ 291 grpc.WithTimeout(5 * time.Second), 292 grpc.WithBlock(), 293 grpc.WithKeepaliveParams(keepalive.ClientParameters{ 294 // Send keepalive every 30 seconds to prevent the connection from 295 // getting closed by upstreams 296 Time: time.Duration(30) * time.Second, 297 }), 298 } 299 switch { 300 case h.opts.useTLS: 301 opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(h.opts.tlsConfig))) 302 default: 303 opts = append(opts, grpc.WithInsecure()) 304 } 305 if conn, err = grpc.Dial(h.opts.host, opts...); err != nil { 306 return nil, err 307 } 308 return conn, nil 309 } 310 311 // Executes tiller.ListReleases RPC. 312 func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.ListReleasesResponse, error) { 313 c, err := h.connect(ctx) 314 if err != nil { 315 return nil, err 316 } 317 defer c.Close() 318 319 rlc := rls.NewReleaseServiceClient(c) 320 s, err := rlc.ListReleases(ctx, req) 321 if err != nil { 322 return nil, err 323 } 324 325 return s.Recv() 326 } 327 328 // Executes tiller.InstallRelease RPC. 329 func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) { 330 c, err := h.connect(ctx) 331 if err != nil { 332 return nil, err 333 } 334 defer c.Close() 335 336 rlc := rls.NewReleaseServiceClient(c) 337 return rlc.InstallRelease(ctx, req) 338 } 339 340 // Executes tiller.UninstallRelease RPC. 341 func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) { 342 c, err := h.connect(ctx) 343 if err != nil { 344 return nil, err 345 } 346 defer c.Close() 347 348 rlc := rls.NewReleaseServiceClient(c) 349 return rlc.UninstallRelease(ctx, req) 350 } 351 352 // Executes tiller.UpdateRelease RPC. 353 func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) { 354 c, err := h.connect(ctx) 355 if err != nil { 356 return nil, err 357 } 358 defer c.Close() 359 360 rlc := rls.NewReleaseServiceClient(c) 361 return rlc.UpdateRelease(ctx, req) 362 } 363 364 // Executes tiller.RollbackRelease RPC. 365 func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) { 366 c, err := h.connect(ctx) 367 if err != nil { 368 return nil, err 369 } 370 defer c.Close() 371 372 rlc := rls.NewReleaseServiceClient(c) 373 return rlc.RollbackRelease(ctx, req) 374 } 375 376 // Executes tiller.GetReleaseStatus RPC. 377 func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) { 378 c, err := h.connect(ctx) 379 if err != nil { 380 return nil, err 381 } 382 defer c.Close() 383 384 rlc := rls.NewReleaseServiceClient(c) 385 return rlc.GetReleaseStatus(ctx, req) 386 } 387 388 // Executes tiller.GetReleaseContent RPC. 389 func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) (*rls.GetReleaseContentResponse, error) { 390 c, err := h.connect(ctx) 391 if err != nil { 392 return nil, err 393 } 394 defer c.Close() 395 396 rlc := rls.NewReleaseServiceClient(c) 397 return rlc.GetReleaseContent(ctx, req) 398 } 399 400 // Executes tiller.GetVersion RPC. 401 func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls.GetVersionResponse, error) { 402 c, err := h.connect(ctx) 403 if err != nil { 404 return nil, err 405 } 406 defer c.Close() 407 408 rlc := rls.NewReleaseServiceClient(c) 409 return rlc.GetVersion(ctx, req) 410 } 411 412 // Executes tiller.GetHistory RPC. 413 func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.GetHistoryResponse, error) { 414 c, err := h.connect(ctx) 415 if err != nil { 416 return nil, err 417 } 418 defer c.Close() 419 420 rlc := rls.NewReleaseServiceClient(c) 421 return rlc.GetHistory(ctx, req) 422 } 423 424 // Executes tiller.TestRelease RPC. 425 func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) { 426 errc := make(chan error, 1) 427 c, err := h.connect(ctx) 428 if err != nil { 429 errc <- err 430 return nil, errc 431 } 432 433 ch := make(chan *rls.TestReleaseResponse, 1) 434 go func() { 435 defer close(errc) 436 defer close(ch) 437 defer c.Close() 438 439 rlc := rls.NewReleaseServiceClient(c) 440 s, err := rlc.RunReleaseTest(ctx, req) 441 if err != nil { 442 errc <- err 443 return 444 } 445 446 for { 447 msg, err := s.Recv() 448 if err == io.EOF { 449 return 450 } 451 if err != nil { 452 errc <- err 453 return 454 } 455 ch <- msg 456 } 457 }() 458 459 return ch, errc 460 }