def collect_extra_hardware(data, failures): """Collect detailed inventory using 'hardware-detect' utility. Recognizes ipa-inspection-benchmarks with list of benchmarks (possible values are cpu, disk, mem) to run. No benchmarks are run by default, as they're pretty time-consuming. Puts collected data as JSON under 'data' key. Requires 'hardware' python package to be installed on the ramdisk in addition to the packages in requirements.txt. :param data: mutable data that we'll send to inspector :param failures: AccumulatedFailures object """ benchmarks = utils.get_agent_params().get("ipa-inspection-benchmarks", []) if benchmarks: benchmarks = ["--benchmark"] + benchmarks.split(",") try: out, err = utils.execute("hardware-detect", *benchmarks) except (processutils.ProcessExecutionError, OSError) as exc: failures.add("failed to run hardware-detect utility: %s", exc) return try: data["data"] = json.loads(out) except ValueError as exc: msg = "JSON returned from hardware-detect cannot be decoded: %s" failures.add(msg, exc)
def test_get_agent_params_from_cache(self, get_cache_mock, set_cache_mock): get_cache_mock.return_value = {'a': 'b'} returned_params = utils.get_agent_params() expected_params = {'a': 'b'} self.assertEqual(expected_params, returned_params) self.assertEqual(0, set_cache_mock.call_count)
def collect_extra_hardware(data, failures): """Collect detailed inventory using 'hardware-detect' utility. Recognizes ipa-inspection-benchmarks with list of benchmarks (possible values are cpu, disk, mem) to run. No benchmarks are run by default, as they're pretty time-consuming. Puts collected data as JSON under 'data' key. Requires 'hardware' python package to be installed on the ramdisk in addition to the packages in requirements.txt. :param data: mutable data that we'll send to inspector :param failures: AccumulatedFailures object """ benchmarks = utils.get_agent_params().get('ipa-inspection-benchmarks', []) if benchmarks: benchmarks = ['--benchmark'] + benchmarks.split(',') try: out, err = utils.execute('hardware-detect', *benchmarks) except (processutils.ProcessExecutionError, OSError) as exc: failures.add('failed to run hardware-detect utility: %s', exc) return try: data['data'] = json.loads(out) except ValueError as exc: msg = 'JSON returned from hardware-detect cannot be decoded: %s' failures.add(msg, exc)
def test_get_agent_params_kernel_cmdline(self, get_cache_mock, read_params_mock, set_cache_mock): get_cache_mock.return_value = {} expected_params = {'a': 'b'} read_params_mock.return_value = expected_params returned_params = utils.get_agent_params() read_params_mock.assert_called_once_with('/proc/cmdline') self.assertEqual(expected_params, returned_params) set_cache_mock.assert_called_once_with(expected_params)
def get_boot_info(self): func = "PowerPCHardwareManager.get_boot_info" boot_mode = 'uefi' if os.path.isdir('/sys/firmware/efi') else 'bios' LOG.debug("%s: The current boot mode is %s", func, boot_mode) pxe_interface = utils.get_agent_params().get('BOOTIF') return BootInfo(current_boot_mode=boot_mode, pxe_interface=pxe_interface)
def test_get_agent_params_vmedia(self, get_cache_mock, read_params_mock, get_vmedia_params_mock, set_cache_mock): get_cache_mock.return_value = {} kernel_params = {'boot_method': 'vmedia'} vmedia_params = {'a': 'b'} expected_params = dict( list(kernel_params.items()) + list(vmedia_params.items())) read_params_mock.return_value = kernel_params get_vmedia_params_mock.return_value = vmedia_params returned_params = utils.get_agent_params() read_params_mock.assert_called_once_with('/proc/cmdline') self.assertEqual(expected_params, returned_params) # Make sure information is cached set_cache_mock.assert_called_once_with(expected_params)
def wait_for_dhcp(): """Wait until NIC's get their IP addresses via DHCP or timeout happens. Depending on the value of inspection_dhcp_all_interfaces configuration option will wait for either all or only PXE booting NIC. Note: only supports IPv4 addresses for now. :return: True if all NIC's got IP addresses, False if timeout happened. Also returns True if waiting is disabled via configuration. """ if not CONF.inspection_dhcp_wait_timeout: return True pxe_mac = utils.get_agent_params().get('BOOTIF') if pxe_mac: pxe_mac = _normalize_mac(pxe_mac) elif not CONF.inspection_dhcp_all_interfaces: LOG.warning('No PXE boot interface known - not waiting for it ' 'to get the IP address') return False threshold = time.time() + CONF.inspection_dhcp_wait_timeout while time.time() <= threshold: interfaces = hardware.dispatch_to_managers('list_network_interfaces') interfaces = [ iface for iface in interfaces if CONF.inspection_dhcp_all_interfaces or iface.mac_address.lower() == pxe_mac ] missing = [ iface.name for iface in interfaces if not iface.ipv4_address ] if not missing: return True LOG.debug('Still waiting for interfaces %s to get IP addresses', missing) time.sleep(_DHCP_RETRY_INTERVAL) LOG.warning( 'Not all network interfaces received IP addresses in ' '%(timeout)d seconds: %(missing)s', { 'timeout': CONF.inspection_dhcp_wait_timeout, 'missing': missing }) return False
def test_get_agent_params_vmedia(self, get_cache_mock, read_params_mock, get_vmedia_params_mock, set_cache_mock): get_cache_mock.return_value = {} kernel_params = {'boot_method': 'vmedia'} vmedia_params = {'a': 'b'} expected_params = dict(list(kernel_params.items()) + list(vmedia_params.items())) read_params_mock.return_value = kernel_params get_vmedia_params_mock.return_value = vmedia_params returned_params = utils.get_agent_params() read_params_mock.assert_called_once_with('/proc/cmdline') self.assertEqual(expected_params, returned_params) # Make sure information is cached set_cache_mock.assert_called_once_with(expected_params)
def collect_default(data, failures): """The default inspection collector. This is the only collector that is called by default. It is designed to be both backward and future compatible: 1. it collects exactly the same data as the old bash-based ramdisk 2. it also posts the whole inventory which we'll eventually use. In both cases it tries to get BMC address, PXE boot device and the expected root device. :param data: mutable data that we'll send to inspector :param failures: AccumulatedFailures object """ wait_for_dhcp() inventory = hardware.dispatch_to_managers('list_hardware_info') # In the future we will only need the current version of inventory, # a guessed root disk, PXE boot interface and IPMI address. # Everything else will be done by inspector itself and its plugins. data['inventory'] = inventory # Replicate the same logic as in deploy. We need to make sure that when # root device hints are not set, inspector will use the same root disk as # will be used for deploy. try: root_disk = utils.guess_root_disk(inventory['disks'][:]) except errors.DeviceNotFound: root_disk = None LOG.warning('no suitable root device detected') else: data['root_disk'] = root_disk LOG.debug('default root device is %s', root_disk.name) # Both boot interface and IPMI address might not be present, # we don't count it as failure data['boot_interface'] = utils.get_agent_params().get('BOOTIF') LOG.debug('boot devices was %s', data['boot_interface']) data['ipmi_address'] = inventory.get('bmc_address') LOG.debug('BMC IP address: %s', data['ipmi_address']) # These 2 calls are required for backward compatibility and should be # dropped after inspector is ready (probably in Mitaka cycle). discover_network_properties(inventory, data, failures) discover_scheduling_properties(inventory, data, root_disk)
def wait_for_dhcp(): """Wait until NIC's get their IP addresses via DHCP or timeout happens. Depending on the value of inspection_dhcp_all_interfaces configuration option will wait for either all or only PXE booting NIC. Note: only supports IPv4 addresses for now. :return: True if all NIC's got IP addresses, False if timeout happened. Also returns True if waiting is disabled via configuration. """ if not CONF.inspection_dhcp_wait_timeout: return True pxe_mac = utils.get_agent_params().get('BOOTIF') if pxe_mac: pxe_mac = _normalize_mac(pxe_mac) elif not CONF.inspection_dhcp_all_interfaces: LOG.warning('No PXE boot interface known - not waiting for it ' 'to get the IP address') return False threshold = time.time() + CONF.inspection_dhcp_wait_timeout while time.time() <= threshold: interfaces = hardware.dispatch_to_managers('list_network_interfaces') interfaces = [iface for iface in interfaces if CONF.inspection_dhcp_all_interfaces or iface.mac_address.lower() == pxe_mac] missing = [iface.name for iface in interfaces if not iface.ipv4_address] if not missing: return True LOG.debug('Still waiting for interfaces %s to get IP addresses', missing) time.sleep(_DHCP_RETRY_INTERVAL) LOG.warning('Not all network interfaces received IP addresses in ' '%(timeout)d seconds: %(missing)s', {'timeout': CONF.inspection_dhcp_wait_timeout, 'missing': missing}) return False
# 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. from oslo_config import cfg from oslo_log import log as logging from ironic_python_agent import netutils from ironic_python_agent import utils LOG = logging.getLogger(__name__) CONF = cfg.CONF APARAMS = utils.get_agent_params() INSPECTION_DEFAULT_COLLECTOR = 'default,logs' INSPECTION_DEFAULT_DHCP_WAIT_TIMEOUT = 60 cli_opts = [ cfg.StrOpt('api_url', default=APARAMS.get('ipa-api-url'), regex='^(mdns|http(s?):\\/\\/.+)', help='URL of the Ironic API. ' 'Can be supplied as "ipa-api-url" kernel parameter.' 'The value must start with either http:// or https://. ' 'A special value "mdns" can be specified to fetch the ' 'URL using multicast DNS service discovery.'), cfg.StrOpt('global_request_id', default=APARAMS.get('ipa-global-request-id'),
# 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. from oslo_config import cfg from ironic_python_agent import inspector from ironic_python_agent import utils CONF = cfg.CONF APARAMS = utils.get_agent_params() cli_opts = [ cfg.StrOpt('api_url', default=APARAMS.get('ipa-api-url', 'http://127.0.0.1:6385'), deprecated_name='api-url', help='URL of the Ironic API'), cfg.StrOpt('listen_host', default=APARAMS.get('ipa-listen-host', '0.0.0.0'), deprecated_name='listen-host', help='The IP address to listen on.'), cfg.IntOpt('listen_port', default=int(APARAMS.get('ipa-listen-port', 9999)), deprecated_name='listen-port',
def get_boot_info(self): boot_mode = 'uefi' if os.path.isdir('/sys/firmware/efi') else 'bios' LOG.debug('The current boot mode is %s', boot_mode) pxe_interface = utils.get_agent_params().get('BOOTIF') return BootInfo(current_boot_mode=boot_mode, pxe_interface=pxe_interface)