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)
Exemple #3
0
 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)
Exemple #4
0
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 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)
Exemple #9
0
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)
Exemple #12
0
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)
 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)