Support partition HTTP images in CLI
Also removed some dead code from sources. Change-Id: I570eda45285771068711ef90d22550632411e98f Story: #2002048 Task: #26208
This commit is contained in:
parent
2afd20938d
commit
fc85cb9230
@ -58,14 +58,21 @@ def _do_deploy(api, args, formatter):
|
|||||||
raise RuntimeError("%s cannot be used as a hostname" % args.hostname)
|
raise RuntimeError("%s cannot be used as a hostname" % args.hostname)
|
||||||
|
|
||||||
if _is_http(args.image):
|
if _is_http(args.image):
|
||||||
|
kwargs = {}
|
||||||
if not args.image_checksum:
|
if not args.image_checksum:
|
||||||
raise RuntimeError("HTTP(s) images require --image-checksum")
|
raise RuntimeError("HTTP(s) images require --image-checksum")
|
||||||
elif _is_http(args.image_checksum):
|
elif _is_http(args.image_checksum):
|
||||||
source = sources.HttpWholeDiskImage(
|
kwargs['checksum_url'] = args.image_checksum
|
||||||
args.image, checksum_url=args.image_checksum)
|
|
||||||
else:
|
else:
|
||||||
source = sources.HttpWholeDiskImage(
|
kwargs['checksum'] = args.image_checksum
|
||||||
args.image, checksum=args.image_checksum)
|
|
||||||
|
if args.image_kernel or args.image_ramdisk:
|
||||||
|
source = sources.HttpPartitionImage(args.image,
|
||||||
|
args.image_kernel,
|
||||||
|
args.image_ramdisk,
|
||||||
|
**kwargs)
|
||||||
|
else:
|
||||||
|
source = sources.HttpWholeDiskImage(args.image, **kwargs)
|
||||||
else:
|
else:
|
||||||
source = args.image
|
source = args.image
|
||||||
|
|
||||||
@ -145,6 +152,8 @@ def _parse_args(args, config):
|
|||||||
required=True)
|
required=True)
|
||||||
deploy.add_argument('--image-checksum',
|
deploy.add_argument('--image-checksum',
|
||||||
help='image MD5 checksum or URL with checksums')
|
help='image MD5 checksum or URL with checksums')
|
||||||
|
deploy.add_argument('--image-kernel', help='URL of the image\'s kernel')
|
||||||
|
deploy.add_argument('--image-ramdisk', help='URL of the image\'s ramdisk')
|
||||||
deploy.add_argument('--network', help='network to use (name or UUID)',
|
deploy.add_argument('--network', help='network to use (name or UUID)',
|
||||||
dest='nics', action=NICAction)
|
dest='nics', action=NICAction)
|
||||||
deploy.add_argument('--port', help='port to attach (name or UUID)',
|
deploy.add_argument('--port', help='port to attach (name or UUID)',
|
||||||
|
@ -90,8 +90,7 @@ class HttpWholeDiskImage(_Source):
|
|||||||
specifically, by **ironic-conductor** processes).
|
specifically, by **ironic-conductor** processes).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, url, checksum=None, checksum_url=None,
|
def __init__(self, url, checksum=None, checksum_url=None):
|
||||||
kernel_url=None, ramdisk_url=None):
|
|
||||||
"""Create an HTTP source.
|
"""Create an HTTP source.
|
||||||
|
|
||||||
:param url: URL of the image.
|
:param url: URL of the image.
|
||||||
@ -108,8 +107,6 @@ class HttpWholeDiskImage(_Source):
|
|||||||
self.url = url
|
self.url = url
|
||||||
self.checksum = checksum
|
self.checksum = checksum
|
||||||
self.checksum_url = checksum_url
|
self.checksum_url = checksum_url
|
||||||
self.kernel_url = kernel_url
|
|
||||||
self.ramdisk_url = ramdisk_url
|
|
||||||
|
|
||||||
def _validate(self, connection):
|
def _validate(self, connection):
|
||||||
# TODO(dtantsur): should we validate image URLs here? Ironic will do it
|
# TODO(dtantsur): should we validate image URLs here? Ironic will do it
|
||||||
@ -178,3 +175,70 @@ class HttpPartitionImage(HttpWholeDiskImage):
|
|||||||
updates['/instance_info/kernel'] = self.kernel_url
|
updates['/instance_info/kernel'] = self.kernel_url
|
||||||
updates['/instance_info/ramdisk'] = self.ramdisk_url
|
updates['/instance_info/ramdisk'] = self.ramdisk_url
|
||||||
return updates
|
return updates
|
||||||
|
|
||||||
|
|
||||||
|
class FileWholeDiskImage(_Source):
|
||||||
|
"""A whole-disk image from a local file location.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
The location must be local to the **ironic-conductor** process handling
|
||||||
|
the node, not to metalsmith itself! Since there is no easy way to
|
||||||
|
determine which conductor handles a node, the same file must be
|
||||||
|
available at the same location to all conductors in the same group.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, location, checksum):
|
||||||
|
"""Create a local file source.
|
||||||
|
|
||||||
|
:param location: Location of the image, optionally starting with
|
||||||
|
``file://``.
|
||||||
|
:param checksum: MD5 checksum of the image.
|
||||||
|
"""
|
||||||
|
if not location.startswith('file://'):
|
||||||
|
location = 'file://' + location
|
||||||
|
self.location = location
|
||||||
|
self.checksum = checksum
|
||||||
|
|
||||||
|
def _node_updates(self, connection):
|
||||||
|
LOG.debug('Image: %(image)s, checksum %(checksum)s',
|
||||||
|
{'image': self.location, 'checksum': self.checksum})
|
||||||
|
return {
|
||||||
|
'/instance_info/image_source': self.location,
|
||||||
|
'/instance_info/image_checksum': self.checksum,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FilePartitionImage(_Source):
|
||||||
|
"""A partition image from a local file location.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
The location must be local to the **ironic-conductor** process handling
|
||||||
|
the node, not to metalsmith itself! Since there is no easy way to
|
||||||
|
determine which conductor handles a node, the same file must be
|
||||||
|
available at the same location to all conductors in the same group.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, location, kernel_location, ramdisk_location, checksum):
|
||||||
|
"""Create a local file source.
|
||||||
|
|
||||||
|
:param location: Location of the image, optionally starting with
|
||||||
|
``file://``.
|
||||||
|
:param kernel_location: Location of the kernel of the image,
|
||||||
|
optionally starting with ``file://``.
|
||||||
|
:param ramdisk_location: Location of the ramdisk of the image,
|
||||||
|
optionally starting with ``file://``.
|
||||||
|
:param checksum: MD5 checksum of the image.
|
||||||
|
"""
|
||||||
|
super(FilePartitionImage, self).__init__(location, checksum)
|
||||||
|
if not kernel_location.startswith('file://'):
|
||||||
|
kernel_location = 'file://' + kernel_location
|
||||||
|
if not ramdisk_location.startswith('file://'):
|
||||||
|
ramdisk_location = 'file://' + ramdisk_location
|
||||||
|
self.kernel_location = kernel_location
|
||||||
|
self.ramdisk_location = ramdisk_location
|
||||||
|
|
||||||
|
def _node_updates(self, connection):
|
||||||
|
updates = super(FilePartitionImage, self)._node_updates(connection)
|
||||||
|
updates['/instance_info/kernel'] = self.kernel_location
|
||||||
|
updates['/instance_info/ramdisk'] = self.ramdisk_location
|
||||||
|
return updates
|
||||||
|
@ -378,6 +378,21 @@ class TestDeploy(testtools.TestCase):
|
|||||||
self.assertFalse(mock_pr.return_value.reserve_node.called)
|
self.assertFalse(mock_pr.return_value.reserve_node.called)
|
||||||
self.assertFalse(mock_pr.return_value.provision_node.called)
|
self.assertFalse(mock_pr.return_value.provision_node.called)
|
||||||
|
|
||||||
|
def test_args_http_partition_image(self, mock_pr):
|
||||||
|
args = ['deploy', '--image', 'https://example.com/image.img',
|
||||||
|
'--image-kernel', 'https://example.com/kernel',
|
||||||
|
'--image-ramdisk', 'https://example.com/ramdisk',
|
||||||
|
'--image-checksum', '95e750180c7921ea0d545c7165db66b8',
|
||||||
|
'--network', 'mynet', '--resource-class', 'compute']
|
||||||
|
self._check(mock_pr, args, {}, {'image': mock.ANY})
|
||||||
|
|
||||||
|
source = mock_pr.return_value.provision_node.call_args[1]['image']
|
||||||
|
self.assertIsInstance(source, sources.HttpPartitionImage)
|
||||||
|
self.assertEqual('https://example.com/image.img', source.url)
|
||||||
|
self.assertEqual('https://example.com/kernel', source.kernel_url)
|
||||||
|
self.assertEqual('https://example.com/ramdisk', source.ramdisk_url)
|
||||||
|
self.assertEqual('95e750180c7921ea0d545c7165db66b8', source.checksum)
|
||||||
|
|
||||||
def test_args_custom_wait(self, mock_pr):
|
def test_args_custom_wait(self, mock_pr):
|
||||||
args = ['deploy', '--network', 'mynet', '--image', 'myimg',
|
args = ['deploy', '--network', 'mynet', '--image', 'myimg',
|
||||||
'--wait', '3600', '--resource-class', 'compute']
|
'--wait', '3600', '--resource-class', 'compute']
|
||||||
|
@ -24,6 +24,29 @@
|
|||||||
register: baremetal_endpoint_result
|
register: baremetal_endpoint_result
|
||||||
failed_when: baremetal_endpoint_result.stdout == ""
|
failed_when: baremetal_endpoint_result.stdout == ""
|
||||||
|
|
||||||
|
- name: Copy partition images directory
|
||||||
|
command: >
|
||||||
|
cp -r /opt/stack/devstack/files/images/{{ cirros_uec_image_result.stdout }}
|
||||||
|
/opt/stack/data/ironic/httpboot/metalsmith
|
||||||
|
args:
|
||||||
|
creates: /opt/stack/data/ironic/httpboot/metalsmith
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Create MD5 checksums file for partition images
|
||||||
|
shell: md5sum cirros-* > CHECKSUMS
|
||||||
|
args:
|
||||||
|
chdir: /opt/stack/data/ironic/httpboot/metalsmith
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Change ownership of image files
|
||||||
|
file:
|
||||||
|
path: /opt/stack/data/ironic/httpboot/metalsmith
|
||||||
|
state: directory
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
recurse: yes
|
||||||
|
mode: a+r
|
||||||
|
become: yes
|
||||||
|
|
||||||
- name: Calculate MD5 checksum for HTTP disk image
|
- name: Calculate MD5 checksum for HTTP disk image
|
||||||
shell: |
|
shell: |
|
||||||
md5sum /opt/stack/devstack/files/{{ cirros_disk_image_result.stdout }}.img \
|
md5sum /opt/stack/devstack/files/{{ cirros_disk_image_result.stdout }}.img \
|
||||||
@ -33,6 +56,10 @@
|
|||||||
|
|
||||||
- name: Set facts for HTTP image
|
- name: Set facts for HTTP image
|
||||||
set_fact:
|
set_fact:
|
||||||
|
metalsmith_partition_image: "{{ baremetal_endpoint_result.stdout}}/metalsmith/{{ cirros_uec_image_result.stdout | replace('-uec', '-blank') }}.img"
|
||||||
|
metalsmith_partition_kernel_image: "{{ baremetal_endpoint_result.stdout}}/metalsmith/{{ cirros_uec_image_result.stdout | replace('-uec', '-vmlinuz') }}"
|
||||||
|
metalsmith_partition_ramdisk_image: "{{ baremetal_endpoint_result.stdout}}/metalsmith/{{ cirros_uec_image_result.stdout | replace('-uec', '-initrd') }}"
|
||||||
|
metalsmith_partition_checksum: "{{ baremetal_endpoint_result.stdout}}/metalsmith/CHECKSUMS"
|
||||||
metalsmith_whole_disk_image: "{{ baremetal_endpoint_result.stdout}}/{{ cirros_disk_image_result.stdout }}.img"
|
metalsmith_whole_disk_image: "{{ baremetal_endpoint_result.stdout}}/{{ cirros_disk_image_result.stdout }}.img"
|
||||||
metalsmith_whole_disk_checksum: "{{ cirros_disk_image_checksum_result.stdout }}"
|
metalsmith_whole_disk_checksum: "{{ cirros_disk_image_checksum_result.stdout }}"
|
||||||
|
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
metalsmith_resource_class: baremetal
|
metalsmith_resource_class: baremetal
|
||||||
metalsmith_instances:
|
metalsmith_instances:
|
||||||
- hostname: test
|
- hostname: test
|
||||||
image: "{{ image }}"
|
|
||||||
image_checksum: "{{ image_checksum | default('') }}"
|
|
||||||
nics:
|
nics:
|
||||||
- "{{ nic }}"
|
- "{{ nic }}"
|
||||||
ssh_public_keys:
|
ssh_public_keys:
|
||||||
|
@ -11,15 +11,15 @@
|
|||||||
- name: Test a whole-disk image
|
- name: Test a whole-disk image
|
||||||
include: exercise.yaml
|
include: exercise.yaml
|
||||||
vars:
|
vars:
|
||||||
image: "{{ metalsmith_whole_disk_image }}"
|
metalsmith_image: "{{ metalsmith_whole_disk_image }}"
|
||||||
image_checksum: "{{ metalsmith_whole_disk_checksum | default('') }}"
|
metalsmith_image_checksum: "{{ metalsmith_whole_disk_checksum | default('') }}"
|
||||||
# NOTE(dtantsur): cannot specify swap with whole disk images
|
# NOTE(dtantsur): cannot specify swap with whole disk images
|
||||||
metalsmith_swap_size:
|
metalsmith_swap_size:
|
||||||
|
|
||||||
- name: Test a partition image
|
- name: Test a partition image
|
||||||
include: exercise.yaml
|
include: exercise.yaml
|
||||||
vars:
|
vars:
|
||||||
image: "{{ metalsmith_partition_image }}"
|
metalsmith_image: "{{ metalsmith_partition_image }}"
|
||||||
image_checksum: "{{ metalsmith_partition_checksum | default('') }}"
|
metalsmith_image_checksum: "{{ metalsmith_partition_checksum | default('') }}"
|
||||||
# FIXME(dtantsur): cover partition images
|
metalsmith_image_kernel: "{{ metalsmith_partition_kernel_image | default('') }}"
|
||||||
when: not (metalsmith_use_http | default(false))
|
metalsmith_image_ramdisk: "{{ metalsmith_partition_ramdisk_image | default('') }}"
|
||||||
|
@ -25,6 +25,10 @@ The following optional variables provide the defaults for Instance_ attributes:
|
|||||||
the default for ``image``.
|
the default for ``image``.
|
||||||
``metalsmith_image_checksum``
|
``metalsmith_image_checksum``
|
||||||
the default for ``image_checksum``.
|
the default for ``image_checksum``.
|
||||||
|
``metalsmith_image_kernel``
|
||||||
|
the default for ``image_kernel``.
|
||||||
|
``metalsmith_image_ramdisk``
|
||||||
|
the default for ``image_ramdisk``.
|
||||||
``metalsmith_netboot``
|
``metalsmith_netboot``
|
||||||
the default for ``netboot``
|
the default for ``netboot``
|
||||||
``metalsmith_nics``
|
``metalsmith_nics``
|
||||||
@ -62,6 +66,12 @@ Each instances has the following attributes:
|
|||||||
UUID, name or HTTP(s) URL of the image to use for deployment. Mandatory.
|
UUID, name or HTTP(s) URL of the image to use for deployment. Mandatory.
|
||||||
``image_checksum`` (defaults to ``metalsmith_image_checksum``)
|
``image_checksum`` (defaults to ``metalsmith_image_checksum``)
|
||||||
MD5 checksum or checksum file URL for an HTTP(s) image.
|
MD5 checksum or checksum file URL for an HTTP(s) image.
|
||||||
|
``image_kernel`` (defaults to ``metalsmith_image_kernel``)
|
||||||
|
URL of the kernel image if and only if the ``image`` is a URL of
|
||||||
|
a partition image.
|
||||||
|
``image_ramdisk`` (defaults to ``metalsmith_image_ramdisk``)
|
||||||
|
URL of the ramdisk image if and only if the ``image`` is a URL of
|
||||||
|
a partition image.
|
||||||
``netboot``
|
``netboot``
|
||||||
whether to boot the deployed instance from network (PXE, iPXE, etc).
|
whether to boot the deployed instance from network (PXE, iPXE, etc).
|
||||||
The default is to use local boot (requires a bootloader on the image).
|
The default is to use local boot (requires a bootloader on the image).
|
||||||
@ -152,3 +162,13 @@ Example
|
|||||||
nics:
|
nics:
|
||||||
- network: ctlplane
|
- network: ctlplane
|
||||||
- port: 1899af15-149d-47dc-b0dc-a68614eeb5c4
|
- port: 1899af15-149d-47dc-b0dc-a68614eeb5c4
|
||||||
|
- hostname: custom-partition-image
|
||||||
|
resource_class: custom
|
||||||
|
image: https://example.com/images/custom-1.0.root.img
|
||||||
|
image_kernel: https://example.com/images/custom-1.0.vmlinuz
|
||||||
|
image_ramdisk: https://example.com/images/custom-1.0.initrd
|
||||||
|
image_checksum: https://example.com/images/MD5SUMS
|
||||||
|
- hostname: custom-whole-disk-image
|
||||||
|
resource_class: custom
|
||||||
|
image: https://example.com/images/custom-1.0.qcow2
|
||||||
|
image_checksum: https://example.com/images/MD5SUMS
|
||||||
|
@ -4,6 +4,8 @@ metalsmith_capabilities: {}
|
|||||||
metalsmith_conductor_group:
|
metalsmith_conductor_group:
|
||||||
metalsmith_extra_args:
|
metalsmith_extra_args:
|
||||||
metalsmith_image_checksum:
|
metalsmith_image_checksum:
|
||||||
|
metalsmith_image_kernel:
|
||||||
|
metalsmith_image_ramdisk:
|
||||||
metalsmith_netboot: false
|
metalsmith_netboot: false
|
||||||
metalsmith_nics: []
|
metalsmith_nics: []
|
||||||
metalsmith_resource_class:
|
metalsmith_resource_class:
|
||||||
|
@ -24,6 +24,15 @@
|
|||||||
--ssh-public-key {{ ssh_key }}
|
--ssh-public-key {{ ssh_key }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
--image {{ image }}
|
--image {{ image }}
|
||||||
|
{% if image_checksum %}
|
||||||
|
--image-checksum {{ image_checksum }}
|
||||||
|
{% endif %}
|
||||||
|
{% if image_kernel %}
|
||||||
|
--image-kernel {{ image_kernel }}
|
||||||
|
{% endif %}
|
||||||
|
{% if image_ramdisk %}
|
||||||
|
--image-ramdisk {{ image_ramdisk }}
|
||||||
|
{% endif %}
|
||||||
--hostname {{ instance.hostname }}
|
--hostname {{ instance.hostname }}
|
||||||
{% if netboot %}
|
{% if netboot %}
|
||||||
--netboot
|
--netboot
|
||||||
@ -40,9 +49,6 @@
|
|||||||
{% for node in candidates %}
|
{% for node in candidates %}
|
||||||
--candidate {{ node }}
|
--candidate {{ node }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if image_checksum %}
|
|
||||||
--image-checksum {{ image_checksum }}
|
|
||||||
{% endif %}
|
|
||||||
when: state == 'present'
|
when: state == 'present'
|
||||||
vars:
|
vars:
|
||||||
candidates: "{{ instance.candidates | default(metalsmith_candidates) }}"
|
candidates: "{{ instance.candidates | default(metalsmith_candidates) }}"
|
||||||
@ -50,7 +56,9 @@
|
|||||||
conductor_group: "{{ instance.conductor_group | default(metalsmith_conductor_group) }}"
|
conductor_group: "{{ instance.conductor_group | default(metalsmith_conductor_group) }}"
|
||||||
extra_args: "{{ instance.extra_args | default(metalsmith_extra_args) }}"
|
extra_args: "{{ instance.extra_args | default(metalsmith_extra_args) }}"
|
||||||
image: "{{ instance.image | default(metalsmith_image) }}"
|
image: "{{ instance.image | default(metalsmith_image) }}"
|
||||||
image: "{{ instance.image_checksum | default(metalsmith_image_checksum) }}"
|
image_checksum: "{{ instance.image_checksum | default(metalsmith_image_checksum) }}"
|
||||||
|
image_kernel: "{{ instance.image_kernel | default(metalsmith_image_kernel) }}"
|
||||||
|
image_ramdisk: "{{ instance.image_ramdisk | default(metalsmith_image_ramdisk) }}"
|
||||||
netboot: "{{ instance.netboot | default(metalsmith_netboot) }}"
|
netboot: "{{ instance.netboot | default(metalsmith_netboot) }}"
|
||||||
nics: "{{ instance.nics | default(metalsmith_nics) }}"
|
nics: "{{ instance.nics | default(metalsmith_nics) }}"
|
||||||
resource_class: "{{ instance.resource_class | default(metalsmith_resource_class) }}"
|
resource_class: "{{ instance.resource_class | default(metalsmith_resource_class) }}"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user