summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2019-07-09 07:43:30 +0000
committerGerrit Code Review <review@openstack.org>2019-07-09 07:43:30 +0000
commite33744ac2d28d23e1e7951c50deaf07806665023 (patch)
tree02a52f38546f1dca2964c4950008b48ce7601e90
parent8e307de1e5325d2eb0ce0234d4d44634cb153feb (diff)
parent696606f6826394a32e9d09647f2ab1a8653bf8cb (diff)
downloadironic-python-agent-e33744ac2d28d23e1e7951c50deaf07806665023.tar.gz
Merge "manual introspection trigger command"4.0.0
-rw-r--r--doc/source/admin/how_it_works.rst27
-rw-r--r--ironic_python_agent/agent.py9
-rw-r--r--ironic_python_agent/cmd/inspect.py30
-rw-r--r--ironic_python_agent/config.py12
-rw-r--r--ironic_python_agent/inspect.py86
-rw-r--r--ironic_python_agent/inspector.py4
-rw-r--r--ironic_python_agent/tests/unit/test_inspector.py4
-rw-r--r--releasenotes/notes/manual-introspection-b04b5c25f5e004ac.yaml13
-rw-r--r--setup.cfg1
9 files changed, 180 insertions, 6 deletions
diff --git a/doc/source/admin/how_it_works.rst b/doc/source/admin/how_it_works.rst
index aeb25ad2..d93c878c 100644
--- a/doc/source/admin/how_it_works.rst
+++ b/doc/source/admin/how_it_works.rst
@@ -60,6 +60,33 @@ full endpoint of Ironic Inspector, for example::
Make sure your DHCP environment is set to boot IPA by default.
+For the cases where the infrastructure operator and cloud user are the same,
+an additional tool exists that can be installed alongside the agent inside
+a running instance. This is the ``ironic-collect-introspection-data``
+command which allows for a node in ``ACTIVE`` state to publish updated
+introspection data to ironic-inspector. This ability requires ironic-inspector
+to be configured with ``[processing]permit_active_introspection`` set to
+``True``. For example::
+
+ ironic-collect-introspection-data --inspection_callback_url http://IP:5050/v1/continue
+
+Alternatively, this command may also be used with multicast DNS
+functionality to identify the `Ironic Inspector`_ service endpoint.
+For example::
+
+ ironic-collect-introspection-data --inspection_callback_url mdns
+
+An additional daemon mode may be useful for some operators who wish to receive
+regular updates, in the form of the ``[DEFAULT]introspection_daemon`` boolean
+configuration option.
+For example::
+
+ ironic-collect-introspection-data --inspection_callback_url mdns --introspection_daemon
+
+The above command will attempt to connect to introspection and will then enter
+a loop to publish every 300 seconds. This can be tuned with the
+``[DEFAULT]introspection_daemon_post_interval`` configuration option.
+
.. _Ironic Inspector: https://docs.openstack.org/ironic-inspector/
Hardware Inventory
diff --git a/ironic_python_agent/agent.py b/ironic_python_agent/agent.py
index 390afce8..4641b82e 100644
--- a/ironic_python_agent/agent.py
+++ b/ironic_python_agent/agent.py
@@ -388,8 +388,13 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
# lookup will fail due to unknown MAC.
uuid = None
if cfg.CONF.inspection_callback_url:
- uuid = inspector.inspect()
-
+ try:
+ # Attempt inspection. This may fail, and previously
+ # an error would be logged.
+ uuid = inspector.inspect()
+ except errors.InspectionError as e:
+ LOG.error('Failed to perform inspection: %(err)s',
+ {'error': e})
if self.api_url:
self._wait_for_interface()
content = self.api_client.lookup_node(
diff --git a/ironic_python_agent/cmd/inspect.py b/ironic_python_agent/cmd/inspect.py
new file mode 100644
index 00000000..af747f7e
--- /dev/null
+++ b/ironic_python_agent/cmd/inspect.py
@@ -0,0 +1,30 @@
+# Copyright 2013 Rackspace, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+from oslo_config import cfg
+from oslo_log import log
+
+from ironic_python_agent import inspect as inspection
+
+CONF = cfg.CONF
+
+
+def run():
+ """Entrypoint for IronicPythonAgent."""
+ log.register_options(CONF)
+ CONF(args=sys.argv[1:])
+ log.setup(CONF, 'ironic-python-agent')
+ inspection.IronicInspection().run()
diff --git a/ironic_python_agent/config.py b/ironic_python_agent/config.py
index 5bd1cdc2..2b65bcfe 100644
--- a/ironic_python_agent/config.py
+++ b/ironic_python_agent/config.py
@@ -217,6 +217,18 @@ cli_opts = [
'Must be provided together with "certfile" option. '
'Default is to not present any client certificates to '
'the server.'),
+ cfg.BoolOpt('introspection_daemon',
+ default=False,
+ help='When the ``ironic-collect-introspection-data`` '
+ 'command is executed, continue running as '
+ 'a background process and continue to post data '
+ 'to the bare metal inspection service.'),
+ cfg.IntOpt('introspection_daemon_post_interval',
+ default=300,
+ help='The interval in seconds by which to transmit data to '
+ 'the bare metal introspection service when the '
+ '``ironic-collect-introspection-data`` program is '
+ 'executing in daemon mode.'),
]
CONF.register_cli_opts(cli_opts)
diff --git a/ironic_python_agent/inspect.py b/ironic_python_agent/inspect.py
new file mode 100644
index 00000000..b8b8fd73
--- /dev/null
+++ b/ironic_python_agent/inspect.py
@@ -0,0 +1,86 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import select
+import threading
+
+from ironic_lib import exception
+from oslo_config import cfg
+from oslo_log import log
+
+from ironic_python_agent import errors
+from ironic_python_agent import inspector
+
+LOG = log.getLogger(__name__)
+
+
+class IronicInspection(threading.Thread):
+ """Class for manual inspection functionality."""
+
+ def __init__(self):
+ super(IronicInspection, self).__init__()
+ if bool(cfg.CONF.keyfile) != bool(cfg.CONF.certfile):
+ LOG.warning("Only one of 'keyfile' and 'certfile' options is "
+ "defined in config file. Its value will be ignored.")
+
+ def _run(self):
+ try:
+ daemon_mode = cfg.CONF.introspection_daemon
+ post_interval = cfg.CONF.introspection_daemon_post_interval
+
+ inspector.inspect()
+ if not daemon_mode:
+ # No reason to continue unless we're in daemon mode.
+ return
+
+ self.reader, self.writer = os.pipe()
+ p = select.poll()
+ p.register(self.reader)
+
+ try:
+ while daemon_mode:
+ LOG.info('Sleeping until next check-in.')
+ # TODO(TheJulia): It would likely be good to introduce
+ # some jitter into this at some point...
+ if p.poll(post_interval * 1000):
+ if os.read(self.reader, 1).decode() == 'a':
+ break
+ try:
+ inspector.inspect()
+ except errors.InspectionError as e:
+ # Failures happen, no reason to exit as
+ # the failure could be intermittent.
+ LOG.warning('Error reporting introspection '
+ 'data: %(err)s',
+ {'err': e})
+ except exception.ServiceLookupFailure as e:
+ # Likely a mDNS lookup failure. We should
+ # keep retrying.
+ LOG.error('Error looking up introspection '
+ 'endpoint: %(err)s',
+ {'err': e})
+
+ finally:
+ os.close(self.reader)
+ os.close(self.writer)
+ self.reader = None
+ self.writer = None
+ except errors.InspectionError as e:
+ msg = "Inspection failed: %s" % e
+ raise errors.InspectionError(msg)
+
+ def run(self):
+ """Run Inspection."""
+ if not cfg.CONF.inspection_callback_url:
+ cfg.CONF.set_override('inspection_callback_url', 'mdns')
+ self._run()
diff --git a/ironic_python_agent/inspector.py b/ironic_python_agent/inspector.py
index 54de65d0..6b645861 100644
--- a/ironic_python_agent/inspector.py
+++ b/ironic_python_agent/inspector.py
@@ -104,8 +104,8 @@ def inspect():
failures.raise_if_needed()
if resp is None:
- LOG.info('stopping inspection, as inspector returned an error')
- return
+ raise errors.InspectionError('stopping inspection, as inspector '
+ 'returned an error')
LOG.info('inspection finished successfully')
return resp.get('uuid')
diff --git a/ironic_python_agent/tests/unit/test_inspector.py b/ironic_python_agent/tests/unit/test_inspector.py
index 501e8c1e..10f9f9e4 100644
--- a/ironic_python_agent/tests/unit/test_inspector.py
+++ b/ironic_python_agent/tests/unit/test_inspector.py
@@ -137,11 +137,11 @@ class TestInspect(base.IronicAgentTest):
mock_call.return_value = None
mock_ext_mgr.return_value = [self.mock_ext]
- result = inspector.inspect()
+ self.assertRaises(errors.InspectionError,
+ inspector.inspect)
self.mock_collect.assert_called_with_failure()
mock_call.assert_called_with_failure()
- self.assertIsNone(result)
@mock.patch.object(requests, 'post', autospec=True)
diff --git a/releasenotes/notes/manual-introspection-b04b5c25f5e004ac.yaml b/releasenotes/notes/manual-introspection-b04b5c25f5e004ac.yaml
new file mode 100644
index 00000000..5918ee91
--- /dev/null
+++ b/releasenotes/notes/manual-introspection-b04b5c25f5e004ac.yaml
@@ -0,0 +1,13 @@
+---
+features:
+ - |
+ Adds a new CLI command ``ironic-collect-introspection-data`` to enable
+ manually publishing into the ``baremetal-introspection`` service.
+ Executing this command on a system unknown to the Bare Metal service
+ will likely result in the machine becoming registered to Ironic, and
+ as such this command should be used with caution.
+
+ If the capability to update introspection data for running machines
+ has been enabled in the Bare Metal introspection service, then an
+ operator may use this command in the ``active`` or ``rescue`` states
+ to update introspection data.
diff --git a/setup.cfg b/setup.cfg
index 1344c04d..e287f18f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -29,6 +29,7 @@ oslo.config.opts =
console_scripts =
ironic-python-agent = ironic_python_agent.cmd.agent:run
+ ironic-collect-introspection-data = ironic_python_agent.cmd.inspect:run
ironic_python_agent.extensions =
standby = ironic_python_agent.extensions.standby:StandbyExtension