Skip to content

Commit 620f05e

Browse files
Accept new parameters for prepare_image
The parameters sent to `prepare_image` changed in https://review.openstack.org/#/c/86490/ This patch brings `prepare_image` up to date with that change. It also changes the way configdrive is written to disk, to match that Ironic is now allowing Nova to build an ISO partition and send the raw image to the agent. This patch also swaps out subprocess.call for processutils.execute in the standby module, since the commands were being changed anyway. Lastly, this patch changes the expected `hashes` dict to be a string parameter called `checksum`, to match what glance returns. Change-Id: Id8af9be920ba51e7e1ce60f4ffd1477e413582c9
1 parent ab46681 commit 620f05e

File tree

4 files changed

+113
-111
lines changed

4 files changed

+113
-111
lines changed

ironic_python_agent/cmd/agent.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
from ironic_python_agent.openstack.common import log
1919

2020

21-
LOG = log.getLogger()
21+
log.setup('ironic-python-agent')
22+
LOG = log.getLogger(__name__)
2223

2324

2425
def _get_kernel_params():

ironic_python_agent/extensions/standby.py

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,20 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import base64
16+
import gzip
1517
import hashlib
1618
import os
1719
import requests
18-
import subprocess
20+
import six
21+
import StringIO
1922
import time
2023

21-
from ironic_python_agent import configdrive
2224
from ironic_python_agent import errors
2325
from ironic_python_agent.extensions import base
2426
from ironic_python_agent import hardware
2527
from ironic_python_agent.openstack.common import log
28+
from ironic_python_agent import utils
2629

2730
LOG = log.getLogger(__name__)
2831

@@ -47,28 +50,41 @@ def _write_image(image_info, device):
4750
script = _path_to_script('shell/write_image.sh')
4851
command = ['/bin/bash', script, image, device]
4952
LOG.info('Writing image with command: {0}'.format(' '.join(command)))
50-
exit_code = subprocess.call(command)
53+
exit_code = utils.execute(*command)
5154
if exit_code != 0:
5255
raise errors.ImageWriteError(exit_code, device)
5356
totaltime = time.time() - starttime
5457
LOG.info('Image {0} written to device {1} in {2} seconds'.format(
5558
image, device, totaltime))
5659

5760

58-
def _copy_configdrive_to_disk(configdrive_dir, device):
61+
def _write_configdrive_to_file(configdrive, filename):
62+
LOG.debug('Writing configdrive to {0}'.format(filename))
63+
# configdrive data is base64'd, decode it first
64+
data = StringIO.StringIO(base64.b64decode(configdrive))
65+
gunzipped = gzip.GzipFile('configdrive', 'rb', 9, data)
66+
with open(filename, 'wb') as f:
67+
f.write(gunzipped.read())
68+
gunzipped.close()
69+
70+
71+
def _write_configdrive_to_partition(configdrive, device):
72+
filename = _configdrive_location()
73+
_write_configdrive_to_file(configdrive, filename)
74+
5975
starttime = time.time()
6076
script = _path_to_script('shell/copy_configdrive_to_disk.sh')
61-
command = ['/bin/bash', script, configdrive_dir, device]
77+
command = ['/bin/bash', script, filename, device]
6278
LOG.info('copying configdrive to disk with command {0}'.format(
6379
' '.join(command)))
64-
exit_code = subprocess.call(command)
80+
exit_code = utils.execute(*command)
6581

6682
if exit_code != 0:
6783
raise errors.ConfigDriveWriteError(exit_code, device)
6884

6985
totaltime = time.time() - starttime
7086
LOG.info('configdrive copied from {0} to {1} in {2} seconds'.format(
71-
configdrive_dir,
87+
configdrive,
7288
device,
7389
totaltime))
7490

@@ -114,28 +130,22 @@ def _download_image(image_info):
114130

115131

116132
def _verify_image(image_info, image_location):
117-
hashes = image_info['hashes']
118-
for k, v in hashes.items():
119-
algo = getattr(hashlib, k, None)
120-
if algo is None:
121-
continue
122-
log_msg = 'Verifying image at {0} with algorithm {1} against hash {2}'
123-
LOG.debug(log_msg.format(image_location, k, v))
124-
hash_ = algo(open(image_location).read()).hexdigest()
125-
if hash_ == v:
126-
return True
127-
else:
128-
log_msg = ('Image verification failed. Location: {0};'
129-
'algorithm: {1}; image hash: {2};'
130-
'verification hash: {3}')
131-
LOG.warning(log_msg.format(image_location, k, hash_, v))
133+
checksum = image_info['checksum']
134+
log_msg = 'Verifying image at {0} against MD5 checksum {1}'
135+
LOG.debug(log_msg.format(image_location, checksum))
136+
hash_ = hashlib.md5(open(image_location).read()).hexdigest()
137+
if hash_ == checksum:
138+
return True
139+
log_msg = ('Image verification failed. Location: {0};'
140+
'image hash: {1}; verification hash: {2}')
141+
LOG.warning(log_msg.format(image_location, checksum, hash_))
132142
return False
133143

134144

135145
def _validate_image_info(ext, image_info=None, **kwargs):
136146
image_info = image_info or {}
137147

138-
for field in ['id', 'urls', 'hashes']:
148+
for field in ['id', 'urls', 'checksum']:
139149
if field not in image_info:
140150
msg = 'Image is missing \'{0}\' field.'.format(field)
141151
raise errors.InvalidCommandParamsError(msg)
@@ -144,10 +154,10 @@ def _validate_image_info(ext, image_info=None, **kwargs):
144154
raise errors.InvalidCommandParamsError(
145155
'Image \'urls\' must be a list with at least one element.')
146156

147-
if type(image_info['hashes']) != dict or not image_info['hashes']:
157+
if (not isinstance(image_info['checksum'], six.string_types)
158+
or not image_info['checksum']):
148159
raise errors.InvalidCommandParamsError(
149-
'Image \'hashes\' must be a dictionary with at least one '
150-
'element.')
160+
'Image \'checksum\' must be a non-empty string.')
151161

152162

153163
class StandbyExtension(base.BaseAgentExtension):
@@ -171,9 +181,7 @@ def cache_image(self, image_info=None, force=False):
171181
@base.async_command(_validate_image_info)
172182
def prepare_image(self,
173183
image_info=None,
174-
metadata=None,
175-
files=None):
176-
location = _configdrive_location()
184+
configdrive=None):
177185
device = hardware.get_manager().get_os_install_device()
178186

179187
# don't write image again if already cached
@@ -182,16 +190,14 @@ def prepare_image(self,
182190
_write_image(image_info, device)
183191
self.cached_image_id = image_info['id']
184192

185-
LOG.debug('Writing configdrive to {0}'.format(location))
186-
configdrive.write_configdrive(location, metadata, files)
187-
_copy_configdrive_to_disk(location, device)
193+
_write_configdrive_to_partition(configdrive, device)
188194

189195
@base.async_command()
190196
def run_image(self):
191197
script = _path_to_script('shell/reboot.sh')
192198
LOG.info('Rebooting system')
193199
command = ['/bin/bash', script]
194200
# this should never return if successful
195-
exit_code = subprocess.call(command)
201+
exit_code = utils.execute(*command)
196202
if exit_code != 0:
197203
raise errors.SystemRebootError(exit_code)

ironic_python_agent/shell/copy_configdrive_to_disk.sh

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,28 @@ log() {
2222

2323
usage() {
2424
[[ -z "$1" ]] || echo -e "USAGE ERROR: $@\n"
25-
echo "`basename $0`: CONFIGDRIVE_DIR DEVICE"
26-
echo " - This script injects CONFIGDRIVE_DIR contents as an iso9660"
25+
echo "`basename $0`: CONFIGDRIVE DEVICE"
26+
echo " - This script injects CONFIGDRIVE contents as an iso9660"
2727
echo " filesystem on a partition at the end of DEVICE."
2828
exit 1
2929
}
3030

31-
CONFIGDRIVE_DIR="$1"
31+
CONFIGDRIVE="$1"
3232
DEVICE="$2"
3333

34-
[[ -d $CONFIGDRIVE_DIR ]] || usage "$CONFIGDRIVE_DIR (CONFIGDRIVE_DIR) is not a directory"
34+
[[ -f $CONFIGDRIVE ]] || usage "$CONFIGDRIVE (CONFIGDRIVE) is not a regular file"
3535
[[ -b $DEVICE ]] || usage "$DEVICE (DEVICE) is not a block device"
3636

3737
# Create small partition at the end of the device
3838
log "Adding configdrive partition to $DEVICE"
39-
parted -a optimal -s -- $DEVICE mkpart primary ext2 -16MiB -0
39+
parted -a optimal -s -- $DEVICE mkpart primary ext2 -64MiB -0
4040

4141
# Find partition we just created
4242
# Dump all partitions, ignore empty ones, then get the last partition ID
4343
ISO_PARTITION=`sfdisk --dump $DEVICE | grep -v ' 0,' | tail -n1 | awk '{print $1}'`
4444

4545
# This generates the ISO image of the config drive.
46-
log "Writing Configdrive contents in $CONFIGDRIVE_DIR to $ISO_PARTITION"
47-
genisoimage \
48-
-o ${ISO_PARTITION} \
49-
-ldots \
50-
-input-charset 'utf-8' \
51-
-allow-lowercase \
52-
-allow-multidot \
53-
-l \
54-
-publisher "ironic" \
55-
-J \
56-
-r \
57-
-V 'config-2' \
58-
${CONFIGDRIVE_DIR}
46+
log "Writing Configdrive contents in $CONFIGDRIVE to $ISO_PARTITION"
47+
dd if=$CONFIGDRIVE of=$ISO_PARTITION bs=64K oflag=direct
5948

6049
log "${DEVICE} imaged successfully!"

0 commit comments

Comments
 (0)