~ubuntu-branches/ubuntu/vivid/ironic/vivid-updates

« back to all changes in this revision

Viewing changes to ironic/dhcp/neutron.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2015-03-30 11:14:57 UTC
  • mfrom: (1.2.6)
  • Revision ID: package-import@ubuntu.com-20150330111457-kr4ju3guf22m4vbz
Tags: 2015.1~b3-0ubuntu1
* New upstream release.
  + d/control: 
    - Align with upstream dependencies.
    - Add dh-python to build-dependencies.
    - Add psmisc as a dependency. (LP: #1358820)
  + d/p/fix-requirements.patch: Rediffed.
  + d/ironic-conductor.init.in: Fixed typos in LSB headers,
    thanks to JJ Asghar. (LP: #1429962)

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
from neutronclient.common import exceptions as neutron_client_exc
20
20
from neutronclient.v2_0 import client as clientv20
21
 
from oslo.utils import netutils
22
21
from oslo_config import cfg
 
22
from oslo_utils import netutils
23
23
 
24
24
from ironic.common import exception
25
25
from ironic.common.i18n import _
27
27
from ironic.common.i18n import _LW
28
28
from ironic.common import keystone
29
29
from ironic.common import network
 
30
from ironic.conductor import manager
30
31
from ironic.dhcp import base
31
32
from ironic.drivers.modules import ssh
32
33
from ironic.openstack.common import log as logging
48
49
                    'to neutron. Can be either "keystone" or "noauth". '
49
50
                    'Running neutron in noauth mode (related to but not '
50
51
                    'affected by this setting) is insecure and should only be '
51
 
                    'used for testing.')
 
52
                    'used for testing.'),
 
53
    cfg.StrOpt('cleaning_network_uuid',
 
54
               help='UUID of the network to create Neutron ports on when '
 
55
                    'booting to a ramdisk for cleaning/zapping using Neutron '
 
56
                    'DHCP')
52
57
    ]
53
58
 
54
59
CONF = cfg.CONF
140
145
                              "port %s."), port_id)
141
146
            raise exception.FailedToUpdateMacOnPort(port_id=port_id)
142
147
 
143
 
    def update_dhcp_opts(self, task, options):
 
148
    def update_dhcp_opts(self, task, options, vifs=None):
144
149
        """Send or update the DHCP BOOT options for this node.
145
150
 
146
151
        :param task: A TaskManager instance.
147
 
        :param dhcp_opts: this will be a list of dicts, e.g.
 
152
        :param options: this will be a list of dicts, e.g.
148
153
 
149
154
                          ::
150
155
 
154
159
                             'opt_value': '123.123.123.456'},
155
160
                            {'opt_name': 'tftp-server',
156
161
                             'opt_value': '123.123.123.123'}]
 
162
        :param vifs: a dict of Neutron port dicts to update DHCP options on.
 
163
            The keys should be Ironic port UUIDs, and the values should be
 
164
            Neutron port UUIDs
 
165
            If the value is None, will get the list of ports from the Ironic
 
166
            port objects.
157
167
        """
158
 
        vifs = network.get_node_vif_ids(task)
 
168
        if vifs is None:
 
169
            vifs = network.get_node_vif_ids(task)
159
170
        if not vifs:
160
171
            raise exception.FailedToUpdateDHCPOptOnPort(
161
172
                _("No VIFs found for node %(node)s when attempting "
184
195
        # TODO(adam_g): Hack to workaround bug 1334447 until we have a
185
196
        # mechanism for synchronizing events with Neutron.  We need to sleep
186
197
        # only if we are booting VMs, which is implied by SSHPower, to ensure
187
 
        # they do not boot before Neutron agents have setup sufficent DHCP
 
198
        # they do not boot before Neutron agents have setup sufficient DHCP
188
199
        # config for netboot.
189
200
        if isinstance(task.driver.power, ssh.SSHPower):
190
201
            LOG.debug("Waiting 15 seconds for Neutron.")
275
286
                         {'node': task.node.uuid, 'ports': failures})
276
287
 
277
288
        return ip_addresses
 
289
 
 
290
    def create_cleaning_ports(self, task):
 
291
        """Create neutron ports for each port on task.node to boot the ramdisk.
 
292
 
 
293
        :param task: a TaskManager instance.
 
294
        :raises: InvalidParameterValue if the cleaning network is None
 
295
        :returns: a dictionary in the form {port.uuid: neutron_port['id']}
 
296
        """
 
297
        if not CONF.neutron.cleaning_network_uuid:
 
298
            raise exception.InvalidParameterValue(_('Valid cleaning network '
 
299
                                                    'UUID not provided'))
 
300
        neutron_client = _build_client(task.context.auth_token)
 
301
        body = {
 
302
            'port': {
 
303
                'network_id': CONF.neutron.cleaning_network_uuid,
 
304
                'admin_state_up': True,
 
305
            }
 
306
        }
 
307
        ports = {}
 
308
        for ironic_port in task.ports:
 
309
            body['port']['mac_address'] = ironic_port.address
 
310
            try:
 
311
                port = neutron_client.create_port(body)
 
312
            except neutron_client_exc.ConnectionFailed as e:
 
313
                msg = (_('Could not create cleaning port on network %(net)s '
 
314
                         'from %(node)s. %(exc)s') %
 
315
                       {'net': CONF.neutron.cleaning_network_uuid,
 
316
                        'node': task.node.uuid,
 
317
                        'exc': e})
 
318
                LOG.exception(msg)
 
319
                return manager.cleaning_error_handler(task, msg)
 
320
            if not port.get('port') or not port['port'].get('id'):
 
321
                # Rollback changes
 
322
                try:
 
323
                    self.delete_cleaning_ports(task)
 
324
                except Exception:
 
325
                    # Log the error, but continue to cleaning error handler
 
326
                    LOG.exception(_LE('Failed to rollback cleaning port '
 
327
                                      'changes for node %s') % task.node.uuid)
 
328
                msg = (_('Failed to create cleaning ports for node '
 
329
                         '%(node)s') % task.node.uuid)
 
330
                LOG.error(msg)
 
331
                return manager.cleaning_error_handler(task, msg)
 
332
            # Match return value of get_node_vif_ids()
 
333
            ports[ironic_port.uuid] = port['port']['id']
 
334
        return ports
 
335
 
 
336
    def delete_cleaning_ports(self, task):
 
337
        """Deletes the neutron port created for booting the ramdisk.
 
338
 
 
339
        :param task: a TaskManager instance.
 
340
        """
 
341
        neutron_client = _build_client(task.context.auth_token)
 
342
        macs = [p.address for p in task.ports]
 
343
        params = {
 
344
            'network_id': CONF.neutron.cleaning_network_uuid
 
345
        }
 
346
        try:
 
347
            ports = neutron_client.list_ports(**params)
 
348
        except neutron_client_exc.ConnectionFailed as e:
 
349
            msg = (_('Could not get cleaning network vif for %(node)s '
 
350
                     'from Neutron, possible network issue. %(exc)s') %
 
351
                   {'node': task.node.uuid,
 
352
                    'exc': e})
 
353
            LOG.exception(msg)
 
354
            return manager.cleaning_error_handler(task, msg)
 
355
 
 
356
        # Iterate the list of Neutron port dicts, remove the ones we added
 
357
        for neutron_port in ports.get('ports', []):
 
358
            # Only delete ports using the node's mac addresses
 
359
            if neutron_port.get('mac_address') in macs:
 
360
                try:
 
361
                    neutron_client.delete_port(neutron_port.get('id'))
 
362
                except neutron_client_exc.ConnectionFailed as e:
 
363
                    msg = (_('Could not remove cleaning ports on network '
 
364
                             '%(net)s from %(node)s, possible network issue. '
 
365
                             '%(exc)s') %
 
366
                           {'net': CONF.neutron.cleaning_network_uuid,
 
367
                            'node': task.node.uuid,
 
368
                            'exc': e})
 
369
                    LOG.exception(msg)
 
370
                    return manager.cleaning_error_handler(task, msg)