tenderloin 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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