github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/webhook/pkg/cli/cli.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package cli provides a CLI interface for a mutating Kubernetes webhook.
    16  package cli
    17  
    18  import (
    19  	"flag"
    20  	"fmt"
    21  	"net"
    22  	"net/http"
    23  	"os"
    24  	"strconv"
    25  	"strings"
    26  
    27  	"github.com/MerlinKodo/gvisor/pkg/log"
    28  	"github.com/MerlinKodo/gvisor/webhook/pkg/injector"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	k8snet "k8s.io/apimachinery/pkg/util/net"
    31  	"k8s.io/client-go/kubernetes"
    32  	"k8s.io/client-go/rest"
    33  )
    34  
    35  var (
    36  	address   = flag.String("address", "", "The ip address the admission webhook serves on. If unspecified, a public address is selected automatically.")
    37  	port      = flag.Int("port", 0, "The port the admission webhook serves on.")
    38  	podLabels = flag.String("pod-namespace-labels", "", "A comma-separated namespace label selector, the admission webhook will only take effect on pods in selected namespaces, e.g. `label1,label2`.")
    39  )
    40  
    41  // Main runs the webhook.
    42  func Main() {
    43  	flag.Parse()
    44  
    45  	if err := run(); err != nil {
    46  		log.Warningf("%v", err)
    47  		os.Exit(1)
    48  	}
    49  }
    50  
    51  func run() error {
    52  	log.Infof("Starting %s\n", injector.Name)
    53  
    54  	// Create client config.
    55  	cfg, err := rest.InClusterConfig()
    56  	if err != nil {
    57  		return fmt.Errorf("create in cluster config: %w", err)
    58  	}
    59  
    60  	// Create clientset.
    61  	clientset, err := kubernetes.NewForConfig(cfg)
    62  	if err != nil {
    63  		return fmt.Errorf("create kubernetes client: %w", err)
    64  	}
    65  
    66  	if err := injector.CreateConfiguration(clientset, parsePodLabels()); err != nil {
    67  		return fmt.Errorf("create webhook configuration: %w", err)
    68  	}
    69  
    70  	if err := startWebhookHTTPS(clientset); err != nil {
    71  		return fmt.Errorf("start webhook https server: %w", err)
    72  	}
    73  
    74  	return nil
    75  }
    76  
    77  func parsePodLabels() *metav1.LabelSelector {
    78  	rv := &metav1.LabelSelector{}
    79  	for _, s := range strings.Split(*podLabels, ",") {
    80  		req := metav1.LabelSelectorRequirement{
    81  			Key:      strings.TrimSpace(s),
    82  			Operator: "Exists",
    83  		}
    84  		rv.MatchExpressions = append(rv.MatchExpressions, req)
    85  	}
    86  	return rv
    87  }
    88  
    89  func startWebhookHTTPS(clientset kubernetes.Interface) error {
    90  	log.Infof("Starting HTTPS handler")
    91  	defer log.Infof("Stopping HTTPS handler")
    92  
    93  	if *address == "" {
    94  		ip, err := k8snet.ChooseHostInterface()
    95  		if err != nil {
    96  			return fmt.Errorf("select ip address: %w", err)
    97  		}
    98  		*address = ip.String()
    99  	}
   100  	mux := http.NewServeMux()
   101  	mux.Handle("/", http.HandlerFunc(
   102  		func(w http.ResponseWriter, r *http.Request) {
   103  			injector.Admit(w, r)
   104  		}))
   105  	server := &http.Server{
   106  		// Listen on all addresses.
   107  		Addr:      net.JoinHostPort(*address, strconv.Itoa(*port)),
   108  		TLSConfig: injector.GetTLSConfig(),
   109  		Handler:   mux,
   110  	}
   111  	if err := server.ListenAndServeTLS("", ""); err != http.ErrServerClosed {
   112  		return fmt.Errorf("start HTTPS handler: %w", err)
   113  	}
   114  	return nil
   115  }