orca 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -3,4 +3,5 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  gem 'rake'
6
+ gem 'minitest'
6
7
  gem 'mocha', :require => false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- orca (0.2.0)
4
+ orca (0.3.0)
5
5
  colored
6
6
  net-sftp
7
7
  net-ssh
@@ -12,6 +12,7 @@ GEM
12
12
  specs:
13
13
  colored (1.2)
14
14
  metaclass (0.0.1)
15
+ minitest (4.7.5)
15
16
  mocha (0.13.1)
16
17
  metaclass (~> 0.0.1)
17
18
  net-sftp (2.1.2)
@@ -24,6 +25,7 @@ PLATFORMS
24
25
  ruby
25
26
 
26
27
  DEPENDENCIES
28
+ minitest
27
29
  mocha
28
30
  orca!
29
31
  rake
data/README.md CHANGED
@@ -76,7 +76,18 @@ So here are some examples (assuming you have a package called "app" and a node c
76
76
 
77
77
  orca apply app server
78
78
  orca remove app server
79
- orca demonstrate app server
79
+
80
+ You can also directly trigger actions from the CLI like so...
81
+
82
+ orca trigger nginx:reload web-1
83
+
84
+ Options, all commands support the following optional parameters...
85
+
86
+ --demonstrate | dont actually run the commands on the server just pretend like you are
87
+ --sequential | dont attempt to run commands accross multiple nodes in parrallel
88
+ --throw | throw a stack trace rather than pretty printing errors
89
+ --file | path to the orca.rb file to load, defaults to ./orca/orca.rb
90
+ --skip-dependancies | Don't validate and run dependancies, only the pkg in question
80
91
 
81
92
 
82
93
  The Orca DSL
data/lib/orca.rb CHANGED
@@ -37,6 +37,7 @@ require_relative "./orca/package_index"
37
37
  require_relative "./orca/node"
38
38
  require_relative "./orca/group"
39
39
  require_relative "./orca/runner"
40
+ require_relative "./orca/trigger_runner"
40
41
  require_relative "./orca/resolver"
41
42
  require_relative "./orca/execution_context"
42
43
  require_relative "./orca/local_file"
data/lib/orca/cli.rb CHANGED
@@ -7,6 +7,7 @@ class Orca::Cli < Thor
7
7
  class_option :file, :banner => 'ORCA_FILE', :desc => "path to the orca.rb file to load, defaults to ./orca/orca.rb"
8
8
  class_option :throw, :type => :boolean, :desc => "Don't pretty print errors, raise with a stack trace."
9
9
  class_option :sequential, :type => :boolean, :desc => "Don't run tasks in parrallel across nodes."
10
+ class_option :'skip-dependancies', :type => :boolean, :desc => "Don't validate and run dependancies."
10
11
 
11
12
  desc "apply PACKAGE_NAME GROUP_OR_NODE_NAME", "apply the given package onto the given named group"
12
13
  def apply(package, group)
@@ -28,6 +29,11 @@ class Orca::Cli < Thor
28
29
  directory('template', 'orca')
29
30
  end
30
31
 
32
+ desc "trigger ACTION_REF GROUP_OR_NODE_NAME", "trigger an action directly e.g. `orca trigger nginx:reload web-1`"
33
+ def trigger(action_ref, group)
34
+ run_command(action_ref, group, :trigger)
35
+ end
36
+
31
37
  private
32
38
 
33
39
  def run_command(package, group, cmd)
@@ -1,4 +1,6 @@
1
1
  class Orca::ExecutionContext
2
+ attr_reader :node
3
+
2
4
  def initialize(node)
3
5
  @node = node
4
6
  end
@@ -11,6 +13,10 @@ class Orca::ExecutionContext
11
13
  @node.execute(cmd)
12
14
  end
13
15
 
16
+ def log(msg)
17
+ @node.log('log', msg)
18
+ end
19
+
14
20
  def sudo(cmd)
15
21
  @node.sudo(cmd)
16
22
  end
@@ -47,7 +53,7 @@ class Orca::ExecutionContext
47
53
  pkg_name, action_name = *action_ref.split(':', 2)
48
54
  pkg = Orca::PackageIndex.default.get(pkg_name)
49
55
  action = pkg.actions[action_name]
50
- raise "Action #{action_ref} could not be found." unless action
56
+ raise Orca::MissingActionError.new(action_ref) unless action
51
57
  instance_exec(*args, &action)
52
58
  end
53
59
 
@@ -56,6 +62,16 @@ class Orca::ExecutionContext
56
62
  end
57
63
  end
58
64
 
65
+ class Orca::MissingActionError < StandardError
66
+ def initialize(action_ref)
67
+ @action_ref = action_ref
68
+ end
69
+
70
+ def message
71
+ "Action '#{@action_ref}' could not be found."
72
+ end
73
+ end
74
+
59
75
  class Orca::MockExecutionContext < Orca::ExecutionContext
60
76
  def run(cmd)
61
77
  @node.log 'mock-execute', cmd
@@ -1,15 +1,16 @@
1
1
  Orca.extension :file_sync do
2
2
  class Orca::Package
3
- def file(config)
4
- Orca::FileSync.new(self, config).configure
3
+ def file(config, &blk)
4
+ Orca::FileSync.new(self, config, &blk).configure
5
5
  end
6
6
  end
7
7
  end
8
8
 
9
9
  class Orca::FileSync
10
- def initialize(parent, config)
10
+ def initialize(parent, config, &blk)
11
11
  @parent = parent
12
12
  @config = config
13
+ @after_apply = blk
13
14
  raise ArgumentError.new('A file :source must be provided') unless local_path
14
15
  raise ArgumentError.new('A file :destination must be provided') unless remote_path
15
16
  end
@@ -48,6 +49,10 @@ class Orca::FileSync
48
49
  add_permissions_package unless permissions.nil? and user.nil? and group.nil?
49
50
  end
50
51
 
52
+ def run_after_apply(context)
53
+ context.instance_eval(&@after_apply)
54
+ end
55
+
51
56
  def add_content_package
52
57
  fs = self
53
58
  add_package('content') do |package|
@@ -61,6 +66,7 @@ class Orca::FileSync
61
66
  tmp_path = "orca-upload-#{local_file.hash}"
62
67
  local_file.copy_to(remote(tmp_path))
63
68
  sudo("mv #{tmp_path} #{fs.remote_path}")
69
+ fs.run_after_apply(self)
64
70
  end
65
71
 
66
72
  package.command :remove do
@@ -79,6 +85,7 @@ class Orca::FileSync
79
85
  package.command :apply do
80
86
  remote(fs.remote_path).set_owner(fs.user, fs.group) unless fs.user.nil? and fs.group.nil?
81
87
  remote(fs.remote_path).set_permissions(fs.permissions) unless fs.permissions.nil?
88
+ fs.run_after_apply(self)
82
89
  end
83
90
 
84
91
  package.command :validate do
data/lib/orca/node.rb CHANGED
@@ -23,6 +23,14 @@ class Orca::Node
23
23
  Orca::Node.register(self)
24
24
  end
25
25
 
26
+ def get(option)
27
+ @options[option]
28
+ end
29
+
30
+ def method_missing(meth, *args)
31
+ get(meth)
32
+ end
33
+
26
34
  def upload(from, to)
27
35
  log('sftp', "UPLOAD: #{from} => #{to}")
28
36
  sftp.upload!(from, to)
@@ -71,14 +79,25 @@ class Orca::Node
71
79
 
72
80
  def log(context, msg)
73
81
  Thread.exclusive { puts "#{self.to_s} [#{context.to_s.bold}] #{msg}" }
82
+ msg
74
83
  end
75
84
 
76
85
  def connection
77
86
  return @connection if @connection
78
- @connetion = Net::SSH.start(@host, (@options[:user] || 'root'), @options)
87
+ @connetion = Net::SSH.start(@host, (@options[:user] || 'root'), options_for_ssh)
79
88
  end
80
89
 
81
90
  def to_s
82
91
  "#{name}(#{host})"
83
92
  end
93
+
94
+ private
95
+
96
+ def options_for_ssh
97
+ opts = [:auth_methods, :compression, :compression_level, :config, :encryption , :forward_agent , :global_known_hosts_file , :hmac , :host_key , :host_key_alias , :host_name, :kex , :keys , :key_data , :keys_only , :logger , :paranoid , :passphrase , :password , :port , :properties , :proxy , :rekey_blocks_limit , :rekey_limit , :rekey_packet_limit , :timeout , :user , :user_known_hosts_file , :verbose ]
98
+ @options.reduce({}) do |hsh, (k,v)|
99
+ hsh[k] = v if opts.include?(k)
100
+ hsh
101
+ end
102
+ end
84
103
  end
@@ -55,7 +55,7 @@ class Orca::RemoteFile
55
55
  end
56
56
 
57
57
  def delete!
58
- @context.remove(path)
58
+ @context.remove(path) if exists?
59
59
  invalidate!
60
60
  self
61
61
  end
data/lib/orca/runner.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  class Orca::Runner
2
- def initialize(node, package)
2
+ def initialize(node, package, skip_dependancies=false)
3
3
  @node = node
4
4
  @package = package
5
5
  @perform = true
6
+ @skip_dependancies = skip_dependancies
6
7
  end
7
8
 
8
9
  def packages
10
+ return [@package] if @skip_dependancies
9
11
  resolver = Orca::Resolver.new(@package)
10
12
  resolver.resolve
11
13
  resolver.packages
data/lib/orca/suite.rb CHANGED
@@ -3,6 +3,7 @@ class Orca::Suite
3
3
  def initialize(options={})
4
4
  @sequential = options[:sequential]
5
5
  @demonstrate = options[:demonstrate]
6
+ @skip_dependancies = options[:'skip-dependancies'] || false
6
7
  end
7
8
 
8
9
  def load_file(file)
@@ -11,8 +12,14 @@ class Orca::Suite
11
12
 
12
13
  def run(group_name, pkg_name, command, sequential=false)
13
14
  group = Orca::Group.find(group_name)
14
- pkg = Orca::PackageIndex.default.get(pkg_name)
15
- runners = group.nodes.map { |node| Orca::Runner.new(node, pkg) }
15
+ runners = group.nodes.map do |node|
16
+ if command == :trigger
17
+ Orca::TriggerRunner.new(node, pkg_name)
18
+ else
19
+ pkg = Orca::PackageIndex.default.get(pkg_name)
20
+ Orca::Runner.new(node, pkg, @skip_dependancies)
21
+ end
22
+ end
16
23
  if @sequential
17
24
  runners.each {|runner| exec(runner, command) }
18
25
  else
@@ -0,0 +1,14 @@
1
+ class Orca::TriggerRunner
2
+ def initialize(node, action_ref)
3
+ @node = node
4
+ @action_ref = action_ref
5
+ end
6
+
7
+ def execute(_)
8
+ Orca::ExecutionContext.new(@node).trigger(@action_ref)
9
+ end
10
+
11
+ def demonstrate(_)
12
+ Orca::MockExecutionContext.new(@node).trigger(@action_ref)
13
+ end
14
+ end
data/orca.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
10
10
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
11
11
  gem.name = "orca"
12
12
  gem.require_paths = ["lib"]
13
- gem.version = '0.2.0'
13
+ gem.version = '0.3.0'
14
14
  gem.add_dependency('colored')
15
15
  gem.add_dependency('net-ssh')
16
16
  gem.add_dependency('net-sftp')
@@ -75,9 +75,20 @@ describe Orca::RemoteFile do
75
75
 
76
76
  describe 'delete!' do
77
77
  it "removes the file from the remote server" do
78
+ @context.expects(:run)
79
+ .with(%[if [ -f #{@remote_file_path} ]; then echo "true"; else echo "false"; fi])
80
+ .returns("true\n")
78
81
  @context.expects(:remove).with(@remote_file.path)
79
82
  @remote_file.delete!
80
83
  end
84
+
85
+ it "doesn't delete missing files" do
86
+ @context.expects(:run)
87
+ .with(%[if [ -f #{@remote_file_path} ]; then echo "true"; else echo "false"; fi])
88
+ .returns("false\n")
89
+ @context.expects(:remove).with(@remote_file.path).never
90
+ @remote_file.delete!
91
+ end
81
92
  end
82
93
 
83
94
  describe 'set_permissions' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: orca
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
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: 2013-06-24 00:00:00.000000000 Z
12
+ date: 2013-06-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: colored
@@ -107,6 +107,7 @@ files:
107
107
  - lib/orca/resolver.rb
108
108
  - lib/orca/runner.rb
109
109
  - lib/orca/suite.rb
110
+ - lib/orca/trigger_runner.rb
110
111
  - orca.gemspec
111
112
  - test/dsl_test.rb
112
113
  - test/fixtures/example.txt
@@ -131,7 +132,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
131
132
  version: '0'
132
133
  segments:
133
134
  - 0
134
- hash: 1672503668912245797
135
+ hash: 1540904086341919600
135
136
  required_rubygems_version: !ruby/object:Gem::Requirement
136
137
  none: false
137
138
  requirements:
@@ -140,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
141
  version: '0'
141
142
  segments:
142
143
  - 0
143
- hash: 1672503668912245797
144
+ hash: 1540904086341919600
144
145
  requirements: []
145
146
  rubyforge_project:
146
147
  rubygems_version: 1.8.23