service.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. Copyright 2018 Google LLC
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package cloud
  14. import (
  15. "context"
  16. "fmt"
  17. "k8s.io/klog"
  18. alpha "google.golang.org/api/compute/v0.alpha"
  19. beta "google.golang.org/api/compute/v0.beta"
  20. ga "google.golang.org/api/compute/v1"
  21. )
  22. // Service is the top-level adapter for all of the different compute API
  23. // versions.
  24. type Service struct {
  25. GA *ga.Service
  26. Alpha *alpha.Service
  27. Beta *beta.Service
  28. ProjectRouter ProjectRouter
  29. RateLimiter RateLimiter
  30. }
  31. // wrapOperation wraps a GCE anyOP in a version generic operation type.
  32. func (s *Service) wrapOperation(anyOp interface{}) (operation, error) {
  33. switch o := anyOp.(type) {
  34. case *ga.Operation:
  35. r, err := ParseResourceURL(o.SelfLink)
  36. if err != nil {
  37. return nil, err
  38. }
  39. return &gaOperation{s: s, projectID: r.ProjectID, key: r.Key}, nil
  40. case *alpha.Operation:
  41. r, err := ParseResourceURL(o.SelfLink)
  42. if err != nil {
  43. return nil, err
  44. }
  45. return &alphaOperation{s: s, projectID: r.ProjectID, key: r.Key}, nil
  46. case *beta.Operation:
  47. r, err := ParseResourceURL(o.SelfLink)
  48. if err != nil {
  49. return nil, err
  50. }
  51. return &betaOperation{s: s, projectID: r.ProjectID, key: r.Key}, nil
  52. default:
  53. return nil, fmt.Errorf("invalid type %T", anyOp)
  54. }
  55. }
  56. // WaitForCompletion of a long running operation. This will poll the state of
  57. // GCE for the completion status of the given operation. genericOp can be one
  58. // of alpha, beta, ga Operation types.
  59. func (s *Service) WaitForCompletion(ctx context.Context, genericOp interface{}) error {
  60. op, err := s.wrapOperation(genericOp)
  61. if err != nil {
  62. klog.Errorf("wrapOperation(%+v) error: %v", genericOp, err)
  63. return err
  64. }
  65. return s.pollOperation(ctx, op)
  66. }
  67. // pollOperation calls operations.isDone until the function comes back true or context is Done.
  68. // If an error occurs retrieving the operation, the loop will continue until the context is done.
  69. // This is to prevent a transient error from bubbling up to controller-level logic.
  70. func (s *Service) pollOperation(ctx context.Context, op operation) error {
  71. var pollCount int
  72. for {
  73. // Check if context has been cancelled. Note that ctx.Done() must be checked before
  74. // returning ctx.Err().
  75. select {
  76. case <-ctx.Done():
  77. klog.V(5).Infof("op.pollOperation(%v, %v) not completed, poll count = %d, ctx.Err = %v", ctx, op, pollCount, ctx.Err())
  78. return ctx.Err()
  79. default:
  80. // ctx is not canceled, continue immediately
  81. }
  82. pollCount++
  83. klog.V(5).Infof("op.isDone(%v) waiting; op = %v, poll count = %d", ctx, op, pollCount)
  84. s.RateLimiter.Accept(ctx, op.rateLimitKey())
  85. done, err := op.isDone(ctx)
  86. if err != nil {
  87. klog.V(5).Infof("op.isDone(%v) error; op = %v, poll count = %d, err = %v, retrying", ctx, op, pollCount, err)
  88. }
  89. if done {
  90. break
  91. }
  92. }
  93. klog.V(5).Infof("op.isDone(%v) complete; op = %v, poll count = %d, op.err = %v", ctx, op, pollCount, op.error())
  94. return op.error()
  95. }