summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ironic/drivers/modules/image_utils.py10
-rw-r--r--ironic/drivers/modules/pxe_base.py6
-rw-r--r--ironic/tests/unit/drivers/modules/test_image_utils.py37
-rw-r--r--ironic/tests/unit/drivers/modules/test_pxe.py12
-rw-r--r--releasenotes/config.yaml5
-rw-r--r--releasenotes/notes/fix-context-image-hardlink-16f452974abc7327.yaml7
-rw-r--r--releasenotes/notes/prevent-pxe-retry-when-token-exists-a4f38f7da56c1397.yaml7
-rw-r--r--reno.yaml4
-rw-r--r--tox.ini12
-rw-r--r--zuul.d/ironic-jobs.yaml2
-rw-r--r--zuul.d/project.yaml1
11 files changed, 88 insertions, 15 deletions
diff --git a/ironic/drivers/modules/image_utils.py b/ironic/drivers/modules/image_utils.py
index bb0dfa166..838189ca8 100644
--- a/ironic/drivers/modules/image_utils.py
+++ b/ironic/drivers/modules/image_utils.py
@@ -208,6 +208,16 @@ class ImageHandler(object):
try:
os.link(image_file, published_file)
os.chmod(image_file, self._file_permission)
+ try:
+ utils.execute(
+ '/usr/sbin/restorecon', '-i', '-R', 'v', public_dir)
+ except FileNotFoundError as exc:
+ LOG.debug(
+ "Could not restore SELinux context on "
+ "%(public_dir)s, restorecon command not found.\n"
+ "Error: %(error)s",
+ {'public_dir': public_dir,
+ 'error': exc})
except OSError as exc:
LOG.debug(
diff --git a/ironic/drivers/modules/pxe_base.py b/ironic/drivers/modules/pxe_base.py
index 317b65b85..78d7b5987 100644
--- a/ironic/drivers/modules/pxe_base.py
+++ b/ironic/drivers/modules/pxe_base.py
@@ -490,6 +490,12 @@ class PXEBaseMixin(object):
def _should_retry_boot(node):
# NOTE(dtantsur): this assumes IPA, do we need to make it generic?
for field in ('agent_last_heartbeat', 'last_power_state_change'):
+ if node.driver_internal_info.get('agent_secret_token', False):
+ LOG.debug('Not retrying PXE boot for node %(node)s; an agent '
+ 'token has been identified, meaning the agent '
+ 'has started.',
+ {'node': node.uuid})
+ return False
if manager_utils.value_within_timeout(
node.driver_internal_info.get(field),
CONF.pxe.boot_retry_timeout):
diff --git a/ironic/tests/unit/drivers/modules/test_image_utils.py b/ironic/tests/unit/drivers/modules/test_image_utils.py
index 6d79629d9..4e382fbbf 100644
--- a/ironic/tests/unit/drivers/modules/test_image_utils.py
+++ b/ironic/tests/unit/drivers/modules/test_image_utils.py
@@ -105,47 +105,70 @@ class RedfishImageHandlerTestCase(db_base.DbTestCase):
mock_swift_api.delete_object.assert_called_once_with(
'ironic_redfish_container', object_name)
+ @mock.patch.object(utils, 'execute', autospec=True)
@mock.patch.object(os, 'chmod', autospec=True)
@mock.patch.object(image_utils, 'shutil', autospec=True)
@mock.patch.object(os, 'link', autospec=True)
@mock.patch.object(os, 'mkdir', autospec=True)
def test_publish_image_local_link(
- self, mock_mkdir, mock_link, mock_shutil, mock_chmod):
+ self, mock_mkdir, mock_link, mock_shutil, mock_chmod,
+ mock_execute):
self.config(use_swift=False, group='redfish')
self.config(http_url='http://localhost', group='deploy')
img_handler_obj = image_utils.ImageHandler(self.node.driver)
-
url = img_handler_obj.publish_image('file.iso', 'boot.iso')
-
self.assertEqual(
'http://localhost/redfish/boot.iso', url)
+ mock_mkdir.assert_called_once_with('/httpboot/redfish', 0o755)
+ mock_link.assert_called_once_with(
+ 'file.iso', '/httpboot/redfish/boot.iso')
+ mock_chmod.assert_called_once_with('file.iso', 0o644)
+ mock_execute.assert_called_once_with(
+ '/usr/sbin/restorecon', '-i', '-R', 'v', '/httpboot/redfish')
+ @mock.patch.object(utils, 'execute', autospec=True)
+ @mock.patch.object(os, 'chmod', autospec=True)
+ @mock.patch.object(image_utils, 'shutil', autospec=True)
+ @mock.patch.object(os, 'link', autospec=True)
+ @mock.patch.object(os, 'mkdir', autospec=True)
+ def test_publish_image_local_link_no_restorecon(
+ self, mock_mkdir, mock_link, mock_shutil, mock_chmod,
+ mock_execute):
+ self.config(use_swift=False, group='redfish')
+ self.config(http_url='http://localhost', group='deploy')
+ img_handler_obj = image_utils.ImageHandler(self.node.driver)
+ url = img_handler_obj.publish_image('file.iso', 'boot.iso')
+ self.assertEqual(
+ 'http://localhost/redfish/boot.iso', url)
mock_mkdir.assert_called_once_with('/httpboot/redfish', 0o755)
mock_link.assert_called_once_with(
'file.iso', '/httpboot/redfish/boot.iso')
mock_chmod.assert_called_once_with('file.iso', 0o644)
+ mock_execute.return_value = FileNotFoundError
+ mock_shutil.assert_not_called()
+ @mock.patch.object(utils, 'execute', autospec=True)
@mock.patch.object(os, 'chmod', autospec=True)
@mock.patch.object(image_utils, 'shutil', autospec=True)
@mock.patch.object(os, 'link', autospec=True)
@mock.patch.object(os, 'mkdir', autospec=True)
def test_publish_image_external_ip(
- self, mock_mkdir, mock_link, mock_shutil, mock_chmod):
+ self, mock_mkdir, mock_link, mock_shutil, mock_chmod,
+ mock_execute):
self.config(use_swift=False, group='redfish')
self.config(http_url='http://localhost',
external_http_url='http://non-local.host',
group='deploy')
img_handler_obj = image_utils.ImageHandler(self.node.driver)
-
url = img_handler_obj.publish_image('file.iso', 'boot.iso')
-
self.assertEqual(
'http://non-local.host/redfish/boot.iso', url)
-
mock_mkdir.assert_called_once_with('/httpboot/redfish', 0o755)
mock_link.assert_called_once_with(
'file.iso', '/httpboot/redfish/boot.iso')
mock_chmod.assert_called_once_with('file.iso', 0o644)
+ mock_execute.assert_called_once_with(
+ '/usr/sbin/restorecon', '-i', '-R', 'v', '/httpboot/redfish')
@mock.patch.object(os, 'chmod', autospec=True)
@mock.patch.object(image_utils, 'shutil', autospec=True)
diff --git a/ironic/tests/unit/drivers/modules/test_pxe.py b/ironic/tests/unit/drivers/modules/test_pxe.py
index d999a8f7a..be48f890e 100644
--- a/ironic/tests/unit/drivers/modules/test_pxe.py
+++ b/ironic/tests/unit/drivers/modules/test_pxe.py
@@ -1277,6 +1277,18 @@ class PXEBootRetryTestCase(db_base.DbTestCase):
mock_boot_dev.assert_called_once_with(task, 'pxe',
persistent=False)
+ def test_check_boot_status_not_retry_with_token(self, mock_power,
+ mock_boot_dev):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ task.node.driver_internal_info = {
+ 'agent_secret_token': 'xyz'
+ }
+ task.driver.boot._check_boot_status(task)
+ self.assertTrue(task.shared)
+ mock_power.assert_not_called()
+ mock_boot_dev.assert_not_called()
+
class iPXEBootRetryTestCase(PXEBootRetryTestCase):
diff --git a/releasenotes/config.yaml b/releasenotes/config.yaml
new file mode 100644
index 000000000..26538010e
--- /dev/null
+++ b/releasenotes/config.yaml
@@ -0,0 +1,5 @@
+---
+# Ignore the kilo-eol tag because that branch does not work with reno
+# and contains no release notes.
+# Ignore bugfix tags because their releasenotes are covered under stable
+closed_branch_tag_re: 'r"(?!^(kilo-|bugfix-)).+-eol$"'
diff --git a/releasenotes/notes/fix-context-image-hardlink-16f452974abc7327.yaml b/releasenotes/notes/fix-context-image-hardlink-16f452974abc7327.yaml
new file mode 100644
index 000000000..90d38d5cc
--- /dev/null
+++ b/releasenotes/notes/fix-context-image-hardlink-16f452974abc7327.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+ - |
+ Fixes an issue where if selinux is enabled and enforcing, and
+ the published image is a hardlink, the source selinux context
+ is preserved, causing access denied when retrieving the image
+ using hardlink URL.
diff --git a/releasenotes/notes/prevent-pxe-retry-when-token-exists-a4f38f7da56c1397.yaml b/releasenotes/notes/prevent-pxe-retry-when-token-exists-a4f38f7da56c1397.yaml
new file mode 100644
index 000000000..5db6db6ec
--- /dev/null
+++ b/releasenotes/notes/prevent-pxe-retry-when-token-exists-a4f38f7da56c1397.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+ - |
+ Fixes a race condition in PXE initialization where logic to retry
+ what we suspect as potentially failed PXE boot operations was not
+ consulting if an ``agent token`` had been established, which is the
+ very first step in agent initialization.
diff --git a/reno.yaml b/reno.yaml
deleted file mode 100644
index dd0aac790..000000000
--- a/reno.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-# Ignore the kilo-eol tag because that branch does not work with reno
-# and contains no release notes.
-closed_branch_tag_re: "(.+)(?<!kilo)-eol"
diff --git a/tox.ini b/tox.ini
index cffaa8f1d..363ef8918 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,14 +1,15 @@
[tox]
minversion = 3.18.0
-skipsdist = True
envlist = py3,pep8
ignore_basepython_conflict=true
+requires =
+ tox<4
[testenv]
usedevelop = True
basepython = python3
setenv = VIRTUAL_ENV={envdir}
- PYTHONDONTWRITEBYTECODE = 1
+ PYTHONDONTWRITEBYTECODE=1
LANGUAGE=en_US
LC_ALL=en_US.UTF-8
PYTHONWARNINGS=default::DeprecationWarning
@@ -18,7 +19,12 @@ deps =
-r{toxinidir}/test-requirements.txt
commands =
stestr run --slowest {posargs}
-passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
+passenv = http_proxy
+ HTTP_PROXY
+ https_proxy
+ HTTPS_PROXY
+ no_proxy
+ NO_PROXY
[testenv:unit-with-driver-libs]
deps = {[testenv]deps}
diff --git a/zuul.d/ironic-jobs.yaml b/zuul.d/ironic-jobs.yaml
index 44a59b78a..c02d4488f 100644
--- a/zuul.d/ironic-jobs.yaml
+++ b/zuul.d/ironic-jobs.yaml
@@ -24,6 +24,8 @@
override-checkout: stable/zed
- name: openstack/requirements
override-checkout: stable/zed
+ - name: openstack/cinder
+ override-checkout: stable/zed
irrelevant-files:
- ^.*\.rst$
- ^api-ref/.*$
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 6bf317a45..9bff3446a 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -6,7 +6,6 @@
- openstack-python3-zed-jobs-ironic-bugfix202-arm64
- periodic-stable-jobs
- publish-openstack-docs-pti
- - release-notes-jobs-python3
check:
jobs:
- ironic-tox-unit-with-driver-libs