aboutsummaryrefslogtreecommitdiff
path: root/contrib/dev/vagrant/Vagrantfile
blob: 3088e21267649dfcc6a5462d434a94e0181461cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# -*- mode: ruby -*-
# vi: set ft=ruby :

require "ipaddr"

# Check for required plugin(s)
['vagrant-hostmanager'].each do |plugin|
  unless Vagrant.has_plugin?(plugin)
    raise "#{plugin} plugin not found. Please install it via 'vagrant plugin install #{plugin}'"
  end
end

class VagrantConfigMissing < StandardError
end

vagrant_dir = File.expand_path(File.dirname(__FILE__))

# get kolla and kolla-ansibe repos path relative to current directory
# they will be used by the bootstrap script to configure the nodes
kolla_ansible_repo_path = File.expand_path(File.join(vagrant_dir, '..', '..', '..'))
kolla_repo_path = File.expand_path(File.join(vagrant_dir, '..', '..', '..', '..', 'kolla'))

# Vagrantfile.custom contains user customization for the Vagrantfile
# You shouldn't have to edit the Vagrantfile, ever.
if File.exists?(File.join(vagrant_dir, 'Vagrantfile.custom'))
  eval(IO.read(File.join(vagrant_dir, 'Vagrantfile.custom')), binding)
end

# Either libvirt or virtualbox
PROVIDER ||= "libvirt"
# Either centos or ubuntu
DISTRO ||= "centos"

# The libvirt graphics_ip used for each guest. Only applies if PROVIDER
# is libvirt.
GRAPHICSIP ||= "127.0.0.1"

# The bootstrap.sh provision_script requires CentOS 7 or Ubuntu 15.10.
# Provisioning other boxes than the default ones may therefore
# require changes to bootstrap.sh.
PROVISION_SCRIPT ||= "bootstrap.sh"

PROVIDER_DEFAULTS ||= {
  libvirt: {
    centos: {
      base_image: "centos/7",
      bridge_interface: "virbr0",
      vagrant_shared_folder: "/home/vagrant/sync",
      sync_method: "nfs",
      kolla_path: "/home/vagrant/kolla",
      kolla_ansible_path: "/home/vagrant/kolla-ansible"
    }
  },
  virtualbox: {
    centos: {
      base_image: "puppetlabs/centos-7.0-64-puppet",
      bridge_interface: "wlp3s0b1",
      vagrant_shared_folder: "/home/vagrant/sync",
      sync_method: "virtualbox",
      kolla_path: "/home/vagrant/kolla",
      kolla_ansible_path: "/home/vagrant/kolla-ansible"
    },
    ubuntu: {
      base_image: "ubuntu/wily64",
      bridge_interface: "wlp3s0b1",
      vagrant_shared_folder: "/home/vagrant/sync",
      sync_method: "virtualbox",
      kolla_path: "/home/vagrant/kolla",
      kolla_ansible_path: "/home/vagrant/kolla-ansible"
    }
  }
}

# Whether the host network adapter is Wi-Fi.
# On VirtualBox, the user must first manually create a NAT-Network
# named "OSNetwork". The default network CIDR must be changed.
# The Neutron external interface will be connected to this Network.
WIFI = false unless self.class.const_defined?(:WIFI)

# Whether to do Multi-node or All-in-One deployment
MULTINODE = false unless self.class.const_defined?(:MULTINODE)

# The following is only used when deploying in Multi-nodes
NUMBER_OF_CONTROL_NODES ||= 3
NUMBER_OF_COMPUTE_NODES ||= 1
NUMBER_OF_STORAGE_NODES ||= 1
NUMBER_OF_NETWORK_NODES ||= 1

NODE_SETTINGS ||= {
  aio: {
    cpus: 4,
    memory: 4096
  },
  operator: {
    cpus: 1,
    memory: 1024
  },
  control: {
    cpus: 1,
    memory: 2048
  },
  compute: {
    cpus: 1,
    memory: 1024
  },
  storage: {
    cpus: 1,
    memory: 1024
  },
  network: {
    cpus: 1,
    memory: 1024
  }
}

# Configure a new SSH key and config so the operator is able to connect with
# the other cluster nodes.
unless File.file?(File.join(vagrant_dir, 'vagrantkey'))
  system("ssh-keygen -f #{File.join(vagrant_dir, 'vagrantkey')} -N '' -C this-is-vagrant")
end

def get_default(setting)
  PROVIDER_DEFAULTS[PROVIDER.to_sym][DISTRO.to_sym][setting]
rescue
  raise VagrantConfigMissing,
    "Missing configuration for PROVIDER_DEFAULTS[#{PROVIDER}][#{DISTRO}][#{setting}]"
end

def get_setting(node, setting)
  NODE_SETTINGS[node][setting]
rescue
  raise VagrantConfigMissing,
    "Missing configuration for NODE_SETTINGS[#{node}][#{setting}]"
end

def configure_wifi_vbox_networking(vm)
  # Even if adapters 1 & 2 don't need to be modified, if the order is to be
  # maintained, some modification has to be done to them. This will maintain
  # the association inside the guest OS: NIC1 -> eth0, NIC2 -> eth1, NIC3 ->
  # eht2. The modifications for adapters 1 & 2 only change optional properties.
  # Adapter 3 is enabled and connected to the NAT-Network named "OSNetwork",
  # while also changing its optional properties. Since adapter 3 is used by
  # Neutron for the external network, promiscuous mode is set to "allow-all".
  # Also, use virtio as the adapter type, for better performance.
  vm.customize ["modifyvm", :id, "--nictype1", "virtio"]
  vm.customize ["modifyvm", :id, "--cableconnected1", "on"]
  vm.customize ["modifyvm", :id, "--nicpromisc2", "deny"]
  vm.customize ["modifyvm", :id, "--nictype2", "virtio"]
  vm.customize ["modifyvm", :id, "--cableconnected2", "on"]
  vm.customize ["modifyvm", :id, "--nic3", "natnetwork"]
  vm.customize ["modifyvm", :id, "--nat-network3", "OSNetwork"]
  vm.customize ["modifyvm", :id, "--nicpromisc3", "allow-all"]
  vm.customize ["modifyvm", :id, "--nictype3", "virtio"]
  vm.customize ["modifyvm", :id, "--cableconnected3", "on"]
end

def configure_wifi_if_enabled(vm)
  if WIFI
    case PROVIDER
    when "virtualbox"
      configure_wifi_vbox_networking(vm)
#   TODO(lucian-serb): Configure networking on Wi-Fi for other hypervisors.
#   when "libvirt"
#     configure_wifi_libvirt_networking(vm)
    end
  end
end

Vagrant.configure(2) do |config|

  # check for kolla repo to be available
  unless File.directory?(kolla_repo_path)
    raise VagrantConfigMissing,
      "Missing kolla repository checkout at #{kolla_repo_path}"
  end

  config.vm.box = get_default(:base_image)

  # Next to the hostonly NAT-network there is a host-only network with all
  # nodes attached. Plus, each node receives a 3rd adapter connected to the
  # outside public network.
  config.vm.network "private_network", type: "dhcp"
  # On VirtualBox hosts with Wi-Fi, do not create a public bridged interface.
  # A NAT-Network will be used instead.
  # TODO(lucian-serb): Do the same for other hypervisors as well?
  unless PROVIDER == "virtualbox" && WIFI
    config.vm.network "public_network", dev: get_default(:bridge_interface), mode: 'bridge', type: 'bridge'
  end

  my_privatekey = File.read(File.join(vagrant_dir, "vagrantkey"))
  my_publickey = File.read(File.join(vagrant_dir, "vagrantkey.pub"))

  config.vm.provision :shell, inline: <<-EOS
    mkdir -p /root/.ssh
    echo '#{my_privatekey}' > /root/.ssh/id_rsa
    chmod 600 /root/.ssh/id_rsa
    echo '#{my_publickey}' > /root/.ssh/authorized_keys
    chmod 600 /root/.ssh/authorized_keys
    echo '#{my_publickey}' > /root/.ssh/id_rsa.pub
    chmod 644 /root/.ssh/id_rsa.pub
    mkdir -p /home/vagrant/.ssh
    echo '#{my_privatekey}' >> /home/vagrant/.ssh/id_rsa
    chmod 600 /home/vagrant/.ssh/*
    echo 'Host *' > ~vagrant/.ssh/config
    echo StrictHostKeyChecking no >> ~vagrant/.ssh/config
    chown -R vagrant: /home/vagrant/.ssh
  EOS

  config.hostmanager.enabled = true
  # Make sure hostmanager picks IP address of eth1
  config.hostmanager.ip_resolver = proc do |vm, resolving_vm|
    case PROVIDER
    when "libvirt"
      if vm.name
        `python newest_dhcp_lease.py #{vm.name}`.chop
      end
    when "virtualbox"
      if vm.id
        `VBoxManage guestproperty get #{vm.id} "/VirtualBox/GuestInfo/Net/1/V4/IP"`.split()[1]
      end
    end
  end

  # The operator controls the deployment
  config.vm.define "operator", primary: true do |admin|
    admin.vm.hostname = "operator.local"
    admin.vm.provision :shell, path: PROVISION_SCRIPT, args: "operator #{MULTINODE ? 'multinode' : 'aio'} #{get_default(:kolla_path)} #{get_default(:kolla_ansible_path)}"
    admin.vm.synced_folder kolla_ansible_repo_path, get_default(:kolla_ansible_path), create:"True", type: get_default(:sync_method)
    admin.vm.synced_folder kolla_repo_path, get_default(:kolla_path), create:"True", type: get_default(:sync_method)
    admin.vm.synced_folder File.join(vagrant_dir, 'storage', 'operator'), "/data/host", create:"True", type: get_default(:sync_method)
    admin.vm.synced_folder File.join(vagrant_dir, 'storage', 'shared'), "/data/shared", create:"True", type: get_default(:sync_method)
    admin.vm.synced_folder ".", get_default(:vagrant_shared_folder), disabled: true
    admin.vm.provider PROVIDER do |vm|
      vm.memory = MULTINODE ? get_setting(:operator, :memory) : get_setting(:aio, :memory)
      vm.cpus = MULTINODE ? get_setting(:operator, :cpus) : get_setting(:aio, :cpus)
      if PROVIDER == "libvirt"
        vm.graphics_ip = GRAPHICSIP
      end
      configure_wifi_if_enabled(vm)
    end
    admin.hostmanager.aliases = "operator"
  end

  if MULTINODE
    ['compute', 'storage', 'network', 'control'].each do |node_type|
      (1..self.class.const_get("NUMBER_OF_#{node_type.upcase}_NODES")).each do |i|
        hostname = "#{node_type}0#{i}"
        config.vm.define hostname do |node|
          node.vm.hostname = "#{hostname}.local"
          node.vm.provision :shell, path: PROVISION_SCRIPT, args: "#{hostname} multinode #{get_default(:kolla_path)} #{get_default(:kolla_ansible_path)}"
          node.vm.synced_folder File.join(vagrant_dir, 'storage', node_type), "/data/host", create:"True", type: get_default(:sync_method)
          node.vm.synced_folder File.join(vagrant_dir, 'storage', 'shared'), "/data/shared", create:"True", type: get_default(:sync_method)
          node.vm.synced_folder ".", get_default(:vagrant_shared_folder), disabled: true
          node.vm.provider PROVIDER do |vm|
            vm.memory = get_setting(node_type.to_sym, :memory)
            vm.cpus = get_setting(node_type.to_sym, :cpus)
            if PROVIDER == "libvirt"
              vm.graphics_ip = GRAPHICSIP
            end
            configure_wifi_if_enabled(vm)
          end
          node.hostmanager.aliases = hostname
        end
      end
    end
  end

end