libvirtinator 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/libvirtinator/config.rb +44 -0
- data/lib/libvirtinator/examples/Capfile +3 -0
- data/lib/libvirtinator/examples/config/deploy/vm_name.rb +28 -0
- data/lib/libvirtinator/examples/config/deploy.rb +65 -0
- data/lib/libvirtinator/examples/config/sysadmins_keys.rb +20 -0
- data/lib/libvirtinator/examples/first_boot.sh.erb +8 -0
- data/lib/libvirtinator/examples/fstab.erb +8 -0
- data/lib/libvirtinator/examples/hostname.erb +1 -0
- data/lib/libvirtinator/examples/hosts.erb +11 -0
- data/lib/libvirtinator/examples/interfaces.erb +17 -0
- data/lib/libvirtinator/examples/server.xml.erb +57 -0
- data/lib/libvirtinator/examples/sudoers-sudo.erb +2 -0
- data/lib/libvirtinator/examples/vmbuilder-init.sh.erb +9 -0
- data/lib/libvirtinator/examples/vmbuilder.cfg.erb +16 -0
- data/lib/libvirtinator/image.rb +185 -0
- data/lib/libvirtinator/lv.rb +45 -0
- data/lib/libvirtinator/users.rb +55 -0
- data/lib/libvirtinator/vm.rb +411 -0
- data/lib/libvirtinator.rb +5 -0
- metadata +81 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
namespace :libvirtinator do
|
2
|
+
# TODO: fix needing to define a stage before being able to install
|
3
|
+
desc 'Write example config files'
|
4
|
+
task :install do
|
5
|
+
run_locally do
|
6
|
+
execute "mkdir", "-p", "config/deploy", "templates/libvirtinator"
|
7
|
+
{
|
8
|
+
'examples/Capfile' => 'Capfile_example',
|
9
|
+
'examples/config/deploy.rb' => 'config/deploy_example.rb',
|
10
|
+
'examples/config/sysadmins_keys.rb' => 'config/sysadmins_keys_example.rb',
|
11
|
+
'examples/config/deploy/vm_name.rb' => 'config/deploy/vm_name_example.rb',
|
12
|
+
'examples/first_boot.sh.erb' => 'templates/libvirtinator/first_boot_example.sh.erb',
|
13
|
+
'examples/fstab.erb' => 'templates/libvirtinator/fstab_example.erb',
|
14
|
+
'examples/hostname.erb' => 'templates/libvirtinator/hostname_example.erb',
|
15
|
+
'examples/hosts.erb' => 'templates/libvirtinator/hosts_example.erb',
|
16
|
+
'examples/interfaces.erb' => 'templates/libvirtinator/interfaces_example.erb',
|
17
|
+
'examples/server.xml.erb' => 'templates/libvirtinator/server_example.xml.erb',
|
18
|
+
'examples/sudoers-sudo.erb' => 'templates/libvirtinator/sudoers-sudo_example.erb',
|
19
|
+
'examples/vmbuilder-init.sh.erb' => 'templates/libvirtinator/vmbuilder-init_example.sh.erb',
|
20
|
+
'examples/vmbuilder.cfg.erb' => 'templates/libvirtinator/vmbuilder_example.cfg.erb',
|
21
|
+
}.each do |source, destination|
|
22
|
+
config = File.read(File.dirname(__FILE__) + "/#{source}")
|
23
|
+
File.open("./#{destination}", 'w') { |f| f.write(config) }
|
24
|
+
info "Wrote '#{destination}'"
|
25
|
+
end
|
26
|
+
info "Now remove the '_example' portion of their names or diff with existing files and add the needed lines."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Write an example VM config file'
|
31
|
+
task :install_vm do
|
32
|
+
run_locally do
|
33
|
+
execute "mkdir", "-p", "config/deploy"
|
34
|
+
{
|
35
|
+
'examples/config/deploy/vm_name.rb' => 'config/deploy/vm_name_example.rb',
|
36
|
+
}.each do |source, destination|
|
37
|
+
config = File.read(File.dirname(__FILE__) + "/#{source}")
|
38
|
+
File.open("./#{destination}", 'w') { |f| f.write(config) }
|
39
|
+
info "Wrote '#{destination}'"
|
40
|
+
end
|
41
|
+
info "Now remove the '_example' portion of the name or diff with existing files and add the needed lines."
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
set :host_machine_name, "my-host"
|
2
|
+
set :user, -> { ENV['USER'] } # SSH user
|
3
|
+
|
4
|
+
role :app, "#{fetch(:user)}@#{fetch(:host_machine_name)}.example.com"
|
5
|
+
|
6
|
+
set :base_image, "ubuntu-14.04-v0.0.0-docker1.3.1.qcow2"
|
7
|
+
set :node_name, -> { fetch(:stage) }
|
8
|
+
|
9
|
+
set :data_disk_enabled, true
|
10
|
+
set :data_disk_gb, "50"
|
11
|
+
set :data_disk_type, "lv" # "lv" or "qemu"
|
12
|
+
set :data_disk_mount_point, "/var/www" # inside the vm
|
13
|
+
set :data_disk_partition, "0" # set to "0" for none (normal),
|
14
|
+
# set to <partition number> for legacy logical volumes w/ partitions
|
15
|
+
set :memory_gb, "2"
|
16
|
+
set :cpus, "4"
|
17
|
+
|
18
|
+
set :ip, "123.123.123.123"
|
19
|
+
set :cidr, "123_123_123_123-27"
|
20
|
+
|
21
|
+
set :node_fqdn, -> { "#{fetch(:node_name)}.example.com" }
|
22
|
+
set :app_fqdn, "my-app.example.com"
|
23
|
+
set :hostname, "my-app"
|
24
|
+
|
25
|
+
set :usergroups, ["sysadmins"]
|
26
|
+
fetch(:usergroups).each do |usergroup|
|
27
|
+
require "./config/#{usergroup}_keys.rb"
|
28
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# config valid only for Capistrano 3.1
|
2
|
+
lock '3.2.1'
|
3
|
+
|
4
|
+
set :log_level, :info
|
5
|
+
#set :log_level, :debug
|
6
|
+
|
7
|
+
# Setup the host machiness you will use
|
8
|
+
set "my_host_data_disk_vg_path", "/dev/ubuntu-vg"
|
9
|
+
set "my_host_dns_nameservers", "8.8.8.8 8.8.4.4"
|
10
|
+
set "my_host_bridge", "br0"
|
11
|
+
set "my_host_root_partitions_path", "/RootPartitions"
|
12
|
+
|
13
|
+
set "my_other_host_data_disk_vg_path", "/dev/ubuntu-vg"
|
14
|
+
set "my_other_host_dns_nameservers", "8.8.8.8 8.8.4.4"
|
15
|
+
set "my_other_host_bridge", "br0"
|
16
|
+
set "my_other_host_root_partitions_path", "/RootPartitions"
|
17
|
+
|
18
|
+
# Setup the CIDRs you will use
|
19
|
+
set "123_123_123_123-27_network", "123.123.123.0"
|
20
|
+
set "123_123_123_123-27_gateway", "123.123.123.1"
|
21
|
+
set "123_123_123_123-27_broadcast", "123.123.123.31"
|
22
|
+
set "123_123_123_123-27_netmask", "255.255.255.224"
|
23
|
+
|
24
|
+
set "231_231_231_231-27_network", "231.231.231.0"
|
25
|
+
set "231_231_231_231-27_gateway", "231.231.231.1"
|
26
|
+
set "231_231_231_231-27_broadcast", "231.231.231.31"
|
27
|
+
set "231_231_231_231-27_netmask", "255.255.255.224"
|
28
|
+
|
29
|
+
# Global dns-search. Can be overridden by setting the same
|
30
|
+
# in a VM's settings file, (a config/deploy/<stage>.rb file.)
|
31
|
+
set :dns_search, "example.com example2.com"
|
32
|
+
|
33
|
+
# Setup vmbuilder for building a base image
|
34
|
+
set :release_name, "ubuntu-14.04-v0.0.1-docker1.3.1"
|
35
|
+
set :vmbuilder_run_command, -> {
|
36
|
+
[ "kvm", "ubuntu",
|
37
|
+
"-o",
|
38
|
+
"--debug",
|
39
|
+
"--verbose",
|
40
|
+
"--dest=/tmp/#{fetch(:release_name)}",
|
41
|
+
"--config=templates/#{fetch(:release_name)}.cfg",
|
42
|
+
"--execscript=templates/#{fetch(:release_name)}-init.sh",
|
43
|
+
"--firstboot=/tmp/first_boot.sh",
|
44
|
+
"--rootsize=15360",
|
45
|
+
"--swapsize=2048"
|
46
|
+
].join(' ')
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
## Settings that shouldn't need changed:
|
51
|
+
set :nbd_run_file, -> { "/var/lock/#{fetch(:node_name)}.nbd" }
|
52
|
+
set :nbd_lock_file, -> { "/var/lock/qemu-nbd-#{fetch(:nbd)}" }
|
53
|
+
set :dev_nbd, -> { "/dev/#{fetch(:nbd)}" }
|
54
|
+
set :dev_nbdp1, -> { "/dev/#{fetch(:nbd)}p1" }
|
55
|
+
set :dns_nameservers, -> { fetch("#{fetch(:host_machine_name)}_dns_nameservers") }
|
56
|
+
set :bridge, -> { fetch("#{fetch(:host_machine_name)}_bridge") }
|
57
|
+
set :root_partitions_path, -> { fetch("#{fetch(:host_machine_name)}_root_partitions_path") }
|
58
|
+
set :base_image_path, -> { "#{fetch(:root_partitions_path)}/#{fetch(:base_image)}" }
|
59
|
+
set :root_image_path, -> { "#{fetch(:root_partitions_path)}/#{fetch(:node_name)}-root.qcow2" }
|
60
|
+
set :mount_point, -> { "#{fetch(:root_partitions_path)}/#{fetch(:node_name)}-root.qcow2_mnt" }
|
61
|
+
set :data_disk_vg_path, -> { fetch("#{fetch(:host_machine_name)}_data_disk_vg_path") }
|
62
|
+
set :data_disk_lv_name, -> { "#{fetch(:node_name)}-data" }
|
63
|
+
set :data_disk_lv_path, -> { "#{fetch(:data_disk_vg_path)}/#{fetch(:data_disk_lv_name)}" }
|
64
|
+
set :data_disk_qemu_path, -> { "#{fetch(:root_partitions_path)}/#{fetch(:node_name)}-data.qcow2" }
|
65
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
set :sysadmins, [
|
2
|
+
{
|
3
|
+
"name" => "username",
|
4
|
+
"disabled" => false,
|
5
|
+
"groups" => ["sudo", "docker"],
|
6
|
+
"ssh_keys" => [
|
7
|
+
"ssh-rsa blahblahblah username@computer",
|
8
|
+
"ssh-rsa blahblahblahother username@computer2"
|
9
|
+
]
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"name" => "username-other",
|
13
|
+
"disabled" => false,
|
14
|
+
"groups" => ["sudo", "docker"],
|
15
|
+
"ssh_keys" => [
|
16
|
+
"ssh-rsa blahblahblah username-other@computer",
|
17
|
+
"ssh-rsa blahblahblahother username-other@computer2"
|
18
|
+
]
|
19
|
+
}
|
20
|
+
]
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# /etc/fstab: static file system information.
|
2
|
+
# <file system> <mount point> <type> <options> <dump> <pass>
|
3
|
+
proc /proc proc defaults 0 0
|
4
|
+
/dev/vda1 / ext4 defaults 0 0
|
5
|
+
/dev/vda2 swap swap defaults 0 0
|
6
|
+
<% if @data_disk_enabled %>
|
7
|
+
/dev/vdb<%= @data_disk_partition unless @data_disk_partition == "0" %> <%= @data_disk_mount_point %> ext4 defaults 0 2
|
8
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= @hostname %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
127.0.0.1 localhost
|
2
|
+
127.0.1.1 <%= @node_fqdn %> <%= @node_name %>
|
3
|
+
127.0.1.1 <%= @app_fqdn %> <%= @hostname %>
|
4
|
+
|
5
|
+
# The following lines are desirable for IPv6 capable hosts
|
6
|
+
::1 ip6-localhost ip6-loopback
|
7
|
+
fe00::0 ip6-localnet
|
8
|
+
ff00::0 ip6-mcastprefix
|
9
|
+
ff02::1 ip6-allnodes
|
10
|
+
ff02::2 ip6-allrouters
|
11
|
+
ff02::3 ip6-allhosts
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file describes the network interfaces available on your system
|
2
|
+
# and how to activate them. For more information, see interfaces(5).
|
3
|
+
|
4
|
+
# The loopback network interface
|
5
|
+
auto lo
|
6
|
+
iface lo inet loopback
|
7
|
+
|
8
|
+
# The primary network interface
|
9
|
+
auto eth0
|
10
|
+
iface eth0 inet static
|
11
|
+
network <%= @network %>
|
12
|
+
gateway <%= @gateway %>
|
13
|
+
address <%= @ip %>
|
14
|
+
broadcast <%= @broadcast %>
|
15
|
+
netmask <%= @netmask %>
|
16
|
+
dns-nameservers <%= @dns_nameservers %>
|
17
|
+
dns-search <%= @dns_search %>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<domain type='kvm'>
|
2
|
+
<name><%= @node_name %></name>
|
3
|
+
<memory><%= @memory_gb %></memory>
|
4
|
+
<currentMemory><%= @memory_gb %></currentMemory>
|
5
|
+
<vcpu><%= @cpus %></vcpu>
|
6
|
+
<os>
|
7
|
+
<type>hvm</type>
|
8
|
+
<type arch='x86_64' machine='pc-0.12'>hvm</type>
|
9
|
+
<boot dev='hd'/>
|
10
|
+
</os>
|
11
|
+
<features>
|
12
|
+
<acpi/>
|
13
|
+
</features>
|
14
|
+
<clock offset='utc'/>
|
15
|
+
<on_poweroff>destroy</on_poweroff>
|
16
|
+
<on_reboot>restart</on_reboot>
|
17
|
+
<on_crash>destroy</on_crash>
|
18
|
+
<devices>
|
19
|
+
<emulator>/usr/bin/kvm</emulator>
|
20
|
+
<disk type='file' device='disk'>
|
21
|
+
<driver name='qemu' type='qcow2'/>
|
22
|
+
<source file='<%= @root_image_path %>'/>
|
23
|
+
<target dev='vda' bus='virtio'/>
|
24
|
+
</disk>
|
25
|
+
<% if @data_disk_enabled %>
|
26
|
+
<% if @data_disk_type == "lv" %>
|
27
|
+
<disk type='file' device='disk'>
|
28
|
+
<driver name='qemu' type='raw'/>
|
29
|
+
<source file='<%= @data_disk_lv_path %>'/>
|
30
|
+
<target dev='vdb' bus='virtio'/>
|
31
|
+
</disk>
|
32
|
+
<% end %>
|
33
|
+
<% if @data_disk_type == "qemu" %>
|
34
|
+
<disk type='file' device='disk'>
|
35
|
+
<driver name='qemu' type='qcow2'/>
|
36
|
+
<source file='<%= @data_disk_qemu_path %>'/>
|
37
|
+
<target dev='vdb' bus='virtio'/>
|
38
|
+
</disk>
|
39
|
+
<% end %>
|
40
|
+
<% end %>
|
41
|
+
<interface type='bridge'>
|
42
|
+
<source bridge='<%= @bridge %>'/>
|
43
|
+
<model type='virtio'/>
|
44
|
+
</interface>
|
45
|
+
<input type='mouse' bus='ps2'/>
|
46
|
+
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1'/>
|
47
|
+
<video>
|
48
|
+
<model type='cirrus' vram='9216' heads='1'/>
|
49
|
+
</video>
|
50
|
+
<serial type='pty'>
|
51
|
+
<target port='0'/>
|
52
|
+
</serial>
|
53
|
+
<console type='pty'>
|
54
|
+
<target port='0'/>
|
55
|
+
</console>
|
56
|
+
</devices>
|
57
|
+
</domain>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
chroot $1 apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
|
4
|
+
chroot $1 sh -c "echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
|
5
|
+
chroot $1 apt-get purge -y grub
|
6
|
+
chroot $1 apt-get update -qq
|
7
|
+
chroot $1 apt-get install -y lxc-docker grub-pc
|
8
|
+
chroot $1 sed -i'' -e"s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"cgroup_enable=memory swapaccount=1\"/" /etc/default/grub
|
9
|
+
chroot $1 update-grub
|
@@ -0,0 +1,16 @@
|
|
1
|
+
[DEFAULT]
|
2
|
+
arch = amd64
|
3
|
+
tmpfs = -
|
4
|
+
user = ubuntu
|
5
|
+
name = ubuntu
|
6
|
+
execscript = /tmp/init.sh
|
7
|
+
firstboot = /tmp/first_boot.sh
|
8
|
+
|
9
|
+
[ubuntu]
|
10
|
+
mirror = http://archive.ubuntu.com/ubuntu
|
11
|
+
flavour = virtual
|
12
|
+
suite = trusty
|
13
|
+
domain = example.com
|
14
|
+
components = main,restricted,universe,multiverse
|
15
|
+
removepkg = grub
|
16
|
+
addpkg = openssh-server, unattended-upgrades, acpid, aptitude, language-pack-en-base, bwm-ng, htop, iotop, bzip2, file, unzip, zip, rar, unrar, nmap, man-db, curl, tmux, git-core, vim, locate, ipcalc, sl, nagios-plugins-basic, wget, rsync, tcpdump, mtr, apparmor, cgroup-lite, apt-transport-https, linux-image-generic, grub-pc
|
@@ -0,0 +1,185 @@
|
|
1
|
+
namespace :image do
|
2
|
+
desc "Build a base qcow2 image."
|
3
|
+
task :build_base do
|
4
|
+
on roles(:app) do
|
5
|
+
as :root do
|
6
|
+
["first_boot.sh", "vmbuilder-init.sh", "vmbuilder.cfg"].each do |file|
|
7
|
+
template = File.new(File.expand_path("templates/#{file}.erb")).read
|
8
|
+
generated_config_file = ERB.new(template).result(binding)
|
9
|
+
upload! StringIO.new(generated_config_file), "/tmp/#{file}"
|
10
|
+
execute("chown", "-R", "root:root", "/tmp/#{file}")
|
11
|
+
execute("chmod", "770", "/tmp/#{file}")
|
12
|
+
end
|
13
|
+
# rootsize & swapsize settings do not get picked up in cfg file, so set here
|
14
|
+
if test "vmbuilder", fetch(:vmbuilder_run_command)
|
15
|
+
execute "mv /tmp/#{fetch(:release_name)}/*.qcow2 /tmp/#{fetch(:release_name)}/#{fetch(:release_name)}.qcow2"
|
16
|
+
info("Build finished successfully!")
|
17
|
+
info("You probably want to run 'cp /tmp/#{fetch(:release_name)}/#{fetch(:release_name)}.qcow2 <root partitions path>'.")
|
18
|
+
info("If you ran this on a Ubuntu 14.04 or later host, you'll probabaly want to make the image compatible " +
|
19
|
+
"with older versions of qemu using a command like this: 'sudo qemu-img amend -f qcow2 -o compat=0.10 #{fetch(:release_name)}.qcow2'.")
|
20
|
+
end
|
21
|
+
execute "rm", "/tmp/first_boot.sh", "-f"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#desc "Mount qcow2 image by creating a run file holding the nbd needed."
|
27
|
+
task :mount do
|
28
|
+
on roles(:app) do
|
29
|
+
as :root do
|
30
|
+
if test "[", "-f", fetch(:nbd_run_file), "]"
|
31
|
+
unless test "[", "-f", fetch(:nbd_lock_file), "]"
|
32
|
+
unless test "mountpoint", "-q", fetch(:mount_point)
|
33
|
+
info "Removing leftover run file"
|
34
|
+
execute "rm", fetch(:nbd_run_file), "-f"
|
35
|
+
unless test "[", "-f", fetch(:nbd_run_file), "]"
|
36
|
+
Rake::Task['image:mount'].reenable
|
37
|
+
return Rake::Task['image:mount'].invoke
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
raise "nbd run file already exists. is it already connected?"
|
42
|
+
end
|
43
|
+
info "Mounting #{fetch(:root_image_path)} on #{fetch(:mount_point)}"
|
44
|
+
set :nbd_connected, false
|
45
|
+
until fetch(:nbd_connected)
|
46
|
+
Rake::Task['image:connect_to_unused_nbd'].reenable
|
47
|
+
Rake::Task['image:connect_to_unused_nbd'].invoke
|
48
|
+
end
|
49
|
+
raise "Mount point #{fetch(:mount_point)} is already mounted" if test "mountpoint", "-q", fetch(:mount_point)
|
50
|
+
execute "mkdir", "-p", fetch(:mount_point)
|
51
|
+
execute "mount", fetch(:dev_nbdp1), fetch(:mount_point)
|
52
|
+
raise "Failed to mount #{fetch(:mount_point)}" unless test "mountpoint", "-q", fetch(:mount_point)
|
53
|
+
info "Mounted #{fetch(:root_image_path)} on #{fetch(:mount_point)} using #{fetch(:dev_nbd)}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#desc "Un-mount qcow2 image"
|
59
|
+
task :umount do
|
60
|
+
on roles(:app) do
|
61
|
+
as :root do
|
62
|
+
if test "[", "-f", fetch(:nbd_run_file), "]"
|
63
|
+
info "found #{fetch(:nbd_run_file)}"
|
64
|
+
else
|
65
|
+
info "Unable to read #{fetch(:nbd_run_file)}"
|
66
|
+
end
|
67
|
+
set :nbd, capture("cat", fetch(:nbd_run_file)).chomp
|
68
|
+
unless test "mountpoint", "-q", fetch(:mount_point)
|
69
|
+
info "#{fetch(:mount_point)} is not mounted"
|
70
|
+
end
|
71
|
+
info "Unmounting root image #{fetch(:root_image_path)}"
|
72
|
+
execute "umount", fetch(:mount_point)
|
73
|
+
if test "mountpoint", "-q", fetch(:mount_point)
|
74
|
+
info "Failed to umount #{fetch(:mount_point)}"
|
75
|
+
end
|
76
|
+
Rake::Task['image:disconnect_from_nbd'].invoke
|
77
|
+
execute "rm", fetch(:mount_point), "-rf"
|
78
|
+
raise "Failed to remove #{fetch(:mount_point)}" if test "[", "-d", fetch(:mount_point), "]"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
desc "Find the base image for each root qcow2 image."
|
84
|
+
task :list_bases do
|
85
|
+
on roles(:app) do
|
86
|
+
as :root do
|
87
|
+
set :files, -> { capture("ls", "#{fetch(:root_partitions_path)}/*.qcow2" ).split }
|
88
|
+
if fetch(:files, "").empty?
|
89
|
+
fatal "Error: No qcow2 files found in #{fetch(:root_partitions_path)}"
|
90
|
+
exit
|
91
|
+
end
|
92
|
+
fetch(:files).each do |image_file|
|
93
|
+
backing_file = ""
|
94
|
+
capture("qemu-img info #{image_file}").each_line do |line|
|
95
|
+
if line =~ /backing\ file:/
|
96
|
+
backing_file = line.split[2]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
unless backing_file.empty?
|
100
|
+
info "#{backing_file} < #{image_file}"
|
101
|
+
else
|
102
|
+
info "No backing file found for #{image_file}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
task :connect_to_unused_nbd do
|
110
|
+
on roles(:app) do
|
111
|
+
as :root do
|
112
|
+
set :prelock, -> { "#{fetch(:nbd_lock_file)}.prelock" }
|
113
|
+
begin
|
114
|
+
raise "Error: #{fetch(:root_image_path)} not found!" unless test "[", "-f", fetch(:root_image_path), "]"
|
115
|
+
set :nbd, "nbd#{rand(16)}"
|
116
|
+
info "Randomly trying the #{fetch(:nbd)} network block device"
|
117
|
+
if test "[", "-f", fetch(:prelock), "]"
|
118
|
+
info "Another process is checking #{fetch(:nbd)}. Trying again..."
|
119
|
+
set :nbd_connected, false
|
120
|
+
return
|
121
|
+
else
|
122
|
+
execute "touch", fetch(:prelock)
|
123
|
+
info "Checking for qemu-nbd created lock file"
|
124
|
+
if test "[", "-f", fetch(:nbd_lock_file), "]"
|
125
|
+
info "#{fetch(:dev_nbd)} lockfile already in place - nbd device may be in use. Trying again..."
|
126
|
+
set :nbd_connected, false
|
127
|
+
return
|
128
|
+
end
|
129
|
+
if test "[", "-b", fetch(:dev_nbdp1), "]"
|
130
|
+
info "nbd device in use but no lockfile, Trying again..."
|
131
|
+
set :nbd_connected, false
|
132
|
+
return
|
133
|
+
end
|
134
|
+
info "Found unused block device"
|
135
|
+
|
136
|
+
execute "qemu-nbd", "-c", fetch(:dev_nbd), fetch(:root_image_path)
|
137
|
+
info "Waiting for block device to come online . . . "
|
138
|
+
begin
|
139
|
+
Timeout::timeout(20) do
|
140
|
+
until test "[", "-b", fetch(:dev_nbdp1), "]"
|
141
|
+
sleep 3
|
142
|
+
end
|
143
|
+
execute "echo", fetch(:nbd), ">", fetch(:nbd_run_file)
|
144
|
+
info "device online"
|
145
|
+
set :nbd_connected, true
|
146
|
+
end
|
147
|
+
rescue TimeoutError
|
148
|
+
fatal "Error: unable to create block dev #{fetch(:dev_nbd)}, trying again..."
|
149
|
+
set :nbd_connected, false
|
150
|
+
return
|
151
|
+
#raise "unable to create block device #{fetch(:dev_nbd)}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
ensure
|
155
|
+
execute "rm", fetch(:prelock), "-f"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
task :disconnect_from_nbd do
|
162
|
+
on roles(:app) do
|
163
|
+
as :root do
|
164
|
+
execute "qemu-nbd", "-d", fetch(:dev_nbd)
|
165
|
+
info "Waiting for block device to go offline . . . "
|
166
|
+
begin
|
167
|
+
Timeout::timeout(20) do
|
168
|
+
while test "[", "-b", fetch(:dev_nbdp1), "]"
|
169
|
+
print ". "
|
170
|
+
sleep 3
|
171
|
+
end
|
172
|
+
info "block device offline"
|
173
|
+
end
|
174
|
+
rescue TimeoutError
|
175
|
+
info "Error: unable to free block dev #{fetch(:dev_nbd)}"
|
176
|
+
execute "rm", fetch(:nbd_run_file), "-rf"
|
177
|
+
execute "touch", fetch(:nbd_lock_file)
|
178
|
+
exit 1
|
179
|
+
end
|
180
|
+
raise "failed to free #{fetch(:dev_nbd)}" if test "[", "-b", fetch(:dev_nbdp1), "]"
|
181
|
+
execute "rm", fetch(:nbd_run_file), "-rf"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
namespace :lv do
|
2
|
+
desc "Remove a logical volume and recreate it."
|
3
|
+
task :recreate do
|
4
|
+
on roles(:app) do
|
5
|
+
as :root do
|
6
|
+
if test "[", "-b", fetch(:data_disk_lv_path), "]"
|
7
|
+
ask :yes_no, "Are you sure you want to delete and recreate the logical volume #{fetch(:data_disk_lv_path)}?"
|
8
|
+
if fetch(:yes_no).chomp.downcase == "yes"
|
9
|
+
execute "lvremove", "--force", fetch(:data_disk_lv_path)
|
10
|
+
sleep 1
|
11
|
+
end
|
12
|
+
else
|
13
|
+
warn "Error: #{fetch(:data_disk_lv_path)} not found, yet you called lv:recreate!"
|
14
|
+
end
|
15
|
+
Rake::Task["lv:create"].invoke
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
#desc "Create a logical volume."
|
21
|
+
task :create do
|
22
|
+
on roles(:app) do
|
23
|
+
as :root do
|
24
|
+
if test "lvcreate", fetch(:data_disk_vg_path), "-L", "#{fetch(:data_disk_gb)}G", "-n", fetch(:data_disk_lv_name)
|
25
|
+
Rake::Task["lv:mkfs"].invoke
|
26
|
+
else
|
27
|
+
fatal "Error running lvcreate!"
|
28
|
+
exit
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#desc "Create an ext4 filesystem."
|
35
|
+
task :mkfs do
|
36
|
+
on roles(:app) do
|
37
|
+
as :root do
|
38
|
+
unless test "[", "-b", fetch(:data_disk_lv_path), "]"
|
39
|
+
raise "Tried to create filesystem but path does not exist!"
|
40
|
+
end
|
41
|
+
execute "mkfs.ext4", "-q", "-m", "0", fetch(:data_disk_lv_path)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
namespace :users do
|
2
|
+
|
3
|
+
task :load_settings do
|
4
|
+
set :path, ""
|
5
|
+
until File.exists?(fetch(:path)) and (! File.directory?(fetch(:path)))
|
6
|
+
ask :path, "Which private key has SSH access to the VM? Specifiy an absolute path"
|
7
|
+
end
|
8
|
+
SSHKit::Backend::Netssh.configure do |ssh|
|
9
|
+
ssh.ssh_options = {
|
10
|
+
keys: fetch(:path),
|
11
|
+
forward_agent: false,
|
12
|
+
auth_methods: %w(publickey)
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Idempotently setup unix admin users using SSH with sudo rights."
|
18
|
+
task :setup => :load_settings do
|
19
|
+
on "#{fetch(:user)}@#{fetch(:ip)}" do
|
20
|
+
as :root do
|
21
|
+
fetch(:usergroups).each do |usergroup|
|
22
|
+
usergroup = usergroup.to_sym
|
23
|
+
next if fetch(usergroup).nil? or fetch(usergroup).empty?
|
24
|
+
fetch(usergroup).each do |user|
|
25
|
+
key_file = "/home/#{user['name']}/.ssh/authorized_keys"
|
26
|
+
if user['disabled']
|
27
|
+
if test "id", "-u", user['name']
|
28
|
+
execute "bash", "-c", "\"echo", "''", ">", "#{key_file}\""
|
29
|
+
execute "passwd", "-d", user['name']
|
30
|
+
info "Disabled user #{user['name']}"
|
31
|
+
end
|
32
|
+
else
|
33
|
+
unless test "id", "-u", user['name']
|
34
|
+
exit unless test "adduser", "--disabled-password", "--gecos", "\'\'", user['name']
|
35
|
+
end
|
36
|
+
execute "usermod", "-s", "'/bin/bash'", user['name']
|
37
|
+
user['groups'].each do |group|
|
38
|
+
execute "usermod", "-a", "-G", group, user['name']
|
39
|
+
end
|
40
|
+
execute "mkdir", "-p", "/home/#{user['name']}/.ssh"
|
41
|
+
execute "chown", "#{user['name']}.", "-R", "/home/#{user['name']}"
|
42
|
+
execute "chmod", "700", "/home/#{user['name']}/.ssh"
|
43
|
+
content = StringIO.new("#{user['ssh_keys'].join("\n\n")}\n")
|
44
|
+
upload! content, "/tmp/temp_authorized_keys"
|
45
|
+
execute "mv", "/tmp/temp_authorized_keys", "/home/#{user['name']}/.ssh/authorized_keys"
|
46
|
+
execute "chown", "#{user['name']}.", "#{key_file}"
|
47
|
+
execute "chmod", "600", "#{key_file}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
info "Finished setting up users"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,411 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'timeout'
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
namespace :vm do
|
6
|
+
desc "Check the current status of a VM"
|
7
|
+
task :status do
|
8
|
+
on roles(:app) do
|
9
|
+
as :root do
|
10
|
+
if test("virsh", "list", "--all", "|", "grep", "-q", "#{fetch(:node_name)}")
|
11
|
+
if test("virsh", "list", "|", "grep", "-q", "#{fetch(:node_name)}")
|
12
|
+
info "VM #{fetch(:node_name)} exists and is running on #{host}"
|
13
|
+
else
|
14
|
+
info "VM #{fetch(:node_name)} is defined but not running on #{host}"
|
15
|
+
end
|
16
|
+
else
|
17
|
+
info "VM #{fetch(:node_name)} is undefined on #{host}"
|
18
|
+
end
|
19
|
+
if system "bash -c \"ping -c 3 -w 5 #{fetch(:ip)} &> /dev/null\""
|
20
|
+
begin
|
21
|
+
Timeout::timeout(5) do
|
22
|
+
(TCPSocket.open(fetch(:ip),22) rescue nil)
|
23
|
+
info "The IP #{fetch(:ip)} is responding to ping and SSH"
|
24
|
+
end
|
25
|
+
rescue TimeoutError
|
26
|
+
info "The IP #{fetch(:ip)} is responding to ping but not SSH"
|
27
|
+
end
|
28
|
+
else
|
29
|
+
info "The IP #{fetch(:ip)} is not responding to ping"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Start a copy-on-write Virtual Machine from a base image."
|
36
|
+
task :start do
|
37
|
+
on roles(:app) do
|
38
|
+
info "Preparing to start #{fetch(:node_name)}"
|
39
|
+
Rake::Task['vm:ensure_nbd_module'].invoke
|
40
|
+
Rake::Task['vm:ensure_root_partitions_path'].invoke
|
41
|
+
Rake::Task['vm:ensure_vm_not_running'].invoke
|
42
|
+
Rake::Task['vm:ensure_ip_no_ping'].invoke
|
43
|
+
Rake::Task['vm:ensure_vm_not_defined'].invoke
|
44
|
+
Rake::Task['vm:verify_base'].invoke
|
45
|
+
Rake::Task['vm:remove_root_image'].invoke
|
46
|
+
Rake::Task['vm:create_root_image'].invoke
|
47
|
+
begin
|
48
|
+
Rake::Task["image:mount"].invoke
|
49
|
+
Rake::Task['vm:update_root_image'].invoke
|
50
|
+
ensure
|
51
|
+
Rake::Task["image:umount"].invoke
|
52
|
+
end
|
53
|
+
Rake::Task['vm:create_data'].invoke
|
54
|
+
Rake::Task['vm:define_domain'].invoke
|
55
|
+
Rake::Task['vm:start_domain'].invoke
|
56
|
+
Rake::Task['vm:reset_known_hosts_on_host'].invoke
|
57
|
+
Rake::Task['vm:setup_agent_forwarding'].invoke
|
58
|
+
Rake::Task['vm:wait_for_ping'].invoke
|
59
|
+
Rake::Task['vm:wait_for_ssh_alive'].invoke
|
60
|
+
Rake::Task['users:setup'].invoke
|
61
|
+
info "Say, you don't say? Are we finished?"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
task :ensure_root_partitions_path do
|
66
|
+
on roles(:app) do
|
67
|
+
as :root do
|
68
|
+
dir = fetch(:root_partitions_path)
|
69
|
+
unless test "[", "-d", dir, "]"
|
70
|
+
fatal "Error: root partitions path #{dir} is not a directory!" && raise
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
task :ensure_nbd_module do
|
77
|
+
on roles(:app) do
|
78
|
+
as :root do
|
79
|
+
unless test("lsmod | grep -q nbd")
|
80
|
+
info 'Running modprobe nbd'
|
81
|
+
execute "modprobe", "nbd"
|
82
|
+
sleep 0.5
|
83
|
+
unless test("lsmod | grep -q nbd")
|
84
|
+
fatal "Error: Unable to modprobe nbd!" && raise
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
task :ensure_vm_not_running do
|
92
|
+
on roles(:app) do
|
93
|
+
as :root do
|
94
|
+
if test("virsh", "list", "|", "grep", "-q", "#{fetch(:node_name)}")
|
95
|
+
fatal "The VM #{fetch(:node_name)} is already running!" && raise
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
task :ensure_ip_no_ping do
|
102
|
+
run_locally do
|
103
|
+
info "Attempting to ping #{fetch(:ip)}"
|
104
|
+
if system "bash -c \"ping -c 3 -w 5 #{fetch(:ip)} &> /dev/null\""
|
105
|
+
fatal "The IP #{fetch(:ip)} is already pingable!"
|
106
|
+
raise
|
107
|
+
else
|
108
|
+
info "No ping returned, continuing"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
task :ensure_vm_not_defined do
|
114
|
+
on roles(:app) do
|
115
|
+
as :root do
|
116
|
+
if test("virsh", "list", "--all", "|", "grep", "-q", "#{fetch(:node_name)}")
|
117
|
+
set :yes_or_no, ""
|
118
|
+
until fetch(:yes_or_no).chomp.downcase == "yes" or fetch(:yes_or_no).chomp.downcase == "no"
|
119
|
+
ask :yes_or_no, "The VM #{fetch(:node_name)} is defined but not running! Do you want to undefine/redefine it?"
|
120
|
+
end
|
121
|
+
unless fetch(:yes_or_no).chomp.downcase == "yes"
|
122
|
+
exit
|
123
|
+
else
|
124
|
+
execute "virsh", "undefine", fetch(:node_name)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
task :verify_base do
|
132
|
+
on roles(:app) do
|
133
|
+
as :root do
|
134
|
+
unless test "[", "-f", fetch(:base_image_path), "]"
|
135
|
+
fatal "Error: cannot find the base image #{fetch(:base_image_path)}" && raise
|
136
|
+
end
|
137
|
+
raise unless test("chown", "libvirt-qemu:kvm", fetch(:base_image_path))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
task :remove_root_image do
|
143
|
+
on roles(:app) do
|
144
|
+
as :root do
|
145
|
+
# use 'cap <server> create recreate_root=true' to recreate the root image
|
146
|
+
if ENV['recreate_root'] == "true"
|
147
|
+
if test "[", "-f", root_image_path, "]"
|
148
|
+
set :yes_or_no, ""
|
149
|
+
until fetch(:yes_or_no).chomp.downcase == "yes" or fetch(:yes_or_no).chomp.downcase == "no"
|
150
|
+
ask :yes_or_no, "Are you sure you want to remove the existing #{root_image_path} file?"
|
151
|
+
end
|
152
|
+
if fetch(:yes_or_no).chomp.downcase == "yes"
|
153
|
+
info "Removing old image"
|
154
|
+
execute "rm", root_image_path
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
task :create_root_image do
|
163
|
+
on roles(:app) do
|
164
|
+
as :root do
|
165
|
+
unless test "[", "-f", fetch(:root_image_path), "]"
|
166
|
+
info "Creating new image"
|
167
|
+
execute "qemu-img", "create", "-b", fetch(:base_image_path), "-f", "qcow2", fetch(:root_image_path)
|
168
|
+
else
|
169
|
+
set :yes_or_no, ""
|
170
|
+
until fetch(:yes_or_no).chomp.downcase == "yes" or fetch(:yes_or_no).chomp.downcase == "no"
|
171
|
+
ask :yes_or_no, "#{fetch(:root_image_path)} already exists, do you want to continue to update it's configuration?"
|
172
|
+
end
|
173
|
+
if fetch(:yes_or_no).chomp.downcase == "yes"
|
174
|
+
info "Updating file on an existing image."
|
175
|
+
else
|
176
|
+
exit
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
task :update_root_image do
|
184
|
+
on roles(:app) do
|
185
|
+
as :root do
|
186
|
+
mount_point = fetch(:mount_point)
|
187
|
+
raise if mount_point.nil?
|
188
|
+
set :logs_path, -> { fetch(:internal_logs_path) }
|
189
|
+
@internal_logs_path = fetch(:logs_path)
|
190
|
+
@node_name = fetch(:node_name)
|
191
|
+
@node_fqdn = fetch(:node_fqdn)
|
192
|
+
@app_fqdn = fetch(:app_fqdn)
|
193
|
+
@hostname = fetch(:hostname)
|
194
|
+
@data_disk_enabled = fetch(:data_disk_enabled)
|
195
|
+
@data_disk_partition = fetch(:data_disk_partition)
|
196
|
+
@data_disk_mount_point = fetch(:data_disk_mount_point)
|
197
|
+
@network = fetch("#{fetch(:cidr)}_network")
|
198
|
+
@gateway = fetch("#{fetch(:cidr)}_gateway")
|
199
|
+
@ip = fetch(:ip)
|
200
|
+
@broadcast = fetch("#{fetch(:cidr)}_broadcast")
|
201
|
+
@netmask = fetch("#{fetch(:cidr)}_netmask")
|
202
|
+
@dns_nameservers = fetch(:dns_nameservers)
|
203
|
+
@dns_search = fetch(:dns_search)
|
204
|
+
{
|
205
|
+
"sudoers-sudo" => "#{mount_point}/etc/sudoers.d/sudo",
|
206
|
+
"hosts" => "#{mount_point}/etc/hosts",
|
207
|
+
"hostname" => "#{mount_point}/etc/hostname",
|
208
|
+
"fstab" => "#{mount_point}/etc/fstab",
|
209
|
+
"interfaces" => "#{mount_point}/etc/network/interfaces",
|
210
|
+
}.each do |file, path|
|
211
|
+
template = File.new(File.expand_path("./templates/libvirtinator/#{file}.erb")).read
|
212
|
+
generated_config_file = ERB.new(template).result(binding)
|
213
|
+
upload! StringIO.new(generated_config_file), "/tmp/#{file}.file"
|
214
|
+
execute("mv", "/tmp/#{file}.file", path)
|
215
|
+
execute("chown", "root:root", path)
|
216
|
+
end
|
217
|
+
execute "sed", "-i\"\"", "\"/PermitRootLogin/c\\PermitRootLogin no\"",
|
218
|
+
"#{mount_point}/etc/ssh/sshd_config"
|
219
|
+
execute "chmod", "440", "#{mount_point}/etc/sudoers.d/*"
|
220
|
+
execute "echo", "-e", "\"\n#includedir /etc/sudoers.d\n\"", ">>",
|
221
|
+
"#{mount_point}/etc/sudoers"
|
222
|
+
user = fetch(:user)
|
223
|
+
begin
|
224
|
+
execute "bash", "-c", "\"for", "m", "in", "'sys'", "'dev'", "'proc';",
|
225
|
+
"do", "mount", "/$m", "#{mount_point}/$m", "-o", "bind;", "done\""
|
226
|
+
execute "chroot", mount_point, "/bin/bash", "-c",
|
227
|
+
"\"if", "!", "id", user, "&>", "/dev/null;", "then",
|
228
|
+
"useradd", "--user-group", "--shell",
|
229
|
+
"/bin/bash", "--create-home", "#{user};", "fi\""
|
230
|
+
execute "chroot", mount_point, "/bin/bash", "-c",
|
231
|
+
"\"usermod", "-a", "-G", "sudo", "#{user}\""
|
232
|
+
execute "mkdir", "-p", "#{mount_point}/home/#{user}/.ssh"
|
233
|
+
execute "chroot", mount_point, "/bin/bash", "-c",
|
234
|
+
"\"chown", "#{user}:#{user}", "/home/#{user}", "/home/#{user}/.ssh\""
|
235
|
+
execute "chmod", "700", "#{mount_point}/home/#{user}/.ssh"
|
236
|
+
set :path, ""
|
237
|
+
until File.exists? fetch(:path) and ! File.directory? fetch(:path)
|
238
|
+
ask :path, "Which public key should we install in #{user}'s authorized_keys file? Specifiy an absolute path"
|
239
|
+
end
|
240
|
+
upload! File.open(fetch(:path)), "/tmp/pubkeys"
|
241
|
+
execute "mv", "/tmp/pubkeys", "#{mount_point}/home/#{user}/.ssh/authorized_keys"
|
242
|
+
execute "chroot", mount_point, "/bin/bash", "-c",
|
243
|
+
"\"chown", "#{user}:#{user}", "/home/#{user}/.ssh/authorized_keys\""
|
244
|
+
execute "chmod", "600", "#{mount_point}/home/#{user}/.ssh/authorized_keys"
|
245
|
+
execute "mkdir", "-p", "#{mount_point}#{fetch(:data_disk_mount_point)}" if fetch(:data_disk_enabled)
|
246
|
+
ensure
|
247
|
+
execute "bash", "-c", "\"for", "m", "in", "'sys'", "'dev'", "'proc';",
|
248
|
+
"do", "umount", "#{mount_point}/$m;", "done\""
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
task :create_data do
|
255
|
+
on roles(:app) do
|
256
|
+
as 'root' do
|
257
|
+
unless fetch(:data_disk_enabled)
|
258
|
+
info "Not using a separate data disk."
|
259
|
+
break
|
260
|
+
end
|
261
|
+
if fetch(:data_disk_type) == "qemu"
|
262
|
+
if ! test("[", "-f", fetch(:data_disk_qemu_path), "]") or ENV['recreate_data'] == "true"
|
263
|
+
execute "guestfish", "--new", "disk:#{fetch(:data_disk_gb)}G << _EOF_
|
264
|
+
mkfs ext4 /dev/vda
|
265
|
+
_EOF_"
|
266
|
+
execute "qemu-img", "convert", "-O", "qcow2", "test1.img", "test1.qcow2"
|
267
|
+
execute "rm", "test1.img"
|
268
|
+
execute "mv", "test1.qcow2", fetch(:data_disk_qemu_path)
|
269
|
+
end
|
270
|
+
elsif fetch(:data_disk_type) == "lv"
|
271
|
+
if ENV['recreate_data'] == "true"
|
272
|
+
if test "[", "-b", fetch(:data_disk_lv_path), "]"
|
273
|
+
Rake::Task['lv:recreate'].invoke
|
274
|
+
else
|
275
|
+
Rake::Task['lv:create'].invoke
|
276
|
+
end
|
277
|
+
else
|
278
|
+
if test "[", "-b", fetch(:data_disk_lv_path), "]"
|
279
|
+
info "Found and using existing logical volume #{fetch(:data_disk_lv_path)}"
|
280
|
+
else
|
281
|
+
Rake::Task['lv:create'].invoke
|
282
|
+
end
|
283
|
+
end
|
284
|
+
else
|
285
|
+
fatal "No recognized disk type (lv, qemu), yet size is greater than zero!"
|
286
|
+
fatal "Fixed this by adding a recognized disk type (lv, qemu) to your config."
|
287
|
+
raise
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
task :define_domain do
|
294
|
+
on roles(:app) do
|
295
|
+
as 'root' do
|
296
|
+
# instance variables needed for ERB
|
297
|
+
@node_name = fetch(:node_name)
|
298
|
+
@memory_gb = fetch(:memory_gb).to_i * 1024 * 1024
|
299
|
+
@cpus = fetch(:cpus)
|
300
|
+
@root_image_path = fetch(:root_image_path)
|
301
|
+
@data_disk_enabled = fetch(:data_disk_enabled)
|
302
|
+
@data_disk_type = fetch(:data_disk_type)
|
303
|
+
@data_disk_lv_path = fetch(:data_disk_lv_path)
|
304
|
+
@data_disk_qemu_path = fetch(:data_disk_qemu_path)
|
305
|
+
@bridge = fetch(:bridge)
|
306
|
+
template = File.new(File.expand_path("templates/libvirtinator/server.xml.erb")).read
|
307
|
+
generated_config_file = ERB.new(template).result(binding)
|
308
|
+
upload! StringIO.new(generated_config_file), "/tmp/server.xml"
|
309
|
+
execute "virsh", "define", "/tmp/server.xml"
|
310
|
+
execute "rm", "/tmp/server.xml", "-rf"
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
task :start_domain do
|
316
|
+
on roles(:app) do
|
317
|
+
as 'root' do
|
318
|
+
execute "virsh", "start", "#{fetch(:node_name)}"
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# Keep this to aid with users setup
|
324
|
+
task :reset_known_hosts_on_host do
|
325
|
+
run_locally do
|
326
|
+
user = if ENV['SUDO_USER']; ENV['SUDO_USER']; else; ENV['USER']; end
|
327
|
+
execute "sudo", "-u", user, "ssh-keygen", "-R", "#{fetch(:node_name)}"
|
328
|
+
execute "sudo", "-u", user, "ssh-keygen", "-R", "#{fetch(:node_fqdn)}"
|
329
|
+
execute "sudo", "-u", user, "ssh-keygen", "-R", "#{fetch(:hostname)}"
|
330
|
+
execute "sudo", "-u", user, "ssh-keygen", "-R", "#{fetch(:app_fqdn)}"
|
331
|
+
execute "sudo", "-u", user, "ssh-keygen", "-R", "#{fetch(:ip)}"
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
task :wait_for_ping do
|
336
|
+
run_locally do
|
337
|
+
info "Waiting for VM to respond to ping.."
|
338
|
+
begin
|
339
|
+
Timeout::timeout(30) do
|
340
|
+
until system "bash -c \"ping -c 3 -w 5 #{fetch(:ip)} &> /dev/null\"" do
|
341
|
+
print ' ...'
|
342
|
+
end
|
343
|
+
info "Ping alive!"
|
344
|
+
end
|
345
|
+
rescue Timeout::Error
|
346
|
+
puts
|
347
|
+
set :yes_or_no, ""
|
348
|
+
until fetch(:yes_or_no).chomp.downcase == "yes" or fetch(:yes_or_no).chomp.downcase == "no"
|
349
|
+
ask :yes_or_no, "Networking on the VM has not come up in 30 seconds, would you like to wait another 30?"
|
350
|
+
end
|
351
|
+
if fetch(:yes_or_no).chomp.downcase == "yes"
|
352
|
+
Rake::Task['vm:wait_for_ping'].reenable
|
353
|
+
return Rake::Task['vm:wait_for_ping'].invoke
|
354
|
+
else
|
355
|
+
warn "Exiting.."
|
356
|
+
exit
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
task :setup_agent_forwarding do
|
363
|
+
run_locally do
|
364
|
+
lines = <<-eos
|
365
|
+
\nHost #{fetch(:node_fqdn)}
|
366
|
+
ForwardAgent yes
|
367
|
+
Host #{fetch(:hostname)}
|
368
|
+
ForwardAgent yes
|
369
|
+
Host #{fetch(:app_fqdn)}
|
370
|
+
ForwardAgent yes
|
371
|
+
Host #{fetch(:ip)}
|
372
|
+
ForwardAgent yes
|
373
|
+
Host #{fetch(:node_name)}
|
374
|
+
ForwardAgent yes\n
|
375
|
+
eos
|
376
|
+
{ENV['USER'] => "/home/#{ENV['USER']}/.ssh"}.each do |user, dir|
|
377
|
+
if File.directory?(dir)
|
378
|
+
unless File.exists?("#{dir}/config")
|
379
|
+
execute "sudo", "-u", "#{user}", "touch", "#{dir}/config"
|
380
|
+
execute "chmod", "600", "#{dir}/config"
|
381
|
+
end
|
382
|
+
execute "echo", "-e", "\"#{lines}\"", ">>", "#{dir}/config"
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
task :wait_for_ssh_alive do
|
389
|
+
run_locally do
|
390
|
+
info "Waiting for VM SSH alive.."
|
391
|
+
begin
|
392
|
+
Timeout::timeout(30) do
|
393
|
+
(print "..."; sleep 3) until (TCPSocket.open(fetch(:ip),22) rescue nil)
|
394
|
+
end
|
395
|
+
rescue TimeoutError
|
396
|
+
set :yes_or_no, ""
|
397
|
+
until fetch(:yes_or_no).chomp.downcase == "yes" or fetch(:yes_or_no).chomp.downcase == "no"
|
398
|
+
ask :yes_or_no, "SSH on the VM has not come up in 30 seconds, would you like to wait another 30?"
|
399
|
+
end
|
400
|
+
if fetch(:yes_or_no).chomp.downcase == "yes"
|
401
|
+
Rake::Task['vm:wait_for_ssh_alive'].reenable
|
402
|
+
return Rake::Task['vm:wait_for_ssh_alive'].invoke
|
403
|
+
else
|
404
|
+
warn "Exiting.."
|
405
|
+
exit
|
406
|
+
end
|
407
|
+
end
|
408
|
+
info "SSH alive!"
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: libvirtinator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- david amick
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-11-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: capistrano
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.1
|
30
|
+
description: An Opinionated libvirt VM Deployment gem
|
31
|
+
email: davidamick@ctisolutionsinc.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- lib/libvirtinator.rb
|
37
|
+
- lib/libvirtinator/config.rb
|
38
|
+
- lib/libvirtinator/vm.rb
|
39
|
+
- lib/libvirtinator/users.rb
|
40
|
+
- lib/libvirtinator/image.rb
|
41
|
+
- lib/libvirtinator/lv.rb
|
42
|
+
- lib/libvirtinator/examples/Capfile
|
43
|
+
- lib/libvirtinator/examples/config/deploy.rb
|
44
|
+
- lib/libvirtinator/examples/config/deploy/vm_name.rb
|
45
|
+
- lib/libvirtinator/examples/config/sysadmins_keys.rb
|
46
|
+
- lib/libvirtinator/examples/first_boot.sh.erb
|
47
|
+
- lib/libvirtinator/examples/fstab.erb
|
48
|
+
- lib/libvirtinator/examples/hostname.erb
|
49
|
+
- lib/libvirtinator/examples/hosts.erb
|
50
|
+
- lib/libvirtinator/examples/interfaces.erb
|
51
|
+
- lib/libvirtinator/examples/server.xml.erb
|
52
|
+
- lib/libvirtinator/examples/sudoers-sudo.erb
|
53
|
+
- lib/libvirtinator/examples/vmbuilder-init.sh.erb
|
54
|
+
- lib/libvirtinator/examples/vmbuilder.cfg.erb
|
55
|
+
homepage: https://github.com/snarlysodboxer/libvirtinator
|
56
|
+
licenses:
|
57
|
+
- GNU
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 1.9.3
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements:
|
75
|
+
- Docker ~1.3.1
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.8.23.2
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Deploy libvirt VMs
|
81
|
+
test_files: []
|