...

Source file src/k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun/dryrun.go

Documentation: k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun

     1  /*
     2  Copyright 2017 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 dryrun
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"os"
    23  	"path/filepath"
    24  	"time"
    25  
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	errorsutil "k8s.io/apimachinery/pkg/util/errors"
    28  
    29  	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
    30  	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
    31  	"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
    32  )
    33  
    34  // FileToPrint represents a temporary file on disk that might want to be aliased when printing
    35  // Useful for things like loading a file from /tmp/ but saying to the user "Would write file foo to /etc/kubernetes/..."
    36  type FileToPrint struct {
    37  	RealPath  string
    38  	PrintPath string
    39  }
    40  
    41  // NewFileToPrint makes a new instance of FileToPrint with the specified arguments
    42  func NewFileToPrint(realPath, printPath string) FileToPrint {
    43  	return FileToPrint{
    44  		RealPath:  realPath,
    45  		PrintPath: printPath,
    46  	}
    47  }
    48  
    49  // PrintDryRunFile is a helper method around PrintDryRunFiles
    50  func PrintDryRunFile(fileName, realDir, printDir string, w io.Writer) error {
    51  	return PrintDryRunFiles([]FileToPrint{
    52  		NewFileToPrint(filepath.Join(realDir, fileName), filepath.Join(printDir, fileName)),
    53  	}, w)
    54  }
    55  
    56  // PrintDryRunFiles prints the contents of the FileToPrints given to it to the writer w
    57  func PrintDryRunFiles(files []FileToPrint, w io.Writer) error {
    58  	errs := []error{}
    59  	for _, file := range files {
    60  		if len(file.RealPath) == 0 {
    61  			continue
    62  		}
    63  
    64  		fileBytes, err := os.ReadFile(file.RealPath)
    65  		if err != nil {
    66  			errs = append(errs, err)
    67  			continue
    68  		}
    69  
    70  		// Make it possible to fake the path of the file; i.e. you may want to tell the user
    71  		// "Here is what would be written to /etc/kubernetes/admin.conf", although you wrote it to /tmp/kubeadm-dryrun/admin.conf and are loading it from there
    72  		// Fall back to the "real" path if PrintPath is not set
    73  		outputFilePath := file.PrintPath
    74  		if len(outputFilePath) == 0 {
    75  			outputFilePath = file.RealPath
    76  		}
    77  
    78  		fmt.Fprintf(w, "[dryrun] Would write file %q with content:\n", outputFilePath)
    79  		apiclient.PrintBytesWithLinePrefix(w, fileBytes, "\t")
    80  	}
    81  	return errorsutil.NewAggregate(errs)
    82  }
    83  
    84  // Waiter is an implementation of apiclient.Waiter that should be used for dry-running
    85  type Waiter struct{}
    86  
    87  // NewWaiter returns a new Waiter object that talks to the given Kubernetes cluster
    88  func NewWaiter() apiclient.Waiter {
    89  	return &Waiter{}
    90  }
    91  
    92  // WaitForControlPlaneComponents just returns a dummy nil, to indicate that the program should just proceed
    93  func (w *Waiter) WaitForControlPlaneComponents(cfg *kubeadmapi.ClusterConfiguration) error {
    94  	return nil
    95  }
    96  
    97  // WaitForAPI just returns a dummy nil, to indicate that the program should just proceed
    98  func (w *Waiter) WaitForAPI() error {
    99  	fmt.Println("[dryrun] Would wait for the API Server's /healthz endpoint to return 'ok'")
   100  	return nil
   101  }
   102  
   103  // WaitForPodsWithLabel just returns a dummy nil, to indicate that the program should just proceed
   104  func (w *Waiter) WaitForPodsWithLabel(kvLabel string) error {
   105  	fmt.Printf("[dryrun] Would wait for the Pods with the label %q in the %s namespace to become Running\n", kvLabel, metav1.NamespaceSystem)
   106  	return nil
   107  }
   108  
   109  // WaitForPodToDisappear just returns a dummy nil, to indicate that the program should just proceed
   110  func (w *Waiter) WaitForPodToDisappear(podName string) error {
   111  	fmt.Printf("[dryrun] Would wait for the %q Pod in the %s namespace to be deleted\n", podName, metav1.NamespaceSystem)
   112  	return nil
   113  }
   114  
   115  // WaitForKubelet blocks until the kubelet /healthz endpoint returns 'ok'
   116  func (w *Waiter) WaitForKubelet() error {
   117  	fmt.Println("[dryrun] Would make sure the kubelet's /healthz endpoint is healthy")
   118  	return nil
   119  }
   120  
   121  // SetTimeout is a no-op; we don't wait in this implementation
   122  func (w *Waiter) SetTimeout(_ time.Duration) {}
   123  
   124  // WaitForStaticPodControlPlaneHashes returns an empty hash for all control plane images;
   125  func (w *Waiter) WaitForStaticPodControlPlaneHashes(_ string) (map[string]string, error) {
   126  	return map[string]string{
   127  		kubeadmconstants.KubeAPIServer:         "",
   128  		kubeadmconstants.KubeControllerManager: "",
   129  		kubeadmconstants.KubeScheduler:         "",
   130  	}, nil
   131  }
   132  
   133  // WaitForStaticPodSingleHash returns an empty hash
   134  // but the empty strings there are needed
   135  func (w *Waiter) WaitForStaticPodSingleHash(_ string, _ string) (string, error) {
   136  	return "", nil
   137  }
   138  
   139  // WaitForStaticPodHashChange returns a dummy nil error in order for the flow to just continue as we're dryrunning
   140  func (w *Waiter) WaitForStaticPodHashChange(_, _, _ string) error {
   141  	return nil
   142  }
   143  
   144  // PrintFilesIfDryRunning prints the static pod manifests to stdout and informs about the temporary directory to go and lookup when dry running
   145  func PrintFilesIfDryRunning(needPrintManifest bool, manifestDir string, outputWriter io.Writer) error {
   146  	var files []FileToPrint
   147  	// Print static pod manifests if it is a control plane
   148  	if needPrintManifest {
   149  		fmt.Printf("[dryrun] Wrote certificates, kubeconfig files and control plane manifests to the %q directory\n", manifestDir)
   150  		for _, component := range kubeadmconstants.ControlPlaneComponents {
   151  			realPath := kubeadmconstants.GetStaticPodFilepath(component, manifestDir)
   152  			outputPath := kubeadmconstants.GetStaticPodFilepath(component, kubeadmconstants.GetStaticPodDirectory())
   153  			files = append(files, NewFileToPrint(realPath, outputPath))
   154  		}
   155  	} else {
   156  		fmt.Printf("[dryrun] Wrote certificates and kubeconfig files to the %q directory\n", manifestDir)
   157  	}
   158  
   159  	fmt.Println("[dryrun] The certificates or kubeconfig files would not be printed due to their sensitive nature")
   160  	fmt.Printf("[dryrun] Please examine the %q directory for details about what would be written\n", manifestDir)
   161  
   162  	// Print kubelet config manifests
   163  	kubeletConfigFiles := []string{kubeadmconstants.KubeletConfigurationFileName, kubeadmconstants.KubeletEnvFileName}
   164  	for _, filename := range kubeletConfigFiles {
   165  		realPath := filepath.Join(manifestDir, filename)
   166  		outputPath := filepath.Join(kubeadmconstants.KubeletRunDirectory, filename)
   167  		files = append(files, NewFileToPrint(realPath, outputPath))
   168  	}
   169  
   170  	return PrintDryRunFiles(files, outputWriter)
   171  }
   172  

View as plain text