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