From e96c2e7c848a67b3e61fe26a667b0d26794cc4eb Mon Sep 17 00:00:00 2001
From: "James E. Blair" <jeblair@openstack.org>
Date: Wed, 12 Mar 2014 14:24:20 -0700
Subject: [PATCH] Use unbound

On all machines, set up unbound as a caching recursive resolver.
On single-use slaves, set it up to forward cache misses to the
DNS servers obtained by the template host on boot.

Change-Id: I8505f5a277f20b1328900a9a515cd84db77b2b3b
---
 .../files/nodepool/scripts/prepare_node.sh    | 30 +++++++
 .../openstack_project/manifests/template.pp   |  2 +
 modules/unbound/files/unbound.default         | 18 ++++
 modules/unbound/manifests/init.pp             | 86 +++++++++++++++++++
 4 files changed, 136 insertions(+)
 create mode 100644 modules/unbound/files/unbound.default
 create mode 100644 modules/unbound/manifests/init.pp

diff --git a/modules/openstack_project/files/nodepool/scripts/prepare_node.sh b/modules/openstack_project/files/nodepool/scripts/prepare_node.sh
index e274ab2ba1..f40b972c13 100755
--- a/modules/openstack_project/files/nodepool/scripts/prepare_node.sh
+++ b/modules/openstack_project/files/nodepool/scripts/prepare_node.sh
@@ -23,6 +23,17 @@ PYTHON3=${4:-false}
 PYPY=${5:-false}
 ALL_MYSQL_PRIVS=${6:-false}
 
+# Save the nameservers configured by our provider.
+echo 'forward-zone:' > /tmp/forwarding.conf
+echo '  name: "."' >> /tmp/forwarding.conf
+# HPCloud nameservers (which have 10. addresses) strip RRSIG records.
+# Until this is resolved, use google instead.
+if grep "^nameserver \(10\|206\)\." /etc/resolv.conf; then
+    echo "  forward-addr: 8.8.8.8">> /tmp/forwarding.conf
+else
+    grep "^nameserver" /etc/resolv.conf|sed 's/nameserver \(.*\)/  forward-addr: \1/' >> /tmp/forwarding.conf
+fi
+
 sudo hostname $HOSTNAME
 wget https://git.openstack.org/cgit/openstack-infra/config/plain/install_puppet.sh
 sudo bash -xe install_puppet.sh
@@ -37,6 +48,25 @@ else
 	-e "class {'openstack_project::single_use_slave': install_users => false, sudo => $SUDO, bare => $BARE, python3 => $PYTHON3, include_pypy => $PYPY, all_mysql_privs => $ALL_MYSQL_PRIVS, ssh_key => '$NODEPOOL_SSH_KEY', }"
 fi
 
+# The puppet modules should install unbound.  Take the nameservers
+# that we ended up with at boot and configure unbound to forward to
+# them.
+sudo mv /tmp/forwarding.conf /etc/unbound/
+sudo chown root:root /etc/unbound/forwarding.conf
+sudo chmod a+r /etc/unbound/forwarding.conf
+# HPCloud has selinux enabled by default, Rackspace apparently not.
+# Regardless, apply the correct context.
+if [ -x /sbin/restorecon ] ; then
+    sudo chcon system_u:object_r:named_conf_t:s0 /etc/unbound/forwarding.conf
+fi
+
+sudo bash -c "echo 'include: /etc/unbound/forwarding.conf' >> /etc/unbound/unbound.conf"
+sudo /etc/init.d/unbound restart
+
+# Make sure DNS works.
+dig git.openstack.org
+
+# Cache all currently known gerrit repos.
 sudo mkdir -p /opt/git
 sudo -i python /opt/nodepool-scripts/cache_git_repos.py
 
diff --git a/modules/openstack_project/manifests/template.pp b/modules/openstack_project/manifests/template.pp
index f0c4e1131d..265f6db4e6 100644
--- a/modules/openstack_project/manifests/template.pp
+++ b/modules/openstack_project/manifests/template.pp
@@ -43,6 +43,8 @@ class openstack_project::template (
     ensure => present,
   }
 
+  class { 'unbound': }
+
   if $::osfamily == 'Debian' {
     # Custom rsyslog config to disable /dev/xconsole noise on Debuntu servers
     file { '/etc/rsyslog.d/50-default.conf':
diff --git a/modules/unbound/files/unbound.default b/modules/unbound/files/unbound.default
new file mode 100644
index 0000000000..784cb4c947
--- /dev/null
+++ b/modules/unbound/files/unbound.default
@@ -0,0 +1,18 @@
+# If set, the unbound daemon will be started and stopped by the init script.
+UNBOUND_ENABLE=true
+
+# Whether to automatically update the root trust anchor file.
+ROOT_TRUST_ANCHOR_UPDATE=true
+
+# File in which to store the root trust anchor.
+ROOT_TRUST_ANCHOR_FILE=/var/lib/unbound/root.key
+
+# If set, the unbound init script will provide unbound's listening
+# IP addresses as nameservers to resolvconf.
+RESOLVCONF=true
+
+# If set, resolvconf nameservers will be configured as forwarders
+# to be used by unbound.
+RESOLVCONF_FORWARDERS=false
+
+#DAEMON_OPTS="-c /etc/unbound/unbound.conf"
diff --git a/modules/unbound/manifests/init.pp b/modules/unbound/manifests/init.pp
new file mode 100644
index 0000000000..ba56607163
--- /dev/null
+++ b/modules/unbound/manifests/init.pp
@@ -0,0 +1,86 @@
+# Copyright (C) 2014 OpenStack Foundation
+#
+# 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.
+
+# == Class: unbound
+
+# This installs unbound in its default configuration as a caching
+# recursive resolver.
+
+class unbound (
+) {
+
+  if ($::osfamily == 'Debian') {
+    # This file differs from that in the package only by setting
+    # RESOLVCONF_FORWARDERS to false.
+    file { '/etc/default/unbound':
+      source  => 'puppet:///modules/unbound/unbound.default',
+      owner   => 'root',
+      group   => 'root',
+      mode    => '0444',
+    }
+
+    # We require the defaults file be in place before installing the
+    # package to work around this bug:
+    # https://bugs.launchpad.net/ubuntu/+source/unbound/+bug/988513
+    # where we could end up briefly forwarding to a provider's broken
+    # DNS.
+    package { 'unbound':
+      ensure  => present,
+      require => File['/etc/default/unbound'],
+    }
+  }
+
+  # Ubuntu uses resolvconf which will update resolv.conf to point to
+  # localhost after unbound is installed.  NOTE: Debian unknown.
+  if ($::osfamily == 'RedHat') {
+    package { 'unbound':
+      ensure  => present,
+    }
+
+    # Rackspace uses static config files
+    file { '/etc/resolv.conf':
+      content => "nameserver 127.0.0.1\n",
+      owner   => 'root',
+      group   => 'root',
+      mode    => '0444',
+      require => Service['unbound'],
+      notify  => Exec['make-resolv-conf-immutable'],
+    }
+
+    # Rackspace uses file injection to configure networking which
+    # overwrites all of the files on disk where we could set the env
+    # variable to disable the resolv.conf update on network-up.
+    # Instead, make that file immutable so that the update will fail
+    # (harmlessly).  Of course this means Puppet won't be able to
+    # update it either after this, but we don't plan on changing it.
+    exec { 'make-resolv-conf-immutable':
+      command     => '/usr/bin/chattr +i /etc/resolv.conf',
+      refreshonly => true,
+    }
+
+    # HPCloud uses dhclient; tell dhclient to use our nameserver instead.
+    exec { '/usr/bin/printf "\nsupersede domain-name-servers 127.0.0.1;\n" >> /etc/dhcp/dhclient-eth0.conf':
+        unless => '/bin/grep -q "supersede domain-name-servers" /etc/dhcp/dhclient-eth0.conf'
+    }
+  }
+
+  service { 'unbound':
+    ensure     => running,
+    name       => 'unbound',
+    enable     => true,
+    hasrestart => true,
+    hasstatus  => false,
+    require    => Package['unbound'],
+  }
+}