jamie 0.1.0.alpha16 → 0.1.0.alpha17
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/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:
|