--- /dev/null
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
--- /dev/null
+Name: ipa-deployer
+Version: %{_version}
+Release: 1%{?dist}
+Summary: Deployment image for ironic python agent
+
+License: %{_platform_licence}
+Source0: %{name}-%{version}.tar.gz
+Vendor: %{_platform_vendor}
+
+BuildArch: noarch
+BuildRequires: diskimage-builder qemu-img-ev which sudo PyYAML e2fsprogs syslinux genisoimage wget kernel python2-ironic-python-agent python-ironic-lib python-devel
+
+%define dib_selinuxfile elements/rpm-distro/cleanup.d/99-selinux-fixfiles-restore
+%define dib_epel elements/epel/pre-install.d/05-rpm-epel-release
+
+%description
+Deployment image for ironic python agent image
+
+%prep
+%autosetup
+
+%build
+sudo rm -rf %{python2_sitelib}/diskimage_builder/%{dib_selinuxfile} %{_datarootdir}ยง/diskimage-builder/%{dib_selinuxfile} %{python2_sitelib}/diskimage_builder/elements/epel/pre-install.d/05-rpm-epel-release
+cp /etc/yum.conf work/local.repo
+wget --progress=dot:giga https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1801-01.qcow2 -O CentOS.qcow2
+DIB_DEBUG_TRACE=1 \
+ ELEMENTS_PATH="${PWD}/work/dib-ipa-element/" \
+ DIB_LOCAL_IMAGE="file://${PWD}/CentOS.qcow2" \
+ DIB_YUM_REPO_CONF="work/local.repo" \
+ DIB_LOCAL_REPO="/usr/localrepo/" \
+ break=after-error /usr/bin/disk-image-create --install-type package localrepo centos7 virtmedia-netconf ironic-agent
+
+if [[ $? == 0 ]]; then
+ work/iso-image-create -o ./ironic-deploy.iso -i ./image.initramfs -k ./image.vmlinuz
+else
+ echo "Failed to run disk-image-create"
+fi
+
+%install
+mkdir -p %{buildroot}/opt/images/
+rsync -av ironic-deploy.iso %{buildroot}/opt/images/
+
+%files
+%defattr(0755,root,root)
+/opt/images/
--- /dev/null
+#!/bin/bash
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+
+if [ ${DIB_DEBUG_TRACE:-0} -gt 0 ]; then
+ set -x
+fi
+set -eu
+set -o pipefail
+
+[ -n "$TARGET_ROOT" ]
+
+# Remove all the repo file content in the target root.
+for file in `ls $TMP_MOUNT_PATH/etc/yum.repos.d/*.repo`; do
+ sudo truncate -s 0 $file
+done
+
+# mount the local repo dir on target loop device
+sudo mkdir -p $TARGET_ROOT/$DIB_LOCAL_REPO
+sudo mount --bind $DIB_LOCAL_REPO $TARGET_ROOT/$DIB_LOCAL_REPO
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+if [ "${DIB_DEBUG_TRACE:-0}" -gt 0 ]; then
+ set -x
+fi
+set -eu
+set -o pipefail
+
+echo > $TARGET_ROOT/etc/resolv.conf
+
+if [ -n "${DIB_YUM_REPO_CONF}" ]; then
+ rm -rf $TARGET_ROOT/${DIB_YUM_REPO_CONF}
+fi
--- /dev/null
+#!/bin/bash
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+
+if [ "${DIB_DEBUG_TRACE:-0}" -gt 0 ]; then
+ set -x
+fi
+set -eu
+set -o pipefail
+
+unlink /etc/udev/rules.d/80-net-name-slot.rules
--- /dev/null
+#!/bin/bash
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+
+if [ "${DIB_DEBUG_TRACE:-0}" -gt 0 ]; then
+ set -x
+fi
+set -eu
+set -o pipefail
+
+#TODO:- At the moment ipa ramdisk is 34MB. Some more packages should be added to,
+# the below remove list to reduce the size. Easy way to find the list:
+# 1. Extract ipa ramdisk.
+# 2. Chroot to the rootfs
+# 3. yum erase unused packages one by one.
+# 4. Verify openstack-ironic-python-agent and its dependent packages remain.
+
+install-packages -e kernel-debug-devel gcc rsync sudo pykickstart genisoimage \
+ man-db kbd-misc plymouth cronie \
+ kernel-headers
+
+# chrony cpp* cups* GeoIP gsettings-desktop-schemas \
+# libjpeg-turbo nfs* newt* numactl-libs openjpeg2
+
+${YUM:-yum} clean all
+
+# Rebuilding the rpm database after removing packages will reduce
+# its size
+rpm --rebuilddb
--- /dev/null
+#!/bin/bash
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+
+if [ "${DIB_DEBUG_TRACE:-0}" -gt 0 ]; then
+ set -x
+fi
+set -eu
+set -o pipefail
+
+rm -rf ironic-virtmedia-netconfig
+rm -rf ironic-bmc-hardware-manager
--- /dev/null
+#!/bin/bash
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+
+if [ "${DIB_DEBUG_TRACE:-0}" -gt 0 ]; then
+ set -x
+fi
+set -eu
+set -o pipefail
+
+if [ -e /etc/udev/rules.d/99-dhcp-all-interfaces.rules ]; then
+ rm -f /etc/udev/rules.d/99-dhcp-all-interfaces.rules
+fi
+
--- /dev/null
+#!/bin/bash
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+
+if [ "${DIB_DEBUG_TRACE:-0}" -gt 0 ]; then
+ set -x
+fi
+set -eu
+set -o pipefail
+
+cp -r $(find / -name ironic-virtmedia-netconfig -type d) .
+pushd ironic-virtmedia-netconfig/src/
+python setup.py install --root / --no-compile --install-purelib /lib/python2.7/site-packages/
+popd
+cp -r $(find / -name ironic-bmc-hardware-manager -type d) .
+pushd ironic-bmc-hardware-manager/src
+python setup.py install --root / --no-compile --install-purelib /lib/python2.7/site-packages/
+popd
+cp ironic-virtmedia-netconfig/bin/virtmedia-netconfig /usr/bin/
+cp ironic-virtmedia-netconfig/bin/erase-oldfs.sh /usr/bin/
+cp ironic-virtmedia-netconfig/services/virtmedia-netconfig.service /lib/systemd/system/
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+numa-mpol-local-wrapper
+openvswitch
+os-net-config
+qemu-img-ev
+biosdevname
+#patch
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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
+
+from ironic_python_agent import hardware
+from ironic_python_agent import utils
+
+from oslo_log import log
+from oslo_concurrency import processutils
+
+
+LOG = log.getLogger()
+
+
+class BMCHardwareManager(hardware.GenericHardwareManager):
+ HARDWARE_MANAGER_NAME = 'BMCHardwareManager'
+ HARDWARE_MANAGER_VERSION = '1'
+
+ def evaluate_hardware_support(self):
+ """Declare level of hardware support provided."""
+
+ LOG.info('Running in BMC environment')
+ return hardware.HardwareSupport.SERVICE_PROVIDER
+
+ def list_network_interfaces(self):
+ network_interfaces_list = []
+
+ bmc_mac = self.get_ipmi_info().get('MAC Address', False)
+ if bmc_mac:
+ LOG.info("Adding MAC address net interfaces %s", bmc_mac)
+ bmc_address = self.get_bmc_address()
+ network_interfaces_list.append(hardware.NetworkInterface(
+ name="BMC_INTERFACE",
+ mac_addr=bmc_mac,
+ ipv4_address=bmc_address,
+ has_carrier=True,
+ vendor="BMC",
+ product="Akraino"))
+
+ else:
+ network_interfaces_list = super(BMCHardwareManager, self).list_network_interfaces()
+ return network_interfaces_list
+
+ def get_ipmi_info(self):
+ # These modules are rarely loaded automatically
+ utils.try_execute('modprobe', 'ipmi_msghandler')
+ utils.try_execute('modprobe', 'ipmi_devintf')
+ utils.try_execute('modprobe', 'ipmi_si')
+
+ try:
+ out, _e = utils.execute(
+ "ipmitool lan print", shell=True, attempts=2)
+ except (processutils.ProcessExecutionError, OSError) as e:
+ # Not error, because it's normal in virtual environment
+ LOG.warning("Cannot get BMC info: %s", e)
+ return {}
+
+ info = {}
+ for line in out.split('\n'):
+ spl = line.find(':')
+ if spl == -1:
+ continue
+ else:
+ key = line[0:spl].strip()
+ if key == '':
+ continue
+ info[line[0:spl].strip()] = line[spl+1:].strip()
+ return info
+
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+from setuptools import setup, find_packages
+
+VERSION = '0.1'
+PROJECT = 'ironic_bmc_hardware_manager'
+
+setup(
+ name=PROJECT,
+ version=VERSION,
+ description='ironic_bmc_hardware_manager',
+ author='Janne Suominen',
+ author_email='janne.suominen@nokia.com',
+ platforms=['Any'],
+ scripts=[],
+ provides=[],
+ install_requires=['openstack-ironic-python-agent'],
+ namespace_packages=[],
+ packages=find_packages(),
+ entry_points={
+ 'ironic_python_agent.hardware_managers': [
+ 'bmc = ironic_bmc_hardware_manager.bmc:BMCHardwareManager'
+ ],
+ },
+ zip_safe=False,
+)
--- /dev/null
+#!/bin/bash
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+SYS_BLOCK="/sys/class/block"
+
+function is_partition(){
+ device=$1
+ if [ -e $SYS_BLOCK/$device/partition ];then
+ return 0
+ else
+ return 1
+ fi
+}
+
+function is_removable(){
+ device=$1
+ sysdev=$SYS_BLOCK/$device
+ if ( is_partition $device );then
+ removable=$(readlink -f $sysdev/..)/removable
+ else
+ removable=$sysdev/removable
+ fi
+ if [ -e $removable ] && [ $(cat $removable) -eq 1 ];then
+ return 0
+ else
+ return 1
+ fi
+
+}
+
+device_list=$(ls $SYS_BLOCK)
+read -r -a hd_devices <<< $device_list
+
+
+for hd_dev in ${hd_devices[@]}; do
+ if [ -b /dev/$hd_dev ] && (( is_removable $hd_dev ) || ( is_partition $hd_dev )); then
+ echo "Removable or partition $hd_dev. Skipping..."
+ continue
+ fi
+ wipefs --all /dev/$hd_dev
+ sgdisk -Z -o /dev/$hd_dev
+ dd if=/dev/zero of=/dev/$hd_dev bs=1M count=200
+done
--- /dev/null
+#!/usr/bin/python2
+# Copyright 2019 Nokia
+#
+# 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 sys
+
+from virtmedia_netconfig import main
+
+
+if __name__ == "__main__":
+ sys.exit(main.main())
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+[Unit]
+Description=Service to configure network by reading configuration from Virtual media.
+Wants=network-online.target
+After=network-online.target local-fs.target
+Before=openstack-ironic-python-agent.service
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/virtmedia-netconfig
+StandardOutput=kmsg+console
+StandardError=inherit
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+VERSION = '0.1'
+PROJECT = 'virtmedia_netconfig'
+
+from setuptools import setup, find_packages
+setup(
+ name=PROJECT,
+ version=VERSION,
+ description='ironic-virtmedia-netconfig',
+ author='Chandra Rangavajjula',
+ author_email='chandra.s.rangavajjula@nokia.com',
+ platforms=['Any'],
+ scripts=[],
+ provides=[],
+ install_requires=['openstack-ironic-python-agent'],
+ namespace_packages=[],
+ packages=find_packages(),
+ include_package_data=True,
+ entry_points={},
+ zip_safe=False,
+)
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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__('pkg_resources').declare_namespace(__name__)
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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 tarfile
+import sys
+import os
+import errno
+import stat
+import time
+import tempfile
+import shutil
+
+import json
+import logging
+import subprocess
+
+from oslo_config import cfg
+from oslo_log import log
+from ironic_python_agent import utils
+from ironic_lib import utils as ironic_utils
+from ironic_python_agent import errors
+from oslo_concurrency import processutils
+
+CONF = cfg.CONF
+LOG = log.getLogger(__name__)
+dhclient_physIfaces = []
+
+def dhclient_path():
+ if os.path.exists("/usr/sbin/dhclient"):
+ return "/usr/sbin/dhclient"
+ elif os.path.exists("/sbin/dhclient"):
+ return "/sbin/dhclient"
+ else:
+ raise RuntimeError("Could not find dhclient")
+
+def stop_dhclient_process(interface):
+ """Stop a DHCP process before running os-net-config.
+
+ :param interface: The interface on which to stop dhclient.
+ """
+ pid_file = '/var/run/dhclient-%s.pid' % (interface)
+ try:
+ dhclient = dhclient_path()
+ except RuntimeError as err:
+ LOG.info('Exception when stopping dhclient: %s' % err)
+ return
+
+ if os.path.exists(pid_file):
+ LOG.info('Stopping %s on interface %s' % (dhclient, interface))
+ utils.execute(dhclient, '-r', '-pf', pid_file, interface)
+ try:
+ os.unlink(pid_file)
+ except OSError as err:
+ LOG.error('Could not remove dhclient pid file \'%s\': %s' %
+ (pid_file, err))
+
+def _poll_interface(_ifacedata):
+ ifacedata = json.loads(_ifacedata)
+ global dhclient_physIfaces
+
+ physIfaces = []
+ if "network_config" in ifacedata:
+ for netconfdata in ifacedata["network_config"]:
+ if "device" in netconfdata:
+ if "bond" not in netconfdata["device"]:
+ # Is (physical) interface
+ LOG.debug('Physical device %s' % netconfdata["device"])
+ physIfaces.append(netconfdata["device"])
+
+ elif "members" in netconfdata:
+ # logical interface with member (f.ex bond)
+ for _member in netconfdata["members"]:
+ if "type" in _member:
+ if _member["type"] == 'interface':
+ if "name" in _member:
+ LOG.debug('Physical device %s' % _member["name"])
+ physIfaces.append(_member["name"])
+ elif "name" in netconfdata:
+ if "type" in netconfdata and netconfdata["type"] == 'interface':
+ LOG.debug('Physical device %s' % netconfdata["name"])
+ physIfaces.append(netconfdata["name"])
+
+ LOG.info('Checking for physical device(s) "%s"' % ', '.join(physIfaces))
+ dhclient_physIfaces = list(physIfaces)
+ wait_secs = 5
+ max_wait_secs = 60
+
+ while len(physIfaces) > 0 and max_wait_secs >= 0:
+ missing_devices = []
+ max_wait_secs = max_wait_secs - wait_secs
+
+ for _device in physIfaces:
+ devicepath = "/sys/class/net/%s/device" % _device
+ LOG.debug('Check path "%s"' % devicepath )
+ if os.path.exists(devicepath):
+ LOG.debug('Device "%s" in known by kernel' % _device)
+ physIfaces.remove(_device)
+ else:
+ LOG.debug('Device "%s" in not (yet) known by kernel' % _device)
+ missing_devices.append(_device)
+
+ if len(physIfaces) > 0:
+ LOG.info('Device(s) not (yet?) known by kernel: "%s"' % ', '.join(missing_devices))
+ time.sleep(wait_secs)
+
+
+ if len(physIfaces) > 0:
+ msg = 'Timeout, Device(s) missing: "%s"' % ', '.join(physIfaces)
+ LOG.error(msg)
+ raise errors.VirtualMediaBootError(msg)
+ else:
+ LOG.info('All physical devices found.')
+
+ for _device in dhclient_physIfaces:
+ stop_dhclient_process(_device)
+
+def _configure_static_net(os_net_config):
+ """Configures network using os-net-config utility"""
+ global dhclient_physIfaces
+ LOG.debug("Configuring static network with os-net-config: %s", os_net_config)
+ try:
+ os.makedirs('/etc/os-net-config/')
+ except OSError as exc:
+ if exc.errno != errno.EEXIST:
+ raise
+ pass
+ with open('/etc/os-net-config/config.yaml', 'w') as fp:
+ fp.write(os_net_config)
+
+ try:
+ _poll_interface(os_net_config)
+ except Exception as e:
+ LOG.info('Exception while checking for physical interfaces: %s' % str(e) )
+
+ try:
+ os.system('/usr/sbin/ip a > /tmp/ifaces_before_initial_netconfig')
+ except Exception as e:
+ LOG.info('Exception while logging runtime ifaces to /tmp/ifaces_before_initial_netconfig: %s' % str(e) )
+
+ LOG.info('Running os-net-config..')
+
+ cmd = [ '/usr/bin/os-net-config', '--detailed-exit-codes', '-v', '-c', '/etc/os-net-config/config.yaml']
+ wait_secs = 5
+ retries = 3
+ while retries > 0:
+ retries = retries - 1
+ netconf_process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ while True:
+ output = netconf_process.stdout.readline()
+ if output == '' and netconf_process.poll() is not None:
+ break
+ if output:
+ LOG.info(output.strip())
+
+ rc = netconf_process.poll()
+ LOG.info('os-net-config exit with status %d' % rc)
+
+ # os-net-config returns:
+ # 0 when nothing changed,
+ # 1 on error,
+ # 2 when config was modified (assuming option "--detailed-exit-codes")
+
+ if rc == 0 or rc == 1:
+ LOG.info('os-net-config modified nothing or execution error. Not what we want..')
+ LOG.info('Attempt removing physical interface ifcfg-files to force os-net-config to reconfigure')
+
+ for iface in dhclient_physIfaces:
+ ifcfg_file = '/etc/sysconfig/network-scripts/ifcfg-' + str(iface)
+ try:
+ LOG.info('Removing "%s"' % ifcfg_file)
+ os.system('/usr/bin/rm -f ' + ifcfg_file)
+ except Exception as e:
+ LOG.info('Ignoring exception when removing "%s": %s' % (ifcfg_file, str(e)))
+ pass
+ time.sleep(wait_secs)
+
+ elif rc == 2:
+ LOG.info('os-net-config done.')
+ break
+ else:
+ LOG.info('os-net-config unknown exit code??')
+ time.sleep(wait_secs)
+
+ # Config should be in place assuming os-net-config above was successfull
+ # As additional step restart network.service
+ LOG.info('Restarting network.service')
+ try:
+ cmd = ['/usr/bin/systemctl', 'restart', 'network']
+ subprocess.check_call(cmd)
+ except Exception as e:
+ LOG.info('Igoring exception when restarting network service: %s' % str(e))
+ pass
+
+
+def get_file_size(filename):
+ "Get the file size by seeking at end"
+ fd= os.open(filename, os.O_RDONLY)
+ try:
+ return os.lseek(fd, 0, os.SEEK_END)
+ finally:
+ os.close(fd)
+
+def wait_for_cd_device():
+ """ This function waits for /dev/sr0 device to appear """
+ inputiso = '/dev/sr0'
+ wait_count = 30
+ while not os.path.exists(inputiso) and wait_count:
+ LOG.debug('Waiting for %s to appear. Time left = %d secs' %(inputiso,wait_count))
+ time.sleep(1)
+ wait_count -= 1
+
+ if not wait_count:
+ msg = "Unable to find device %s" %(inputiso)
+ raise errors.VirtualMediaBootError(msg)
+
+def check_cd_config():
+ """ This function checks for any extended 64K block in CD.
+ If it is available it will extract the contents for the block.
+ Loop mount the image for reading configuration parameters.
+ """
+ inputiso = '/dev/sr0'
+ outputtgz = '/tmp/cdconf.tgz'
+ mode = os.stat(inputiso).st_mode
+ if stat.S_ISBLK(mode):
+ filesize = get_file_size(inputiso)
+ skip = filesize / 2048-32
+ ironic_utils.dd(inputiso, outputtgz, 'bs=2k', 'skip=%d'%skip)
+
+ # Check if tgz file is valid.
+ try:
+ utils.execute("/usr/bin/gzip", '-t', outputtgz)
+ except processutils.ProcessExecutionError as err:
+ if 'not in gzip format' in err.stderr:
+ LOG.info('File is not gzip format skipping!!')
+ sys.exit()
+
+ LOG.info('Configuration file in gzip format proceeding for extraction')
+ tar = tarfile.open(outputtgz)
+ tar.extractall('/tmp/floppy')
+ tar.close()
+
+ dir_list = os.listdir('/tmp/floppy')
+ for item in dir_list:
+ if item.find('.img') != -1:
+ os.mkdir('/tmp/floppy/mnt')
+ utils.execute("mount", '-o', 'loop', '/tmp/floppy/%s' %item, '/tmp/floppy/mnt')
+ time.sleep(1)
+
+def _get_vmedia_params():
+ """This method returns the parameters passed through virtual media floppy.
+
+ :returns: a partial dict of potential agent configuration parameters
+ :raises: VirtualMediaBootError when it cannot find the virtual media device
+ """
+ parameters_file = "parameters.txt"
+
+ vmedia_device_file_lower_case = "/dev/disk/by-label/ir-vfd-dev"
+ vmedia_device_file_upper_case = "/dev/disk/by-label/IR-VFD-DEV"
+ if os.path.exists(vmedia_device_file_lower_case):
+ vmedia_device_file = vmedia_device_file_lower_case
+ elif os.path.exists(vmedia_device_file_upper_case):
+ vmedia_device_file = vmedia_device_file_upper_case
+ else:
+
+ # TODO(rameshg87): This block of code is there only for compatibility
+ # reasons (so that newer agent can work with older Ironic). Remove
+ # this after Liberty release.
+ vmedia_device = utils._get_vmedia_device()
+ if not vmedia_device:
+ msg = "Unable to find virtual media device"
+ raise errors.VirtualMediaBootError(msg)
+
+ vmedia_device_file = os.path.join("/dev", vmedia_device)
+
+ vmedia_mount_point = tempfile.mkdtemp()
+ try:
+ try:
+ stdout, stderr = utils.execute("mount", vmedia_device_file,
+ vmedia_mount_point)
+ except processutils.ProcessExecutionError as e:
+ msg = ("Unable to mount virtual media device %(device)s: "
+ "%(error)s" % {'device': vmedia_device_file, 'error': e})
+ raise errors.VirtualMediaBootError(msg)
+
+ parameters_file_path = os.path.join(vmedia_mount_point,
+ parameters_file)
+ params = _read_params_from_file(parameters_file_path, '\n')
+
+ try:
+ stdout, stderr = utils.execute("umount", vmedia_mount_point)
+ except processutils.ProcessExecutionError as e:
+ pass
+ finally:
+ try:
+ shutil.rmtree(vmedia_mount_point)
+ except Exception as e:
+ pass
+
+ return params
+
+def _read_params_from_file(filepath, seperator=None):
+ """Extract key=value pairs from a file.
+
+ :param filepath: path to a file containing key=value pairs separated by
+ whitespace or newlines.
+ :returns: a dictionary representing the content of the file
+ """
+ with open(filepath) as f:
+ cmdline = f.read()
+
+ options = cmdline.split(seperator)
+ params = {}
+ for option in options:
+ if '=' not in option:
+ continue
+ k, v = option.split('=', 1)
+ params[k] = v
+
+ return params
+
+def main():
+ log.register_options(CONF)
+ CONF(args=sys.argv[1:])
+ log.setup(CONF, 'virtmedia-netconfig')
+ LOG.info("Starting virtmedia-netconfig!!")
+
+ params = _read_params_from_file('/proc/cmdline')
+ # If the node booted over virtual media, the parameters are passed
+ # in a text file within the virtual media floppy.
+
+ if params.get('boot_method') == 'vmedia':
+ LOG.info("This node is booted with vmedia. Checking for available virtual media!!")
+ wait_for_cd_device()
+ check_cd_config()
+ vmedia_params = _get_vmedia_params()
+ params.update(vmedia_params)
+ LOG.debug("vmedia parameters: %r", vmedia_params)
+ os_net_config = params.get('os_net_config')
+ LOG.info("virtmedia: os_net_config=%s" %os_net_config)
+ if os_net_config:
+ _configure_static_net(os_net_config)
+
+ LOG.debug("Erasing old filesystems")
+ utils.execute('/usr/bin/erase-oldfs.sh')
+
+
+if __name__ == "__main__":
+ sys.exit(main())
--- /dev/null
+#!/bin/bash
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+
+if [ "${DIB_DEBUG_TRACE:-0}" -gt 0 ]; then
+ set -x
+fi
+set -eu
+set -o pipefail
+systemctl enable virtmedia-netconfig.service
--- /dev/null
+#!/bin/bash
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+
+if [ "${DIB_DEBUG_TRACE:-0}" -gt 0 ]; then
+ set -x
+fi
+set -eu
+set -o pipefail
+
+rootpw=`openssl passwd -1 -salt root root`
+usermod --pass="$rootpw" root
--- /dev/null
+# Copyright 2019 Nokia
+#
+# 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.
+#
+
+# do not edit this file, it will be overwritten on update
+
+ACTION!="add", GOTO="net_name_slot_end"
+SUBSYSTEM!="net", GOTO="net_name_slot_end"
+NAME!="", GOTO="net_name_slot_end"
+
+IMPORT{cmdline}="net.ifnames"
+ENV{net.ifnames}=="0", GOTO="net_name_slot_end"
+
+NAME=="", ENV{ID_NET_NAME_ONBOARD}!="", NAME="$env{ID_NET_NAME_ONBOARD}"
+NAME=="", ENV{ID_NET_NAME_SLOT}!="", NAME="$env{ID_NET_NAME_SLOT}"
+NAME=="", ENV{ID_NET_NAME_PATH}!="", NAME="$env{ID_NET_NAME_PATH}"
+
+LABEL="net_name_slot_end"
--- /dev/null
+#!/bin/bash
+#
+# Copyright 2012 Hewlett-Packard Development Company, L.P.
+# 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.
+#
+# This script generates iso image from the given kernel and ramdisk
+
+SCRIPTNAME=`basename $0`
+TMP_BUILD_DIR="/tmp/$SCRIPTNAME.$$"
+QEMU_IMG="/usr/bin/qemu-img"
+MKISOFS="/usr/bin/mkisofs"
+
+
+function show_options() {
+
+ echo "Usage: ${SCRIPTNAME} [options]"
+ echo
+ echo "Options:"
+
+ echo " -o output filename "
+ echo " -i initrd "
+ echo " -k kernel "
+}
+
+function cleanup() {
+
+ v_print "Cleaning up.."
+ rm -rf $TMP_BUILD_DIR
+}
+
+function err_print() {
+ echo "ERROR: $@" 1>&2;
+}
+
+function v_print() {
+
+ echo "$*"
+}
+
+
+# Parse command line options
+ARGS=`getopt -o "o:i:k:" -l "output,initrd,kernel:" \
+ -n "$SCRIPTNAME" -- "$@"`
+if [ $? -ne 0 ];
+then
+ exit 1
+fi
+
+eval set -- "$ARGS"
+
+while true ; do
+ case "$1" in
+ -o) OUTPUT_FILENAME=$2; shift 2 ;;
+ -i) INITRD=$2; shift 2 ;;
+ -k) KERNEL=$2; shift 2 ;;
+ # *) show_options ; exit 1 ;;
+ --) shift; break ;;
+ esac
+done
+
+# Verify whether kernel, initrd, and the image file is present
+if [ -z "$OUTPUT_FILENAME" ]; then
+ err_print "Output filename not provided."
+ show_options
+ exit 1
+fi
+
+if [ -z "$INITRD" ]; then
+ err_print "Initrd not provided."
+ show_options
+ exit 1
+fi
+
+if [ -z "$KERNEL" ]; then
+ err_print "Kernel not provided."
+ show_options
+ exit 1
+fi
+
+# Create a temporary build directory for holiding the contents of iso
+TMP_IMAGE_DIR="$TMP_BUILD_DIR/image"
+v_print "Creating temporary directory $TMP_IMAGE_DIR"
+mkdir -p "$TMP_IMAGE_DIR"
+
+# Copy isolinux bin to the isolinux directory
+mkdir -p "$TMP_IMAGE_DIR/isolinux"
+v_print "Copying isolinux.bin"
+if [ -f /usr/share/syslinux/isolinux.bin ]
+then
+ cp /usr/share/syslinux/isolinux.bin "$TMP_IMAGE_DIR/isolinux"
+
+elif [ -f /usr/lib/syslinux/isolinux.bin ]
+then
+ cp /usr/lib/syslinux/isolinux.bin "$TMP_IMAGE_DIR/isolinux"
+else
+ err_print "Could not find isolinux.bin. Install syslinux?"
+ cleanup
+ exit 1
+fi
+
+
+# Copy initrd, kernel
+v_print "Copying kernel to $TMP_IMAGE_DIR/vmlinuz"
+cp $KERNEL "$TMP_IMAGE_DIR/vmlinuz"
+if [ $? -ne 0 ]; then
+ err_print "Failed to copy $KERNEL to $TMP_IMAGE_DIR"
+ cleanup
+ exit 1
+fi
+
+v_print "Copying initrd to $TMP_IMAGE_DIR/initrd"
+cp $INITRD "$TMP_IMAGE_DIR/initrd"
+if [ $? -ne 0 ]; then
+ err_print "Failed to copy $INITRD to $TMP_IMAGE_DIR"
+ cleanup
+ exit 1
+fi
+
+# Generate isolinux.cfg for default booting
+v_print "Generating isolinux.cfg"
+echo "\
+DEFAULT install
+LABEL install
+ menu label "Install image"
+ kernel /vmlinuz
+ append initrd=/initrd boot_method=vmedia console=tty0 console=ttyS1,115200 selinux=0 --
+TIMEOUT 5
+PROMPT 0 " > "$TMP_IMAGE_DIR/isolinux/isolinux.cfg"
+
+# Convert relative path output filename to absolute path
+echo $OUTPUT_FILENAME | grep -q '^/'
+if [ $? -ne 0 ]; then
+ OUTPUT_FILENAME="$PWD/$OUTPUT_FILENAME"
+fi
+
+# Create the ISO
+v_print "Generating the ISO"
+cd $TMP_IMAGE_DIR && $MKISOFS -r -V "INSTALL_IMAGE" -cache-inodes -J -l -b isolinux/isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table -o $OUTPUT_FILENAME .
+
+# Cleanup
+cleanup
+