fiunchinho/iam-role-annotator

View on GitHub
cmd/root.go

Summary

Maintainability
A
0 mins
Test Coverage
package cmd

import (
    "fmt"
    "os"

    "path/filepath"

    "os/signal"
    "syscall"

    "time"

    "k8s.io/client-go/util/homedir"

    "github.com/fiunchinho/iam-role-annotator/pkg"
    "github.com/spf13/cobra"
    "github.com/spf13/viper"
    "github.com/spotahome/kooper/operator/controller"
    "go.uber.org/zap"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/clientcmd"
)

var (
    zapLogger, _ = zap.NewProduction(zap.AddCallerSkip(1))
    logger       = pkg.NewLogger(*zapLogger.Sugar())
    stopC        = make(chan struct{})
    finishC      = make(chan error)
    signalC      = make(chan os.Signal, 1)
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
    Use:   "iam-role-annotator",
    Short: "Kubernetes controller that automatically adds annotations in Pods to they can assume AWS Roles.",
    Long:  `Kubernetes controller that automatically adds annotations in Pods to they can assume AWS Roles.`,
    Run: func(cmd *cobra.Command, args []string) {
        defer zapLogger.Sync()
        signal.Notify(signalC, syscall.SIGTERM, syscall.SIGINT)

        k8sCli, err := getKubernetesClient(viper.GetString("kubeconfig"), logger)
        if err != nil {
            logger.Errorf("Can't create k8s client: %s", err)
            os.Exit(1)
        }

        go func() {
            finishC <- getController(k8sCli, logger).Run(stopC)
        }()

        select {
        case err := <-finishC:
            if err != nil {
                logger.Errorf("error running controller: %s", err)
                os.Exit(1)
            }
        case <-signalC:
            logger.Info("Signal captured, exiting...")
        }
    },
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
    if err := rootCmd.Execute(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

func init() {
    cobra.OnInitialize(func() {
        namespace := viper.GetString("namespace")
        if len(namespace) == 0 {
            logger.Error("Error: required flag \"namespace\" or environment variable \"NAMESPACE\" not set")
            os.Exit(1)
        }

        awsAccountID := viper.GetString("aws-account-id")
        if len(awsAccountID) == 0 {
            logger.Error("Error: required flag \"aws-account-id\" or environment variable \"AWS_ACCOUNT_ID\" not set")
            os.Exit(1)
        }
    })

    rootCmd.Flags().String("kubeconfig", filepath.Join(homedir.HomeDir(), ".kube", "config"), "Path to the kubeconfig file")
    viper.BindPFlag("kubeconfig", rootCmd.Flags().Lookup("kubeconfig"))

    rootCmd.Flags().String("namespace", "", "kubernetes namespace where this app is running")
    viper.BindPFlag("namespace", rootCmd.Flags().Lookup("namespace"))

    rootCmd.Flags().String("aws-account-id", "", "AWS Account ID that appears on the ARN of the roles referenced on the annotations")
    viper.BindPFlag("aws-account-id", rootCmd.Flags().Lookup("aws-account-id"))
    viper.BindEnv("aws-account-id", "AWS_ACCOUNT_ID")

    rootCmd.Flags().Int("resync-seconds", 30, "The number of seconds the controller will resync the resources")
    viper.BindPFlag("resync-seconds", rootCmd.Flags().Lookup("resync-seconds"))

    viper.AutomaticEnv()
}

func getKubernetesClient(kubeconfig string, logger pkg.Logger) (kubernetes.Interface, error) {
    var err error
    var cfg *rest.Config

    cfg, err = rest.InClusterConfig()
    if err != nil {
        logger.Warningf("Falling back to using kubeconfig file: %s", err)
        cfg, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
        if err != nil {
            return nil, err
        }
    }

    return kubernetes.NewForConfig(cfg)
}

func getController(k8sCli kubernetes.Interface, logger pkg.Logger) controller.Controller {
    return controller.NewSequential(
        time.Duration(viper.GetInt("resync-seconds"))*time.Second,
        pkg.NewHandler(pkg.NewIamRoleAnnotator(k8sCli, viper.GetString("aws-account-id"), logger)),
        pkg.NewDeploymentRetrieve(viper.GetString("namespace"), k8sCli),
        nil,
        logger,
    )
}