k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kubeadm/app/util/dryrun/dryrun.go (about) 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 }