Exemple #1
0
 def test_validate(self, mock_network, mock_subnet, mock_port):
     nic_info = [{
         'network': 'network'
     }, {
         'subnet': 'subnet'
     }, {
         'port': 'port'
     }]
     nics = _nics.NICs(self.connection, self.node, nic_info)
     mock_network.return_value = {'network_id': 'net_id'}
     mock_subnet.return_value = {
         'network_id': 'net_id',
         'fixed_ips': [{
             'subnet_id': 'subnet_id'
         }]
     }
     mock_port.return_value = port_mock = mock.Mock(id='port_id')
     nics.validate()
     mock_network.assert_called_once_with(nics, nic_info[0])
     mock_subnet.assert_called_once_with(nics, nic_info[1])
     mock_port.assert_called_once_with(nics, nic_info[2])
     self.assertEqual(('network', {
         'network_id': 'net_id'
     }), nics._validated[0])
     self.assertEqual(('subnet', {
         'network_id': 'net_id',
         'fixed_ips': [{
             'subnet_id': 'subnet_id'
         }]
     }), nics._validated[1])
     self.assertEqual(('port', port_mock), nics._validated[2])
Exemple #2
0
 def test_get_subnet(self):
     nic_info = [{'subnet': 'net-name'}]
     hostname = 'test-host'
     nics = _nics.NICs(self.connection,
                       self.node,
                       nic_info,
                       hostname=hostname)
     fake_net = mock.Mock(id='fake_net_id', name='fake_net_name')
     fake_subnet = mock.Mock(id='fake_subnetnet_id',
                             name='fake_subnetnet_name',
                             network_id=fake_net.id)
     self.connection.network.find_subnet.return_value = fake_subnet
     self.connection.network.get_network.return_value = fake_net
     return_value = nics._get_subnet(nic_info[0])
     self.connection.network.find_subnet.assert_called_once_with(
         nic_info[0]['subnet'], ignore_missing=False)
     self.connection.network.get_network.assert_called_once_with(
         fake_subnet.network_id)
     self.assertEqual(
         {
             'network_id': fake_net.id,
             'name': '%s-%s' % (hostname, fake_net.name),
             'fixed_ips': [{
                 'subnet_id': fake_subnet.id
             }]
         }, return_value)
Exemple #3
0
 def test_detach_and_delete_ports(self, mock_detach_delete):
     nics = _nics.NICs(self.connection, self.node, [])
     nics.created_ports = ['port_a_id']
     nics.attached_ports = ['port_a_id', 'port_b_id']
     nics.detach_and_delete_ports()
     mock_detach_delete.assert_called_once_with(self.connection, nics._node,
                                                nics.created_ports,
                                                nics.attached_ports)
Exemple #4
0
 def test_get_port_unexpected_fields(self):
     nic_info = [{'port': 'port_uuid', 'unexpected': 'field'}]
     nics = _nics.NICs(self.connection,
                       self.node,
                       nic_info,
                       hostname='test-host')
     self.assertRaisesRegex(exceptions.InvalidNIC,
                            'Unexpected fields for a port: unexpected',
                            nics._get_port, nic_info[0])
Exemple #5
0
 def test_get_port_resource_not_found(self):
     nic_info = [{'port': 'aaaa-bbbb-cccc'}]
     nics = _nics.NICs(self.connection,
                       self.node,
                       nic_info,
                       hostname='test-host')
     self.connection.network.find_port.side_effect = (
         sdk_exc.SDKException('SDK_ERROR'))
     self.assertRaisesRegex(exceptions.InvalidNIC,
                            'Cannot find port aaaa-bbbb-cccc: SDK_ERROR',
                            nics._get_port, nic_info[0])
Exemple #6
0
 def test_get_subnet_resource_not_found(self):
     nic_info = [{'subnet': 'uuid'}]
     self.connection.network.find_subnet.side_effect = (
         sdk_exc.SDKException('SDK_ERROR'))
     nics = _nics.NICs(self.connection,
                       self.node,
                       nic_info,
                       hostname='test-host')
     self.assertRaisesRegex(exceptions.InvalidNIC,
                            'Cannot find subnet uuid: SDK_ERROR',
                            nics._get_subnet, nic_info[0])
Exemple #7
0
 def test_get_port(self):
     nic_info = [{'port': 'port_uuid'}]
     nics = _nics.NICs(self.connection,
                       self.node,
                       nic_info,
                       hostname='test-host')
     fake_port = mock.Mock()
     self.connection.network.find_port.return_value = fake_port
     return_value = nics._get_port(nic_info[0])
     self.connection.network.find_port.assert_called_once_with(
         nic_info[0]['port'], ignore_missing=False)
     self.assertEqual(fake_port, return_value)
Exemple #8
0
 def test_get_network_resource_not_found(self):
     nic_info = [{'network': 'aaaa-bbbb-cccc', 'fixed_ip': '1.1.1.1'}]
     self.connection.network.find_network.side_effect = (
         sdk_exc.SDKException('SDK_ERROR'))
     nics = _nics.NICs(self.connection,
                       self.node,
                       nic_info,
                       hostname='test-host')
     self.assertRaisesRegex(
         exceptions.InvalidNIC,
         'Cannot find network aaaa-bbbb-cccc: SDK_ERROR', nics._get_network,
         nic_info[0])
Exemple #9
0
 def test_init(self):
     nic_info = [{'network': 'uuid', 'fixed_ip': '1.1.1.1'}]
     nics = _nics.NICs(self.connection,
                       self.node,
                       nic_info,
                       hostname='test-host')
     self.assertEqual(nics._node, self.node)
     self.assertEqual(nics._connection, self.connection)
     self.assertEqual(nics._nics, nic_info)
     self.assertIsNone(nics._validated)
     self.assertEqual(nics._hostname, 'test-host')
     self.assertEqual(nics.created_ports, [])
     self.assertEqual(nics.attached_ports, [])
Exemple #10
0
 def test_get_network_unexpected_fields(self):
     nic_info = [{
         'network': 'uuid',
         'subnet': 'subnet_name',
         'fixed_ip': '1.1.1.1',
         'unexpected': 'field'
     }]
     nics = _nics.NICs(self.connection,
                       self.node,
                       nic_info,
                       hostname='test-host')
     self.assertRaisesRegex(exceptions.InvalidNIC,
                            'Unexpected fields for a network: unexpected',
                            nics._get_network, nic_info[0])
Exemple #11
0
 def test_create_and_attach_ports(self, mock_network, mock_subnet,
                                  mock_port):
     nic_info = [{
         'network': 'network'
     }, {
         'subnet': 'subnet'
     }, {
         'port': 'port'
     }]
     nics = _nics.NICs(self.connection, self.node, nic_info)
     mock_network.return_value = {'network_id': 'net_id'}
     mock_subnet.return_value = {
         'network_id': 'net_id',
         'fixed_ips': [{
             'subnet_id': 'subnet_id'
         }]
     }
     port_a_mock = mock.Mock(id='port_a_id')
     port_b_mock = mock.Mock(id='port_b_id')
     port_c_mock = mock.Mock(id='port_c_id')
     self.connection.network.create_port.side_effect = [
         port_a_mock, port_b_mock
     ]
     mock_port.return_value = port_c_mock
     nics.create_and_attach_ports()
     self.connection.network.create_port.assert_has_calls([
         mock.call(binding_host_id=nics._node.id,
                   **{'network_id': 'net_id'}),
         mock.call(binding_host_id=nics._node.id,
                   **{
                       'network_id': 'net_id',
                       'fixed_ips': [{
                           'subnet_id': 'subnet_id'
                       }]
                   })
     ])
     self.connection.network.update_port.assert_has_calls(
         [mock.call(port_c_mock, binding_host_id=nics._node.id)])
     self.connection.baremetal.attach_vif_to_node.assert_has_calls([
         mock.call(nics._node, port_a_mock.id),
         mock.call(nics._node, port_b_mock.id),
         mock.call(nics._node, port_c_mock.id)
     ])
     self.assertEqual([port_a_mock.id, port_b_mock.id], nics.created_ports)
     self.assertEqual([port_a_mock.id, port_b_mock.id, port_c_mock.id],
                      nics.attached_ports)
Exemple #12
0
 def test_get_network_and_subnet_not_found(self):
     nic_info = [{'network': 'net-name', 'subnet': 'subnet-name'}]
     hostname = 'test-host'
     nics = _nics.NICs(self.connection,
                       self.node,
                       nic_info,
                       hostname=hostname)
     fake_net = mock.Mock(id='fake_net_id', name='fake_net_name')
     self.connection.network.find_network.return_value = fake_net
     self.connection.network.find_subnet.side_effect = (
         sdk_exc.SDKException('SDK_ERROR'))
     self.assertRaisesRegex(exceptions.InvalidNIC,
                            ('Cannot find subnet subnet-name on network '
                             'net-name: SDK_ERROR'), nics._get_network,
                            nic_info[0])
     self.connection.network.find_network.assert_called_once_with(
         nic_info[0]['network'], ignore_missing=False)
     self.connection.network.find_subnet.assert_called_once_with(
         nic_info[0]['subnet'],
         network_id=fake_net.id,
         ignore_missing=False)
Exemple #13
0
    def provision_node(self,
                       node,
                       image,
                       nics=None,
                       root_size_gb=None,
                       swap_size_mb=None,
                       config=None,
                       hostname=None,
                       netboot=False,
                       capabilities=None,
                       traits=None,
                       wait=None,
                       clean_up_on_failure=True):
        """Provision the node with the given image.

        Example::

         provisioner.provision_node("compute-1", "centos",
                                    nics=[{"network": "private"},
                                          {"network": "external"}],
                                    root_size_gb=50,
                                    wait=3600)

        :param node: Node object, UUID or name. Will be reserved first, if
            not reserved already. Must be in the "available" state with
            maintenance mode off.
        :param image: Image source - one of :mod:`~metalsmith.sources`,
            `Image` name or UUID.
        :param nics: List of virtual NICs to attach to physical ports.
            Each item is a dict with a key describing the type of the NIC:

            * ``{"port": "<port name or ID>"}`` to use the provided pre-created
              port.
            * ``{"network": "<network name or ID>"}`` to create a port on the
              provided network. Optionally, a ``fixed_ip`` argument can be used
              to specify an IP address.
            * ``{"subnet": "<subnet name or ID>"}`` to create a port with an IP
              address from the provided subnet. The network is determined from
              the subnet.

        :param root_size_gb: The size of the root partition. By default
            the value of the local_gb property is used.
        :param swap_size_mb: The size of the swap partition. It's an error
            to specify it for a whole disk image.
        :param config: configuration to pass to the instance, one of
            objects from :py:mod:`metalsmith.instance_config`.
        :param hostname: Hostname to assign to the instance. If provided,
            overrides the ``hostname`` passed to ``reserve_node``.
        :param netboot: Whether to use networking boot for final instances.
        :param capabilities: Requested capabilities of the node. If present,
            overwrites the capabilities set by :meth:`reserve_node`.
            Note that the capabilities are not checked against the ones
            provided by the node - use :meth:`reserve_node` for that.
        :param traits: Requested traits of the node. If present, overwrites
            the traits set by :meth:`reserve_node`. Note that the traits are
            not checked against the ones provided by the node - use
            :meth:`reserve_node` for that.
        :param wait: How many seconds to wait for the deployment to finish,
            None to return immediately.
        :param clean_up_on_failure: If True, then on failure the node is
            cleared of instance information, VIFs are detached, created ports
            and allocations are deleted.
        :return: :py:class:`metalsmith.Instance` object with the current
            status of provisioning. If ``wait`` is not ``None``, provisioning
            is already finished.
        :raises: :py:class:`metalsmith.exceptions.Error`
        """
        if config is None:
            config = instance_config.GenericConfig()
        if isinstance(image, str):
            image = sources.GlanceImage(image)

        _utils.check_hostname(hostname)

        try:
            node = self._get_node(node)
        except Exception as exc:
            raise exceptions.InvalidNode('Cannot find node %(node)s: %(exc)s' %
                                         {
                                             'node': node,
                                             'exc': exc
                                         })

        node, allocation = self._check_node_for_deploy(node, hostname)
        nics = _nics.NICs(self.connection,
                          node,
                          nics,
                          hostname=allocation and allocation.name or None)

        try:
            root_size_gb = _utils.get_root_disk(root_size_gb, node)

            image._validate(self.connection, root_size_gb)

            nics.validate()

            if capabilities is None:
                capabilities = node.instance_info.get('capabilities') or {}

            if self._dry_run:
                LOG.warning('Dry run, not provisioning node %s',
                            _utils.log_res(node))
                return node

            nics.create_and_attach_ports()

            capabilities['boot_option'] = 'netboot' if netboot else 'local'

            instance_info = self._clean_instance_info(node.instance_info)
            if root_size_gb is not None:
                instance_info['root_gb'] = root_size_gb
            instance_info['capabilities'] = capabilities
            if hostname:
                instance_info['display_name'] = hostname

            extra = node.extra.copy()
            extra[_CREATED_PORTS] = nics.created_ports
            extra[_ATTACHED_PORTS] = nics.attached_ports
            instance_info.update(image._node_updates(self.connection))
            if traits is not None:
                instance_info['traits'] = traits
            if swap_size_mb is not None:
                instance_info['swap_mb'] = swap_size_mb

            LOG.debug(
                'Updating node %(node)s with instance info %(iinfo)s '
                'and extras %(extra)s', {
                    'node': _utils.log_res(node),
                    'iinfo': instance_info,
                    'extra': extra
                })
            node = self.connection.baremetal.update_node(
                node, instance_info=instance_info, extra=extra)
            self.connection.baremetal.validate_node(node)

            network_data = _network_metadata.create_network_metadata(
                self.connection, node.extra.get(_ATTACHED_PORTS))

            LOG.debug('Generating a configdrive for node %s',
                      _utils.log_res(node))
            cd = config.generate(node, _utils.hostname_for(node, allocation),
                                 network_data)
            LOG.debug('Starting provisioning of node %s', _utils.log_res(node))
            self.connection.baremetal.set_node_provision_state(node,
                                                               'active',
                                                               config_drive=cd)
        except Exception:
            with _utils.reraise_os_exc(
                    exceptions.DeploymentFailed) as expected:
                if clean_up_on_failure:
                    LOG.error('Deploy attempt failed on node %s, cleaning up',
                              _utils.log_res(node),
                              exc_info=not expected)
                    self._clean_up(node, nics=nics)

        LOG.info('Provisioning started on node %s', _utils.log_res(node))

        if wait is not None:
            LOG.debug(
                'Waiting for node %(node)s to reach state active '
                'with timeout %(timeout)s', {
                    'node': _utils.log_res(node),
                    'timeout': wait
                })
            instance = self.wait_for_provisioning([node], timeout=wait)[0]
            LOG.info('Deploy succeeded on node %s', _utils.log_res(node))
        else:
            # Update the node to return it's latest state
            node = self.connection.baremetal.get_node(node.id)
            instance = _instance.Instance(self.connection, node, allocation)

        return instance