tenderloin 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +24 -3
- data/lib/tenderloin/cli.rb +12 -0
- data/lib/tenderloin/commands.rb +20 -0
- data/lib/tenderloin/config.rb +22 -2
- data/lib/tenderloin/downloaders/file.rb +2 -2
- data/lib/tenderloin/fusion_vm.rb +13 -4
- data/lib/tenderloin/ssh.rb +5 -4
- data/lib/tenderloin/util.rb +13 -6
- data/templates/Tenderfile +2 -0
- metadata +1 -1
data/README.md
CHANGED
@@ -5,7 +5,7 @@ Tenderloin is a tool for building and distributing virtualized development envir
|
|
5
5
|
It is based on [Vagrant](http://vagrantup.com), specifically the 0.1.4 release. This was
|
6
6
|
the simplest, and provided a good starting point
|
7
7
|
|
8
|
-
It is designed to use VMWare Fusion as the underlying provider.
|
8
|
+
It is designed to use VMWare Fusion as the underlying provider. It has only been tested with Version 5. In theory this should be adaptable easily to VMWare workstation on other platforms, by updating the path to vmrun/the DHCP config.
|
9
9
|
|
10
10
|
Features:
|
11
11
|
|
@@ -21,14 +21,35 @@ Features:
|
|
21
21
|
To build your first virtual environment:
|
22
22
|
|
23
23
|
loin init
|
24
|
-
|
24
|
+
# Warning! I'm 2gb's and un-optimized
|
25
|
+
loin box add base http://s3.lstoll.net/tenderloin/precise64.box
|
25
26
|
loin up
|
26
27
|
|
27
28
|
The file describing your VM is called 'Tenderfile', but you can optionally change this with
|
28
|
-
the -f flag, to allow multiple VM descriptions in the same place.
|
29
|
+
the -f flag, to allow multiple VM descriptions in the same place, e.g `loin up -f esxi.loin`
|
30
|
+
|
31
|
+
## Using Vagrant Boxes.
|
32
|
+
|
33
|
+
You can reference vagrant boxes directly, and the importer will convert them to native VMWare. The imported VM won't have additions installed, so you won't be able to use shared folders.
|
34
|
+
|
35
|
+
## Provisioning
|
36
|
+
|
37
|
+
Provisioning is either via a shell script, or by launching a command directly. Chef and Puppet provisioning isn't natively supported - if you wish to use these you will need to write your own launcher script.
|
38
|
+
|
39
|
+
You can also set up paths to rsync using the provisioner, these wil be synced with --delete before the proisioning script/command runs. This is useful for machines that don't have the additions installed, and avoids using shared folders
|
40
|
+
|
41
|
+
## Tenderfile
|
42
|
+
|
43
|
+
You can [view the template](tenderloin/tree/master/templates/Tenderfile) to see all available options.
|
44
|
+
|
45
|
+
## Project status
|
46
|
+
|
47
|
+
This project is currently still in a pretty raw state. It is a quick hack to see how it would work, and to directly achieve a goal. The tests are broken, and the code might still be rough. I am currently using it on a daily basis though, so it's definitely usable.
|
29
48
|
|
30
49
|
## Building base boxes
|
31
50
|
|
51
|
+
*Note:* [Veewee](https://github.com/jedi4ever/veewee) supports building bases boxes with VMWare. The VMDK from this can be used in a Tenderloin box. More automation around this coming soon!
|
52
|
+
|
32
53
|
Currently base boxes are built manually. The process:
|
33
54
|
|
34
55
|
* Create image in Fusion
|
data/lib/tenderloin/cli.rb
CHANGED
@@ -61,5 +61,17 @@ module Tenderloin
|
|
61
61
|
Tenderloin::Commands.ssh
|
62
62
|
end
|
63
63
|
|
64
|
+
desc "ip [--file <tenderfile>]", "Shows the IP to access the VM"
|
65
|
+
def ip()
|
66
|
+
setup
|
67
|
+
Tenderloin::Commands.show_ip
|
68
|
+
end
|
69
|
+
|
70
|
+
desc "jsondump [--file <tenderfile>]", "Dumps a JSON representation of the VM"
|
71
|
+
def jsondump
|
72
|
+
setup
|
73
|
+
Tenderloin::Commands.json_dump
|
74
|
+
end
|
75
|
+
|
64
76
|
end
|
65
77
|
end
|
data/lib/tenderloin/commands.rb
CHANGED
@@ -150,6 +150,26 @@ error
|
|
150
150
|
Env.persisted_vm.execute!(Actions::VM::Provision)
|
151
151
|
end
|
152
152
|
|
153
|
+
# Gets the IP
|
154
|
+
def show_ip
|
155
|
+
Env.load!
|
156
|
+
Env.require_persisted_vm
|
157
|
+
puts Env.persisted_vm.fusion_vm.ip
|
158
|
+
end
|
159
|
+
|
160
|
+
def json_dump
|
161
|
+
# Bump log level, don't want other output
|
162
|
+
Tenderloin::Logger.set_level Logger::ERROR
|
163
|
+
Env.load!
|
164
|
+
ret = {:config => Tenderloin.config.to_hash}
|
165
|
+
if Env.persisted_vm
|
166
|
+
ret[:vm] = Env.persisted_vm.fusion_vm.to_hash
|
167
|
+
else
|
168
|
+
ret[:vm] = {:running => false}
|
169
|
+
end
|
170
|
+
puts ret.to_json
|
171
|
+
end
|
172
|
+
|
153
173
|
private
|
154
174
|
|
155
175
|
def act_on_vm(&block)
|
data/lib/tenderloin/config.rb
CHANGED
@@ -60,6 +60,12 @@ module Tenderloin
|
|
60
60
|
attr_accessor :max_tries
|
61
61
|
attr_accessor :timeout
|
62
62
|
attr_accessor :key
|
63
|
+
def keys=(keys)
|
64
|
+
@keys=keys
|
65
|
+
end
|
66
|
+
def keys
|
67
|
+
@keys || (key ? [key] : nil)
|
68
|
+
end
|
63
69
|
attr_accessor :port
|
64
70
|
end
|
65
71
|
|
@@ -99,7 +105,7 @@ module Tenderloin
|
|
99
105
|
end
|
100
106
|
end
|
101
107
|
|
102
|
-
class ProvisioningConfig
|
108
|
+
class ProvisioningConfig < Base
|
103
109
|
attr_accessor :script
|
104
110
|
attr_accessor :command
|
105
111
|
attr_accessor :rsync
|
@@ -108,7 +114,7 @@ module Tenderloin
|
|
108
114
|
end
|
109
115
|
end
|
110
116
|
|
111
|
-
class SharedFoldersConfig
|
117
|
+
class SharedFoldersConfig < Base
|
112
118
|
attr_accessor :enabled
|
113
119
|
attr_accessor :folders
|
114
120
|
end
|
@@ -139,6 +145,20 @@ module Tenderloin
|
|
139
145
|
def loaded!
|
140
146
|
@loaded = true
|
141
147
|
end
|
148
|
+
|
149
|
+
def to_hash
|
150
|
+
hsh = Tenderloin.config.instance_variables_hash
|
151
|
+
hsh.delete(:tenderloin)
|
152
|
+
hsh = hsh.inject({}) do |h, (k, iv)|
|
153
|
+
if iv.class.to_s =~ /Tenderloin::Config/
|
154
|
+
h[k] = iv.instance_variables_hash
|
155
|
+
else
|
156
|
+
h[k] = iv
|
157
|
+
end
|
158
|
+
h
|
159
|
+
end
|
160
|
+
hsh
|
161
|
+
end
|
142
162
|
end
|
143
163
|
end
|
144
164
|
end
|
@@ -9,7 +9,7 @@ module Tenderloin
|
|
9
9
|
# For now we read the contents of one into a buffer
|
10
10
|
# and copy it into the other. In the future, we should do
|
11
11
|
# a system-level file copy (FileUtils.cp).
|
12
|
-
open(source_url) do |f|
|
12
|
+
open(::File.expand_path(source_url)) do |f|
|
13
13
|
loop do
|
14
14
|
break if f.eof?
|
15
15
|
destination_file.write(f.read(BUFFERSIZE))
|
@@ -18,4 +18,4 @@ module Tenderloin
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|
data/lib/tenderloin/fusion_vm.rb
CHANGED
@@ -7,16 +7,19 @@ module Tenderloin
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def run(cmd, opts='')
|
10
|
+
runcmd = "#{VMRUN} #{cmd} #{@vmx} #{opts}"
|
10
11
|
retrycount = 0
|
11
12
|
while true
|
12
|
-
res = `#{
|
13
|
+
res = `#{runcmd}`
|
13
14
|
if $? == 0
|
14
15
|
return res
|
16
|
+
elsif res =~ /The virtual machine is not powered on/
|
17
|
+
return
|
15
18
|
else
|
16
19
|
if res =~ /VMware Tools are not running/
|
17
20
|
sleep 1; next unless retrycount > 10
|
18
21
|
end
|
19
|
-
raise "Error running vmrun command
|
22
|
+
raise "Error running vmrun command:\n#{runcmd}\nResponse: " + res
|
20
23
|
end
|
21
24
|
end
|
22
25
|
end
|
@@ -50,8 +53,10 @@ module Tenderloin
|
|
50
53
|
end
|
51
54
|
|
52
55
|
def ip
|
53
|
-
ip = get_guest_var('ip')
|
54
|
-
|
56
|
+
ip = get_guest_var('ip')
|
57
|
+
if ip && ip.strip =~ /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/
|
58
|
+
ip = ip.strip
|
59
|
+
else
|
55
60
|
mac_address = VMXFile.load(@vmx)["ethernet0.generatedAddress"]
|
56
61
|
ip = dhcp_leases[mac_address]
|
57
62
|
end
|
@@ -86,5 +91,9 @@ module Tenderloin
|
|
86
91
|
end
|
87
92
|
mac_ip
|
88
93
|
end
|
94
|
+
|
95
|
+
def to_hash
|
96
|
+
{:ip => ip, :running => running?}
|
97
|
+
end
|
89
98
|
end
|
90
99
|
end
|
data/lib/tenderloin/ssh.rb
CHANGED
@@ -4,7 +4,7 @@ module Tenderloin
|
|
4
4
|
|
5
5
|
class << self
|
6
6
|
def connect(ip)
|
7
|
-
if options.
|
7
|
+
if options.keys
|
8
8
|
Kernel.exec "#{cmd_ssh_opts} #{options.username}@#{ip}"
|
9
9
|
else
|
10
10
|
Kernel.exec cmd_ssh_opts(ip).strip
|
@@ -50,8 +50,9 @@ module Tenderloin
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def cmd_ssh_opts(ip=nil)
|
53
|
-
if options.
|
54
|
-
|
53
|
+
if options.keys
|
54
|
+
keyopts = options.keys.map {|k| "-i #{File.expand_path(k)}"}.join(' ')
|
55
|
+
"ssh #{keyopts} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p #{options.port}"
|
55
56
|
else
|
56
57
|
"#{SCRIPT} #{options.username} #{options.password} #{options.host || ip} #{options.port}".strip
|
57
58
|
end
|
@@ -62,7 +63,7 @@ module Tenderloin
|
|
62
63
|
opts[:port] = Tenderloin.config.ssh.port
|
63
64
|
opts[:password] = Tenderloin.config.ssh.password
|
64
65
|
opts[:timeout] = Tenderloin.config.ssh.timeout
|
65
|
-
opts[:keys] =
|
66
|
+
opts[:keys] = Tenderloin.config[:ssh][:keys] if Tenderloin.config[:ssh][:keys]
|
66
67
|
opts
|
67
68
|
end
|
68
69
|
end
|
data/lib/tenderloin/util.rb
CHANGED
@@ -27,15 +27,23 @@ error
|
|
27
27
|
|
28
28
|
class Logger < ::Logger
|
29
29
|
@@singleton_logger = nil
|
30
|
+
@@level = Logger::INFO
|
30
31
|
|
31
32
|
class << self
|
33
|
+
def set_level(level)
|
34
|
+
@@singleton_logger.level = level if @@singleton_logger
|
35
|
+
@@level = level
|
36
|
+
end
|
37
|
+
|
32
38
|
def singleton_logger
|
33
39
|
# TODO: Buffer messages until config is loaded, then output them?
|
34
|
-
if Tenderloin.config.loaded?
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
40
|
+
logger = if Tenderloin.config.loaded?
|
41
|
+
@@singleton_logger ||= Tenderloin::Logger.new(Tenderloin.config.tenderloin.log_output)
|
42
|
+
else
|
43
|
+
Tenderloin::Logger.new(nil)
|
44
|
+
end
|
45
|
+
logger.level = @@level
|
46
|
+
logger
|
39
47
|
end
|
40
48
|
|
41
49
|
def reset_logger!
|
@@ -48,4 +56,3 @@ error
|
|
48
56
|
end
|
49
57
|
end
|
50
58
|
end
|
51
|
-
|
data/templates/Tenderfile
CHANGED
@@ -13,6 +13,8 @@ Tenderloin::Config.run do |config|
|
|
13
13
|
# config.ssh.username = 'youruser'
|
14
14
|
# config.ssh.password = 'yourpass'
|
15
15
|
# config.ssh.key = '~/.ssh/id_rsa'
|
16
|
+
## SSH key can also be an array of keys
|
17
|
+
# config.ssh.keys = ['~/.ssh/id_rsa', '~/.ssh/id_rsa_other']
|
16
18
|
|
17
19
|
## Provisioning can either provide a shell script, or a command to execute.
|
18
20
|
## You can also provide folders to rsync (over SSH)
|