github.com/coreos/mantle@v0.13.0/platform/api/gcloud/pending.go (about) 1 // Copyright 2017 CoreOS, Inc. 2 // 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package gcloud 16 17 import ( 18 "fmt" 19 "time" 20 21 "google.golang.org/api/compute/v1" 22 "google.golang.org/api/googleapi" 23 ) 24 25 type doable interface { 26 Do(opts ...googleapi.CallOption) (*compute.Operation, error) 27 } 28 29 type Pending struct { 30 Interval time.Duration 31 Timeout time.Duration // for default progress function 32 Progress func(desc string, elapsed time.Duration, op *compute.Operation) error 33 34 desc string 35 do doable 36 } 37 38 func (a *API) NewPending(desc string, do doable) *Pending { 39 pending := &Pending{ 40 Interval: 10 * time.Second, 41 Timeout: 10 * time.Minute, 42 desc: desc, 43 do: do, 44 } 45 pending.Progress = pending.defaultProgress 46 return pending 47 } 48 49 func (p *Pending) Wait() error { 50 var op *compute.Operation 51 var err error 52 failures := 0 53 start := time.Now() 54 for { 55 op, err = p.do.Do() 56 if err == nil { 57 err := p.Progress(p.desc, time.Now().Sub(start), op) 58 if err != nil { 59 return err 60 } 61 } else { 62 failures++ 63 if failures > 5 { 64 return fmt.Errorf("Fetching %q status failed: %v", p.desc, err) 65 } 66 } 67 if op != nil && op.Status == "DONE" { 68 break 69 } 70 time.Sleep(p.Interval) 71 } 72 if op.Error != nil { 73 if len(op.Error.Errors) > 0 { 74 return fmt.Errorf("Operation %q failed: %+v", p.desc, op.Error.Errors) 75 } 76 return fmt.Errorf("Operation %q failed to start", p.desc) 77 } 78 return nil 79 } 80 81 func (p *Pending) defaultProgress(desc string, elapsed time.Duration, op *compute.Operation) error { 82 var err error 83 switch op.Status { 84 case "PENDING", "RUNNING": 85 err = fmt.Errorf("Operation %q is %q", desc, op.Status) 86 case "DONE": 87 return nil 88 default: 89 err = fmt.Errorf("Unknown operation status %q for %q: %+v", op.Status, desc, op) 90 } 91 92 if p.Timeout > 0 && elapsed > p.Timeout { 93 return fmt.Errorf("Failed to wait for operation %q: %v", desc, err) 94 } 95 96 return nil 97 }