itamae 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +60 -0
- data/Rakefile +62 -0
- data/bin/itamae +5 -0
- data/example/foo +1 -0
- data/example/node.json +1 -0
- data/example/recipe.rb +15 -0
- data/itamae.gemspec +32 -0
- data/lib/itamae.rb +13 -0
- data/lib/itamae/cli.rb +23 -0
- data/lib/itamae/logger.rb +44 -0
- data/lib/itamae/node.rb +9 -0
- data/lib/itamae/recipe.rb +46 -0
- data/lib/itamae/resources.rb +25 -0
- data/lib/itamae/resources/base.rb +151 -0
- data/lib/itamae/resources/directory.rb +26 -0
- data/lib/itamae/resources/file.rb +36 -0
- data/lib/itamae/resources/package.rb +15 -0
- data/lib/itamae/resources/remote_file.rb +16 -0
- data/lib/itamae/resources/template.rb +19 -0
- data/lib/itamae/runner.rb +49 -0
- data/lib/itamae/specinfra.rb +44 -0
- data/lib/itamae/version.rb +3 -0
- data/spec/integration/Vagrantfile +19 -0
- data/spec/integration/default_spec.rb +33 -0
- data/spec/integration/recipes/default.rb +26 -0
- data/spec/integration/recipes/hello.erb +1 -0
- data/spec/integration/recipes/hello.txt +1 -0
- data/spec/integration/recipes/node.json +3 -0
- data/spec/integration/spec_helper.rb +45 -0
- data/spec/unit/lib/itamae/logger_spec.rb +20 -0
- data/spec/unit/lib/itamae/node_spec.rb +6 -0
- data/spec/unit/lib/itamae/recipe_spec.rb +6 -0
- data/spec/unit/lib/itamae/resources/base_spec.rb +135 -0
- data/spec/unit/lib/itamae/resources/package_spec.rb +18 -0
- data/spec/unit/lib/itamae/resources/remote_file_spec.rb +23 -0
- data/spec/unit/lib/itamae/resources_spec.rb +14 -0
- data/spec/unit/lib/itamae/runner_spec.rb +29 -0
- data/spec/unit/spec_helper.rb +22 -0
- metadata +230 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e8b0f4978f8d00ca41234de5b288befcdc1f0f68
|
4
|
+
data.tar.gz: 20ad47b014f03d7af8ac547152281c5c0fbd9f99
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dd694c3e13fa40bbee8862338c59ff8079dd30763ba2710c9868e9a4dda8bda080baef7a46a8a21c4b67fdecab051447eb2064015625e1e5f843f741de767c85
|
7
|
+
data.tar.gz: 3d95d7a8a67337c18b56d569e3b6e45dfe65331e9a522a5d7f5a8586c330698c81199699584f94080b52befdaf561ffd5d4c9b683958244f1175515e8abf735f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in itamae.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
path = Pathname.new("Gemfile.local")
|
7
|
+
eval(path.read) if path.exist?
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
if RUBY_PLATFORM.include?('darwin')
|
11
|
+
gem 'growl'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013-2014 Ryota Arai
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# Itamae
|
2
|
+
|
3
|
+
Configuration management tool like Chef which is simpler and lighter than Chef
|
4
|
+
|
5
|
+
## Concept
|
6
|
+
|
7
|
+
* Good DSL like Chef
|
8
|
+
* Simpler and lighter than Chef
|
9
|
+
* It's just like Chef. No compatibility.
|
10
|
+
* Idempotent.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
```
|
15
|
+
$ gem install itamae
|
16
|
+
```
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
### Run locally
|
21
|
+
|
22
|
+
```
|
23
|
+
$ sudo itamae execute -j example/node.json example/recipe.rb
|
24
|
+
D, [2013-12-24T14:05:50.859587 #7156] DEBUG -- : Loading node data from /vagrant/example/node.json ...
|
25
|
+
I, [2013-12-24T14:05:50.862072 #7156] INFO -- : >>> Executing Itamae::Resources::Package ({:action=>:install, :name=>"git"})...
|
26
|
+
D, [2013-12-24T14:05:51.335070 #7156] DEBUG -- : Command `apt-get -y install git` succeeded
|
27
|
+
D, [2013-12-24T14:05:51.335251 #7156] DEBUG -- : STDOUT> Reading package lists...
|
28
|
+
Building dependency tree...
|
29
|
+
Reading state information...
|
30
|
+
git is already the newest version.
|
31
|
+
0 upgraded, 0 newly installed, 0 to remove and 156 not upgraded.
|
32
|
+
D, [2013-12-24T14:05:51.335464 #7156] DEBUG -- : STDERR>
|
33
|
+
I, [2013-12-24T14:05:51.335531 #7156] INFO -- : <<< Succeeded.
|
34
|
+
I, [2013-12-24T14:05:51.335728 #7156] INFO -- : >>> Executing Itamae::Resources::File ({:action=>:create, :source=>"foo", :path=>"/home/vagrant/foo"})...
|
35
|
+
D, [2013-12-24T14:05:51.335842 #7156] DEBUG -- : Copying a file from '/vagrant/example/foo' to '/home/vagrant/foo'...
|
36
|
+
I, [2013-12-24T14:05:51.339119 #7156] INFO -- : <<< Succeeded.
|
37
|
+
```
|
38
|
+
|
39
|
+
### Run via SSH
|
40
|
+
|
41
|
+
```
|
42
|
+
$ itamae ssh -j example/node.json -h 192.168.10.10 -p 22 -u user -i /path/to/private_key example/recipe.rb
|
43
|
+
```
|
44
|
+
|
45
|
+
## Run tests
|
46
|
+
|
47
|
+
Requirements: Vagrant
|
48
|
+
|
49
|
+
```
|
50
|
+
$ bundle exec rake spec
|
51
|
+
```
|
52
|
+
|
53
|
+
## Contributing
|
54
|
+
|
55
|
+
1. Fork it
|
56
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
57
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
58
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
59
|
+
5. Create new Pull Request
|
60
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'net/ssh'
|
5
|
+
|
6
|
+
desc 'Run unit and integration specs.'
|
7
|
+
task :spec => ['spec:unit', 'spec:integration:all']
|
8
|
+
|
9
|
+
namespace :spec do
|
10
|
+
RSpec::Core::RakeTask.new("unit") do |task|
|
11
|
+
task.ruby_opts = '-I ./spec/unit'
|
12
|
+
task.pattern = "./spec/unit{,/*/**}/*_spec.rb"
|
13
|
+
end
|
14
|
+
|
15
|
+
namespace :integration do
|
16
|
+
targets = []
|
17
|
+
Bundler.with_clean_env do
|
18
|
+
`cd spec/integration && /usr/bin/vagrant status`.split("\n\n")[1].each_line do |line|
|
19
|
+
targets << line.match(/^[^ ]+/)[0]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
task :all => targets
|
24
|
+
|
25
|
+
targets.each do |target|
|
26
|
+
desc "Run provision and specs to #{target}"
|
27
|
+
task target => ["provision:#{target}", "serverspec:#{target}"]
|
28
|
+
|
29
|
+
namespace :provision do
|
30
|
+
task target do
|
31
|
+
Bundler.with_clean_env do
|
32
|
+
config = Tempfile.new('', Dir.tmpdir)
|
33
|
+
env = {"VAGRANT_CWD" => File.expand_path('./spec/integration')}
|
34
|
+
system env, "/usr/bin/vagrant up #{target}"
|
35
|
+
system env, "/usr/bin/vagrant ssh-config #{target} > #{config.path}"
|
36
|
+
options = Net::SSH::Config.for(target, [config.path])
|
37
|
+
|
38
|
+
cmd = "bundle exec bin/itamae ssh"
|
39
|
+
cmd << " -h #{options[:host_name]}"
|
40
|
+
cmd << " -u #{options[:user]}"
|
41
|
+
cmd << " -p #{options[:port]}"
|
42
|
+
cmd << " -i #{options[:keys].first}"
|
43
|
+
cmd << " -j spec/integration/recipes/node.json"
|
44
|
+
cmd << " spec/integration/recipes/default.rb"
|
45
|
+
|
46
|
+
system cmd
|
47
|
+
abort unless $?.exitstatus == 0
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
namespace :serverspec do
|
53
|
+
desc "Run serverspec tests to #{target}"
|
54
|
+
RSpec::Core::RakeTask.new(target.to_sym) do |t|
|
55
|
+
ENV['TARGET_HOST'] = target
|
56
|
+
t.ruby_opts = '-I ./spec/integration'
|
57
|
+
t.pattern = "spec/integration/*_spec.rb"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/bin/itamae
ADDED
data/example/foo
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Hello
|
data/example/node.json
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"file_source": "foo"}
|
data/example/recipe.rb
ADDED
data/itamae.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'itamae/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "itamae"
|
8
|
+
spec.version = Itamae::VERSION
|
9
|
+
spec.authors = ["Ryota Arai"]
|
10
|
+
spec.email = ["ryota.arai@gmail.com"]
|
11
|
+
spec.summary = %q{Simple Configuration Management Tool}
|
12
|
+
spec.homepage = "https://github.com/ryotarai/itamae"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_runtime_dependency "thor"
|
21
|
+
spec.add_runtime_dependency "specinfra", "2.0.0.beta20"
|
22
|
+
spec.add_runtime_dependency "hashie"
|
23
|
+
|
24
|
+
# TODO: move to specinfra
|
25
|
+
spec.add_runtime_dependency "net-scp"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
30
|
+
spec.add_development_dependency "serverspec", "2.0.0.beta16"
|
31
|
+
spec.add_development_dependency "pry-byebug"
|
32
|
+
end
|
data/lib/itamae.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "itamae/version"
|
2
|
+
require "itamae/runner"
|
3
|
+
require "itamae/cli"
|
4
|
+
require "itamae/recipe"
|
5
|
+
require "itamae/resources"
|
6
|
+
require "itamae/logger"
|
7
|
+
require "itamae/node"
|
8
|
+
require "itamae/specinfra"
|
9
|
+
|
10
|
+
module Itamae
|
11
|
+
# Your code goes here...
|
12
|
+
end
|
13
|
+
|
data/lib/itamae/cli.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'itamae'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module Itamae
|
5
|
+
class CLI < Thor
|
6
|
+
desc "local RECIPE [RECIPE...]", "Run Itamae locally"
|
7
|
+
option :node_json, type: :string, aliases: ['-j']
|
8
|
+
def local(*recipe_files)
|
9
|
+
Runner.run(recipe_files, :local, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "ssh RECIPE [RECIPE...]", "Run Itamae via ssh"
|
13
|
+
option :node_json, type: :string, aliases: ['-j']
|
14
|
+
option :host, required: true, type: :string, aliases: ['-h']
|
15
|
+
option :user, type: :string, aliases: ['-u']
|
16
|
+
option :key, type: :string, aliases: ['-i']
|
17
|
+
option :port, type: :numeric, aliases: ['-p']
|
18
|
+
def ssh(*recipe_files)
|
19
|
+
Runner.run(recipe_files, :ssh, options)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'itamae'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
module Itamae
|
5
|
+
module Logger
|
6
|
+
class Formatter
|
7
|
+
def call(severity, datetime, progname, msg)
|
8
|
+
"[%s] %5s : %s\n" % [format_datetime(datetime), severity, msg2str(msg)]
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def format_datetime(time)
|
13
|
+
time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d" % time.usec
|
14
|
+
end
|
15
|
+
|
16
|
+
def msg2str(msg)
|
17
|
+
case msg
|
18
|
+
when ::String
|
19
|
+
msg
|
20
|
+
when ::Exception
|
21
|
+
"#{ msg.message } (#{ msg.class })\n" <<
|
22
|
+
(msg.backtrace || []).join("\n")
|
23
|
+
else
|
24
|
+
msg.inspect
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.logger
|
30
|
+
@logger ||= ::Logger.new($stdout).tap do |logger|
|
31
|
+
logger.formatter = Formatter.new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.logger=(l)
|
36
|
+
@logger = l
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.method_missing(method, *args, &block)
|
40
|
+
logger.public_send(method, *args, &block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
data/lib/itamae/node.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'itamae'
|
2
|
+
|
3
|
+
module Itamae
|
4
|
+
class Recipe
|
5
|
+
attr_reader :path
|
6
|
+
attr_reader :runner
|
7
|
+
|
8
|
+
def initialize(runner, path)
|
9
|
+
@runner = runner
|
10
|
+
@path = path
|
11
|
+
@resources = []
|
12
|
+
load_resources
|
13
|
+
end
|
14
|
+
|
15
|
+
def node
|
16
|
+
@runner.node
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
@resources.each do |resource|
|
21
|
+
Logger.info ">>> Executing #{resource.class.name} (#{resource.options})..."
|
22
|
+
begin
|
23
|
+
resource.run
|
24
|
+
rescue Resources::CommandExecutionError
|
25
|
+
Logger.error "<<< Failed."
|
26
|
+
exit 2
|
27
|
+
else
|
28
|
+
Logger.info "<<< Succeeded."
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def load_resources
|
36
|
+
instance_eval(File.read(@path), @path, 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(method, name, &block)
|
40
|
+
klass = Resources.get_resource_class(method)
|
41
|
+
resource = klass.new(self, name, &block)
|
42
|
+
@resources << resource
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'itamae'
|
2
|
+
require 'itamae/resources/base'
|
3
|
+
require 'itamae/resources/file'
|
4
|
+
require 'itamae/resources/package'
|
5
|
+
require 'itamae/resources/remote_file'
|
6
|
+
require 'itamae/resources/directory'
|
7
|
+
require 'itamae/resources/template'
|
8
|
+
|
9
|
+
module Itamae
|
10
|
+
module Resources
|
11
|
+
Error = Class.new(StandardError)
|
12
|
+
CommandExecutionError = Class.new(StandardError)
|
13
|
+
OptionMissingError = Class.new(StandardError)
|
14
|
+
InvalidTypeError = Class.new(StandardError)
|
15
|
+
NotSupportedOsError = Class.new(StandardError)
|
16
|
+
|
17
|
+
def self.get_resource_class_name(method)
|
18
|
+
method.to_s.split('_').map {|part| part.capitalize}.join
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.get_resource_class(method)
|
22
|
+
const_get(get_resource_class_name(method))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'itamae'
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
module Itamae
|
5
|
+
module Resources
|
6
|
+
class Base
|
7
|
+
@defined_options ||= {}
|
8
|
+
@supported_oses ||= []
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_reader :defined_options
|
12
|
+
attr_reader :supported_oses
|
13
|
+
|
14
|
+
def inherited(subclass)
|
15
|
+
subclass.instance_variable_set(
|
16
|
+
:@defined_options,
|
17
|
+
self.defined_options.dup
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def define_option(name, options)
|
22
|
+
current = @defined_options[name.to_sym] || {}
|
23
|
+
@defined_options[name.to_sym] = current.merge(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def support_os(hash)
|
27
|
+
@supported_oses << hash
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
define_option :action, type: Symbol, required: true
|
32
|
+
|
33
|
+
attr_reader :resource_name
|
34
|
+
attr_reader :options
|
35
|
+
|
36
|
+
def initialize(recipe, resource_name, &block)
|
37
|
+
@options = {}
|
38
|
+
@recipe = recipe
|
39
|
+
@resource_name = resource_name
|
40
|
+
|
41
|
+
instance_eval(&block) if block_given?
|
42
|
+
|
43
|
+
process_options
|
44
|
+
ensure_os
|
45
|
+
end
|
46
|
+
|
47
|
+
def run
|
48
|
+
public_send("#{action}_action".to_sym)
|
49
|
+
end
|
50
|
+
|
51
|
+
def nothing_action
|
52
|
+
# do nothing
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def method_missing(method, *args)
|
58
|
+
if args.size == 1 && self.class.defined_options[method]
|
59
|
+
return @options[method] = args.first
|
60
|
+
elsif args.size == 0 && @options.has_key?(method)
|
61
|
+
return @options[method]
|
62
|
+
end
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
def process_options
|
67
|
+
self.class.defined_options.each_pair do |key, details|
|
68
|
+
@options[key] ||= @resource_name if details[:default_name]
|
69
|
+
@options[key] ||= details[:default]
|
70
|
+
|
71
|
+
if details[:required] && !@options[key]
|
72
|
+
raise Resources::OptionMissingError, "'#{key}' option is required but it is not set."
|
73
|
+
end
|
74
|
+
|
75
|
+
if @options[key] && details[:type] && !@options[key].is_a?(details[:type])
|
76
|
+
raise Resources::InvalidTypeError, "#{key} option should be #{details[:type]}."
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def run_specinfra(type, *args)
|
82
|
+
command = Specinfra.command.public_send(type, *args)
|
83
|
+
run_command(command)
|
84
|
+
end
|
85
|
+
|
86
|
+
def run_command(command)
|
87
|
+
result = backend.run_command(command)
|
88
|
+
exit_status = result.exit_status
|
89
|
+
|
90
|
+
if exit_status == 0
|
91
|
+
method = :debug
|
92
|
+
Logger.public_send(method, "Command `#{command}` succeeded")
|
93
|
+
else
|
94
|
+
method = :error
|
95
|
+
Logger.public_send(method, "Command `#{command}` failed. (exit status: #{exit_status})")
|
96
|
+
end
|
97
|
+
|
98
|
+
if result.stdout && result.stdout != ''
|
99
|
+
Logger.public_send(method, "STDOUT> #{result.stdout.chomp}")
|
100
|
+
end
|
101
|
+
if result.stderr && result.stderr != ''
|
102
|
+
Logger.public_send(method, "STDERR> #{result.stderr.chomp}")
|
103
|
+
end
|
104
|
+
|
105
|
+
unless exit_status == 0
|
106
|
+
raise CommandExecutionError
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def copy_file(src, dst)
|
111
|
+
Logger.debug "Copying a file from '#{src}' to '#{dst}'..."
|
112
|
+
unless ::File.exist?(src)
|
113
|
+
raise Error, "The file '#{src}' doesn't exist."
|
114
|
+
end
|
115
|
+
unless backend.copy_file(src, dst)
|
116
|
+
raise Error, "Copying a file failed."
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def node
|
121
|
+
runner.node
|
122
|
+
end
|
123
|
+
|
124
|
+
def backend
|
125
|
+
Itamae.backend
|
126
|
+
end
|
127
|
+
|
128
|
+
def runner
|
129
|
+
@recipe.runner
|
130
|
+
end
|
131
|
+
|
132
|
+
def shell_escape(str)
|
133
|
+
Shellwords.escape(str)
|
134
|
+
end
|
135
|
+
|
136
|
+
def ensure_os
|
137
|
+
return unless self.class.supported_oses
|
138
|
+
ok = self.class.supported_oses.any? do |supported|
|
139
|
+
supported.each_pair.all? do |k, v|
|
140
|
+
backend.os[k] == v
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
unless ok
|
145
|
+
raise NotSupportedOsError, "#{self.class.name} resource doesn't support this OS now."
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|