Class: TestLab::Provider::Vagrant

Inherits:
Object
  • Object
show all
Defined in:
lib/testlab/providers/vagrant.rb

Overview

Vagrant Provider Class

Author:

  • Zachary Patten <zachary AT jovelabs DOT com>

Constant Summary collapse

RUNNING_STATES =

States which indicate the VM is running

%w(running).map(&:to_sym)
SHUTDOWN_STATES =

States which indicate the VM is shut down

%w(aborted paused saved poweroff).map(&:to_sym)
UNKNOWN_STATE =

The state we report if we can not determine the VM state

:unknown
VALID_STATES =

A collection of all valid states the VM can be in

(RUNNING_STATES + SHUTDOWN_STATES).flatten
INVALID_STATES =

A collection of all invalid states the VM can be in

(%w(not_created).map(&:to_sym) + [UNKNOWN_STATE]).flatten
ALL_STATES =

A collection of all states the VM can be in

(VALID_STATES + INVALID_STATES).flatten

Instance Method Summary collapse

Constructor Details

#initialize(config = {}, ui = nil) ⇒ Vagrant

Returns a new instance of Vagrant.



33
34
35
36
37
38
39
40
41
# File 'lib/testlab/providers/vagrant.rb', line 33

def initialize(config={}, ui=nil)
  @config   = (config || Hash.new)
  @ui       = (ui || TestLab.ui)

  # ensure our vagrant key is there
  @config[:vagrant] ||= Hash.new

  @command = ZTK::Command.new(:ui => @ui, :silence => true, :ignore_exit_status => true, :timeout => 3600)
end

Instance Method Details

#alive?Boolean

Is the Vagrant-controlled VM alive?

Returns:

  • (Boolean)


180
181
182
# File 'lib/testlab/providers/vagrant.rb', line 180

def alive?
  (self.exists? && (RUNNING_STATES.include?(self.state) rescue false))
end

#boxObject



225
226
227
# File 'lib/testlab/providers/vagrant.rb', line 225

def box
  (@config[:vagrant][:box] || "raring64")
end

#box_urlObject



229
230
231
# File 'lib/testlab/providers/vagrant.rb', line 229

def box_url
  (@config[:vagrant][:box_url] || "http://files.vagrantup.com/raring64.box")
end

#cpusObject



233
234
235
# File 'lib/testlab/providers/vagrant.rb', line 233

def cpus
  (@config[:vagrant][:cpus] || 2)
end

#createObject

Create the Vagrant instance



46
47
48
# File 'lib/testlab/providers/vagrant.rb', line 46

def create
  true
end

#dead?Boolean

Is the Vagrant-controlled VM dead?

Returns:

  • (Boolean)


185
186
187
# File 'lib/testlab/providers/vagrant.rb', line 185

def dead?
  !self.alive?
end

#destroyObject

Destroy Vagrant-controlled VM



51
52
53
54
55
56
57
58
59
# File 'lib/testlab/providers/vagrant.rb', line 51

def destroy
  @state = nil
  self.alive? and self.down

  @state = nil
  self.exists? and self.vagrant_cli("destroy", "--force", self.instance_id)

  true
end

#down(*args) ⇒ Object

Halt Vagrant-controlled VM



74
75
76
77
78
79
80
# File 'lib/testlab/providers/vagrant.rb', line 74

def down(*args)
  @state = nil
  arguments = (%W(halt #{self.instance_id}) + args).flatten.compact
  self.vagrant_cli(*arguments)

  true
end

#exists?Boolean

Does the Vagrant-controlled VM exist?

Returns:

  • (Boolean)


175
176
177
# File 'lib/testlab/providers/vagrant.rb', line 175

def exists?
  (self.state != :not_created)
end

#export(filename = nil) ⇒ Object

Export the Vagrant-controlled VM



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/testlab/providers/vagrant.rb', line 85

def export(filename=nil)
  tempfile = Tempfile.new('export')
  temppath = tempfile.path.dup
  tempfile.unlink
  File.exists?(temppath) or FileUtils.mkdir_p(temppath)

  labfile_source      = File.join(@config[:vagrant][:file], 'Labfile')
  labfile_destination = File.join(temppath, 'Labfile')

  image_name          = "lab.ova"
  image_location      = File.join(temppath, image_name)

  export_destination  = File.join(@config[:vagrant][:file], "#{self.instance_id}.lab")

  self.down
  self.vboxmanage_cli(%W(export #{self.instance_id} --output #{image_location}))
  FileUtils.cp(labfile_source, labfile_destination)

  Dir.chdir(temppath) do
    @command.exec(%(tar cvf #{export_destination} *))
  end

  FileUtils.rm_rf(temppath)
end

#hostnameObject

END CORE CONFIG



221
222
223
# File 'lib/testlab/providers/vagrant.rb', line 221

def hostname
  (@config[:vagrant][:hostname] || self.instance_id)
end

#identityObject



201
202
203
# File 'lib/testlab/providers/vagrant.rb', line 201

def identity
  (@config[:vagrant][:identity] || File.join(ENV['HOME'], ".vagrant.d", "insecure_private_key"))
end

#import(filename = nil) ⇒ Object

Import the Vagrant-controlled VM



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/testlab/providers/vagrant.rb', line 111

def import(filename=nil)
  filename = (filename || "#{self.instance_id}.lab")

  tempfile = Tempfile.new('export')
  temppath = tempfile.path.dup
  tempfile.unlink
  File.exists?(temppath) or FileUtils.mkdir_p(temppath)

  id_filename = File.join(@config[:vagrant][:file], ".vagrant", "machines", self.instance_id, "virtualbox", "id")
  FileUtils.mkdir_p(File.dirname(id_filename))

  labfile_source = File.join(temppath, 'Labfile')
  labfile_destination = File.join(@config[:vagrant][:file], 'Labfile')

  image_name  = "lab.ova"
  image_location = File.join(temppath, image_name)

  FileUtils.cp(filename, temppath)
  Dir.chdir(temppath) do
    @command.exec(%(tar xvf #{filename}))
  end

  self.destroy
  self.vboxmanage_cli(%W(import #{image_location} --vsys 0 --vmname #{self.instance_id} --vsys 0 --cpus #{self.cpus} --vsys 0 --memory #{self.memory}))
  uuid = self.vboxmanage_cli(%W(showvminfo #{self.instance_id} | grep UUID | head -1 | cut -f 2 -d ':')).output.strip

  @command.exec(%(echo '#{uuid}' > #{id_filename}))

  FileUtils.cp(labfile_source, labfile_destination)

  FileUtils.rm_rf(temppath)
end

#instance_idObject

START CORE CONFIG



192
193
194
195
# File 'lib/testlab/providers/vagrant.rb', line 192

def instance_id
  default_id = "#{TestLab.hostname}-#{@config[:node][:id]}-#{File.basename(@config[:vagrant][:file])}"
  (@config[:vagrant][:id] || default_id.downcase)
end

#ipObject



205
206
207
# File 'lib/testlab/providers/vagrant.rb', line 205

def ip
  (@config[:vagrant][:ip] || "192.168.33.#{last_octet}")
end

#last_octetObject



209
210
211
212
# File 'lib/testlab/providers/vagrant.rb', line 209

def last_octet
  crc32 = Zlib.crc32(self.instance_id)
  (crc32.modulo(254) + 1)
end

#memoryObject



237
238
239
# File 'lib/testlab/providers/vagrant.rb', line 237

def memory
  (@config[:vagrant][:memory] || (1024 * 2))
end

#portObject



214
215
216
# File 'lib/testlab/providers/vagrant.rb', line 214

def port
  (@config[:vagrant][:port] || 22)
end

#reloadObject

Reload Vagrant-controlled VM



147
148
149
150
151
152
# File 'lib/testlab/providers/vagrant.rb', line 147

def reload
  self.down
  self.up

  true
end

#render_vagrantfileObject



291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/testlab/providers/vagrant.rb', line 291

def render_vagrantfile
  context = {
    :id => self.instance_id,
    :ip => self.ip,
    :hostname => self.hostname,
    :user => self.user,
    :port => self.port,
    :cpus => self.cpus,
    :memory => self.memory,
    :resize => self.resize,
    :box => self.box,
    :box_url => self.box_url,
    :synced_folders => self.synced_folders
  }

  vagrantfile_template = File.join(TestLab::Provider.template_dir, "vagrant", "Vagrantfile.erb")
  vagrantfile          = File.join(@config[:vagrant][:file], "Vagrantfile")

  File.open(vagrantfile, 'w') do |file|
    file.puts(ZTK::Template.render(vagrantfile_template, context))
  end
end

#resizeObject



241
242
243
# File 'lib/testlab/providers/vagrant.rb', line 241

def resize
  (@config[:vagrant][:resize] || (1024 * 16))
end

#stateObject

Inquire the state of the Vagrant-controlled VM



157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/testlab/providers/vagrant.rb', line 157

def state
  if @state.nil?
    output = self.vagrant_cli("status").output.split("\n").select{ |line| (line =~ /#{self.instance_id}/) }.first
    result = UNKNOWN_STATE
    ALL_STATES.map{ |s| s.to_s.gsub('_', ' ') }.each do |state|
      if output =~ /#{state}/
        result = state.to_s.gsub(' ', '_')
        break
      end
    end
    @state = result.to_sym
  end
  @state
end

#synced_foldersObject



245
246
247
# File 'lib/testlab/providers/vagrant.rb', line 245

def synced_folders
  (@config[:vagrant][:synced_folders] || nil)
end

#upObject

Online Vagrant-controlled VM



64
65
66
67
68
69
70
71
# File 'lib/testlab/providers/vagrant.rb', line 64

def up
  @state = nil
  self.vagrant_cli("up", self.instance_id)

  ZTK::TCPSocketCheck.new(:host => self.ip, :port => self.port, :wait => 120, :ui => @ui).wait

  true
end

#userObject



197
198
199
# File 'lib/testlab/providers/vagrant.rb', line 197

def user
  (@config[:vagrant][:user] || "vagrant")
end

#vagrant_cli(*args) ⇒ Object



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/testlab/providers/vagrant.rb', line 251

def vagrant_cli(*args)
  @ui.logger.debug { "args == #{args.inspect}" }

  command = TestLab.build_command_line("vagrant", *args)
  @ui.logger.debug { "command == #{command.inspect}" }

  render_vagrantfile
  result = @command.exec(command)

  if result.exit_code != 0
    @ui.stderr.puts
    @ui.stderr.puts
    @ui.stderr.puts(result.output)

    raise VagrantError, "Vagrant failed to execute!"
  end

  result
end

#vboxmanage_cli(*args) ⇒ Object



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/testlab/providers/vagrant.rb', line 271

def vboxmanage_cli(*args)
  @ui.logger.debug { "args == #{args.inspect}" }

  command = TestLab.build_command_line("VBoxManage", *args)
  @ui.logger.debug { "command == #{command.inspect}" }

  render_vagrantfile
  result = @command.exec(command)

  if result.exit_code != 0
    @ui.stderr.puts
    @ui.stderr.puts
    @ui.stderr.puts(result.output)

    raise VagrantError, "VBoxManage failed to execute!"
  end

  result
end