summaryrefslogtreecommitdiff
path: root/ironic/common
diff options
context:
space:
mode:
authorLucas Alvares Gomes <lucasagomes@gmail.com>2014-06-30 17:00:56 +0100
committerLucas Alvares Gomes <lucasagomes@gmail.com>2014-07-22 10:16:45 +0100
commita9d7a6567fb89ac59b5d1eb1df3cfee662268f98 (patch)
tree7eebde733cb5d667934ae580f35c842d9fbea5ae /ironic/common
parent036c79e38f994121022a69a0bc76917e0048fd63 (diff)
downloadironic-a9d7a6567fb89ac59b5d1eb1df3cfee662268f98.tar.gz
Rename/update common/tftp.py to common/pxe_utils.py
The functions in the common/tftp.py are not related to TFTP, the functions are PXE related and most of them are used to generate the PXE configuration file. Moving it from tftp.py to pxe_utils.py will make it less confusing and is also needed by the iPXE work since iPXE doesn't generate any configuration file under the TFTP folder. The dhcp_options_for_instance() method was updated to not receive the PXE boot file image from the parameters and just get it from the configuration because we were always using the value from the configuration anyway. Implements: blueprint ipxe-boot Change-Id: Icfbaa4d6cdb9cbe0c392bf3dbd50ad980c70560c
Diffstat (limited to 'ironic/common')
-rw-r--r--ironic/common/neutron.py4
-rw-r--r--ironic/common/pxe_utils.py167
-rw-r--r--ironic/common/tftp.py140
3 files changed, 168 insertions, 143 deletions
diff --git a/ironic/common/neutron.py b/ironic/common/neutron.py
index 897f60610..034a177bd 100644
--- a/ironic/common/neutron.py
+++ b/ironic/common/neutron.py
@@ -23,7 +23,6 @@ from oslo.config import cfg
from ironic.api import acl
from ironic.common import exception
from ironic.common import keystone
-from ironic.common import tftp
from ironic.drivers.modules import ssh
from ironic.openstack.common import log as logging
@@ -144,9 +143,8 @@ def get_node_vif_ids(task):
return port_vifs
-def update_neutron(task, pxe_bootfile_name):
+def update_neutron(task, options):
"""Send or update the DHCP BOOT options to Neutron for this node."""
- options = tftp.dhcp_options_for_instance(pxe_bootfile_name)
vifs = get_node_vif_ids(task)
if not vifs:
LOG.warning(_("No VIFs found for node %(node)s when attempting to "
diff --git a/ironic/common/pxe_utils.py b/ironic/common/pxe_utils.py
new file mode 100644
index 000000000..19685b8f0
--- /dev/null
+++ b/ironic/common/pxe_utils.py
@@ -0,0 +1,167 @@
+#
+# Copyright 2014 Rackspace, Inc
+# All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# 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.
+
+import os
+
+import jinja2
+from oslo.config import cfg
+
+from ironic.common import utils
+from ironic.drivers import utils as driver_utils
+from ironic.openstack.common import fileutils
+from ironic.openstack.common import log as logging
+
+CONF = cfg.CONF
+
+LOG = logging.getLogger(__name__)
+
+PXE_CFG_DIR_NAME = 'pxelinux.cfg'
+
+
+def _ensure_config_dirs_exist(node_uuid):
+ """Ensure that the node's and PXE configuration directories exist.
+
+ :param node_uuid: the UUID of the node.
+
+ """
+ tftp_root = CONF.pxe.tftp_root
+ fileutils.ensure_tree(os.path.join(tftp_root, node_uuid))
+ fileutils.ensure_tree(os.path.join(tftp_root, PXE_CFG_DIR_NAME))
+
+
+def _build_pxe_config(pxe_options, template):
+ """Build the PXE boot configuration file.
+
+ This method builds the PXE boot configuration file by rendering the
+ template with the given parameters.
+
+ :param pxe_options: A dict of values to set on the configuration file.
+ :param template: The PXE configuration template.
+ :returns: A formatted string with the file content.
+
+ """
+ tmpl_path, tmpl_file = os.path.split(template)
+ env = jinja2.Environment(loader=jinja2.FileSystemLoader(tmpl_path))
+ template = env.get_template(tmpl_file)
+ return template.render({'pxe_options': pxe_options,
+ 'ROOT': '{{ ROOT }}'})
+
+
+def _link_mac_pxe_configs(task):
+ """Link each MAC address with the PXE configuration file.
+
+ :param task: A TaskManager instance.
+
+ """
+ pxe_config_file_path = get_pxe_config_file_path(task.node.uuid)
+ for mac in driver_utils.get_node_mac_addresses(task):
+ mac_path = _get_pxe_mac_path(mac)
+ utils.unlink_without_raise(mac_path)
+ utils.create_link_without_raise(pxe_config_file_path, mac_path)
+
+
+def _get_pxe_mac_path(mac):
+ """Convert a MAC address into a PXE config file name.
+
+ :param mac: A MAC address string in the format xx:xx:xx:xx:xx:xx.
+ :returns: the path to the config file.
+
+ """
+ return os.path.join(
+ CONF.pxe.tftp_root,
+ PXE_CFG_DIR_NAME,
+ "01-" + mac.replace(":", "-").lower()
+ )
+
+
+def get_deploy_kr_info(node_uuid, driver_info):
+ """Get uuid and tftp path for deploy kernel and ramdisk.
+
+ Note: driver_info should be validated outside of this method.
+ """
+ image_info = {}
+ for label in ('deploy_kernel', 'deploy_ramdisk'):
+ # the values for these keys will look like "glance://image-uuid"
+ image_info[label] = (
+ str(driver_info[label]).split('/')[-1],
+ os.path.join(CONF.pxe.tftp_root, node_uuid, label)
+ )
+ return image_info
+
+
+def get_pxe_config_file_path(node_uuid):
+ """Generate the path for the node's PXE configuration file.
+
+ :param node_uuid: the UUID of the node.
+ :returns: The path to the node's PXE configuration file.
+
+ """
+ return os.path.join(CONF.pxe.tftp_root, node_uuid, 'config')
+
+
+def create_pxe_config(task, pxe_options, template=None):
+ """Generate PXE configuration file and MAC address links for it.
+
+ This method will generate the PXE configuration file for the task's
+ node under a directory named with the UUID of that node. For each
+ MAC address (port) of that node, a symlink for the configuration file
+ will be created under the PXE configuration directory, so regardless
+ of which port boots first they'll get the same PXE configuration.
+
+ :param task: A TaskManager instance.
+ :param pxe_options: A dictionary with the PXE configuration
+ parameters.
+ :param template: The PXE configuration template. If no template is
+ given the CONF.pxe.pxe_config_template will be used.
+
+ """
+ LOG.debug("Building PXE config for node %s", task.node.uuid)
+
+ if template is None:
+ template = CONF.pxe.pxe_config_template
+
+ _ensure_config_dirs_exist(task.node.uuid)
+
+ pxe_config_file_path = get_pxe_config_file_path(task.node.uuid)
+ pxe_config = _build_pxe_config(pxe_options, template)
+ utils.write_to_file(pxe_config_file_path, pxe_config)
+ _link_mac_pxe_configs(task)
+
+
+def clean_up_pxe_config(task):
+ """Clean up the TFTP environment for the task's node.
+
+ :param task: A TaskManager instance.
+
+ """
+ LOG.debug("Cleaning up PXE config for node %s", task.node.uuid)
+
+ for mac in driver_utils.get_node_mac_addresses(task):
+ utils.unlink_without_raise(_get_pxe_mac_path(mac))
+
+ utils.rmtree_without_raise(os.path.join(CONF.pxe.tftp_root,
+ task.node.uuid))
+
+
+def dhcp_options_for_instance():
+ """Retrieves the DHCP PXE boot options."""
+ return [{'opt_name': 'bootfile-name',
+ 'opt_value': CONF.pxe.pxe_bootfile_name},
+ {'opt_name': 'server-ip-address',
+ 'opt_value': CONF.pxe.tftp_server},
+ {'opt_name': 'tftp-server',
+ 'opt_value': CONF.pxe.tftp_server}
+ ]
diff --git a/ironic/common/tftp.py b/ironic/common/tftp.py
deleted file mode 100644
index 88399e0da..000000000
--- a/ironic/common/tftp.py
+++ /dev/null
@@ -1,140 +0,0 @@
-#
-# Copyright 2014 Rackspace, Inc
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# 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.
-
-import os
-
-import jinja2
-from oslo.config import cfg
-
-from ironic.common import utils
-from ironic.drivers import utils as driver_utils
-from ironic.openstack.common import fileutils
-from ironic.openstack.common import log as logging
-
-
-tftp_opts = [
- cfg.StrOpt('tftp_server',
- default='$my_ip',
- help='IP address of Ironic compute node\'s tftp server.',
- deprecated_group='pxe'),
- cfg.StrOpt('tftp_root',
- default='/tftpboot',
- help='Ironic compute node\'s tftp root path.',
- deprecated_group='pxe')
- ]
-
-CONF = cfg.CONF
-CONF.register_opts(tftp_opts, group='tftp')
-
-LOG = logging.getLogger(__name__)
-
-
-def get_deploy_kr_info(node_uuid, driver_info):
- """Get uuid and tftp path for deploy kernel and ramdisk.
-
- Note: driver_info should be validated outside of this method.
- """
- image_info = {}
- for label in ('deploy_kernel', 'deploy_ramdisk'):
- # the values for these keys will look like "glance://image-uuid"
- image_info[label] = (
- str(driver_info[label]).split('/')[-1],
- os.path.join(CONF.tftp.tftp_root, node_uuid, label)
- )
- return image_info
-
-
-def create_pxe_config(task, pxe_options, pxe_config_template):
- """Generate PXE configuration file and MAC symlinks for it."""
- node = task.node
- fileutils.ensure_tree(os.path.join(CONF.tftp.tftp_root,
- node.uuid))
- fileutils.ensure_tree(os.path.join(CONF.tftp.tftp_root,
- 'pxelinux.cfg'))
-
- pxe_config_file_path = get_pxe_config_file_path(node.uuid)
- pxe_config = build_pxe_config(node, pxe_options, pxe_config_template)
- utils.write_to_file(pxe_config_file_path, pxe_config)
- _write_mac_pxe_configs(task)
-
-
-def clean_up_pxe_config(task):
- """Clean up the TFTP environment for the task's node."""
- node = task.node
-
- utils.unlink_without_raise(get_pxe_config_file_path(node.uuid))
- for port in driver_utils.get_node_mac_addresses(task):
- utils.unlink_without_raise(get_pxe_mac_path(port))
-
- utils.rmtree_without_raise(os.path.join(CONF.tftp.tftp_root, node.uuid))
-
-
-def _write_mac_pxe_configs(task):
- """Create a file in the PXE config directory for each MAC so regardless
- of which port boots first, they'll get the same PXE config.
- """
- pxe_config_file_path = get_pxe_config_file_path(task.node.uuid)
- for port in driver_utils.get_node_mac_addresses(task):
- mac_path = get_pxe_mac_path(port)
- utils.unlink_without_raise(mac_path)
- utils.create_link_without_raise(pxe_config_file_path, mac_path)
-
-
-def build_pxe_config(node, pxe_options, pxe_config_template):
- """Build the PXE config file for a node
-
- This method builds the PXE boot configuration file for a node,
- given all the required parameters.
-
- :param pxe_options: A dict of values to set on the configuration file
- :returns: A formatted string with the file content.
- """
- LOG.debug("Building PXE config for deployment %s."), node['id']
-
- tmpl_path, tmpl_file = os.path.split(pxe_config_template)
- env = jinja2.Environment(loader=jinja2.FileSystemLoader(tmpl_path))
- template = env.get_template(tmpl_file)
- return template.render({'pxe_options': pxe_options,
- 'ROOT': '{{ ROOT }}'})
-
-
-def get_pxe_mac_path(mac):
- """Convert a MAC address into a PXE config file name.
-
- :param mac: A mac address string in the format xx:xx:xx:xx:xx:xx.
- :returns: the path to the config file.
- """
- return os.path.join(
- CONF.tftp.tftp_root,
- 'pxelinux.cfg',
- "01-" + mac.replace(":", "-").lower()
- )
-
-
-def get_pxe_config_file_path(node_uuid):
- """Generate the path for an instances PXE config file."""
- return os.path.join(CONF.tftp.tftp_root, node_uuid, 'config')
-
-
-def dhcp_options_for_instance(pxe_bootfile_name):
- """Retrives the DHCP PXE boot options."""
- return [{'opt_name': 'bootfile-name',
- 'opt_value': pxe_bootfile_name},
- {'opt_name': 'server-ip-address',
- 'opt_value': CONF.tftp.tftp_server},
- {'opt_name': 'tftp-server',
- 'opt_value': CONF.tftp.tftp_server}
- ]