github.com/strongmonkey/helm@v2.7.2+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) 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.Force = h.opts.force 163 req.ResetValues = h.opts.resetValues 164 req.ReuseValues = h.opts.reuseValues 165 ctx := NewContext() 166 167 if h.opts.before != nil { 168 if err := h.opts.before(ctx, req); err != nil { 169 return nil, err 170 } 171 } 172 err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values) 173 if err != nil { 174 return nil, err 175 } 176 err = chartutil.ProcessRequirementsImportValues(req.Chart) 177 if err != nil { 178 return nil, err 179 } 180 181 return h.update(ctx, req) 182 } 183 184 // GetVersion returns the server version. 185 func (h *Client) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error) { 186 for _, opt := range opts { 187 opt(&h.opts) 188 } 189 req := &rls.GetVersionRequest{} 190 ctx := NewContext() 191 192 if h.opts.before != nil { 193 if err := h.opts.before(ctx, req); err != nil { 194 return nil, err 195 } 196 } 197 return h.version(ctx, req) 198 } 199 200 // RollbackRelease rolls back a release to the previous version. 201 func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) { 202 for _, opt := range opts { 203 opt(&h.opts) 204 } 205 req := &h.opts.rollbackReq 206 req.Recreate = h.opts.recreate 207 req.Force = h.opts.force 208 req.DisableHooks = h.opts.disableHooks 209 req.DryRun = h.opts.dryRun 210 req.Name = rlsName 211 ctx := NewContext() 212 213 if h.opts.before != nil { 214 if err := h.opts.before(ctx, req); err != nil { 215 return nil, err 216 } 217 } 218 return h.rollback(ctx, req) 219 } 220 221 // ReleaseStatus returns the given release's status. 222 func (h *Client) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) { 223 for _, opt := range opts { 224 opt(&h.opts) 225 } 226 req := &h.opts.statusReq 227 req.Name = rlsName 228 ctx := NewContext() 229 230 if h.opts.before != nil { 231 if err := h.opts.before(ctx, req); err != nil { 232 return nil, err 233 } 234 } 235 return h.status(ctx, req) 236 } 237 238 // ReleaseContent returns the configuration for a given release. 239 func (h *Client) ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) { 240 for _, opt := range opts { 241 opt(&h.opts) 242 } 243 req := &h.opts.contentReq 244 req.Name = rlsName 245 ctx := NewContext() 246 247 if h.opts.before != nil { 248 if err := h.opts.before(ctx, req); err != nil { 249 return nil, err 250 } 251 } 252 return h.content(ctx, req) 253 } 254 255 // ReleaseHistory returns a release's revision history. 256 func (h *Client) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) { 257 for _, opt := range opts { 258 opt(&h.opts) 259 } 260 261 req := &h.opts.histReq 262 req.Name = rlsName 263 ctx := NewContext() 264 265 if h.opts.before != nil { 266 if err := h.opts.before(ctx, req); err != nil { 267 return nil, err 268 } 269 } 270 return h.history(ctx, req) 271 } 272 273 // RunReleaseTest executes a pre-defined test on a release. 274 func (h *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error) { 275 for _, opt := range opts { 276 opt(&h.opts) 277 } 278 279 req := &h.opts.testReq 280 req.Name = rlsName 281 ctx := NewContext() 282 283 return h.test(ctx, req) 284 } 285 286 // connect returns a gRPC connection to Tiller or error. The gRPC dial options 287 // are constructed here. 288 func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) { 289 opts := []grpc.DialOption{ 290 grpc.WithTimeout(5 * time.Second), 291 grpc.WithBlock(), 292 } 293 switch { 294 case h.opts.useTLS: 295 opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(h.opts.tlsConfig))) 296 default: 297 opts = append(opts, grpc.WithInsecure()) 298 } 299 if conn, err = grpc.Dial(h.opts.host, opts...); err != nil { 300 return nil, err 301 } 302 return conn, nil 303 } 304 305 // Executes tiller.ListReleases RPC. 306 func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.ListReleasesResponse, error) { 307 c, err := h.connect(ctx) 308 if err != nil { 309 return nil, err 310 } 311 defer c.Close() 312 313 rlc := rls.NewReleaseServiceClient(c) 314 s, err := rlc.ListReleases(ctx, req) 315 if err != nil { 316 return nil, err 317 } 318 319 return s.Recv() 320 } 321 322 // Executes tiller.InstallRelease RPC. 323 func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) { 324 c, err := h.connect(ctx) 325 if err != nil { 326 return nil, err 327 } 328 defer c.Close() 329 330 rlc := rls.NewReleaseServiceClient(c) 331 return rlc.InstallRelease(ctx, req) 332 } 333 334 // Executes tiller.UninstallRelease RPC. 335 func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) { 336 c, err := h.connect(ctx) 337 if err != nil { 338 return nil, err 339 } 340 defer c.Close() 341 342 rlc := rls.NewReleaseServiceClient(c) 343 return rlc.UninstallRelease(ctx, req) 344 } 345 346 // Executes tiller.UpdateRelease RPC. 347 func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) { 348 c, err := h.connect(ctx) 349 if err != nil { 350 return nil, err 351 } 352 defer c.Close() 353 354 rlc := rls.NewReleaseServiceClient(c) 355 return rlc.UpdateRelease(ctx, req) 356 } 357 358 // Executes tiller.RollbackRelease RPC. 359 func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) { 360 c, err := h.connect(ctx) 361 if err != nil { 362 return nil, err 363 } 364 defer c.Close() 365 366 rlc := rls.NewReleaseServiceClient(c) 367 return rlc.RollbackRelease(ctx, req) 368 } 369 370 // Executes tiller.GetReleaseStatus RPC. 371 func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) { 372 c, err := h.connect(ctx) 373 if err != nil { 374 return nil, err 375 } 376 defer c.Close() 377 378 rlc := rls.NewReleaseServiceClient(c) 379 return rlc.GetReleaseStatus(ctx, req) 380 } 381 382 // Executes tiller.GetReleaseContent RPC. 383 func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) (*rls.GetReleaseContentResponse, error) { 384 c, err := h.connect(ctx) 385 if err != nil { 386 return nil, err 387 } 388 defer c.Close() 389 390 rlc := rls.NewReleaseServiceClient(c) 391 return rlc.GetReleaseContent(ctx, req) 392 } 393 394 // Executes tiller.GetVersion RPC. 395 func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls.GetVersionResponse, error) { 396 c, err := h.connect(ctx) 397 if err != nil { 398 return nil, err 399 } 400 defer c.Close() 401 402 rlc := rls.NewReleaseServiceClient(c) 403 return rlc.GetVersion(ctx, req) 404 } 405 406 // Executes tiller.GetHistory RPC. 407 func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.GetHistoryResponse, error) { 408 c, err := h.connect(ctx) 409 if err != nil { 410 return nil, err 411 } 412 defer c.Close() 413 414 rlc := rls.NewReleaseServiceClient(c) 415 return rlc.GetHistory(ctx, req) 416 } 417 418 // Executes tiller.TestRelease RPC. 419 func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) { 420 errc := make(chan error, 1) 421 c, err := h.connect(ctx) 422 if err != nil { 423 errc <- err 424 return nil, errc 425 } 426 427 ch := make(chan *rls.TestReleaseResponse, 1) 428 go func() { 429 defer close(errc) 430 defer close(ch) 431 defer c.Close() 432 433 rlc := rls.NewReleaseServiceClient(c) 434 s, err := rlc.RunReleaseTest(ctx, req) 435 if err != nil { 436 errc <- err 437 return 438 } 439 440 for { 441 msg, err := s.Recv() 442 if err == io.EOF { 443 return 444 } 445 if err != nil { 446 errc <- err 447 return 448 } 449 ch <- msg 450 } 451 }() 452 453 return ch, errc 454 }