Commit 5da9c082 authored by Łukasz Nowak's avatar Łukasz Nowak

kvm: Improve boot image url handling

image-download-controller raises error state during download process, to
inform other components that download is not ready yet.

template-kvm-run.in asserts presence of all images and otherwise refuses to
start, so that it gives chance for the image to being downloaded.

Sorting images happen by proper key instead of needless links.

Fix race condition, as the hash parameter shall depend on boot image url
configuration, and not it's failure state.
parent a9e7b041
...@@ -19,7 +19,7 @@ md5sum = 087f226ba90928dcc5a722d7008c867a ...@@ -19,7 +19,7 @@ md5sum = 087f226ba90928dcc5a722d7008c867a
[template-kvm] [template-kvm]
filename = instance-kvm.cfg.jinja2 filename = instance-kvm.cfg.jinja2
md5sum = baa3ee5b653731124bfc2ac2fa835787 md5sum = 2ff55931eab48f7992e8e1cb16b44b95
[template-kvm-cluster] [template-kvm-cluster]
filename = instance-kvm-cluster.cfg.jinja2.in filename = instance-kvm-cluster.cfg.jinja2.in
...@@ -55,7 +55,7 @@ md5sum = a8cf453d20f01c707f02c4b4014580d8 ...@@ -55,7 +55,7 @@ md5sum = a8cf453d20f01c707f02c4b4014580d8
[template-kvm-run] [template-kvm-run]
filename = template/template-kvm-run.in filename = template/template-kvm-run.in
md5sum = 875261817970d0f83335824373288b9d md5sum = 395ee373ccda3382d257fde1ff4222b0
[template-kvm-controller] [template-kvm-controller]
filename = template/kvm-controller-run.in filename = template/kvm-controller-run.in
...@@ -79,11 +79,11 @@ md5sum = d57764bb7135037b4d21543b2f56ce1d ...@@ -79,11 +79,11 @@ md5sum = d57764bb7135037b4d21543b2f56ce1d
[image-download-controller] [image-download-controller]
filename = template/image-download-controller.py filename = template/image-download-controller.py
md5sum = 9c67058edcc4edae0b57956c0932a9fc md5sum = 4d48b3da5bc611fc6533335b5953c840
[image-download-config-creator] [image-download-config-creator]
filename = template/image-download-config-creator.py filename = template/image-download-config-creator.py
md5sum = 54261e418ab9860efe73efd514c4d47f md5sum = 8fbe05c4175a7f31b6bffced9ad4e91d
[whitelist-firewall-download-controller] [whitelist-firewall-download-controller]
filename = template/whitelist-firewall-download-controller.py filename = template/whitelist-firewall-download-controller.py
......
...@@ -162,7 +162,8 @@ config-filename = ${boot-image-url-select-json-config:error-state-file} ...@@ -162,7 +162,8 @@ config-filename = ${boot-image-url-select-json-config:error-state-file}
# wrapper to execute boot-image-url-select-download on each run # wrapper to execute boot-image-url-select-download on each run
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:scripts}/boot-image-url-select-updater wrapper-path = ${directory:scripts}/boot-image-url-select-updater
command-line = {{ python_executable }} {{ image_download_controller }} ${boot-image-url-select-json-config:rendered} {{ curl_executable_location }} ${:md5sum-state-file} ${:error-state-file} ${boot-image-url-select-processed-config:processed-md5sum} command-line = {{ python_executable }} {{ image_download_controller }} ${:config} {{ curl_executable_location }} ${:md5sum-state-file} ${:error-state-file} ${boot-image-url-select-processed-config:processed-md5sum}
config = ${boot-image-url-select-json-config:rendered}
md5sum-state-filename = boot-image-url-select-download-controller-md5sum-fail.json md5sum-state-filename = boot-image-url-select-download-controller-md5sum-fail.json
md5sum-state-file = ${directory:boot-image-url-select-expose}/${:md5sum-state-filename} md5sum-state-file = ${directory:boot-image-url-select-expose}/${:md5sum-state-filename}
error-state-filename = boot-image-url-select-download-controller-error.text error-state-filename = boot-image-url-select-download-controller-error.text
...@@ -258,7 +259,8 @@ config-filename = ${boot-image-url-list-json-config:error-state-file} ...@@ -258,7 +259,8 @@ config-filename = ${boot-image-url-list-json-config:error-state-file}
# wrapper to execute boot-image-url-list-download on each run # wrapper to execute boot-image-url-list-download on each run
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:scripts}/boot-image-url-list-updater wrapper-path = ${directory:scripts}/boot-image-url-list-updater
command-line = {{ python_executable }} {{ image_download_controller }} ${boot-image-url-list-json-config:rendered} {{ curl_executable_location }} ${:md5sum-state-file} ${:error-state-file} ${boot-image-url-list-processed-config:processed-md5sum} command-line = {{ python_executable }} {{ image_download_controller }} ${:config} {{ curl_executable_location }} ${:md5sum-state-file} ${:error-state-file} ${boot-image-url-list-processed-config:processed-md5sum}
config = ${boot-image-url-list-json-config:rendered}
md5sum-state-filename = boot-image-url-list-download-controller-md5sum-fail.json md5sum-state-filename = boot-image-url-list-download-controller-md5sum-fail.json
md5sum-state-file = ${directory:boot-image-url-list-expose}/${:md5sum-state-filename} md5sum-state-file = ${directory:boot-image-url-list-expose}/${:md5sum-state-filename}
error-state-filename = boot-image-url-list-download-controller-error.text error-state-filename = boot-image-url-list-download-controller-error.text
...@@ -355,7 +357,8 @@ config-filename = ${virtual-hard-drive-url-json-config:error-state-file} ...@@ -355,7 +357,8 @@ config-filename = ${virtual-hard-drive-url-json-config:error-state-file}
# wrapper to execute virtual-hard-drive-url-download on each run # wrapper to execute virtual-hard-drive-url-download on each run
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:scripts}/virtual-hard-drive-url-updater wrapper-path = ${directory:scripts}/virtual-hard-drive-url-updater
command-line = {{ python_executable }} {{ image_download_controller }} ${virtual-hard-drive-url-json-config:rendered} {{ curl_executable_location }} ${:md5sum-state-file} ${:error-state-file} ${virtual-hard-drive-url-processed-config:processed-md5sum} command-line = {{ python_executable }} {{ image_download_controller }} ${:config} {{ curl_executable_location }} ${:md5sum-state-file} ${:error-state-file} ${virtual-hard-drive-url-processed-config:processed-md5sum}
config = ${virtual-hard-drive-url-json-config:rendered}
md5sum-state-filename = virtual-hard-drive-url-download-controller-md5sum-fail.json md5sum-state-filename = virtual-hard-drive-url-download-controller-md5sum-fail.json
md5sum-state-file = ${directory:virtual-hard-drive-url-expose}/${:md5sum-state-filename} md5sum-state-file = ${directory:virtual-hard-drive-url-expose}/${:md5sum-state-filename}
error-state-filename = virtual-hard-drive-url-download-controller-error.text error-state-filename = virtual-hard-drive-url-download-controller-error.text
...@@ -547,13 +550,13 @@ command = [ ! -f {{ '${' + key + '}' }} ] && touch {{ '${' + key + '}' }} ...@@ -547,13 +550,13 @@ command = [ ! -f {{ '${' + key + '}' }} ] && touch {{ '${' + key + '}' }}
{%- endmacro %} {%- endmacro %}
{#- Create depending sections, as state files appear late, so it's better to have empty file which will impact the hash anyway #} {#- Create depending sections, as state files appear late, so it's better to have empty file which will impact the hash anyway #}
{%- if boot_image_url_list_enabled %} {%- if boot_image_url_list_enabled %}
{{ generate_depend_section('boot-image-url-list-depend', 'boot-image-url-list-download-wrapper:md5sum-state-file') }} {{ generate_depend_section('boot-image-url-list-depend', 'boot-image-url-list-download-wrapper:config') }}
{%- endif %} {%- endif %}
{%- if boot_image_url_select_enabled %} {%- if boot_image_url_select_enabled %}
{{ generate_depend_section('boot-image-url-select-depend', 'boot-image-url-select-download-wrapper:md5sum-state-file') }} {{ generate_depend_section('boot-image-url-select-depend', 'boot-image-url-select-download-wrapper:config') }}
{%- endif %} {%- endif %}
{%- if virtual_hard_drive_url_enabled %} {%- if virtual_hard_drive_url_enabled %}
{{ generate_depend_section('virtual-hard-drive-url-depend', 'virtual-hard-drive-url-download-wrapper:md5sum-state-file') }} {{ generate_depend_section('virtual-hard-drive-url-depend', 'virtual-hard-drive-url-download-wrapper:config') }}
{%- endif %} {%- endif %}
[kvm-instance] [kvm-instance]
......
...@@ -51,7 +51,7 @@ if __name__ == "__main__": ...@@ -51,7 +51,7 @@ if __name__ == "__main__":
'url': url, 'url': url,
'destination': md5sum, 'destination': md5sum,
'destination-tmp': md5sum + '_tmp', 'destination-tmp': md5sum + '_tmp',
'link': 'image_%03i' % (image_number,), 'image-number': '%03i' % (image_number,),
}) })
else: else:
print('INF: checksum %s repeated, used url %s' % (url, )) print('INF: checksum %s repeated, used url %s' % (url, ))
......
...@@ -41,11 +41,13 @@ if __name__ == "__main__": ...@@ -41,11 +41,13 @@ if __name__ == "__main__":
print('ERR: There are problems with configuration') print('ERR: There are problems with configuration')
print('INF: Storing errors in %s' % (error_state_file,)) print('INF: Storing errors in %s' % (error_state_file,))
# switch to error state during image download
with open(error_state_file, 'w') as fh:
fh.write('\n'.join(['INF Download in progress']))
# clean the destination directory # clean the destination directory
file_to_keep_list = [] file_to_keep_list = []
for image in config['image-list']: for image in config['image-list']:
file_to_keep_list.append(image['destination']) file_to_keep_list.append(image['destination'])
file_to_keep_list.append(image['link'])
for fname in os.listdir(config['destination-directory']): for fname in os.listdir(config['destination-directory']):
if fname not in file_to_keep_list: if fname not in file_to_keep_list:
print('INF: Removing obsolete %s' % (fname,)) print('INF: Removing obsolete %s' % (fname,))
...@@ -118,20 +120,6 @@ if __name__ == "__main__": ...@@ -118,20 +120,6 @@ if __name__ == "__main__":
os.rename(destination_tmp, destination) os.rename(destination_tmp, destination)
print('INF: %s : Stored with checksum %s' % ( print('INF: %s : Stored with checksum %s' % (
image['url'], image['md5sum'])) image['url'], image['md5sum']))
for image in config['image-list']:
destination = os.path.join(
config['destination-directory'], image['destination'])
link = os.path.join(config['destination-directory'], image['link'])
if os.path.exists(destination):
if os.path.lexists(link):
if not os.path.islink(link):
os.remove(link)
if os.path.islink(link) and os.readlink(link) != destination:
os.remove(link)
if not os.path.lexists(link):
print('INF: %s : Symlinking %s -> %s' % (
image['url'], link, destination))
os.symlink(destination, link)
with open(md5sum_fail_file, 'w') as fh: with open(md5sum_fail_file, 'w') as fh:
if new_md5sum_state_dict != {}: if new_md5sum_state_dict != {}:
json.dump(new_md5sum_state_dict, fh, indent=2) json.dump(new_md5sum_state_dict, fh, indent=2)
......
...@@ -329,6 +329,22 @@ if cpu_model: ...@@ -329,6 +329,22 @@ if cpu_model:
if rgx.match(cpu_model): if rgx.match(cpu_model):
kvm_argument_list.extend(['-cpu', cpu_model]) kvm_argument_list.extend(['-cpu', cpu_model])
def handle_image(config, name):
with open(config) as fh:
image_config = json.load(fh)
if image_config['error-amount'] == 0:
for image in sorted(image_config['image-list'], key=lambda k: k['image-number']):
destination = os.path.join(image_config['destination-directory'], image['destination'])
if os.path.exists(destination):
kvm_argument_list.extend([
'-drive',
'file=%s,media=cdrom' % (destination,)
])
else:
raise ValueError('%s not ready yet' % (name,))
else:
raise ValueError('%s not ready yet' % (name,))
# Try to connect to NBD server (and second nbd if defined). # Try to connect to NBD server (and second nbd if defined).
# If not available, don't even specify it in qemu command line parameters. # If not available, don't even specify it in qemu command line parameters.
# Reason: if qemu starts with unavailable NBD drive, it will just crash. # Reason: if qemu starts with unavailable NBD drive, it will just crash.
...@@ -350,33 +366,10 @@ else: ...@@ -350,33 +366,10 @@ else:
# Debian installation CDs, rendering it uninstallable # Debian installation CDs, rendering it uninstallable
if boot_image_url_select_json_config: if boot_image_url_select_json_config:
# Support boot-image-url-select # Support boot-image-url-select
with open(boot_image_url_select_json_config) as fh: handle_image(boot_image_url_select_json_config, 'boot-image-url-select')
image_config = json.load(fh)
if image_config['error-amount'] == 0:
for image in sorted(image_config['image-list'], key=lambda k: k['link']):
link = os.path.join(image_config['destination-directory'], image['link'])
if os.path.exists(link) and os.path.islink(link):
kvm_argument_list.extend([
'-drive',
'file=%s,media=cdrom' % (link,)
])
else:
raise ValueError('boot-image-url-select not ready yet')
if boot_image_url_list_json_config: if boot_image_url_list_json_config:
# Support boot-image-url-list # Support boot-image-url-list
with open(boot_image_url_list_json_config) as fh: handle_image(boot_image_url_list_json_config, 'boot-image-url-list')
image_config = json.load(fh)
if image_config['error-amount'] == 0:
for image in sorted(image_config['image-list'], key=lambda k: k['link']):
link = os.path.join(image_config['destination-directory'], image['link'])
if os.path.exists(link) and os.path.islink(link):
kvm_argument_list.extend([
'-drive',
'file=%s,media=cdrom' % (link,)
])
else:
raise ValueError('boot-image-url-list not ready yet')
# Always add by default the default image # Always add by default the default image
kvm_argument_list.extend([ kvm_argument_list.extend([
'-drive', 'file=%s,media=cdrom' % default_cdrom_iso '-drive', 'file=%s,media=cdrom' % default_cdrom_iso
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment