... | ... |
@@ -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 |
}) |