Example #1
0
 def test_get_client_without_auth_token(self, mock_client):
     utils.get_client(None)
     args = {'os_password': CONF.ironic.os_password,
             'os_username': CONF.ironic.os_username,
             'os_auth_url': CONF.ironic.os_auth_url,
             'os_tenant_name': CONF.ironic.os_tenant_name,
             'os_endpoint_type': CONF.ironic.os_endpoint_type,
             'os_service_type': CONF.ironic.os_service_type,
             'os_ironic_api_version': '1.6',
             'max_retries': CONF.ironic.max_retries,
             'retry_interval': CONF.ironic.retry_interval}
     mock_client.assert_called_once_with(1, **args)
Example #2
0
 def test_get_client_with_auth_token(self, mock_keystone_client, mock_client):
     fake_token = "token"
     fake_ironic_url = "http://127.0.0.1:6385"
     mock_keystone_client().service_catalog.url_for.return_value = fake_ironic_url
     utils.get_client(fake_token)
     args = {
         "os_auth_token": fake_token,
         "ironic_url": fake_ironic_url,
         "os_ironic_api_version": "1.6",
         "max_retries": CONF.ironic.max_retries,
         "retry_interval": CONF.ironic.retry_interval,
     }
     mock_client.assert_called_once_with(1, **args)
Example #3
0
 def test_get_client_with_auth_token(self, mock_keystone_client,
                                     mock_client):
     fake_token = 'token'
     fake_ironic_url = 'http://127.0.0.1:6385'
     mock_keystone_client().service_catalog.url_for.return_value = (
         fake_ironic_url)
     utils.get_client(fake_token)
     args = {'os_auth_token': fake_token,
             'ironic_url': fake_ironic_url,
             'os_ironic_api_version': '1.6',
             'max_retries': CONF.ironic.max_retries,
             'retry_interval': CONF.ironic.retry_interval}
     mock_client.assert_called_once_with(1, **args)
Example #4
0
 def test_get_client_without_auth_token(self, mock_client):
     utils.get_client(None)
     args = {
         "os_password": CONF.ironic.os_password,
         "os_username": CONF.ironic.os_username,
         "os_auth_url": CONF.ironic.os_auth_url,
         "os_tenant_name": CONF.ironic.os_tenant_name,
         "os_endpoint_type": CONF.ironic.os_endpoint_type,
         "os_service_type": CONF.ironic.os_service_type,
         "os_ironic_api_version": "1.6",
         "max_retries": CONF.ironic.max_retries,
         "retry_interval": CONF.ironic.retry_interval,
     }
     mock_client.assert_called_once_with(1, **args)
Example #5
0
 def test_get_client_without_auth_token(self, mock_client):
     utils.get_client(None)
     args = {
         'os_password': CONF.ironic.os_password,
         'os_username': CONF.ironic.os_username,
         'os_auth_url': CONF.ironic.os_auth_url,
         'os_tenant_name': CONF.ironic.os_tenant_name,
         'os_endpoint_type': CONF.ironic.os_endpoint_type,
         'os_service_type': CONF.ironic.os_service_type,
         'os_ironic_api_version': '1.6',
         'max_retries': CONF.ironic.max_retries,
         'retry_interval': CONF.ironic.retry_interval
     }
     mock_client.assert_called_once_with(1, **args)
Example #6
0
 def test_get_client_with_auth_token(self, mock_keystone_client,
                                     mock_client):
     fake_token = 'token'
     fake_ironic_url = 'http://127.0.0.1:6385'
     mock_keystone_client().service_catalog.url_for.return_value = (
         fake_ironic_url)
     utils.get_client(fake_token)
     args = {
         'os_auth_token': fake_token,
         'ironic_url': fake_ironic_url,
         'os_ironic_api_version': '1.6',
         'max_retries': CONF.ironic.max_retries,
         'retry_interval': CONF.ironic.retry_interval
     }
     mock_client.assert_called_once_with(1, **args)
def hook(introspection_data, **kwargs):
    ironic = utils.get_client()
    try:
        node = ironic.node.create(**{'driver': 'fake'})
    except exceptions.HttpError as exc:
        raise utils.Error(_("Can not create node in ironic for unknown"
                            "node: %s") % exc)
    return node_cache.add_node(node.uuid, ironic=ironic)
Example #8
0
def update_filters(ironic=None):
    """Update firewall filter rules for introspection.

    Gives access to PXE boot port for any machine, except for those,
    whose MAC is registered in Ironic and is not on introspection right now.

    This function is called from both introspection initialization code and
    from periodic task. This function is supposed to be resistant to unexpected
    iptables state.

    ``init()`` function must be called once before any call to this function.
    This function is using ``eventlet`` semaphore to serialize access from
    different green threads.

    Does nothing, if firewall management is disabled in configuration.

    :param ironic: Ironic client instance, optional.
    """
    if not CONF.firewall.manage_firewall:
        return

    assert INTERFACE is not None
    ironic = utils.get_client() if ironic is None else ironic

    with LOCK:
        macs_active = set(p.address for p in ironic.port.list(limit=0))
        to_blacklist = macs_active - node_cache.active_macs()
        LOG.debug('Blacklisting active MAC\'s %s', to_blacklist)

        # Clean up a bit to account for possible troubles on previous run
        _clean_up(NEW_CHAIN)
        # Operate on temporary chain
        _iptables('-N', NEW_CHAIN)
        # - Blacklist active macs, so that nova can boot them
        for mac in to_blacklist:
            _iptables('-A', NEW_CHAIN, '-m', 'mac', '--mac-source', mac, '-j',
                      'DROP')
        # - Whitelist everything else
        _iptables('-A', NEW_CHAIN, '-j', 'ACCEPT')

        # Swap chains
        _iptables('-I', 'INPUT', '-i', INTERFACE, '-p', 'udp', '--dport', '67',
                  '-j', NEW_CHAIN)
        _iptables('-D',
                  'INPUT',
                  '-i',
                  INTERFACE,
                  '-p',
                  'udp',
                  '--dport',
                  '67',
                  '-j',
                  CHAIN,
                  ignore=True)
        _iptables('-F', CHAIN, ignore=True)
        _iptables('-X', CHAIN, ignore=True)
        _iptables('-E', NEW_CHAIN, CHAIN)
Example #9
0
def introspect(uuid, new_ipmi_credentials=None, token=None):
    """Initiate hardware properties introspection for a given node.

    :param uuid: node uuid
    :param new_ipmi_credentials: tuple (new username, new password) or None
    :param token: authentication token
    :raises: Error
    """
    ironic = utils.get_client(token)

    try:
        node = ironic.node.get(uuid)
    except exceptions.NotFound:
        raise utils.Error(_("Cannot find node %s") % uuid, code=404)
    except exceptions.HttpError as exc:
        raise utils.Error(
            _("Cannot get node %(node)s: %(exc)s") % {
                'node': uuid,
                'exc': exc
            })

    utils.check_provision_state(node, with_credentials=new_ipmi_credentials)

    if new_ipmi_credentials:
        new_ipmi_credentials = (_validate_ipmi_credentials(
            node, new_ipmi_credentials))
    else:
        validation = ironic.node.validate(node.uuid)
        if not validation.power['result']:
            msg = _('Failed validation of power interface for node %(node)s, '
                    'reason: %(reason)s')
            raise utils.Error(msg % {
                'node': node.uuid,
                'reason': validation.power['reason']
            })

    node_info = node_cache.add_node(node.uuid,
                                    bmc_address=utils.get_ipmi_address(node),
                                    ironic=ironic)
    node_info.set_option('new_ipmi_credentials', new_ipmi_credentials)

    def _handle_exceptions():
        try:
            _background_introspect(ironic, node_info)
        except utils.Error as exc:
            node_info.finished(error=str(exc))
        except Exception as exc:
            msg = _('Unexpected exception in background introspection thread')
            LOG.exception(msg)
            node_info.finished(error=msg)

    utils.spawn_n(_handle_exceptions)
Example #10
0
def update_filters(ironic=None):
    """Update firewall filter rules for introspection.

    Gives access to PXE boot port for any machine, except for those,
    whose MAC is registered in Ironic and is not on introspection right now.

    This function is called from both introspection initialization code and
    from periodic task. This function is supposed to be resistant to unexpected
    iptables state.

    ``init()`` function must be called once before any call to this function.
    This function is using ``eventlet`` semaphore to serialize access from
    different green threads.

    Does nothing, if firewall management is disabled in configuration.

    :param ironic: Ironic client instance, optional.
    """
    if not CONF.firewall.manage_firewall:
        return

    assert INTERFACE is not None
    ironic = utils.get_client() if ironic is None else ironic

    with LOCK:
        macs_active = set(p.address for p in ironic.port.list(limit=0))
        to_blacklist = macs_active - node_cache.active_macs()
        LOG.debug('Blacklisting active MAC\'s %s', to_blacklist)

        # Clean up a bit to account for possible troubles on previous run
        _clean_up(NEW_CHAIN)
        # Operate on temporary chain
        _iptables('-N', NEW_CHAIN)
        # - Blacklist active macs, so that nova can boot them
        for mac in to_blacklist:
            _iptables('-A', NEW_CHAIN, '-m', 'mac',
                      '--mac-source', mac, '-j', 'DROP')
        # - Whitelist everything else
        _iptables('-A', NEW_CHAIN, '-j', 'ACCEPT')

        # Swap chains
        _iptables('-I', 'INPUT', '-i', INTERFACE, '-p', 'udp',
                  '--dport', '67', '-j', NEW_CHAIN)
        _iptables('-D', 'INPUT', '-i', INTERFACE, '-p', 'udp',
                  '--dport', '67', '-j', CHAIN,
                  ignore=True)
        _iptables('-F', CHAIN, ignore=True)
        _iptables('-X', CHAIN, ignore=True)
        _iptables('-E', NEW_CHAIN, CHAIN)
Example #11
0
def _process_node(node, introspection_data, node_info):
    # NOTE(dtantsur): repeat the check in case something changed
    utils.check_provision_state(node)

    node_info.create_ports(introspection_data.get('macs') or ())

    _run_post_hooks(node_info, introspection_data)

    if CONF.processing.store_data == 'swift':
        swift_object_name = swift.store_introspection_data(
            introspection_data, node_info.uuid)
        LOG.info(
            _LI('Introspection data for node %(node)s was stored in '
                'Swift in object %(obj)s'), {
                    'node': node_info.uuid,
                    'obj': swift_object_name
                })
        if CONF.processing.store_data_location:
            node_info.patch([{
                'op': 'add',
                'path': '/extra/%s' % CONF.processing.store_data_location,
                'value': swift_object_name
            }])
    else:
        LOG.debug(
            'Swift support is disabled, introspection data for node %s '
            'won\'t be stored', node_info.uuid)

    ironic = utils.get_client()
    firewall.update_filters(ironic)

    node_info.invalidate_cache()
    rules.apply(node_info, introspection_data)

    resp = {'uuid': node.uuid}

    if node_info.options.get('new_ipmi_credentials'):
        new_username, new_password = (
            node_info.options.get('new_ipmi_credentials'))
        utils.spawn_n(_finish_set_ipmi_credentials, ironic, node, node_info,
                      introspection_data, new_username, new_password)
        resp['ipmi_setup_credentials'] = True
        resp['ipmi_username'] = new_username
        resp['ipmi_password'] = new_password
    else:
        utils.spawn_n(_finish, ironic, node_info)

    return resp
Example #12
0
def introspect(uuid, new_ipmi_credentials=None, token=None):
    """Initiate hardware properties introspection for a given node.

    :param uuid: node uuid
    :param new_ipmi_credentials: tuple (new username, new password) or None
    :param token: authentication token
    :raises: Error
    """
    ironic = utils.get_client(token)

    try:
        node = ironic.node.get(uuid)
    except exceptions.NotFound:
        raise utils.Error(_("Cannot find node %s") % uuid, code=404)
    except exceptions.HttpError as exc:
        raise utils.Error(_("Cannot get node %(node)s: %(exc)s") %
                          {'node': uuid, 'exc': exc})

    utils.check_provision_state(node, with_credentials=new_ipmi_credentials)

    if new_ipmi_credentials:
        new_ipmi_credentials = (
            _validate_ipmi_credentials(node, new_ipmi_credentials))
    else:
        validation = ironic.node.validate(node.uuid)
        if not validation.power['result']:
            msg = _('Failed validation of power interface for node %(node)s, '
                    'reason: %(reason)s')
            raise utils.Error(msg % {'node': node.uuid,
                                     'reason': validation.power['reason']})

    node_info = node_cache.add_node(node.uuid,
                                    bmc_address=utils.get_ipmi_address(node),
                                    ironic=ironic)
    node_info.set_option('new_ipmi_credentials', new_ipmi_credentials)

    def _handle_exceptions():
        try:
            _background_introspect(ironic, node_info)
        except utils.Error as exc:
            node_info.finished(error=str(exc))
        except Exception as exc:
            msg = _('Unexpected exception in background introspection thread')
            LOG.exception(msg)
            node_info.finished(error=msg)

    utils.spawn_n(_handle_exceptions)
Example #13
0
def _process_node(node, introspection_data, node_info):
    # NOTE(dtantsur): repeat the check in case something changed
    utils.check_provision_state(node)

    node_info.create_ports(introspection_data.get('macs') or ())

    _run_post_hooks(node_info, introspection_data)

    if CONF.processing.store_data == 'swift':
        swift_object_name = swift.store_introspection_data(introspection_data,
                                                           node_info.uuid)
        LOG.info(_LI('Introspection data for node %(node)s was stored in '
                     'Swift in object %(obj)s'),
                 {'node': node_info.uuid, 'obj': swift_object_name})
        if CONF.processing.store_data_location:
            node_info.patch([{'op': 'add', 'path': '/extra/%s' %
                              CONF.processing.store_data_location,
                              'value': swift_object_name}])
    else:
        LOG.debug('Swift support is disabled, introspection data for node %s '
                  'won\'t be stored', node_info.uuid)

    ironic = utils.get_client()
    firewall.update_filters(ironic)

    node_info.invalidate_cache()
    rules.apply(node_info, introspection_data)

    resp = {'uuid': node.uuid}

    if node_info.options.get('new_ipmi_credentials'):
        new_username, new_password = (
            node_info.options.get('new_ipmi_credentials'))
        utils.spawn_n(_finish_set_ipmi_credentials,
                      ironic, node, node_info, introspection_data,
                      new_username, new_password)
        resp['ipmi_setup_credentials'] = True
        resp['ipmi_username'] = new_username
        resp['ipmi_password'] = new_password
    else:
        utils.spawn_n(_finish, ironic, node_info)

    return resp
Example #14
0
def sync_with_ironic():
    ironic = utils.get_client()
    # TODO(yuikotakada): pagination
    ironic_nodes = ironic.node.list(limit=0)
    ironic_node_uuids = {node.uuid for node in ironic_nodes}
    node_cache.delete_nodes_not_in_list(ironic_node_uuids)
Example #15
0
 def ironic(self):
     """Ironic client instance."""
     if self._ironic is None:
         self._ironic = utils.get_client()
     return self._ironic
Example #16
0
def sync_with_ironic():
    ironic = utils.get_client()
    # TODO(yuikotakada): pagination
    ironic_nodes = ironic.node.list(limit=0)
    ironic_node_uuids = {node.uuid for node in ironic_nodes}
    node_cache.delete_nodes_not_in_list(ironic_node_uuids)
Example #17
0
    def setUp(self):
        super(Base, self).setUp()
        rules.delete_all()

        self.cli = utils.get_client()
        self.cli.reset_mock()
        self.cli.node.get.return_value = self.node
        self.cli.node.update.return_value = self.node
        self.cli.node.list.return_value = [self.node]

        # https://github.com/openstack/ironic-inspector/blob/master/HTTP-API.rst  # noqa
        self.data = {
            'cpus': 4,
            'cpu_arch': 'x86_64',
            'memory_mb': 12288,
            'local_gb': 464,
            'interfaces': {
                'eth1': {'mac': self.macs[0], 'ip': '1.2.1.2'},
                'eth2': {'mac': '12:12:21:12:21:12'},
                'eth3': {'mac': self.macs[1], 'ip': '1.2.1.1'},
            },
            'boot_interface': '01-' + self.macs[0].replace(':', '-'),
            'ipmi_address': self.bmc_address,
            'inventory': {
                'disks': [
                    {'name': '/dev/sda', 'model': 'Big Data Disk',
                     'size': 1000 * units.Gi},
                    {'name': '/dev/sdb', 'model': 'Small OS Disk',
                     'size': 20 * units.Gi},
                ]
            },
            'root_disk': {'name': '/dev/sda', 'model': 'Big Data Disk',
                          'size': 1000 * units.Gi},
        }
        self.data_old_ramdisk = {
            'cpus': 4,
            'cpu_arch': 'x86_64',
            'memory_mb': 12288,
            'local_gb': 464,
            'interfaces': {
                'eth1': {'mac': self.macs[0], 'ip': '1.2.1.2'},
                'eth2': {'mac': '12:12:21:12:21:12'},
                'eth3': {'mac': self.macs[1], 'ip': '1.2.1.1'},
            },
            'boot_interface': '01-' + self.macs[0].replace(':', '-'),
            'ipmi_address': self.bmc_address,
        }

        self.patch = [
            {'op': 'add', 'path': '/properties/cpus', 'value': '4'},
            {'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
            {'op': 'add', 'path': '/properties/memory_mb', 'value': '12288'},
            {'path': '/properties/local_gb', 'value': '999', 'op': 'add'}
        ]
        self.patch_old_ramdisk = [
            {'op': 'add', 'path': '/properties/cpus', 'value': '4'},
            {'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
            {'op': 'add', 'path': '/properties/memory_mb', 'value': '12288'},
            {'path': '/properties/local_gb', 'value': '464', 'op': 'add'}
        ]
        self.patch_root_hints = [
            {'op': 'add', 'path': '/properties/cpus', 'value': '4'},
            {'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
            {'op': 'add', 'path': '/properties/memory_mb', 'value': '12288'},
            {'path': '/properties/local_gb', 'value': '19', 'op': 'add'}
        ]

        self.node.power_state = 'power off'