64
61
file_size = os.path.getsize(infile)
65
62
if resize and file_size < FLAGS.minimum_root_size:
66
63
last_sector = FLAGS.minimum_root_size / sector_size - 1
67
yield execute('dd if=/dev/zero of=%s count=1 seek=%d bs=%d'
68
% (infile, last_sector, sector_size))
69
yield execute('e2fsck -fp %s' % infile, check_exit_code=False)
70
yield execute('resize2fs %s' % infile)
64
execute('dd if=/dev/zero of=%s count=1 seek=%d bs=%d'
65
% (infile, last_sector, sector_size))
66
execute('e2fsck -fp %s' % infile, check_exit_code=False)
67
execute('resize2fs %s' % infile)
71
68
file_size = FLAGS.minimum_root_size
72
69
elif file_size % sector_size != 0:
73
logging.warn("Input partition size not evenly divisible by"
74
" sector size: %d / %d", file_size, sector_size)
70
logging.warn(_("Input partition size not evenly divisible by"
71
" sector size: %d / %d"), file_size, sector_size)
75
72
primary_sectors = file_size / sector_size
76
73
if local_bytes % sector_size != 0:
77
logging.warn("Bytes for local storage not evenly divisible"
78
" by sector size: %d / %d", local_bytes, sector_size)
74
logging.warn(_("Bytes for local storage not evenly divisible"
75
" by sector size: %d / %d"), local_bytes, sector_size)
79
76
local_sectors = local_bytes / sector_size
86
83
last_sector = local_last # e
88
85
# create an empty file
89
yield execute('dd if=/dev/zero of=%s count=1 seek=%d bs=%d'
90
% (outfile, mbr_last, sector_size))
86
execute('dd if=/dev/zero of=%s count=1 seek=%d bs=%d'
87
% (outfile, mbr_last, sector_size))
92
89
# make mbr partition
93
yield execute('parted --script %s mklabel msdos' % outfile)
90
execute('parted --script %s mklabel msdos' % outfile)
95
92
# append primary file
96
yield execute('dd if=%s of=%s bs=%s conv=notrunc,fsync oflag=append'
97
% (infile, outfile, FLAGS.block_size))
93
execute('dd if=%s of=%s bs=%s conv=notrunc,fsync oflag=append'
94
% (infile, outfile, FLAGS.block_size))
99
96
# make primary partition
100
yield execute('parted --script %s mkpart primary %ds %ds'
101
% (outfile, primary_first, primary_last))
97
execute('parted --script %s mkpart primary %ds %ds'
98
% (outfile, primary_first, primary_last))
103
100
if local_bytes > 0:
104
101
# make the file bigger
105
yield execute('dd if=/dev/zero of=%s count=1 seek=%d bs=%d'
106
% (outfile, last_sector, sector_size))
102
execute('dd if=/dev/zero of=%s count=1 seek=%d bs=%d'
103
% (outfile, last_sector, sector_size))
107
104
# make and format local partition
108
yield execute('parted --script %s mkpartfs primary %s %ds %ds'
109
% (outfile, local_type, local_first, local_last))
112
@defer.inlineCallbacks
105
execute('parted --script %s mkpartfs primary %s %ds %ds'
106
% (outfile, local_type, local_first, local_last))
109
def extend(image, size, execute):
110
file_size = os.path.getsize(image)
111
if file_size >= size:
113
return execute('truncate -s size %s' % (image,))
113
116
def inject_data(image, key=None, net=None, partition=None, execute=None):
114
117
"""Injects a ssh key and optionally net data into a disk image.
119
122
If partition is not specified it mounts the image as a single partition.
122
out, err = yield execute('sudo losetup -f --show %s' % image)
125
out, err = execute('sudo losetup --find --show %s' % image)
124
raise exception.Error('Could not attach image to loopback: %s' % err)
127
raise exception.Error(_('Could not attach image to loopback: %s')
125
129
device = out.strip()
127
131
if not partition is None:
128
132
# create partition
129
out, err = yield execute('sudo kpartx -a %s' % device)
133
out, err = execute('sudo kpartx -a %s' % device)
131
raise exception.Error('Failed to load partition: %s' % err)
135
raise exception.Error(_('Failed to load partition: %s') % err)
132
136
mapped_device = '/dev/mapper/%sp%s' % (device.split('/')[-1],
135
139
mapped_device = device
136
out, err = yield execute('sudo tune2fs -c 0 -i 0 %s' % mapped_device)
141
# We can only loopback mount raw images. If the device isn't there,
142
# it's normally because it's a .vmdk or a .vdi etc
143
if not os.path.exists(mapped_device):
144
raise exception.Error('Mapped device was not found (we can'
145
' only inject raw disk images): %s' %
148
# Configure ext2fs so that it doesn't auto-check every N boots
149
out, err = execute('sudo tune2fs -c 0 -i 0 %s' % mapped_device)
138
151
tmpdir = tempfile.mkdtemp()
140
153
# mount loopback to dir
141
out, err = yield execute(
142
155
'sudo mount %s %s' % (mapped_device, tmpdir))
144
raise exception.Error('Failed to mount filesystem: %s' % err)
157
raise exception.Error(_('Failed to mount filesystem: %s')
148
162
# inject key file
149
yield _inject_key_into_fs(key, tmpdir, execute=execute)
163
_inject_key_into_fs(key, tmpdir, execute=execute)
151
yield _inject_net_into_fs(net, tmpdir, execute=execute)
165
_inject_net_into_fs(net, tmpdir, execute=execute)
154
yield execute('sudo umount %s' % mapped_device)
168
execute('sudo umount %s' % mapped_device)
156
170
# remove temporary directory
157
yield execute('rmdir %s' % tmpdir)
171
execute('rmdir %s' % tmpdir)
158
172
if not partition is None:
159
173
# remove partitions
160
yield execute('sudo kpartx -d %s' % device)
174
execute('sudo kpartx -d %s' % device)
162
176
# remove loopback
163
yield execute('sudo losetup -d %s' % device)
166
@defer.inlineCallbacks
177
execute('sudo losetup --detach %s' % device)
167
180
def _inject_key_into_fs(key, fs, execute=None):
168
181
"""Add the given public ssh key to root's authorized_keys.
170
183
key is an ssh key string.
171
184
fs is the path to the base of the filesystem into which to inject the key.
173
sshdir = os.path.join(os.path.join(fs, 'root'), '.ssh')
174
yield execute('sudo mkdir -p %s' % sshdir) # existing dir doesn't matter
175
yield execute('sudo chown root %s' % sshdir)
176
yield execute('sudo chmod 700 %s' % sshdir)
186
sshdir = os.path.join(fs, 'root', '.ssh')
187
execute('sudo mkdir -p %s' % sshdir) # existing dir doesn't matter
188
execute('sudo chown root %s' % sshdir)
189
execute('sudo chmod 700 %s' % sshdir)
177
190
keyfile = os.path.join(sshdir, 'authorized_keys')
178
yield execute('sudo tee -a %s' % keyfile, '\n' + key.strip() + '\n')
181
@defer.inlineCallbacks
191
execute('sudo tee -a %s' % keyfile, '\n' + key.strip() + '\n')
182
194
def _inject_net_into_fs(net, fs, execute=None):
183
195
"""Inject /etc/network/interfaces into the filesystem rooted at fs.
185
197
net is the contents of /etc/network/interfaces.
187
199
netdir = os.path.join(os.path.join(fs, 'etc'), 'network')
188
yield execute('sudo mkdir -p %s' % netdir) # existing dir doesn't matter
189
yield execute('sudo chown root:root %s' % netdir)
190
yield execute('sudo chmod 755 %s' % netdir)
200
execute('sudo mkdir -p %s' % netdir) # existing dir doesn't matter
201
execute('sudo chown root:root %s' % netdir)
202
execute('sudo chmod 755 %s' % netdir)
191
203
netfile = os.path.join(netdir, 'interfaces')
192
yield execute('sudo tee %s' % netfile, net)
204
execute('sudo tee %s' % netfile, net)