1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2012 Michael Still and Canonical Inc
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7
# not use this file except in compliance with the License. You may obtain
8
# a copy of the License at
10
# http://www.apache.org/licenses/LICENSE-2.0
12
# Unless required by applicable law or agreed to in writing, software
13
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
# License for the specific language governing permissions and limitations
18
"""Config Drive v2 helper."""
26
from nova.api.metadata import base as instance_metadata
27
from nova import exception
28
from nova import flags
29
from nova.openstack.common import cfg
30
from nova.openstack.common import log as logging
31
from nova import utils
32
from nova import version
33
from nova.virt.libvirt import utils as virtutils
35
LOG = logging.getLogger(__name__)
38
cfg.StrOpt('config_drive_format',
40
help='Config drive format. One of iso9660 (default) or vfat'),
41
cfg.StrOpt('config_drive_tempdir',
42
default=tempfile.tempdir,
43
help=('Where to put temporary files associated with '
44
'config drive creation')),
48
FLAGS.register_opts(configdrive_opts)
51
class ConfigDriveBuilder(object):
52
def __init__(self, instance_md=None):
55
# TODO(mikal): I don't think I can use utils.tempdir here, because
56
# I need to have the directory last longer than the scope of this
58
self.tempdir = tempfile.mkdtemp(dir=FLAGS.config_drive_tempdir,
61
if instance_md is not None:
62
self.add_instance_metadata(instance_md)
64
def _add_file(self, path, data):
65
filepath = os.path.join(self.tempdir, path)
66
dirname = os.path.dirname(filepath)
67
virtutils.ensure_tree(dirname)
68
with open(filepath, 'w') as f:
71
def add_instance_metadata(self, instance_md):
72
for (path, value) in instance_md.metadata_for_config_drive():
73
self._add_file(path, value)
74
LOG.debug(_('Added %(filepath)s to config drive'),
77
def _make_iso9660(self, path):
78
utils.execute('genisoimage',
84
'-publisher', ('"OpenStack nova %s"'
85
% version.version_string()),
94
def _make_vfat(self, path):
95
# NOTE(mikal): This is a little horrible, but I couldn't find an
96
# equivalent to genisoimage for vfat filesystems. vfat images are
98
with open(path, 'w') as f:
99
f.truncate(64 * 1024 * 1024)
101
virtutils.mkfs('vfat', path, label='config-2')
105
mountdir = tempfile.mkdtemp(dir=FLAGS.config_drive_tempdir,
107
_out, err = utils.trycmd('mount', '-o', 'loop', path, mountdir,
110
raise exception.ConfigDriveMountFailed(operation='mount',
114
_out, err = utils.trycmd('chown',
115
'%s.%s' % (os.getuid(), os.getgid()),
116
mountdir, run_as_root=True)
118
raise exception.ConfigDriveMountFailed(operation='chown',
121
# NOTE(mikal): I can't just use shutils.copytree here, because the
122
# destination directory already exists. This is annoying.
123
for ent in os.listdir(self.tempdir):
124
shutil.copytree(os.path.join(self.tempdir, ent),
125
os.path.join(mountdir, ent))
129
utils.execute('umount', mountdir, run_as_root=True)
130
shutil.rmtree(mountdir)
132
def make_drive(self, path):
133
if FLAGS.config_drive_format == 'iso9660':
134
self._make_iso9660(path)
135
elif FLAGS.config_drive_format == 'vfat':
136
self._make_vfat(path)
138
raise exception.ConfigDriveUnknownFormat(
139
format=FLAGS.config_drive_format)
143
utils.delete_if_exists(self.imagefile)
146
shutil.rmtree(self.tempdir)
148
LOG.error(_('Could not remove tmpdir: %s'), str(e))