Statistics
| Branch: | Tag: | Revision:

root / image_creator / rsync.py @ 1fa75c4c

History | View | Annotate | Download (4.2 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 1fa75c4c Nikos Skalkotos
    def run(self, src, dest):
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 1fa75c4c Nikos Skalkotos
        self._out.output("Calculating total number of host files ...", False)
94 1fa75c4c Nikos Skalkotos
95 1fa75c4c Nikos Skalkotos
        # If you don't specify a destination, rsync will list the source files.
96 1fa75c4c Nikos Skalkotos
        dry_run = subprocess.Popen(cmd + [src], shell=False,
97 1fa75c4c Nikos Skalkotos
                                   stdout=subprocess.PIPE, bufsize=0)
98 d15368cc Nikos Skalkotos
        try:
99 d15368cc Nikos Skalkotos
            total = 0
100 d15368cc Nikos Skalkotos
            for line in iter(dry_run.stdout.readline, b''):
101 d15368cc Nikos Skalkotos
                total += 1
102 d15368cc Nikos Skalkotos
        finally:
103 d15368cc Nikos Skalkotos
            dry_run.communicate()
104 d15368cc Nikos Skalkotos
            if dry_run.returncode != 0:
105 d15368cc Nikos Skalkotos
                raise FatalError("rsync failed")
106 d15368cc Nikos Skalkotos
107 1fa75c4c Nikos Skalkotos
        self._out.success("%d" % total)
108 74149d07 Nikos Skalkotos
109 1fa75c4c Nikos Skalkotos
        progress = self._out.Progress(total,
110 1fa75c4c Nikos Skalkotos
                                     "Copying host files into the image ... ")
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 d15368cc Nikos Skalkotos
            run.poll()
127 d15368cc Nikos Skalkotos
            if run.returncode is None:
128 d15368cc Nikos Skalkotos
                run.send_signal(signal.SIGHUP)
129 d15368cc Nikos Skalkotos
            run.communicate()
130 d15368cc Nikos Skalkotos
            if run.returncode != 0:
131 d15368cc Nikos Skalkotos
                raise FatalError("rsync failed")
132 74149d07 Nikos Skalkotos
133 74149d07 Nikos Skalkotos
134 74149d07 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :