op.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. "google.golang.org/api/googleapi"
  22. "github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
  23. )
  24. const (
  25. operationStatusDone = "DONE"
  26. )
  27. // operation is a GCE operation that can be watied on.
  28. type operation interface {
  29. // isDone queries GCE for the done status. This call can block.
  30. isDone(ctx context.Context) (bool, error)
  31. // error returns the resulting error of the operation. This may be nil if the operations
  32. // was successful.
  33. error() error
  34. // rateLimitKey returns the rate limit key to use for the given operation.
  35. // This rate limit will govern how fast the server will be polled for
  36. // operation completion status.
  37. rateLimitKey() *RateLimitKey
  38. }
  39. type gaOperation struct {
  40. s *Service
  41. projectID string
  42. key *meta.Key
  43. err error
  44. }
  45. func (o *gaOperation) String() string {
  46. return fmt.Sprintf("gaOperation{%q, %v}", o.projectID, o.key)
  47. }
  48. func (o *gaOperation) isDone(ctx context.Context) (bool, error) {
  49. var (
  50. op *ga.Operation
  51. err error
  52. )
  53. switch o.key.Type() {
  54. case meta.Regional:
  55. op, err = o.s.GA.RegionOperations.Get(o.projectID, o.key.Region, o.key.Name).Context(ctx).Do()
  56. klog.V(5).Infof("GA.RegionOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Region, o.key.Name, op, err, ctx)
  57. case meta.Zonal:
  58. op, err = o.s.GA.ZoneOperations.Get(o.projectID, o.key.Zone, o.key.Name).Context(ctx).Do()
  59. klog.V(5).Infof("GA.ZoneOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Zone, o.key.Name, op, err, ctx)
  60. case meta.Global:
  61. op, err = o.s.GA.GlobalOperations.Get(o.projectID, o.key.Name).Context(ctx).Do()
  62. klog.V(5).Infof("GA.GlobalOperations.Get(%v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Name, op, err, ctx)
  63. default:
  64. return false, fmt.Errorf("invalid key type: %#v", o.key)
  65. }
  66. if err != nil {
  67. return false, err
  68. }
  69. if op == nil || op.Status != operationStatusDone {
  70. return false, nil
  71. }
  72. if op.Error != nil && len(op.Error.Errors) > 0 && op.Error.Errors[0] != nil {
  73. e := op.Error.Errors[0]
  74. o.err = &googleapi.Error{Code: int(op.HttpErrorStatusCode), Message: fmt.Sprintf("%v - %v", e.Code, e.Message)}
  75. }
  76. return true, nil
  77. }
  78. func (o *gaOperation) rateLimitKey() *RateLimitKey {
  79. return &RateLimitKey{
  80. ProjectID: o.projectID,
  81. Operation: "Get",
  82. Service: "Operations",
  83. Version: meta.VersionGA,
  84. }
  85. }
  86. func (o *gaOperation) error() error {
  87. return o.err
  88. }
  89. type alphaOperation struct {
  90. s *Service
  91. projectID string
  92. key *meta.Key
  93. err error
  94. }
  95. func (o *alphaOperation) String() string {
  96. return fmt.Sprintf("alphaOperation{%q, %v}", o.projectID, o.key)
  97. }
  98. func (o *alphaOperation) isDone(ctx context.Context) (bool, error) {
  99. var (
  100. op *alpha.Operation
  101. err error
  102. )
  103. switch o.key.Type() {
  104. case meta.Regional:
  105. op, err = o.s.Alpha.RegionOperations.Get(o.projectID, o.key.Region, o.key.Name).Context(ctx).Do()
  106. klog.V(5).Infof("Alpha.RegionOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Region, o.key.Name, op, err, ctx)
  107. case meta.Zonal:
  108. op, err = o.s.Alpha.ZoneOperations.Get(o.projectID, o.key.Zone, o.key.Name).Context(ctx).Do()
  109. klog.V(5).Infof("Alpha.ZoneOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Zone, o.key.Name, op, err, ctx)
  110. case meta.Global:
  111. op, err = o.s.Alpha.GlobalOperations.Get(o.projectID, o.key.Name).Context(ctx).Do()
  112. klog.V(5).Infof("Alpha.GlobalOperations.Get(%v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Name, op, err, ctx)
  113. default:
  114. return false, fmt.Errorf("invalid key type: %#v", o.key)
  115. }
  116. if err != nil {
  117. return false, err
  118. }
  119. if op == nil || op.Status != operationStatusDone {
  120. return false, nil
  121. }
  122. if op.Error != nil && len(op.Error.Errors) > 0 && op.Error.Errors[0] != nil {
  123. e := op.Error.Errors[0]
  124. o.err = &googleapi.Error{Code: int(op.HttpErrorStatusCode), Message: fmt.Sprintf("%v - %v", e.Code, e.Message)}
  125. }
  126. return true, nil
  127. }
  128. func (o *alphaOperation) rateLimitKey() *RateLimitKey {
  129. return &RateLimitKey{
  130. ProjectID: o.projectID,
  131. Operation: "Get",
  132. Service: "Operations",
  133. Version: meta.VersionAlpha,
  134. }
  135. }
  136. func (o *alphaOperation) error() error {
  137. return o.err
  138. }
  139. type betaOperation struct {
  140. s *Service
  141. projectID string
  142. key *meta.Key
  143. err error
  144. }
  145. func (o *betaOperation) String() string {
  146. return fmt.Sprintf("betaOperation{%q, %v}", o.projectID, o.key)
  147. }
  148. func (o *betaOperation) isDone(ctx context.Context) (bool, error) {
  149. var (
  150. op *beta.Operation
  151. err error
  152. )
  153. switch o.key.Type() {
  154. case meta.Regional:
  155. op, err = o.s.Beta.RegionOperations.Get(o.projectID, o.key.Region, o.key.Name).Context(ctx).Do()
  156. klog.V(5).Infof("Beta.RegionOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Region, o.key.Name, op, err, ctx)
  157. case meta.Zonal:
  158. op, err = o.s.Beta.ZoneOperations.Get(o.projectID, o.key.Zone, o.key.Name).Context(ctx).Do()
  159. klog.V(5).Infof("Beta.ZoneOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Zone, o.key.Name, op, err, ctx)
  160. case meta.Global:
  161. op, err = o.s.Beta.GlobalOperations.Get(o.projectID, o.key.Name).Context(ctx).Do()
  162. klog.V(5).Infof("Beta.GlobalOperations.Get(%v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Name, op, err, ctx)
  163. default:
  164. return false, fmt.Errorf("invalid key type: %#v", o.key)
  165. }
  166. if err != nil {
  167. return false, err
  168. }
  169. if op == nil || op.Status != operationStatusDone {
  170. return false, nil
  171. }
  172. if op.Error != nil && len(op.Error.Errors) > 0 && op.Error.Errors[0] != nil {
  173. e := op.Error.Errors[0]
  174. o.err = &googleapi.Error{Code: int(op.HttpErrorStatusCode), Message: fmt.Sprintf("%v - %v", e.Code, e.Message)}
  175. }
  176. return true, nil
  177. }
  178. func (o *betaOperation) rateLimitKey() *RateLimitKey {
  179. return &RateLimitKey{
  180. ProjectID: o.projectID,
  181. Operation: "Get",
  182. Service: "Operations",
  183. Version: meta.VersionBeta,
  184. }
  185. }
  186. func (o *betaOperation) error() error {
  187. return o.err
  188. }