Skip to content

Commit

Permalink
fix: remove duplicate line in known_hosts when minikube deletes
Browse files Browse the repository at this point in the history
  • Loading branch information
ComradeProgrammer committed Aug 30, 2024
1 parent 5e60432 commit 6184085
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 6 deletions.
54 changes: 54 additions & 0 deletions cmd/minikube/cmd/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/docker/machine/libmachine"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/client-go/util/homedir"
"k8s.io/klog/v2"
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
"k8s.io/minikube/pkg/drivers/kic"
Expand All @@ -53,6 +54,7 @@ import (
"k8s.io/minikube/pkg/minikube/reason"
"k8s.io/minikube/pkg/minikube/sshagent"
"k8s.io/minikube/pkg/minikube/style"
"k8s.io/minikube/pkg/util"
)

var (
Expand Down Expand Up @@ -232,7 +234,15 @@ func runDelete(_ *cobra.Command, args []string) {
delCtx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()

// use a background goroutine to run this delete
// so that this will not block for a long time
deleteKnownHostsChannel := make(chan struct{})
go func() {
deleteKnownHosts()
deleteKnownHostsChannel <- struct{}{}
}()
if deleteAll {

deleteContainersAndVolumes(delCtx, oci.Docker)
deleteContainersAndVolumes(delCtx, oci.Podman)

Expand All @@ -244,6 +254,7 @@ func runDelete(_ *cobra.Command, args []string) {
} else {
out.Step(style.DeletingHost, "Successfully deleted all profiles")
}

} else {
if len(args) > 0 {
exit.Message(reason.Usage, "usage: minikube delete")
Expand All @@ -270,6 +281,8 @@ func runDelete(_ *cobra.Command, args []string) {
delete.PossibleLeftOvers(delCtx, cname, driver.Podman)
}
}
// if deleteKnownHosts hasn't finished, then wait
<-deleteKnownHostsChannel

// If the purge flag is set, go ahead and delete the .minikube directory.
if purge {
Expand Down Expand Up @@ -725,3 +738,44 @@ func getPids(path string) ([]int, error) {

return pids, nil
}

// deleKnownHost read minikube nodes' keys from the minikube home folder
// and remove them from the known_hosts file
// This is the long term solution for issue https://github.com/kubernetes/minikube/issues/16868
func deleteKnownHosts() {
// remove this line from known_hosts file if it exists
knownHosts := filepath.Join(homedir.HomeDir(), ".ssh", "known_hosts")
machinesDir := filepath.Join(localpath.MiniPath(), "machines")
fileInfo, err := os.ReadDir(machinesDir)
if err != nil {
klog.Warningf("error reading machines in minikube home: %v", err)
return
}
if _, err := os.Stat(knownHosts); err != nil {
klog.Warningf("no host files found when cleaning host files: %v", err)
return
}
for _, file := range fileInfo {
if file.IsDir() {
nodeName := file.Name()

knowHostPath := filepath.Join(localpath.MiniPath(), "machines", nodeName, "known_host")
if _, err := os.Stat(knowHostPath); err == nil {
// if this file exists, remove this line from known_hosts
key, err := os.ReadFile(knowHostPath)
if err != nil {
klog.Warningf("error reading keys from %s: %v", knowHostPath, err)
continue
}
if err := util.RemoveLineFromFile(string(key), knownHosts); err != nil {
klog.Warningf("failed to remove key: %v", err)
}
// and, remove the file which stores this key
if err := os.Remove(knowHostPath); err != nil {
klog.Warningf("failed to remove key: %v", err)
}
}
}
}

}
6 changes: 4 additions & 2 deletions cmd/minikube/cmd/docker-env.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ docker-cli install instructions: https://minikube.sigs.k8s.io/docs/tutorials/doc
dockerPath = ""
}

if dockerPath != "" {
if dockerPath != "" && co.Config.KubernetesConfig.ContainerRuntime == constants.Docker {
out, err := tryDockerConnectivity("docker", ec)
if err != nil { // docker might be up but been loaded with wrong certs/config
// to fix issues like this #8185
Expand Down Expand Up @@ -427,7 +427,9 @@ docker-cli install instructions: https://minikube.sigs.k8s.io/docs/tutorials/doc
// TODO: refactor to work with docker, temp fix to resolve regression
if cr == constants.Containerd {
// eventually, run something similar to ssh --append-known
appendKnownHelper(nodeName, true)
if err := appendKnownHelper(nodeName, appendKnown); err != nil {
exit.Error(reason.AppendKnownError, "failed to apppen keys to known_hosts", err)
}
}
}
},
Expand Down
19 changes: 15 additions & 4 deletions cmd/minikube/cmd/ssh-host.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/mustload"
"k8s.io/minikube/pkg/minikube/node"
Expand All @@ -45,11 +46,13 @@ var sshHostCmd = &cobra.Command{
Short: "Retrieve the ssh host key of the specified node",
Long: "Retrieve the ssh host key of the specified node.",
Run: func(_ *cobra.Command, _ []string) {
appendKnownHelper(nodeName, appendKnown)
if err := appendKnownHelper(nodeName, appendKnown); err != nil {
exit.Error(reason.AppendKnownError, "failed to apppen keys to known_hosts", err)
}
},
}

func appendKnownHelper(nodeName string, appendKnown bool) {
func appendKnownHelper(nodeName string, appendKnown bool) error {
cname := ClusterFlagValue()
co := mustload.Running(cname)
if co.CP.Host.DriverName == driver.None {
Expand Down Expand Up @@ -99,7 +102,7 @@ func appendKnownHelper(nodeName string, appendKnown bool) {
knownHosts := filepath.Join(sshDir, "known_hosts")

if sshutil.KnownHost(host, knownHosts) {
return
return nil
}

f, err := os.OpenFile(knownHosts, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
Expand All @@ -122,8 +125,16 @@ func appendKnownHelper(nodeName string, appendKnown bool) {

fmt.Fprintf(os.Stderr, "Host added: %s (%s)\n", knownHosts, host)

return
// then store it into minikube home folder
// so that when we execute `minikube delete`
// these keys can be removed properly
_, cc := mustload.Partial(ClusterFlagValue())
knownHostPath := filepath.Join(localpath.MiniPath(), "machines", config.MachineName(*cc, *n), "known_host")
if err := os.WriteFile(knownHostPath, []byte(keys), 0666); err != nil {
return fmt.Errorf("WriteString to %s: %v", knownHostPath, err)
}
}
return nil
}

func init() {
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/reason/reason.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ var (
InternalSemverParse = Kind{ID: "MK_SEMVER_PARSE", ExitCode: ExProgramError}
// minikube was unable to daemonize the minikube process
DaemonizeError = Kind{ID: "MK_DAEMONIZE", ExitCode: ExProgramError}
// minikube was unable to add keys to known_hosts
AppendKnownError = Kind{ID: "MK_APPENDKNOWN", ExitCode: ExProgramError}

// insufficient cores available for use by minikube and kubernetes
RsrcInsufficientCores = Kind{ID: "RSRC_INSUFFICIENT_CORES", ExitCode: ExInsufficientCores, Style: style.UnmetRequirement}
Expand Down
37 changes: 37 additions & 0 deletions pkg/util/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package util

import (
"bufio"
"fmt"
"os"
"os/user"
Expand Down Expand Up @@ -163,3 +164,39 @@ func MaskProxyPasswordWithKey(v string) string {
}
return v
}

// remove the specified line from the given file
func RemoveLineFromFile(knownHostLine string, filePath string) error {
fd, err := os.OpenFile(filePath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
return fmt.Errorf("failed to open %s: %v", filePath, err)
}
defer fd.Close()

// read each line from known_hosts and find theline we want to delete
scanner := bufio.NewScanner(fd)
newLines := make([]string, 0)
for scanner.Scan() {
line := string(scanner.Bytes())
if strings.TrimSpace(line) != strings.TrimSpace(knownHostLine) {
// remove the line which is identical with the key
newLines = append(newLines, line)
}
}
// remove the contents and move to the head of this file
if err := fd.Truncate(0); err != nil {
return fmt.Errorf("failed to write to %s: %v", filePath, err)
}
if _, err := fd.Seek(0, 0); err != nil {
return fmt.Errorf("failed to write to %s: %v", filePath, err)
}

// write the new content into the file

for _, line := range newLines {
if _, err := fmt.Fprintln(fd, line); err != nil {
return fmt.Errorf("failed to write to %s: %v", filePath, err)
}
}
return nil
}

0 comments on commit 6184085

Please sign in to comment.