github.com/abayer/test-infra@v0.0.5/prow/cmd/artifact-uploader/main.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"flag"
    23  	"fmt"
    24  
    25  	"github.com/sirupsen/logrus"
    26  	"k8s.io/client-go/kubernetes"
    27  	"k8s.io/client-go/rest"
    28  	"k8s.io/client-go/tools/clientcmd"
    29  	"k8s.io/test-infra/prow/kube"
    30  
    31  	"k8s.io/test-infra/prow/artifact-uploader"
    32  	"k8s.io/test-infra/prow/gcsupload"
    33  	"k8s.io/test-infra/prow/logrusutil"
    34  	"k8s.io/test-infra/prow/pod-utils/options"
    35  )
    36  
    37  // newOptions returns an empty Options with no nil fields
    38  func newOptions() *Options {
    39  	return &Options{
    40  		Options: gcsupload.NewOptions(),
    41  	}
    42  }
    43  
    44  // Options holds info about parallelism, how to upload and cluster credentials.
    45  type Options struct {
    46  	// NumWorkers determines the number of workers that consume
    47  	// the controller's work queue
    48  	NumWorkers int `json:"num_workers"`
    49  	// ProwJobNamespace is the namespace in the cluster that holds
    50  	// ProwJob objects
    51  	ProwJobNamespace string `json:"'prow_job_namespace'"`
    52  
    53  	*gcsupload.Options
    54  
    55  	clusterConfig *rest.Config
    56  }
    57  
    58  // Validate ensures that the set of options are
    59  // self-consistent and valid
    60  func (o *Options) Validate() error {
    61  	if o.NumWorkers == 0 {
    62  		return errors.New("number of workers cannot be zero")
    63  	}
    64  
    65  	if o.ProwJobNamespace == "" {
    66  		return errors.New("namespace containing ProwJobs not configured")
    67  	}
    68  
    69  	return o.Options.Validate()
    70  }
    71  
    72  const (
    73  	// JSONConfigEnvVar is the environment variable that
    74  	// utilities expect to find a full JSON configuration
    75  	// in when run.
    76  	JSONConfigEnvVar = "ARTIFACTUPLOAD_OPTIONS"
    77  )
    78  
    79  // ConfigVar exposes the environment variable used
    80  // to store serialized configuration
    81  func (o *Options) ConfigVar() string {
    82  	return JSONConfigEnvVar
    83  }
    84  
    85  // LoadConfig loads options from serialized config
    86  func (o *Options) LoadConfig(config string) error {
    87  	return json.Unmarshal([]byte(config), o)
    88  }
    89  
    90  // BindOptions binds flags to options
    91  func (o *Options) BindOptions(flags *flag.FlagSet) {
    92  	flags.IntVar(&o.NumWorkers, "num-workers", 25, "Number of threads to use for processing updates.")
    93  	flags.StringVar(&o.ProwJobNamespace, "prow-job-ns", "", "Namespace containing ProwJobs.")
    94  	gcsupload.BindOptions(o.Options, flags)
    95  }
    96  
    97  // Complete internalizes command line arguments
    98  func (o *Options) Complete(args []string) {
    99  	o.Options.Complete(args)
   100  }
   101  
   102  // loadClusterConfig loads connection configuration
   103  // for the cluster we're deploying to. We prefer to
   104  // use in-cluster configuration if possible, but will
   105  // fall back to using default rules otherwise.
   106  func loadClusterConfig() (*rest.Config, error) {
   107  	clusterConfig, err := rest.InClusterConfig()
   108  	if err == nil {
   109  		return clusterConfig, nil
   110  	}
   111  
   112  	credentials, err := clientcmd.NewDefaultClientConfigLoadingRules().Load()
   113  	if err != nil {
   114  		return nil, fmt.Errorf("could not load credentials from config: %v", err)
   115  	}
   116  
   117  	clusterConfig, err = clientcmd.NewDefaultClientConfig(*credentials, &clientcmd.ConfigOverrides{}).ClientConfig()
   118  	if err != nil {
   119  		return nil, fmt.Errorf("could not load client configuration: %v", err)
   120  	}
   121  	return clusterConfig, nil
   122  }
   123  
   124  // Run uploads artifacts with the specified options forever.
   125  //
   126  // Sends a stop message to the artifact uploader when it is interrupted.
   127  func (o *Options) Run() error {
   128  	clusterConfig, err := loadClusterConfig()
   129  	if err != nil {
   130  		return fmt.Errorf("failed to load cluster config: %v", err)
   131  	}
   132  
   133  	client, err := kubernetes.NewForConfig(clusterConfig)
   134  	if err != nil {
   135  		return err
   136  	}
   137  
   138  	prowJobClient, err := kube.NewClientInCluster(o.ProwJobNamespace)
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	controller := artifact_uploader.NewController(client.CoreV1(), prowJobClient, o.Options)
   144  
   145  	stop := make(chan struct{})
   146  	defer close(stop)
   147  	go controller.Run(o.NumWorkers, stop)
   148  
   149  	// Wait forever
   150  	select {}
   151  }
   152  
   153  func main() {
   154  	o := newOptions()
   155  	if err := options.Load(o); err != nil {
   156  		logrus.Fatalf("Could not resolve options: %v", err)
   157  	}
   158  
   159  	if err := o.Validate(); err != nil {
   160  		logrus.Fatalf("Invalid options: %v", err)
   161  	}
   162  
   163  	logrus.SetFormatter(
   164  		logrusutil.NewDefaultFieldsFormatter(nil, logrus.Fields{"component": "artifact-uploader"}),
   165  	)
   166  
   167  	if err := o.Run(); err != nil {
   168  		logrus.WithError(err).Fatal("Failed to run the GCS uploader controller")
   169  	}
   170  }