atesta 0.0.0 → 0.0.1
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/VERSION +1 -1
- data/lib/atesta.rb +12 -0
- data/lib/block_attr.rb +23 -0
- data/lib/class_attr.rb +26 -0
- data/lib/execution.rb +95 -0
- data/lib/hash.rb +36 -0
- data/lib/lock.rb +22 -0
- data/lib/node.rb +38 -0
- data/lib/output.rb +50 -0
- data/lib/recipe.rb +183 -0
- data/lib/release_window.rb +30 -0
- data/lib/resource/base.rb +49 -0
- data/lib/resource/cron.rb +23 -0
- data/lib/resource/directory.rb +24 -0
- data/lib/resource/execute.rb +30 -0
- data/lib/resource/file.rb +33 -0
- data/lib/resource/gem.rb +27 -0
- data/lib/resource/git.rb +102 -0
- data/lib/resource/group.rb +28 -0
- data/lib/resource/hook.rb +25 -0
- data/lib/resource/link.rb +27 -0
- data/lib/resource/package.rb +26 -0
- data/lib/resource/remote_file.rb +44 -0
- data/lib/resource/service.rb +23 -0
- data/lib/resource/swap_release.rb +25 -0
- data/lib/resource/template.rb +68 -0
- data/lib/resource/user.rb +29 -0
- data/lib/resource/version.rb +42 -0
- data/lib/resource.rb +20 -0
- data/lib/runtime_error.rb +8 -0
- data/lib/status.rb +37 -0
- metadata +33 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1
|
data/lib/atesta.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'lib/block_attr'
|
2
|
+
require 'lib/class_attr'
|
3
|
+
require 'lib/execution'
|
4
|
+
require 'lib/hash'
|
5
|
+
require 'lib/lock'
|
6
|
+
require 'lib/node'
|
7
|
+
require 'lib/output'
|
8
|
+
require 'lib/recipe'
|
9
|
+
require 'lib/release_window'
|
10
|
+
require 'lib/runtime_error'
|
11
|
+
require 'lib/status'
|
12
|
+
require 'lib/resource'
|
data/lib/block_attr.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module BlockAttr
|
2
|
+
|
3
|
+
def self.included klass
|
4
|
+
klass.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
|
9
|
+
# No Convention over Configuration attributes.
|
10
|
+
def block_attr *list
|
11
|
+
@attributes = ((@attributes || [])+ list).uniq
|
12
|
+
list.each do |new_method|
|
13
|
+
instance_eval do
|
14
|
+
define_method new_method do |argument|
|
15
|
+
instance_variable_set "@#{new_method}", argument
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/lib/class_attr.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
# Dynamically define class attribute accessors
|
3
|
+
module ClassAttr
|
4
|
+
|
5
|
+
def self.included klass
|
6
|
+
klass.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def class_attr *list
|
12
|
+
list.each do |my_method|
|
13
|
+
eval "
|
14
|
+
def self.#{my_method}= #{my_method}
|
15
|
+
@#{my_method} = #{my_method}
|
16
|
+
end
|
17
|
+
def self.#{my_method}
|
18
|
+
@#{my_method}
|
19
|
+
end
|
20
|
+
"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/execution.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'md5'
|
2
|
+
|
3
|
+
class Execution
|
4
|
+
|
5
|
+
attr_accessor :user, :always_run
|
6
|
+
|
7
|
+
def initialize title, value
|
8
|
+
@commands = []
|
9
|
+
@title = title
|
10
|
+
@value = value
|
11
|
+
@always_run = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def ignore
|
15
|
+
Output.jump
|
16
|
+
Output.error 'Ignoring execution', '..'
|
17
|
+
Output.ruler
|
18
|
+
end
|
19
|
+
|
20
|
+
def always_run boolean
|
21
|
+
@always_run = boolean
|
22
|
+
end
|
23
|
+
|
24
|
+
def banner
|
25
|
+
Output.jump
|
26
|
+
Output.info @title, @value
|
27
|
+
# Output.info 'Hash', serialize
|
28
|
+
Output.ruler
|
29
|
+
end
|
30
|
+
|
31
|
+
def serialize
|
32
|
+
MD5.hexdigest @title + (@commands * '')
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.block title, value = nil, user = 'deploy', &block
|
36
|
+
@object = new(title, value)
|
37
|
+
@object.user = user
|
38
|
+
@object.execute &block
|
39
|
+
end
|
40
|
+
|
41
|
+
def execute &block
|
42
|
+
banner
|
43
|
+
yield(self)
|
44
|
+
run_commands
|
45
|
+
end
|
46
|
+
|
47
|
+
def run_commands
|
48
|
+
st = Status.get
|
49
|
+
st.execution!.hashes = [] unless st.execution.respond_to?(:hashes)
|
50
|
+
if st.execution.hashes.include?(serialize)
|
51
|
+
Output.warn 'Ignoring', 'Already executed..'
|
52
|
+
end
|
53
|
+
if @always_run
|
54
|
+
Output.warn 'Always run switch detected', 'Forcing execution!'
|
55
|
+
end
|
56
|
+
@commands.map { |cmd| code_for(cmd) }.each do |code|
|
57
|
+
Output.command code
|
58
|
+
unless @always_run
|
59
|
+
next if st.execution.hashes.include? serialize
|
60
|
+
end
|
61
|
+
run_or_raise code
|
62
|
+
end
|
63
|
+
unless st.execution.hashes.include? serialize
|
64
|
+
st.execution.hashes << serialize
|
65
|
+
end
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def run_or_raise code
|
70
|
+
return if system code
|
71
|
+
Output.jump
|
72
|
+
Output.ruler :error
|
73
|
+
Output.error 'EXECUTION FAILED', code
|
74
|
+
Output.ruler :error
|
75
|
+
raise 'Que pedo!'
|
76
|
+
end
|
77
|
+
|
78
|
+
def code_for cmd
|
79
|
+
if cmd[:path]
|
80
|
+
"cd #{cmd[:path]} && sudo -u #{@user} #{cmd[:command]}"
|
81
|
+
else
|
82
|
+
"sudo -u #{@user} #{cmd[:command]}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def run string, path = nil
|
87
|
+
@commands << { :command => string, :path => path }
|
88
|
+
end
|
89
|
+
|
90
|
+
def command string, path = nil
|
91
|
+
run string, path
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
data/lib/hash.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
# Merges self with another hash, recursively.
|
4
|
+
#
|
5
|
+
# This code was lovingly stolen from some random gem:
|
6
|
+
# http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
|
7
|
+
#
|
8
|
+
# Thanks to whoever made it.
|
9
|
+
def deep_merge(hash)
|
10
|
+
target = dup
|
11
|
+
|
12
|
+
hash.keys.each do |key|
|
13
|
+
if hash[key].is_a? Hash and self[key].is_a? Hash
|
14
|
+
target[key] = target[key].deep_merge(hash[key])
|
15
|
+
next
|
16
|
+
end
|
17
|
+
|
18
|
+
target[key] = hash[key]
|
19
|
+
end
|
20
|
+
|
21
|
+
target
|
22
|
+
end
|
23
|
+
|
24
|
+
# From: http://www.gemtacular.com/gemdocs/cerberus-0.2.2/doc/classes/Hash.html
|
25
|
+
# File lib/cerberus/utils.rb, line 42
|
26
|
+
def deep_merge!(second)
|
27
|
+
second.each_pair do |k,v|
|
28
|
+
if self[k].is_a?(Hash) and second[k].is_a?(Hash)
|
29
|
+
self[k].deep_merge!(second[k])
|
30
|
+
else
|
31
|
+
self[k] = second[k]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/lock.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
class Lock; end
|
2
|
+
|
3
|
+
class << Lock
|
4
|
+
|
5
|
+
def use lock_file
|
6
|
+
@lock_file = lock_file
|
7
|
+
end
|
8
|
+
|
9
|
+
def locked?
|
10
|
+
File.exist? @lock_file
|
11
|
+
end
|
12
|
+
|
13
|
+
def lock
|
14
|
+
system "touch #{@lock_file}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def unlock
|
18
|
+
lock
|
19
|
+
system "rm #{@lock_file}"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/node.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hashie'
|
3
|
+
|
4
|
+
class Node
|
5
|
+
|
6
|
+
def self.set object
|
7
|
+
@node = object
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.get
|
11
|
+
@node
|
12
|
+
end
|
13
|
+
|
14
|
+
def dna
|
15
|
+
@dna
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.magic matcher, path
|
19
|
+
set resolve(matcher, path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.resolve matcher, path
|
23
|
+
Output.banner 'Loading', 'Merging default attributes...'
|
24
|
+
@hash = @dna = eval(File.read path)
|
25
|
+
Dir[matcher].each do |attr_file|
|
26
|
+
next if File.directory? attr_file
|
27
|
+
Output.info 'Merging node', attr_file
|
28
|
+
@hash = @hash.deep_merge(eval(File.read attr_file) || {}).
|
29
|
+
deep_merge(@hash)
|
30
|
+
end
|
31
|
+
# TODO: remove ARGV
|
32
|
+
@hash[:instance_role] = ARGV[1]
|
33
|
+
@hash[:platform] = 'ubuntu'
|
34
|
+
Hashie::Mash.new(@hash)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
data/lib/output.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'isna'
|
3
|
+
|
4
|
+
module Output
|
5
|
+
|
6
|
+
CHAR = '#'
|
7
|
+
RULER = '='
|
8
|
+
|
9
|
+
def self.jump
|
10
|
+
puts ''
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.ruler type_of_output = :info
|
14
|
+
puts "[%s;%s;%sm#{CHAR} #{RULER * 77}[0m" % type_for(type_of_output)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.banner key, value, type_of_output = :info
|
18
|
+
jump
|
19
|
+
kv key, value, type_for(type_of_output)
|
20
|
+
ruler type_of_output
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.command code
|
24
|
+
puts "[0;36;1m#{code}[0m"
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.type_for symbol
|
28
|
+
return [0, 32, 1] if symbol == :info
|
29
|
+
return [0, 33, 1] if symbol == :warn
|
30
|
+
return [5, 31, 1] if symbol == :error
|
31
|
+
[1, 36, 1]
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.info key, value
|
35
|
+
kv key, value, self.type_for(:info)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.warn key, value
|
39
|
+
kv key, value, type_for(:warn)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.error key, value
|
43
|
+
kv key, value, type_for(:error)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.kv key, value, combo
|
47
|
+
puts "[%s;%s;%sm#{CHAR} #{key}[0m: [0;0m#{value}[0m" % combo
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
data/lib/recipe.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
module Recipe
|
2
|
+
|
3
|
+
attr_accessor :stack
|
4
|
+
|
5
|
+
def change_binding binding
|
6
|
+
@binding = binding
|
7
|
+
end
|
8
|
+
|
9
|
+
def init binding
|
10
|
+
change_binding binding
|
11
|
+
stack
|
12
|
+
end
|
13
|
+
|
14
|
+
def resource_not_supported *args
|
15
|
+
Output.warn 'Resource not supported', args.inspect
|
16
|
+
end
|
17
|
+
|
18
|
+
def clean_stack!
|
19
|
+
@stack = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def cron_append object
|
23
|
+
@cron_jobs << object
|
24
|
+
Output.info 'Cron job detected', object.get_title
|
25
|
+
end
|
26
|
+
|
27
|
+
def cron_variable title, variable
|
28
|
+
@cron_jobs ||= []
|
29
|
+
@cron_vars ||= []
|
30
|
+
@cron_vars << ''
|
31
|
+
@cron_vars << "# #{title}"
|
32
|
+
@cron_vars << variable
|
33
|
+
end
|
34
|
+
|
35
|
+
def setup_crontab
|
36
|
+
Output.jump
|
37
|
+
Output.info 'Setting up nice cron jobs', 'this is sweeet root crontab!'
|
38
|
+
Output.ruler
|
39
|
+
t = ::Tempfile.new('temporal_crontab')
|
40
|
+
@cron_vars.each do |line|
|
41
|
+
t.puts line
|
42
|
+
end
|
43
|
+
@cron_jobs.each do |resource|
|
44
|
+
t.puts ''
|
45
|
+
t.puts "# #{resource.get_title}"
|
46
|
+
t.puts "#{resource.run}"
|
47
|
+
end
|
48
|
+
t.close
|
49
|
+
system "cat #{t.path} | crontab"
|
50
|
+
system 'crontab -l'
|
51
|
+
t.unlink
|
52
|
+
end
|
53
|
+
|
54
|
+
def stack
|
55
|
+
@stack ||= []
|
56
|
+
end
|
57
|
+
|
58
|
+
def stack_append object
|
59
|
+
@stack << object
|
60
|
+
end
|
61
|
+
|
62
|
+
def template name, &block
|
63
|
+
stack_append ::Resource::Template.new(name, &block)
|
64
|
+
end
|
65
|
+
|
66
|
+
def directory name, &block
|
67
|
+
stack_append ::Resource::Directory.new(name, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
def gem_package name, &block
|
71
|
+
stack_append ::Resource::Gem.new(name, &block)
|
72
|
+
end
|
73
|
+
|
74
|
+
def package package_name, &block
|
75
|
+
block = Proc.new {} unless block
|
76
|
+
stack_append ::Resource::Package.new(package_name, &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def execute title, &block
|
80
|
+
stack_append ::Resource::Execute.new(title, &block)
|
81
|
+
end
|
82
|
+
|
83
|
+
def user username, &block
|
84
|
+
stack_append ::Resource::User.new(username, &block)
|
85
|
+
end
|
86
|
+
|
87
|
+
def link source, &block
|
88
|
+
stack_append ::Resource::Link.new(source, &block)
|
89
|
+
end
|
90
|
+
|
91
|
+
def git repository, &block
|
92
|
+
stack_append ::Resource::Git.new(repository, &block)
|
93
|
+
end
|
94
|
+
|
95
|
+
def cron title, &block
|
96
|
+
cron_append ::Resource::Cron.new(title, &block)
|
97
|
+
end
|
98
|
+
|
99
|
+
def service name, &block
|
100
|
+
stack_append ::Resource::Service.new(name, &block)
|
101
|
+
end
|
102
|
+
|
103
|
+
def system_group groupname, &block
|
104
|
+
stack_append ::Resource::Group.new(groupname, &block)
|
105
|
+
end
|
106
|
+
|
107
|
+
def remote_file target, &block
|
108
|
+
stack_append ::Resource::RemoteFile.new(target, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
def file target, &block
|
112
|
+
stack_append ::Resource::File.new(target, &block)
|
113
|
+
end
|
114
|
+
|
115
|
+
def swap_release release_path, &block
|
116
|
+
stack_append ::Resource::SwapRelease.new(release_path, &block)
|
117
|
+
end
|
118
|
+
|
119
|
+
def version location, &block
|
120
|
+
stack_append ::Resource::Version.new(location, &block)
|
121
|
+
end
|
122
|
+
|
123
|
+
def hook target
|
124
|
+
target = status.release_path + "/deploy/#{target}.rb"
|
125
|
+
Resource::Hook.new(target, @binding).run
|
126
|
+
end
|
127
|
+
|
128
|
+
def node
|
129
|
+
@node ||= ::Node.get
|
130
|
+
end
|
131
|
+
|
132
|
+
def include_recipe name
|
133
|
+
@recipes ||= []
|
134
|
+
if @recipes.include? name
|
135
|
+
Output.warn 'Already loaded recipe with name', name
|
136
|
+
return
|
137
|
+
end
|
138
|
+
@recipes << name
|
139
|
+
Output.info 'Including recipe', name
|
140
|
+
include_file :Recipe, @recipes_target % name
|
141
|
+
end
|
142
|
+
|
143
|
+
def include_file file_type, some_file
|
144
|
+
unless ::File.exist? some_file
|
145
|
+
Output.warn "#{file_type} file not found (skipping)", some_file
|
146
|
+
return
|
147
|
+
end
|
148
|
+
eval(File.read(some_file), @binding)
|
149
|
+
Output.info 'Executable units', stack.size
|
150
|
+
end
|
151
|
+
|
152
|
+
def load_recipes recipes_target, list
|
153
|
+
Output.banner 'Loading', 'Instantiating recipes...'
|
154
|
+
@recipes_target = recipes_target
|
155
|
+
list.each { |recipe| include_recipe recipe }
|
156
|
+
end
|
157
|
+
|
158
|
+
def summary
|
159
|
+
Output.banner 'Printing', 'Execution summary'
|
160
|
+
Output.info 'Total Recipes', node[:recipes].size
|
161
|
+
Output.info 'Total executable stack units', stack.size
|
162
|
+
end
|
163
|
+
|
164
|
+
def status
|
165
|
+
Status.get
|
166
|
+
end
|
167
|
+
|
168
|
+
def transaction &block
|
169
|
+
yield
|
170
|
+
rescue => e
|
171
|
+
Output.error 'Rolling back', ' =:D '
|
172
|
+
raise e
|
173
|
+
end
|
174
|
+
|
175
|
+
def whoami
|
176
|
+
(File.exist? 'env/whoami') ? File.read('env/whoami').chop : 'Unknown user'
|
177
|
+
end
|
178
|
+
|
179
|
+
def server_ip_address
|
180
|
+
(File.exist? 'env/ip') ? File.read('env/ip').chop : 'Unknown ip address'
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class ReleaseWindow
|
2
|
+
|
3
|
+
def initialize releases_path, releases, window = 5, matcher = '*'
|
4
|
+
@matcher = matcher
|
5
|
+
@releases_path = releases_path
|
6
|
+
@releases = releases.compact
|
7
|
+
@window = window
|
8
|
+
end
|
9
|
+
|
10
|
+
def all_releases
|
11
|
+
Dir[@releases_path + @matcher].map do |r|
|
12
|
+
File.basename(r)
|
13
|
+
end.compact
|
14
|
+
end
|
15
|
+
|
16
|
+
def deletable_releases
|
17
|
+
all_releases - current_window
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_window
|
21
|
+
@releases.last(@window)
|
22
|
+
end
|
23
|
+
|
24
|
+
def deletable_files
|
25
|
+
deletable_releases.map do |r|
|
26
|
+
"#{@releases_path}#{r}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Base
|
4
|
+
|
5
|
+
include ::BlockAttr
|
6
|
+
include ::ClassAttr
|
7
|
+
|
8
|
+
# Access child's class_name statically
|
9
|
+
class_attr :class_name
|
10
|
+
|
11
|
+
# This resource should be executed always??
|
12
|
+
# *boolean*
|
13
|
+
block_attr :always_run
|
14
|
+
|
15
|
+
# Setup class name
|
16
|
+
def self.inherited name
|
17
|
+
@class_name = name
|
18
|
+
end
|
19
|
+
|
20
|
+
# Translate octal to decimal modes
|
21
|
+
def unix_mode
|
22
|
+
@mode.to_i.to_s(8)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Configure default settings for any resource
|
26
|
+
def set_base_defaults
|
27
|
+
@not_if = false
|
28
|
+
@owner = 'root'
|
29
|
+
@always_run = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def not_if condition = nil, &block
|
33
|
+
if condition.is_a?(String)
|
34
|
+
if system(condition)
|
35
|
+
@not_if = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
if block_given? && yield
|
39
|
+
@not_if = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def should_skip?
|
44
|
+
@not_if == true
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Cron < Base
|
4
|
+
|
5
|
+
block_attr :title, :command
|
6
|
+
|
7
|
+
def initialize title, &block
|
8
|
+
@command = ''
|
9
|
+
@title = title
|
10
|
+
self.instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_title
|
14
|
+
@title
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
@command
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Directory < Base
|
4
|
+
|
5
|
+
block_attr :owner, :group, :mode, :action, :recursive, :target
|
6
|
+
|
7
|
+
def initialize target, &block
|
8
|
+
set_base_defaults
|
9
|
+
@target = target
|
10
|
+
self.instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
Execution.block 'Creating directory', @target, 'root' do |b|
|
15
|
+
b.always_run @always_run
|
16
|
+
b.run "mkdir -p #{@target}"
|
17
|
+
b.run "chmod #{unix_mode} #{@target}"
|
18
|
+
b.run "chown #{@owner}:#{@group} #{@target}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Execute < Base
|
4
|
+
|
5
|
+
block_attr :owner, :title, :path
|
6
|
+
|
7
|
+
def initialize title, &block
|
8
|
+
set_base_defaults
|
9
|
+
@path = nil
|
10
|
+
@commands = []
|
11
|
+
@title = title
|
12
|
+
self.instance_eval(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def command string
|
16
|
+
@commands << { :command => string, :path => @path }
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
Execution.block 'Execution', @title, @owner do |b|
|
21
|
+
b.always_run @always_run
|
22
|
+
@commands.each do |command_hash|
|
23
|
+
b.run "#{command_hash[:command]}", command_hash[:path]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class File < Base
|
4
|
+
|
5
|
+
block_attr :content, :owner, :group, :mode, :action, :target
|
6
|
+
|
7
|
+
def initialize target, &block
|
8
|
+
set_base_defaults
|
9
|
+
@target = target
|
10
|
+
self.instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Compile any given string into a file remotely!
|
14
|
+
#
|
15
|
+
# 1. try to run everytime
|
16
|
+
# 2. if file exists and current string checksum matches the old
|
17
|
+
# one skip it!
|
18
|
+
# 3. otherwise just re-compile the file!
|
19
|
+
#
|
20
|
+
def run
|
21
|
+
Execution.block 'Creating a custom file', @target, 'root' do |b|
|
22
|
+
b.always_run true
|
23
|
+
b.run "mkdir -p #{::File.dirname(@target)}"
|
24
|
+
::File.open(@target, 'w+') { |file| file.write @content }
|
25
|
+
b.run "chown #{@owner}:#{@owner} #{::File.dirname(@target)}"
|
26
|
+
b.run "chown #{@owner}:#{@owner} #{@target}"
|
27
|
+
b.run "chmod #{unix_mode} #{@target}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/resource/gem.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Gem < Base
|
4
|
+
|
5
|
+
block_attr :version, :source, :action, :owner, :name
|
6
|
+
|
7
|
+
def initialize name, &block
|
8
|
+
set_base_defaults
|
9
|
+
@owner = 'root'
|
10
|
+
@name = name
|
11
|
+
self.instance_eval(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
command = []
|
16
|
+
command << "gem install #{@name}"
|
17
|
+
command << "--source #{@source}" if @source
|
18
|
+
command << "--version #{@version}" if @version
|
19
|
+
Execution.block 'Installing gem', @name, @owner do |b|
|
20
|
+
b.always_run @always_run
|
21
|
+
b.run(command * ' ')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/resource/git.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Git < Base
|
4
|
+
|
5
|
+
block_attr :owner, :repository, :sandbox_path, :sandbox_name
|
6
|
+
block_attr :branch, :release_path, :timestamped, :swaping_branch
|
7
|
+
block_attr :capsule_object
|
8
|
+
|
9
|
+
def initialize repository, &block
|
10
|
+
set_base_defaults
|
11
|
+
@repository = repository
|
12
|
+
@sandbox_path = '/tmp'
|
13
|
+
@sandbox_name = 'repository_sandbox'
|
14
|
+
@always_run = true
|
15
|
+
@timestamped = true
|
16
|
+
@swaping_branch = 'master'
|
17
|
+
self.instance_eval(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
clone unless cloned?
|
22
|
+
fetch_and_pull
|
23
|
+
revision = revision(@branch)
|
24
|
+
checkout revision
|
25
|
+
key = @timestamped ? Time.now.strftime('%Y%m%d%H%M%S') : revision
|
26
|
+
my_release_path = @release_path + key
|
27
|
+
relocate my_release_path
|
28
|
+
encapsulate_object revision, my_release_path, key
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def encapsulate_object revision, my_release_path, key
|
34
|
+
@capsule_object.release_path = my_release_path
|
35
|
+
@capsule_object.revision = revision
|
36
|
+
@capsule_object.key = key
|
37
|
+
end
|
38
|
+
|
39
|
+
def clone args = []
|
40
|
+
Execution.block 'Cloning repository', @owner do |b|
|
41
|
+
b.always_run @always_run
|
42
|
+
b.run "git clone #{args.join(' ')} #{@repository} #{@sandbox_path}/#{@sandbox_name}", @sandbox_path
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_and_pull
|
47
|
+
Execution.block 'Updating existing repository changes', @repository, @owner do |b|
|
48
|
+
b.always_run @always_run
|
49
|
+
b.run "git checkout #{@swaping_branch}", checkout_location
|
50
|
+
b.run 'git fetch', checkout_location
|
51
|
+
b.run 'git pull', checkout_location
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def relocate target
|
56
|
+
Execution.block 'Installing snapshot of checkout', @owner, @owner do |b|
|
57
|
+
b.always_run @always_run
|
58
|
+
b.run "touch #{target}"
|
59
|
+
b.run "rm -rf #{target}"
|
60
|
+
b.run "cp -r #{checkout_location} #{target}"
|
61
|
+
b.run "ls #{target} | column"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def revision branch
|
66
|
+
return @revision if @revision
|
67
|
+
Execution.block "Extracting revision hash for", branch, @owner do |b|
|
68
|
+
b.always_run @always_run
|
69
|
+
b.run "git ls-remote #{@repository} #{branch}"
|
70
|
+
end
|
71
|
+
@revision = `sudo -u #{@owner} git ls-remote #{@repository} #{branch}`
|
72
|
+
@revision = (@revision.scan /[a-zA-Z0-9]{40}/).first
|
73
|
+
end
|
74
|
+
|
75
|
+
def checkout revision
|
76
|
+
Execution.block "Using revision to create new branch", "#{revision} ~> #{@owner}", @owner do |b|
|
77
|
+
b.always_run @always_run
|
78
|
+
b.run "git checkout #{@swaping_branch}", checkout_location
|
79
|
+
b.run "git branch -f #{@owner}", checkout_location
|
80
|
+
b.run "git branch -D #{@owner}", checkout_location
|
81
|
+
b.run "git checkout -b #{@owner} #{revision}", checkout_location
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def checkout_location
|
86
|
+
"#{@sandbox_path}/#{@sandbox_name}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def remove
|
90
|
+
Execution.block "Removing existing copy of repository: #{checkout_location}", @owner do |b|
|
91
|
+
b.always_run @always_run
|
92
|
+
b.run "rm -rf #{checkout_location}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def cloned?
|
97
|
+
::File.exist? checkout_location
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Group < Base
|
4
|
+
|
5
|
+
block_attr :groupname, :gid
|
6
|
+
|
7
|
+
def initialize groupname, &block
|
8
|
+
set_base_defaults
|
9
|
+
@groupname = groupname
|
10
|
+
self.instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
Execution.block 'Creating new group', @groupname, 'root' do |b|
|
15
|
+
b.always_run @always_run
|
16
|
+
groups = `cat /etc/group | cut -d: -f1`
|
17
|
+
groups = groups.scan(/[a-zA-Z\-_]+/)
|
18
|
+
if groups.include? @groupname
|
19
|
+
Output.warn 'Aborted, I think this group already exists', groups.inspect
|
20
|
+
else
|
21
|
+
b.run "groupadd -g #{@gid} #{@groupname}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Hook < Base
|
4
|
+
|
5
|
+
def initialize target, binding
|
6
|
+
@target = target
|
7
|
+
@binding = binding
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
if ::File.exist?(@target)
|
12
|
+
Output.info 'Hook found', @target
|
13
|
+
eval(::File.read(@target), @binding)
|
14
|
+
else
|
15
|
+
Output.warn 'Hook not found', @target
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def should_skip?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Link < Base
|
4
|
+
|
5
|
+
block_attr :source, :to, :owner, :group
|
6
|
+
|
7
|
+
def initialize source, &block
|
8
|
+
set_base_defaults
|
9
|
+
@source = source
|
10
|
+
@to = 'no_target'
|
11
|
+
self.instance_eval(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
Execution.block 'Building Link', "#{@source} ~> #{@to}", @owner do |b|
|
16
|
+
b.always_run @always_run
|
17
|
+
b.run "mkdir -p #{::File.dirname(@to)}"
|
18
|
+
b.run "mkdir -p #{::File.dirname(@source)}" unless ::File.exist?(::File.dirname(@source))
|
19
|
+
b.run "touch #{@source}"
|
20
|
+
b.run "rm -rf #{@source}"
|
21
|
+
b.run "ln -s #{@to} #{@source}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Package < Base
|
4
|
+
|
5
|
+
block_attr :action, :package_name, :owner
|
6
|
+
|
7
|
+
def initialize package_name, &block
|
8
|
+
set_base_defaults
|
9
|
+
@package_name = package_name
|
10
|
+
self.instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
Execution.block 'Installing Package', @package_name, @owner do |b|
|
15
|
+
b.always_run @always_run
|
16
|
+
b.run "apt-get install -y #{@package_name}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def value_for_platform *args
|
21
|
+
@package_name
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class RemoteFile < Base
|
4
|
+
|
5
|
+
block_attr :owner, :group, :mode, :source
|
6
|
+
|
7
|
+
# Install a static local file into a remote server.
|
8
|
+
def initialize target, &block
|
9
|
+
set_base_defaults
|
10
|
+
@pattern = 'cookbooks/*/files/default/'
|
11
|
+
@target = target
|
12
|
+
self.instance_eval(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def content
|
16
|
+
(Dir[@pattern + '*'] + Dir[@pattern + '*.*']).each do |file|
|
17
|
+
return ::File.read(file) if file.include? @source
|
18
|
+
end
|
19
|
+
'Resource was not found'
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
Execution.block 'Creating a remote file', @target, @owner do |b|
|
24
|
+
if ::File.exist? @target
|
25
|
+
sums_equal = MD5.hexdigest(::File.read(@target)) == MD5.hexdigest(content)
|
26
|
+
else
|
27
|
+
sums_equal = false
|
28
|
+
@always_run = true
|
29
|
+
end
|
30
|
+
if sums_equal
|
31
|
+
Output.warn 'Skipping', 'checksum comparison matches'
|
32
|
+
else
|
33
|
+
Output.warn 'Generating file with ruby', @target
|
34
|
+
::File.open(@target, 'w+') { |file| file.write content }
|
35
|
+
b.always_run @always_run
|
36
|
+
b.run "chown #{@owner}:#{@group} #{@target}"
|
37
|
+
b.run "chmod #{unix_mode} #{@target}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Service < Base
|
4
|
+
|
5
|
+
block_attr :action
|
6
|
+
|
7
|
+
def initialize name, &block
|
8
|
+
set_base_defaults
|
9
|
+
@name = name
|
10
|
+
@always_run = true
|
11
|
+
self.instance_eval(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
Execution.block "Changing #{@name} service", @action, 'root' do |b|
|
16
|
+
b.always_run @always_run
|
17
|
+
b.run "/etc/init.d/#{@name} #{@action}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class SwapRelease < Base
|
4
|
+
|
5
|
+
block_attr :owner, :release_path, :current
|
6
|
+
|
7
|
+
def initialize release_path, &block
|
8
|
+
set_base_defaults
|
9
|
+
@release_path = release_path
|
10
|
+
self.instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
Execution.block 'Swaping releases', "#{@current} ~> #{@release_path}", 'root' do |b|
|
15
|
+
b.always_run true
|
16
|
+
b.run "touch #{@current.chop}"
|
17
|
+
b.run "rm #{@current.chop}"
|
18
|
+
b.run "ln -s #{@release_path} #{@current.chop}"
|
19
|
+
b.run "chown #{@owner}:#{@owner} #{@current.chop}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
3
|
+
module Resource
|
4
|
+
|
5
|
+
class Template < Base
|
6
|
+
|
7
|
+
class_attr :source
|
8
|
+
|
9
|
+
block_attr :owner, :group, :mode, :source, :action, :variables, :backup, :target
|
10
|
+
|
11
|
+
PREFIX = ''
|
12
|
+
|
13
|
+
def run
|
14
|
+
Execution.block 'Compiling template file', @target, @owner do |b|
|
15
|
+
compile!
|
16
|
+
b.always_run @always_run
|
17
|
+
end
|
18
|
+
Execution.block 'Ensuring file permissions', @target, 'root' do |b|
|
19
|
+
b.run "chown #{@owner}:#{@owner} #{@target}"
|
20
|
+
b.run "chmod #{unix_mode} #{@target}"
|
21
|
+
b.always_run @always_run
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def initialize target, &block
|
28
|
+
set_base_defaults
|
29
|
+
@target = target
|
30
|
+
ensure_target_zone
|
31
|
+
self.instance_eval(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def target_path
|
35
|
+
"#{PREFIX}#{@target}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def needs_compilation?
|
39
|
+
return true unless ::File.exist?(target_path)
|
40
|
+
MD5.hexdigest(::File.read target_path) != MD5.hexdigest(compile_template)
|
41
|
+
end
|
42
|
+
|
43
|
+
def compile!
|
44
|
+
Output.info 'Erubis is compiling', target_path
|
45
|
+
::File.open(target_path, 'w+') { |file| file.write(compile_template) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def ensure_target_zone
|
49
|
+
system "mkdir -p #{PREFIX}#{::File.dirname(@target)}"
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_source
|
54
|
+
Dir['cookbooks/*/templates/*/*.*'].each do |file|
|
55
|
+
return file if file.include? ::File.basename(@source)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def compile_template
|
60
|
+
@compile_template ||=
|
61
|
+
Erubis::Eruby.new(::File.read(find_source)).evaluate(
|
62
|
+
{ :node => Node.get }.merge(@variables || {})
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class User < Base
|
4
|
+
|
5
|
+
block_attr :password, :uid, :gid, :shell, :action, :username
|
6
|
+
|
7
|
+
def initialize username, &block
|
8
|
+
set_base_defaults
|
9
|
+
@username = username
|
10
|
+
@shell = '/bin/bash'
|
11
|
+
self.instance_eval(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
Execution.block 'Creating new user', @username, @owner do |b|
|
16
|
+
b.always_run @always_run
|
17
|
+
users = `cat /etc/passwd | grep "/home" |cut -d: -f1`
|
18
|
+
users = users.scan(/[a-zA-Z\-_]+/)
|
19
|
+
if users.include? @username
|
20
|
+
Output.warn 'Aborted, I think this user already exists', users.inspect
|
21
|
+
else
|
22
|
+
b.run "useradd -b /home -u #{@uid} -s #{@shell} -g #{@username} -m -k /home/#{@username} #{@username}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
class Version < Base
|
4
|
+
|
5
|
+
block_attr :location, :current_version, :deployed_by, :deployed_time
|
6
|
+
block_attr :server_info, :environment, :branch, :ip, :copy_to, :owner
|
7
|
+
block_attr :reset
|
8
|
+
|
9
|
+
def initialize location, &block
|
10
|
+
set_base_defaults
|
11
|
+
@location = location
|
12
|
+
@current_version = 'n/a'
|
13
|
+
@deployed_by = 'n/a'
|
14
|
+
@server_info = 'n/a'
|
15
|
+
@environment = 'n/a'
|
16
|
+
@branch = 'n/a'
|
17
|
+
@ip = 'n/a'
|
18
|
+
@copy_to = '/tmp/'
|
19
|
+
@version = ::Deploy::Version.new
|
20
|
+
self.instance_eval(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
Execution.block 'Deployment version file', @location, 'root' do |b|
|
25
|
+
b.always_run true
|
26
|
+
@version.deployed_by = @deployed_by
|
27
|
+
@version.current_version = @current_version
|
28
|
+
@version.add :server_info, @server_info
|
29
|
+
@version.add :environment, @environment
|
30
|
+
@version.add :branch, @branch
|
31
|
+
@version.add :reset, @reset
|
32
|
+
@version.add :ip, @ip
|
33
|
+
@version.store_to_file @location
|
34
|
+
Output.info 'Copying version file to', @copy_to
|
35
|
+
b.run "cp #{@location} #{@copy_to}"
|
36
|
+
b.run "chown #{@owner}:#{@owner} #{@copy_to}/#{::File.basename(@location)}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/resource.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
module Resource; end
|
3
|
+
|
4
|
+
require 'lib/resource/base'
|
5
|
+
require 'lib/resource/cron'
|
6
|
+
require 'lib/resource/directory'
|
7
|
+
require 'lib/resource/execute'
|
8
|
+
require 'lib/resource/file'
|
9
|
+
require 'lib/resource/gem'
|
10
|
+
require 'lib/resource/git'
|
11
|
+
require 'lib/resource/group'
|
12
|
+
require 'lib/resource/hook'
|
13
|
+
require 'lib/resource/link'
|
14
|
+
require 'lib/resource/package'
|
15
|
+
require 'lib/resource/remote_file'
|
16
|
+
require 'lib/resource/service'
|
17
|
+
require 'lib/resource/swap_release'
|
18
|
+
require 'lib/resource/template'
|
19
|
+
require 'lib/resource/user'
|
20
|
+
require 'lib/resource/version'
|
data/lib/status.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hashie'
|
3
|
+
require 'lib/output'
|
4
|
+
|
5
|
+
class Status; end
|
6
|
+
|
7
|
+
class << Status
|
8
|
+
|
9
|
+
# TODO: extract this from class
|
10
|
+
FILE = '/tmp/deployment/env/status'
|
11
|
+
|
12
|
+
def load_or_create
|
13
|
+
Output.info 'Loading status file', FILE
|
14
|
+
`mkdir -p #{File.dirname(FILE)}`
|
15
|
+
(File.exist? FILE) ? eval(File.read(FILE)) : {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def get
|
19
|
+
@status ||= Hashie::Mash.new(load_or_create)
|
20
|
+
end
|
21
|
+
|
22
|
+
def reload!
|
23
|
+
Output.jump
|
24
|
+
Output.info 'Reloading status', FILE
|
25
|
+
save
|
26
|
+
@status = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def save
|
30
|
+
Output.info 'Saving deployment status to file', FILE
|
31
|
+
File.open(FILE, 'w+') do |file|
|
32
|
+
file.write Status.get.to_hash.inspect
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: atesta
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- kazuyoshi tlacaelel
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-11-29 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -49,6 +49,35 @@ files:
|
|
49
49
|
- Rakefile
|
50
50
|
- VERSION
|
51
51
|
- lib/atesta.rb
|
52
|
+
- lib/block_attr.rb
|
53
|
+
- lib/class_attr.rb
|
54
|
+
- lib/execution.rb
|
55
|
+
- lib/hash.rb
|
56
|
+
- lib/lock.rb
|
57
|
+
- lib/node.rb
|
58
|
+
- lib/output.rb
|
59
|
+
- lib/recipe.rb
|
60
|
+
- lib/release_window.rb
|
61
|
+
- lib/resource.rb
|
62
|
+
- lib/resource/base.rb
|
63
|
+
- lib/resource/cron.rb
|
64
|
+
- lib/resource/directory.rb
|
65
|
+
- lib/resource/execute.rb
|
66
|
+
- lib/resource/file.rb
|
67
|
+
- lib/resource/gem.rb
|
68
|
+
- lib/resource/git.rb
|
69
|
+
- lib/resource/group.rb
|
70
|
+
- lib/resource/hook.rb
|
71
|
+
- lib/resource/link.rb
|
72
|
+
- lib/resource/package.rb
|
73
|
+
- lib/resource/remote_file.rb
|
74
|
+
- lib/resource/service.rb
|
75
|
+
- lib/resource/swap_release.rb
|
76
|
+
- lib/resource/template.rb
|
77
|
+
- lib/resource/user.rb
|
78
|
+
- lib/resource/version.rb
|
79
|
+
- lib/runtime_error.rb
|
80
|
+
- lib/status.rb
|
52
81
|
- test/helper.rb
|
53
82
|
- test/test_atesta.rb
|
54
83
|
has_rdoc: true
|