jamie 0.1.0.alpha16 → 0.1.0.alpha17
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/jamie/cli.rb +23 -2
- data/lib/jamie/driver/dummy.rb +58 -0
- data/lib/jamie/version.rb +1 -1
- data/lib/jamie.rb +109 -40
- metadata +3 -2
data/Rakefile
CHANGED
data/lib/jamie/cli.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
-
require 'erb'
|
4
3
|
require 'ostruct'
|
5
4
|
require 'thor'
|
6
5
|
|
@@ -25,7 +24,7 @@ module Jamie
|
|
25
24
|
say Array(result).map{ |i| i.name }.join("\n")
|
26
25
|
end
|
27
26
|
|
28
|
-
[:create, :converge, :setup, :verify, :
|
27
|
+
[:create, :converge, :setup, :verify, :destroy].each do |action|
|
29
28
|
desc(
|
30
29
|
"#{action} (all ['REGEX']|[INSTANCE])",
|
31
30
|
"#{action.capitalize} one or more instances"
|
@@ -33,6 +32,28 @@ module Jamie
|
|
33
32
|
define_method(action) { |*args| exec_action(action) }
|
34
33
|
end
|
35
34
|
|
35
|
+
desc "test (all ['REGEX']|[INSTANCE]) [opts]", "Test one or more instances"
|
36
|
+
long_desc <<-DESC
|
37
|
+
Test one or more instances
|
38
|
+
|
39
|
+
There are 3 post-verify modes for instance cleanup, triggered with
|
40
|
+
the `--destroy' flag:
|
41
|
+
|
42
|
+
* passing: instances passing verify will be destroyed afterwards.\n
|
43
|
+
* always: instances will always be destroyed afterwards.\n
|
44
|
+
* never: instances will never be destroyed afterwards.
|
45
|
+
DESC
|
46
|
+
method_option :destroy, :aliases => "-d", :default => "passing",
|
47
|
+
:desc => "Destroy strategy to use after testing (passing, always, never)."
|
48
|
+
def test(*args)
|
49
|
+
destroy_mode = options[:destroy]
|
50
|
+
if ! %w{passing always never}.include?(options[:destroy])
|
51
|
+
raise ArgumentError, "Destroy mode must be passing, always, or never."
|
52
|
+
end
|
53
|
+
result = parse_subcommand(args[0], args[1])
|
54
|
+
Array(result).each { |instance| instance.test(destroy_mode.to_sym) }
|
55
|
+
end
|
56
|
+
|
36
57
|
desc "version", "Print Jamie's version information"
|
37
58
|
def version
|
38
59
|
say "Jamie version #{Jamie::VERSION}"
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require 'jamie'
|
20
|
+
|
21
|
+
module Jamie
|
22
|
+
|
23
|
+
module Driver
|
24
|
+
|
25
|
+
# Dummy driver for Jamie.
|
26
|
+
class Dummy < Jamie::Driver::Base
|
27
|
+
|
28
|
+
def create(instance, state)
|
29
|
+
state['my_id'] = "#{instance.name}-#{Time.now.to_i}"
|
30
|
+
report(:create, instance, state)
|
31
|
+
end
|
32
|
+
|
33
|
+
def converge(instance, state)
|
34
|
+
report(:converge, instance, state)
|
35
|
+
end
|
36
|
+
|
37
|
+
def setup(instance, state)
|
38
|
+
report(:setup, instance, state)
|
39
|
+
end
|
40
|
+
|
41
|
+
def verify(instance, state)
|
42
|
+
report(:verify, instance, state)
|
43
|
+
end
|
44
|
+
|
45
|
+
def destroy(instance, state)
|
46
|
+
report(:destroy, instance, state)
|
47
|
+
state.delete('my_id')
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def report(action, instance, state)
|
53
|
+
puts "[Dummy] Action ##{action} called on " +
|
54
|
+
"instance=#{instance} with state=#{state}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/jamie/version.rb
CHANGED
data/lib/jamie.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'base64'
|
4
4
|
require 'delegate'
|
5
5
|
require 'digest'
|
6
|
+
require 'erb'
|
6
7
|
require 'fileutils'
|
7
8
|
require 'json'
|
8
9
|
require 'mixlib/shellout'
|
@@ -150,7 +151,11 @@ module Jamie
|
|
150
151
|
end
|
151
152
|
|
152
153
|
def yaml
|
153
|
-
@yaml ||= YAML.
|
154
|
+
@yaml ||= YAML.load(yaml_contents).rmerge(local_yaml)
|
155
|
+
end
|
156
|
+
|
157
|
+
def yaml_contents
|
158
|
+
ERB.new(IO.read(File.expand_path(yaml_file))).result
|
154
159
|
end
|
155
160
|
|
156
161
|
def local_yaml_file
|
@@ -161,7 +166,7 @@ module Jamie
|
|
161
166
|
def local_yaml
|
162
167
|
@local_yaml ||= begin
|
163
168
|
if File.exists?(local_yaml_file)
|
164
|
-
YAML.
|
169
|
+
YAML.load(ERB.new(IO.read(local_yaml_file)).result)
|
165
170
|
else
|
166
171
|
Hash.new
|
167
172
|
end
|
@@ -364,10 +369,7 @@ module Jamie
|
|
364
369
|
# @todo rescue Driver::ActionFailed and return some kind of null object
|
365
370
|
# to gracfully stop action chaining
|
366
371
|
def create
|
367
|
-
|
368
|
-
action(:create) { |state| platform.driver.create(self, state) }
|
369
|
-
puts " Creation of instance #{name} complete."
|
370
|
-
self
|
372
|
+
transition_to(:create)
|
371
373
|
end
|
372
374
|
|
373
375
|
# Converges this running instance.
|
@@ -378,10 +380,7 @@ module Jamie
|
|
378
380
|
# @todo rescue Driver::ActionFailed and return some kind of null object
|
379
381
|
# to gracfully stop action chaining
|
380
382
|
def converge
|
381
|
-
|
382
|
-
action(:converge) { |state| platform.driver.converge(self, state) }
|
383
|
-
puts " Convergence of instance #{name} complete."
|
384
|
-
self
|
383
|
+
transition_to(:converge)
|
385
384
|
end
|
386
385
|
|
387
386
|
# Sets up this converged instance for suite tests.
|
@@ -392,10 +391,7 @@ module Jamie
|
|
392
391
|
# @todo rescue Driver::ActionFailed and return some kind of null object
|
393
392
|
# to gracfully stop action chaining
|
394
393
|
def setup
|
395
|
-
|
396
|
-
action(:setup) { |state| platform.driver.setup(self, state) }
|
397
|
-
puts " Setup of instance #{name} complete."
|
398
|
-
self
|
394
|
+
transition_to(:setup)
|
399
395
|
end
|
400
396
|
|
401
397
|
# Verifies this set up instance by executing suite tests.
|
@@ -406,10 +402,7 @@ module Jamie
|
|
406
402
|
# @todo rescue Driver::ActionFailed and return some kind of null object
|
407
403
|
# to gracfully stop action chaining
|
408
404
|
def verify
|
409
|
-
|
410
|
-
action(:verify) { |state| platform.driver.verify(self, state) }
|
411
|
-
puts " Verification of instance #{name} complete."
|
412
|
-
self
|
405
|
+
transition_to(:verify)
|
413
406
|
end
|
414
407
|
|
415
408
|
# Destroys this instance.
|
@@ -420,40 +413,75 @@ module Jamie
|
|
420
413
|
# @todo rescue Driver::ActionFailed and return some kind of null object
|
421
414
|
# to gracfully stop action chaining
|
422
415
|
def destroy
|
423
|
-
|
424
|
-
action(:destroy) { |state| platform.driver.destroy(self, state) }
|
425
|
-
destroy_state
|
426
|
-
puts " Destruction of instance #{name} complete."
|
427
|
-
self
|
416
|
+
transition_to(:destroy)
|
428
417
|
end
|
429
418
|
|
430
419
|
# Tests this instance by creating, converging and verifying. If this
|
431
420
|
# instance is running, it will be pre-emptively destroyed to ensure a
|
432
421
|
# clean slate. The instance will be left post-verify in a running state.
|
433
422
|
#
|
434
|
-
# @
|
435
|
-
#
|
436
|
-
# @see #converge
|
437
|
-
# @see #setup
|
438
|
-
# @see #verify
|
423
|
+
# @param destroy_mode [Symbol] strategy used to cleanup after instance
|
424
|
+
# has finished verifying (default: `:passing`)
|
439
425
|
# @return [self] this instance, used to chain actions
|
440
426
|
#
|
441
427
|
# @todo rescue Driver::ActionFailed and return some kind of null object
|
442
428
|
# to gracfully stop action chaining
|
443
|
-
def test
|
429
|
+
def test(destroy_mode = :passing)
|
444
430
|
puts "-----> Cleaning up any prior instances of #{name}"
|
445
431
|
destroy
|
446
432
|
puts "-----> Testing instance #{name}"
|
447
|
-
create
|
448
|
-
converge
|
449
|
-
setup
|
450
433
|
verify
|
434
|
+
destroy if destroy_mode == :passing
|
451
435
|
puts " Testing of instance #{name} complete."
|
452
436
|
self
|
437
|
+
ensure
|
438
|
+
destroy if destroy_mode == :always
|
453
439
|
end
|
454
440
|
|
455
441
|
private
|
456
442
|
|
443
|
+
def transition_to(desired)
|
444
|
+
FSM.actions(last_action, desired).each do |transition|
|
445
|
+
send("#{transition}_action")
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
def create_action
|
450
|
+
puts "-----> Creating instance #{name}"
|
451
|
+
action(:create) { |state| platform.driver.create(self, state) }
|
452
|
+
puts " Creation of instance #{name} complete."
|
453
|
+
self
|
454
|
+
end
|
455
|
+
|
456
|
+
def converge_action
|
457
|
+
puts "-----> Converging instance #{name}"
|
458
|
+
action(:converge) { |state| platform.driver.converge(self, state) }
|
459
|
+
puts " Convergence of instance #{name} complete."
|
460
|
+
self
|
461
|
+
end
|
462
|
+
|
463
|
+
def setup_action
|
464
|
+
puts "-----> Setting up instance #{name}"
|
465
|
+
action(:setup) { |state| platform.driver.setup(self, state) }
|
466
|
+
puts " Setup of instance #{name} complete."
|
467
|
+
self
|
468
|
+
end
|
469
|
+
|
470
|
+
def verify_action
|
471
|
+
puts "-----> Verifying instance #{name}"
|
472
|
+
action(:verify) { |state| platform.driver.verify(self, state) }
|
473
|
+
puts " Verification of instance #{name} complete."
|
474
|
+
self
|
475
|
+
end
|
476
|
+
|
477
|
+
def destroy_action
|
478
|
+
puts "-----> Destroying instance #{name}"
|
479
|
+
action(:destroy) { |state| platform.driver.destroy(self, state) }
|
480
|
+
destroy_state
|
481
|
+
puts " Destruction of instance #{name} complete."
|
482
|
+
self
|
483
|
+
end
|
484
|
+
|
457
485
|
def action(what)
|
458
486
|
state = load_state
|
459
487
|
yield state if block_given?
|
@@ -482,6 +510,46 @@ module Jamie
|
|
482
510
|
platform.driver['jamie_root'], ".jamie", "#{name}.yml"
|
483
511
|
))
|
484
512
|
end
|
513
|
+
|
514
|
+
def last_action
|
515
|
+
load_state['last_action']
|
516
|
+
end
|
517
|
+
|
518
|
+
# The simplest finite state machine pseudo-implementation needed to manage
|
519
|
+
# an Instance.
|
520
|
+
class FSM
|
521
|
+
|
522
|
+
# Returns an Array of all transitions to bring an Instance from its last
|
523
|
+
# reported transistioned state into the desired transitioned state.
|
524
|
+
#
|
525
|
+
# @param last [String,Symbol,nil] the last known transitioned state of
|
526
|
+
# the Instance, defaulting to `nil` (for unknown or no history)
|
527
|
+
# @param desired [String,Symbol] the desired transitioned state for the
|
528
|
+
# Instance
|
529
|
+
# @return [Array<Symbol>] an Array of transition actions to perform
|
530
|
+
def self.actions(last = nil, desired)
|
531
|
+
last_index = index(last)
|
532
|
+
desired_index = index(desired)
|
533
|
+
|
534
|
+
if last_index == desired_index || last_index > desired_index
|
535
|
+
Array(TRANSITIONS[desired_index])
|
536
|
+
else
|
537
|
+
TRANSITIONS.slice(last_index + 1, desired_index - last_index)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
private
|
542
|
+
|
543
|
+
TRANSITIONS = [ :destroy, :create, :converge, :setup, :verify ]
|
544
|
+
|
545
|
+
def self.index(transition)
|
546
|
+
if transition.nil?
|
547
|
+
0
|
548
|
+
else
|
549
|
+
TRANSITIONS.find_index { |t| t == transition.to_sym }
|
550
|
+
end
|
551
|
+
end
|
552
|
+
end
|
485
553
|
end
|
486
554
|
|
487
555
|
# Command string generator to interface with Jamie Runner (jr). The
|
@@ -781,7 +849,7 @@ module Jamie
|
|
781
849
|
end
|
782
850
|
|
783
851
|
def converge(instance, state)
|
784
|
-
ssh_args =
|
852
|
+
ssh_args = build_ssh_args(state)
|
785
853
|
|
786
854
|
install_omnibus(ssh_args) if config['require_chef_omnibus']
|
787
855
|
prepare_chef_home(ssh_args)
|
@@ -790,7 +858,7 @@ module Jamie
|
|
790
858
|
end
|
791
859
|
|
792
860
|
def setup(instance, state)
|
793
|
-
ssh_args =
|
861
|
+
ssh_args = build_ssh_args(state)
|
794
862
|
|
795
863
|
if instance.jr.setup_cmd
|
796
864
|
ssh(ssh_args, instance.jr.setup_cmd)
|
@@ -798,7 +866,7 @@ module Jamie
|
|
798
866
|
end
|
799
867
|
|
800
868
|
def verify(instance, state)
|
801
|
-
ssh_args =
|
869
|
+
ssh_args = build_ssh_args(state)
|
802
870
|
|
803
871
|
if instance.jr.run_cmd
|
804
872
|
ssh(ssh_args, instance.jr.sync_cmd)
|
@@ -812,11 +880,12 @@ module Jamie
|
|
812
880
|
|
813
881
|
protected
|
814
882
|
|
815
|
-
def
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
883
|
+
def build_ssh_args(state)
|
884
|
+
opts = Hash.new
|
885
|
+
opts[:password] = config['password'] if config['password']
|
886
|
+
opts[:keys] = Array(config['ssh_key']) if config['ssh_key']
|
887
|
+
|
888
|
+
[ state['hostname'], config['username'], opts ]
|
820
889
|
end
|
821
890
|
|
822
891
|
def chef_home
|
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.alpha17
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -174,6 +174,7 @@ files:
|
|
174
174
|
- jamie.gemspec
|
175
175
|
- lib/jamie.rb
|
176
176
|
- lib/jamie/cli.rb
|
177
|
+
- lib/jamie/driver/dummy.rb
|
177
178
|
- lib/jamie/rake_tasks.rb
|
178
179
|
- lib/jamie/thor_tasks.rb
|
179
180
|
- lib/jamie/version.rb
|
@@ -199,7 +200,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
199
200
|
version: '0'
|
200
201
|
segments:
|
201
202
|
- 0
|
202
|
-
hash: -
|
203
|
+
hash: -4096747563693358273
|
203
204
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
204
205
|
none: false
|
205
206
|
requirements:
|