atesta 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|