summaryrefslogtreecommitdiff
path: root/morphlib/mountableimage.py
blob: ecca58f36df417cf88efe232b820974de00fae64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# Copyright (C) 2012-2013,2015  Codethink Limited
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.


import cliapp
import logging
import os
import tempfile
import gzip

import morphlib


class MountableImage(object): # pragma: no cover

    '''Mountable image (deals with decompression).

    Note, this is a read-only mount in the sense that the decompressed
    image is not then recompressed after, instead any changes are discarded.

    '''
    def __init__(self, app, artifact_path):
        self.app = app
        self.artifact_path = artifact_path

    def setup(self, path):
        self.app.status(msg='Preparing image %(path)s', path=path, chatty=True)
        self.app.status(msg='  Decompressing...', chatty=True)
        (tempfd, self.temp_path) = \
            tempfile.mkstemp(dir=self.app.settings['tempdir'])

        try:
            with os.fdopen(tempfd, "wb") as outfh:
                infh = gzip.open(path, "rb")
                morphlib.util.copyfileobj(infh, outfh)
                infh.close()
        except BaseException, e:
            logging.error('Caught exception: %s' % str(e))
            logging.info('Removing temporary file %s' % self.temp_path)
            os.unlink(self.temp_path)
            raise
        self.app.status(msg='  Mounting image at %(path)s',
                        path=self.temp_path, chatty=True)
        part = morphlib.fsutils.setup_device_mapping(self.app.runcmd,
                                                     self.temp_path)
        mount_point = tempfile.mkdtemp(dir=self.app.settings['tempdir'])
        morphlib.fsutils.mount(self.app.runcmd, part, mount_point)
        self.mount_point = mount_point
        return mount_point

    def cleanup(self, path, mount_point):
        self.app.status(msg='Clearing down image at %(path)s', path=path,
                        chatty=True)
        try:
            morphlib.fsutils.unmount(self.app.runcmd, mount_point)
        except BaseException, e:
            logging.info('Ignoring error when unmounting: %s' % str(e))
        try:
            morphlib.fsutils.undo_device_mapping(self.app.runcmd, path)
        except BaseException, e:
            logging.info(
                'Ignoring error when undoing device mapping: %s' % str(e))
        try:
            os.rmdir(mount_point)
            os.unlink(path)
        except BaseException, e:
            logging.info(
                'Ignoring error when removing temporary files: %s' % str(e))

    def __enter__(self):
        return self.setup(self.artifact_path)

    def __exit__(self, exctype, excvalue, exctraceback):
        self.cleanup(self.temp_path, self.mount_point)