Browse code

oc rsync: expose additional rsync flags

Cesar Wong authored on 2016/01/08 05:44:38
Showing 8 changed files
... ...
@@ -2630,6 +2630,10 @@ _oc_rsync()
2630 2630
     flags+=("--container=")
2631 2631
     two_word_flags+=("-c")
2632 2632
     flags+=("--delete")
2633
+    flags+=("--exclude=")
2634
+    flags+=("--include=")
2635
+    flags+=("--no-perms")
2636
+    flags+=("--progress")
2633 2637
     flags+=("--quiet")
2634 2638
     flags+=("-q")
2635 2639
     flags+=("--strategy=")
... ...
@@ -7602,6 +7602,10 @@ _openshift_cli_rsync()
7602 7602
     flags+=("--container=")
7603 7603
     two_word_flags+=("-c")
7604 7604
     flags+=("--delete")
7605
+    flags+=("--exclude=")
7606
+    flags+=("--include=")
7607
+    flags+=("--no-perms")
7608
+    flags+=("--progress")
7605 7609
     flags+=("--quiet")
7606 7610
     flags+=("-q")
7607 7611
     flags+=("--strategy=")
... ...
@@ -27,7 +27,7 @@ type rsyncStrategy struct {
27 27
 	RemoteExecutor executor
28 28
 }
29 29
 
30
-var rshExcludeFlags = sets.NewString("delete", "strategy", "quiet")
30
+var rshExcludeFlags = sets.NewString("delete", "strategy", "quiet", "include", "exclude", "progress", "no-perms")
31 31
 
32 32
 func newRsyncStrategy(f *clientcmd.Factory, c *cobra.Command, o *RsyncOptions) (copyStrategy, error) {
33 33
 	// Determine the rsh command to pass to the local rsync command
... ...
@@ -48,19 +48,10 @@ func newRsyncStrategy(f *clientcmd.Factory, c *cobra.Command, o *RsyncOptions) (
48 48
 		return nil, err
49 49
 	}
50 50
 
51
-	// TODO: Expose more flags to send to the rsync command
52
-	// either as a special argument or any unrecognized arguments.
53 51
 	// The blocking-io flag is used to resolve a sync issue when
54 52
 	// copying from the pod to the local machine
55 53
 	flags := []string{"-a", "--blocking-io", "--omit-dir-times", "--numeric-ids"}
56
-	if o.Quiet {
57
-		flags = append(flags, "-q")
58
-	} else {
59
-		flags = append(flags, "-v")
60
-	}
61
-	if o.Delete {
62
-		flags = append(flags, "--delete")
63
-	}
54
+	flags = append(flags, rsyncFlagsFromOptions(o)...)
64 55
 
65 56
 	return &rsyncStrategy{
66 57
 		Flags:          flags,
... ...
@@ -259,17 +259,8 @@ func (s *rsyncDaemonStrategy) Validate() error {
259 259
 }
260 260
 
261 261
 func newRsyncDaemonStrategy(f *clientcmd.Factory, c *cobra.Command, o *RsyncOptions) (copyStrategy, error) {
262
-	// TODO: Expose more flags to send to the rsync command
263
-	// either as a special argument or any unrecognized arguments.
264 262
 	flags := []string{"-a", "--omit-dir-times", "--numeric-ids"}
265
-	if o.Quiet {
266
-		flags = append(flags, "-q")
267
-	} else {
268
-		flags = append(flags, "-v")
269
-	}
270
-	if o.Delete {
271
-		flags = append(flags, "--delete")
272
-	}
263
+	flags = append(flags, rsyncFlagsFromOptions(o)...)
273 264
 
274 265
 	remoteExec, err := newRemoteExecutor(f, o)
275 266
 	if err != nil {
... ...
@@ -30,6 +30,7 @@ type tarStrategy struct {
30 30
 	Delete         bool
31 31
 	Tar            tar.Tar
32 32
 	RemoteExecutor executor
33
+	IgnoredFlags   []string
33 34
 }
34 35
 
35 36
 func newTarStrategy(f *clientcmd.Factory, c *cobra.Command, o *RsyncOptions) (copyStrategy, error) {
... ...
@@ -37,6 +38,8 @@ func newTarStrategy(f *clientcmd.Factory, c *cobra.Command, o *RsyncOptions) (co
37 37
 	tarHelper := tar.New()
38 38
 	tarHelper.SetExclusionPattern(nil)
39 39
 
40
+	ignoredFlags := rsyncSpecificFlags(o)
41
+
40 42
 	remoteExec, err := newRemoteExecutor(f, o)
41 43
 	if err != nil {
42 44
 		return nil, err
... ...
@@ -47,6 +50,7 @@ func newTarStrategy(f *clientcmd.Factory, c *cobra.Command, o *RsyncOptions) (co
47 47
 		Delete:         o.Delete,
48 48
 		Tar:            tarHelper,
49 49
 		RemoteExecutor: remoteExec,
50
+		IgnoredFlags:   ignoredFlags,
50 51
 	}, nil
51 52
 }
52 53
 
... ...
@@ -110,6 +114,11 @@ func deleteFiles(source, dest *pathSpec, remoteExecutor executor) error {
110 110
 func (r *tarStrategy) Copy(source, destination *pathSpec, out, errOut io.Writer) error {
111 111
 
112 112
 	glog.V(3).Infof("Copying files with tar")
113
+
114
+	if len(r.IgnoredFlags) > 0 {
115
+		fmt.Fprintf(errOut, "Ignoring the following flags because they only apply to rsync: %s\n", strings.Join(r.IgnoredFlags, ", "))
116
+	}
117
+
113 118
 	if r.Delete {
114 119
 		// Implement the rsync --delete flag as a separate call to first delete directory contents
115 120
 		err := deleteFiles(source, destination, r.RemoteExecutor)
... ...
@@ -34,8 +34,8 @@ for the copy.`
34 34
   # Synchronize a pod directory with a local directory
35 35
   $ %[1]s POD:/remote/dir/ ./local/dir`
36 36
 
37
-	noRsyncUnixWarning    = "WARNING: rsync command not found in path. Please use your package manager to install it."
38
-	noRsyncWindowsWarning = "WARNING: rsync command not found in path. Download cwRsync for Windows and add it to your PATH."
37
+	noRsyncUnixWarning    = "WARNING: rsync command not found in path. Please use your package manager to install it.\n"
38
+	noRsyncWindowsWarning = "WARNING: rsync command not found in path. Download cwRsync for Windows and add it to your PATH.\n"
39 39
 )
40 40
 
41 41
 // copyStrategy
... ...
@@ -66,6 +66,11 @@ type RsyncOptions struct {
66 66
 	Quiet         bool
67 67
 	Delete        bool
68 68
 
69
+	RsyncInclude  string
70
+	RsyncExclude  string
71
+	RsyncProgress bool
72
+	RsyncNoPerms  bool
73
+
69 74
 	Out    io.Writer
70 75
 	ErrOut io.Writer
71 76
 }
... ...
@@ -97,6 +102,10 @@ func NewCmdRsync(name, parent string, f *clientcmd.Factory, out, errOut io.Write
97 97
 	// Flags for rsync options, Must match rsync flag names
98 98
 	cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", false, "Suppress non-error messages")
99 99
 	cmd.Flags().BoolVar(&o.Delete, "delete", false, "Delete files not present in source")
100
+	cmd.Flags().StringVar(&o.RsyncExclude, "exclude", "", "rsync - exclude files matching specified pattern")
101
+	cmd.Flags().StringVar(&o.RsyncInclude, "include", "", "rsync - include files matching specified pattern")
102
+	cmd.Flags().BoolVar(&o.RsyncProgress, "progress", false, "rsync - show progress during transfer")
103
+	cmd.Flags().BoolVar(&o.RsyncNoPerms, "no-perms", false, "rsync - do not transfer permissions")
100 104
 	return cmd
101 105
 }
102 106
 
... ...
@@ -2,6 +2,7 @@ package rsync
2 2
 
3 3
 import (
4 4
 	"bytes"
5
+	"fmt"
5 6
 	"os"
6 7
 	"os/exec"
7 8
 	"runtime"
... ...
@@ -75,3 +76,45 @@ func checkRsync(e executor) error {
75 75
 func checkTar(e executor) error {
76 76
 	return executeWithLogging(e, testTarCommand)
77 77
 }
78
+
79
+func rsyncFlagsFromOptions(o *RsyncOptions) []string {
80
+	flags := []string{}
81
+	if o.Quiet {
82
+		flags = append(flags, "-q")
83
+	} else {
84
+		flags = append(flags, "-v")
85
+	}
86
+	if o.Delete {
87
+		flags = append(flags, "--delete")
88
+	}
89
+	if len(o.RsyncInclude) > 0 {
90
+		flags = append(flags, fmt.Sprintf("--include=%s", o.RsyncInclude))
91
+	}
92
+	if len(o.RsyncExclude) > 0 {
93
+		flags = append(flags, fmt.Sprintf("--exclude=%s", o.RsyncExclude))
94
+	}
95
+	if o.RsyncProgress {
96
+		flags = append(flags, "--progress")
97
+	}
98
+	if o.RsyncNoPerms {
99
+		flags = append(flags, "--no-perms")
100
+	}
101
+	return flags
102
+}
103
+
104
+func rsyncSpecificFlags(o *RsyncOptions) []string {
105
+	flags := []string{}
106
+	if len(o.RsyncInclude) > 0 {
107
+		flags = append(flags, "--include")
108
+	}
109
+	if len(o.RsyncExclude) > 0 {
110
+		flags = append(flags, "--exclude")
111
+	}
112
+	if o.RsyncProgress {
113
+		flags = append(flags, "--progress")
114
+	}
115
+	if o.RsyncNoPerms {
116
+		flags = append(flags, "--no-perms")
117
+	}
118
+	return flags
119
+}
... ...
@@ -26,27 +26,27 @@ var _ = g.Describe("cli: parallel: oc rsync", func() {
26 26
 		strategies   = []string{"rsync", "rsync-daemon", "tar"}
27 27
 	)
28 28
 
29
-	g.Describe("copy by strategy", func() {
30
-		var podName string
31
-
32
-		g.JustBeforeEach(func() {
33
-			oc.SetOutputDir(exutil.TestContext.OutputDir)
34
-
35
-			g.By(fmt.Sprintf("calling oc new-app -f %q", templatePath))
36
-			err := oc.Run("new-app").Args("-f", templatePath).Execute()
37
-			o.Expect(err).NotTo(o.HaveOccurred())
38
-
39
-			g.By("expecting the jenkins service get endpoints")
40
-			err = oc.KubeFramework().WaitForAnEndpoint("jenkins")
41
-			o.Expect(err).NotTo(o.HaveOccurred())
29
+	var podName string
30
+	g.JustBeforeEach(func() {
31
+		oc.SetOutputDir(exutil.TestContext.OutputDir)
32
+
33
+		g.By(fmt.Sprintf("calling oc new-app -f %q", templatePath))
34
+		err := oc.Run("new-app").Args("-f", templatePath).Execute()
35
+		o.Expect(err).NotTo(o.HaveOccurred())
36
+
37
+		g.By("expecting the jenkins service get endpoints")
38
+		err = oc.KubeFramework().WaitForAnEndpoint("jenkins")
39
+		o.Expect(err).NotTo(o.HaveOccurred())
40
+
41
+		g.By("Getting the jenkins pod name")
42
+		selector, _ := labels.Parse("name=jenkins")
43
+		pods, err := oc.KubeREST().Pods(oc.Namespace()).List(selector, fields.Everything())
44
+		o.Expect(err).NotTo(o.HaveOccurred())
45
+		o.Expect(len(pods.Items)).ToNot(o.BeZero())
46
+		podName = pods.Items[0].Name
47
+	})
42 48
 
43
-			g.By("Getting the jenkins pod name")
44
-			selector, _ := labels.Parse("name=jenkins")
45
-			pods, err := oc.KubeREST().Pods(oc.Namespace()).List(selector, fields.Everything())
46
-			o.Expect(err).NotTo(o.HaveOccurred())
47
-			o.Expect(len(pods.Items)).ToNot(o.BeZero())
48
-			podName = pods.Items[0].Name
49
-		})
49
+	g.Describe("copy by strategy", func() {
50 50
 
51 51
 		testRsyncFn := func(strategy string) func() {
52 52
 			return func() {
... ...
@@ -143,4 +143,80 @@ var _ = g.Describe("cli: parallel: oc rsync", func() {
143 143
 			g.It(fmt.Sprintf("should copy files with the %s strategy", strategy), testRsyncFn(strategy))
144 144
 		}
145 145
 	})
146
+
147
+	g.Describe("rsync specific flags", func() {
148
+
149
+		g.It("should honor the --exclude flag", func() {
150
+			g.By(fmt.Sprintf("Calling oc rsync %s %s:/tmp --exclude=image-streams-rhel7.json", sourcePath1, podName))
151
+			err := oc.Run("rsync").Args(
152
+				sourcePath1,
153
+				fmt.Sprintf("%s:/tmp", podName),
154
+				"--exclude=image-streams-rhel7.json").Execute()
155
+			o.Expect(err).NotTo(o.HaveOccurred())
156
+
157
+			g.By("Verifying that files are copied to the container")
158
+			result, err := oc.Run("rsh").Args(podName, "ls", "/tmp/image-streams").Output()
159
+			o.Expect(err).NotTo(o.HaveOccurred())
160
+			o.Expect(result).To(o.ContainSubstring("image-streams-centos7.json"))
161
+			o.Expect(result).NotTo(o.ContainSubstring("image-streams-rhel7.json"))
162
+		})
163
+
164
+		g.It("should honor the --include flag", func() {
165
+			g.By(fmt.Sprintf("Calling oc rsync %s %s:/tmp --exclude=*.json --include=image-streams-rhel7.json", sourcePath1, podName))
166
+			err := oc.Run("rsync").Args(
167
+				sourcePath1,
168
+				fmt.Sprintf("%s:/tmp", podName),
169
+				"--exclude=*.json",
170
+				"--include=image-streams-rhel7.json").Execute()
171
+			o.Expect(err).NotTo(o.HaveOccurred())
172
+
173
+			g.By("Verifying that files are copied to the container")
174
+			result, err := oc.Run("rsh").Args(podName, "ls", "/tmp/image-streams").Output()
175
+			o.Expect(err).NotTo(o.HaveOccurred())
176
+			o.Expect(result).To(o.ContainSubstring("image-streams-rhel7.json"))
177
+			o.Expect(result).NotTo(o.ContainSubstring("image-streams-centos7.json"))
178
+		})
179
+
180
+		g.It("should honor the --progress flag", func() {
181
+			g.By(fmt.Sprintf("Calling oc rsync %s %s:/tmp --progress", sourcePath1, podName))
182
+			result, err := oc.Run("rsync").Args(
183
+				sourcePath1,
184
+				fmt.Sprintf("%s:/tmp", podName),
185
+				"--progress").Output()
186
+			o.Expect(err).NotTo(o.HaveOccurred())
187
+			o.Expect(result).To(o.ContainSubstring("100%"))
188
+		})
189
+
190
+		g.It("should honor the --no-perms flag", func() {
191
+			g.By("Creating a temporary destination directory")
192
+			tempDir, err := ioutil.TempDir("", "rsync")
193
+			o.Expect(err).NotTo(o.HaveOccurred())
194
+
195
+			g.By(fmt.Sprintf("Copying the jenkins directory from the pod to the temp directory: oc rsync %s:/var/lib/jenkins %s", podName, tempDir))
196
+			err = oc.Run("rsync").Args(
197
+				fmt.Sprintf("%s:/var/lib/jenkins", podName),
198
+				tempDir).Execute()
199
+			o.Expect(err).NotTo(o.HaveOccurred())
200
+
201
+			localJenkinsDir := filepath.Join(tempDir, "jenkins")
202
+			g.By("By changing the permissions on the local jenkins directory")
203
+			err = os.Chmod(localJenkinsDir, 0700)
204
+			o.Expect(err).NotTo(o.HaveOccurred())
205
+
206
+			g.By(fmt.Sprintf("Copying the local jenkins directory to the pod with no flags: oc rsync %s/ %s:/var/lib/jenkins", localJenkinsDir, podName))
207
+			err = oc.Run("rsync").Args(
208
+				fmt.Sprintf("%s/", localJenkinsDir),
209
+				fmt.Sprintf("%s:/var/lib/jenkins", podName)).Execute()
210
+			// An error should occur trying to set permissions on the directory
211
+			o.Expect(err).To(o.HaveOccurred())
212
+
213
+			g.By(fmt.Sprintf("Copying the local jenkins directory to the pod with: oc rsync %s/ %s:/var/lib/jenkins --no-perms", localJenkinsDir, podName))
214
+			err = oc.Run("rsync").Args(
215
+				fmt.Sprintf("%s/", localJenkinsDir),
216
+				fmt.Sprintf("%s:/var/lib/jenkins", podName),
217
+				"--no-perms").Execute()
218
+			o.Expect(err).NotTo(o.HaveOccurred())
219
+		})
220
+	})
221
+
146 222
 })