github.com/spinnaker/spin@v1.30.0/cmd/orca-tasks/task_watcher.go (about) 1 // Copyright (c) 2019, Google, 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 orca_tasks 16 17 import ( 18 "fmt" 19 "strings" 20 "time" 21 22 "github.com/spinnaker/spin/cmd/gateclient" 23 ) 24 25 func calculateSleepTime(now int64, lastTryTime int64, attempts int64) time.Duration { 26 sleepTime := attempts * attempts 27 if sleepTime > 20 { 28 sleepTime = 20 29 } 30 if sleepTime+now > lastTryTime { 31 sleepTime = lastTryTime - now + 1 32 } 33 return time.Duration(sleepTime) * time.Second 34 } 35 36 // WaitForSuccessfulTask observes an Orca task to see if it completed successfully. 37 func WaitForSuccessfulTask(gateClient *gateclient.GatewayClient, taskRef map[string]interface{}) error { 38 id := idFromTaskRef(taskRef) 39 task, resp, err := gateClient.TaskControllerApi.GetTaskUsingGET1(gateClient.Context, id) 40 41 attempts := int64(0) 42 now := time.Now().UTC().Unix() 43 lastTryTime := now + int64(gateClient.RetryTimeout()) 44 for (task == nil || !taskCompleted(task)) && now < lastTryTime { 45 attempts += 1 46 sleepTime := calculateSleepTime(now, lastTryTime, attempts) 47 time.Sleep(sleepTime) 48 id := idFromTaskRef(taskRef) 49 task, resp, err = gateClient.TaskControllerApi.GetTaskUsingGET1(gateClient.Context, id) 50 now = time.Now().UTC().Unix() 51 } 52 53 if err != nil { 54 return err 55 } 56 if resp.StatusCode < 200 || resp.StatusCode > 299 { 57 return fmt.Errorf("Encountered an error saving application, status code: %d\n", resp.StatusCode) 58 } 59 if !TaskSucceeded(task) { 60 return fmt.Errorf("Encountered an error saving application, task output was: %v\n", task) 61 } 62 return nil 63 } 64 65 func taskCompleted(task map[string]interface{}) bool { 66 taskStatus, exists := task["status"] 67 if !exists { 68 return false 69 } 70 COMPLETED := [...]string{"SUCCEEDED", "STOPPED", "SKIPPED", "TERMINAL", "FAILED_CONTINUE"} 71 for _, status := range COMPLETED { 72 if taskStatus == status { 73 return true 74 } 75 } 76 return false 77 } 78 79 func TaskSucceeded(task map[string]interface{}) bool { 80 taskStatus, exists := task["status"] 81 if !exists { 82 return false 83 } 84 85 SUCCESSFUL := [...]string{"SUCCEEDED", "STOPPED", "SKIPPED"} 86 for _, status := range SUCCESSFUL { 87 if taskStatus == status { 88 return true 89 } 90 } 91 return false 92 } 93 94 func idFromTaskRef(taskRef map[string]interface{}) string { 95 toks := strings.Split(taskRef["ref"].(string), "/") 96 return toks[len(toks)-1] 97 }