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