jamie 0.1.0.alpha8 → 0.1.0.alpha9
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/jamie.gemspec +2 -0
- data/lib/jamie/driver/vagrant.rb +20 -33
- data/lib/jamie/vagrant.rb +2 -16
- data/lib/jamie/version.rb +1 -1
- data/lib/jamie.rb +341 -16
- metadata +37 -2
data/jamie.gemspec
CHANGED
data/lib/jamie/driver/vagrant.rb
CHANGED
@@ -9,58 +9,45 @@ module Jamie
|
|
9
9
|
module Driver
|
10
10
|
|
11
11
|
# Vagrant driver for Jamie. It communicates to Vagrant via the CLI.
|
12
|
-
class Vagrant < Jamie::Driver::
|
12
|
+
class Vagrant < Jamie::Driver::SSHBase
|
13
13
|
|
14
14
|
default_config 'memory', '256'
|
15
15
|
|
16
|
-
def
|
17
|
-
|
16
|
+
def perform_create(instance, state)
|
17
|
+
state['name'] = instance.name
|
18
|
+
run "vagrant up #{state['name']} --no-provision"
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
-
run "vagrant provision #{
|
21
|
+
def perform_converge(instance, state)
|
22
|
+
run "vagrant provision #{state['name']}"
|
22
23
|
end
|
23
24
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
else
|
28
|
-
super
|
29
|
-
end
|
25
|
+
def perform_destroy(instance, state)
|
26
|
+
run "vagrant destroy #{state['name']} -f"
|
27
|
+
state.delete('name')
|
30
28
|
end
|
31
29
|
|
32
|
-
|
33
|
-
if instance.jr.run_cmd
|
34
|
-
ssh instance, instance.jr.sync_cmd
|
35
|
-
ssh instance, instance.jr.run_cmd
|
36
|
-
else
|
37
|
-
super
|
38
|
-
end
|
39
|
-
end
|
30
|
+
protected
|
40
31
|
|
41
|
-
def
|
42
|
-
|
32
|
+
def generate_ssh_args(state)
|
33
|
+
Array(state['name'])
|
43
34
|
end
|
44
35
|
|
45
|
-
|
36
|
+
def ssh(ssh_args, cmd)
|
37
|
+
run %{vagrant ssh #{ssh_args.first} --command '#{cmd}'}
|
38
|
+
end
|
46
39
|
|
47
40
|
def run(cmd)
|
48
41
|
puts " [vagrant command] '#{display_cmd(cmd)}'"
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
"in #{shellout.execution_time} seconds."
|
55
|
-
shellout.error!
|
42
|
+
sh = Mixlib::ShellOut.new(cmd, :live_stream => STDOUT,
|
43
|
+
:timeout => 60000)
|
44
|
+
sh.run_command
|
45
|
+
puts " [vagrant command] ran in #{sh.execution_time} seconds."
|
46
|
+
sh.error!
|
56
47
|
rescue Mixlib::ShellOut::ShellCommandFailed => ex
|
57
48
|
raise ActionFailed, ex.message
|
58
49
|
end
|
59
50
|
|
60
|
-
def ssh(instance, cmd)
|
61
|
-
run %{vagrant ssh #{instance.name} --command '#{cmd}'}
|
62
|
-
end
|
63
|
-
|
64
51
|
def display_cmd(cmd)
|
65
52
|
parts = cmd.partition("\n")
|
66
53
|
parts[1] == "\n" ? "#{parts[0]}..." : cmd
|
data/lib/jamie/vagrant.rb
CHANGED
@@ -45,25 +45,11 @@ module Jamie
|
|
45
45
|
c.vm.provision :chef_solo do |chef|
|
46
46
|
chef.log_level = config.jamie.log_level
|
47
47
|
chef.run_list = instance.run_list
|
48
|
-
chef.json = instance.
|
49
|
-
chef.data_bags_path =
|
48
|
+
chef.json = instance.attributes
|
49
|
+
chef.data_bags_path = instance.suite.data_bags_path
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
54
|
-
def self.calculate_data_bags_path(config, instance)
|
55
|
-
base_path = config.jamie.test_base_path
|
56
|
-
instance_data_bags_path = File.join(base_path, instance.name, "data_bags")
|
57
|
-
common_data_bags_path = File.join(base_path, "data_bags")
|
58
|
-
|
59
|
-
if File.directory?(instance_data_bags_path)
|
60
|
-
instance_data_bags_path
|
61
|
-
elsif File.directory?(common_data_bags_path)
|
62
|
-
common_data_bags_path
|
63
|
-
else
|
64
|
-
nil
|
65
|
-
end
|
66
|
-
end
|
67
53
|
end
|
68
54
|
end
|
69
55
|
|
data/lib/jamie/version.rb
CHANGED
data/lib/jamie.rb
CHANGED
@@ -3,7 +3,14 @@
|
|
3
3
|
require 'base64'
|
4
4
|
require 'delegate'
|
5
5
|
require 'digest'
|
6
|
+
require 'fileutils'
|
7
|
+
require 'json'
|
8
|
+
require 'mixlib/shellout'
|
6
9
|
require 'net/https'
|
10
|
+
require 'net/scp'
|
11
|
+
require 'net/ssh'
|
12
|
+
require 'socket'
|
13
|
+
require 'stringio'
|
7
14
|
require 'yaml'
|
8
15
|
require 'vendor/hash_recursive_merge'
|
9
16
|
|
@@ -51,7 +58,7 @@ module Jamie
|
|
51
58
|
# convergence integration
|
52
59
|
def suites
|
53
60
|
@suites ||= Collection.new(
|
54
|
-
Array(yaml["suites"]).map { |hash|
|
61
|
+
Array(yaml["suites"]).map { |hash| new_suite(hash) })
|
55
62
|
end
|
56
63
|
|
57
64
|
# @return [Array<Instance>] all instances, resulting from all platform and
|
@@ -113,8 +120,14 @@ module Jamie
|
|
113
120
|
|
114
121
|
private
|
115
122
|
|
123
|
+
def new_suite(hash)
|
124
|
+
data_bags_path = calculate_data_bags_path(hash['name'])
|
125
|
+
Suite.new(hash.rmerge({ 'data_bags_path' => data_bags_path }))
|
126
|
+
end
|
127
|
+
|
116
128
|
def new_platform(hash)
|
117
129
|
mpc = merge_platform_config(hash)
|
130
|
+
mpc['driver_config']['jamie_root'] = File.dirname(yaml_file)
|
118
131
|
mpc['driver'] = new_driver(mpc['driver_plugin'], mpc['driver_config'])
|
119
132
|
Platform.new(mpc)
|
120
133
|
end
|
@@ -146,6 +159,19 @@ module Jamie
|
|
146
159
|
default_driver_config.rmerge(common_driver_config.rmerge(platform_config))
|
147
160
|
end
|
148
161
|
|
162
|
+
def calculate_data_bags_path(suite_name)
|
163
|
+
suite_data_bags_path = File.join(test_base_path, suite_name, "data_bags")
|
164
|
+
common_data_bags_path = File.join(test_base_path, "data_bags")
|
165
|
+
|
166
|
+
if File.directory?(suite_data_bags_path)
|
167
|
+
suite_data_bags_path
|
168
|
+
elsif File.directory?(common_data_bags_path)
|
169
|
+
common_data_bags_path
|
170
|
+
else
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
149
175
|
def default_driver_config
|
150
176
|
{ 'driver_plugin' => DEFAULT_DRIVER_PLUGIN }
|
151
177
|
end
|
@@ -166,7 +192,11 @@ module Jamie
|
|
166
192
|
attr_reader :run_list
|
167
193
|
|
168
194
|
# @return [Hash] Hash of Chef node attributes
|
169
|
-
attr_reader :
|
195
|
+
attr_reader :attributes
|
196
|
+
|
197
|
+
# @return [String] local path to the suite's data bags, or nil if one does
|
198
|
+
# not exist
|
199
|
+
attr_reader :data_bags_path
|
170
200
|
|
171
201
|
# Constructs a new suite.
|
172
202
|
#
|
@@ -174,13 +204,15 @@ module Jamie
|
|
174
204
|
# @option options [String] :name logical name of this suit (**Required**)
|
175
205
|
# @option options [String] :run_list Array of Chef run_list items
|
176
206
|
# (**Required**)
|
177
|
-
# @option options [Hash] :
|
207
|
+
# @option options [Hash] :attributes Hash of Chef node attributes
|
208
|
+
# @option options [String] :data_bags_path path to data bags
|
178
209
|
def initialize(options = {})
|
179
210
|
validate_options(options)
|
180
211
|
|
181
212
|
@name = options['name']
|
182
213
|
@run_list = options['run_list']
|
183
|
-
@
|
214
|
+
@attributes = options['attributes'] || Hash.new
|
215
|
+
@data_bags_path = options['data_bags_path']
|
184
216
|
end
|
185
217
|
|
186
218
|
private
|
@@ -208,7 +240,7 @@ module Jamie
|
|
208
240
|
attr_reader :run_list
|
209
241
|
|
210
242
|
# @return [Hash] Hash of Chef node attributes
|
211
|
-
attr_reader :
|
243
|
+
attr_reader :attributes
|
212
244
|
|
213
245
|
# Constructs a new platform.
|
214
246
|
#
|
@@ -219,14 +251,14 @@ module Jamie
|
|
219
251
|
# will manage this platform's lifecycle actions (**Required**)
|
220
252
|
# @option options [Array<String>] :run_list Array of Chef run_list
|
221
253
|
# items
|
222
|
-
# @option options [Hash] :
|
254
|
+
# @option options [Hash] :attributes Hash of Chef node attributes
|
223
255
|
def initialize(options = {})
|
224
256
|
validate_options(options)
|
225
257
|
|
226
258
|
@name = options['name']
|
227
259
|
@driver = options['driver']
|
228
260
|
@run_list = Array(options['run_list'])
|
229
|
-
@
|
261
|
+
@attributes = options['attributes'] || Hash.new
|
230
262
|
end
|
231
263
|
|
232
264
|
private
|
@@ -279,8 +311,12 @@ module Jamie
|
|
279
311
|
# suite overriding values from the platform.
|
280
312
|
#
|
281
313
|
# @return [Hash] merged hash of Chef node attributes
|
282
|
-
def
|
283
|
-
platform.
|
314
|
+
def attributes
|
315
|
+
platform.attributes.rmerge(suite.attributes)
|
316
|
+
end
|
317
|
+
|
318
|
+
def dna
|
319
|
+
attributes.rmerge({ 'run_list' => run_list })
|
284
320
|
end
|
285
321
|
|
286
322
|
# Creates this instance.
|
@@ -552,40 +588,90 @@ module Jamie
|
|
552
588
|
# @param attr [Object] configuration key
|
553
589
|
# @return [Object] value at configuration key
|
554
590
|
def [](attr)
|
555
|
-
|
591
|
+
config[attr]
|
556
592
|
end
|
557
593
|
|
558
594
|
# Creates an instance.
|
559
595
|
#
|
560
596
|
# @param instance [Instance] an instance
|
561
597
|
# @raise [ActionFailed] if the action could not be completed
|
562
|
-
def create(instance)
|
598
|
+
def create(instance)
|
599
|
+
action(:create, instance)
|
600
|
+
end
|
563
601
|
|
564
602
|
# Converges a running instance.
|
565
603
|
#
|
566
604
|
# @param instance [Instance] an instance
|
567
605
|
# @raise [ActionFailed] if the action could not be completed
|
568
|
-
def converge(instance)
|
606
|
+
def converge(instance)
|
607
|
+
action(:converge, instance)
|
608
|
+
end
|
569
609
|
|
570
610
|
# Sets up an instance.
|
571
611
|
#
|
572
612
|
# @param instance [Instance] an instance
|
573
613
|
# @raise [ActionFailed] if the action could not be completed
|
574
|
-
def setup(instance)
|
614
|
+
def setup(instance)
|
615
|
+
action(:setup, instance)
|
616
|
+
end
|
575
617
|
|
576
618
|
# Verifies a converged instance.
|
577
619
|
#
|
578
620
|
# @param instance [Instance] an instance
|
579
621
|
# @raise [ActionFailed] if the action could not be completed
|
580
|
-
def verify(instance)
|
622
|
+
def verify(instance)
|
623
|
+
action(:verify, instance)
|
624
|
+
end
|
581
625
|
|
582
626
|
# Destroys an instance.
|
583
627
|
#
|
584
628
|
# @param instance [Instance] an instance
|
585
629
|
# @raise [ActionFailed] if the action could not be completed
|
586
|
-
def destroy(instance)
|
630
|
+
def destroy(instance)
|
631
|
+
action(:destroy, instance)
|
632
|
+
destroy_state(instance)
|
633
|
+
end
|
634
|
+
|
635
|
+
protected
|
636
|
+
|
637
|
+
attr_reader :config
|
638
|
+
|
639
|
+
def action(what, instance)
|
640
|
+
state = load_state(instance)
|
641
|
+
public_send("perform_#{what}", instance, state)
|
642
|
+
state['last_action'] = what.to_s
|
643
|
+
ensure
|
644
|
+
dump_state(instance, state)
|
645
|
+
end
|
646
|
+
|
647
|
+
def load_state(instance)
|
648
|
+
statefile = state_filepath(instance)
|
587
649
|
|
588
|
-
|
650
|
+
if File.exists?(statefile)
|
651
|
+
YAML.load_file(statefile)
|
652
|
+
else
|
653
|
+
{ 'name' => instance.name }
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
def dump_state(instance, state)
|
658
|
+
statefile = state_filepath(instance)
|
659
|
+
dir = File.dirname(statefile)
|
660
|
+
|
661
|
+
FileUtils.mkdir_p(dir) if !File.directory?(dir)
|
662
|
+
File.open(statefile, "wb") { |f| f.write(YAML.dump(state)) }
|
663
|
+
end
|
664
|
+
|
665
|
+
def destroy_state(instance)
|
666
|
+
statefile = state_filepath(instance)
|
667
|
+
FileUtils.rm(statefile) if File.exists?(statefile)
|
668
|
+
end
|
669
|
+
|
670
|
+
def state_filepath(instance)
|
671
|
+
File.expand_path(File.join(
|
672
|
+
config['jamie_root'], ".jamie", "#{instance.name}.yml"
|
673
|
+
))
|
674
|
+
end
|
589
675
|
|
590
676
|
def self.defaults
|
591
677
|
@defaults ||= Hash.new
|
@@ -595,5 +681,244 @@ module Jamie
|
|
595
681
|
defaults[attr] = value
|
596
682
|
end
|
597
683
|
end
|
684
|
+
|
685
|
+
# Base class for a driver that uses SSH to communication with an instance.
|
686
|
+
# A subclass must implement the following methods:
|
687
|
+
# * #perform_create(instance, state)
|
688
|
+
# * #perform_destroy(instance, state)
|
689
|
+
class SSHBase < Base
|
690
|
+
|
691
|
+
def perform_converge(instance, state)
|
692
|
+
ssh_args = generate_ssh_args(state)
|
693
|
+
|
694
|
+
install_omnibus(ssh_args) if config['require_chef_omnibus']
|
695
|
+
prepare_chef_home(ssh_args)
|
696
|
+
upload_chef_data(ssh_args, instance)
|
697
|
+
run_chef_solo(ssh_args)
|
698
|
+
end
|
699
|
+
|
700
|
+
def perform_setup(instance, state)
|
701
|
+
ssh_args = generate_ssh_args(state)
|
702
|
+
|
703
|
+
if instance.jr.setup_cmd
|
704
|
+
ssh(ssh_args, instance.jr.setup_cmd)
|
705
|
+
else
|
706
|
+
super
|
707
|
+
end
|
708
|
+
end
|
709
|
+
|
710
|
+
def perform_verify(instance, state)
|
711
|
+
ssh_args = generate_ssh_args(state)
|
712
|
+
|
713
|
+
if instance.jr.run_cmd
|
714
|
+
ssh(ssh_args, instance.jr.sync_cmd)
|
715
|
+
ssh(ssh_args, instance.jr.run_cmd)
|
716
|
+
else
|
717
|
+
super
|
718
|
+
end
|
719
|
+
end
|
720
|
+
|
721
|
+
protected
|
722
|
+
|
723
|
+
def generate_ssh_args(state)
|
724
|
+
[ state['hostname'],
|
725
|
+
config['username'],
|
726
|
+
{ :password => config['password'] }
|
727
|
+
]
|
728
|
+
end
|
729
|
+
|
730
|
+
def chef_home
|
731
|
+
"/tmp/jamie-chef-solo".freeze
|
732
|
+
end
|
733
|
+
|
734
|
+
def install_omnibus(ssh_args)
|
735
|
+
ssh(ssh_args, <<-INSTALL)
|
736
|
+
if [ ! -d "/opt/chef" ] ; then
|
737
|
+
curl -L https://www.opscode.com/chef/install.sh | sudo bash
|
738
|
+
fi
|
739
|
+
INSTALL
|
740
|
+
end
|
741
|
+
|
742
|
+
def prepare_chef_home(ssh_args)
|
743
|
+
ssh(ssh_args, "sudo rm -rf #{chef_home} && mkdir -p #{chef_home}")
|
744
|
+
end
|
745
|
+
|
746
|
+
def upload_chef_data(ssh_args, instance)
|
747
|
+
Jamie::ChefDataUploader.new(
|
748
|
+
instance, ssh_args, config['jamie_root'], chef_home
|
749
|
+
).upload
|
750
|
+
end
|
751
|
+
|
752
|
+
def run_chef_solo(ssh_args)
|
753
|
+
ssh(ssh_args, <<-RUN_SOLO)
|
754
|
+
sudo chef-solo -c #{chef_home}/solo.rb -j #{chef_home}/dna.json
|
755
|
+
RUN_SOLO
|
756
|
+
end
|
757
|
+
|
758
|
+
def ssh(ssh_args, cmd)
|
759
|
+
Net::SSH.start(*ssh_args) do |ssh|
|
760
|
+
exit_code = ssh_exec_with_exit!(ssh, cmd)
|
761
|
+
|
762
|
+
if exit_code != 0
|
763
|
+
shorter_cmd = cmd.squeeze(" ").strip
|
764
|
+
raise ActionFailed,
|
765
|
+
"SSH exited (#{exit_code}) for command: [#{shorter_cmd}]"
|
766
|
+
end
|
767
|
+
end
|
768
|
+
rescue Net::SSH::Exception => ex
|
769
|
+
raise ActionFailed, ex.message
|
770
|
+
end
|
771
|
+
|
772
|
+
def ssh_exec_with_exit!(ssh, cmd)
|
773
|
+
exit_code = nil
|
774
|
+
ssh.open_channel do |channel|
|
775
|
+
channel.exec(cmd) do |ch, success|
|
776
|
+
|
777
|
+
channel.on_data do |ch, data|
|
778
|
+
$stdout.print data
|
779
|
+
end
|
780
|
+
|
781
|
+
channel.on_extended_data do |ch, type, data|
|
782
|
+
$stderr.print data
|
783
|
+
end
|
784
|
+
|
785
|
+
channel.on_request("exit-status") do |ch, data|
|
786
|
+
exit_code = data.read_long
|
787
|
+
end
|
788
|
+
end
|
789
|
+
end
|
790
|
+
ssh.loop
|
791
|
+
exit_code
|
792
|
+
end
|
793
|
+
|
794
|
+
def wait_for_sshd(hostname)
|
795
|
+
print "." until test_ssh(hostname)
|
796
|
+
end
|
797
|
+
|
798
|
+
def test_ssh(hostname)
|
799
|
+
socket = TCPSocket.new(hostname, config['port'])
|
800
|
+
IO.select([socket], nil, nil, 5)
|
801
|
+
rescue SocketError, Errno::ECONNREFUSED,
|
802
|
+
Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
803
|
+
sleep 2
|
804
|
+
false
|
805
|
+
rescue Errno::EPERM, Errno::ETIMEDOUT
|
806
|
+
false
|
807
|
+
ensure
|
808
|
+
socket && socket.close
|
809
|
+
end
|
810
|
+
end
|
811
|
+
end
|
812
|
+
|
813
|
+
# Uploads Chef asset files such as dna.json, data bags, and cookbooks to an
|
814
|
+
# instance over SSH.
|
815
|
+
class ChefDataUploader
|
816
|
+
|
817
|
+
def initialize(instance, ssh_args, jamie_root, chef_home)
|
818
|
+
@instance = instance
|
819
|
+
@ssh_args = ssh_args
|
820
|
+
@jamie_root = jamie_root
|
821
|
+
@chef_home = chef_home
|
822
|
+
end
|
823
|
+
|
824
|
+
def upload
|
825
|
+
Net::SCP.start(*ssh_args) do |scp|
|
826
|
+
upload_json scp
|
827
|
+
upload_solo_rb scp
|
828
|
+
upload_cookbooks scp
|
829
|
+
upload_data_bags scp if instance.suite.data_bags_path
|
830
|
+
end
|
831
|
+
end
|
832
|
+
|
833
|
+
private
|
834
|
+
|
835
|
+
attr_reader :instance, :ssh_args, :jamie_root, :chef_home
|
836
|
+
|
837
|
+
def upload_json(scp)
|
838
|
+
json_file = StringIO.new(instance.dna.to_json)
|
839
|
+
scp.upload!(json_file, "#{chef_home}/dna.json")
|
840
|
+
end
|
841
|
+
|
842
|
+
def upload_solo_rb(scp)
|
843
|
+
solo_rb_file = StringIO.new(solo_rb_contents)
|
844
|
+
scp.upload!(solo_rb_file, "#{chef_home}/solo.rb")
|
845
|
+
end
|
846
|
+
|
847
|
+
def upload_cookbooks(scp)
|
848
|
+
cookbooks_dir = local_cookbooks
|
849
|
+
scp.upload!(cookbooks_dir, "#{chef_home}/cookbooks",
|
850
|
+
:recursive => true
|
851
|
+
) do |ch, name, sent, total|
|
852
|
+
file = name.sub(%r{^#{cookbooks_dir}/}, '')
|
853
|
+
puts " #{file}: #{sent}/#{total}"
|
854
|
+
end
|
855
|
+
ensure
|
856
|
+
FileUtils.rmtree(cookbooks_dir)
|
857
|
+
end
|
858
|
+
|
859
|
+
def upload_data_bags(scp)
|
860
|
+
data_bags_dir = instance.suite.data_bags_path
|
861
|
+
scp.upload!(data_bags_dir, "#{chef_home}/data_bags",
|
862
|
+
:recursive => true
|
863
|
+
) do |ch, name, sent, total|
|
864
|
+
file = name.sub(%r{^#{data_bags_dir}/}, '')
|
865
|
+
puts " #{file}: #{sent}/#{total}"
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
869
|
+
def solo_rb_contents
|
870
|
+
solo = []
|
871
|
+
solo << %{node_name "#{instance.name}"}
|
872
|
+
solo << %{file_cache_path "#{chef_home}/cache"}
|
873
|
+
solo << %{cookbook_path "#{chef_home}/cookbooks"}
|
874
|
+
solo << %{role_path "#{chef_home}/roles"}
|
875
|
+
if instance.suite.data_bags_path
|
876
|
+
solo << %{data_bag_path "#{chef_home}/data_bags"}
|
877
|
+
end
|
878
|
+
solo << %{log_level :info}
|
879
|
+
solo.join("\n")
|
880
|
+
end
|
881
|
+
|
882
|
+
def local_cookbooks
|
883
|
+
if File.exists?(File.join(jamie_root, "Berksfile"))
|
884
|
+
tmpdir = Dir.mktmpdir(instance.name)
|
885
|
+
run_berks(tmpdir)
|
886
|
+
tmpdir
|
887
|
+
elsif File.exists?(File.join(jamie_root, "Cheffile"))
|
888
|
+
tmpdir = Dir.mktmpdir(instance.name)
|
889
|
+
run_librarian(tmpdir)
|
890
|
+
tmpdir
|
891
|
+
else
|
892
|
+
abort "Berksfile or Cheffile must exist in #{jamie_root}"
|
893
|
+
end
|
894
|
+
end
|
895
|
+
|
896
|
+
def run_berks(tmpdir)
|
897
|
+
begin
|
898
|
+
run "if ! command -v berks >/dev/null ; then exit 1 ; fi"
|
899
|
+
rescue Mixlib::ShellOut::ShellCommandFailed
|
900
|
+
abort ">>>>>> Berkshelf must be installed, add it to your Gemfile."
|
901
|
+
end
|
902
|
+
run "berks install --path #{tmpdir}"
|
903
|
+
end
|
904
|
+
|
905
|
+
def run_librarian(tmpdir)
|
906
|
+
begin
|
907
|
+
run "if ! command -v librarian-chef >/dev/null ; then exit 1 ; fi"
|
908
|
+
rescue Mixlib::ShellOut::ShellCommandFailed
|
909
|
+
abort ">>>>>> Librarian must be installed, add it to your Gemfile."
|
910
|
+
end
|
911
|
+
run "librarian-chef install --path #{tmpdir}"
|
912
|
+
end
|
913
|
+
|
914
|
+
def run(cmd)
|
915
|
+
puts " [local command] '#{cmd}'"
|
916
|
+
sh = Mixlib::ShellOut.new(cmd, :live_stream => STDOUT)
|
917
|
+
sh.run_command
|
918
|
+
puts " [local command] ran in #{sh.execution_time} seconds."
|
919
|
+
sh.error!
|
920
|
+
rescue Mixlib::ShellOut::ShellCommandFailed => ex
|
921
|
+
raise ActionFailed, ex.message
|
922
|
+
end
|
598
923
|
end
|
599
924
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jamie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.
|
4
|
+
version: 0.1.0.alpha9
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -27,6 +27,38 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: net-ssh
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: net-scp
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
30
62
|
- !ruby/object:Gem::Dependency
|
31
63
|
name: mixlib-shellout
|
32
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -159,6 +191,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
159
191
|
- - ! '>='
|
160
192
|
- !ruby/object:Gem::Version
|
161
193
|
version: '0'
|
194
|
+
segments:
|
195
|
+
- 0
|
196
|
+
hash: -3537010149917719501
|
162
197
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
198
|
none: false
|
164
199
|
requirements:
|