Files
actions-runner-controller/cmd/githubrunnerscalesetlistener/autoScalerKubernetesManager.go
Tingluo Huang 622eaa34f8 Introduce new preview auto-scaling mode for ARC. (#2153)
Co-authored-by: Cory Miller <cory-miller@github.com>
Co-authored-by: Nikola Jokic <nikola-jokic@github.com>
Co-authored-by: Ava Stancu <AvaStancu@github.com>
Co-authored-by: Ferenc Hammerl <fhammerl@github.com>
Co-authored-by: Francesco Renzi <rentziass@github.com>
Co-authored-by: Bassem Dghaidi <Link-@github.com>
2023-01-17 12:06:20 -05:00

130 lines
3.8 KiB
Go

package main
import (
"context"
"encoding/json"
"fmt"
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
jsonpatch "github.com/evanphx/json-patch"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
type AutoScalerKubernetesManager struct {
*kubernetes.Clientset
logger logr.Logger
}
func NewKubernetesManager(logger *logr.Logger) (*AutoScalerKubernetesManager, error) {
conf, err := rest.InClusterConfig()
if err != nil {
return nil, err
}
kubeClient, err := kubernetes.NewForConfig(conf)
if err != nil {
return nil, err
}
var manager = &AutoScalerKubernetesManager{
Clientset: kubeClient,
logger: logger.WithName("KubernetesManager"),
}
return manager, nil
}
func (k *AutoScalerKubernetesManager) ScaleEphemeralRunnerSet(ctx context.Context, namespace, resourceName string, runnerCount int) error {
original := &v1alpha1.EphemeralRunnerSet{
Spec: v1alpha1.EphemeralRunnerSetSpec{
Replicas: -1,
},
}
originalJson, err := json.Marshal(original)
if err != nil {
k.logger.Error(err, "could not marshal empty ephemeral runner set")
}
patch := &v1alpha1.EphemeralRunnerSet{
Spec: v1alpha1.EphemeralRunnerSetSpec{
Replicas: runnerCount,
},
}
patchJson, err := json.Marshal(patch)
if err != nil {
k.logger.Error(err, "could not marshal patch ephemeral runner set")
}
mergePatch, err := jsonpatch.CreateMergePatch(originalJson, patchJson)
if err != nil {
k.logger.Error(err, "could not create merge patch json for ephemeral runner set")
}
k.logger.Info("Created merge patch json for EphemeralRunnerSet update", "json", string(mergePatch))
patchedEphemeralRunnerSet := &v1alpha1.EphemeralRunnerSet{}
err = k.RESTClient().
Patch(types.MergePatchType).
Prefix("apis", "actions.github.com", "v1alpha1").
Namespace(namespace).
Resource("EphemeralRunnerSets").
Name(resourceName).
Body([]byte(mergePatch)).
Do(ctx).
Into(patchedEphemeralRunnerSet)
if err != nil {
return fmt.Errorf("could not patch ephemeral runner set , patch JSON: %s, error: %w", string(mergePatch), err)
}
k.logger.Info("Ephemeral runner set scaled.", "namespace", namespace, "name", resourceName, "replicas", patchedEphemeralRunnerSet.Spec.Replicas)
return nil
}
func (k *AutoScalerKubernetesManager) UpdateEphemeralRunnerWithJobInfo(ctx context.Context, namespace, resourceName, ownerName, repositoryName, jobWorkflowRef, jobDisplayName string, workflowRunId, jobRequestId int64) error {
original := &v1alpha1.EphemeralRunner{}
originalJson, err := json.Marshal(original)
if err != nil {
return fmt.Errorf("could not marshal empty ephemeral runner, error: %w", err)
}
patch := &v1alpha1.EphemeralRunner{
Status: v1alpha1.EphemeralRunnerStatus{
JobRequestId: jobRequestId,
JobRepositoryName: fmt.Sprintf("%s/%s", ownerName, repositoryName),
WorkflowRunId: workflowRunId,
JobWorkflowRef: jobWorkflowRef,
JobDisplayName: jobDisplayName,
},
}
patchedJson, err := json.Marshal(patch)
if err != nil {
return fmt.Errorf("could not marshal patched ephemeral runner, error: %w", err)
}
mergePatch, err := jsonpatch.CreateMergePatch(originalJson, patchedJson)
if err != nil {
k.logger.Error(err, "could not create merge patch json for ephemeral runner")
}
k.logger.Info("Created merge patch json for EphemeralRunner status update", "json", string(mergePatch))
patchedStatus := &v1alpha1.EphemeralRunner{}
err = k.RESTClient().
Patch(types.MergePatchType).
Prefix("apis", "actions.github.com", "v1alpha1").
Namespace(namespace).
Resource("EphemeralRunners").
Name(resourceName).
SubResource("status").
Body(mergePatch).
Do(ctx).
Into(patchedStatus)
if err != nil {
return fmt.Errorf("could not patch ephemeral runner status, patch JSON: %s, error: %w", string(mergePatch), err)
}
return nil
}