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 CHANGED
@@ -1 +1 @@
1
- 0.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}" % 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 "#{code}"
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}: #{value}" % 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
@@ -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
@@ -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'
@@ -0,0 +1,8 @@
1
+ class RuntimeError
2
+
3
+ def initialize *args
4
+ Status.save
5
+ super
6
+ end
7
+
8
+ end
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: 31
4
+ hash: 29
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 0
10
- version: 0.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: 2010-08-26 00:00:00 -05:00
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