pauper 0.1.17 → 0.2.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.
- checksums.yaml +4 -4
- data/{README → README.md} +0 -0
- data/Rakefile +9 -0
- data/bin/pauper +173 -103
- data/lib/dhcpd.rb +0 -4
- data/lib/fusion.rb +112 -0
- data/lib/libvirt.rb +4 -4
- data/lib/lxc.rb +4 -4
- data/lib/pauper.rb +177 -17
- data/lib/pauper/version.rb +3 -0
- data/test/pauper_test.rb +7 -0
- data/test/test_helper.rb +5 -0
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94d280ad4009853e8492e658aaea2a837ec85942
|
4
|
+
data.tar.gz: f7d798e8947f7bd3bd5b6815b935d3e7e71564d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 956b22f89d47919396c52c5458cab8af7017da569be4460d6974d90771fb95c7dda58c0b737a1b8e5a4b40000deb599c52a34c5600461f407acc895d03a091b1
|
7
|
+
data.tar.gz: 34de6a41b2922bc528593b86e207532f42869dfc43facbad61f1db6f449876305c19d3b7c715c0370aa349ab1624d323ec30bbbe86da912bc75f3cdd251bae82
|
data/{README → README.md}
RENAMED
File without changes
|
data/Rakefile
ADDED
data/bin/pauper
CHANGED
@@ -3,148 +3,218 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'thor'
|
5
5
|
require 'pauper'
|
6
|
+
require 'fusion'
|
7
|
+
|
8
|
+
# Check for new versions on startup
|
9
|
+
SKIP_VERSION_CHECK_FLAG = '--skip-version-check'
|
10
|
+
unless ARGV.include?(SKIP_VERSION_CHECK_FLAG)
|
11
|
+
current_version = Gem.loaded_specs['pauper'].version
|
12
|
+
latest_version = Gem.latest_version_for('pauper')
|
13
|
+
if current_version < latest_version
|
14
|
+
puts "It's your lucky day! There's a new version of Pauper available. You're on #{current_version}. Latest is #{latest_version}."
|
15
|
+
puts "You can skip this check with the #{SKIP_VERSION_CHECK_FLAG} flag, if you really must."
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
end
|
19
|
+
ARGV.delete(SKIP_VERSION_CHECK_FLAG)
|
20
|
+
|
6
21
|
require 'vmx'
|
7
|
-
require 'dhcpd'
|
8
22
|
|
9
|
-
|
23
|
+
module Pauperism
|
24
|
+
class Vm < Thor
|
25
|
+
class_option :vmpath, :type => :string
|
26
|
+
class_option :vmrunpath, :type => :string # TODO: implement
|
10
27
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
desc "destroy [NODENAME]", "Completely destroy a VM"
|
18
|
-
def destroy(node_name=nil)
|
19
|
-
pauper = Pauper.new
|
20
|
-
if node_name
|
21
|
-
pauper.destroy(node_name)
|
22
|
-
else
|
23
|
-
pauper.destroy_all
|
28
|
+
no_commands do
|
29
|
+
def fusion(vmpath=Fusion::DEFAULT_VMPATH)
|
30
|
+
vmpath = File.expand_path(options[:vmpath]) if options[:vmpath]
|
31
|
+
@fusion ||= Fusion.new(vmpath)
|
32
|
+
end
|
24
33
|
end
|
25
|
-
end
|
26
34
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
35
|
+
desc 'start', 'Starts your fusion VM'
|
36
|
+
def start
|
37
|
+
say "Starting your VM, this may take a while..."
|
38
|
+
fusion.start
|
39
|
+
fusion.list
|
40
|
+
end
|
32
41
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
pauper.start(node_name)
|
38
|
-
else
|
39
|
-
pauper.start_all
|
42
|
+
desc 'stop', 'Stop given fusion VM '
|
43
|
+
def stop
|
44
|
+
fusion.stop
|
45
|
+
fusion.list
|
40
46
|
end
|
41
|
-
end
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
if node_name
|
47
|
-
pauper.stop(node_name)
|
48
|
-
else
|
49
|
-
pauper.stop_all
|
48
|
+
desc 'reset', 'Reset given fusion VM'
|
49
|
+
def reset
|
50
|
+
fusion.reset
|
50
51
|
end
|
51
|
-
end
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
if node_name
|
57
|
-
pauper.resume(node_name)
|
58
|
-
else
|
59
|
-
pauper.resume_all
|
53
|
+
desc 'suspend', 'Suspend given fusion VM'
|
54
|
+
def suspend
|
55
|
+
fusion.suspend
|
60
56
|
end
|
61
|
-
end
|
62
57
|
|
58
|
+
desc 'pause', 'Pause given fusion VM'
|
59
|
+
def pause
|
60
|
+
fusion.pause
|
61
|
+
end
|
63
62
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
if node_name
|
68
|
-
pauper.suspend(node_name)
|
69
|
-
else
|
70
|
-
pauper.suspend_all
|
63
|
+
desc 'unpause', 'Unpause given fusion VM'
|
64
|
+
def unpause
|
65
|
+
fusion.unpause
|
71
66
|
end
|
72
|
-
end
|
73
67
|
|
68
|
+
desc 'list', 'List running fusion VMs'
|
69
|
+
def list
|
70
|
+
fusion.list
|
71
|
+
end
|
74
72
|
|
73
|
+
desc 'vmruner', 'A tube straight to the vmrun command...'
|
74
|
+
def vmruner(cmd)
|
75
|
+
fusion.vmrun('list')
|
76
|
+
end
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
else
|
82
|
-
pauper.setup_all
|
78
|
+
desc 'setup', 'Setup your pauper vm experience'
|
79
|
+
def setup
|
80
|
+
say "Adding some lines to your vmx to try and help you be headless"
|
81
|
+
fusion.setup
|
82
|
+
# TODO: do more...
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
+
class CLI < Thor
|
87
|
+
class_option :pauperfile, :type => :string
|
86
88
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
89
|
+
desc "bootstrap", "Initialize the base image"
|
90
|
+
def bootstrap
|
91
|
+
pauper.bootstrap
|
92
|
+
end
|
92
93
|
|
94
|
+
desc "destroy [NODENAME]", "Completely destroy a VM"
|
95
|
+
def destroy(node_name=nil)
|
96
|
+
if node_name
|
97
|
+
pauper.destroy(node_name)
|
98
|
+
else
|
99
|
+
pauper.destroy_all
|
100
|
+
end
|
101
|
+
end
|
93
102
|
|
94
|
-
|
95
|
-
|
96
|
-
|
103
|
+
desc "create [NODENAME]", "Create a VM"
|
104
|
+
def create(node_name=nil)
|
105
|
+
pauper.create(node_name)
|
106
|
+
end
|
97
107
|
|
98
|
-
|
108
|
+
desc "start [NODENAME]", "Start a VM"
|
109
|
+
def start(node_name=nil)
|
110
|
+
if node_name
|
111
|
+
pauper.start(node_name)
|
112
|
+
else
|
113
|
+
pauper.start_all
|
114
|
+
end
|
115
|
+
end
|
99
116
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
vms.each do |vm|
|
107
|
-
puts "\t#{File.basename(vm)}"
|
117
|
+
desc "stop [NODENAME]", "Stop a VM"
|
118
|
+
def stop(node_name=nil)
|
119
|
+
if node_name
|
120
|
+
pauper.stop(node_name)
|
121
|
+
else
|
122
|
+
pauper.stop_all
|
108
123
|
end
|
109
|
-
exit
|
110
124
|
end
|
111
125
|
|
112
|
-
|
113
|
-
|
126
|
+
desc "resume [NODENAME]", "Resume a VM"
|
127
|
+
def resume(node_name=nil)
|
128
|
+
if node_name
|
129
|
+
pauper.resume(node_name)
|
130
|
+
else
|
131
|
+
pauper.resume_all
|
132
|
+
end
|
133
|
+
end
|
114
134
|
|
115
|
-
|
116
|
-
|
135
|
+
desc "suspend [NODENAME]", "Suspends a VM"
|
136
|
+
def suspend(node_name=nil)
|
137
|
+
if node_name
|
138
|
+
pauper.suspend(node_name)
|
139
|
+
else
|
140
|
+
pauper.suspend_all
|
141
|
+
end
|
142
|
+
end
|
117
143
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
144
|
+
desc "setup [NODENAME]", "Refresh configs and run Chef on a VM"
|
145
|
+
def setup(node_name=nil)
|
146
|
+
if node_name
|
147
|
+
pauper.setup(node_name)
|
148
|
+
else
|
149
|
+
pauper.setup_all
|
150
|
+
end
|
122
151
|
end
|
123
152
|
|
124
|
-
|
153
|
+
desc 'write_hosts', 'Write out a new /etc/hosts file'
|
154
|
+
def write_hosts
|
155
|
+
pauper.write_hosts
|
156
|
+
end
|
125
157
|
|
126
|
-
# Set up DHCPD
|
127
158
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
159
|
+
desc 'setup_osx [VMNAME]', 'Set up things for OS X'
|
160
|
+
def setup_osx(vm_path=Fusion::DEFAULT_VMPATH)
|
161
|
+
unless Pauper.osx?
|
162
|
+
puts 'Not OSX! I refuse!'
|
163
|
+
exit
|
164
|
+
end
|
165
|
+
pauper(true)
|
166
|
+
|
167
|
+
vmx_file = Fusion.new(vm_path).vmx
|
168
|
+
vmx = VMX.new(vmx_file)
|
169
|
+
|
170
|
+
mac = vmx.data['ethernet0.generatedAddress']
|
171
|
+
arpmac = mac.gsub(/0([0-9a-fA-F])/, '\1') # switch it to the format that arp likes
|
172
|
+
|
173
|
+
match = `arp -a | grep -i #{arpmac}`.match(/\(([0-9.]+)\)/)
|
174
|
+
unless match
|
175
|
+
puts "Could not find any running VM with MAC addr: #{arpmac}"
|
176
|
+
puts " >> Manually SSH into the VM then try again <<"
|
177
|
+
exit
|
178
|
+
end
|
132
179
|
|
133
|
-
|
134
|
-
|
135
|
-
|
180
|
+
ip = match.captures[0]
|
181
|
+
|
182
|
+
# Set up DHCPD
|
183
|
+
pauper.setup_osx_dhcpd(mac, ip)
|
184
|
+
|
185
|
+
# Set up route
|
186
|
+
pauper.setup_osx_routes(ip)
|
187
|
+
|
188
|
+
# Write hosts
|
189
|
+
pauper.write_osx_hosts(ip)
|
190
|
+
end
|
191
|
+
|
192
|
+
desc "up", "Start all nodes on your vm from local!"
|
193
|
+
def up
|
194
|
+
# TODO: check if VM is running
|
195
|
+
pauper(true).up
|
136
196
|
end
|
137
197
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
198
|
+
desc "halt", "Stop all nodes on your vm from local!"
|
199
|
+
def halt
|
200
|
+
pauper(true).halt
|
201
|
+
end
|
202
|
+
|
203
|
+
desc "reload", "Basically an up then a halt..."
|
204
|
+
def reload
|
205
|
+
pauper(true).reload
|
206
|
+
end
|
207
|
+
|
208
|
+
no_commands do
|
209
|
+
def pauper(ignore_network=false, pauperfile=Pauper::DEFAULT_PAUPERFILE)
|
210
|
+
pauperfile = File.expand_path(options[:pauperfile]) if options[:pauperfile]
|
211
|
+
@pauper ||= Pauper.new(ignore_network, pauperfile)
|
212
|
+
end
|
143
213
|
end
|
144
214
|
|
145
|
-
|
146
|
-
|
215
|
+
desc 'vm SUBCOMMAND', 'Operations dealing with VMware Fusion'
|
216
|
+
subcommand 'vm', Vm
|
147
217
|
end
|
148
218
|
end
|
149
219
|
|
150
|
-
CLI.start
|
220
|
+
Pauperism::CLI.start
|
data/lib/dhcpd.rb
CHANGED
data/lib/fusion.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
require 'open3'
|
3
|
+
require 'vmx'
|
4
|
+
|
5
|
+
class Fusion
|
6
|
+
DEFAULT_VMRUN = "/Applications/VMware\\ Fusion.app/Contents/Library/vmrun"
|
7
|
+
DEFAULT_VMPATH = "#{ENV['HOME']}/Documents/Virtual\\ Machines*/*.vmwarevm"
|
8
|
+
|
9
|
+
def initialize(vmpath=DEFAULT_VMPATH, nogui='nogui', force='hard')
|
10
|
+
@vmpath = vmpath
|
11
|
+
@vmrun = DEFAULT_VMRUN
|
12
|
+
@nogui = nogui
|
13
|
+
@force = force
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
vmrun('start')
|
18
|
+
end
|
19
|
+
|
20
|
+
def stop
|
21
|
+
vmrun('stop')
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset
|
25
|
+
vmrun('reset')
|
26
|
+
end
|
27
|
+
|
28
|
+
def suspend
|
29
|
+
vmrun('suspend')
|
30
|
+
end
|
31
|
+
|
32
|
+
def pause
|
33
|
+
vmrun('pause')
|
34
|
+
end
|
35
|
+
|
36
|
+
def unpause
|
37
|
+
vmrun('unpause')
|
38
|
+
end
|
39
|
+
|
40
|
+
def list
|
41
|
+
vmrun('list')
|
42
|
+
end
|
43
|
+
|
44
|
+
def vmrun(cmd)
|
45
|
+
case cmd
|
46
|
+
when 'start'
|
47
|
+
cmd = "#{@vmrun} -T fusion #{cmd} #{vmx.shellescape} #{@gui}"
|
48
|
+
when 'stop', 'reset', 'suspend'
|
49
|
+
cmd = "#{@vmrun} -T fusion #{cmd} #{vmx.shellescape} #{@force}"
|
50
|
+
when 'pause', 'unpause'
|
51
|
+
cmd = "#{@vmrun} -T fusion #{cmd} #{vmx.shellescape}"
|
52
|
+
else
|
53
|
+
cmd = "#{@vmrun} #{cmd}"
|
54
|
+
end
|
55
|
+
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
|
56
|
+
while line = stdout.gets
|
57
|
+
puts "> #{line}"
|
58
|
+
end
|
59
|
+
while line = stderr.gets
|
60
|
+
puts "err> #{line}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def setup
|
66
|
+
# this really just adds a few things to the vmx file for better headless
|
67
|
+
# operations.
|
68
|
+
v = VMX.new vmx
|
69
|
+
v.data['msg.autoAnswer'] = "TRUE" # Attempt to answer gui boxes you no longer get
|
70
|
+
puts " msg.autoAnswer=TRUE : auto answer gui boxes for you"
|
71
|
+
v.data['usb.generic.pluginAction'] = "host" # Always plug usb devices into host
|
72
|
+
puts " usb.generic.pluginAction='host' : never ask to plug usb things into vm"
|
73
|
+
v.data['mks.enable3d'] = "FALSE" # Turn of accelerated 3d... we dont need it
|
74
|
+
puts " mks.enable3d=FALSE : there is no need for 3d when headless..."
|
75
|
+
v.save vmx
|
76
|
+
end
|
77
|
+
|
78
|
+
def set_vmrun_to(vmrun)
|
79
|
+
@vmrun = vmrun
|
80
|
+
end
|
81
|
+
|
82
|
+
def link_vmrun(to='/user/local/bin/vmrun')
|
83
|
+
cmd = "ln -s #{@vmrun} #{to}"
|
84
|
+
if File.exists? to
|
85
|
+
puts "Something already exists at #{to}"
|
86
|
+
else
|
87
|
+
system(cmd)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def generate_startup_script
|
92
|
+
# TODO: Generate a startup script that calls pauper vm start/suspend at the
|
93
|
+
# right times.
|
94
|
+
end
|
95
|
+
|
96
|
+
def vmx
|
97
|
+
vms = Dir[@vmpath]
|
98
|
+
if vms.size == 0
|
99
|
+
puts "I can't find your VM. Try passing in a path to the <name>.vmwarevm dir."
|
100
|
+
exit
|
101
|
+
elsif vms.size > 1
|
102
|
+
puts "I'm not sure which VM I should use! Try passing one of these options:"
|
103
|
+
vms.each do |vm|
|
104
|
+
puts "\t--vmpath=#{vm}"
|
105
|
+
end
|
106
|
+
exit
|
107
|
+
end
|
108
|
+
|
109
|
+
# Return .vmx file
|
110
|
+
Dir[vms[0] + '/*.vmx'][0]
|
111
|
+
end
|
112
|
+
end
|
data/lib/libvirt.rb
CHANGED
@@ -43,10 +43,10 @@ EOF
|
|
43
43
|
File.open(".tmp.pauper.xml",'w') do |f|
|
44
44
|
f.puts config_data
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
system("sudo mv .tmp.pauper.xml #{CONF_FILE}")
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
def load_config
|
51
51
|
system("sudo virsh net-define #{CONF_FILE}")
|
52
52
|
end
|
@@ -70,9 +70,9 @@ EOF
|
|
70
70
|
return true
|
71
71
|
end
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
def loaded?
|
75
|
-
virsh = `sudo virsh net-info pauper | grep '^Name.*pauper$'`
|
75
|
+
virsh = `sudo virsh net-info pauper | grep '^Name.*pauper$'`
|
76
76
|
unless virsh == ""
|
77
77
|
return true
|
78
78
|
end
|
data/lib/lxc.rb
CHANGED
@@ -12,11 +12,11 @@ class LXC
|
|
12
12
|
@interface = ''
|
13
13
|
@template = ERB.new <<EOF
|
14
14
|
lxc.utsname = <%= node_name %>
|
15
|
-
lxc.pts = 1024
|
15
|
+
lxc.pts = 1024
|
16
16
|
lxc.tty = 4
|
17
17
|
lxc.cgroup.cpu.shares = 512
|
18
|
-
lxc.rootfs = /var/lib/lxc/<%= node_name %>/rootfs
|
19
|
-
lxc.mount = /var/lib/lxc/<%= node_name %>/fstab
|
18
|
+
lxc.rootfs = /var/lib/lxc/<%= node_name %>/rootfs
|
19
|
+
lxc.mount = /var/lib/lxc/<%= node_name %>/fstab
|
20
20
|
lxc.network.type = veth
|
21
21
|
lxc.network.name = eth0
|
22
22
|
lxc.network.link = <%= interface %>
|
@@ -43,7 +43,7 @@ EOF
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def save(filename=@filename)
|
46
|
-
config_data = @template.result(OpenStruct.new(:node_name => @node_name,
|
46
|
+
config_data = @template.result(OpenStruct.new(:node_name => @node_name,
|
47
47
|
:mac => @mac, :interface => @interface ).send(:binding))
|
48
48
|
File.open(".tmp.lxc.conf",'w') do |f|
|
49
49
|
f.puts config_data
|
data/lib/pauper.rb
CHANGED
@@ -11,21 +11,24 @@ require 'ostruct'
|
|
11
11
|
require 'lxc'
|
12
12
|
require 'libvirt'
|
13
13
|
require 'hosts'
|
14
|
+
require 'dhcpd'
|
15
|
+
|
16
|
+
require 'io/console' # for 'noecho'
|
17
|
+
|
18
|
+
require 'pauper/version'
|
14
19
|
|
15
20
|
class Pauper
|
16
21
|
DEFAULT_PAUPERFILE = './Pauperfile'
|
17
22
|
DEFAULT_VM_PATH = File.expand_path('/var/lib/lxc/')
|
18
23
|
|
19
|
-
def initialize(pauperfile=DEFAULT_PAUPERFILE)
|
24
|
+
def initialize(ignore_network = false, pauperfile = DEFAULT_PAUPERFILE)
|
20
25
|
if root?
|
21
26
|
puts "Don't run as root!"
|
22
27
|
exit
|
23
28
|
end
|
24
29
|
|
25
|
-
@pauper_config = Pauper::Config.new(
|
26
|
-
|
27
|
-
network.enable
|
28
|
-
@pauper_config.config[:bridge] = network.interface
|
30
|
+
@pauper_config = Pauper::Config.new(pauperfile)
|
31
|
+
setup_network unless ignore_network
|
29
32
|
end
|
30
33
|
|
31
34
|
def root?
|
@@ -35,16 +38,19 @@ class Pauper
|
|
35
38
|
def config
|
36
39
|
@pauper_config
|
37
40
|
end
|
38
|
-
|
41
|
+
|
39
42
|
def bootstrap
|
40
43
|
raise "Base already exists!" if vm_exists?("base")
|
41
44
|
|
42
|
-
|
45
|
+
ip = "#{@pauper_config.config[:subnet]}.2"
|
46
|
+
ssh_clean_known_hosts('base', ip)
|
47
|
+
@pauper_config.config[:nodes].each { |n| ssh_clean_known_hosts(n.name, "#{@pauper_config.config[:subnet]}.#{n.config[:last_octet]}") }
|
48
|
+
|
49
|
+
lxc_pauper_template
|
43
50
|
system("sudo touch /var/lib/lxc/lxc.conf")
|
44
51
|
system("sudo lxc-create -n base -t pauper -f /var/lib/lxc/lxc.conf -- -a amd64 --auth-key #{public_ssh_key} -r lucid")
|
45
52
|
mac = generate_mac
|
46
|
-
|
47
|
-
|
53
|
+
|
48
54
|
lxc = LXC.new('base')
|
49
55
|
lxc.interface = @pauper_config.config[:bridge]
|
50
56
|
lxc.mac = mac
|
@@ -82,7 +88,7 @@ class Pauper
|
|
82
88
|
def public_ssh_key
|
83
89
|
ssh_key + ".pub"
|
84
90
|
end
|
85
|
-
|
91
|
+
|
86
92
|
def prepare_fstab(node_name)
|
87
93
|
File.open('.tmp.fstab','w') do |f|
|
88
94
|
@pauper_config.config[:shares].each do |share_name, guest_path, host_path, options|
|
@@ -110,7 +116,7 @@ class Pauper
|
|
110
116
|
system "sudo mv .tmp.interfaces #{DEFAULT_VM_PATH}/#{node_name}/rootfs/etc/network/interfaces"
|
111
117
|
system "sudo mv .tmp.resolv.conf #{DEFAULT_VM_PATH}/#{node_name}/rootfs/etc/resolv.conf"
|
112
118
|
end
|
113
|
-
|
119
|
+
|
114
120
|
def prepare_base_cache
|
115
121
|
@pauper_config.config[:shares].each do |share_name, guest_path, host_path, options|
|
116
122
|
cmd "sudo mkdir -p #{host_path}"
|
@@ -122,7 +128,7 @@ class Pauper
|
|
122
128
|
def reconfigure_ssh(node_name)
|
123
129
|
cmd "sudo chroot /var/lib/lxc/#{node_name}/rootfs/ /usr/sbin/dpkg-reconfigure openssh-server"
|
124
130
|
end
|
125
|
-
|
131
|
+
|
126
132
|
def create(node_name)
|
127
133
|
node_config = get_node_config(node_name)
|
128
134
|
|
@@ -132,7 +138,7 @@ class Pauper
|
|
132
138
|
clone_base(node_name)
|
133
139
|
mac = generate_mac
|
134
140
|
ip = "#{@pauper_config.config[:subnet]}.#{node_config.config[:last_octet]}"
|
135
|
-
|
141
|
+
|
136
142
|
lxc = LXC.new(node_name)
|
137
143
|
lxc.interface = @pauper_config.config[:bridge]
|
138
144
|
lxc.mac = mac
|
@@ -206,7 +212,7 @@ EOF
|
|
206
212
|
else
|
207
213
|
node_config = get_node_config(node_name)
|
208
214
|
ip = node_ip(node_config)
|
209
|
-
end
|
215
|
+
end
|
210
216
|
|
211
217
|
if vm_exists?(node_name)
|
212
218
|
stop_node(node_name)
|
@@ -218,8 +224,7 @@ EOF
|
|
218
224
|
|
219
225
|
puts "Destroying #{node_name}..."
|
220
226
|
cmd "sudo lxc-destroy -n '#{node_name}' >> pauper.log 2>&1"
|
221
|
-
|
222
|
-
cmd "ssh-keygen -R '#{ip}' >> pauper.log 2>&1"
|
227
|
+
ssh_clean_known_hosts(node_name, ip)
|
223
228
|
else
|
224
229
|
puts "#{node_name} hasn't even been created yet, thusly you can't destroy it!"
|
225
230
|
end
|
@@ -284,6 +289,26 @@ EOF
|
|
284
289
|
hosts.save(@pauper_config.config[:dev_domain])
|
285
290
|
end
|
286
291
|
|
292
|
+
def setup_osx_routes(dev_ip)
|
293
|
+
gateway = `route -n get #{@pauper_config.config[:subnet]}.0`.match(/gateway: (.*)$/).captures[0]
|
294
|
+
unless gateway == dev_ip
|
295
|
+
puts "Adding route to LXC hosts..."
|
296
|
+
system 'sudo', 'route', 'add', "#{@pauper_config.config[:subnet]}.0/24", dev_ip
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def setup_osx_dhcpd(mac, dev_ip)
|
301
|
+
dhcpd = DHCPD.new('/Library/Preferences/VMware Fusion/vmnet8/dhcpd.conf')
|
302
|
+
unless dhcpd.config['dev'] &&
|
303
|
+
dhcpd.config['dev']['hardware ethernet'] == mac &&
|
304
|
+
dhcpd.config['dev']['fixed-address'] == dev_ip
|
305
|
+
|
306
|
+
puts "Writing correct IP/MAC combo into dhcpd.conf file..."
|
307
|
+
dhcpd.config['dev'] = { 'hardware ethernet' => mac, 'fixed-address' => dev_ip }
|
308
|
+
dhcpd.save
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
287
312
|
def start_all
|
288
313
|
puts "Starting all nodes..."
|
289
314
|
@pauper_config.config[:nodes].each { |n| start(n.name) }
|
@@ -314,8 +339,133 @@ EOF
|
|
314
339
|
@pauper_config.config[:nodes].each { |n| setup(n.name) }
|
315
340
|
end
|
316
341
|
|
342
|
+
# Should call pauper stop on your vm and then do the things needed for the
|
343
|
+
# hosts to get setup and made visible
|
344
|
+
# Assumes that your local /etc/hosts already knows of your dev ip
|
345
|
+
def up
|
346
|
+
puts "Let me get you setup..."
|
347
|
+
ip = hosts_dev_ip
|
348
|
+
cmds = ["cd #{code_dir}/pauper-env",
|
349
|
+
"pauper start",
|
350
|
+
"pauper write_hosts",
|
351
|
+
"sudo iptables -F"]
|
352
|
+
ssh_with_sudo ip, cmds
|
353
|
+
if Pauper.osx?
|
354
|
+
setup_osx_routes(ip)
|
355
|
+
write_osx_hosts(ip)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
# Should call pauper stop on your vm
|
360
|
+
# Assumes that your local /etc/hosts already knows of your dev ip
|
361
|
+
def halt
|
362
|
+
puts "Let me blow things up..."
|
363
|
+
cmds = ["cd #{code_dir}/pauper-env",
|
364
|
+
"pauper stop"]
|
365
|
+
ssh_with_sudo hosts_dev_ip, cmds
|
366
|
+
end
|
367
|
+
|
368
|
+
# runs the same commands as doing a halt + up but it does it in
|
369
|
+
# one SSH session rather than two... also takes a nap in the middle
|
370
|
+
# Assumes that your local /etc/hosts already knows of your dev ip
|
371
|
+
def reload
|
372
|
+
puts "Let me blow things up..."
|
373
|
+
ip = hosts_dev_ip
|
374
|
+
cmds = ["cd #{code_dir}/pauper-env",
|
375
|
+
"pauper stop",
|
376
|
+
"sleep 2", #napping
|
377
|
+
"echo '*-*-*>KABOOM<*-*-*'",
|
378
|
+
"pauper start",
|
379
|
+
"pauper write_hosts",
|
380
|
+
"sudo iptables -F"]
|
381
|
+
ssh_with_sudo ip, cmds
|
382
|
+
if Pauper.osx?
|
383
|
+
setup_osx_routes(ip)
|
384
|
+
write_osx_hosts(ip)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def self.osx?
|
389
|
+
RUBY_PLATFORM.include? 'darwin'
|
390
|
+
end
|
391
|
+
|
317
392
|
private
|
318
393
|
|
394
|
+
# This does SSH using some crazy channel things and lots of call backs
|
395
|
+
# requesting a pty all so that we can respond to sudo asking for a password.
|
396
|
+
#
|
397
|
+
# This needs an ssh agent. It should error without one...
|
398
|
+
#
|
399
|
+
# if cmds are passed as a array of strings it will be joined with ';'
|
400
|
+
# this is prefereable to many calls as each new call with require a new
|
401
|
+
# ssh connection.
|
402
|
+
# else cmds is assumed to be a string and used as is.
|
403
|
+
#
|
404
|
+
# this has some logic to ignore the string "sudo: unable to reslove host"
|
405
|
+
# because my vm likes to spout that 20 times per call...
|
406
|
+
def ssh_with_sudo(ip, cmds)
|
407
|
+
cmds = cmds.join(';') if cmds.kind_of?(Array)
|
408
|
+
# arrays that define what to match on when parsing responses
|
409
|
+
ignore_exact = ['', 'sudo', ':'] # exect string matchs
|
410
|
+
ignore_partial = ['unable to resolve host'] # partial string matches
|
411
|
+
pass_phrases = ['[sudo] password', # sudo waiting for password
|
412
|
+
'Enter passphrase for '] # key waiting for password...
|
413
|
+
puts "\e[32m====> SSH >===="
|
414
|
+
lines = 0
|
415
|
+
Net::SSH.start ip, ENV['USER'], {:forward_agent => true} do |ssh|
|
416
|
+
ssh.open_channel do |channel|
|
417
|
+
channel.request_pty do |ch, success| # Needed for password responses
|
418
|
+
abort('Failed to get pty...') unless success
|
419
|
+
end
|
420
|
+
channel.exec cmds do |ch, success|
|
421
|
+
abort('Failed to exec command...') unless success
|
422
|
+
channel.on_data do |ch, data|
|
423
|
+
data.rstrip! # Screw newlines
|
424
|
+
if pass_phrases.any? {|s| data.include? s}
|
425
|
+
print "#{lines}> #{data}"
|
426
|
+
lines += 1
|
427
|
+
channel.send_data STDIN.noecho(&:gets)
|
428
|
+
print "\n"
|
429
|
+
elsif ignore_exact.index data
|
430
|
+
elsif ignore_partial.any? {|s| data.include? s}
|
431
|
+
else
|
432
|
+
puts "#{lines}> #{data}"
|
433
|
+
lines += 1
|
434
|
+
end
|
435
|
+
end
|
436
|
+
channel.on_extended_data do |ch, type, data|
|
437
|
+
# in case of stderr
|
438
|
+
print "\e[31m#{lines}-err> #{data} -- #{type}\e[32m"
|
439
|
+
end
|
440
|
+
end
|
441
|
+
channel.wait # until it closes...
|
442
|
+
end
|
443
|
+
ssh.loop
|
444
|
+
end
|
445
|
+
puts "====< SSH <====\e[0m"
|
446
|
+
end
|
447
|
+
|
448
|
+
def code_dir
|
449
|
+
@pauper_config.config[:shares].each do |a|
|
450
|
+
if a[0] == 'fastly'
|
451
|
+
return a[2]
|
452
|
+
end
|
453
|
+
end
|
454
|
+
return nil
|
455
|
+
end
|
456
|
+
|
457
|
+
def hosts_dev_ip
|
458
|
+
ip = Hosts.new.config.key 'dev'
|
459
|
+
abort 'could not find dev ip in /etc/hosts' unless ip
|
460
|
+
ip
|
461
|
+
end
|
462
|
+
|
463
|
+
def setup_network
|
464
|
+
network = LIBVIRT.new(@pauper_config.config[:subnet])
|
465
|
+
network.enable
|
466
|
+
@pauper_config.config[:bridge] = network.interface
|
467
|
+
end
|
468
|
+
|
319
469
|
def node_ip(node_config)
|
320
470
|
return node_config.config[:ip] if node_config.config[:ip]
|
321
471
|
@subnet = @pauper_config.config[:subnet]
|
@@ -327,6 +477,11 @@ EOF
|
|
327
477
|
system *args
|
328
478
|
end
|
329
479
|
|
480
|
+
def ssh_clean_known_hosts(hostname, ip)
|
481
|
+
cmd "ssh-keygen -R '#{hostname}' >> pauper.log 2>&1"
|
482
|
+
cmd "ssh-keygen -R '#{ip}' >> pauper.log 2>&1"
|
483
|
+
end
|
484
|
+
|
330
485
|
def ssh_exec(ssh, cmd)
|
331
486
|
puts "ssh> #{cmd}"
|
332
487
|
print ssh.exec!(cmd)
|
@@ -1044,7 +1199,12 @@ end
|
|
1044
1199
|
:chef_options => {},
|
1045
1200
|
:dev_domain => nil
|
1046
1201
|
}
|
1047
|
-
|
1202
|
+
if File.exists? pauperfile
|
1203
|
+
pauperpath = File.dirname(pauperfile)
|
1204
|
+
instance_eval File.read(pauperfile)
|
1205
|
+
else
|
1206
|
+
abort "!! Could not find Pauperfile at #{pauperfile} !!"
|
1207
|
+
end
|
1048
1208
|
end
|
1049
1209
|
|
1050
1210
|
def get_node(node_name)
|
data/test/pauper_test.rb
ADDED
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pauper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tyler McMullen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-02-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -78,12 +78,17 @@ extra_rdoc_files: []
|
|
78
78
|
files:
|
79
79
|
- bin/pauper
|
80
80
|
- lib/dhcpd.rb
|
81
|
+
- lib/fusion.rb
|
81
82
|
- lib/hosts.rb
|
82
83
|
- lib/libvirt.rb
|
83
84
|
- lib/lxc.rb
|
85
|
+
- lib/pauper/version.rb
|
84
86
|
- lib/pauper.rb
|
85
87
|
- lib/vmx.rb
|
86
|
-
- README
|
88
|
+
- README.md
|
89
|
+
- Rakefile
|
90
|
+
- test/pauper_test.rb
|
91
|
+
- test/test_helper.rb
|
87
92
|
homepage: http://github.com/fastly/Pauper
|
88
93
|
licenses: []
|
89
94
|
metadata: {}
|
@@ -107,4 +112,6 @@ rubygems_version: 2.0.3
|
|
107
112
|
signing_key:
|
108
113
|
specification_version: 4
|
109
114
|
summary: A semi-sane way to manage a multi-vm dev environment
|
110
|
-
test_files:
|
115
|
+
test_files:
|
116
|
+
- test/pauper_test.rb
|
117
|
+
- test/test_helper.rb
|