Class: Pauper

Inherits:
Object
  • Object
show all
Defined in:
lib/pauper.rb,
lib/pauper/version.rb

Defined Under Namespace

Classes: Config

Constant Summary collapse

DEFAULT_PAUPERFILE =
'./Pauperfile'
DEFAULT_VM_PATH =
File.expand_path('/var/lib/lxc/')
VERSION =
'0.2.0'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ignore_network = false, pauperfile = DEFAULT_PAUPERFILE) ⇒ Pauper

Returns a new instance of Pauper.



24
25
26
27
28
29
30
31
32
# File 'lib/pauper.rb', line 24

def initialize(ignore_network = false, pauperfile = DEFAULT_PAUPERFILE)
  if root?
    puts "Don't run as root!"
    exit
  end

  @pauper_config = Pauper::Config.new(pauperfile)
  setup_network unless ignore_network
end

Class Method Details

.osx?Boolean

Returns:

  • (Boolean)


388
389
390
# File 'lib/pauper.rb', line 388

def self.osx?
  RUBY_PLATFORM.include? 'darwin'
end

Instance Method Details

#bootstrapObject



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
# File 'lib/pauper.rb', line 42

def bootstrap
  raise "Base already exists!" if vm_exists?("base")

  ip = "#{@pauper_config.config[:subnet]}.2"
  ssh_clean_known_hosts('base', ip)
  @pauper_config.config[:nodes].each { |n| ssh_clean_known_hosts(n.name, "#{@pauper_config.config[:subnet]}.#{n.config[:last_octet]}") }

  lxc_pauper_template
  system("sudo touch /var/lib/lxc/lxc.conf")
  system("sudo lxc-create -n base -t pauper -f /var/lib/lxc/lxc.conf -- -a amd64 --auth-key #{public_ssh_key} -r lucid")
  mac = generate_mac

  lxc = LXC.new('base')
  lxc.interface = @pauper_config.config[:bridge]
  lxc.mac = mac
  lxc.save

  prepare_fstab('base')
  prepare_vm_network('base',ip)
  prepare_base_cache

  puts "Installing chef..."
  cmd "sudo chroot /var/lib/lxc/base/rootfs/ bash -c 'wget #{@pauper_config.config[:chef_download_url]}/#{@pauper_config.config[:chef_deb_name]} && dpkg -i #{@pauper_config.config[:chef_deb_name]}; rm #{@pauper_config.config[:chef_deb_name]}'"

  start_node('base')
  sleep 3

  chef_node = "base#{@pauper_config.config[:node_suffix]}"
  cmd "knife bootstrap --bootstrap-version chef-full -N #{chef_node} -E #{@pauper_config.config[:chef_environment]} -x root -r \"#{@pauper_config.config[:default_run_list].join(",")}\" #{ip}"

  stop_node('base')
end

#configObject



38
39
40
# File 'lib/pauper.rb', line 38

def config
  @pauper_config
end

#create(node_name) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/pauper.rb', line 132

def create(node_name)
  node_config = get_node_config(node_name)

  raise "VM already exists!" if vm_exists?(node_name)

  puts "Cloning base..."
  clone_base(node_name)
  mac = generate_mac
  ip = "#{@pauper_config.config[:subnet]}.#{node_config.config[:last_octet]}"

  lxc = LXC.new(node_name)
  lxc.interface = @pauper_config.config[:bridge]
  lxc.mac = mac
  lxc.save

  prepare_fstab(node_name)
  prepare_vm_network(node_name,ip)
  reconfigure_ssh(node_name)
  puts "Starting..."
  start_node(node_name)
  sleep 3
  setup(node_name)
end

#destroy(node_name) ⇒ Object



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/pauper.rb', line 209

def destroy(node_name)
  if node_name == 'base'
    ip = @pauper_config.config[:subnet] + '.2'
  else
    node_config = get_node_config(node_name)
    ip = node_ip(node_config)
  end

  if vm_exists?(node_name)
    stop_node(node_name)

    chef_node = "#{node_name}#{@pauper_config.config[:node_suffix]}"
    puts "Removing #{node_name} from Chef..."
    `knife node delete #{chef_node} -y`
    `knife client delete #{chef_node} -y`

    puts "Destroying #{node_name}..."
    cmd "sudo lxc-destroy -n '#{node_name}' >> pauper.log 2>&1"
    ssh_clean_known_hosts(node_name, ip)
  else
    puts "#{node_name} hasn't even been created yet, thusly you can't destroy it!"
  end
end

#destroy_allObject



332
333
334
335
# File 'lib/pauper.rb', line 332

def destroy_all
  puts "Destroying all nodes..."
  @pauper_config.config[:nodes].each { |n| destroy(n.name) }
end

#haltObject

Should call pauper stop on your vm Assumes that your local /etc/hosts already knows of your dev ip



361
362
363
364
365
366
# File 'lib/pauper.rb', line 361

def halt
  puts "Let me blow things up..."
  cmds = ["cd #{code_dir}/pauper-env",
          "pauper stop"]
  ssh_with_sudo hosts_dev_ip, cmds
end

#prepare_base_cacheObject



120
121
122
123
124
125
126
# File 'lib/pauper.rb', line 120

def prepare_base_cache
  @pauper_config.config[:shares].each do |share_name, guest_path, host_path, options|
    cmd "sudo mkdir -p #{host_path}"
    cmd "sudo mkdir -p /var/lib/lxc/base/rootfs#{guest_path}"
  end
  cmd "sudo mkdir -p /var/cache/lxc/lucid/cache/apt/partial"
end

#prepare_fstab(node_name) ⇒ Object



92
93
94
95
96
97
98
99
# File 'lib/pauper.rb', line 92

def prepare_fstab(node_name)
  File.open('.tmp.fstab','w') do |f|
    @pauper_config.config[:shares].each do |share_name, guest_path, host_path, options|
      f.puts "#{host_path} #{DEFAULT_VM_PATH}/#{node_name}/rootfs/#{guest_path} none defaults,bind 0 0"
    end
  end
  system "sudo mv .tmp.fstab #{DEFAULT_VM_PATH}/#{node_name}/fstab"
end

#prepare_vm_network(node_name, ip) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/pauper.rb', line 101

def prepare_vm_network(node_name,ip)
  host_ip = "#{@pauper_config.config[:subnet]}.1"
  File.open('.tmp.interfaces', 'w') do |f|
    f.puts "auto lo"
    f.puts "iface lo inet loopback"
    f.puts ""
    f.puts "auto eth0"
    f.puts "iface eth0 inet static"
    f.puts " address #{ip}"
    f.puts " netmask 255.255.255.0"
    f.puts " gateway #{host_ip}"
  end
  File.open('.tmp.resolv.conf', 'w') do |f|
    f.puts "nameserver #{host_ip}"
  end
  system "sudo mv .tmp.interfaces #{DEFAULT_VM_PATH}/#{node_name}/rootfs/etc/network/interfaces"
  system "sudo mv .tmp.resolv.conf #{DEFAULT_VM_PATH}/#{node_name}/rootfs/etc/resolv.conf"
end

#public_ssh_keyObject



88
89
90
# File 'lib/pauper.rb', line 88

def public_ssh_key
  ssh_key + ".pub"
end

#reconfigure_ssh(node_name) ⇒ Object



128
129
130
# File 'lib/pauper.rb', line 128

def reconfigure_ssh(node_name)
  cmd "sudo chroot /var/lib/lxc/#{node_name}/rootfs/ /usr/sbin/dpkg-reconfigure openssh-server"
end

#reloadObject

runs the same commands as doing a halt + up but it does it in

one SSH session rather than two... also takes a nap in the middle

Assumes that your local /etc/hosts already knows of your dev ip



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/pauper.rb', line 371

def reload
  puts "Let me blow things up..."
  ip = hosts_dev_ip
  cmds = ["cd #{code_dir}/pauper-env",
          "pauper stop",
          "sleep 2", #napping
          "echo '*-*-*>KABOOM<*-*-*'",
          "pauper start",
          "pauper write_hosts",
          "sudo iptables -F"]
  ssh_with_sudo ip, cmds
  if Pauper.osx?
    setup_osx_routes(ip)
    write_osx_hosts(ip)
  end
end

#resume(node_name) ⇒ Object



255
256
257
258
259
260
261
262
# File 'lib/pauper.rb', line 255

def resume(node_name)
  if vm_frozen?(node_name)
    puts "Resuming #{node_name}..."
    resume_node(node_name)
  else
    puts "wtf, #{node_name} is not suspended."
  end
end

#resume_allObject



322
323
324
325
# File 'lib/pauper.rb', line 322

def resume_all
  puts "Resuming all nodes..."
  @pauper_config.config[:nodes].each { |n| resume(n.name) }
end

#root?Boolean

Returns:

  • (Boolean)


34
35
36
# File 'lib/pauper.rb', line 34

def root?
  Process.euid == 0
end

#setup(node_name) ⇒ Object



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
# File 'lib/pauper.rb', line 156

def setup(node_name)
  node_config = get_node_config(node_name)
  config = @pauper_config.config
  puts "Setting up #{node_name}..."
  client_erb = ERB.new "node_name              \"<%= chef_node %>\"\nchef_server_url        \"<%= config[:chef_server_url] %>\"\nchef_download_url      \"<%= config[:chef_download_url] %>\"\nchef_deb_name          \"<%= config[:chef_deb_name] %>\"\nvalidation_client_name \"<%= config[:validation_client_name] %>\"\nenvironment            \"<%= config[:chef_environment] %>\"\nverbose_logging        false\njson_attribs           \"/etc/chef/client-config.json\"\n"
  chef_node = "#{node_name}#{config[:node_suffix]}"
  client_rb_data = client_erb.result(OpenStruct.new(:config => config, :chef_node => chef_node).send(:binding))
  tmp_client_rb_path = ".tmp.#{node_name}.client.rb"
  File.open(tmp_client_rb_path,'w') do |f|
    f.puts client_rb_data
  end

  ip = node_ip(node_config)

  chef_attribs = {
    :run_list => config[:default_run_list] + node_config.config[:run_list],
    :ip => {
      :private => ip,
      :private_netmask => '255.255.255.0'
    }
  }.merge(config[:chef_options]).merge(node_config.config[:chef_options])

  puts "Uploading Chef files..."
  Net::SCP.start ip, ENV['USER'] do |scp|
    scp.upload! tmp_client_rb_path, "client.rb"
    scp.upload! config[:validation_key_path], "validation.pem"
    scp.upload! StringIO.new(chef_attribs.to_json), "client-config.json"
  end

  FileUtils.rm(tmp_client_rb_path)

  puts "Connecting over SSH..."
  Net::SSH.start ip, ENV['USER'] do |ssh|
    ssh_exec ssh, "sudo mv client.rb /etc/chef/"
    ssh_exec ssh, "sudo mv validation.pem /etc/chef/"
    ssh_exec ssh, "sudo mv client-config.json /etc/chef/"
    ssh_exec ssh, "sudo touch /etc/chef/disabled"

    ssh.exec! "sudo /usr/bin/chef-client" do |channel, stream, data|
      print data
    end
  end
end

#setup_allObject



337
338
339
340
# File 'lib/pauper.rb', line 337

def setup_all
  puts "Setting up all nodes..."
  @pauper_config.config[:nodes].each { |n| setup(n.name) }
end

#setup_osx_dhcpd(mac, dev_ip) ⇒ Object



300
301
302
303
304
305
306
307
308
309
310
# File 'lib/pauper.rb', line 300

def setup_osx_dhcpd(mac, dev_ip)
  dhcpd = DHCPD.new('/Library/Preferences/VMware Fusion/vmnet8/dhcpd.conf')
  unless dhcpd.config['dev'] &&
    dhcpd.config['dev']['hardware ethernet'] == mac &&
    dhcpd.config['dev']['fixed-address'] == dev_ip

    puts "Writing correct IP/MAC combo into dhcpd.conf file..."
    dhcpd.config['dev'] = { 'hardware ethernet' => mac, 'fixed-address' => dev_ip }
    dhcpd.save
  end
end

#setup_osx_routes(dev_ip) ⇒ Object



292
293
294
295
296
297
298
# File 'lib/pauper.rb', line 292

def setup_osx_routes(dev_ip)
  gateway = `route -n get #{@pauper_config.config[:subnet]}.0`.match(/gateway: (.*)$/).captures[0]
  unless gateway == dev_ip
    puts "Adding route to LXC hosts..."
    system 'sudo', 'route', 'add', "#{@pauper_config.config[:subnet]}.0/24", dev_ip
  end
end

#ssh_keyObject



79
80
81
82
83
84
85
86
# File 'lib/pauper.rb', line 79

def ssh_key
  @ssh_key ||= begin
    key = @pauper_config.config[:bootstrap_ssh_key] || "/home/#{username}/.ssh/id_rsa"
    raise "The private SSH key set in your Pauperfile does not exist." unless File.exist?(key)
    raise "The public SSH key set in your Pauperfile does not exist." unless File.exist?("#{key}.pub")
    key
  end
end

#start(node_name) ⇒ Object



242
243
244
245
246
247
248
249
250
251
252
# File 'lib/pauper.rb', line 242

def start(node_name)
  if vm_running?(node_name)
    puts "Dude, #{node_name} is already running!"
  elsif vm_exists?(node_name)
    puts "Starting #{node_name}..."
    start_node node_name
  else
    puts "Generating, then starting #{node_name}..."
    create node_name
  end
end

#start_allObject



312
313
314
315
# File 'lib/pauper.rb', line 312

def start_all
  puts "Starting all nodes..."
  @pauper_config.config[:nodes].each { |n| start(n.name) }
end

#stop(node_name) ⇒ Object



233
234
235
236
237
238
239
240
# File 'lib/pauper.rb', line 233

def stop(node_name)
  if vm_running?(node_name)
    puts "Stopping #{node_name}..."
    stop_node(node_name)
  else
    puts "wtf, #{node_name} is not running."
  end
end

#stop_allObject



317
318
319
320
# File 'lib/pauper.rb', line 317

def stop_all
  puts "Stopping all nodes..."
  @pauper_config.config[:nodes].each { |n| stop(n.name) }
end

#suspend(node_name) ⇒ Object



264
265
266
267
268
269
270
271
# File 'lib/pauper.rb', line 264

def suspend(node_name)
  if vm_frozen?(node_name)
    puts "Dude, #{node_name} is already suspended!"
  else
    puts "Suspending #{node_name}..."
    suspend_node(node_name)
  end
end

#suspend_allObject



327
328
329
330
# File 'lib/pauper.rb', line 327

def suspend_all
  puts "Suspending all nodes..."
  @pauper_config.config[:nodes].each { |n| suspend(n.name) }
end

#upObject

Should call pauper stop on your vm and then do the things needed for the

hosts to get setup and made visible

Assumes that your local /etc/hosts already knows of your dev ip



345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/pauper.rb', line 345

def up
  puts "Let me get you setup..."
  ip = hosts_dev_ip
  cmds = ["cd #{code_dir}/pauper-env",
          "pauper start",
          "pauper write_hosts",
          "sudo iptables -F"]
  ssh_with_sudo ip, cmds
  if Pauper.osx?
    setup_osx_routes(ip)
    write_osx_hosts(ip)
  end
end

#usernameObject



75
76
77
# File 'lib/pauper.rb', line 75

def username
  ENV['USER']
end

#write_hostsObject



273
274
275
276
277
278
279
280
# File 'lib/pauper.rb', line 273

def write_hosts
  puts "Writing /etc/hosts file..."
  hosts = Hosts.new
  @pauper_config.config[:nodes].each do |node|
    hosts.config[node_ip(node)] = node.name
  end
  hosts.save(@pauper_config.config[:dev_domain])
end

#write_osx_hosts(dev_ip) ⇒ Object



282
283
284
285
286
287
288
289
290
# File 'lib/pauper.rb', line 282

def write_osx_hosts(dev_ip)
  puts "Writing /etc/hosts file..."
  hosts = Hosts.new
  @pauper_config.config[:nodes].each do |node|
    hosts.config[node_ip(node)] = node.name
  end
  hosts.config[dev_ip] = 'dev'
  hosts.save(@pauper_config.config[:dev_domain])
end