Improve/fix idempotence in xfs script.
[obnox/vagrant/vagrant-gluster-samba-cluster.git] / Vagrantfile
1 # -*- mode: ruby -*-
2 # vi: ft=ruby:et:ts=2:sts=2:sw=2
3
4 VAGRANTFILE_API_VERSION = 2
5
6
7 require 'yaml'
8
9 #
10 # Defaults for Configuration data.
11 # Will be overridden from the settings file
12 # and (possibly later) from commandline parameters.
13 #
14
15 net_default = {
16   :type   => 'veth',
17   :flags  => 'up',
18   :hwaddr => '',
19   :name   => '',
20   :ipv4   => '',
21   :ipv6   => '',
22 }
23
24 network_opts = [ :type, :link, :flags, :hwaddr, :name, :ipv4, :ipv6 ]
25
26 libvirt_network_parms = {
27   :hwaddr => :mac,
28   :ipv4   => :ip,
29   :ipv6   => '',
30   :link   => '',
31   :flags  => '',
32   :type   => '',
33 }
34
35 defaults = {
36   :provider => {
37     :libvirt => {
38       :prefix => 'vagrant',
39     },
40   },
41 }
42
43
44 vms = [
45   {
46     #:hostname => 'gluno1',
47     :hostname => 'node1',
48     #:box => 'local-fedora-rawhide-64',
49     #:box => 'purpleidea-fedora-21',
50     #:box => 'local-fedora-21.2',
51     :provider => {
52       :lxc => {
53         :container_name => 'gluno1',
54         #:container_name => 'node1',
55       },
56       :libvirt => {
57         :box => 'local-fedora-21.2',
58         :prefix => 'gluster',
59       }, 
60     },
61     :internal_if => 'virbr1',
62     :networks => [
63       {
64         :link => 'virbr1',
65         :ipv4 => '172.20.10.30',
66       },
67       #{
68       #  :link => 'virbr2',
69       #  #:ipv4 => '10.111.222.201',
70       #},
71     ],
72   },
73 ]
74
75 #
76 # Load the config, if it exists,
77 # possibly override with commandline args,
78 # (currently none supported yet)
79 # and then store the config.
80 #
81
82 projectdir = File.expand_path File.dirname(__FILE__)
83 f = File.join(projectdir, 'vagrant.yaml')
84 if File.exists?(f)
85   settings = YAML::load_file f
86
87   if settings[:vms].is_a?(Array)
88     vms = settings[:vms]
89   end
90   puts "Loaded settings from #{f}."
91 end
92
93 # TODO(?): ARGV-processing
94
95 settings = {
96   :vms  => vms,
97 }
98
99 File.open(f, 'w') do |file|
100   file.write settings.to_yaml
101 end
102 puts "Wrote settings to #{f}."
103
104
105 # apply defaults:
106
107 vms.each do |vm|
108   defaults.keys.each do |cat|
109     next if not vm.has_key?(cat)
110     defaults[cat].keys.each do |subcat|
111       next if not vm[cat].has_key?(subcat)
112       defaults[cat][subcat].keys.each do |key|
113         if not vm[cat][subcat].has_key?(key)
114           vm[cat][subcat][key] = defaults[cat][subcat][key]
115         end
116       end
117     end
118   end
119
120   #if not vm[:provider][:libvirt].has_key?(:prefix)
121   #  vm[:provider][:libvirt][:prefix] = default_libvirt_prefix
122   #end
123
124   vm[:networks].each do |net|
125     net_default.keys.each do |key|
126       if not net.has_key?(key)
127         net[key] = net_default[key]
128       end
129     end
130   end
131 end
132
133
134 # compose the list of cluster internal ips
135 #
136 cluster_internal_ips = vms.map do |vm|
137   net = nil
138   vm[:networks].each do |n|
139     if n[:link] == vm[:internal_if]
140       net = n
141       break
142     end
143   end
144   if net != nil
145     net[:ipv4]
146   end
147 end
148
149 #print "internal ips: "
150 #print cluster_internal_ips
151 #print "\n"
152
153 #PROVISION_SCRIPT = <<SCRIPT
154 #yum -y install make samba
155 #SCRIPT
156
157 NET_FIX_ALWAYS_SCRIPT = <<SCRIPT
158 set -e
159 # eth1 is not brought up automatically
160 # by 'vagrant up' of the existing vm
161 # because eth1 is not up, glusterd can
162 # not be started and gluster volumes can
163 # not be mountd. fix it all up here until
164 # we have a correctly working environment
165 ifup eth1
166 MOUNTPT=/gluster/gv0
167 grep -q -s "${MOUNTPT}" /etc/fstab && {
168   # already provisioned...
169   systemctl restart glusterd
170   mount ${MOUNTPT}
171 }
172 true
173 SCRIPT
174
175 NET_FIX_INITIAL_SCRIPT = <<SCRIPT
176 set -e
177 # Fix dhclient running on private network IF
178 ifdown eth1
179 systemctl restart NetworkManager
180 ifup eth1
181 SCRIPT
182
183 INSTALL_SCRIPT = <<SCRIPT
184 set -e
185 yum -y install xfsprogs
186 yum -y install glusterfs{,-server,-fuse,-geo-replication}
187 yum -y install ctdb samba
188 SCRIPT
189
190 XFS_SCRIPT = <<SCRIPT
191 set -e
192
193 DEVICE=$1
194 PARTDEV=${DEVICE}1
195 DISKDEV="/dev/${DEVICE}"
196 DISKPARTDEV="/dev/${PARTDEV}"
197 ##MOUNTP=$2
198 MOUNTP=/export/${PARTDEV}
199 BRICKD=${MOUNTP}/brick
200
201 BACKUP_SUFFIX=".orig.$(date +%Y%m%d-%H%M%S)"
202
203 parted -s ${DISKDEV} print && {
204   echo "Labe exists on ${DISKDEV}."
205 } || {
206   echo "Creating label on ${DISKDEV}."
207   parted -s ${DISKDEV} mklabel msdos
208 }
209
210 parted -s ${DISKDEV} print 1 && {
211   echo "Partition ${DISKPARTDEV} exists."
212 } || {
213   echo "Creating partition ${DISKPARTDEV}."
214   parted -s ${DISKDEV} mkpart primary 1 100%
215 }
216
217 blkid -s TYPE ${DISKPARTDEV} | grep -q -s 'TYPE="xfs"' && {
218   echo "Partition ${DISKPARTDEV} contains xfs file system."
219 } || {
220   echo "Creating xfs filesystem on ${DISKPARTDEV}."
221   mkfs.xfs -f ${DISKPARTDEV}
222 }
223
224 mkdir -p ${MOUNTP}
225
226 FILE=/etc/fstab
227
228 grep -q -s ${DISKPARTDEV} ${FILE} && {
229   echo "Mount entry for ${DISKPARTDEV} is present in ${FILE}."
230 } || {
231   echo "Creating mount entry for ${DISKPARTDEV} in ${FILE}."
232   test -f ${FILE} || touch ${FILE}
233   cp -f -a ${FILE} ${FILE}${BACKUP_SUFFIX}
234   cat <<EOF >> ${FILE}
235 ${DISKPARTDEV} ${MOUNTP} xfs defaults 0 0
236 EOF
237 }
238
239 mount | grep ${MOUNTP} && {
240   echo "${MOUNTP} is already mounted."
241 } || {
242   echo "Mounting ${MOUNTP}."
243   mount ${MOUNTP}
244 }
245
246 mkdir -p ${BRICKD}
247 SCRIPT
248
249 GLUSTER_START_SCRIPT = <<SCRIPT
250 set -e
251 systemctl start glusterd.service
252 SCRIPT
253
254 #GLUSTER_PROBE_SCRIPT = <<SCRIPT
255 #set -e
256 #
257 #PEER_IP=$1
258 #
259 #gluster peer probe ${PEER_IP}
260 #SCRIPT
261
262 GLUSTER_PROBE_SCRIPT = <<SCRIPT
263 set -e
264
265 PEER_IPS="$@"
266
267 for PEER_IP in ${PEER_IPS}
268 do
269   # try for some time to reach the other node:
270   for COUNT in $(seq 1 12)
271   do
272     gluster peer probe ${PEER_IP} && break
273     sleep 1
274   done
275 done
276 SCRIPT
277
278 GLUSTER_CREATEVOL_SCRIPT = <<SCRIPT
279 set -e
280 VOLNAME=$1
281 shift
282 REP=$1
283 shift
284
285 echo "gluster volume create $VOLNAME rep $REP transport tcp $@"
286 gluster volume create $VOLNAME rep $REP transport tcp $@
287
288 gluster volume start $VOLNAME
289 SCRIPT
290
291 GLUSTER_MOUNT_SCRIPT = <<SCRIPT
292 set -e
293 VOLNAME=$1
294 shift
295 MOUNTPT=$1
296 shift
297
298 MOUNTDEV="127.0.0.1:/${VOLNAME}"
299
300 mkdir -p ${MOUNTPT}
301
302 #mount -t glusterfs ${MOUNTDEV} ${MOUNTPT}
303
304 BACKUP_SUFFIX=".orig.$(date +%Y%m%d-%H%M%S)"
305
306 FILE=/etc/fstab
307
308 grep -q -s "${MOUNTPT}" ${FILE} || {
309   test -f ${FILE} || touch ${FILE}
310   cp -f -a ${FILE} ${FILE}${BACKUP_SUFFIX}
311
312   cat <<EOF >> ${FILE}
313 ${MOUNTDEV} ${MOUNTPT} glusterfs defaults,selinux 0 0
314 EOF
315 }
316
317 mount ${MOUNTPT}
318
319 SCRIPT
320
321
322 CTDB_STOP_SCRIPT = <<SCRIPT
323 set -e
324 systemctl stop ctdb.service
325 SCRIPT
326
327 CTDB_CREATE_NODES_SCRIPT = <<SCRIPT
328 set -e
329
330 BACKUP_SUFFIX=".orig.$(date +%Y%m%d-%H%M%S)"
331
332 NODES_IPS="$@"
333
334 FILE=/etc/ctdb/nodes
335 test -f ${FILE} || touch ${FILE}
336 cp -f -a ${FILE} ${FILE}${BACKUP_SUFFIX}
337
338 echo -n > ${FILE}
339 for IP in ${NODES_IPS}
340 do
341   echo "$IP" >> ${FILE}
342 done
343 SCRIPT
344
345 CTDB_CREATE_PUBADDRS_SCRIPT = <<SCRIPT
346 set -e
347
348 BACKUP_SUFFIX=".orig.$(date +%Y%m%d-%H%M%S)"
349
350 PUB_IPS="$@"
351
352 FILE=/etc/ctdb/public_addresses
353 test -f ${FILE} || touch ${FILE}
354 cp -f -a ${FILE} ${FILE}${BACKUP_SUFFIX}
355
356 echo -n > ${FILE}
357 for IP in ${PUB_IPS}
358 do
359   echo ${IP} >> ${FILE}
360 done
361 SCRIPT
362
363 CTDB_CREATE_CONF_SCRIPT = <<SCRIPT
364 set -e
365
366 BACKUP_SUFFIX=".orig.$(date +%Y%m%d-%H%M%S)"
367
368 RECLOCKDIR=/gluster/gv0/ctdb
369 mkdir -p ${RECLOCKDIR}
370 RECLOCKFILE=${RECLOCKDIR}/reclock
371
372 PUBLIC_ADDRESSES_FILE=/etc/ctdb/public_addresses
373 NODES_FILE=/etc/ctdb/nodes
374
375 FILE=/etc/sysconfig/ctdb
376 test -f ${FILE} || touch ${FILE}
377 cp -f -a ${FILE} ${FILE}${BACKUP_SUFFIX}
378
379 echo -n > ${FILE}
380 cat <<EOF >> ${FILE}
381 CTDB_NODES=${NODES_FILE}
382 CTDB_PUBLIC_ADDRESSES=${PUBLIC_ADDRESSES_FILE}
383 CTDB_RECOVERY_LOCK=${RECLOCKFILE}
384 CTDB_MANAGES_SAMBA="yes"
385 CTDB_SAMBA_SKIP_SHARE_CKECK="yes"
386 #CTDB_MANAGES_WINBIND="yes"
387 EOF
388 SCRIPT
389
390 SAMBA_CREATE_CONF_SCRIPT = <<SCRIPT
391 set -e
392
393 BACKUP_SUFFIX=".orig.$(date +%Y%m%d-%H%M%S)"
394
395 GLUSTER_VOL=$1
396
397 GLUSTER_VOL_MOUNT=$2
398
399 mkdir -p ${GLUSTER_VOL_MOUNT}/share1
400 chmod -R 0777 ${GLUSTER_VOL_MOUNT}/share1
401
402 mkdir -p ${GLUSTER_VOL_MOUNT}/share2
403 chmod -R 0777 ${GLUSTER_VOL_MOUNT}/share2
404
405 FILE=/etc/samba/smb.conf
406 test -f ${FILE} || touch ${FILE}
407 cp -f -a ${FILE} ${FILE}${BACKUP_SUFFIX}
408
409 echo -n > ${FILE}
410 cat <<EOF >> ${FILE}
411 [global]
412     netbios name = sambacluster
413     workgroup = vagrant
414     security = user
415
416     clustering = yes
417     #include = registry
418
419 [share1]
420     path = /share1
421     vfs objects = acl_xattr glusterfs
422     glusterfs:volume = ${GLUSTER_VOL}
423     kernel share modes = no
424     read only = no
425
426 [share2]
427     path = ${GLUSTER_VOL_MOUNT}/share2
428     vfs objects = acl_xattr
429     read only = no
430 EOF
431 SCRIPT
432
433 CTDB_START_SCRIPT = <<SCRIPT
434 set -e
435 systemctl start ctdb.service
436 SCRIPT
437 #
438 # The vagrant machine definitions
439 #
440
441 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
442
443   if Vagrant.has_plugin?("vagrant-cachier")
444     config.cache.scope = :box
445   end
446
447   vms.each do |machine|
448     config.vm.define machine[:hostname] do |node|
449       node.vm.box = machine[:provider][:libvirt][:box]
450       node.vm.hostname = machine[:hostname]
451
452       node.vm.provider :libvirt do |libvirt|
453         libvirt.default_prefix = machine[:provider][:libvirt][:prefix]
454         libvirt.memory = 1024
455         libvirt.storage :file, :size => '64M', :device => 'vdb'
456         libvirt.storage :file, :size => '10G', :device => 'vdc'
457
458         machine[:networks].each do |net|
459           if not net[:ipv4] == ''
460             node.vm.network :private_network, :ip => net[:ipv4]
461           end
462         end
463       end
464
465
466       # There is some problem with the fedora base box:
467       # Upon first boot, ifdown eth1 fails and the dhclient
468       # keep being active. Simply bringing down and up again
469       # the interface is not sufficient. We need to restart
470       # NetworkManager in order to teach it to not feel
471       # responsible for the interface any more.
472       node.vm.provision "net_fix_initial", type: "shell" do |s|
473         s.inline = NET_FIX_INITIAL_SCRIPT
474       end
475
476       node.vm.provision "install", type: "shell" do |s|
477         s.inline = INSTALL_SCRIPT
478       end
479
480       # There is some problem with the fedora base box:
481       # We need to up the interface on reboots.
482       # It does not come up automatically.
483       node.vm.provision "net_fix_always", type: "shell", run: "always" do |s|
484         s.inline = NET_FIX_ALWAYS_SCRIPT
485       end
486
487       # multiple privisioners with same name possible?
488       node.vm.provision "xfs", type: "shell" do |s|
489         s.inline = XFS_SCRIPT
490         #s.args = [ "vdb", "/export/gluster/brick1" ]
491         s.args = [ "vdb" ]
492       end
493
494       node.vm.provision "xfs", type: "shell" do |s|
495         s.inline = XFS_SCRIPT
496         #s.args = [ "vdc" , "/export/gluster/brick2" ]
497         s.args = [ "vdc" ]
498       end
499
500       node.vm.provision "gluster_start", type: "shell" do |s|
501         s.inline = GLUSTER_START_SCRIPT
502       end
503
504       node.vm.provision "gluster_probe", type: "shell" do |s|
505         s.inline = GLUSTER_PROBE_SCRIPT
506         s.args = cluster_internal_ips
507       end
508
509       node.vm.provision "gluster_createvol", type: "shell" do |s|
510         mount_points = cluster_internal_ips.map do |ip|
511           "#{ip}:/export/vdb1/brick"
512         end
513         s.inline = GLUSTER_CREATEVOL_SCRIPT
514         s.args = [ "gv0", "3" ] + mount_points
515       end
516
517       node.vm.provision "gluster_mount", type: "shell" do |s|
518         s.inline = GLUSTER_MOUNT_SCRIPT
519         s.args = [ "gv0", "/gluster/gv0" ]
520       end
521
522       node.vm.provision "gluster_createvol", type: "shell" do |s|
523         mount_points = cluster_internal_ips.map do |ip|
524           "#{ip}:/export/vdc1/brick"
525         end
526         s.inline = GLUSTER_CREATEVOL_SCRIPT
527         s.args = [ "gv1", "3" ] + mount_points
528       end
529
530       node.vm.provision "gluster_mount", type: "shell" do |s|
531         s.inline = GLUSTER_MOUNT_SCRIPT
532         s.args = [ "gv1", "/gluster/gv1" ]
533       end
534
535       #
536       # ctdb / samba config
537       #
538
539       node.vm.provision "ctdb_stop", type: "shell" do |s|
540         s.inline = CTDB_STOP_SCRIPT
541       end
542
543       node.vm.provision "ctdb_create_nodes", type: "shell" do |s|
544         s.inline = CTDB_CREATE_NODES_SCRIPT
545         s.args = cluster_internal_ips
546       end
547
548       #node.vm.provision "ctdb_create_pubaddrs", type: "shell" do |s|
549       #  s.inline = CTDB_CREATE_PUBADDRS_SCRIPT
550       #  s.arg =
551       #end
552
553       node.vm.provision "ctdb_create_conf", type: "shell" do |s|
554         s.inline = CTDB_CREATE_CONF_SCRIPT
555       end
556
557       node.vm.provision "samba_create_conf", type: "shell" do |s|
558         s.inline = SAMBA_CREATE_CONF_SCRIPT
559         s.args = [ "gv1", "/gluster/gv1" ]
560       end
561
562       node.vm.provision "ctdb_start", type: "shell" do |s|
563         s.inline = CTDB_START_SCRIPT
564       end
565
566     end
567   end
568
569 end