├── solo
├── solo.json
├── solo.rb
├── run
└── solo-from-scratch
├── README.md
├── cookbooks
└── cephco-generic
│ ├── files
│ └── default
│ │ ├── ceph-libvirt-dns.yaml
│ │ ├── libvirt-net-back.xml
│ │ ├── libvirt-net-pub.xml
│ │ ├── libvirt-net-front.xml
│ │ ├── ceph-libvirt-dns.conf
│ │ ├── parser.py
│ │ ├── rename-if-by-mac
│ │ └── ceph-libvirt-dns.py
│ ├── templates
│ └── default
│ │ ├── libvirt-net-isolated.xml.erb
│ │ ├── interfaces-mira.erb
│ │ └── interfaces.erb
│ └── recipes
│ ├── default.rb
│ ├── ssh-keys.rb
│ ├── libvirt-dns.rb
│ ├── networking-mira.rb
│ ├── networking.rb
│ └── libvirt.rb
└── data_bags
└── ssh-keys
├── sage_flab.json
├── dmick_angus.json
├── alfredo_papaya_local.json
├── andrew_schoen_gmail_com.json
├── zack_zack_cerzas_macbook_pro_local.json
├── sage_ped.json
├── sage_autriche.json
├── sage_doctrine.json
└── dgallowa_dgallowa_csb.json
/solo/solo.json:
--------------------------------------------------------------------------------
1 | {
2 | "run_list": [ "recipe[cephco-generic::default]" ]
3 | }
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | coobook-vm-general
2 | =============
3 |
4 | Chef Solo recipes used to bring up KVM hypervisors in the Sepia lab
5 |
--------------------------------------------------------------------------------
/solo/solo.rb:
--------------------------------------------------------------------------------
1 | root = File.absolute_path(File.dirname(__FILE__))
2 |
3 | file_cache_path root
4 | cookbook_path root + '/../cookbooks'
5 | data_bag_path root + '/../data_bags'
6 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/files/default/ceph-libvirt-dns.yaml:
--------------------------------------------------------------------------------
1 | config:
2 | database: 'mysql://username:password@hostname/databasename?charset=utf8&use_unicode=0'
3 | leasefile: '/var/lib/dhcp/dhcpd.leases'
4 |
5 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/files/default/libvirt-net-back.xml:
--------------------------------------------------------------------------------
1 |
2 | back
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/files/default/libvirt-net-pub.xml:
--------------------------------------------------------------------------------
1 |
2 | pub
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/files/default/libvirt-net-front.xml:
--------------------------------------------------------------------------------
1 |
2 | front
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/templates/default/libvirt-net-isolated.xml.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= @name %>
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/files/default/ceph-libvirt-dns.conf:
--------------------------------------------------------------------------------
1 | description "Libvirt/PowerDNS integration"
2 |
3 | start on runlevel [2345]
4 | stop on runlevel [!2345]
5 |
6 | console log
7 |
8 | respawn
9 |
10 | exec /srv/inktank.com/ceph-libvirt-dns/ceph-libvirt-dns.py
11 |
12 |
--------------------------------------------------------------------------------
/data_bags/ssh-keys/sage_flab.json:
--------------------------------------------------------------------------------
1 | {"id": "sage_flab", "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDn63qpJuh+ZwrRDfDoikZ9Tm5nPJ/m9tP1kyjALJF/CRSiL5g9jRqXiVDcsvdpYmKlFa8Ra0cL1AGq6G3oRue3Lfmw6gTAa4t6m2fTynorQ0V8g/j2//Jc4pIHv43zsWFUPbcIhJf0JIHPrz/jWf2zYsCD7HFBPD7cCVZUV8LmigwSr+TWd3b5t0BCMLs1iRFTx+12V6xwVYqK+74WPnCRTvs7MedSS6taxwSWLhVi7nTtW0XfDG5y26dpoPVoK+zIJVfOaqhh5cjq9K4ds/oJjq39tXRyZ8jJmunE+V92i52P+L3OiXhNfmRUsStKXoKJY4VjLQCELod5y+BULleZ sage@flab"}
2 |
--------------------------------------------------------------------------------
/data_bags/ssh-keys/dmick_angus.json:
--------------------------------------------------------------------------------
1 | {"id": "dmick_angus", "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC305rmql/Qm8Si+DFvAs77hSUZakwiXhhAhSetS89bWq3AdPQTL1MUXJHFm3AMzwzb00tndvsl1AUmFseXLfAi87daNcKJdwEj/JvXgcHKzAXOpVRfArHh08JnOumQiP4EoLYvq7rL+3LjEFURKOWJLLnGxh4E+iiJAnxLTG3WuUcnz9kXVTwtmIs60+2yH+gZJkkB04mnivPYjX46sHigoKgtlE2JnQfOU1lBkeZaBeUhoZX2rIKwRyGELPPcUBwHk10izyk6tePLAw9bSWeS9uEaa/m+qa8neJDyR4/hWQNR9yRXp0YjKkiKoFog+qtsBt3xBNzTPsFLxZ5zugmp dmick@angus"}
2 |
--------------------------------------------------------------------------------
/data_bags/ssh-keys/alfredo_papaya_local.json:
--------------------------------------------------------------------------------
1 | {"id": "alfredo_papaya_local", "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCWy2i6Iv6IWLh53Z44O4fQ0ctxR8odCAWIZAaSQXAxxC++RS+95Zr+BZ5wJwsBOyP1G4AAhl+9uwnn3NmDDG7fKGexPoQrTZZ27KdJ3bHpZRq5LJf9byWFwz4rDsqIqkGjI9sUkfa6nV7ci2BdEkIgLupTT2uXUzTb/njOjI7Fc+cQ7ac4QfJ+yeIcqxeje/YYDF3068V4z1yynk9q2KRXYdERKQghaWDNJlbdBhn/fmsam6okOtUnsXjE88qGPd+LVHWfK0EfYvYXiAoOaJDK8d4EXnJ4RKJceQPBk8ravuQtKVwnRIr8WtmILHuoztthfwqb2WvZ5iMDt6v7oQZ alfredo@papaya.local"}
2 |
--------------------------------------------------------------------------------
/data_bags/ssh-keys/andrew_schoen_gmail_com.json:
--------------------------------------------------------------------------------
1 | {"id": "andrew_schoen_gmail_com", "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDehvF7TbkfX9Ga4fNdq/j9GHu3c9cNk4iIHVs7e14j0h9DlV14aPyn/M0+z90PK+5p2uL9EvRzkbsPrfxpG3pxUa1pmVmKIPvBruA7ln8tExOVwO3XEsBG7b8VWUMlQmwRS9WEfkKAIHlr9cgIFGb1yrMW30RyL7keO1giotAq/wR9pMicyqYAbZOtI3MuPsDVTNxtyD3RwRUQicz6vNaK/RwfMCZVgdvoinrJ7VSyFVEiitzuQqMlrF935sfLvhuyxmwvJKfZI8QMEYcFbKd1cDnCk9n/PySNRY96gb41nb5pUk+0eaDu37jnmj7LLqoidD3UWUuHNnGBAAk+zNlD andrew.schoen@gmail.com"}
2 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/recipes/default.rb:
--------------------------------------------------------------------------------
1 | package 'qemu-kvm'
2 | package 'libvirt-bin'
3 | package 'virtinst'
4 | package 'ebtables'
5 | package 'python-vm-builder'
6 |
7 | include_recipe "cephco-generic::ssh-keys"
8 |
9 | if node['hostname'].match(/^(mira|irvingi)/)
10 | include_recipe "cephco-generic::networking-mira"
11 | else
12 | include_recipe "cephco-generic::networking"
13 | end
14 |
15 | include_recipe "cephco-generic::libvirt"
16 | include_recipe "cephco-generic::libvirt-dns"
17 |
--------------------------------------------------------------------------------
/data_bags/ssh-keys/zack_zack_cerzas_macbook_pro_local.json:
--------------------------------------------------------------------------------
1 | {"id": "zack_zack_cerzas_macbook_pro_local", "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBwJCoMbbxQrI9jM5I/lX0MYDB57LzYXDJTXqmLfJ8E5IHwQbn708/EFXAHuJlCyoJAuA8FaU/Y5/l2LBlVXwp9v+8ftk/D6AcsuQ+Hi0ZLCTvW10OUIS2cwX/of//JJIu6roy3r3SWwUcQvwjaZYLm7QkC+1StsLNMHdgiVRFiibqml72Q53VTtSTt6z2aXjrHzhpZq0hBK/13aknzAjHvGprQnchKVzhA/7A5pArF3CXpnI7aCwKvvjU0AcvqqD8WNLMpF4hFSoTK7xluKB+5UAJ36wefIO2KFM/zMwUtl4/aDhDdPeSaQRWq/q7viKLVNS0X9j2PjSRTfYhJNZr zack@zack-cerzas-macbook-pro.local"}
2 |
--------------------------------------------------------------------------------
/data_bags/ssh-keys/sage_ped.json:
--------------------------------------------------------------------------------
1 | {"id": "sage_ped", "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAJhK1wkU1Drfn+UiBwK0WDL2IDGXpSiAQy9yr62gwSCBo+BRK1+wEsZ55bnl1wOXbYTPNpjYdMHL6kHyWyOsU2L+TbndZRqlLF/7Czq8qxirguZlL0rGI0cU/wAbmPlTReu79iCpiWrAgVCz9D7JfknZc+WPe9l7gvo0xZxadmnJAAAAFQDU1Sd06gjxy7rVDcNuGo5avW7pDQAAAIAAuLKZfwlFV0ng47jXUwApKPuipJWs8nLFdZstHFNfvk+mLan7gm8mGP/+c//6VaHIgH+4SsSIXydPHW+noR1qSuS4pmtJJzKYW3yocRRYXg1M0SbG7yfuhrcU6qBeC3KS2ErJY+Z2DnXg/ILPN8IZK1mYyGKe8/1g/biqgXCqnwAAAIEAlNbOGFpxjX2LabXLfNsf4ICN7AsJVoh9Doneh0GNCQoBmiQOE1S7uOm8knJLeXgtCEZt35tlMX9yZpbFxjkCeni5fuimujU1AK08vJFpYfILV6MP5PynwAfNBMCFp5n1UENnpSkn8drXa4F0F/riZk+GDeiS1R61rdC+5eZ0ieI= sage@ped"}
2 |
--------------------------------------------------------------------------------
/data_bags/ssh-keys/sage_autriche.json:
--------------------------------------------------------------------------------
1 | {"id": "sage_autriche", "key": "ssh-dss AAAAB3NzaC1kc3MAAACBANFvOX/l/Q0sOxp9CoRl4XXYHKQGriGGbAgLEfqQz/NydGijoGrgDugjeG4Yzmx75LHb90v5mJejvtXM6QD1E6KVZwrSaWEHoSXN5LgG1BMZLUhWMJZI1dwaRlNGhIDz3pGxwmh9VXA8fNh2DYdmIuKMr76T3FMV7GeGKBiIGS3RAAAAFQDwCvlxKWXtM/4gdT+Ujxx4rojOZQAAAIEAmDBwmmdxsIftzOfbx/zTkg5FDr/jg0sfwRlSu+KFQaUMJNmYpJZMT44x9UB/OqbQitb1RhvGAkg/qE6aM0i6TYWP//5LPt5aLpVW7HUbwUot5j53KU/SyOmVbXVvi0FbdFtCuABLpMuxlY4XNaFrXnDVDPVWElVVA28U/FE6KzEAAACBAIBhOzyKHrT4erxG2av9PZ7JeGsfiPluiNHyEicvu7uitil86oZK7JjBagK0BGx+QQMdy1OjqpVHXx5KzN2UkknfgmgWW42UfgOsDpYnoGFuTtI+Pm9UX5g/K9UqoHNs2F+ulyVKfM4vuQkTZKG0mYoq7AGgEFCCDrUMBxfudCLH sage@autriche"}
2 |
--------------------------------------------------------------------------------
/data_bags/ssh-keys/sage_doctrine.json:
--------------------------------------------------------------------------------
1 | {"id": "sage_doctrine", "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAKfzZai/1ud7t3PS9WuR6CiSw0vpNShC3m8VoHXAgcQ0LLcC+b/+OpOvKdNhIqnR4uW1Hrm+BEdlUND0lcpuuJ8xOe0UK6AXXVAjtReKR6VzghpT5RDfL4pzWXxq/YzzE1+Yia++g+fJAmst6W9SYq63z80fKDLoRTi18ZN2GCFpAAAAFQDmAmlaOxukcQzTCrq2IcRi7KlMNQAAAIBxUTY4vWfJMgG9JqMoLQfNi98Ouyb31XJnuAAlT/KVSJebDNiMV/b5L79pOYGUjEVXvK1w6YNf4O9gcRsn93oys7NgcWaEsXizmp/7yS8A27Os+6bcWvZdbQd6NeCP17R/swiuUa3DjEjFmjMmt0MGZ/kL4MacEVJPWgaubg9aRwAAAIEApgppgTz98GP9rquAwksULxWy1zOHO2CL3lwKPD/fOOTLltIP0QxvNmRXJJUZQGxa93OwtU8aLvBv8VHYqw2BfZZvpdooTU3kxi56nevKXXda4w2c1TdVTKKP+aai+ijMrUoWOJQmuD6BSe+egLaAMc27YnuhuuLESBcm/V4dak4= sage@doctrine"}
2 |
--------------------------------------------------------------------------------
/data_bags/ssh-keys/dgallowa_dgallowa_csb.json:
--------------------------------------------------------------------------------
1 | {"id": "dgallowa_dgallowa_csb", "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAN3MlkYQNsm1uB6uJQ7hWJ1Ro9Gusrhi/b/KshPMFh51VWBQn71LdCCjdrsE6FWs5FYE/hr7MITJe+si7aZCmuf8U9tc+oiYh3spXtRhJVIM80FOVRXUmt2XR8I+oNbpcFDayYu956Volafksk3oYjsO356swj7+Q+AUQVF4bDJRAAAAFQCkB2YZKItSDL7XfAl6ZmJ21vqUMwAAAIEAsZspNIUwssVJGO4r3M3BECWklWLEFviIjGVKdPWulN10eRCczZrH7vMOs8coHKDQqYdS2RejlojT03FjFAqeBiTeAlcmgHoev+vqTg2Yhqx3gROzNc6NmG887owCOU4j7LJQP6SX8I8EpSXCMNOZliv2ZokjX2DuRsuIDxQdc84AAACBAMAp++fcqmGS7x7ic2x4rhyiYmdqlMIl8lrM3GkVR6qGuIVBvOGl38ieJKcTBLeRgyC04uIMfk8P9lLvZw3UF97qH3V0imKfq8aYnBGxCv+IjtdOrR5k4hrUW+P0qipvU+4dgHlpqwTKB4MtD9uDxvhENWvqcCnOS5rI6dddaZT6 dgallowa@dgallowa.csb"}
2 |
--------------------------------------------------------------------------------
/solo/run:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | cd "$(dirname "$0")"
5 |
6 | for package in chef ruby1.9.1 ruby1.9.1-dev build-essential; do
7 | if [ "$(dpkg --status -- $package|sed -n 's/^Status: //p')" != "install ok installed" ]; then
8 | # add a space after old values
9 | missing="${missing:+$missing }$package"
10 | fi
11 | done
12 | if [ -n "$missing" ]; then
13 | echo "$0: installing missing required packages: $missing" 1>&2
14 | sudo \
15 | env DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical \
16 | apt-get \
17 | -q \
18 | -o Dpkg::Options::=--force-confnew \
19 | install \
20 | --no-install-recommends \
21 | --assume-yes \
22 | -- \
23 | $missing
24 | fi
25 |
26 |
27 | sudo chef-solo -c solo.rb -j solo.json
28 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/templates/default/interfaces-mira.erb:
--------------------------------------------------------------------------------
1 | # AUTO-GENERATED with Chef, DO NOT EDIT
2 |
3 | # The loopback network interface
4 | auto lo
5 | iface lo inet loopback
6 |
7 | auto eth0
8 | iface eth0 inet manual
9 | pre-up /etc/network/rename-if-by-mac -- "$IFACE" <%= @macs['1g1'] %>
10 | pre-up ip link set dev "$IFACE" up
11 |
12 | auto br-front
13 | iface br-front inet static
14 | bridge_ports eth0
15 | bridge_fd 9
16 | bridge_hello 2
17 | bridge_maxage 12
18 | bridge_stp off
19 | # "front" is special: instead of just the vlan trunk, it has a
20 | # native vlan for PXE; this IP address is useful for SSH
21 | address <%= @ips['front'] %>
22 | netmask 255.255.240.0
23 | gateway 10.214.128.1
24 | dns-domain sepia.ceph.com
25 | dns-search front.sepia.ceph.com
26 | dns-nameservers 10.214.128.4 10.214.128.5
27 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/recipes/ssh-keys.rb:
--------------------------------------------------------------------------------
1 | directory '/home/ubuntu/.ssh' do
2 | owner "ubuntu"
3 | group "ubuntu"
4 | mode "0755"
5 | end
6 |
7 | ruby_block "set up ssh keys" do
8 | block do
9 | names = data_bag('ssh-keys')
10 | f = File.open('/home/ubuntu/.ssh/authorized_keys.chef', 'w') do |f|
11 | names.each do |name|
12 | data = data_bag_item('ssh-keys', name)
13 | f.puts(data['key'])
14 | end
15 | end
16 | end
17 | end
18 |
19 | execute "merge authorized ssh keys" do
20 | command <<-'EOH'
21 | set -e
22 | set -- ~ubuntu/.ssh/authorized_keys.chef
23 | if [ -e ~ubuntu/.ssh/authorized_keys ]; then
24 | set -- "$@" ~ubuntu/.ssh/authorized_keys
25 | fi
26 | sort -u -o ~ubuntu/.ssh/authorized_keys.tmp -- "$@"
27 | chown ubuntu:ubuntu -- ~ubuntu/.ssh/authorized_keys.tmp
28 | mv -- ~ubuntu/.ssh/authorized_keys.tmp ~ubuntu/.ssh/authorized_keys
29 | EOH
30 | end
31 |
32 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/recipes/libvirt-dns.rb:
--------------------------------------------------------------------------------
1 | package 'python-webpy'
2 | package 'python-requests'
3 | package 'python-sqlalchemy'
4 | package 'python-mysqldb'
5 | package 'python-yaml'
6 | package 'python-lxml'
7 | package 'python-pyparsing'
8 |
9 | execute "Create ceph-libvirt-dns dir" do
10 | command <<-EOH
11 | mkdir -p /srv/inktank.com/ceph-libvirt-dns
12 | EOH
13 | end
14 |
15 | cookbook_file '/srv/inktank.com/ceph-libvirt-dns/ceph-libvirt-dns.py' do
16 | source "ceph-libvirt-dns.py"
17 | mode 0755
18 | owner "root"
19 | group "root"
20 | end
21 |
22 | cookbook_file '/srv/inktank.com/ceph-libvirt-dns/parser.py' do
23 | source "parser.py"
24 | mode 0755
25 | owner "root"
26 | group "root"
27 | end
28 |
29 | cookbook_file '/etc/init/ceph-libvirt-dns.conf' do
30 | source "ceph-libvirt-dns.conf"
31 | mode 0755
32 | owner "root"
33 | group "root"
34 | end
35 |
36 | execute "Start ceph-libvirt-dns service" do
37 | command <<-EOH
38 | start ceph-libvirt-dns
39 | EOH
40 | end
41 |
42 |
--------------------------------------------------------------------------------
/solo/solo-from-scratch:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # This file is not chmod a+x on purpose, to avoid running it
4 | # accidentally. Automation will always run it through
5 | #
6 | # wget -q -O- https://raw.github.com/ceph/cookbook-vm-general/master/solo/solo-from-scratch | sh
7 |
8 | set -e
9 |
10 | for package in git; do
11 | if [ "$(dpkg --status -- $package|sed -n 's/^Status: //p')" != "install ok installed" ]; then
12 | # add a space after old values
13 | missing="${missing:+$missing }$package"
14 | fi
15 | done
16 | if [ -n "$missing" ]; then
17 | echo "solo-from-scratch: installing missing required packages: $missing" 1>&2
18 | sudo \
19 | env DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical \
20 | apt-get \
21 | -q \
22 | -o Dpkg::Options::=--force-confnew \
23 | install \
24 | --no-install-recommends \
25 | --assume-yes \
26 | -- \
27 | $missing
28 | fi
29 |
30 | SCRATCH="$(mktemp -d --tmpdir 'solo-from-scratch.XXXXXXXXXXXX')"
31 | cd "$SCRATCH"
32 |
33 | cleanup () {
34 | rm -rf "$SCRATCH"
35 | }
36 |
37 | trap cleanup INT TERM EXIT
38 | git init
39 | git pull https://github.com/ceph/cookbook-vm-general.git
40 | ./solo/run
41 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/templates/default/interfaces.erb:
--------------------------------------------------------------------------------
1 | # AUTO-GENERATED with Chef, DO NOT EDIT
2 |
3 | # The loopback network interface
4 | auto lo
5 | iface lo inet loopback
6 |
7 |
8 | auto eth0
9 | iface eth0 inet manual
10 | pre-up /etc/network/rename-if-by-mac -- "$IFACE" <%= @macs['1g1'] %>
11 | pre-up ip link set dev "$IFACE" up
12 |
13 | auto br-front
14 | iface br-front inet static
15 | bridge_ports eth0
16 | bridge_fd 9
17 | bridge_hello 2
18 | bridge_maxage 12
19 | bridge_stp off
20 | # "front" is special: instead of just the vlan trunk, it has a
21 | # native vlan for PXE; this IP address is useful for SSH
22 | address <%= @ips['front'] %>
23 | netmask 255.255.240.0
24 | gateway 10.214.128.1
25 | dns-domain sepia.ceph.com
26 | dns-search front.sepia.ceph.com
27 | dns-nameservers 10.214.128.4 10.214.128.5
28 |
29 |
30 | # "back" side: trunk with native vlan
31 | auto eth2
32 | iface eth2 inet manual
33 | pre-up /etc/network/rename-if-by-mac -- "$IFACE" <%= @macs['10g2'] %>
34 | # ixgbe README warns against bridging/routing and LRO/GRO
35 | # http://downloadmirror.intel.com/14687/eng/README.txt
36 | pre-up ethtool -K "$IFACE" gro off lro off
37 | pre-up ip link set dev "$IFACE" up
38 |
39 | auto br-back
40 | iface br-back inet static
41 | bridge_ports eth2
42 | bridge_fd 9
43 | bridge_hello 2
44 | bridge_maxage 12
45 | bridge_stp off
46 | address <%= @ips['back'] %>
47 | netmask 255.255.240.0
48 |
49 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/recipes/networking-mira.rb:
--------------------------------------------------------------------------------
1 | package 'ethtool'
2 | package 'bridge-utils'
3 |
4 | front_mac = IO.popen('ifconfig eth0 | grep -i hwadd | awk "{print \$5}"').read.chop
5 |
6 | front_ip = IO.popen('ip addr show dev eth0 | grep -w inet | awk "{print \$2}" | cut -d"/" -f1').read.chop
7 |
8 | need_run = ! File.open('/etc/network/interfaces').read() =~ /br-front/
9 |
10 | GENERIC_MACS = {
11 | node['hostname'] => {
12 | '1g1' => front_mac,
13 | },
14 | }
15 |
16 | GENERIC_IPS = {
17 | node['hostname'] => {
18 | 'front' => front_ip,
19 | },
20 | }
21 |
22 | cookbook_file '/etc/network/rename-if-by-mac' do
23 | backup false
24 | owner 'root'
25 | group 'root'
26 | mode 0755
27 | end
28 |
29 |
30 | # generate a .chef file from a template, and then be extra careful in
31 | # swapping it in place; effecting changes over ssh is DANGEROUS,
32 | # please have a serial console handy
33 | template '/etc/network/interfaces.chef' do
34 | source 'interfaces-mira.erb'
35 | mode 0644
36 | variables(
37 | 'macs' => GENERIC_MACS[node['hostname']],
38 | 'ips' => GENERIC_IPS[node['hostname']],
39 | )
40 | only_if need_run
41 | end
42 |
43 | execute "activate network config" do
44 | command <<-'EOH'
45 | set -e
46 | ifdown -a
47 | mv /etc/network/interfaces.chef /etc/network/interfaces
48 | ifup -a
49 | EOH
50 | # don't run the ifdown/ifup if there's no change to the file
51 | only_if {need_run && "cmp /etc/network/interfaces.chef /etc/network/interfaces"}
52 | end
53 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/recipes/networking.rb:
--------------------------------------------------------------------------------
1 | package 'ethtool'
2 | package 'bridge-utils'
3 |
4 |
5 | front_mac = IO.popen('ifconfig eth0 | grep -i hwadd | awk "{print \$5}"').read.chop
6 | back_mac = IO.popen('ifconfig eth2 | grep -i hwadd | awk "{print \$5}"').read.chop
7 |
8 | front_ip = IO.popen('ip addr show dev eth0 | grep -w inet | awk "{print \$2}" | cut -d"/" -f1').read.chop
9 | back_ip = IO.popen('ip addr show dev eth2 | grep -w inet | awk "{print \$2}" | cut -d"/" -f1').read.chop
10 |
11 | need_run = ! File.open('/etc/network/interfaces').read() =~ /br-front/
12 |
13 | GENERIC_MACS = {
14 | node['hostname'] => {
15 | '1g1' => front_mac,
16 | '10g1' => back_mac,
17 | },
18 | }
19 |
20 | GENERIC_IPS = {
21 | node['hostname'] => {
22 | 'front' => front_ip,
23 | 'back' => back_ip,
24 | },
25 | }
26 |
27 | cookbook_file '/etc/network/rename-if-by-mac' do
28 | backup false
29 | owner 'root'
30 | group 'root'
31 | mode 0755
32 | end
33 |
34 |
35 | # generate a .chef file from a template, and then be extra careful in
36 | # swapping it in place; effecting changes over ssh is DANGEROUS,
37 | # please have a serial console handy
38 | template '/etc/network/interfaces.chef' do
39 | source 'interfaces.erb'
40 | mode 0644
41 | variables(
42 | 'macs' => GENERIC_MACS[node['hostname']],
43 | 'ips' => GENERIC_IPS[node['hostname']],
44 | )
45 | only_if need_run
46 | end
47 |
48 | execute "activate network config" do
49 | command <<-'EOH'
50 | set -e
51 | ifdown -a
52 | mv /etc/network/interfaces.chef /etc/network/interfaces
53 | ifup -a
54 | EOH
55 | # don't run the ifdown/ifup if there's no change to the file
56 | only_if {need_run && "cmp /etc/network/interfaces.chef /etc/network/interfaces"}
57 | end
58 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/files/default/parser.py:
--------------------------------------------------------------------------------
1 | from pyparsing import (
2 | CharsNotIn,
3 | Combine,
4 | Keyword,
5 | Literal,
6 | ParseSyntaxException,
7 | TokenConverter,
8 | Word,
9 | alphas,
10 | hexnums,
11 | nestedExpr,
12 | nums,
13 | quotedString,
14 | )
15 |
16 |
17 | # ungroup is only available in pyparsing >=1.5.6
18 | try:
19 | from pyparsing import ungroup
20 | _ungroup = ungroup
21 | except ImportError:
22 | def _ungroup(expr):
23 | return TokenConverter(expr).setParseAction(lambda t: t[0])
24 |
25 |
26 | def dictify(s, loc, toks):
27 | return dict(toks)
28 |
29 | _p_ip_address = Combine(Word(nums) - ('.' + Word(nums)) * 3)
30 |
31 | _p_lease_deleted = Literal("deleted")
32 | _p_lease_deleted.setParseAction(lambda s, loc, toks: True)
33 |
34 | _p_lease_active = Literal("binding state active")
35 | _p_lease_active.setParseAction(lambda s, loc, toks: True)
36 |
37 | _p_hex_digit = Word(hexnums, exact=2)
38 | _p_mac = Combine(
39 | _p_hex_digit + ':' + _p_hex_digit + ':' + _p_hex_digit + ':'
40 | + _p_hex_digit + ':' + _p_hex_digit + ':' + _p_hex_digit)
41 |
42 | _p_lease_hardware_ethernet = _ungroup(
43 | Keyword("hardware").suppress()
44 | + Keyword("ethernet").suppress()
45 | + _p_mac
46 | )
47 |
48 | _p_lease_junk = (
49 | Word(alphas)
50 | # if we include { } ; here, they become greedy and eat the closing
51 | # brace or semicolon
52 | + CharsNotIn('{};')
53 | ).suppress()
54 |
55 | _p_lease_decl = (
56 | _p_lease_deleted.setResultsName('deleted')
57 | | _p_lease_active.setResultsName('active')
58 | | _p_lease_hardware_ethernet.setResultsName('mac')
59 | | _p_lease_junk
60 | ) + Literal(';').suppress()
61 |
62 | _p_lease = (
63 | Keyword("lease").suppress()
64 | + _p_ip_address.setResultsName('ip')
65 | + _ungroup(
66 | nestedExpr(
67 | opener='{',
68 | closer='}',
69 | content=_p_lease_decl,
70 | ignoreExpr=quotedString,
71 | ),
72 | )
73 | ).setParseAction(dictify)
74 |
75 |
76 | def parse(s):
77 | g = _p_lease.scanString(s)
78 | while True:
79 | try:
80 | (toks, start, end) = next(g)
81 | except StopIteration:
82 | break
83 | except ParseSyntaxException:
84 | # hide errors from callers; probably encountered the last,
85 | # partial statement while dhcpd is appending to the file;
86 | # stop here, inotify will wake up the caller as the next
87 | # chunk arrives
88 | break
89 | else:
90 | (tok,) = toks
91 | yield tok
92 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/files/default/rename-if-by-mac:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # nameif is not useful when virtual interfaces are inheriting the mac
4 | # from the physical interface; e.g. after a "ip link add link ... name
5 | # ... type vlan id ...", it will try to rename the vlan interface,
6 | # collides with the physical interface, and aborts
7 |
8 | import argparse
9 | import os
10 | import re
11 | import subprocess
12 | import sys
13 |
14 | PROG = os.path.basename(sys.argv[0])
15 |
16 | class Fail(SystemExit):
17 | def __init__(self, msg, **kwargs):
18 | msg = msg.format(**kwargs)
19 | super(Fail, self).__init__('{prog}: {msg}'.format(
20 | prog=PROG,
21 | msg=msg,
22 | ))
23 |
24 | LINK_RE = re.compile(r"""
25 | # ifindex
26 | ^\d+:[ ]
27 | # iface name
28 | (?P.*?):[ ]
29 | # uninteresting
30 | .*[ ]
31 | # mac address
32 | link/ether\ (?P[0-9a-f][0-9a-f](?::[0-9a-f][0-9a-f]){5})
33 | # tailing uninterestingness
34 | [ ]
35 | """, re.MULTILINE|re.VERBOSE)
36 |
37 | def get_state():
38 | output = subprocess.check_output(['ip', '-o', 'link', 'show'])
39 | matches = LINK_RE.findall(output)
40 | links = dict(matches)
41 | return links
42 |
43 |
44 | def main():
45 | parser = argparse.ArgumentParser(
46 | description='Rename interface based on MAC address',
47 | )
48 | parser.add_argument(
49 | 'iface',
50 | help='Desired interface name',
51 | )
52 | parser.add_argument(
53 | 'mac',
54 | help='MAC address to look for',
55 | )
56 | args = parser.parse_args()
57 |
58 | state = get_state()
59 |
60 | cur = state.get(args.iface)
61 | if cur is not None:
62 | if cur != args.mac:
63 | raise Fail(
64 | 'Interface exists with wrong MAC: {iface} {mac}',
65 | iface=args.iface,
66 | mac=cur,
67 | )
68 |
69 | # all done here
70 | return
71 |
72 | # no interface by that name exists currently; look for it
73 | candidates = [iface
74 | for (iface,mac) in state.iteritems()
75 | if mac == args.mac]
76 | if not candidates:
77 | raise Fail(
78 | 'Cannot find any interface with MAC: {mac}',
79 | mac=args.mac,
80 | )
81 |
82 | if len(candidates) > 1:
83 | only_eth = [iface
84 | for iface in candidates
85 | if iface.startswith('eth')]
86 | if only_eth:
87 | candidates = only_eth
88 |
89 | if len(candidates) > 1:
90 | raise Fail(
91 | 'Several candidate interfaces, aborting: {ifaces}',
92 | ifaces=' '.join(candidates),
93 | )
94 |
95 | # and finally do it
96 | iface = candidates[0]
97 | os.execvp('ip', ['ip', 'link', 'set', iface, 'name', args.iface])
98 |
99 | if __name__ == '__main__':
100 | import sys
101 | sys.exit(main())
102 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/recipes/libvirt.rb:
--------------------------------------------------------------------------------
1 | # workaround for bug https://bugs.launchpad.net/ubuntu/+source/libvirt/+bug/1018956
2 | execute 'set up libvirt pool default' do
3 | command <<-'EOH'
4 | set -e
5 | if ! virsh pool-uuid default >/dev/null 2>/dev/null; then
6 | # does not exist
7 | virsh pool-define-as --name default dir --target /var/lib/libvirt/images
8 | fi
9 | virsh -q pool-info default | while read line; do
10 | case "$line" in
11 | State:\ *inactive)
12 | virsh pool-start default
13 | ;;
14 | Autostart:\ *no)
15 | virsh pool-autostart default
16 | ;;
17 | esac
18 | done
19 | EOH
20 | end
21 |
22 | # Remove default pool and crete vpm pools if vpm host:
23 | execute 'Setting up teuthology VM pools' do
24 | command <<-'EOH'
25 | set -e
26 | if [ -d /srv/libvirtpool ]
27 | then
28 | cd /srv/libvirtpool
29 | virsh pool-destroy default
30 | virsh pool-undefine default
31 | for pool in *
32 | do
33 | sudo virsh pool-define-as --name $pool --type dir --target /srv/libvirtpool/$pool
34 | sudo virsh pool-autostart $pool
35 | sudo virsh pool-build $pool
36 | sudo virsh pool-start $pool
37 | done
38 | fi
39 | EOH
40 | end
41 |
42 |
43 | directory '/srv/chef' do
44 | owner 'root'
45 | group 'root'
46 | mode 0755
47 | end
48 |
49 | cookbook_file '/srv/chef/libvirt-net-pub.xml' do
50 | owner 'root'
51 | group 'root'
52 | mode 0644
53 | end
54 |
55 | execute 'set up libvirt network pub' do
56 | command <<-'EOH'
57 | set -e
58 | if ! virsh net-uuid pub >/dev/null 2>/dev/null; then
59 | # does not exist
60 | virsh net-define /srv/chef/libvirt-net-pub.xml
61 | fi
62 | virsh -q net-info pub | while read line; do
63 | case "$line" in
64 | Active:\ *no)
65 | virsh net-start pub
66 | ;;
67 | Autostart:\ *no)
68 | virsh net-autostart pub
69 | ;;
70 | esac
71 | done
72 | EOH
73 | end
74 |
75 | cookbook_file '/srv/chef/libvirt-net-front.xml' do
76 | owner 'root'
77 | group 'root'
78 | mode 0644
79 | end
80 |
81 |
82 | execute 'set up libvirt network front' do
83 | command <<-'EOH'
84 | set -e
85 | if ! virsh net-uuid front >/dev/null 2>/dev/null; then
86 | # does not exist
87 | virsh net-define /srv/chef/libvirt-net-front.xml
88 | fi
89 | virsh -q net-info front | while read line; do
90 | case "$line" in
91 | Active:\ *no)
92 | virsh net-start front
93 | ;;
94 | Autostart:\ *no)
95 | virsh net-autostart front
96 | ;;
97 | esac
98 | done
99 | EOH
100 | end
101 |
102 |
103 | if !node['hostname'].match(/^(mira|irvingi)/)
104 | cookbook_file '/srv/chef/libvirt-net-back.xml' do
105 | owner 'root'
106 | group 'root'
107 | mode 0644
108 | end
109 |
110 | execute 'set up libvirt network back' do
111 | command <<-'EOH'
112 | set -e
113 | if ! virsh net-uuid back >/dev/null 2>/dev/null; then
114 | # does not exist
115 | virsh net-define /srv/chef/libvirt-net-back.xml
116 | fi
117 | virsh -q net-info back | while read line; do
118 | case "$line" in
119 | Active:\ *no)
120 | virsh net-start back
121 | ;;
122 | Autostart:\ *no)
123 | virsh net-autostart back
124 | ;;
125 | esac
126 | done
127 | EOH
128 | end
129 | end
130 |
131 |
132 | execute 'allow libvirt for user ubuntu' do
133 | command <<-'EOH'
134 | set -e
135 | gpasswd -a ubuntu libvirtd
136 | EOH
137 | end
138 |
139 |
140 | # TODO refactor into a libvirt_interface LWR?
141 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].each do |num|
142 |
143 | template "/srv/chef/libvirt-net-isolated#{num}.xml" do
144 | source 'libvirt-net-isolated.xml.erb'
145 | owner 'root'
146 | group 'root'
147 | mode 0644
148 | variables(
149 | 'name' => "isolated#{num}",
150 | )
151 | end
152 |
153 | execute "set up libvirt network isolated#{num}" do
154 | environment ({
155 | 'NET' => "isolated#{num}",
156 | })
157 | command <<-'EOH'
158 | set -e
159 | if ! virsh net-uuid "$NET" >/dev/null 2>/dev/null; then
160 | # does not exist
161 | virsh net-define /srv/chef/libvirt-net-"$NET".xml
162 | fi
163 | virsh -q net-info "$NET" | while read line; do
164 | case "$line" in
165 | Active:\ *no)
166 | virsh net-start "$NET"
167 | ;;
168 | Autostart:\ *no)
169 | virsh net-autostart "$NET"
170 | ;;
171 | esac
172 | done
173 | EOH
174 | end
175 |
176 | end
177 |
--------------------------------------------------------------------------------
/cookbooks/cephco-generic/files/default/ceph-libvirt-dns.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import argparse
3 | import requests
4 | import re
5 | import sys
6 | import time
7 | import datetime
8 | import traceback
9 | import sqlalchemy as sq
10 | import web
11 | import yaml
12 | import libvirt
13 | import json
14 | from lxml import etree
15 | import parser
16 | import os
17 | import subprocess
18 |
19 | url = 'http://10.214.128.1:8080/'
20 | domain = 'front.sepia.ceph.com'
21 | sleepinterval = 40
22 | guestlist = []
23 |
24 | def parse_args():
25 | parser = argparse.ArgumentParser(
26 | description='DNS for libvirt',
27 | )
28 | parser.add_argument(
29 | '--config',
30 | metavar='CONFIGFILE',
31 | help='path to YAML config file',
32 | )
33 | parser.add_argument(
34 | '--server',
35 | action='store_true', default=False,
36 | help='Run as the server (http/sql access).',
37 | )
38 | parser.add_argument(
39 | 'remainder',
40 | nargs=argparse.REMAINDER,
41 | help='Remainder arguments for webpy, ip:port for listen address'
42 | )
43 | args = parser.parse_args()
44 | return args
45 |
46 | def read_config(path):
47 | if path is None:
48 | raise NameError('Configuration file not specified with --config or cant be opened')
49 | else:
50 | with file(path) as f:
51 | obj = yaml.safe_load(f)
52 | assert 'config' in obj
53 | return obj['config']
54 |
55 |
56 | urls = (
57 | '/', 'index'
58 | )
59 |
60 | def parseleases(s):
61 | leases = {}
62 | for l in parser.parse(s):
63 | if 'active' in l:
64 | if 'mac' in l:
65 | assert 'mac' in l
66 | leases[l['mac']] = l
67 | return leases
68 |
69 | def add(leases, dburl, name, mac):
70 | my_domain_id = 1
71 | db = sq.create_engine(dburl)
72 | metadata = sq.MetaData(bind=db)
73 | records_table = sq.Table('records', metadata,
74 | sq.Column('id', sq.Integer, primary_key=True),
75 | sq.Column('domain_id', sq.Integer),
76 | sq.Column('name', sq.String),
77 | sq.Column('type', sq.String),
78 | sq.Column('content', sq.String),
79 | sq.Column('ttl', sq.Integer),
80 | sq.Column('prio', sq.Integer),
81 | sq.Column('change_date', sq.Integer),
82 | sq.Column('ordername', sq.String),
83 | sq.Column('auth', sq.Integer),
84 | sq.Column('propernoun_epoch', sq.Integer),
85 | )
86 |
87 | ip = leases[mac]['ip']
88 | existcheck = sq.select([records_table], records_table.c.name==name).limit(1).execute().fetchone()
89 | if existcheck is None:
90 | state = "Added"
91 | ins = records_table.insert()
92 | db.execute(ins, domain_id=my_domain_id, name=name, type="A", content=ip, ttl="30", auth="1")
93 | else:
94 | if existcheck[4] == ip:
95 | state = "No Change"
96 | else:
97 | state = "Updated"
98 | records_table.update().where(records_table.c.name==name).values(content=ip).execute()
99 | returnstring = " " + state + " HOSTNAME: "+name+" MAC: "+mac+" IP: "+ip
100 | return returnstring
101 |
102 | def delete(dburl, name):
103 | my_domain_id = 1
104 | db = sq.create_engine(dburl)
105 | metadata = sq.MetaData(bind=db)
106 | records_table = sq.Table('records', metadata,
107 | sq.Column('id', sq.Integer, primary_key=True),
108 | sq.Column('domain_id', sq.Integer),
109 | sq.Column('name', sq.String),
110 | sq.Column('type', sq.String),
111 | sq.Column('content', sq.String),
112 | sq.Column('ttl', sq.Integer),
113 | sq.Column('prio', sq.Integer),
114 | sq.Column('change_date', sq.Integer),
115 | sq.Column('ordername', sq.String),
116 | sq.Column('auth', sq.Integer),
117 | sq.Column('propernoun_epoch', sq.Integer),
118 | )
119 | state = 'Deleting'
120 | records_table.delete().where(records_table.c.name==name).execute()
121 | returnstring = " " + state + " HOSTNAME: "+name
122 | return returnstring
123 |
124 | class index:
125 | def GET(self):
126 | i = web.input()
127 | print i
128 | s = open(web.leasefile).read()
129 | leases = parseleases(s)
130 | string = ''
131 | for guest in i:
132 | if '|' not in i[guest]:
133 | print "Client sent junk data"
134 | else:
135 | name = i[guest].split('|')[0]
136 | mac = i[guest].split('|')[1]
137 | hostname = name + '.' + domain
138 | if mac in leases:
139 | string = string + '\n' + add(leases, web.dburl, name=hostname, mac=mac)
140 | else:
141 | #Delete entry mac string
142 | if mac == 'FF:FF:FF:FF:FF:FF':
143 | string = string + '\n' + delete(web.dburl, name=hostname)
144 | else:
145 | string = string + '\n ' + "Error: IP for: " + name + " not found from MAC: " + mac
146 | return string
147 |
148 | def is_gitbuilder(name):
149 | return name.startswith('gitbuilder-')
150 |
151 | def getLXCstring():
152 | returnstring = ""
153 | dir = "/var/lib/lxc"
154 | if os.path.exists(dir):
155 | if os.listdir(dir):
156 | for o in os.listdir(dir):
157 | if os.path.isdir(dir + "/" + o):
158 | name = o
159 | if os.path.isfile(dir + "/" + o + "/config"):
160 | contents = open(dir + "/" + o + "/config").read()
161 | if "br-front" in contents:
162 | for line in open(dir + "/" + o + "/config").readlines():
163 | if re.search('lxc.network.hwaddr', line):
164 | mac = line.split()[2]
165 | lxcinfo = subprocess.Popen(['lxc-info', '-n', name] ,stdout=subprocess.PIPE).stdout.read()
166 | if "RUNNING" in lxcinfo and not is_gitbuilder(name):
167 | returnstring = returnstring + name + '=' + name + '|' + mac + '&'
168 | else:
169 | return returnstring
170 | else:
171 | return returnstring
172 | return returnstring
173 |
174 | def getAllDomains(conn):
175 | """
176 | List and get all domains, active or not.
177 |
178 | The python bindings don't seem to have this at version
179 | 0.9.8-2ubuntu17.1 and a combination of listDefinedDomains and
180 | listDomainsID is just miserable.
181 |
182 | http://libvirt.org/html/libvirt-libvirt.html#virConnectListAllDomains
183 |
184 | Also fetch the actual domain object, as we'll need the xml.
185 | """
186 | for name in conn.listDefinedDomains():
187 | try:
188 | domain = conn.lookupByName(name)
189 | except libvirt.libvirtError as e:
190 | if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
191 | # lost a race, someone undefined the domain
192 | # between listing names and fetching details
193 | pass
194 | else:
195 | raise
196 | else:
197 | yield domain
198 |
199 | for id_ in conn.listDomainsID():
200 | try:
201 | domain = conn.lookupByID(id_)
202 | except libvirt.libvirtError as e:
203 | if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
204 | # lost a race, someone undefined the domain
205 | # between listing names and fetching details
206 | pass
207 | else:
208 | raise
209 | else:
210 | yield domain
211 |
212 |
213 | def get_interfaces(tree):
214 | networks = tree.xpath(
215 | "/domain/devices/interface[@type='network']",
216 | )
217 | for net in networks:
218 | (name,) = net.xpath('./source/@network')
219 | (mac,) = net.xpath('./mac/@address')
220 | yield (name, mac)
221 |
222 |
223 | def _handle_event(conn, domain, event, detail, getstring):
224 | msg = dict(
225 | type='libvirt',
226 | vm=dict(
227 | name=domain.name(),
228 | uuid=domain.UUIDString(),
229 | ),
230 | )
231 | if event == libvirt.VIR_DOMAIN_EVENT_DEFINED:
232 | xml_s = domain.XMLDesc(flags=2)
233 | tree = etree.fromstring(xml_s)
234 | ifaces = get_interfaces(tree)
235 | ifaces = list(ifaces)
236 | msg['vm']['interfaces'] = ifaces
237 | elif event == libvirt.VIR_DOMAIN_EVENT_UNDEFINED:
238 | pass
239 | else:
240 | print >>sys.stderr, \
241 | ('unknown event:'
242 | + ' Domain {name} event={event} detail={detail}'.format(
243 | name=domain.name(),
244 | event=event,
245 | detail=detail,
246 | )
247 | )
248 | return
249 | name = ''
250 | for int in ifaces:
251 | name = domain.name()
252 | if 'front' or 'br-front' in int:
253 | mac = int[1]
254 | getstring = getstring + name + '=' + name + '|' + mac + '&'
255 | return getstring, name
256 |
257 |
258 | def libvirt_list_and_update_dns(guestlist):
259 | uri = 'qemu:///system'
260 | try:
261 | conn = libvirt.openReadOnly(uri)
262 | except Exception:
263 | print "Something went wrong connecting to libvirt. Is libvirt-bin installed/running? Sleeping for 5 minutes"
264 | time.sleep(300)
265 | return False
266 | pass
267 |
268 | getstring = ''
269 | deletestring = ''
270 |
271 | guests = []
272 | for domain in getAllDomains(conn):
273 | if is_gitbuilder(guest)
274 | continue
275 | getstring, guest = _handle_event(
276 | conn=conn,
277 | domain=domain,
278 | event=libvirt.VIR_DOMAIN_EVENT_DEFINED,
279 | detail=None,
280 | getstring=getstring
281 | )
282 | guests.append(guest)
283 |
284 | #If a guest was removed give it a fake mac so the server will delete the DNS entry
285 | for guest in guestlist:
286 | if guest not in guests:
287 | getstring = getstring + guest + '=' + guest + '|FF:FF:FF:FF:FF:FF&'
288 |
289 | getstring = getstring.rstrip('&')
290 | lxcstring = getLXCstring().rstrip('&')
291 | if lxcstring != '':
292 | getstring = getstring + "&" + lxcstring
293 |
294 | if getstring == '':
295 | print "Host has no guests with front network bridging. Not contacting server."
296 | return False, guests
297 |
298 | try:
299 | update = requests.get(url + '?' + getstring)
300 | except Exception:
301 | print "Contacting the server failed. Is it down? Sleeping for 5 minutes"
302 | time.sleep(300)
303 | return False, guests
304 |
305 | try:
306 | exception = update.raise_for_status()
307 | except Exception:
308 | print "Server response was abnormal (non 200) Sleeping for 5 minutes"
309 | traceback.print_exc()
310 | time.sleep(300)
311 | return False, guests
312 |
313 | print 'Server Response:'+update.content
314 | return True, guests
315 |
316 | def main(guestlist):
317 | args = parse_args()
318 |
319 | if args.server:
320 | print "Running in Server Mode:"
321 | config = read_config(args.config)
322 | web.dburl = config['database']
323 | web.leasefile = config['leasefile']
324 | # Webpy also uses Arguments. Replace sys.argv with argument 0 (script name) and add unused arguments by argparse)
325 | sys.argv = [sys.argv[0]] + args.remainder
326 | app = web.application(urls, globals())
327 | app.run()
328 | else:
329 | print "Running in Client Mode:"
330 | while True:
331 | print datetime.datetime.now()
332 | updated, guestlist = libvirt_list_and_update_dns(guestlist)
333 | if updated == False:
334 | sleepinterval = 5
335 | else:
336 | sleepinterval = 40
337 | print "Sleeping for "+str(sleepinterval)+" Seconds..."
338 | time.sleep(sleepinterval)
339 |
340 | if __name__ == "__main__":
341 | main(guestlist)
342 |
--------------------------------------------------------------------------------