mirror of https://github.com/k3s-io/k3s
111 lines
3.4 KiB
Go
111 lines
3.4 KiB
Go
/*
|
|
Copyright 2018 Google LLC
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package cloud
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"k8s.io/klog"
|
|
|
|
alpha "google.golang.org/api/compute/v0.alpha"
|
|
beta "google.golang.org/api/compute/v0.beta"
|
|
ga "google.golang.org/api/compute/v1"
|
|
)
|
|
|
|
// Service is the top-level adapter for all of the different compute API
|
|
// versions.
|
|
type Service struct {
|
|
GA *ga.Service
|
|
Alpha *alpha.Service
|
|
Beta *beta.Service
|
|
ProjectRouter ProjectRouter
|
|
RateLimiter RateLimiter
|
|
}
|
|
|
|
// wrapOperation wraps a GCE anyOP in a version generic operation type.
|
|
func (s *Service) wrapOperation(anyOp interface{}) (operation, error) {
|
|
switch o := anyOp.(type) {
|
|
case *ga.Operation:
|
|
r, err := ParseResourceURL(o.SelfLink)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &gaOperation{s: s, projectID: r.ProjectID, key: r.Key}, nil
|
|
case *alpha.Operation:
|
|
r, err := ParseResourceURL(o.SelfLink)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &alphaOperation{s: s, projectID: r.ProjectID, key: r.Key}, nil
|
|
case *beta.Operation:
|
|
r, err := ParseResourceURL(o.SelfLink)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &betaOperation{s: s, projectID: r.ProjectID, key: r.Key}, nil
|
|
default:
|
|
return nil, fmt.Errorf("invalid type %T", anyOp)
|
|
}
|
|
}
|
|
|
|
// WaitForCompletion of a long running operation. This will poll the state of
|
|
// GCE for the completion status of the given operation. genericOp can be one
|
|
// of alpha, beta, ga Operation types.
|
|
func (s *Service) WaitForCompletion(ctx context.Context, genericOp interface{}) error {
|
|
op, err := s.wrapOperation(genericOp)
|
|
if err != nil {
|
|
klog.Errorf("wrapOperation(%+v) error: %v", genericOp, err)
|
|
return err
|
|
}
|
|
|
|
return s.pollOperation(ctx, op)
|
|
}
|
|
|
|
// pollOperation calls operations.isDone until the function comes back true or context is Done.
|
|
// If an error occurs retrieving the operation, the loop will continue until the context is done.
|
|
// This is to prevent a transient error from bubbling up to controller-level logic.
|
|
func (s *Service) pollOperation(ctx context.Context, op operation) error {
|
|
var pollCount int
|
|
for {
|
|
// Check if context has been cancelled. Note that ctx.Done() must be checked before
|
|
// returning ctx.Err().
|
|
select {
|
|
case <-ctx.Done():
|
|
klog.V(5).Infof("op.pollOperation(%v, %v) not completed, poll count = %d, ctx.Err = %v", ctx, op, pollCount, ctx.Err())
|
|
return ctx.Err()
|
|
default:
|
|
// ctx is not canceled, continue immediately
|
|
}
|
|
|
|
pollCount++
|
|
klog.V(5).Infof("op.isDone(%v) waiting; op = %v, poll count = %d", ctx, op, pollCount)
|
|
s.RateLimiter.Accept(ctx, op.rateLimitKey())
|
|
done, err := op.isDone(ctx)
|
|
if err != nil {
|
|
klog.V(5).Infof("op.isDone(%v) error; op = %v, poll count = %d, err = %v, retrying", ctx, op, pollCount, err)
|
|
}
|
|
|
|
if done {
|
|
break
|
|
}
|
|
}
|
|
|
|
klog.V(5).Infof("op.isDone(%v) complete; op = %v, poll count = %d, op.err = %v", ctx, op, pollCount, op.error())
|
|
return op.error()
|
|
}
|