itamae 1.0.0.beta1
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.
- 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
|
+
|