105 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
| package controllers
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"github.com/summerwind/actions-runner-controller/api/v1alpha1"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alpha1.RunnerDeployment, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
 | |
| 	if hra.Spec.MinReplicas == nil {
 | |
| 		return nil, fmt.Errorf("horizontalrunnerautoscaler %s/%s is missing minReplicas", hra.Namespace, hra.Name)
 | |
| 	} else if hra.Spec.MaxReplicas == nil {
 | |
| 		return nil, fmt.Errorf("horizontalrunnerautoscaler %s/%s is missing maxReplicas", hra.Namespace, hra.Name)
 | |
| 	}
 | |
| 
 | |
| 	var repos [][]string
 | |
| 
 | |
| 	repoID := rd.Spec.Template.Spec.Repository
 | |
| 	if repoID == "" {
 | |
| 		orgName := rd.Spec.Template.Spec.Organization
 | |
| 		if orgName == "" {
 | |
| 			return nil, fmt.Errorf("asserting runner deployment spec to detect bug: spec.template.organization should not be empty on this code path")
 | |
| 		}
 | |
| 
 | |
| 		metrics := hra.Spec.Metrics
 | |
| 
 | |
| 		if len(metrics) == 0 {
 | |
| 			return nil, fmt.Errorf("validating autoscaling metrics: one or more metrics is required")
 | |
| 		} else if tpe := metrics[0].Type; tpe != v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns {
 | |
| 			return nil, fmt.Errorf("validting autoscaling metrics: unsupported metric type %q: only supported value is %s", tpe, v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns)
 | |
| 		} else if len(metrics[0].RepositoryNames) == 0 {
 | |
| 			return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].repositoryNames is required and must have one more more entries for organizational runner deployment")
 | |
| 		}
 | |
| 
 | |
| 		for _, repoName := range metrics[0].RepositoryNames {
 | |
| 			repos = append(repos, []string{orgName, repoName})
 | |
| 		}
 | |
| 	} else {
 | |
| 		repo := strings.Split(repoID, "/")
 | |
| 
 | |
| 		repos = append(repos, repo)
 | |
| 	}
 | |
| 
 | |
| 	var total, inProgress, queued, completed, unknown int
 | |
| 
 | |
| 	for _, repo := range repos {
 | |
| 		user, repoName := repo[0], repo[1]
 | |
| 		list, _, err := r.GitHubClient.Actions.ListRepositoryWorkflowRuns(context.TODO(), user, repoName, nil)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		for _, r := range list.WorkflowRuns {
 | |
| 			total++
 | |
| 
 | |
| 			// In May 2020, there are only 3 statuses.
 | |
| 			// Follow the below links for more details:
 | |
| 			// - https://developer.github.com/v3/actions/workflow-runs/#list-repository-workflow-runs
 | |
| 			// - https://developer.github.com/v3/checks/runs/#create-a-check-run
 | |
| 			switch r.GetStatus() {
 | |
| 			case "completed":
 | |
| 				completed++
 | |
| 			case "in_progress":
 | |
| 				inProgress++
 | |
| 			case "queued":
 | |
| 				queued++
 | |
| 			default:
 | |
| 				unknown++
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	minReplicas := *hra.Spec.MinReplicas
 | |
| 	maxReplicas := *hra.Spec.MaxReplicas
 | |
| 	necessaryReplicas := queued + inProgress
 | |
| 
 | |
| 	var desiredReplicas int
 | |
| 
 | |
| 	if necessaryReplicas < minReplicas {
 | |
| 		desiredReplicas = minReplicas
 | |
| 	} else if necessaryReplicas > maxReplicas {
 | |
| 		desiredReplicas = maxReplicas
 | |
| 	} else {
 | |
| 		desiredReplicas = necessaryReplicas
 | |
| 	}
 | |
| 
 | |
| 	rd.Status.Replicas = &desiredReplicas
 | |
| 	replicas := desiredReplicas
 | |
| 
 | |
| 	r.Log.V(1).Info(
 | |
| 		"Calculated desired replicas",
 | |
| 		"computed_replicas_desired", desiredReplicas,
 | |
| 		"spec_replicas_min", minReplicas,
 | |
| 		"spec_replicas_max", maxReplicas,
 | |
| 		"workflow_runs_completed", completed,
 | |
| 		"workflow_runs_in_progress", inProgress,
 | |
| 		"workflow_runs_queued", queued,
 | |
| 		"workflow_runs_unknown", unknown,
 | |
| 	)
 | |
| 
 | |
| 	return &replicas, nil
 | |
| }
 |