~ubuntu-branches/ubuntu/vivid/ironic/vivid-updates

« back to all changes in this revision

Viewing changes to ironic/drivers/modules/image_cache.py

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2015-01-05 12:21:37 UTC
  • mfrom: (1.2.4)
  • Revision ID: package-import@ubuntu.com-20150105122137-171bqrdpcxqipunk
Tags: 2015.1~b1-0ubuntu1
* New upstream beta release:
  - d/control: Align version requirements with upstream release.
* d/watch: Update uversionmangle to deal with kilo beta versioning
  changes.
* d/control: Bumped Standards-Version to 3.9.6, no changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
import time
24
24
 
25
25
from oslo.config import cfg
 
26
from oslo_concurrency import lockutils
26
27
 
27
28
from ironic.common import exception
28
29
from ironic.common.glance_service import service_utils
31
32
from ironic.common import images
32
33
from ironic.common import utils
33
34
from ironic.openstack.common import fileutils
34
 
from ironic.openstack.common import lockutils
35
35
from ironic.openstack.common import log as logging
36
36
 
37
37
 
72
72
        if master_dir is not None:
73
73
            fileutils.ensure_tree(master_dir)
74
74
 
75
 
    def fetch_image(self, uuid, dest_path, ctx=None):
76
 
        """Fetch image with given uuid to the destination path.
 
75
    def fetch_image(self, href, dest_path, ctx=None, force_raw=True):
 
76
        """Fetch image by given href to the destination path.
77
77
 
78
78
        Does nothing if destination path exists.
79
79
        Only creates a link if master image for this UUID is already in cache.
80
80
        Otherwise downloads an image and also stores it in cache.
81
81
 
82
 
        :param uuid: image UUID or href to fetch
 
82
        :param href: image UUID or href to fetch
83
83
        :param dest_path: destination file path
84
84
        :param ctx: context
 
85
        :param force_raw: boolean value, whether to convert the image to raw
 
86
                          format
85
87
        """
86
88
        img_download_lock_name = 'download-image'
87
89
        if self.master_dir is None:
88
 
            #NOTE(ghe): We don't share images between instances/hosts
 
90
            # NOTE(ghe): We don't share images between instances/hosts
89
91
            if not CONF.parallel_image_downloads:
90
92
                with lockutils.lock(img_download_lock_name, 'ironic-'):
91
 
                    _fetch_to_raw(ctx, uuid, dest_path, self._image_service)
 
93
                    _fetch(ctx, href, dest_path, self._image_service,
 
94
                           force_raw)
92
95
            else:
93
 
                _fetch_to_raw(ctx, uuid, dest_path, self._image_service)
 
96
                _fetch(ctx, href, dest_path, self._image_service, force_raw)
94
97
            return
95
98
 
96
 
        #TODO(ghe): have hard links and counts the same behaviour in all fs
 
99
        # TODO(ghe): have hard links and counts the same behaviour in all fs
97
100
 
98
 
        master_file_name = service_utils.parse_image_ref(uuid)[0]
 
101
        master_file_name = service_utils.parse_image_ref(href)[0]
99
102
        master_path = os.path.join(self.master_dir, master_file_name)
100
103
 
101
104
        if CONF.parallel_image_downloads:
106
109
            if os.path.exists(dest_path):
107
110
                LOG.debug("Destination %(dest)s already exists for "
108
111
                            "image %(uuid)s" %
109
 
                          {'uuid': uuid,
 
112
                          {'uuid': href,
110
113
                           'dest': dest_path})
111
114
                return
112
115
 
117
120
            except OSError:
118
121
                LOG.info(_LI("Master cache miss for image %(uuid)s, "
119
122
                             "starting download"),
120
 
                         {'uuid': uuid})
 
123
                         {'uuid': href})
121
124
            else:
122
125
                LOG.debug("Master cache hit for image %(uuid)s",
123
 
                          {'uuid': uuid})
 
126
                          {'uuid': href})
124
127
                return
125
128
 
126
 
            self._download_image(uuid, master_path, dest_path, ctx=ctx)
 
129
            self._download_image(
 
130
                href, master_path, dest_path, ctx=ctx, force_raw=force_raw)
127
131
 
128
132
        # NOTE(dtantsur): we increased cache size - time to clean up
129
133
        self.clean_up()
130
134
 
131
 
    def _download_image(self, uuid, master_path, dest_path, ctx=None):
132
 
        """Download image from Glance and store at a given path.
 
135
    def _download_image(self, href, master_path, dest_path, ctx=None,
 
136
                        force_raw=True):
 
137
        """Download image by href and store at a given path.
 
138
 
133
139
        This method should be called with uuid-specific lock taken.
134
140
 
135
 
        :param uuid: image UUID or href to fetch
 
141
        :param href: image UUID or href to fetch
136
142
        :param master_path: destination master path
137
143
        :param dest_path: destination file path
138
144
        :param ctx: context
 
145
        :param force_raw: boolean value, whether to convert the image to raw
 
146
                          format
139
147
        """
140
 
        #TODO(ghe): timeout and retry for downloads
141
 
        #TODO(ghe): logging when image cannot be created
 
148
        # TODO(ghe): timeout and retry for downloads
 
149
        # TODO(ghe): logging when image cannot be created
142
150
        tmp_dir = tempfile.mkdtemp(dir=self.master_dir)
143
 
        tmp_path = os.path.join(tmp_dir, uuid)
 
151
        tmp_path = os.path.join(tmp_dir, href.split('/')[-1])
 
152
 
144
153
        try:
145
 
            _fetch_to_raw(ctx, uuid, tmp_path, self._image_service)
 
154
            _fetch(ctx, href, tmp_path, self._image_service, force_raw)
146
155
            # NOTE(dtantsur): no need for global lock here - master_path
147
156
            # will have link count >1 at any moment, so won't be cleaned up
148
157
            os.link(tmp_path, master_path)
217
226
 
218
227
    def _clean_up_ensure_cache_size(self, listing, amount):
219
228
        """Clean up stage 2: try to ensure cache size < threshold.
 
229
 
220
230
        Try to delete the oldest files until conditions is satisfied
221
231
        or no more files are eligable for delition.
222
232
 
281
291
    return stat.f_frsize * stat.f_bavail
282
292
 
283
293
 
284
 
def _fetch_to_raw(context, image_href, path, image_service=None):
 
294
def _fetch(context, image_href, path, image_service=None, force_raw=False):
285
295
    """Fetch image and convert to raw format if needed."""
286
296
    path_tmp = "%s.part" % path
287
 
    images.fetch(context, image_href, path_tmp, image_service)
288
 
    required_space = images.converted_size(path_tmp)
289
 
    directory = os.path.dirname(path_tmp)
290
 
    _clean_up_caches(directory, required_space)
291
 
    images.image_to_raw(image_href, path, path_tmp)
 
297
    images.fetch(context, image_href, path_tmp, image_service,
 
298
                 force_raw=False)
 
299
    # Notes(yjiang5): If glance can provide the virtual size information,
 
300
    # then we can firstly clean cach and then invoke images.fetch().
 
301
    if force_raw:
 
302
        required_space = images.converted_size(path_tmp)
 
303
        directory = os.path.dirname(path_tmp)
 
304
        _clean_up_caches(directory, required_space)
 
305
        images.image_to_raw(image_href, path, path_tmp)
 
306
    else:
 
307
        os.rename(path_tmp, path)
292
308
 
293
309
 
294
310
def _clean_up_caches(directory, amount):