diff --git a/pxelinux-provisioning/README.rst b/pxelinux-provisioning/README.rst new file mode 100644 index 00000000..e0ee7f30 --- /dev/null +++ b/pxelinux-provisioning/README.rst @@ -0,0 +1,76 @@ +OpenStack-Ansible pxelinux Provisioning +####################################### +:date: 2018-04-24 +:tags: rackspace, openstack, ansible +:category: \*openstack, \*nix + + +About this repository +--------------------- + +This repository provides for basic "pxelinux" provisioning using debian based +operating systems. + +A complete set of options can be seen within the ``playbook/group_vars/all.yml`` +file. + +These provisioning playbooks have been created to use static inventory. Example +static inventory used for these playbooks can be seen in the +``playbooks/inventory.yml`` file. + +Scripts have been created to simplify the deployment of these playbooks and +install ansible however they are 100% optional. + + +Playbook Usage +-------------- + +These playbooks require three groups, ``dhcp_hosts``, ``pxe_hosts``, and +``pxe_servers``. The groups ``dhcp_hosts`` and ``pxe_hosts`` are used as targets +to install the required packages and setup the TFTP and DHCP services. The group +``pxe_servers`` is as a set of targets that to deploy a given OS. + +Each host in the ``pxe_servers`` group should have the something similar to the +following configuration. + +.. code-block:: yaml + + $name_used_in_inventory: + ansible_os_family: "{{ default_images[default_image_name]['image_type'] }}" + server_hostname: '$hostname' + server_image: "ubuntu-16.04-amd64" + server_default_interface: 'eth0' + server_obm_ip: 192.168.1.100 + server_model: PowerEdge R710 + server_mac_address: 00:11:22:33:44:55 + server_extra_options: '' + server_fixed_addr: "10.0.0.100" + server_domain_name: "{{ default_server_domain_name }}" + ansible_host: "{{ server_fixed_addr }}" + +The options **$name_used_in_inventory** and **$hostname** need to be changed to +reflect the machine being deployed as well as the ``server_mac_address`` and +``server_obm_ip`` entries. Note ``server_obm_ip`` is optional and not a +required attribute. + +With the inventory all setup the script ``build.sh`` can be used to deploy +everything or the playbooks could be run with the following commmand. + +.. code-block:: bash + + ansible-playbook -vv -i /root/inventory.yml + -e setup_host=${SETUP_HOST:-"true"} + -e setup_pxeboot=${SETUP_PXEBOOT:-"true"} + -e setup_dhcpd=${SETUP_DHCPD:-"true"} + -e default_image=${DEFAULT_IMAGE:-"ubuntu-16.04-amd64"} + -e default_http_proxy=${DEFAULT_HTTP_PROXY:-''} + --force-handlers + playbooks/site.yml + +Once the playbooks have completed, set the ``pxe_servers`` target hosts, PXE +boot once and reboot them. + +For convience a playbook named ``playbooks/idrac-config.yml`` has been added +which will do **minimal** drac reset and re-configuration which will result in +the host being ready to PXE. This playbook is **not** intended for production +use and was included **only** as an example. diff --git a/pxelinux-provisioning/ansible-env.rc b/pxelinux-provisioning/ansible-env.rc new file mode 100644 index 00000000..830f43f7 --- /dev/null +++ b/pxelinux-provisioning/ansible-env.rc @@ -0,0 +1,19 @@ +export ANSIBLE_GATHERING="${ANSIBLE_GATHERING:-smart}" +export ANSIBLE_GATHER_SUBSET="${ANSIBLE_GATHER_SUBSET:-network,hardware,virtual}" + +export ANSIBLE_CACHE_PLUGIN="${ANSIBLE_CACHE_PLUGIN:-jsonfile}" +export ANSIBLE_CACHE_PLUGIN_CONNECTION="${ANSIBLE_CACHE_PLUGIN_CONNECTION:-/tmp/mnaio_facts}" +export ANSIBLE_CACHE_PLUGIN_TIMEOUT="${ANSIBLE_CACHE_PLUGIN_TIMEOUT:-86400}" + +export ANSIBLE_HOST_KEY_CHECKING=False +export ANSIBLE_SSH_CONTROL_PATH=/tmp/%%h-%%r +export ANSIBLE_SSH_ARGS="-o ControlMaster=no \ + -o UserKnownHostsFile=/dev/null \ + -o StrictHostKeyChecking=no \ + -o ServerAliveInterval=64 \ + -o ServerAliveCountMax=1024 \ + -o Compression=no \ + -o TCPKeepAlive=yes \ + -o VerifyHostKeyDNS=no \ + -o ForwardX11=no \ + -o ForwardAgent=yes" diff --git a/pxelinux-provisioning/bindep.txt b/pxelinux-provisioning/bindep.txt new file mode 100644 index 00000000..f2924a2a --- /dev/null +++ b/pxelinux-provisioning/bindep.txt @@ -0,0 +1,63 @@ +# This file facilitates OpenStack-CI package installation +# before the execution of any tests. +# +# See the following for details: +# - http://docs.openstack.org/infra/bindep/ +# - https://git.openstack.org/cgit/openstack-infra/bindep +# +# Even if the role does not make use of this facility, it +# is better to have this file empty, otherwise OpenStack-CI +# will fall back to installing its default packages which +# will potentially be detrimental to the tests executed. +# +# Note: +# This file is maintained in the openstack-ansible-tests repository. +# https://git.openstack.org/cgit/openstack/openstack-ansible-tests/tree/bindep.txt +# If you need to remove or add extra dependencies, you should modify +# the central file instead and once your change is accepted then update +# this file as well. The purpose of this file is to ensure that Python and +# Ansible have all their necessary binary requirements on the test host before +# tox executes. Any binary requirements needed by services/roles should be +# installed by those roles in their applicable package install tasks, not through +# using this file. +# + +# Base requirements for Ubuntu +build-essential [platform:dpkg] +git-core [platform:dpkg] +libssl-dev [platform:dpkg] +libffi-dev [platform:dpkg] +python2.7 [platform:dpkg] +python-apt [platform:dpkg] +python-dev [platform:dpkg] + +# Base requirements for RPM distros +gcc [platform:rpm] +gcc-c++ [platform:rpm] +git [platform:rpm] +libffi-devel [platform:rpm !platform:opensuseproject-42] +libffi-devel-gcc5 [platform:opensuseproject-42] +openssl-devel [platform:redhat] +libopenssl-devel [platform:suse] +python-devel [platform:rpm] +python2-dnf [platform:fedora] + +# For SELinux +libselinux-python [platform:redhat] +libsemanage-python [platform:redhat] + +# For SSL SNI support +python-pyasn1 [platform:dpkg platform:suse] +python-openssl [platform:dpkg] +python-ndg-httpsclient [platform:ubuntu !platform:ubuntu-14] +python2-pyasn1 [platform:redhat] +python2-pyOpenSSL [platform:redhat !platform:fedora] +pyOpenSSL [platform:fedora] +python-pyOpenSSL [platform:opensuseproject-42] +python2-pyOpenSSL [platform:suse !platform:opensuseproject-42] +python-ndg_httpsclient [platform:redhat !platform:fedora] +python2-ndg_httpsclient [platform:fedora] +python-ndg-httpsclient [platform:suse] + +# Required for compressing collected log files in CI +gzip diff --git a/pxelinux-provisioning/bootstrap.sh b/pxelinux-provisioning/bootstrap.sh new file mode 100755 index 00000000..27e4d0cb --- /dev/null +++ b/pxelinux-provisioning/bootstrap.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# Copyright 2015, Rackspace US, Inc. +# +# 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. + +set -o pipefail +set -euov + +BINDEP_FILE=${BINDEP_FILE:-bindep.txt} + +source /etc/os-release || source /usr/lib/os-release + +case "${ID,,}" in + *suse*) + # Need to pull libffi and python-pyOpenSSL early + # because we install ndg-httpsclient from pip on Leap 42.1 + [[ "${VERSION}" == "42.1" ]] && extra_suse_deps="libffi-devel python-pyOpenSSL" + sudo zypper -n in python-devel lsb-release ${extra_suse_deps:-} + ;; + amzn|centos|rhel) + sudo yum install -y python-devel redhat-lsb-core + ;; + ubuntu|debian) + sudo apt-get update && sudo apt-get install -y python-dev lsb-release + ;; + *) + echo "Unsupported distribution: ${ID,,}" + exit 1 +esac + +# Install pip +if ! which pip &>/dev/null; then + curl --silent --show-error --retry 5 \ + https://bootstrap.pypa.io/get-pip.py | sudo python2.7 +fi + +# Install bindep and tox +sudo pip install 'bindep>=2.4.0' tox + +# CentOS 7 requires two additional packages: +# redhat-lsb-core - for bindep profile support +# epel-release - required to install python-ndg_httpsclient/python2-pyasn1 +if [[ ${ID,,} == "centos" ]]; then + sudo yum -y install redhat-lsb-core epel-release yum-utils + # epel-release could be installed but not enabled (which is very common + # in openstack-ci) so enable it here if needed + sudo yum-config-manager --enable epel || true +# openSUSE 42.1 does not have python-ndg-httpsclient +elif [[ ${ID,,} == *suse* ]] && [[ ${VERSION} == "42.1" ]]; then + sudo pip install ndg-httpsclient +fi + +# Get a list of packages to install with bindep. If packages need to be +# installed, bindep exits with an exit code of 1. +BINDEP_PKGS=$(bindep -b -f ${BINDEP_FILE} test || true) +echo "Packages to install: ${BINDEP_PKGS}" + +# Install OS packages using bindep +if [[ ${#BINDEP_PKGS} > 0 ]]; then + case "${ID,,}" in + *suse*) + sudo zypper -n in $BINDEP_PKGS + ;; + centos) + sudo yum install -y $BINDEP_PKGS + ;; + ubuntu|debian) + sudo apt-get update + DEBIAN_FRONTEND=noninteractive \ + sudo apt-get -q --option "Dpkg::Options::=--force-confold" \ + --assume-yes install $BINDEP_PKGS + ;; + esac +fi + +sudo pip install ansible diff --git a/pxelinux-provisioning/build.sh b/pxelinux-provisioning/build.sh new file mode 100755 index 00000000..682865a7 --- /dev/null +++ b/pxelinux-provisioning/build.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Copyright [2016] [Kevin Carter] +# +# 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. + +set -euvo + +source bootstrap.sh + +source run.sh diff --git a/pxelinux-provisioning/playbooks/deploy-dhcp.yml b/pxelinux-provisioning/playbooks/deploy-dhcp.yml new file mode 100644 index 00000000..787ea7d1 --- /dev/null +++ b/pxelinux-provisioning/playbooks/deploy-dhcp.yml @@ -0,0 +1,72 @@ +--- +# 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. + +- name: Deploy DHCP + hosts: dhcp_hosts + gather_facts: "{{ gather_facts | default(true) }}" + pre_tasks: + - name: Gather variables for each operating system + include_vars: "{{ item }}" + with_first_found: + - "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}-{{ ansible_distribution_version | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_os_family | lower }}-{{ ansible_distribution_major_version | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_os_family | lower }}.yml" + tags: + - always + + - name: Install all required packages for dhcpd_install + package: + pkg: "{{ item }}" + state: "latest" + update_cache: yes + cache_valid_time: 600 + with_items: "{{ default_dhcp_distro_packages }}" + + - name: Enable services + systemd: + name: "{{ item }}" + enabled: yes + with_items: "{{ default_dhcp_distro_packages }}" + + tasks: + - name: Create a template in /etc/dhcp/dhcpd.conf + template: + src: templates/dhcp/dhcpd.conf.j2 + dest: /etc/dhcp/dhcpd.conf + mode: 0644 + owner: root + group: root + notify: restart dhcpd + + - name: Create a template in /etc/dhcp/dhcpd.conf + template: + src: templates/dhcp/isc-dhcp-server.j2 + dest: /etc/default/isc-dhcp-server + mode: 0644 + owner: root + group: root + notify: restart dhcpd + + environment: "{{ deployment_environment_variables | default({}) }}" + + handlers: + - name: restart dhcpd + systemd: + name: "{{ item }}" + state: restarted + with_items: "{{ default_dhcp_distro_packages }}" + + tags: + - deploy-dhcpd diff --git a/pxelinux-provisioning/playbooks/deploy-pxe.yml b/pxelinux-provisioning/playbooks/deploy-pxe.yml new file mode 100644 index 00000000..afea484c --- /dev/null +++ b/pxelinux-provisioning/playbooks/deploy-pxe.yml @@ -0,0 +1,268 @@ +--- +# Copyright 2017, Rackspace US, Inc. +# +# 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 witing, 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. + +- name: Deploy PXE + hosts: pxe_hosts + gather_facts: "{{ gather_facts | default(true) }}" + pre_tasks: + - name: Gather variables for each operating system + include_vars: "{{ item }}" + with_first_found: + - "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}-{{ ansible_distribution_version | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_os_family | lower }}-{{ ansible_distribution_major_version | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_os_family | lower }}.yml" + tags: + - always + + - name: Install host distro packages + package: + pkg: "{{ item }}" + state: "latest" + update_cache: yes + cache_valid_time: 600 + with_items: "{{ default_pxe_distro_packages }}" + + - name: Create base directories + file: + path: "{{ item }}" + state: directory + owner: "root" + group: "root" + mode: "0755" + with_items: + - /var/www/pxe + - /var/www/pxe/images + - /var/www/pxe/iso + - /var/www/pxe/networking + - /var/www/pxe/scripts + - /var/www/pxe/templates + - /var/lib/tftpboot + - /var/lib/tftpboot/boot-screens + - /var/lib/tftpboot/preseed + - /var/lib/tftpboot/pxelinux.cfg + + - name: Get root public key + command: cat /root/.ssh/id_rsa.pub + register: public_key_get + changed_when: false + when: + - default_tftp_ssh_key is undefined + + - name: Set key facts + set_fact: + default_tftp_ssh_key: "{{ public_key_get.stdout }}" + when: + - default_tftp_ssh_key is undefined + + tasks: + - name: Drop NGINX config + copy: + src: "templates/pxe/sites-enabled.default.j2" + dest: /etc/nginx/sites-enabled/default + mode: "0644" + owner: root + group: root + notify: + - restart nginx + + - name: Drop tftp-hpa configs + copy: + src: "templates/pxe/tftp/tftp-hpa.j2" + dest: /etc/default/tftpd-hpa + mode: "0644" + owner: root + group: root + notify: + - restart tftp-hpa + + - name: Drop inetd configs + copy: + src: "templates/pxe/tftp/inetd.conf.j2" + dest: /etc/default/tftpd-hpa + mode: "0644" + owner: root + group: root + notify: + - restart tftp-hpa + + - name: Download image iso(s) + get_url: + url: "{{ item.value.image_iso_url }}" + dest: "/var/www/pxe/iso/{{ item.value.image_name }}" + with_dict: "{{ default_images }}" + + - name: Clean image directory + file: + path: "/var/www/pxe/images/{{ item.value.image_short_name }}" + state: absent + with_dict: "{{ default_images }}" + + - name: Create image directory + file: + path: "/var/www/pxe/images/{{ item.value.image_short_name }}" + state: directory + owner: "root" + group: "root" + mode: "0755" + with_dict: "{{ default_images }}" + + - name: Extract ISO(s) contents + command: "7z x /var/www/pxe/iso/{{ item.value.image_name }}" + args: + chdir: "/var/www/pxe/images/{{ item.value.image_short_name }}" + with_dict: "{{ default_images }}" + + - name: Download pxelinux + get_url: + url: "{{ default_pxelinux_url }}" + dest: "/var/www/pxe/{{ default_pxelinux_name }}" + tmp_dest: /tmp/ + + - name: Clean pxe image directory + file: + path: "/var/www/pxe/{{ default_pxelinux_short_name }}" + state: absent + + - name: Extract pxelinux contents + command: "tar -xf /var/www/pxe/{{ default_pxelinux_name }}" + args: + chdir: "/var/www/pxe" + + - name: Drop pxelinux.cfg default menu + copy: + src: "templates/pxe/tftp/pxelinux.cfg.default.j2" + dest: "{{ item }}" + mode: "0644" + owner: root + group: root + with_items: + - /var/lib/tftpboot/pxelinux.cfg/default + - /var/lib/tftpboot/boot-screens/syslinux.cfg + + # These links are using the shell command because the file module does not create hard links + - name: Create hard links + shell: | + ln -f /var/www/pxe/{{ default_pxelinux_short_name }}/bios/com32/elflink/ldlinux/ldlinux.c32 /var/lib/tftpboot/ldlinux.c32 + ln -f /var/www/pxe/{{ default_pxelinux_short_name }}/bios/core/pxelinux.0 /var/lib/tftpboot/pxelinux.0 + ln -f /var/www/pxe/{{ default_pxelinux_short_name }}/bios/com32/lib/libcom32.c32 /var/lib/tftpboot/boot-screens/libcom32.c32 + ln -f /var/www/pxe/{{ default_pxelinux_short_name }}/bios/com32/libutil/libutil.c32 /var/lib/tftpboot/boot-screens/libutil.c32 + ln -f /var/www/pxe/{{ default_pxelinux_short_name }}/bios/com32/menu/vesamenu.c32 /var/lib/tftpboot/boot-screens/vesamenu.c32 + + - name: Drop boot-screens default menu + template: + src: "templates/pxe/tftp/menu.cfg.j2" + dest: /var/lib/tftpboot/boot-screens/menu.cfg + mode: "0644" + owner: root + group: root + + - name: Drop tftp-hpa configs + template: + src: "templates/pxe/tftp/tftp-hpa.j2" + dest: /etc/default/tftpd-hpa + mode: "0644" + owner: root + group: root + notify: + - restart tftp-hpa + + - name: tftp configs for servers + template: + src: "templates/pxe/tftp/pxelinux.cfg.macaddr.j2" + dest: "/var/lib/tftpboot/pxelinux.cfg/01-{{ hostvars[item]['server_mac_address'] | replace(':', '-') | upper }}" + mode: "0644" + owner: root + group: root + with_items: "{{ groups['pxe_servers'] }}" + + - name: Preseeds for pxe scripts + template: + src: "templates/pxe/{{ item.value.image_type }}/{{ item.value.image_preseed }}-post-install-script.sh.j2" + dest: "/var/www/pxe/scripts/{{ item.value.image_preseed }}-post-install-script.sh" + mode: "0644" + owner: root + group: root + with_dict: "{{ default_images }}" + + - name: Preseeds for pxe + template: + src: "templates/pxe/{{ item.value.image_type }}/{{ item.value.image_preseed }}.preseed.j2" + dest: "/var/lib/tftpboot/preseed/{{ item.value.image_preseed }}.preseed" + mode: "0644" + owner: root + group: root + with_dict: "{{ default_images }}" + + - name: Create netboot bind mount path + file: + path: "/var/lib/tftpboot/{{ item.value.image_short_name }}" + state: directory + owner: "root" + group: "root" + mode: "0755" + with_dict: "{{ default_images }}" + + - name: Unbind mount netboot images + mount: + name: "/var/lib/tftpboot/{{ item.value.image_short_name }}" + src: "/var/www/pxe/images/{{ item.value.image_netboot }}" + opts: bind + fstype: none + state: unmounted + register: fstab + with_dict: "{{ default_images }}" + + - name: Ensure permissions are correct + shell: | + # Fix perms if needed + find /var/lib/tftpboot -type d -exec chmod 0755 {} \; + find /var/lib/tftpboot -type f -exec chmod 0644 {} \; + find /var/www/pxe -type d -exec chmod 0755 {} \; + + - name: Bind mount netboot images + mount: + name: "/var/lib/tftpboot/{{ item.value.image_short_name }}" + src: "/var/www/pxe/images/{{ item.value.image_netboot }}" + opts: bind + fstype: none + state: mounted + register: fstab + with_dict: "{{ default_images }}" + + environment: "{{ deployment_environment_variables | default({}) }}" + + handlers: + - name: restart nginx + systemd: + name: "nginx" + state: restarted + enabled: yes + + - name: restart tftp-hpa + systemd: + name: "tftpd-hpa" + state: restarted + enabled: yes + + - name: restart inetd + systemd: + name: "inetutils-inetd" + state: restarted + enabled: yes + + tags: + - deploy-pxe diff --git a/pxelinux-provisioning/playbooks/group_vars/all.yml b/pxelinux-provisioning/playbooks/group_vars/all.yml new file mode 100644 index 00000000..41ad6221 --- /dev/null +++ b/pxelinux-provisioning/playbooks/group_vars/all.yml @@ -0,0 +1,91 @@ +--- +# 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 is the default system root password. This should be changed. +default_root_password: secrete + +# Depending on the kernel parameters passed into the physical machines when +# booted these options may be different or host specific. +default_interface: "{{ default_network | default('eth0') }}" +default_dhcp_interface: "{{ default_interface }}" + +# To speed up the deployment apt-cacher NG is used on the pxe/dhcp server. +default_acng_bind_address: 0.0.0.0 + +# This is a mapping of OS familiies. While Ansible has a suitable interface for +# for this it can vary in unpredictable ways. This setting it used to determine +# the type of preseed needed to deploy an given OS type. +default_os_families: + ubuntu-16.04-amd64: debian + +# Default setting for Apt-Cacher-NG. +default_mirror_proxy: 'http://{{ default_tftp_server }}:3142/' +default_mirror_hostname: archive.ubuntu.com +default_mirror_directory: /ubuntu + + # IP address, or domain name of the TFTP server +default_tftp_server: "{{ hostvars[groups['pxe_hosts'][0]]['ansible_host'] | default(ansible_host) }}" +# tftp_ssh_key: '' # user defined ssh key, used to access the host +default_tftp_port: 69 +default_tftp_boot_path: /pxelinux.0 # Path of where to boot from first + +# Default ISO images +default_image_name: "ubuntu-16.04-amd64" +default_images: + ubuntu-16.04-amd64: + image_type: debian + image_iso_url: "http://releases.ubuntu.com/16.04.2/ubuntu-16.04.2-server-amd64.iso" + image_name: "ubuntu-16.04.2-server-amd64.iso" + image_short_name: "ubuntu-16.04.2-server-amd64" + image_default_boot: "ubuntu-16.04.2-server-amd64/amd64/boot-screens/menu.cfg" + image_kernel_options: "biosdevname=0 net.ifnames=0 auto=true priority=critical quiet splash" + image_kernel: "ubuntu-16.04.2-server-amd64/amd64/linux" + image_initrd: "ubuntu-16.04.2-server-amd64/amd64/initrd.gz" + image_netboot: "ubuntu-16.04.2-server-amd64/install/netboot/ubuntu-installer" + image_preseed: basic + image_preseed_option: + url: "tftp://{{ default_tftp_server }}/preseed/basic.preseed" + +# PXELinux downloads. While pxelinux is available as a component of most distros +# the version may vary. This stabalizes on a known set. +default_pxelinux_url: "https://www.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz" +default_pxelinux_name: "syslinux-6.03.tar.gz" +default_pxelinux_short_name: "syslinux-6.03" + +# Default network / server setup used in DHCP +default_server_domain_name: "openstack.local" +default_server_netmask: "255.255.255.0" +default_server_gateway: "10.0.0.1" +default_server_dns: "8.8.8.8" +default_server_subnet: "10.0.0.0" + +# List of DHCP Subnets - These are iterated though and each will be created +default_dhcp_default_lease_time: 21600 # Default lease time +default_dhcp_max_lease_time: 43200 # Max lease time + +# DHCP system setup +default_dhcp_list: + - netmask: "{{ default_server_netmask }}" # Netmask + gateway: "{{ default_server_gateway }}" # Gateway + dns: "{{ default_server_dns }}" # DNS + subnet: "{{ default_server_subnet }}" # Subnet mask + default_lease_time: "{{ default_dhcp_default_lease_time }}" # Subnet Default lease time - The default is used if this is not defined + max_lease_time: "{{ default_dhcp_max_lease_time }}" # Subnet Max lease time - The default is used if this is not defined + tftp_boot_path: /pxelinux.0 # Path for tftp of where to boot from first - The default is used if this is not defined + tftp_server: "{{ default_tftp_server }}" # The server hosting the TFTP server - The default is used if this is not defined + dhcp_default_domain_name: "{{ default_server_domain_name }}" # Domain name + +# Determine the root disk. This can be statically set. By default this function +# is run as an early command during preseed which will look at all active disks +# and use the first one. +default_root_disk: '$(fdisk -l | grep sd | grep -wo "dev.*:" | sed "s/\://" | head -n1)' diff --git a/pxelinux-provisioning/playbooks/host_vars/example-host1.yml.example b/pxelinux-provisioning/playbooks/host_vars/example-host1.yml.example new file mode 100644 index 00000000..e975e16e --- /dev/null +++ b/pxelinux-provisioning/playbooks/host_vars/example-host1.yml.example @@ -0,0 +1,27 @@ +--- +# Copyright 2017, Rackspace US, Inc. +# +# 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 witing, 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. + +server_hostname: 'example-host1' # str - required, hostname of server +server_image: "{{ default_image_name }}" # str - required, image name +server_default_interface: 'eth0' # str - required, default interface +server_obm_ip: 10.127.83.200 # str - optional, used for out of band management +server_model: PowerEdge R710 # str - optional, information on the server +server_mac_address: '00:00:00:00:00:00' # str - required, mac address of default interface +server_extra_options: '' # str - not required, added kernel options +server_fixed_addr: '10.127.83.100' # str - required, IP address for this host +server_domain_name: "{{ default_server_domain_name }}" # str - required, domain name for the server + +ansible_host: "{{ server_fixed_addr }}" # str - required, ansible host ip address +ansible_os_family: "{{ images[default_image_name]['image_type'] }}" # str - Set the ansible os family diff --git a/pxelinux-provisioning/playbooks/idrac-config.yml b/pxelinux-provisioning/playbooks/idrac-config.yml new file mode 100644 index 00000000..5a81c0ab --- /dev/null +++ b/pxelinux-provisioning/playbooks/idrac-config.yml @@ -0,0 +1,310 @@ +--- +# Copyright 2017, Rackspace US, Inc. +# +# 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 witing, 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. + +- name: Run DRAC Config + hosts: pxe_servers + gather_facts: false + connection: local + tasks: + - set_fact: + racadm_path: "/opt/dell/srvadmin/sbin/racadm" + tags: + - always + + - name: check for racadm + stat: + path: "{{ racadm_path }}" + register: racadm_command + tags: + - always + + - name: check for racadm_command + fail: + msg: "racadm command is not found." + when: + - not racadm_command.stat.exists + tags: + - always + + - set_fact: + racadm: "{{ racadm_path }} -r {{ server_obm_ip }} -u root -p calvin" + tags: + - always + + - name: set cfgServerBootOnce + command: "{{ racadm }} config -g cfgServerInfo -o cfgServerBootOnce 0" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgServerFirstBootDevice + + - name: set cfgServerFirstBootDevice + command: "{{ racadm }} config -g cfgServerInfo -o cfgServerFirstBootDevice HDD" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgServerFirstBootDevice + + - name: set cfgServerBootOnce + command: "{{ racadm }} config -g cfgServerInfo -o cfgServerBootOnce 1" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgServerBootOnce + + - name: set cfgServerFirstBootDevice + command: "{{ racadm }} config -g cfgServerInfo -o cfgServerFirstBootDevice PXE" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgServerBootOnce + + - name: set cfgNicEnable + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicEnable 1" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicEnable + + - name: set cfgNicIPv4Enable + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicIPv4Enable 1" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicIPv4Enable + + - name: set cfgNicUseDhcp + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicUseDhcp 0" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicUseDhcp + + - name: set cfgNicVLanEnable + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicVLanEnable 0" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicVLanEnable + + - name: set cfgNicVLanID + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicVLanID 1" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicVLanID + + - name: set cfgNicVLanPriority + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicVLanPriority 0" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicVLanPriority + + - name: set cfgNicSelection + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicSelection 2" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicSelection + + - name: set cfgDNSServersFromDHCP + command: "{{ racadm }} config -g cfgLanNetworking -o cfgDNSServersFromDHCP 0" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgDNSServersFromDHCP + + - name: set cfgDNSRacName + command: "{{ racadm }} config -g cfgLanNetworking -o cfgDNSRacName {{ server_hostname }}" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgDNSRacName + + - name: set cfgNicIpAddress + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicIpAddress {{ server_obm_ip }}" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicIpAddress + + - name: set cfgDNSServer1 + command: "{{ racadm }} config -g cfgLanNetworking -o cfgDNSServer1 {{ server_gateway }}" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgDNSServer1 + + - name: set cfgDNSServer2 + command: "{{ racadm }} config -g cfgLanNetworking -o cfgDNSServer2 {{ server_dns }}" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgDNSServer2 + + - name: set cfgNicNetmask + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicNetmask {{ server_netmask }}" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicNetmask + + - name: set cfgNicGateway + command: "{{ racadm }} config -g cfgLanNetworking -o cfgNicGateway {{ server_gateway }}" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgNicGateway + + - name: set cfgDNSDomainName + command: "{{ racadm }} config -g cfgLanNetworking -o cfgDNSDomainName {{ server_domain_name }}" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgDNSDomainName + + - name: set cfgDNSDomainNameFromDHCP + command: "{{ racadm }} config -g cfgLanNetworking -o cfgDNSDomainNameFromDHCP 0" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgDNSDomainNameFromDHCP + + - name: set cfgDNSRegisterRac + command: "{{ racadm }} config -g cfgLanNetworking -o cfgDNSRegisterRac 0" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgDNSRegisterRac + + - name: set cfgIpmiLanEnable + command: "{{ racadm }} config -g cfgIpmiLan -o cfgIpmiLanEnable 1" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgIpmiLanEnable + + - name: set cfgIpmiLanPrivilegeLimit + command: "{{ racadm }} config -g cfgIpmiLan -o cfgIpmiLanPrivilegeLimit 4" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgIpmiLanPrivilegeLimit + + - name: set cfgIpmiLanAlertEnable + command: "{{ racadm }} config -g cfgIpmiLan -o cfgIpmiLanAlertEnable 0" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgIpmiLanAlertEnable + + - name: set cfgIpmiEncryptionKey + command: "{{ racadm }} config -g cfgIpmiLan -o cfgIpmiEncryptionKey 0000000000000000000000000000000000000000" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgIpmiEncryptionKey + + - name: set cfgIpmiPetCommunityName + command: "{{ racadm }} config -g cfgIpmiLan -o cfgIpmiPetCommunityName public" + register: command + until: command is success + retries: 2 + delay: 2 + tags: + - cfgIpmiPetCommunityName + + - name: run sslresetcfg + command: "{{ racadm }} sslresetcfg" + register: command + failed_when: not command.rc in [0, 2] + until: command is success + retries: 2 + delay: 2 + tags: + - sslresetcfg + + - name: run serveraction powercycle + command: "{{ racadm }} serveraction powercycle" + register: command + until: command is success + retries: 2 + delay: 2 + when: + - not inventory_hostname in groups['pxe_hosts'] + tags: + - powercycle + + - name: run racreset + command: "{{ racadm }} racreset" + register: command + until: command is success + retries: 2 + delay: 2 + when: + - not inventory_hostname in groups['pxe_hosts'] + tags: + - racreset diff --git a/pxelinux-provisioning/playbooks/inventory.yml b/pxelinux-provisioning/playbooks/inventory.yml new file mode 100644 index 00000000..40e266be --- /dev/null +++ b/pxelinux-provisioning/playbooks/inventory.yml @@ -0,0 +1,49 @@ +--- +################################## ALL HOSTS ################################## + +all: + vars: + server_netmask: "255.255.255.0" + server_gateway: "10.127.83.1" + server_dns: "8.8.8.8" + server_subnet: "10.127.83.0" + + hosts: + # Local host + localhost: + ansible_host: 127.0.0.1 + + # PXE Server + n1: + ansible_user: root + +################################## PXE HOSTS ################################## + +# The group "pxe_hosts" is used to setup all systems that will be responsible +# for PXE boot. This will install all of the needed capabilities to TFTP serve +# system images. +pxe_hosts: + hosts: + localhost: {} + +dhcp_hosts: + hosts: + localhost: {} + +################################# PXE TARGETS ################################# + +# The group "pxe_servers" is used for all servers that will be a PXE target. +pxe_servers: + hosts: + n1: + ansible_os_family: "{{ default_images[default_image_name]['image_type'] }}" + server_hostname: 'n1' + server_image: "ubuntu-16.04-amd64" + server_default_interface: 'eth0' + server_obm_ip: 10.0.0.200 + server_model: PowerEdge R710 + server_mac_address: 00:11:22:33:44:55 + server_extra_options: '' + server_fixed_addr: "10.0.0.100" + server_domain_name: "{{ default_server_domain_name }}" + ansible_host: "{{ server_fixed_addr }}" diff --git a/pxelinux-provisioning/playbooks/setup-host.yml b/pxelinux-provisioning/playbooks/setup-host.yml new file mode 100644 index 00000000..322a0a2d --- /dev/null +++ b/pxelinux-provisioning/playbooks/setup-host.yml @@ -0,0 +1,147 @@ +--- +# Copyright 2017, Rackspace US, Inc. +# +# 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 witing, 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. + +- name: Deploy PXE Host Setup + hosts: pxe_hosts + gather_facts: "{{ gather_facts | default(true) }}" + pre_tasks: + - name: Gather variables for each operating system + include_vars: "{{ item }}" + with_first_found: + - "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}-{{ ansible_distribution_version | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_os_family | lower }}-{{ ansible_distribution_major_version | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}.yml" + - "{{ playbook_dir }}/vars/{{ ansible_os_family | lower }}.yml" + tags: + - always + + - name: Install host distro packages + package: + pkg: "{{ item }}" + state: "latest" + update_cache: yes + cache_valid_time: 600 + with_items: "{{ default_host_distro_packages }}" + + tasks: + - name: Ensure root has a .ssh directory + file: + path: /root/.ssh + state: directory + owner: root + group: root + mode: 0700 + + - name: Create ssh key pair for root + user: + name: root + generate_ssh_key: yes + ssh_key_bits: 2048 + ssh_key_file: /root/.ssh/id_rsa + + - name: Get root public key + command: cat /root/.ssh/id_rsa.pub + register: public_key_get + changed_when: false + + - name: Set key facts + set_fact: + root_public_key: "{{ public_key_get.stdout }}" + + - name: Ensure root can ssh to localhost + authorized_key: + user: "root" + key: "{{ root_public_key }}" + + - name: Add sysctl options + sysctl: + name: net.ipv4.ip_forward + value: 1 + sysctl_set: yes + state: present + reload: yes + sysctl_file: /etc/sysctl.conf + + - name: Start netfilter persistent + systemd: + name: "{{ default_host_iptables_service }}" + state: started + enabled: yes + + - name: Install repo caching server packages + package: + name: "{{ item }}" + state: "latest" + with_items: "{{ default_pkg_cache_server_distro_packages }}" + + - name: Create cache directory + file: + path: "/var/www/pkg-cache" + state: "directory" + owner: "apt-cacher-ng" + group: "www-data" + mode: "02775" + + - name: Stat the cache path + stat: + path: /var/cache/apt-cacher-ng + register: acs + + - name: Remove cacher directory if its a directory + file: + path: "/var/cache/apt-cacher-ng" + state: "absent" + when: + - acs.stat.isdir is defined and acs.stat.isdir + + - name: Link cacher to the repo path + file: + src: "/var/www/pkg-cache" + dest: "/var/cache/apt-cacher-ng" + state: "link" + + - name: create yum merged mirror list + shell: | + curl https://www.centos.org/download/full-mirrorlist.csv | sed 's/^.*"http:/http:/' | sed 's/".*$//' | grep ^http >/etc/apt-cacher-ng/centos_mirrors + echo "http://mirror.centos.org/centos/" >>/etc/apt-cacher-ng/centos_mirrors + + - name: Drop acng.conf + template: + src: "templates/pxe/acng.conf.j2" + dest: "/etc/apt-cacher-ng/acng.conf" + notify: + - reload acng + + - name: Drop apt package manager proxy + copy: + content: 'Acquire::http { Proxy "{{ default_mirror_proxy }}"; };' + dest: "/etc/apt/apt.conf.d/00apt-cacher-proxy" + + - name: Update apt when proxy is added + apt: + update_cache: yes + + environment: "{{ deployment_environment_variables | default({}) }}" + + handlers: + - name: reload acng + service: + name: "apt-cacher-ng" + state: restarted + enabled: yes + + tags: + - setup-host diff --git a/pxelinux-provisioning/playbooks/site.yml b/pxelinux-provisioning/playbooks/site.yml new file mode 100644 index 00000000..75f16e99 --- /dev/null +++ b/pxelinux-provisioning/playbooks/site.yml @@ -0,0 +1,26 @@ +--- +# Copyright 2017, Rackspace US, Inc. +# +# 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 witing, 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_playbook: setup-host.yml + when: + - setup_host | default(true) | bool + +- import_playbook: deploy-pxe.yml + when: + - setup_pxeboot | default(true) | bool + +- import_playbook: deploy-dhcp.yml + when: + - setup_dhcpd | default(true) | bool diff --git a/pxelinux-provisioning/playbooks/templates/dhcp/dhcpd.conf.j2 b/pxelinux-provisioning/playbooks/templates/dhcp/dhcpd.conf.j2 new file mode 100644 index 00000000..a895c04f --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/dhcp/dhcpd.conf.j2 @@ -0,0 +1,50 @@ +ddns-update-style none; + +allow booting; +allow bootp; + +log-facility local7; +authoritative; + +shared-network all-networks { +{% for dhcp in default_dhcp_list %} + subnet {{ dhcp.subnet }} netmask {{ dhcp.netmask }} { + option routers {{ dhcp.gateway }}; + option domain-name-servers {{ dhcp.dns }}; + option subnet-mask {{ dhcp.netmask }}; +{% if dhcp.default_lease_time is defined and dhcp.default_lease_time > 0 %} + default-lease-time {{ dhcp.default_lease_time }}; +{% else %} + default-lease-time {{ dhcp_default_lease_time }}; +{% endif %} +{% if dhcp.max_lease_time is defined and dhcp.max_lease_time > 0 %} + max-lease-time {{ dhcp.max_lease_time }}; +{% else %} + max-lease-time {{ dhcp_max_lease_time }}; +{% endif %} +{% if dhcp.tftp_server is defined and dhcp.tftp_server | ipaddr %} + next-server {{ dhcp.tftp_server }}; +{% elif default_tftp_server is defined and default_tftp_server | length > 0 %} + next-server {{ default_tftp_server }}; +{% endif %} +{% if dhcp.tftp_boot_path is defined and dhcp.tftp_boot_path | ipaddr %} + filename "{{ dhcp.tftp_boot_path }}"; +{% elif default_tftp_boot_path is defined and default_tftp_boot_path | length > 0 %} + filename "{{ default_tftp_boot_path }}"; +{% endif %} + } + +{% endfor %} + + group { +{% for item in groups['pxe_servers'] %} + host {{ hostvars[item]['server_hostname'] }} { + hardware ethernet {{ hostvars[item]['server_mac_address'] | upper }}; + fixed-address {{ hostvars[item]['server_fixed_addr'] }}; + option host-name "{{ hostvars[item]['server_hostname'] }}"; + } +{% endfor %} + + } + +} diff --git a/pxelinux-provisioning/playbooks/templates/dhcp/isc-dhcp-server.j2 b/pxelinux-provisioning/playbooks/templates/dhcp/isc-dhcp-server.j2 new file mode 100644 index 00000000..11e544e5 --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/dhcp/isc-dhcp-server.j2 @@ -0,0 +1 @@ +INTERFACES="{{ default_dhcp_interface }}" diff --git a/pxelinux-provisioning/playbooks/templates/pxe/acng.conf.j2 b/pxelinux-provisioning/playbooks/templates/pxe/acng.conf.j2 new file mode 100644 index 00000000..f464f835 --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/pxe/acng.conf.j2 @@ -0,0 +1,34 @@ +# {{ ansible_managed }} + +CacheDir: /var/www/pkg-cache +LogDir: /var/log/apt-cacher-ng +Port: 3142 +BindAddress: {{ default_acng_bind_address }} +Remap-debrep: file:deb_mirror*.gz /debian ; file:backends_debian # Debian Archives +Remap-uburep: file:ubuntu_mirrors /ubuntu ; file:backends_ubuntu # Ubuntu Archives +Remap-debvol: file:debvol_mirror*.gz /debian-volatile ; file:backends_debvol # Debian Volatile Archives +Remap-cygwin: file:cygwin_mirrors /cygwin # ; file:backends_cygwin # incomplete, please create this file or specify preferred mirrors here +Remap-sfnet: file:sfnet_mirrors # ; file:backends_sfnet # incomplete, please create this file or specify preferred mirrors here +Remap-alxrep: file:archlx_mirrors /archlinux # ; file:backend_archlx # Arch Linux +Remap-fedora: file:fedora_mirrors # Fedora Linux +Remap-epel: file:epel_mirrors # Fedora EPEL +Remap-slrep: file:sl_mirrors # Scientific Linux +Remap-centos: file:centos_mirrors /centos #centos +ReportPage: acng-report.html +PidFile: /var/run/apt-cacher-ng +ExTreshold: 4 +LocalDirs: acng-doc /usr/share/doc/apt-cacher-ng +PassThroughPattern: .* +{% if default_http_proxy is defined and default_http_proxy %} +Proxy: {{ default_http_proxy }} +{% endif %} +{% if ansible_distribution_release | lower != 'trusty' %} +VfilePatternEx: ^/\?release=[0-9]+&arch= +{% endif %} +# NOTE(mhayden): Caching the CentOS mirror list causes yum to throw +# 503 errors intermittently since the remote file is dynamic. Also, +# yum has issues with retrieving the mariadb.org repodata bz2 and +# that causes more intermittent 503 errors. This DontCache line +# tells apt-cacher-ng to allow requests for these to pass through +# without being cached. +DontCache: (mirrorlist\.centos\.org)|(mariadb\.org.*\.bz2$) diff --git a/pxelinux-provisioning/playbooks/templates/pxe/debian/basic-post-install-script.sh.j2 b/pxelinux-provisioning/playbooks/templates/pxe/debian/basic-post-install-script.sh.j2 new file mode 100644 index 00000000..f158c91f --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/pxe/debian/basic-post-install-script.sh.j2 @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +apt-get remove --purge snap* lxc* lxd* || true + +sed -i 's/\(GRUB_CMDLINE_LINUX_DEFAULT=\).*/\1\"\"/g' /target/etc/default/grub +update-grub + +sed -i '/PermitRootLogin / s/ .*/ without-password/' /etc/ssh/sshd_config + +mkdir -p /root/.ssh +chmod 0700 /root/.ssh +echo "{{ default_tftp_ssh_key }}" >> /root/.ssh/authorized_keys diff --git a/pxelinux-provisioning/playbooks/templates/pxe/debian/basic.preseed.j2 b/pxelinux-provisioning/playbooks/templates/pxe/debian/basic.preseed.j2 new file mode 100644 index 00000000..5242b639 --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/pxe/debian/basic.preseed.j2 @@ -0,0 +1,221 @@ +# Ubuntu Server Preseed +# Kernel Options + +# Use the following option to add additional boot parameters for the +# installed system (if supported by the bootloader installer). +# Note: options passed to the installer will be added automatically. +d-i debian-installer/add-kernel-opts string biosdevname=0 net.ifnames=0 elevator=cfq + +# Networking +d-i netcfg/choose_interface select eth0 +d-i netcfg/dhcp_timeout string 60 + +## USE THIS FOR STATIC NETWORKING +# d-i netcfg/disable_autoconfig boolean true +# d-i netcfg/dhcp_failed note +# d-i netcfg/dhcp_options select Configure network manually + +# # Static network configuration. +# d-i netcfg/get_ipaddress string 10.0.0.100 +# d-i netcfg/get_netmask string 255.255.255.0 +# d-i netcfg/get_gateway string 10.0.0.200 +# d-i netcfg/get_nameservers string 8.8.8.8 +# d-i netcfg/confirm_static boolean true +## USE THIS FOR STATIC NETWORKING + +# Disable that annoying WEP key dialog. +d-i netcfg/wireless_wep string + +# Pre Install + +# Command Line 1: This is necessary otherwise you will be prompted to umount /dev/vda. See Ubuntu bug #1347726. +d-i preseed/early_command string \ + umount /media || true + +# Net Image + +# Required at least for 12.10+ +d-i live-installer/net-image string {{ default_tftp_server }}/images/{{ item.value.image_short_name }}/install/filesystem.squashfs + +# Localization + +d-i debian-installer/locale string en +d-i debian-installer/country string US +d-i debian-installer/locale string en_US.UTF-8 +d-i debian-installer/language string en + +# Keyboard + +# Disable automatic (interactive) keymap detection. +d-i console-setup/ask_detect boolean false +d-i console-setup/layoutcode string us +d-i console-setup/variantcode string +d-i keyboard-configuration/layoutcode string us + +# Mirror + +d-i mirror/country string manual +d-i mirror/http/proxy string {{ default_mirror_proxy }} +d-i mirror/http/hostname string {{ default_mirror_hostname }} +d-i mirror/http/directory string {{ default_mirror_directory }} + +# Clock and Time Zone + +# Controls whether to use NTP to set the clock during the install +d-i clock-setup/ntp boolean true +d-i clock-setup/ntp-server string ntp.ubuntu.com + +# You may set this to any valid setting for TZ; see the contents of +# /usr/share/zoneinfo/ for valid values. +d-i time/zone string US/Central + +# Controls whether or not the hardware clock is set to UTC. +d-i clock-setup/utc boolean true + +# Partitioning +d-i partman/early_command string \ + DISK="{{ default_root_disk }}"; \ + debconf-set partman-auto/method "lvm"; \ + debconf-set partman-auto/disk "${DISK}"; \ + debconf-set partman-auto-lvm/guided_size "max"; \ + debconf-set partman-auto-lvm/new_vg_name "vg00"; \ + debconf-set partman-auto/expert_recipe "custompartitioning :: \ + 512 1 512 ext2 \ + \$primary{ } \ + \$bootable{ } \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext2 } \ + label{ boot } \ + mountpoint{ /boot } \ + . \ + 1024 1 100% ext4 \ \ + \$primary{ } \ + method{ lvm } \ + device{ ${DISK}2 } \ + vg_name{ vg00 } \ + . \ + 2048 1 4096 linux-swap \ + \$lvmok{ } in_vg{ vg00 } \ + lv_name{ swap00 } \ + method{ swap } format{ } \ + . \ + 8192 1 16384 ext4 \ + \$lvmok{ } in_vg{ vg00 } \ + lv_name{ root00 } \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + label{ root } \ + mountpoint{ / } \ + . \ + 16384 1 16384 ext4 \ + \$lvmok{ } in_vg{ vg00 } \ + lv_name{ openstack00 } \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + label{ openstack } \ + mountpoint{ /openstack } \ + . \ + 16384 1 10240000 ext4 \ + \$lvmok{ } in_vg{ vg00 } \ + lv_name{ deleteme } \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + label{ deleteme } \ + mountpoint{ /var/lib/deleteme } \ + ."; + +# If one of the disks that are going to be automatically partitioned +# contains an old LVM configuration, the user will normally receive a +# warning. This can be preseeded away... +d-i partman-lvm/device_remove_lvm boolean true +d-i partman-lvm/device_remove_lvm_span boolean true +d-i partman-auto/purge_lvm_from_device boolean true + +# The same applies to pre-existing software RAID array: +d-i partman-md/device_remove_md boolean true + +# And the same goes for the confirmation to write the lvm partitions. +d-i partman-lvm/confirm boolean true +d-i partman-lvm/confirm_nooverwrite boolean true +d-i partman-md/confirm boolean true +d-i partman-md/confirm_nooverwrite boolean true + +d-i partman-basicfilesystems/choose_label string gpt +d-i partman-basicfilesystems/default_label string gpt +d-i partman-partitioning/choose_label string gpt +d-i partman-partitioning/default_label string gpt +d-i partman/choose_label string gpt +d-i partman/default_label string gpt + +# This makes partman automatically partition without confirmation, provided +# that you told it what to do using one of the methods above. +d-i partman-partitioning/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true + +# Packages + +# Package selection +tasksel tasksel/first multiselect openssh-server + +# Whether to upgrade packages after debootstrap. +# Allowed values: none, safe-upgrade, full-upgrade +d-i pkgsel/upgrade select full-upgrade +d-i pkgsel/include string bridge-utils \ + dstat \ + ethtool \ + git \ + htop \ + ifenslave \ + lvm2 \ + openssh-server \ + parted \ + python3-all \ + python-all \ + tmux \ + vim \ + vlan + +d-i pkgsel/update-policy select none + +# Some versions of the installer can report back on what software you have +# installed, and what software you use. The default is not to report back, +# but sending reports helps the project determine what software is most +# popular and include it on CDs. +popularity-contest popularity-contest/participate boolean false + +# Users and Password + +# Skip creation of a root account (normal user account will be able to +# use sudo). The default is false; preseed this to true if you want to set +# a root password. +d-i passwd/root-login boolean true + +# Alternatively, to skip creation of a normal user account. +d-i passwd/make-user boolean false + +# The installer will warn about weak passwords. If you are sure you know +# what you're doing and want to override it, uncomment this. +d-i user-setup/allow-password-weak boolean true + +# Root password, either in clear text +d-i passwd/root-password password {{ default_root_password }} +d-i passwd/root-password-again password {{ default_root_password }} + +# Bootloader +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true +d-i grub-installer/with_other_os boolean true +d-i grub-installer/bootdev string default + +# Post Install +d-i preseed/late_command string \ + in-target bash -c "wget --no-proxy http://{{ default_tftp_server }}/scripts/basic-post-install-script.sh -O /opt/basic-post-install-script.sh"; \ + in-target bash -c 'chmod +x /opt/basic-post-install-script.sh'; \ + in-target bash -c '/opt/basic-post-install-script.sh' +# Finish + +# Reboot after the install is finished. +d-i finish-install/reboot_in_progress note diff --git a/pxelinux-provisioning/playbooks/templates/pxe/sites-enabled.default.j2 b/pxelinux-provisioning/playbooks/templates/pxe/sites-enabled.default.j2 new file mode 100644 index 00000000..0ae18590 --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/pxe/sites-enabled.default.j2 @@ -0,0 +1,8 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + root /var/www/pxe; + location / { + autoindex on; + } +} \ No newline at end of file diff --git a/pxelinux-provisioning/playbooks/templates/pxe/tftp/inetd.conf.j2 b/pxelinux-provisioning/playbooks/templates/pxe/tftp/inetd.conf.j2 new file mode 100644 index 00000000..934eedc0 --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/pxe/tftp/inetd.conf.j2 @@ -0,0 +1 @@ +tftp dgram udp wait root /usr/sbin/in.tftpd /usr/sbin/in.tftpd -s /var/lib/tftpboot diff --git a/pxelinux-provisioning/playbooks/templates/pxe/tftp/menu.cfg.j2 b/pxelinux-provisioning/playbooks/templates/pxe/tftp/menu.cfg.j2 new file mode 100644 index 00000000..5e2128a3 --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/pxe/tftp/menu.cfg.j2 @@ -0,0 +1,17 @@ +menu hshift 13 +menu width 49 +menu margin 8 +menu tabmsg + +menu title Boot Menu + +{% for key, value in default_images.items() %} +label {{ key }}-{{ default_images[key]['image_preseed'] }} + menu label ^{{ key }}-{{ default_images[key]['image_preseed'] }} automated install + kernel {{ value.image_kernel }} +{% if value.image_type == 'debian' %} + append {{ value.image_kernel_options }} initrd={{ value.image_initrd }} preseed/url={{ default_images[key]['image_preseed_option']['url'] }} preseed/interactive=false netcfg/choose_interface={{ default_interface }} +{% endif %} +{% endfor %} + +menu end diff --git a/pxelinux-provisioning/playbooks/templates/pxe/tftp/pxelinux.cfg.default.j2 b/pxelinux-provisioning/playbooks/templates/pxe/tftp/pxelinux.cfg.default.j2 new file mode 100644 index 00000000..db9ea4e2 --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/pxe/tftp/pxelinux.cfg.default.j2 @@ -0,0 +1,5 @@ +path boot-screens +include boot-screens/menu.cfg +default boot-screens/vesamenu.c32 +prompt 0 +timeout 100 \ No newline at end of file diff --git a/pxelinux-provisioning/playbooks/templates/pxe/tftp/pxelinux.cfg.macaddr.j2 b/pxelinux-provisioning/playbooks/templates/pxe/tftp/pxelinux.cfg.macaddr.j2 new file mode 100644 index 00000000..037cf89d --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/pxe/tftp/pxelinux.cfg.macaddr.j2 @@ -0,0 +1,10 @@ +{% set image_properties = default_images[hostvars[item]['server_image']] %} + +default linux +prompt 0 +timeout 1 +label linux + kernel {{ image_properties['image_kernel'] }} +{% if image_properties['image_type'] == 'debian' %} + append hostname={{ hostvars[item]['server_hostname'] }} domain={{ hostvars[item]['server_domain_name'] }} {{ image_properties['image_kernel_options'] }} initrd={{ image_properties['image_initrd'] }} preseed/url={{ image_properties['image_preseed_option']['url'] }} preseed/interactive=false netcfg/choose_interface={{ hostvars[item]['server_default_interface'] }} {{ hostvars[item]['server_extra_options'] | default('') }} +{% endif %} diff --git a/pxelinux-provisioning/playbooks/templates/pxe/tftp/tftp-hpa.j2 b/pxelinux-provisioning/playbooks/templates/pxe/tftp/tftp-hpa.j2 new file mode 100644 index 00000000..9ccb73df --- /dev/null +++ b/pxelinux-provisioning/playbooks/templates/pxe/tftp/tftp-hpa.j2 @@ -0,0 +1,6 @@ +TFTP_USERNAME="tftp" +TFTP_DIRECTORY="/var/lib/tftpboot" +TFTP_ADDRESS=":{{ default_tftp_port }}" +TFTP_OPTIONS="--secure" +RUN_DAEMON="yes" +OPTIONS="-l -s /var/lib/tftpboot" diff --git a/pxelinux-provisioning/playbooks/vars/ubuntu-16.04.yml b/pxelinux-provisioning/playbooks/vars/ubuntu-16.04.yml new file mode 100644 index 00000000..5b6f9e1d --- /dev/null +++ b/pxelinux-provisioning/playbooks/vars/ubuntu-16.04.yml @@ -0,0 +1,41 @@ +--- +# Copyright 2017, Rackspace US, Inc. +# +# 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 witing, 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. + +default_host_distro_packages: + - bridge-utils + - ifenslave + - iptables-persistent + - lvm2 + - ntp + - openssh-server + - python2.7 + - python-software-properties + - python-netaddr + - software-properties-common + - vlan + +default_pxe_distro_packages: + - tftpd-hpa + - inetutils-inetd + - nginx + - p7zip-full + +default_dhcp_distro_packages: + - isc-dhcp-server + +default_pkg_cache_server_distro_packages: + - apt-cacher-ng + +default_host_iptables_service: "netfilter-persistent" diff --git a/pxelinux-provisioning/run.sh b/pxelinux-provisioning/run.sh new file mode 100755 index 00000000..207d5f2d --- /dev/null +++ b/pxelinux-provisioning/run.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Copyright [2016] [Kevin Carter] +# +# 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. + +set -euvo + +source ansible-env.rc + +ansible-playbook -vv \ + -i ${DEFAULT_INVENTORY:-"playbooks/inventory.yml"} \ + -e setup_host=${SETUP_HOST:-"true"} \ + -e setup_pxeboot=${SETUP_PXEBOOT:-"true"} \ + -e setup_dhcpd=${SETUP_DHCPD:-"true"} \ + -e default_image=${DEFAULT_IMAGE:-"ubuntu-16.04-amd64"} \ + -e default_http_proxy=${DEFAULT_HTTP_PROXY:-''} \ + --force-handlers \ + playbooks/site.yml