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  }