Merge pull request #11304 from daehyeok/copy_node

Implement target node option for cp command
pull/11421/head
ilya-zuyev 2021-05-14 15:59:11 -07:00 committed by GitHub
commit 2a2ffeb380
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 109 additions and 24 deletions

View File

@ -25,8 +25,11 @@ import (
"strings"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/command"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/mustload"
"k8s.io/minikube/pkg/minikube/node"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/reason"
)
@ -35,14 +38,16 @@ import (
var (
srcPath string
dstPath string
dstNode string
)
// cpCmd represents the cp command, similar to docker cp
var cpCmd = &cobra.Command{
Use: "cp <source file path> <target file absolute path>",
Use: "cp <source file path> <target node name>:<target file absolute path>",
Short: "Copy the specified file into minikube",
Long: "Copy the specified file into minikube, it will be saved at path <target file absolute path> in your minikube.\n" +
"Example Command : \"minikube cp a.txt /home/docker/b.txt\"\n",
"Example Command : \"minikube cp a.txt /home/docker/b.txt\"\n" +
" \"minikube cp a.txt minikube-m02:/home/docker/b.txt\"\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
exit.Message(reason.Usage, `Please specify the path to copy:
@ -51,16 +56,47 @@ var cpCmd = &cobra.Command{
srcPath = args[0]
dstPath = args[1]
// if destination path is not a absolute path, trying to parse with <node>:<abs path> format
if !strings.HasPrefix(dstPath, "/") {
if sp := strings.SplitN(dstPath, ":", 2); len(sp) == 2 {
dstNode = sp[0]
dstPath = sp[1]
}
}
validateArgs(srcPath, dstPath)
co := mustload.Running(ClusterFlagValue())
fa, err := assets.NewFileAsset(srcPath, pt.Dir(dstPath), pt.Base(dstPath), "0644")
if err != nil {
out.ErrLn("%v", errors.Wrap(err, "getting file asset"))
os.Exit(1)
}
if err = co.CP.Runner.Copy(fa); err != nil {
co := mustload.Running(ClusterFlagValue())
var runner command.Runner
if dstNode == "" {
runner = co.CP.Runner
} else {
n, _, err := node.Retrieve(*co.Config, dstNode)
if err != nil {
exit.Message(reason.GuestNodeRetrieve, "Node {{.nodeName}} does not exist.", out.V{"nodeName": dstNode})
}
h, err := machine.GetHost(co.API, *co.Config, *n)
if err != nil {
out.ErrLn("%v", errors.Wrap(err, "getting host"))
os.Exit(1)
}
runner, err = machine.CommandRunner(h)
if err != nil {
out.ErrLn("%v", errors.Wrap(err, "getting command runner"))
os.Exit(1)
}
}
if err = runner.Copy(fa); err != nil {
out.ErrLn("%v", errors.Wrap(err, "copying file"))
os.Exit(1)
}

View File

@ -28,7 +28,8 @@ import (
"k8s.io/minikube/pkg/minikube/config"
)
func getHost(api libmachine.API, cc config.ClusterConfig, n config.Node) (*host.Host, error) {
// GetHost find node's host information by name in the given cluster.
func GetHost(api libmachine.API, cc config.ClusterConfig, n config.Node) (*host.Host, error) {
machineName := config.MachineName(cc, n)
host, err := LoadHost(api, machineName)
if err != nil {
@ -49,7 +50,7 @@ func getHost(api libmachine.API, cc config.ClusterConfig, n config.Node) (*host.
// CreateSSHShell creates a new SSH shell / client
func CreateSSHShell(api libmachine.API, cc config.ClusterConfig, n config.Node, args []string, native bool) error {
host, err := getHost(api, cc, n)
host, err := GetHost(api, cc, n)
if err != nil {
return err
}
@ -70,7 +71,7 @@ func CreateSSHShell(api libmachine.API, cc config.ClusterConfig, n config.Node,
// GetSSHHostAddrPort returns the host address and port for ssh
func GetSSHHostAddrPort(api libmachine.API, cc config.ClusterConfig, n config.Node) (string, int, error) {
host, err := getHost(api, cc, n)
host, err := GetHost(api, cc, n)
if err != nil {
return "", 0, err
}

View File

@ -13,10 +13,11 @@ Copy the specified file into minikube
Copy the specified file into minikube, it will be saved at path <target file absolute path> in your minikube.
Example Command : "minikube cp a.txt /home/docker/b.txt"
"minikube cp a.txt minikube-m02:/home/docker/b.txt"
```shell
minikube cp <source file path> <target file absolute path> [flags]
minikube cp <source file path> <target node name>:<target file absolute path> [flags]
```
### Options inherited from parent commands

View File

@ -241,6 +241,9 @@ uses the minikube node add command to add a node to an existing cluster
#### validateProfileListWithMultiNode
make sure minikube profile list outputs correct with multinode clusters
#### validateCopyFileWithMultiNode
validateProfileListWithMultiNode make sure minikube profile list outputs correct with multinode clusters
#### validateStopRunningNode
tests the minikube node stop command

View File

@ -1452,16 +1452,18 @@ func cpTestLocalPath() string {
return filepath.Join(*testdataDir, "cp-test.txt")
}
// validateCpCmd asserts basic "cp" command functionality
func validateCpCmd(ctx context.Context, t *testing.T, profile string) {
if NoneDriver() {
t.Skipf("skipping: cp is unsupported by none driver")
}
func testCpCmd(ctx context.Context, t *testing.T, profile string, node string) {
srcPath := cpTestLocalPath()
dstPath := cpTestMinikubePath()
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "cp", srcPath, dstPath))
cpArgv := []string{"-p", profile, "cp", srcPath}
if node == "" {
cpArgv = append(cpArgv, dstPath)
} else {
cpArgv = append(cpArgv, fmt.Sprintf("%s:%s", node, dstPath))
}
rr, err := Run(t, exec.CommandContext(ctx, Target(), cpArgv...))
if ctx.Err() == context.DeadlineExceeded {
t.Errorf("failed to run command by deadline. exceeded timeout : %s", rr.Command())
}
@ -1469,7 +1471,13 @@ func validateCpCmd(ctx context.Context, t *testing.T, profile string) {
t.Errorf("failed to run an cp command. args %q : %v", rr.Command(), err)
}
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ssh", fmt.Sprintf("sudo cat %s", dstPath)))
sshArgv := []string{"-p", profile, "ssh"}
if node != "" {
sshArgv = append(sshArgv, "-n", node)
}
sshArgv = append(sshArgv, fmt.Sprintf("sudo cat %s", dstPath))
rr, err = Run(t, exec.CommandContext(ctx, Target(), sshArgv...))
if ctx.Err() == context.DeadlineExceeded {
t.Errorf("failed to run command by deadline. exceeded timeout : %s", rr.Command())
}
@ -1487,6 +1495,15 @@ func validateCpCmd(ctx context.Context, t *testing.T, profile string) {
}
}
// validateCpCmd asserts basic "cp" command functionality
func validateCpCmd(ctx context.Context, t *testing.T, profile string) {
if NoneDriver() {
t.Skipf("skipping: cp is unsupported by none driver")
}
testCpCmd(ctx, t, profile, "")
}
// validateMySQL validates a minimalist MySQL deployment
func validateMySQL(ctx context.Context, t *testing.T, profile string) {
if arm64Platform() {

View File

@ -26,6 +26,7 @@ import (
"strings"
"testing"
"k8s.io/minikube/cmd/minikube/cmd"
"k8s.io/minikube/pkg/minikube/config"
)
@ -49,6 +50,7 @@ func TestMultiNode(t *testing.T) {
{"DeployApp2Nodes", validateDeployAppToMultiNode},
{"AddNode", validateAddNodeToMultiNode},
{"ProfileList", validateProfileListWithMultiNode},
{"CopyFile", validateCopyFileWithMultiNode},
{"StopNode", validateStopRunningNode},
{"StartAfterStop", validateStartNodeAfterStop},
{"DeleteNode", validateDeleteNodeFromMultiNode},
@ -157,6 +159,31 @@ func validateProfileListWithMultiNode(ctx context.Context, t *testing.T, profile
}
// validateProfileListWithMultiNode make sure minikube profile list outputs correct with multinode clusters
func validateCopyFileWithMultiNode(ctx context.Context, t *testing.T, profile string) {
if NoneDriver() {
t.Skipf("skipping: cp is unsupported by none driver")
}
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "status", "--output", "json", "--alsologtostderr"))
if err != nil && rr.ExitCode != 7 {
t.Fatalf("failed to run minikube status. args %q : %v", rr.Command(), err)
}
var statuses []cmd.Status
if err = json.Unmarshal(rr.Stdout.Bytes(), &statuses); err != nil {
t.Errorf("failed to decode json from status: args %q: %v", rr.Command(), err)
}
for _, s := range statuses {
if s.Worker {
testCpCmd(ctx, t, profile, s.Name)
} else {
testCpCmd(ctx, t, profile, "")
}
}
}
// validateStopRunningNode tests the minikube node stop command
func validateStopRunningNode(ctx context.Context, t *testing.T, profile string) {
// Run minikube node stop on that node

View File

@ -99,7 +99,7 @@
"Consider increasing Docker Desktop's memory size.": "",
"Continuously listing/getting the status with optional interval duration.": "",
"Copy the specified file into minikube": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n \\\"minikube cp a.txt minikube-m02:/home/docker/b.txt\\\"\\n": "",
"Could not determine a Google Cloud project, which might be ok.": "",
"Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.": "",
"Could not process error from failed deletion": "",

View File

@ -100,7 +100,7 @@
"Consider increasing Docker Desktop's memory size.": "Considera incrementar la memoria asignada a Docker Desktop",
"Continuously listing/getting the status with optional interval duration.": "",
"Copy the specified file into minikube": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n \\\"minikube cp a.txt minikube-m02:/home/docker/b.txt\\\"\\n": "",
"Could not determine a Google Cloud project, which might be ok.": "No se pudo determinar un proyecto de Google Cloud que podría estar bien.",
"Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.": "No se puedo encontrar ninguna credencial de GCP. Corre `gcloud auth application-default login` o establezca la variable de entorno GOOGLE_APPLICATION_CREDENTIALS en la ruta de su archivo de credentiales.",
"Could not process error from failed deletion": "No se pudo procesar el error de la eliminación fallida",

View File

@ -101,7 +101,7 @@
"Consider increasing Docker Desktop's memory size.": "",
"Continuously listing/getting the status with optional interval duration.": "",
"Copy the specified file into minikube": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n \\\"minikube cp a.txt minikube-m02:/home/docker/b.txt\\\"\\n": "",
"Could not determine a Google Cloud project, which might be ok.": "",
"Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.": "",
"Could not process error from failed deletion": "",

View File

@ -98,7 +98,7 @@
"Consider increasing Docker Desktop's memory size.": "",
"Continuously listing/getting the status with optional interval duration.": "",
"Copy the specified file into minikube": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n \\\"minikube cp a.txt minikube-m02:/home/docker/b.txt\\\"\\n": "",
"Could not determine a Google Cloud project, which might be ok.": "",
"Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.": "",
"Could not process error from failed deletion": "",

View File

@ -107,7 +107,7 @@
"Consider increasing Docker Desktop's memory size.": "",
"Continuously listing/getting the status with optional interval duration.": "",
"Copy the specified file into minikube": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n \\\"minikube cp a.txt minikube-m02:/home/docker/b.txt\\\"\\n": "",
"Could not determine a Google Cloud project, which might be ok.": "",
"Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.": "",
"Could not process error from failed deletion": "",

View File

@ -105,7 +105,7 @@
"Consider increasing Docker Desktop's memory size.": "",
"Continuously listing/getting the status with optional interval duration.": "",
"Copy the specified file into minikube": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n \\\"minikube cp a.txt minikube-m02:/home/docker/b.txt\\\"\\n": "",
"Could not determine a Google Cloud project, which might be ok.": "",
"Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.": "",
"Could not process error from failed deletion": "",

View File

@ -95,7 +95,7 @@
"Consider increasing Docker Desktop's memory size.": "",
"Continuously listing/getting the status with optional interval duration.": "",
"Copy the specified file into minikube": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n \\\"minikube cp a.txt minikube-m02:/home/docker/b.txt\\\"\\n": "",
"Could not determine a Google Cloud project, which might be ok.": "",
"Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.": "",
"Could not process error from failed deletion": "",

View File

@ -122,7 +122,7 @@
"Consider increasing Docker Desktop's memory size.": "",
"Continuously listing/getting the status with optional interval duration.": "",
"Copy the specified file into minikube": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n": "",
"Copy the specified file into minikube, it will be saved at path \u003ctarget file absolute path\u003e in your minikube.\\nExample Command : \\\"minikube cp a.txt /home/docker/b.txt\\\"\\n \\\"minikube cp a.txt minikube-m02:/home/docker/b.txt\\\"\\n": "",
"Could not determine a Google Cloud project, which might be ok.": "",
"Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.": "",
"Could not get profile flag": "无法获取配置文件标志",