Skip to content

Commit

Permalink
feat(kube-run): add --copy-to; replace --copy-from-[file|dir] with --…
Browse files Browse the repository at this point in the history
…copy-from

Signed-off-by: Ilya Lesikov <ilya@lesikov.com>
  • Loading branch information
ilya-lesikov committed May 18, 2022
1 parent 6e28ce7 commit 231ccbc
Showing 1 changed file with 106 additions and 85 deletions.
191 changes: 106 additions & 85 deletions cmd/werf/kube_run/kube_run.go
Expand Up @@ -16,7 +16,6 @@ import (
config2 "github.com/containers/image/v5/pkg/docker/config"
imgtypes "github.com/containers/image/v5/types"
"github.com/spf13/cobra"
"github.com/werf/werf/pkg/util"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
Expand All @@ -41,6 +40,7 @@ import (
"github.com/werf/werf/pkg/storage/manager"
"github.com/werf/werf/pkg/tmp_manager"
"github.com/werf/werf/pkg/true_git"
"github.com/werf/werf/pkg/util"
"github.com/werf/werf/pkg/werf"
"github.com/werf/werf/pkg/werf/global_warnings"
)
Expand All @@ -57,15 +57,15 @@ type cmdDataType struct {
ImageName string
Overrides string
RunExtraOptions string
CopyFromFile []string
CopyFromDir []string
CopyFrom []string
CopyTo []string

registryCredsFound bool
}

type copyFrom struct {
From string
To string
type copyFromTo struct {
Src string
Dst string
}

var (
Expand Down Expand Up @@ -131,12 +131,12 @@ func NewCmd() *cobra.Command {
}
}

if err := validateCopyFromFile(); err != nil {
return fmt.Errorf("error validating --copy-from-file: %w", err)
if err := validateCopyFrom(); err != nil {
return fmt.Errorf("error validating --copy-from: %w", err)
}

if err := validateCopyFromDir(); err != nil {
return fmt.Errorf("error validating --copy-from-dir: %w", err)
if err := validateCopyTo(); err != nil {
return fmt.Errorf("error validating --copy-to: %w", err)
}

return runMain(ctx)
Expand Down Expand Up @@ -191,8 +191,8 @@ func NewCmd() *cobra.Command {
cmd.Flags().BoolVarP(&cmdData.Interactive, "interactive", "i", common.GetBoolEnvironmentDefaultFalse("WERF_INTERACTIVE"), "Enable interactive mode (default $WERF_INTERACTIVE or false if not specified)")
cmd.Flags().BoolVarP(&cmdData.AllocateTty, "tty", "t", common.GetBoolEnvironmentDefaultFalse("WERF_TTY"), "Allocate a TTY (default $WERF_TTY or false if not specified)")
cmd.Flags().BoolVarP(&cmdData.AutoPullSecret, "auto-pull-secret", "", common.GetBoolEnvironmentDefaultTrue("WERF_AUTO_PULL_SECRET"), "Automatically create docker config secret in the namespace and plug it via pod's imagePullSecrets for private registry access (default $WERF_AUTO_PULL_SECRET or true if not specified)")
cmd.Flags().StringArrayVarP(&cmdData.CopyFromFile, "copy-from-file", "", []string{}, "Copy file from container to local machine after execution (default $WERF_COPY_FROM_FILE). WARNING: parent directory will be copied to a temporary volume, which might affect performance. Example: \"/from/file:to\".")
cmd.Flags().StringArrayVarP(&cmdData.CopyFromDir, "copy-from-dir", "", []string{}, "Copy dir from container to local machine after execution (default $WERF_COPY_FROM_DIR). Example: \"/from/dir:to\".")
cmd.Flags().StringArrayVarP(&cmdData.CopyFrom, "copy-from", "", []string{}, "Copy file/dir from container to local machine after execution (default $WERF_COPY_FROM). Example: \"/from/file:to\".")
cmd.Flags().StringArrayVarP(&cmdData.CopyTo, "copy-to", "", []string{}, "Copy file/dir from local machine to container after execution (default $WERF_COPY_TO). Example: \"from:/to/file\".")

return cmd
}
Expand Down Expand Up @@ -437,19 +437,19 @@ func run(ctx context.Context, pod, secret, namespace string, werfConfig *config.
return fmt.Errorf("error waiting for Pod readiness: %w", err)
}

if err := execCommandInPod(ctx, namespace, pod, pod, cmdData.Command, commonArgs); err != nil {
return fmt.Errorf("error running command in Pod: %w", err)
for _, copyTo := range getCopyTo() {
if err := copyToPod(ctx, namespace, pod, pod, copyTo, commonArgs); err != nil {
return fmt.Errorf("error copying to Pod: %w", err)
}
}

for _, copyFromFile := range getCopyFromFile() {
if err := copyFromPod(ctx, namespace, pod, pod, copyFromFile, commonArgs); err != nil {
return fmt.Errorf("error copying file from: %w", err)
}
if err := execCommandInPod(ctx, namespace, pod, pod, cmdData.Command, commonArgs); err != nil {
return fmt.Errorf("error running command in Pod: %w", err)
}

for _, copyFromDir := range getCopyFromDir() {
if err := copyFromPod(ctx, namespace, pod, pod, copyFromDir, commonArgs); err != nil {
return fmt.Errorf("error copying dir from: %w", err)
for _, copyFrom := range getCopyFrom() {
if err := copyFromPod(ctx, namespace, pod, pod, copyFrom, commonArgs); err != nil {
return fmt.Errorf("error copying from Pod: %w", err)
}
}

Expand Down Expand Up @@ -521,7 +521,7 @@ func createKubectlRunArgs(pod string, image string, secret string, extraArgs []s

args = append(args, extraArgs...)

if overrides, err := generateOverrides(pod, image, secret); err != nil {
if overrides, err := generateOverrides(secret); err != nil {
return nil, fmt.Errorf("error generating --overrides: %w", err)
} else if overrides != nil {
args = append(args, "--overrides", string(overrides), "--override-type", "strategic")
Expand All @@ -538,10 +538,8 @@ func createKubectlRunArgs(pod string, image string, secret string, extraArgs []s
}

// Can return nil overrides.
func generateOverrides(pod, image, secret string) ([]byte, error) {
func generateOverrides(secret string) ([]byte, error) {
if cmdData.Overrides == "" &&
len(getCopyFromFile()) == 0 &&
len(getCopyFromDir()) == 0 &&
(!cmdData.AutoPullSecret || !cmdData.registryCredsFound) {
return nil, nil
}
Expand Down Expand Up @@ -667,11 +665,11 @@ func isPodReady(namespace string, pod string, extraArgs []string) (bool, error)
}
}

func copyFromPod(ctx context.Context, namespace, pod, container string, copyFrom copyFrom, extraArgs []string) error {
logboek.Context(ctx).LogF("Copying %q from pod %q in namespace %q to %q ...\n", copyFrom.From, pod, namespace, copyFrom.To)
func copyFromPod(ctx context.Context, namespace, pod, container string, copyFrom copyFromTo, extraArgs []string) error {
logboek.Context(ctx).LogF("Copying %q from pod %q in namespace %q to %q ...\n", copyFrom.Src, pod, namespace, copyFrom.Dst)

args := []string{
"cp", fmt.Sprint(namespace, "/", pod, ":", copyFrom.From), copyFrom.To, "-c", container,
"cp", fmt.Sprint(namespace, "/", pod, ":", copyFrom.Src), copyFrom.Dst, "-c", container,
}

args = append(args, extraArgs...)
Expand All @@ -684,7 +682,30 @@ func copyFromPod(ctx context.Context, namespace, pod, container string, copyFrom
}

if err := cmd.Run(); err != nil {
return fmt.Errorf("error copying %q from pod %s/%s: %w", copyFrom.From, namespace, pod, err)
return fmt.Errorf("error copying %q from pod %s/%s: %w", copyFrom.Src, namespace, pod, err)
}

return nil
}

func copyToPod(ctx context.Context, namespace, pod, container string, copyFrom copyFromTo, extraArgs []string) error {
logboek.Context(ctx).LogF("Copying %q to %q in pod %q in namespace %q ...\n", copyFrom.Src, copyFrom.Dst, pod, namespace)

args := []string{
"cp", copyFrom.Src, fmt.Sprint(namespace, "/", pod, ":", copyFrom.Dst), "-c", container,
}

args = append(args, extraArgs...)

cmd := util.ExecKubectlCmd(args...)

if *commonCmdData.DryRun {
fmt.Println(cmd.String())
return nil
}

if err := cmd.Run(); err != nil {
return fmt.Errorf("error copying %q to pod %s/%s: %w", copyFrom.Src, namespace, pod, err)
}

return nil
Expand Down Expand Up @@ -937,87 +958,75 @@ func templateOverrides(line, podName, containerName string) string {
return strings.ReplaceAll(result, "%pod_name%", podName)
}

func validateCopyFromFile() error {
rawCopyFrom := getCopyFromFileRaw()
func validateCopyFrom() error {
rawCopyFrom := getCopyFromRaw()

for _, cf := range rawCopyFrom {
parts := strings.Split(cf, ":")
for _, copyFrom := range rawCopyFrom {
parts := strings.Split(copyFrom, ":")
if len(parts) != 2 {
return fmt.Errorf("wrong format: %s", cf)
return fmt.Errorf("wrong format: %s", copyFrom)
}

src := cleanCopyFromPodPath(parts[0])
src := cleanCopyPodPath(parts[0])
dst, err := cleanCopyFromLocalPath(parts[1], path.Base(src))
if err != nil {
return fmt.Errorf("error cleaning destination path: %w", err)
}

if strings.TrimSpace(src) == "" || strings.TrimSpace(dst) == "" {
return fmt.Errorf("invalid value: %s", cf)
return fmt.Errorf("invalid value: %s", copyFrom)
}

if !path.IsAbs(src) {
return fmt.Errorf("invalid value %q: source should be an absolute path", cf)
}

if src == "/" {
return fmt.Errorf("invalid value %q: source root is not a file", cf)
return fmt.Errorf("invalid value %q: source should be an absolute path", copyFrom)
}
}

return nil
}

func validateCopyFromDir() error {
rawCopyFrom := getCopyFromDirRaw()
func validateCopyTo() error {
rawCopyTo := getCopyToRaw()

for _, cf := range rawCopyFrom {
parts := strings.Split(cf, ":")
for _, copyTo := range rawCopyTo {
parts := strings.Split(copyTo, ":")
if len(parts) != 2 {
return fmt.Errorf("wrong format: %s", cf)
return fmt.Errorf("wrong format: %s", copyTo)
}

src := cleanCopyFromPodPath(parts[0])
dst, err := cleanCopyFromLocalPath(parts[1], path.Base(src))
src, err := cleanCopyToLocalPath(parts[0])
if err != nil {
return fmt.Errorf("error cleaning destination path: %w", err)
return fmt.Errorf("error cleaning source path: %w", err)
}
dst := cleanCopyPodPath(parts[1])

if strings.TrimSpace(src) == "" || strings.TrimSpace(dst) == "" {
return fmt.Errorf("invalid value: %s", cf)
return fmt.Errorf("invalid value: %s", copyTo)
}

if !path.IsAbs(src) {
return fmt.Errorf("invalid value %q: source should be an absolute path", cf)
}

if src == "/" {
return fmt.Errorf("invalid value %q: source / is not allowed", cf)
}

if path.Base(src) == "/" {
return fmt.Errorf("invalid value %q: source file can't be from root directory", cf)
if !path.IsAbs(dst) {
return fmt.Errorf("invalid value %q: destination should be an absolute path", copyTo)
}
}

return nil
}

func getCopyFromFile() []copyFrom {
rawCopyFrom := getCopyFromFileRaw()
func getCopyFrom() []copyFromTo {
rawCopyFrom := getCopyFromRaw()

var result []copyFrom
var result []copyFromTo
for _, rawcf := range rawCopyFrom {
parts := strings.Split(rawcf, ":")
src := cleanCopyFromPodPath(parts[0])
src := cleanCopyPodPath(parts[0])
dst, err := cleanCopyFromLocalPath(parts[1], path.Base(src))
if err != nil {
panic("error cleaning destination path shouldn't happen")
panic("error cleaning destination path")
}

cf := copyFrom{
From: src,
To: dst,
cf := copyFromTo{
Src: src,
Dst: dst,
}

result = append(result, cf)
Expand All @@ -1026,30 +1035,30 @@ func getCopyFromFile() []copyFrom {
return result
}

func getCopyFromDir() []copyFrom {
rawCopyFrom := getCopyFromDirRaw()
func getCopyTo() []copyFromTo {
rawCopyTo := getCopyToRaw()

var result []copyFrom
for _, rawcf := range rawCopyFrom {
parts := strings.Split(rawcf, ":")
src := cleanCopyFromPodPath(parts[0])
dst, err := cleanCopyFromLocalPath(parts[1], path.Base(src))
var result []copyFromTo
for _, rawct := range rawCopyTo {
parts := strings.Split(rawct, ":")
src, err := cleanCopyToLocalPath(parts[0])
if err != nil {
panic("error cleaning destination path shouldn't happen")
panic("error cleaning source path")
}
dst := cleanCopyPodPath(parts[1])

cf := copyFrom{
From: src,
To: dst,
ct := copyFromTo{
Src: src,
Dst: dst,
}

result = append(result, cf)
result = append(result, ct)
}

return result
}

func cleanCopyFromPodPath(rawPath string) string {
func cleanCopyPodPath(rawPath string) string {
return filepath.ToSlash(filepath.Clean(rawPath))
}

Expand All @@ -1071,10 +1080,22 @@ func cleanCopyFromLocalPath(rawPath, srcBaseName string) (string, error) {
return rawPath, nil
}

func getCopyFromFileRaw() []string {
return append(common.PredefinedValuesByEnvNamePrefix("WERF_COPY_FROM_FILE_"), cmdData.CopyFromFile...)
func cleanCopyToLocalPath(rawPath string) (string, error) {
rawPath = filepath.Clean(util.ExpandPath(rawPath))

var err error
rawPath, err = filepath.Abs(rawPath)
if err != nil {
return "", fmt.Errorf("error converting path %q to an absolute path: %w", rawPath, err)
}

return rawPath, nil
}

func getCopyFromRaw() []string {
return append(common.PredefinedValuesByEnvNamePrefix("WERF_COPY_FROM_"), cmdData.CopyFrom...)
}

func getCopyFromDirRaw() []string {
return append(common.PredefinedValuesByEnvNamePrefix("WERF_COPY_FROM_DIR_"), cmdData.CopyFromDir...)
func getCopyToRaw() []string {
return append(common.PredefinedValuesByEnvNamePrefix("WERF_COPY_TO_"), cmdData.CopyTo...)
}

0 comments on commit 231ccbc

Please sign in to comment.