github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/prow/cmd/hook/main.go (about)

     1  /*
     2  Copyright 2016 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  	"bytes"
    21  	"flag"
    22  	"io/ioutil"
    23  	"net/http"
    24  	"net/url"
    25  	"os/signal"
    26  	"strconv"
    27  	"syscall"
    28  	"time"
    29  
    30  	"github.com/prometheus/client_golang/prometheus"
    31  	"github.com/prometheus/client_golang/prometheus/promhttp"
    32  	"github.com/prometheus/client_golang/prometheus/push"
    33  	"github.com/sirupsen/logrus"
    34  
    35  	"k8s.io/test-infra/prow/config"
    36  	"k8s.io/test-infra/prow/git"
    37  	"k8s.io/test-infra/prow/github"
    38  	"k8s.io/test-infra/prow/hook"
    39  	"k8s.io/test-infra/prow/kube"
    40  	"k8s.io/test-infra/prow/plugins"
    41  	"k8s.io/test-infra/prow/slack"
    42  )
    43  
    44  var (
    45  	port = flag.Int("port", 8888, "Port to listen on.")
    46  
    47  	configPath   = flag.String("config-path", "/etc/config/config", "Path to config.yaml.")
    48  	pluginConfig = flag.String("plugin-config", "/etc/plugins/plugins", "Path to plugin config file.")
    49  
    50  	local  = flag.Bool("local", false, "Run locally for testing purposes only. Does not require secret files.")
    51  	dryRun = flag.Bool("dry-run", true, "Dry run for testing. Uses API tokens but does not mutate.")
    52  
    53  	_               = flag.String("github-bot-name", "", "Deprecated.")
    54  	githubEndpoint  = flag.String("github-endpoint", "https://api.github.com", "GitHub's API endpoint.")
    55  	githubTokenFile = flag.String("github-token-file", "/etc/github/oauth", "Path to the file containing the GitHub OAuth secret.")
    56  
    57  	webhookSecretFile = flag.String("hmac-secret-file", "/etc/webhook/hmac", "Path to the file containing the GitHub HMAC secret.")
    58  	slackTokenFile    = flag.String("slack-token-file", "", "Path to the file containing the Slack token to use.")
    59  )
    60  
    61  func main() {
    62  	flag.Parse()
    63  
    64  	configAgent := &config.Agent{}
    65  	if err := configAgent.Start(*configPath); err != nil {
    66  		logrus.WithError(err).Fatal("Error starting config agent.")
    67  	}
    68  
    69  	var webhookSecret []byte
    70  	var githubClient *github.Client
    71  	var kubeClient *kube.Client
    72  	var slackClient *slack.Client
    73  	if *local {
    74  		logrus.Warning("Running in local mode for dev only.")
    75  
    76  		logrus.Print("HMAC Secret: abcde12345")
    77  		webhookSecret = []byte("abcde12345")
    78  
    79  		githubClient = github.NewFakeClient()
    80  		kubeClient = kube.NewFakeClient()
    81  	} else {
    82  		logrus.SetFormatter(&logrus.JSONFormatter{})
    83  
    84  		// Ignore SIGTERM so that we don't drop hooks when the pod is removed.
    85  		// We'll get SIGTERM first and then SIGKILL after our graceful termination
    86  		// deadline.
    87  		signal.Ignore(syscall.SIGTERM)
    88  
    89  		webhookSecretRaw, err := ioutil.ReadFile(*webhookSecretFile)
    90  		if err != nil {
    91  			logrus.WithError(err).Fatal("Could not read webhook secret file.")
    92  		}
    93  		webhookSecret = bytes.TrimSpace(webhookSecretRaw)
    94  
    95  		oauthSecretRaw, err := ioutil.ReadFile(*githubTokenFile)
    96  		if err != nil {
    97  			logrus.WithError(err).Fatal("Could not read oauth secret file.")
    98  		}
    99  		oauthSecret := string(bytes.TrimSpace(oauthSecretRaw))
   100  
   101  		var teamToken string
   102  		if *slackTokenFile != "" {
   103  			teamTokenRaw, err := ioutil.ReadFile(*slackTokenFile)
   104  			if err != nil {
   105  				logrus.WithError(err).Fatal("Could not read slack token file.")
   106  			}
   107  			teamToken = string(bytes.TrimSpace(teamTokenRaw))
   108  		}
   109  
   110  		_, err = url.Parse(*githubEndpoint)
   111  		if err != nil {
   112  			logrus.WithError(err).Fatal("Must specify a valid --github-endpoint URL.")
   113  		}
   114  
   115  		if *dryRun {
   116  			githubClient = github.NewDryRunClient(oauthSecret, *githubEndpoint)
   117  		} else {
   118  			githubClient = github.NewClient(oauthSecret, *githubEndpoint)
   119  		}
   120  
   121  		kubeClient, err = kube.NewClientInCluster(configAgent.Config().ProwJobNamespace)
   122  		if err != nil {
   123  			logrus.WithError(err).Fatal("Error getting kube client.")
   124  		}
   125  
   126  		if !*dryRun && teamToken != "" {
   127  			logrus.Info("Using real slack client.")
   128  			slackClient = slack.NewClient(teamToken)
   129  		}
   130  	}
   131  	if slackClient == nil {
   132  		logrus.Info("Using fake slack client.")
   133  		slackClient = slack.NewFakeClient()
   134  	}
   135  
   136  	gitClient, err := git.NewClient()
   137  	if err != nil {
   138  		logrus.WithError(err).Fatal("Error getting git client.")
   139  	}
   140  
   141  	logger := logrus.StandardLogger()
   142  	githubClient.Logger = logger.WithField("client", "github")
   143  	kubeClient.Logger = logger.WithField("client", "kube")
   144  	gitClient.Logger = logger.WithField("client", "git")
   145  	slackClient.Logger = logger.WithField("client", "slack")
   146  
   147  	pluginAgent := &plugins.PluginAgent{
   148  		PluginClient: plugins.PluginClient{
   149  			GitHubClient: githubClient,
   150  			KubeClient:   kubeClient,
   151  			GitClient:    gitClient,
   152  			SlackClient:  slackClient,
   153  			Logger:       logrus.NewEntry(logrus.StandardLogger()),
   154  		},
   155  	}
   156  	if err := pluginAgent.Start(*pluginConfig); err != nil {
   157  		logrus.WithError(err).Fatal("Error starting plugins.")
   158  	}
   159  
   160  	metrics, err := hook.NewMetrics()
   161  	if err != nil {
   162  		logrus.WithError(err).Fatal("Failed to initialize metrics.")
   163  	}
   164  
   165  	if configAgent.Config().PushGateway.Endpoint != "" {
   166  		go func() {
   167  			for {
   168  				time.Sleep(time.Minute)
   169  				if err := push.FromGatherer("hook", push.HostnameGroupingKey(), configAgent.Config().PushGateway.Endpoint, prometheus.DefaultGatherer); err != nil {
   170  					logrus.WithError(err).Error("Failed to push metrics.")
   171  				}
   172  			}
   173  		}()
   174  	}
   175  
   176  	server := &hook.Server{
   177  		HMACSecret:  webhookSecret,
   178  		ConfigAgent: configAgent,
   179  		Plugins:     pluginAgent,
   180  		Metrics:     metrics,
   181  	}
   182  
   183  	// Return 200 on / for health checks.
   184  	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {})
   185  	http.Handle("/metrics", promhttp.Handler())
   186  	// For /hook, handle a webhook normally.
   187  	http.Handle("/hook", server)
   188  	logrus.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
   189  }