tenderloin 0.3.0 → 0.4.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/config/default.rb CHANGED
@@ -6,6 +6,8 @@ Tenderloin::Config.run do |config|
6
6
 
7
7
  config.ssh.username = "tenderloin"
8
8
  config.ssh.password = "tenderloin"
9
+ config.ssh.key = nil
10
+ config.ssh.port = 22
9
11
  # config.ssh.host = "localhost"
10
12
  config.ssh.max_tries = 10
11
13
  config.ssh.timeout = 30
@@ -18,6 +20,7 @@ Tenderloin::Config.run do |config|
18
20
 
19
21
  config.provisioning.script = nil
20
22
  config.provisioning.command = nil
23
+ config.provisioning.rsync = []
21
24
 
22
25
  config.shared_folders.enabled = true
23
26
  config.shared_folders.folders = []
@@ -15,6 +15,7 @@ module Tenderloin
15
15
 
16
16
  @runner.add_action(Download)
17
17
  @runner.add_action(Unpackage)
18
+ @runner.add_action(Convert)
18
19
  end
19
20
  end
20
21
  end
@@ -0,0 +1,42 @@
1
+ module Tenderloin
2
+ module Actions
3
+ module Box
4
+ # If the box is vagrant format, it converts it to something suitible for tenderloin
5
+ class Convert < Base
6
+
7
+ def execute!
8
+ if !Dir[@runner.directory + '/Tenderfile'].empty?
9
+ # We can do nothing - pretenderized
10
+ logger.info "Tenderloin box provided"
11
+ elsif !Dir[@runner.directory + '/Vagrantfile'].empty?
12
+ # Need to import from Vagrant. Convert the ovf to vmx using OVFtool, then write a base tenderfile
13
+ logger.info "Vagrant box provided, converting"
14
+ convert_ovf
15
+ write_tenderfile
16
+ logger.info "Vagrant box converted. It has a basic Tenderfile, you may want to customize this if needed"
17
+ logger.info "This file can be found in #{@runner.directory}"
18
+ else
19
+ raise "Invalid box - No Tenderfile or Vagrantfile"
20
+ end
21
+ end
22
+
23
+ def convert_ovf
24
+ ovf = File.join(@runner.directory, 'box.ovf')
25
+ vmx = File.join(@runner.directory, 'vmwarebox.vmx')
26
+ OVFTool.ovf2vmx(ovf, vmx, :lax => true)
27
+ FileUtils.rm_rf(@runner.directory)
28
+ FileUtils.mv(@runner.directory + ".vmwarevm", @runner.directory)
29
+ end
30
+
31
+ def write_tenderfile
32
+ tenderfile = <<EOF
33
+ Tenderloin::Config.run do |config|
34
+ config.vm.box_vmx = "vmwarebox.vmx"
35
+ end
36
+ EOF
37
+ File.open(File.join(@runner.directory, 'Tenderfile'), 'w') {|f| f.write(tenderfile) }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -3,10 +3,22 @@ module Tenderloin
3
3
  module VM
4
4
  class Provision < Base
5
5
  def execute!
6
+ run_rsync if Tenderloin.config.provisioning.rsync
6
7
  setup_script if Tenderloin.config.provisioning.script
7
8
  run_command if Tenderloin.config.provisioning.command
8
9
  end
9
10
 
11
+ def run_rsync
12
+ logger.info "Running rsync..."
13
+ Tenderloin.config.provisioning.rsync.each do |rsync|
14
+ src, dst = *rsync
15
+ SSH.execute(@runner.fusion_vm.ip) do |ssh|
16
+ ssh.exec!("mkdir -p #{dst}")
17
+ end
18
+ logger.info SSH.rsync(@runner.fusion_vm.ip, File.expand_path(src), File.expand_path(dst))
19
+ end
20
+ end
21
+
10
22
  def setup_script
11
23
  logger.info "Uploading provisioning script..."
12
24
 
@@ -1,3 +1,5 @@
1
+ require 'timeout'
2
+
1
3
  module Tenderloin
2
4
  module Actions
3
5
  module VM
@@ -29,8 +31,14 @@ module Tenderloin
29
31
  logger.info "Creating shared folders metadata..."
30
32
 
31
33
  shared_folders.each do |name, hostpath, guestpath|
32
- @runner.fusion_vm.share_folder(name, File.expand_path(hostpath))
33
- @runner.fusion_vm.enable_shared_folders
34
+ begin
35
+ status = Timeout::timeout(10) {
36
+ @runner.fusion_vm.share_folder(name, File.expand_path(hostpath))
37
+ @runner.fusion_vm.enable_shared_folders
38
+ }
39
+ rescue Timeout::Error
40
+ logger.warn "Sharing folder #{name} timed out"
41
+ end
34
42
  end
35
43
 
36
44
  logger.info "Linking shared folders..."
@@ -16,6 +16,7 @@ msg
16
16
 
17
17
  # Up is a "meta-action" so it really just queues up a bunch
18
18
  # of other actions in its place:
19
+ Tenderloin::Box.add(Tenderloin.config.vm.box, Tenderloin.config.vm.box_url) unless Tenderloin::Env.box
19
20
  steps = [Import, SharedFolders, Boot]
20
21
  steps << Provision if Tenderloin.config.provisioning.enabled
21
22
  steps.insert(0, MoveHardDrive) if Tenderloin.config.vm.hd_location
@@ -46,6 +47,7 @@ msg
46
47
  data.delete "ethernet1.generatedAddress"
47
48
  data.delete "ethernet0.generatedAddressOffset"
48
49
  data.delete "ethernet1.generatedAddressOffset"
50
+ data.delete 'displayname'
49
51
  data['displayName'] = "tenderloin-" + @runner.vm_id
50
52
  end
51
53
  end
@@ -72,7 +72,7 @@ error
72
72
  def ssh
73
73
  Env.load!
74
74
  Env.require_persisted_vm
75
- SSH.connect :host => Env.persisted_vm.fusion_vm.ip
75
+ SSH.connect Env.persisted_vm.fusion_vm.ip
76
76
  end
77
77
 
78
78
  # Halts a running tenderloin instance. This forcibly halts the instance;
@@ -59,10 +59,13 @@ module Tenderloin
59
59
  attr_accessor :host
60
60
  attr_accessor :max_tries
61
61
  attr_accessor :timeout
62
+ attr_accessor :key
63
+ attr_accessor :port
62
64
  end
63
65
 
64
66
  class VMConfig < Base
65
67
  attr_accessor :box
68
+ attr_accessor :box_url
66
69
  attr_accessor :box_vmx
67
70
  attr_accessor :project_directory
68
71
  attr_accessor :hd_location
@@ -99,8 +102,9 @@ module Tenderloin
99
102
  class ProvisioningConfig
100
103
  attr_accessor :script
101
104
  attr_accessor :command
105
+ attr_accessor :rsync
102
106
  def enabled
103
- script || command
107
+ script || command || !rsync.empty?
104
108
  end
105
109
  end
106
110
 
@@ -11,11 +11,14 @@ module Tenderloin
11
11
  extend Tenderloin::Util
12
12
 
13
13
  class << self
14
- def box; @@box; end
14
+ def box
15
+ load_box! unless @@box
16
+ @@box
17
+ end
15
18
  def persisted_vm; @@persisted_vm; end
16
19
  def root_path; @@root_path; end
17
20
  def dotfile_path
18
- File.join(root_path, $ROOTFILE_NAME + ".loinstate")
21
+ File.join(root_path, "." + $ROOTFILE_NAME + ".loinstate")
19
22
  end
20
23
  def home_path; File.expand_path(Tenderloin.config.tenderloin.home); end
21
24
  def tmp_path; File.join(home_path, "tmp"); end
@@ -127,7 +130,7 @@ No base box was specified! A base box is required as a staring point
127
130
  for every tenderloin virtual machine. Please specify one in your Tenderfile
128
131
  using `config.vm.box`
129
132
  msg
130
- else
133
+ elsif !Tenderloin.config.vm.box_url
131
134
  error_and_exit(<<-msg)
132
135
  Specified box `#{Tenderloin.config.vm.box}` does not exist!
133
136
 
@@ -0,0 +1,21 @@
1
+ module Tenderloin
2
+ class OVFTool
3
+ TOOL = "/Applications/VMware\\ Fusion.app//Contents/Library/VMware\\ OVF\\ Tool/ovftool"
4
+
5
+ def self.run(cmd, opts = '')
6
+ res = `#{TOOL} #{opts} #{cmd}`
7
+ if $? == 0
8
+ return res
9
+ else
10
+ raise "Error running ovftool command #{cmd}: " + res
11
+ end
12
+ end
13
+
14
+ def self.ovf2vmx(ovf, vmx, opts = {})
15
+ cmd_opts = []
16
+ cmd_opts << '--lax' if opts[:lax]
17
+ run("#{cmd_opts.join(' ')} #{ovf} #{vmx}")
18
+ end
19
+
20
+ end
21
+ end
@@ -3,17 +3,16 @@ module Tenderloin
3
3
  SCRIPT = File.join(File.dirname(__FILE__), '..', '..', 'script', 'tenderloin-ssh-expect.sh')
4
4
 
5
5
  class << self
6
- def connect(opts={})
7
- options = {}
8
- [:host, :password, :username].each do |param|
9
- options[param] = opts[param] || Tenderloin.config.ssh.send(param)
6
+ def connect(ip)
7
+ if options.key
8
+ Kernel.exec "#{cmd_ssh_opts} #{options.username}@#{ip}"
9
+ else
10
+ Kernel.exec cmd_ssh_opts.strip
10
11
  end
11
-
12
- Kernel.exec "#{SCRIPT} #{options[:username]} #{options[:password]} #{options[:host]} #{port(opts)}".strip
13
12
  end
14
13
 
15
14
  def execute(ip)
16
- Net::SSH.start(ip, Tenderloin.config[:ssh][:username], :port => port, :password => Tenderloin.config[:ssh][:password]) do |ssh|
15
+ Net::SSH.start(ip, Tenderloin.config[:ssh][:username], net_ssh_opts) do |ssh|
17
16
  yield ssh
18
17
  end
19
18
  end
@@ -25,11 +24,16 @@ module Tenderloin
25
24
  end
26
25
  end
27
26
 
27
+ def rsync(ip,src,dst)
28
+ cmd = "rsync -avz --delete -e \"#{cmd_ssh_opts}\" #{src} #{options.username}@#{ip}:#{dst}"
29
+ `#{cmd}`
30
+ end
31
+
28
32
  def up?(ip)
29
33
  check_thread = Thread.new do
30
34
  begin
31
35
  Thread.current[:result] = false
32
- Net::SSH.start(ip, Tenderloin.config.ssh.username, :port => port, :password => Tenderloin.config.ssh.password, :timeout => Tenderloin.config.ssh.timeout) do |ssh|
36
+ Net::SSH.start(ip, Tenderloin.config.ssh.username, net_ssh_opts) do |ssh|
33
37
  Thread.current[:result] = true
34
38
  end
35
39
  rescue Errno::ECONNREFUSED, Net::SSH::Disconnect
@@ -41,8 +45,25 @@ module Tenderloin
41
45
  return check_thread[:result]
42
46
  end
43
47
 
44
- def port(opts={})
45
- opts[:port] || 22
48
+ def options
49
+ Tenderloin.config.ssh
50
+ end
51
+
52
+ def cmd_ssh_opts
53
+ if options.key
54
+ "ssh -i #{options.key} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p #{options.port}"
55
+ else
56
+ "#{SCRIPT} #{options.username} #{options.password} #{options.host} #{options.port}".strip
57
+ end
58
+ end
59
+
60
+ def net_ssh_opts
61
+ opts = {}
62
+ opts[:port] = Tenderloin.config.ssh.port
63
+ opts[:password] = Tenderloin.config.ssh.password
64
+ opts[:timeout] = Tenderloin.config.ssh.timeout
65
+ opts[:keys] = [Tenderloin.config[:ssh][:key]] if Tenderloin.config[:ssh][:key]
66
+ opts
46
67
  end
47
68
  end
48
69
  end
data/templates/Tenderfile CHANGED
@@ -5,19 +5,27 @@ Tenderloin::Config.run do |config|
5
5
 
6
6
  # Every Tenderloin virtual environment requires a box to build off of.
7
7
  config.vm.box = "base"
8
+ # You can optionally specify a path or URL to automatically retrieve it from
9
+ # config.vm.box_url = "http://download"
8
10
 
9
11
  ## SSH username and password defaults to 'tenderloin'. You can change this.
12
+ ## If you provide a key, this will be used over the password
10
13
  # config.ssh.username = 'youruser'
11
14
  # config.ssh.password = 'yourpass'
15
+ # config.ssh.key = '~/.ssh/id_rsa'
12
16
 
13
- ## Provisioning can either provide a shell script, or a command to execute
17
+ ## Provisioning can either provide a shell script, or a command to execute.
18
+ ## You can also provide folders to rsync (over SSH)
14
19
  # config.provisioning.script = <<EOF
15
20
  # ls /usr
16
21
  # EOF
17
22
  # config.provisioning.command = "apt-get install -y ruby"
23
+ ## This is destructive - it uses the --delete flag
24
+ # config.provisioning.rsync << ["src/", "dst"]
18
25
 
19
26
  ## Shared folders are enabled by default, and the project dir is always shared
20
27
  ## You can turn this off, or add additional folders
21
28
  # config.shared_folders.enabled = false
22
- # config.shared_folders.folders = [[["my-files", "src", "/mnt/src"], ["bin-files", "bin", "/mnt/bin"]
29
+ # config.shared_folders.folders << ["my-files", "src", "/mnt/src"]
30
+ # config.shared_folders.folders << ["bin-files", "bin", "/mnt/bin"]
23
31
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tenderloin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -108,6 +108,7 @@ extra_rdoc_files:
108
108
  files:
109
109
  - lib/tenderloin/actions/base.rb
110
110
  - lib/tenderloin/actions/box/add.rb
111
+ - lib/tenderloin/actions/box/convert.rb
111
112
  - lib/tenderloin/actions/box/destroy.rb
112
113
  - lib/tenderloin/actions/box/download.rb
113
114
  - lib/tenderloin/actions/box/unpackage.rb
@@ -132,6 +133,7 @@ files:
132
133
  - lib/tenderloin/downloaders/http.rb
133
134
  - lib/tenderloin/env.rb
134
135
  - lib/tenderloin/fusion_vm.rb
136
+ - lib/tenderloin/ovftool.rb
135
137
  - lib/tenderloin/ssh.rb
136
138
  - lib/tenderloin/util.rb
137
139
  - lib/tenderloin/vm.rb