Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

Add new command: ignite cp #495

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions cmd/ignite/cmd/cp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cmd

import (
"io"

"github.com/spf13/cobra"
"github.com/weaveworks/ignite/cmd/ignite/cmd/vmcmd"
)

// NewCmdCP is an alias for vmcmd.NewCmdCP
func NewCmdCP(out io.Writer) *cobra.Command {
return vmcmd.NewCmdCP(out)
}
1 change: 1 addition & 0 deletions cmd/ignite/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func NewIgniteCommand(in io.Reader, out, err io.Writer) *cobra.Command {

root.AddCommand(NewCmdAttach(os.Stdout))
root.AddCommand(NewCmdCompletion(os.Stdout, root))
root.AddCommand(NewCmdCP(os.Stdout))
root.AddCommand(NewCmdCreate(os.Stdout))
root.AddCommand(NewCmdKill(os.Stdout))
root.AddCommand(NewCmdLogs(os.Stdout))
Expand Down
49 changes: 49 additions & 0 deletions cmd/ignite/cmd/vmcmd/cp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package vmcmd

import (
"io"

"github.com/lithammer/dedent"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/weaveworks/ignite/cmd/ignite/cmd/cmdutil"
"github.com/weaveworks/ignite/cmd/ignite/run"
)

// NewCmdCP CP's a file into a running vm
func NewCmdCP(out io.Writer) *cobra.Command {
cf := &run.CPFlags{}

cmd := &cobra.Command{
Use: "cp <vm> <source> <dest>",
Short: "Copy a file into a running vm",
Long: dedent.Dedent(`
Copy a file from host into running VM.
Uses SCP to SSH into the running VM using the private key created for it during generation.
If no private key was created or wanting to use a different identity file,
use the identity file flag (-i, --identity) to override the used identity file.
The given VM is matched by prefix based on its ID and name.
Use (-r, --recursive) to recursively copy a directory.
`),
Args: cobra.ExactArgs(3),
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(func() error {
co, err := cf.NewCPOptions(args[0], args[1], args[2])
if err != nil {
return err
}

return run.CP(co)
}())
},
}

addCPFlags(cmd.Flags(), cf)
return cmd
}

func addCPFlags(fs *pflag.FlagSet, cf *run.CPFlags) {
fs.StringVarP(&cf.IdentityFile, "identity", "i", "", "Override the vm's default identity file")
fs.Uint32VarP(&cf.Timeout, "timeout", "t", 10, "Timeout waiting for connection in seconds")
fs.BoolVarP(&cf.Recursive, "recursive", "r", false, "Recursively copy entire directories.")
}
96 changes: 96 additions & 0 deletions cmd/ignite/run/cp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package run

import (
"fmt"
"path"

log "github.com/sirupsen/logrus"
api "github.com/weaveworks/ignite/pkg/apis/ignite"
"github.com/weaveworks/ignite/pkg/constants"
"github.com/weaveworks/ignite/pkg/util"
)

type CPFlags struct {
Timeout uint32
IdentityFile string
Recursive bool
}

type cpOptions struct {
*CPFlags
vm *api.VM
source string
dest string
}

func (cf *CPFlags) NewCPOptions(vmMatch string, source string, dest string) (co *cpOptions, err error) {
co = &cpOptions{CPFlags: cf}
co.vm, err = getVMForMatch(vmMatch)
co.source = source
co.dest = dest
return
}

func CP(co *cpOptions) error {
// Check if the VM is running
if !co.vm.Running() {
return fmt.Errorf("VM %q is not running", co.vm.GetUID())
}

ipAddrs := co.vm.Status.IPAddresses
if len(ipAddrs) == 0 {
return fmt.Errorf("VM %q has no usable IP addresses", co.vm.GetUID())
}

// From run/ssh.go:
// We're dealing with local VMs in a trusted (internal) subnet, disable some warnings for convenience
// TODO: For security, track the known_hosts internally, do something about the IP collisions (if needed)
scpOpts := []string{
"LogLevel=ERROR", // Warning: Permanently added '<ip>' (ECDSA) to the list of known hosts.
// We get this if the VM happens to get an address that another container has used:
"UserKnownHostsFile=/dev/null", // WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
"StrictHostKeyChecking=no", // The authenticity of host ***** can't be established
fmt.Sprintf("ConnectTimeout=%d", co.Timeout),
}

scpArgs := make([]string, 0, len(scpOpts)*2+3)

for _, opt := range scpOpts {
scpArgs = append(scpArgs, "-o", opt)
}

scpArgs = append(scpArgs, "-i")

// If an external identity file is specified, use it instead of the internal one
if len(co.IdentityFile) > 0 {
scpArgs = append(scpArgs, co.IdentityFile)
} else {
privKeyFile := path.Join(co.vm.ObjectPath(), fmt.Sprintf(constants.VM_SSH_KEY_TEMPLATE, co.vm.GetUID()))
if !util.FileExists(privKeyFile) {
return fmt.Errorf("no private key found for VM %q", co.vm.GetUID())
}

scpArgs = append(scpArgs, privKeyFile)
}

if co.Recursive {
scpArgs = append(scpArgs, "-r")
}

// Add source, dest args
scpArgs = append(scpArgs, co.source)
scpArgs = append(scpArgs, fmt.Sprintf("root@%s:%s", ipAddrs[0], co.dest))

// SSH into the VM
if code, err := util.ExecForeground("scp", scpArgs...); err != nil {
if code != 2 {
return fmt.Errorf("SCP into VM %q failed: %v", co.vm.GetUID(), err)
}

// Code 255 is used for signaling a connection error, be it caused by
// a failed connection attempt or disconnection by VM reboot.
log.Warnf("SCP command terminated")
}

return nil
}
1 change: 1 addition & 0 deletions docs/cli/ignite/ignite.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Example usage:

* [ignite attach](ignite_attach.md) - Attach to a running VM
* [ignite completion](ignite_completion.md) - Output bash completion for ignite to stdout
* [ignite cp](ignite_cp.md) - Copy a file into a running vm
* [ignite create](ignite_create.md) - Create a new VM without starting it
* [ignite exec](ignite_exec.md) - execute a command in a running VM
* [ignite image](ignite_image.md) - Manage base images for VMs
Expand Down
41 changes: 41 additions & 0 deletions docs/cli/ignite/ignite_cp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## ignite cp

Copy a file into a running vm

### Synopsis


Copy a file from host into running VM.
Uses SCP to SSH into the running VM using the private key created for it during generation.
If no private key was created or wanting to use a different identity file,
use the identity file flag (-i, --identity) to override the used identity file.
The given VM is matched by prefix based on its ID and name.
Use (-r, --recursive) to recursively copy a directory.


```
ignite cp <vm> <source> <dest> [flags]
```

### Options

```
-h, --help help for cp
-i, --identity string Override the vm's default identity file
-r, --recursive Recursively copy entire directories.
-t, --timeout uint32 Timeout waiting for connection in seconds (default 10)
```

### Options inherited from parent commands

```
--log-level loglevel Specify the loglevel for the program (default info)
--network-plugin plugin Network plugin to use. Available options are: [cni docker-bridge] (default cni)
-q, --quiet The quiet mode allows for machine-parsable output by printing only IDs
--runtime runtime Container runtime to use. Available options are: [docker containerd] (default containerd)
```

### SEE ALSO

* [ignite](ignite.md) - ignite: easily run Firecracker VMs

6 changes: 4 additions & 2 deletions vendor/github.com/go-openapi/jsonreference/go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions vendor/github.com/go-openapi/jsonreference/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions vendor/github.com/go-openapi/spec/bindata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions vendor/github.com/go-openapi/spec/go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions vendor/github.com/go-openapi/spec/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vendor/github.com/go-openapi/spec/schema_loader.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading