Statistics
| Branch: | Tag: | Revision:

root / image_creator / rsync.py @ 56884b64

History | View | Annotate | Download (4.5 kB)

1 74149d07 Nikos Skalkotos
# Copyright 2012 GRNET S.A. All rights reserved.
2 74149d07 Nikos Skalkotos
#
3 74149d07 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
4 74149d07 Nikos Skalkotos
# without modification, are permitted provided that the following
5 74149d07 Nikos Skalkotos
# conditions are met:
6 74149d07 Nikos Skalkotos
#
7 74149d07 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
8 74149d07 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
9 74149d07 Nikos Skalkotos
#      disclaimer.
10 74149d07 Nikos Skalkotos
#
11 74149d07 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
12 74149d07 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
13 74149d07 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
14 74149d07 Nikos Skalkotos
#      provided with the distribution.
15 74149d07 Nikos Skalkotos
#
16 74149d07 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 74149d07 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 74149d07 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 74149d07 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 74149d07 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 74149d07 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 74149d07 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 74149d07 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 74149d07 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 74149d07 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 74149d07 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 74149d07 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
28 74149d07 Nikos Skalkotos
#
29 74149d07 Nikos Skalkotos
# The views and conclusions contained in the software and
30 74149d07 Nikos Skalkotos
# documentation are those of the authors and should not be
31 74149d07 Nikos Skalkotos
# interpreted as representing official policies, either expressed
32 74149d07 Nikos Skalkotos
# or implied, of GRNET S.A.
33 74149d07 Nikos Skalkotos
34 74149d07 Nikos Skalkotos
import subprocess
35 d15368cc Nikos Skalkotos
import time
36 d15368cc Nikos Skalkotos
import signal
37 d15368cc Nikos Skalkotos
38 d15368cc Nikos Skalkotos
from image_creator.util import FatalError
39 74149d07 Nikos Skalkotos
40 74149d07 Nikos Skalkotos
41 74149d07 Nikos Skalkotos
class Rsync:
42 d15368cc Nikos Skalkotos
    """Wrapper class for the rsync command"""
43 d15368cc Nikos Skalkotos
44 1fa75c4c Nikos Skalkotos
    def __init__(self, output):
45 1fa75c4c Nikos Skalkotos
        """Create an instance """
46 1fa75c4c Nikos Skalkotos
        self._out = output
47 1fa75c4c Nikos Skalkotos
        self._exclude = []
48 1fa75c4c Nikos Skalkotos
        self._options = ['-v']
49 74149d07 Nikos Skalkotos
50 74149d07 Nikos Skalkotos
    def archive(self):
51 d15368cc Nikos Skalkotos
        """Enable the archive option"""
52 1fa75c4c Nikos Skalkotos
        self._options.append('-a')
53 74149d07 Nikos Skalkotos
        return self
54 74149d07 Nikos Skalkotos
55 1fa75c4c Nikos Skalkotos
    def xattrs(self):
56 1fa75c4c Nikos Skalkotos
        """Preserve extended attributes"""
57 1fa75c4c Nikos Skalkotos
        self._options.append('-X')
58 1fa75c4c Nikos Skalkotos
        return self
59 1fa75c4c Nikos Skalkotos
60 1fa75c4c Nikos Skalkotos
    def hard_links(self):
61 1fa75c4c Nikos Skalkotos
        """Preserve hard links"""
62 1fa75c4c Nikos Skalkotos
        self._options.append('-H')
63 1fa75c4c Nikos Skalkotos
        return self
64 1fa75c4c Nikos Skalkotos
65 1fa75c4c Nikos Skalkotos
    def acls(self):
66 1fa75c4c Nikos Skalkotos
        """Preserve ACLs"""
67 1fa75c4c Nikos Skalkotos
        self._options.append('-A')
68 1fa75c4c Nikos Skalkotos
        return self
69 1fa75c4c Nikos Skalkotos
70 1fa75c4c Nikos Skalkotos
    def sparse(self):
71 1fa75c4c Nikos Skalkotos
        """Handle sparse files efficiently"""
72 1fa75c4c Nikos Skalkotos
        self._options.append('-S')
73 1fa75c4c Nikos Skalkotos
        return self
74 1fa75c4c Nikos Skalkotos
75 1fa75c4c Nikos Skalkotos
    def exclude(self, pattern):
76 1fa75c4c Nikos Skalkotos
        """Add an exclude pattern"""
77 1fa75c4c Nikos Skalkotos
        self._exclude.append(pattern)
78 1fa75c4c Nikos Skalkotos
        return self
79 1fa75c4c Nikos Skalkotos
80 1fa75c4c Nikos Skalkotos
    def reset(self):
81 1fa75c4c Nikos Skalkotos
        """Reset all rsync options"""
82 1fa75c4c Nikos Skalkotos
        self._exclude = []
83 1fa75c4c Nikos Skalkotos
        self._options = ['-v']
84 1fa75c4c Nikos Skalkotos
85 63e1b902 Nikos Skalkotos
    def run(self, src, dest, slabel='source', dlabel='destination'):
86 d15368cc Nikos Skalkotos
        """Run the actual command"""
87 74149d07 Nikos Skalkotos
        cmd = []
88 74149d07 Nikos Skalkotos
        cmd.append('rsync')
89 1fa75c4c Nikos Skalkotos
        cmd.extend(self._options)
90 1fa75c4c Nikos Skalkotos
        for i in self._exclude:
91 74149d07 Nikos Skalkotos
            cmd.extend(['--exclude', i])
92 74149d07 Nikos Skalkotos
93 63e1b902 Nikos Skalkotos
        self._out.output("Calculating total number of %s files ..." % slabel,
94 63e1b902 Nikos Skalkotos
                         False)
95 1fa75c4c Nikos Skalkotos
96 1fa75c4c Nikos Skalkotos
        # If you don't specify a destination, rsync will list the source files.
97 1fa75c4c Nikos Skalkotos
        dry_run = subprocess.Popen(cmd + [src], shell=False,
98 1fa75c4c Nikos Skalkotos
                                   stdout=subprocess.PIPE, bufsize=0)
99 d15368cc Nikos Skalkotos
        try:
100 d15368cc Nikos Skalkotos
            total = 0
101 d15368cc Nikos Skalkotos
            for line in iter(dry_run.stdout.readline, b''):
102 d15368cc Nikos Skalkotos
                total += 1
103 d15368cc Nikos Skalkotos
        finally:
104 d15368cc Nikos Skalkotos
            dry_run.communicate()
105 d15368cc Nikos Skalkotos
            if dry_run.returncode != 0:
106 d15368cc Nikos Skalkotos
                raise FatalError("rsync failed")
107 d15368cc Nikos Skalkotos
108 1fa75c4c Nikos Skalkotos
        self._out.success("%d" % total)
109 74149d07 Nikos Skalkotos
110 f2ddf4db Nikos Skalkotos
        progress = self._out.Progress(total, "Copying files to %s" % dlabel)
111 1fa75c4c Nikos Skalkotos
        run = subprocess.Popen(cmd + [src, dest], shell=False,
112 74149d07 Nikos Skalkotos
                               stdout=subprocess.PIPE, bufsize=0)
113 d15368cc Nikos Skalkotos
        try:
114 d15368cc Nikos Skalkotos
            t = time.time()
115 d15368cc Nikos Skalkotos
            i = 0
116 d15368cc Nikos Skalkotos
            for line in iter(run.stdout.readline, b''):
117 d15368cc Nikos Skalkotos
                i += 1
118 d15368cc Nikos Skalkotos
                current = time.time()
119 d15368cc Nikos Skalkotos
                if current - t > 0.1:
120 d15368cc Nikos Skalkotos
                    t = current
121 d15368cc Nikos Skalkotos
                    progress.goto(i)
122 d15368cc Nikos Skalkotos
123 d15368cc Nikos Skalkotos
            progress.success('done')
124 d15368cc Nikos Skalkotos
125 d15368cc Nikos Skalkotos
        finally:
126 fb2d189c Nikos Skalkotos
            def handler(signum, frame):
127 fb2d189c Nikos Skalkotos
                run.terminate()
128 fb2d189c Nikos Skalkotos
                time.sleep(1)
129 fb2d189c Nikos Skalkotos
                run.poll()
130 fb2d189c Nikos Skalkotos
                if run.returncode is None:
131 fb2d189c Nikos Skalkotos
                    run.kill()
132 fb2d189c Nikos Skalkotos
                run.wait()
133 fb2d189c Nikos Skalkotos
134 fb2d189c Nikos Skalkotos
            signal.signal(signal.SIGALRM, handler)
135 fb2d189c Nikos Skalkotos
            signal.alarm(2)
136 d15368cc Nikos Skalkotos
            run.communicate()
137 fb2d189c Nikos Skalkotos
            signal.alarm(0)
138 d15368cc Nikos Skalkotos
            if run.returncode != 0:
139 d15368cc Nikos Skalkotos
                raise FatalError("rsync failed")
140 74149d07 Nikos Skalkotos
141 74149d07 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :