Skip to content
Snippets Groups Projects
Select Git revision
  • 5b08277ce442586608dce7ac12db149ca8889da1
  • master default protected
  • v2.27.1
  • v2.28.0
  • v2.27.0
  • v2.25.1
  • v2.24.3
  • v2.26.0
  • v2.24.2
  • v2.25.0
  • v2.24.1
  • v2.22.2
  • v2.23.3
  • v2.24.0
  • v2.23.2
  • v2.23.1
  • v2.23.0
  • v2.22.1
  • v2.22.0
  • v2.21.0
  • v2.20.0
  • v2.19.1
22 results

gitlab-runner.sh

Blame
  • main.go 9.20 KiB
    package main
    
    import (
    	"context"
    	"fmt"
    	"os"
    	"os/signal"
    	"path/filepath"
    	"syscall"
    
    	"github.com/Sirupsen/logrus"
    	"github.com/pkg/errors"
    	"github.com/urfave/cli"
    
    	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    	clientset "k8s.io/client-go/kubernetes"
    	"k8s.io/client-go/rest"
    	"k8s.io/client-go/tools/clientcmd"
    	"k8s.io/klog/v2"
    
    	pvController "sigs.k8s.io/sig-storage-lib-external-provisioner/v8/controller"
    )
    
    var (
    	VERSION                       = "0.0.1"
    	FlagConfigFile                = "config"
    	FlagProvisionerName           = "provisioner-name"
    	EnvProvisionerName            = "PROVISIONER_NAME"
    	DefaultProvisionerName        = "rancher.io/local-path"
    	FlagNamespace                 = "namespace"
    	EnvNamespace                  = "POD_NAMESPACE"
    	DefaultNamespace              = "local-path-storage"
    	FlagHelperImage               = "helper-image"
    	EnvHelperImage                = "HELPER_IMAGE"
    	DefaultHelperImage            = "rancher/library-busybox:1.32.1"
    	FlagServiceAccountName        = "service-account-name"
    	DefaultServiceAccount         = "local-path-provisioner-service-account"
    	EnvServiceAccountName         = "SERVICE_ACCOUNT_NAME"
    	FlagKubeconfig                = "kubeconfig"
    	DefaultConfigFileKey          = "config.json"
    	DefaultConfigMapName          = "local-path-config"
    	FlagConfigMapName             = "configmap-name"
    	FlagHelperPodFile             = "helper-pod-file"
    	DefaultHelperPodFile          = "helperPod.yaml"
    	FlagWorkerThreads             = "worker-threads"
    	DefaultWorkerThreads          = pvController.DefaultThreadiness
    	FlagProvisioningRetryCount    = "provisioning-retry-count"
    	DefaultProvisioningRetryCount = pvController.DefaultFailedProvisionThreshold
    	FlagDeletionRetryCount        = "deletion-retry-count"
    	DefaultDeletionRetryCount     = pvController.DefaultFailedDeleteThreshold
    )
    
    func cmdNotFound(c *cli.Context, command string) {
    	panic(fmt.Errorf("Unrecognized command: %s", command))
    }
    
    func onUsageError(c *cli.Context, err error, isSubcommand bool) error {
    	panic(fmt.Errorf("Usage error, please check your command"))
    }
    
    func RegisterShutdownChannel(cancelFn context.CancelFunc) {
    	sigs := make(chan os.Signal, 1)
    	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
    	go func() {
    		sig := <-sigs
    		klog.Infof("Receive %v to exit", sig)
    		cancelFn()
    	}()
    }
    
    func StartCmd() cli.Command {
    	return cli.Command{
    		Name: "start",
    		Flags: []cli.Flag{
    			cli.StringFlag{
    				Name:  FlagConfigFile,
    				Usage: "Required. Provisioner configuration file.",
    				Value: "",
    			},
    			cli.StringFlag{
    				Name:   FlagProvisionerName,
    				Usage:  "Required. Specify Provisioner name.",
    				EnvVar: EnvProvisionerName,
    				Value:  DefaultProvisionerName,
    			},
    			cli.StringFlag{
    				Name:   FlagNamespace,
    				Usage:  "Required. The namespace that Provisioner is running in",
    				EnvVar: EnvNamespace,
    				Value:  DefaultNamespace,
    			},
    			cli.StringFlag{
    				Name:   FlagHelperImage,
    				Usage:  "Required. The helper image used for create/delete directories on the host",
    				EnvVar: EnvHelperImage,
    				Value:  DefaultHelperImage,
    			},
    			cli.StringFlag{
    				Name:  FlagKubeconfig,
    				Usage: "Paths to a kubeconfig. Only required when it is out-of-cluster.",
    				Value: "",
    			},
    			cli.StringFlag{
    				Name:  FlagConfigMapName,
    				Usage: "Required. Specify configmap name.",
    				Value: DefaultConfigMapName,
    			},
    			cli.StringFlag{
    				Name:   FlagServiceAccountName,
    				Usage:  "Required. The ServiceAccountName for deployment",
    				EnvVar: EnvServiceAccountName,
    				Value:  DefaultServiceAccount,
    			},
    			cli.StringFlag{
    				Name:  FlagHelperPodFile,
    				Usage: "Paths to the Helper pod yaml file",
    				Value: "",
    			},
    			cli.IntFlag{
    				Name:  FlagWorkerThreads,
    				Usage: "Number of provisioner worker threads.",
    				Value: DefaultWorkerThreads,
    			},
    			cli.IntFlag{
    				Name:  FlagProvisioningRetryCount,
    				Usage: "Number of retries of failed volume provisioning. 0 means retry indefinitely.",
    				Value: DefaultProvisioningRetryCount,
    			},
    			cli.IntFlag{
    				Name:  FlagDeletionRetryCount,
    				Usage: "Number of retries of failed volume deletion. 0 means retry indefinitely.",
    				Value: DefaultDeletionRetryCount,
    			},
    		},
    		Action: func(c *cli.Context) {
    			if err := startDaemon(c); err != nil {
    				logrus.Fatalf("Error starting daemon: %v", err)
    			}
    		},
    	}
    }
    
    func homeDir() string {
    	if h := os.Getenv("HOME"); h != "" {
    		return h
    	}
    	return os.Getenv("USERPROFILE") // windows
    }
    
    func loadConfig(kubeconfig string) (*rest.Config, error) {
    	if len(kubeconfig) > 0 {
    		return clientcmd.BuildConfigFromFlags("", kubeconfig)
    	}
    
    	kubeconfigPath := os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
    	if len(kubeconfigPath) > 0 {
    		envVarFiles := filepath.SplitList(kubeconfigPath)
    		for _, f := range envVarFiles {
    			if _, err := os.Stat(f); err == nil {
    				return clientcmd.BuildConfigFromFlags("", f)
    			}
    		}
    	}
    
    	if c, err := rest.InClusterConfig(); err == nil {
    		return c, nil
    	}
    
    	kubeconfig = filepath.Join(homeDir(), clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName)
    	return clientcmd.BuildConfigFromFlags("", kubeconfig)
    }
    
    func findConfigFileFromConfigMap(kubeClient clientset.Interface, namespace, configMapName, key string) (string, error) {
    	cm, err := kubeClient.CoreV1().ConfigMaps(namespace).Get(context.TODO(), configMapName, metav1.GetOptions{})
    	if err != nil {
    		return "", err
    	}
    	value, ok := cm.Data[key]
    	if !ok {
    		return "", fmt.Errorf("%v is not exist in local-path-config ConfigMap", key)
    	}
    	return value, nil
    }
    
    func startDaemon(c *cli.Context) error {
    	ctx, cancelFn := context.WithCancel(context.TODO())
    	RegisterShutdownChannel(cancelFn)
    
    	config, err := loadConfig(c.String(FlagKubeconfig))
    	if err != nil {
    		return errors.Wrap(err, "unable to get client config")
    	}
    
    	kubeClient, err := clientset.NewForConfig(config)
    	if err != nil {
    		return errors.Wrap(err, "unable to get k8s client")
    	}
    
    	provisionerName := c.String(FlagProvisionerName)
    	if provisionerName == "" {
    		return fmt.Errorf("invalid empty flag %v", FlagProvisionerName)
    	}
    	namespace := c.String(FlagNamespace)
    	if namespace == "" {
    		return fmt.Errorf("invalid empty flag %v", FlagNamespace)
    	}
    	configMapName := c.String(FlagConfigMapName)
    	if configMapName == "" {
    		return fmt.Errorf("invalid empty flag %v", FlagConfigMapName)
    	}
    	configFile := c.String(FlagConfigFile)
    	if configFile == "" {
    		configFile, err = findConfigFileFromConfigMap(kubeClient, namespace, configMapName, DefaultConfigFileKey)
    		if err != nil {
    			return fmt.Errorf("invalid empty flag %v and it also does not exist at ConfigMap %v/%v with err: %v", FlagConfigFile, namespace, configMapName, err)
    		}
    	}
    	helperImage := c.String(FlagHelperImage)
    	if helperImage == "" {
    		return fmt.Errorf("invalid empty flag %v", FlagHelperImage)
    	}
    
    	serviceAccountName := c.String(FlagServiceAccountName)
    	if serviceAccountName == "" {
    		return fmt.Errorf("invalid empty flag %v", FlagServiceAccountName)
    	}
    
    	// if helper pod file is not specified, then find the helper pod by configmap with key = helperPod.yaml
    	// if helper pod file is specified with flag FlagHelperPodFile, then load the file
    	helperPodFile := c.String(FlagHelperPodFile)
    	helperPodYaml := ""
    	if helperPodFile == "" {
    		helperPodYaml, err = findConfigFileFromConfigMap(kubeClient, namespace, configMapName, DefaultHelperPodFile)
    		if err != nil {
    			return fmt.Errorf("invalid empty flag %v and it also does not exist at ConfigMap %v/%v with err: %v", FlagHelperPodFile, namespace, configMapName, err)
    		}
    	} else {
    		helperPodYaml, err = loadFile(helperPodFile)
    		if err != nil {
    			return fmt.Errorf("could not open file %v with err: %v", helperPodFile, err)
    		}
    	}
    
    	provisioningRetryCount := c.Int(FlagProvisioningRetryCount)
    	if provisioningRetryCount < 0 {
    		return fmt.Errorf("invalid negative integer flag %v", FlagProvisioningRetryCount)
    	}
    
    	deletionRetryCount := c.Int(FlagDeletionRetryCount)
    	if deletionRetryCount < 0 {
    		return fmt.Errorf("invalid negative integer flag %v", FlagDeletionRetryCount)
    	}
    
    	workerThreads := c.Int(FlagWorkerThreads)
    	if workerThreads <= 0 {
    		return fmt.Errorf("invalid zero or negative integer flag %v", FlagWorkerThreads)
    	}
    
    	provisioner, err := NewProvisioner(ctx, kubeClient, configFile, namespace, helperImage, configMapName, serviceAccountName, helperPodYaml)
    	if err != nil {
    		return err
    	}
    	pc := pvController.NewProvisionController(
    		kubeClient,
    		provisionerName,
    		provisioner,
    		pvController.LeaderElection(false),
    		pvController.FailedProvisionThreshold(provisioningRetryCount),
    		pvController.FailedDeleteThreshold(deletionRetryCount),
    		pvController.Threadiness(workerThreads),
    	)
    	logrus.Debug("Provisioner started")
    	pc.Run(ctx)
    	logrus.Debug("Provisioner stopped")
    	return nil
    }
    
    func main() {
    	logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
    
    	a := cli.NewApp()
    	a.Version = VERSION
    	a.Usage = "Local Path Provisioner"
    
    	a.Before = func(c *cli.Context) error {
    		if c.GlobalBool("debug") {
    			logrus.SetLevel(logrus.DebugLevel)
    		}
    		return nil
    	}
    
    	a.Flags = []cli.Flag{
    		cli.BoolFlag{
    			Name:   "debug, d",
    			Usage:  "enable debug logging level",
    			EnvVar: "RANCHER_DEBUG",
    		},
    	}
    	a.Commands = []cli.Command{
    		StartCmd(),
    	}
    	a.CommandNotFound = cmdNotFound
    	a.OnUsageError = onUsageError
    
    	if err := a.Run(os.Args); err != nil {
    		logrus.Fatalf("Critical error: %v", err)
    	}
    }