...

Source file src/k8s.io/cli-runtime/pkg/genericclioptions/command_headers.go

Documentation: k8s.io/cli-runtime/pkg/genericclioptions

     1  /*
     2  Copyright 2021 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 genericclioptions
    18  
    19  import (
    20  	"net/http"
    21  	"strings"
    22  
    23  	"github.com/google/uuid"
    24  	"github.com/spf13/cobra"
    25  )
    26  
    27  const (
    28  	kubectlCommandHeader = "Kubectl-Command"
    29  	kubectlSessionHeader = "Kubectl-Session"
    30  )
    31  
    32  // CommandHeaderRoundTripper adds a layer around the standard
    33  // round tripper to add Request headers before delegation. Implements
    34  // the go standard library "http.RoundTripper" interface.
    35  type CommandHeaderRoundTripper struct {
    36  	Delegate http.RoundTripper
    37  	Headers  map[string]string
    38  }
    39  
    40  // CommandHeaderRoundTripper adds Request headers before delegating to standard
    41  // round tripper. These headers are kubectl command headers which
    42  // detail the kubectl command. See SIG CLI KEP 859:
    43  //
    44  //	https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/859-kubectl-headers
    45  func (c *CommandHeaderRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
    46  	for header, value := range c.Headers {
    47  		req.Header.Set(header, value)
    48  	}
    49  	return c.Delegate.RoundTrip(req)
    50  }
    51  
    52  // ParseCommandHeaders fills in a map of custom headers into the CommandHeaderRoundTripper. These
    53  // headers are then filled into each request. For details on the custom headers see:
    54  //
    55  //	https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/859-kubectl-headers
    56  //
    57  // Each call overwrites the previously parsed command headers (not additive).
    58  // TODO(seans3): Parse/add flags removing PII from flag values.
    59  func (c *CommandHeaderRoundTripper) ParseCommandHeaders(cmd *cobra.Command, args []string) {
    60  	if cmd == nil {
    61  		return
    62  	}
    63  	// Overwrites previously parsed command headers (headers not additive).
    64  	c.Headers = map[string]string{}
    65  	// Session identifier to aggregate multiple Requests from single kubectl command.
    66  	uid := uuid.New().String()
    67  	c.Headers[kubectlSessionHeader] = uid
    68  	// Iterate up the hierarchy of commands from the leaf command to create
    69  	// the full command string. Example: kubectl create secret generic
    70  	cmdStrs := []string{}
    71  	for cmd.HasParent() {
    72  		parent := cmd.Parent()
    73  		currName := strings.TrimSpace(cmd.Name())
    74  		cmdStrs = append([]string{currName}, cmdStrs...)
    75  		cmd = parent
    76  	}
    77  	currName := strings.TrimSpace(cmd.Name())
    78  	cmdStrs = append([]string{currName}, cmdStrs...)
    79  	if len(cmdStrs) > 0 {
    80  		c.Headers[kubectlCommandHeader] = strings.Join(cmdStrs, " ")
    81  	}
    82  }
    83  
    84  // CancelRequest is propagated to the Delegate RoundTripper within
    85  // if the wrapped RoundTripper implements this function.
    86  func (c *CommandHeaderRoundTripper) CancelRequest(req *http.Request) {
    87  	type canceler interface {
    88  		CancelRequest(*http.Request)
    89  	}
    90  	// If possible, call "CancelRequest" on the wrapped Delegate RoundTripper.
    91  	if cr, ok := c.Delegate.(canceler); ok {
    92  		cr.CancelRequest(req)
    93  	}
    94  }
    95  

View as plain text