2020-01-28 15:03:23 +09:00
/ *
Copyright 2020 The actions - runner - controller authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package main
import (
"flag"
2020-02-01 20:18:16 +09:00
"fmt"
2020-01-28 15:03:23 +09:00
"os"
2021-02-18 20:19:08 +09:00
"strings"
2020-06-27 17:26:46 +09:00
"time"
2020-01-28 15:03:23 +09:00
2023-01-17 12:06:20 -05:00
githubv1alpha1 "github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
summerwindv1alpha1 "github.com/actions/actions-runner-controller/apis/actions.summerwind.net/v1alpha1"
2022-12-28 01:38:34 +01:00
"github.com/actions/actions-runner-controller/build"
2023-01-17 12:06:20 -05:00
actionsgithubcom "github.com/actions/actions-runner-controller/controllers/actions.github.com"
2022-12-28 01:38:34 +01:00
actionssummerwindnet "github.com/actions/actions-runner-controller/controllers/actions.summerwind.net"
"github.com/actions/actions-runner-controller/github"
2023-01-17 12:06:20 -05:00
"github.com/actions/actions-runner-controller/github/actions"
2022-12-28 01:38:34 +01:00
"github.com/actions/actions-runner-controller/logging"
2020-10-28 15:15:53 +02:00
"github.com/kelseyhightower/envconfig"
2020-01-28 15:03:23 +09:00
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
ctrl "sigs.k8s.io/controller-runtime"
// +kubebuilder:scaffold:imports
)
2020-02-03 16:56:52 +09:00
const (
2020-04-16 19:16:15 +09:00
defaultRunnerImage = "summerwind/actions-runner:latest"
defaultDockerImage = "docker:dind"
2020-02-03 16:56:52 +09:00
)
2023-03-10 18:05:51 +01:00
var scheme = runtime . NewScheme ( )
2020-01-28 15:03:23 +09:00
func init ( ) {
_ = clientgoscheme . AddToScheme ( scheme )
2023-01-17 12:06:20 -05:00
_ = githubv1alpha1 . AddToScheme ( scheme )
_ = summerwindv1alpha1 . AddToScheme ( scheme )
2020-01-28 15:03:23 +09:00
// +kubebuilder:scaffold:scheme
}
2021-12-14 16:29:31 -08:00
type stringSlice [ ] string
func ( i * stringSlice ) String ( ) string {
return fmt . Sprintf ( "%v" , * i )
}
func ( i * stringSlice ) Set ( value string ) error {
* i = append ( * i , value )
return nil
}
2023-03-10 18:05:51 +01:00
2020-01-28 15:03:23 +09:00
func main ( ) {
2020-02-03 16:56:52 +09:00
var (
2020-04-13 22:28:07 +09:00
err error
ghClient * github . Client
2023-01-17 12:06:20 -05:00
metricsAddr string
autoScalingRunnerSetOnly bool
enableLeaderElection bool
disableAdmissionWebhook bool
runnerStatusUpdateHook bool
leaderElectionId string
port int
syncPeriod time . Duration
2020-02-03 16:56:52 +09:00
2022-07-12 20:37:24 +09:00
defaultScaleDownDelay time . Duration
2021-05-10 00:03:11 +00:00
2021-12-14 16:29:31 -08:00
runnerImage string
runnerImagePullSecrets stringSlice
2021-07-14 22:20:08 +01:00
dockerImage string
dockerRegistryMirror string
namespace string
logLevel string
2022-11-04 01:46:58 +00:00
logFormat string
2021-02-18 20:19:08 +09:00
2023-01-17 12:06:20 -05:00
autoScalerImagePullSecrets stringSlice
2021-02-18 20:19:08 +09:00
commonRunnerLabels commaSeparatedStringSlice
2020-02-03 16:56:52 +09:00
)
2020-10-28 15:15:53 +02:00
var c github . Config
err = envconfig . Process ( "github" , & c )
if err != nil {
2021-11-03 10:24:24 +09:00
fmt . Fprintf ( os . Stderr , "Error: processing environment variables: %v\n" , err )
os . Exit ( 1 )
2020-10-28 15:15:53 +02:00
}
2020-01-28 15:03:23 +09:00
flag . StringVar ( & metricsAddr , "metrics-addr" , ":8080" , "The address the metric endpoint binds to." )
flag . BoolVar ( & enableLeaderElection , "enable-leader-election" , false ,
"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager." )
2021-09-11 18:26:29 +03:00
flag . StringVar ( & leaderElectionId , "leader-election-id" , "actions-runner-controller" , "Controller id for leader election." )
2022-05-14 09:11:20 +01:00
flag . StringVar ( & runnerImage , "runner-image" , defaultRunnerImage , "The image name of self-hosted runner container to use by default if one isn't defined in yaml." )
flag . StringVar ( & dockerImage , "docker-image" , defaultDockerImage , "The image name of docker sidecar container to use by default if one isn't defined in yaml." )
2021-12-14 16:29:31 -08:00
flag . Var ( & runnerImagePullSecrets , "runner-image-pull-secret" , "The default image-pull secret name for self-hosted runner container." )
2021-07-14 22:20:08 +01:00
flag . StringVar ( & dockerRegistryMirror , "docker-registry-mirror" , "" , "The default Docker Registry Mirror used by runners." )
2020-10-28 15:15:53 +02:00
flag . StringVar ( & c . Token , "github-token" , c . Token , "The personal access token of GitHub." )
2022-09-05 13:50:17 +01:00
flag . StringVar ( & c . EnterpriseURL , "github-enterprise-url" , c . EnterpriseURL , "Enterprise URL to be used for your GitHub API calls" )
2020-10-28 15:15:53 +02:00
flag . Int64Var ( & c . AppID , "github-app-id" , c . AppID , "The application ID of GitHub App." )
flag . Int64Var ( & c . AppInstallationID , "github-app-installation-id" , c . AppInstallationID , "The installation ID of GitHub App." )
flag . StringVar ( & c . AppPrivateKey , "github-app-private-key" , c . AppPrivateKey , "The path of a private key file to authenticate as a GitHub App" )
2021-12-22 16:24:10 -08:00
flag . StringVar ( & c . URL , "github-url" , c . URL , "GitHub URL to be used for GitHub API calls" )
flag . StringVar ( & c . UploadURL , "github-upload-url" , c . UploadURL , "GitHub Upload URL to be used for GitHub API calls" )
flag . StringVar ( & c . BasicauthUsername , "github-basicauth-username" , c . BasicauthUsername , "Username for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API" )
flag . StringVar ( & c . BasicauthPassword , "github-basicauth-password" , c . BasicauthPassword , "Password for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API" )
flag . StringVar ( & c . RunnerGitHubURL , "runner-github-url" , c . RunnerGitHubURL , "GitHub URL to be used by runners during registration" )
2022-07-09 23:11:29 -07:00
flag . BoolVar ( & runnerStatusUpdateHook , "runner-status-update-hook" , false , "Use custom RBAC for runners (role, role binding and service account)." )
2022-12-28 01:38:34 +01:00
flag . DurationVar ( & defaultScaleDownDelay , "default-scale-down-delay" , actionssummerwindnet . DefaultScaleDownDelay , "The approximate delay for a scale down followed by a scale up, used to prevent flapping (down->up->down->... loop)" )
2022-05-15 21:33:13 -04:00
flag . IntVar ( & port , "port" , 9443 , "The port to which the admission webhook endpoint should bind" )
2022-04-24 02:47:00 +01:00
flag . DurationVar ( & syncPeriod , "sync-period" , 1 * time . Minute , "Determines the minimum frequency at which K8s resources managed by this controller are reconciled." )
2022-12-28 01:38:34 +01:00
flag . Var ( & commonRunnerLabels , "common-runner-labels" , "Runner labels in the K1=V1,K2=V2,... format that are inherited all the runners created by the controller. See https://github.com/actions/actions-runner-controller/issues/321 for more information" )
2021-03-09 09:12:46 +09:00
flag . StringVar ( & namespace , "watch-namespace" , "" , "The namespace to watch for custom resources. Set to empty for letting it watch for all namespaces." )
2022-02-19 09:21:14 +00:00
flag . StringVar ( & logLevel , "log-level" , logging . LogLevelDebug , ` The verbosity of the logging. Valid values are "debug", "info", "warn", "error". Defaults to "debug". ` )
2022-11-04 01:46:58 +00:00
flag . StringVar ( & logFormat , "log-format" , "text" , ` The log format. Valid options are "text" and "json". Defaults to "text" ` )
2023-01-17 12:06:20 -05:00
flag . BoolVar ( & autoScalingRunnerSetOnly , "auto-scaling-runner-set-only" , false , "Make controller only reconcile AutoRunnerScaleSet object." )
flag . Var ( & autoScalerImagePullSecrets , "auto-scaler-image-pull-secrets" , "The default image-pull secret name for auto-scaler listener container." )
2020-01-28 15:03:23 +09:00
flag . Parse ( )
2022-11-04 01:46:58 +00:00
log , err := logging . NewLogger ( logLevel , logFormat )
if err != nil {
fmt . Fprintf ( os . Stderr , "Error: creating logger: %v\n" , err )
os . Exit ( 1 )
}
c . Log = & log
2020-11-10 17:03:33 +09:00
2023-01-17 12:06:20 -05:00
if ! autoScalingRunnerSetOnly {
ghClient , err = c . NewClient ( )
if err != nil {
log . Error ( err , "unable to create client" )
os . Exit ( 1 )
}
2020-03-26 23:12:11 +09:00
}
2020-01-28 21:58:01 +09:00
2022-11-04 01:46:58 +00:00
ctrl . SetLogger ( log )
2020-01-28 15:03:23 +09:00
2023-01-17 12:06:20 -05:00
if autoScalingRunnerSetOnly {
// We don't support metrics for AutoRunnerScaleSet for now
metricsAddr = "0"
}
2020-01-28 15:03:23 +09:00
mgr , err := ctrl . NewManager ( ctrl . GetConfigOrDie ( ) , ctrl . Options {
Scheme : scheme ,
MetricsBindAddress : metricsAddr ,
LeaderElection : enableLeaderElection ,
2021-09-11 18:26:29 +03:00
LeaderElectionID : leaderElectionId ,
2022-05-15 21:33:13 -04:00
Port : port ,
2020-06-27 17:26:46 +09:00
SyncPeriod : & syncPeriod ,
2021-03-09 09:12:46 +09:00
Namespace : namespace ,
2020-01-28 15:03:23 +09:00
} )
if err != nil {
2021-03-20 07:34:25 +09:00
log . Error ( err , "unable to start manager" )
2020-01-28 15:03:23 +09:00
os . Exit ( 1 )
}
2023-03-10 18:05:51 +01:00
if autoScalingRunnerSetOnly {
managerImage := os . Getenv ( "CONTROLLER_MANAGER_CONTAINER_IMAGE" )
if managerImage == "" {
log . Error ( err , "unable to obtain listener image" )
os . Exit ( 1 )
}
managerNamespace := os . Getenv ( "CONTROLLER_MANAGER_POD_NAMESPACE" )
if managerNamespace == "" {
log . Error ( err , "unable to obtain manager pod namespace" )
os . Exit ( 1 )
}
2022-07-12 09:45:00 +09:00
2023-03-10 18:05:51 +01:00
actionsMultiClient := actions . NewMultiClient (
"actions-runner-controller/" + build . Version ,
log . WithName ( "actions-clients" ) ,
)
if err = ( & actionsgithubcom . AutoscalingRunnerSetReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "AutoscalingRunnerSet" ) ,
Scheme : mgr . GetScheme ( ) ,
ControllerNamespace : managerNamespace ,
DefaultRunnerScaleSetListenerImage : managerImage ,
ActionsClient : actionsMultiClient ,
DefaultRunnerScaleSetListenerImagePullSecrets : autoScalerImagePullSecrets ,
} ) . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "AutoscalingRunnerSet" )
os . Exit ( 1 )
}
if err = ( & actionsgithubcom . EphemeralRunnerReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "EphemeralRunner" ) ,
Scheme : mgr . GetScheme ( ) ,
ActionsClient : actionsMultiClient ,
} ) . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "EphemeralRunner" )
os . Exit ( 1 )
}
if err = ( & actionsgithubcom . EphemeralRunnerSetReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "EphemeralRunnerSet" ) ,
Scheme : mgr . GetScheme ( ) ,
ActionsClient : actionsMultiClient ,
} ) . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "EphemeralRunnerSet" )
os . Exit ( 1 )
}
if err = ( & actionsgithubcom . AutoscalingListenerReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "AutoscalingListener" ) ,
Scheme : mgr . GetScheme ( ) ,
} ) . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "AutoscalingListener" )
os . Exit ( 1 )
}
} else {
multiClient := actionssummerwindnet . NewMultiGitHubClient (
mgr . GetClient ( ) ,
ghClient ,
)
2020-01-28 21:58:01 +09:00
2023-01-17 12:06:20 -05:00
runnerReconciler := & actionssummerwindnet . RunnerReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "runner" ) ,
Scheme : mgr . GetScheme ( ) ,
GitHubClient : multiClient ,
DockerImage : dockerImage ,
DockerRegistryMirror : dockerRegistryMirror ,
UseRunnerStatusUpdateHook : runnerStatusUpdateHook ,
// Defaults for self-hosted runner containers
RunnerImage : runnerImage ,
RunnerImagePullSecrets : runnerImagePullSecrets ,
}
2020-02-21 03:01:52 +09:00
2023-01-17 12:06:20 -05:00
if err = runnerReconciler . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "Runner" )
os . Exit ( 1 )
}
2020-02-21 03:01:52 +09:00
2023-01-17 12:06:20 -05:00
runnerReplicaSetReconciler := & actionssummerwindnet . RunnerReplicaSetReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "runnerreplicaset" ) ,
Scheme : mgr . GetScheme ( ) ,
}
2020-02-26 21:23:23 +09:00
2023-01-17 12:06:20 -05:00
if err = runnerReplicaSetReconciler . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "RunnerReplicaSet" )
os . Exit ( 1 )
}
2020-07-19 18:42:06 +09:00
2023-01-17 12:06:20 -05:00
runnerDeploymentReconciler := & actionssummerwindnet . RunnerDeploymentReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "runnerdeployment" ) ,
Scheme : mgr . GetScheme ( ) ,
CommonRunnerLabels : commonRunnerLabels ,
}
2020-07-19 18:42:06 +09:00
2023-01-17 12:06:20 -05:00
if err = runnerDeploymentReconciler . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "RunnerDeployment" )
os . Exit ( 1 )
}
2021-06-22 17:10:09 +09:00
2023-01-17 12:06:20 -05:00
runnerSetReconciler := & actionssummerwindnet . RunnerSetReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "runnerset" ) ,
Scheme : mgr . GetScheme ( ) ,
CommonRunnerLabels : commonRunnerLabels ,
DockerImage : dockerImage ,
DockerRegistryMirror : dockerRegistryMirror ,
GitHubClient : multiClient ,
// Defaults for self-hosted runner containers
RunnerImage : runnerImage ,
RunnerImagePullSecrets : runnerImagePullSecrets ,
UseRunnerStatusUpdateHook : runnerStatusUpdateHook ,
}
2021-05-11 02:34:55 +00:00
2023-01-17 12:06:20 -05:00
if err = runnerSetReconciler . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "RunnerSet" )
os . Exit ( 1 )
}
2021-05-11 02:34:55 +00:00
2023-01-17 12:06:20 -05:00
log . Info (
"Initializing actions-runner-controller" ,
"version" , build . Version ,
"default-scale-down-delay" , defaultScaleDownDelay ,
"sync-period" , syncPeriod ,
"default-runner-image" , runnerImage ,
"default-docker-image" , dockerImage ,
"common-runnner-labels" , commonRunnerLabels ,
"leader-election-enabled" , enableLeaderElection ,
"leader-election-id" , leaderElectionId ,
"watch-namespace" , namespace ,
)
horizontalRunnerAutoscaler := & actionssummerwindnet . HorizontalRunnerAutoscalerReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "horizontalrunnerautoscaler" ) ,
Scheme : mgr . GetScheme ( ) ,
GitHubClient : multiClient ,
DefaultScaleDownDelay : defaultScaleDownDelay ,
}
2020-02-26 21:23:23 +09:00
2023-01-17 12:06:20 -05:00
runnerPodReconciler := & actionssummerwindnet . RunnerPodReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "runnerpod" ) ,
Scheme : mgr . GetScheme ( ) ,
GitHubClient : multiClient ,
}
2021-06-24 20:39:37 +09:00
2023-01-17 12:06:20 -05:00
runnerPersistentVolumeReconciler := & actionssummerwindnet . RunnerPersistentVolumeReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "runnerpersistentvolume" ) ,
Scheme : mgr . GetScheme ( ) ,
}
2022-05-16 09:26:48 +09:00
2023-01-17 12:06:20 -05:00
runnerPersistentVolumeClaimReconciler := & actionssummerwindnet . RunnerPersistentVolumeClaimReconciler {
Client : mgr . GetClient ( ) ,
Log : log . WithName ( "runnerpersistentvolumeclaim" ) ,
Scheme : mgr . GetScheme ( ) ,
}
if err = runnerPodReconciler . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "RunnerPod" )
os . Exit ( 1 )
}
if err = horizontalRunnerAutoscaler . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "HorizontalRunnerAutoscaler" )
os . Exit ( 1 )
}
if err = runnerPersistentVolumeReconciler . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "RunnerPersistentVolume" )
os . Exit ( 1 )
}
if err = runnerPersistentVolumeClaimReconciler . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create controller" , "controller" , "RunnerPersistentVolumeClaim" )
os . Exit ( 1 )
}
if ! disableAdmissionWebhook {
if err = ( & summerwindv1alpha1 . Runner { } ) . SetupWebhookWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create webhook" , "webhook" , "Runner" )
os . Exit ( 1 )
}
if err = ( & summerwindv1alpha1 . RunnerDeployment { } ) . SetupWebhookWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create webhook" , "webhook" , "RunnerDeployment" )
os . Exit ( 1 )
}
if err = ( & summerwindv1alpha1 . RunnerReplicaSet { } ) . SetupWebhookWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create webhook" , "webhook" , "RunnerReplicaSet" )
os . Exit ( 1 )
}
2023-03-10 18:05:51 +01:00
injector := & actionssummerwindnet . PodRunnerTokenInjector {
Client : mgr . GetClient ( ) ,
GitHubClient : multiClient ,
Log : ctrl . Log . WithName ( "webhook" ) . WithName ( "PodRunnerTokenInjector" ) ,
}
if err = injector . SetupWithManager ( mgr ) ; err != nil {
log . Error ( err , "unable to create webhook server" , "webhook" , "PodRunnerTokenInjector" )
os . Exit ( 1 )
2023-02-21 08:18:59 +09:00
}
2023-01-17 12:06:20 -05:00
}
2021-06-22 17:10:09 +09:00
}
2021-03-20 07:34:25 +09:00
log . Info ( "starting manager" )
2020-01-28 15:03:23 +09:00
if err := mgr . Start ( ctrl . SetupSignalHandler ( ) ) ; err != nil {
2021-03-20 07:34:25 +09:00
log . Error ( err , "problem running manager" )
2020-01-28 15:03:23 +09:00
os . Exit ( 1 )
}
}
2021-02-18 20:19:08 +09:00
type commaSeparatedStringSlice [ ] string
func ( s * commaSeparatedStringSlice ) String ( ) string {
return fmt . Sprintf ( "%v" , * s )
}
func ( s * commaSeparatedStringSlice ) Set ( value string ) error {
for _ , v := range strings . Split ( value , "," ) {
if v == "" {
continue
}
* s = append ( * s , v )
}
return nil
}