rubble 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.
@@ -0,0 +1,81 @@
1
+ require 'rubble/executor/base'
2
+ require 'rye'
3
+ require 'rubble/logging'
4
+ require 'tempfile'
5
+
6
+ module Rubble
7
+ module Executor
8
+ class Remote < Base
9
+ attr_reader :box
10
+ attr_reader :server
11
+ attr_reader :local_executor
12
+
13
+ def initialize(server, local_executor)
14
+ super()
15
+
16
+ @server = server
17
+ @local_executor = local_executor
18
+ @box = Rye::Box.new(server.name, :safe => false)
19
+ end
20
+
21
+ def rsync_remote_prefix
22
+ "#{server.name}:"
23
+ end
24
+
25
+ def file_exists?(file_name)
26
+ box.file_exists?(file_name)
27
+ end
28
+
29
+ def mkdir(directory)
30
+ @log.info("Creating directory '#{directory}'.")
31
+ exec('mkdir', '-p', directory.to_s)
32
+ end
33
+
34
+ def cd(directory, create)
35
+ @log.info("Changing directory to #{directory}.")
36
+ if create then
37
+ mkdir directory
38
+ end
39
+ box.cd(directory.to_s)
40
+ end
41
+
42
+ def symlink(source, target)
43
+ @log.info("Symlinking #{source} to #{target}.")
44
+ run('ln', '-s', '-f', '-T', source.to_s, target.to_s)
45
+ end
46
+
47
+ def run(*command)
48
+ Logging.context(:server => server.name) do
49
+ command_str = Shellwords.join(command)
50
+ @log.debug(command_str)
51
+ box.execute(command_str)
52
+ end
53
+ end
54
+
55
+ def close
56
+ if not @box.nil? then
57
+ @box.disconnect
58
+ end
59
+ end
60
+
61
+ def sync_up(filesets, target_dir, *options)
62
+ includes = rsync_includes(filesets)
63
+ parameters = includes.dirs.dup << (rsync_remote_prefix + target_dir).to_s
64
+ @local_executor.rsync(*parameters, :includes => includes.files, :recursive => true, :delete => true,
65
+ :delete_excluded => true)
66
+ end
67
+
68
+ def sync_down(filesets, target_dir, *options)
69
+ files = rsync_includes(filesets).map {|f| rsync_remote_prefix + f}
70
+ parameters = [target_dir].concat(files)
71
+ parameters.concat(options)
72
+ @local_executor.rsync *parameters
73
+ end
74
+
75
+ def sync_remote(source_dir, target_dir, *options)
76
+ parameters = [source_dir, target_dir, *options]
77
+ rsync *parameters
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,41 @@
1
+ require 'yaml'
2
+
3
+ module Rubble
4
+ class FileSet
5
+ attr_reader :dir
6
+ attr_reader :files
7
+
8
+ def initialize(dir, *files)
9
+ @dir = Pathname.pwd + Pathname(dir)
10
+ if files.nil? then
11
+ @files = []
12
+ else
13
+ flattened_files = (files || []).collect {|f| Array(f)}.flatten
14
+
15
+ @files = flattened_files.map do |f|
16
+ p = (@dir + Pathname(f)).relative_path_from(@dir)
17
+ if p.to_s.start_with?('../') or p.to_s == '.' then
18
+ raise ArgumentError, "File name '#{f}' must be relative to base directory #{@dir} of the file set."
19
+ end
20
+ p
21
+ end
22
+
23
+ @files.sort!
24
+ end
25
+
26
+ @files.freeze
27
+ end
28
+
29
+ def paths
30
+ @files.map {|f| @dir + f}
31
+ end
32
+
33
+ def empty?
34
+ @files.empty?
35
+ end
36
+
37
+ def to_s
38
+ to_yaml
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ require 'logging'
2
+
3
+ module Logging
4
+ class << self
5
+ def context(*options)
6
+ options.each do |option|
7
+ option.each do |k, v|
8
+ Logging.mdc[k] = v
9
+ end
10
+ end
11
+
12
+ if block_given? then
13
+ yield
14
+ end
15
+ ensure
16
+ options.each do |option|
17
+ option.each do |k, v|
18
+ Logging.mdc.delete(k)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubble/dsl'
2
+ require 'docile'
3
+
4
+ module Rubble
5
+ module Plan
6
+ class Base
7
+ attr_reader :env
8
+ attr_reader :target
9
+ attr_reader :resource
10
+ attr_reader :server
11
+ def initialize(env, server, params)
12
+ @env = env
13
+ @server = server
14
+ params.each do |k, v|
15
+ @resource = k
16
+ @target = v
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubble/plan/base'
2
+
3
+ module Rubble
4
+ module Plan
5
+ class Deploy < Base
6
+ def execute(context)
7
+ @target.deploy(context, env, server, @resource)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,43 @@
1
+ require 'rubble/dsl'
2
+ require 'rubble/snapshot'
3
+ require 'digest'
4
+ require 'yaml'
5
+
6
+ module Rubble
7
+ module Resource
8
+ class Base
9
+ attr_reader :name
10
+ def initialize(name, *params)
11
+ @name = name
12
+ end
13
+
14
+ def type
15
+ self.class.name.split('::').last.downcase
16
+ end
17
+
18
+ def get_version(filesets)
19
+ md = Digest::SHA1.new
20
+ filesets.each do |fileset|
21
+ fileset.paths.each do |path|
22
+ md.file(path)
23
+ end
24
+ end
25
+ md.hexdigest.force_encoding('UTF-8')
26
+ end
27
+
28
+ def get_filesets
29
+ []
30
+ end
31
+
32
+ def snapshot
33
+ filesets = get_filesets
34
+ version = get_version(filesets)
35
+ Snapshot.new(version, *filesets)
36
+ end
37
+
38
+ def to_s
39
+ to_yaml
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubble/resource/base'
2
+
3
+ module Rubble
4
+ module Resource
5
+ class Database < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,93 @@
1
+ require 'rubble/resource/base'
2
+ require 'rubble/file_set'
3
+ require 'find'
4
+ require 'docile'
5
+
6
+ module Rubble
7
+ module Resource
8
+ class Directory
9
+ attr_reader :includes
10
+ attr_reader :excludes
11
+ dsl_accessor :hidden
12
+
13
+ def initialize(name)
14
+ @name = name
15
+ @includes = []
16
+ @excludes = []
17
+ @default_includes = ['**/*']
18
+ @default_excludes = ['**/*~', '**/#*#']
19
+ @flags = File::FNM_PATHNAME
20
+ end
21
+
22
+ def includes(*pattern)
23
+ @includes.concat(Array(pattern))
24
+ end
25
+
26
+ def excludes(*pattern)
27
+ @excludes.concat(Array(pattern))
28
+ end
29
+
30
+ def hidden(*values)
31
+ if values.empty? then
32
+ (@flags & File.FNM_DOTMATCH) != 0
33
+ else
34
+ if values[0] then
35
+ @flags |= File.FNM_DOTMATCH
36
+ else
37
+ @flags &= ~File.FNM_DOTMATCH
38
+ end
39
+ end
40
+ end
41
+
42
+ def get_fileset
43
+ files = []
44
+ dir = Pathname.new(@name)
45
+
46
+ Find.find(dir) do |path|
47
+ pathname = Pathname.new(path).relative_path_from(dir).to_s
48
+
49
+ if pathname != '.' then
50
+ match = (@includes.empty? ? @default_includes : @includes).any? {|p| File.fnmatch?(p, pathname, @flags)}
51
+ match = match and not (@excludes.empty? ? @default_excludes : @excludes).any? {|p| File.fnmatch?(p, pathname, @flags)}
52
+
53
+ if match then
54
+ if not File.directory?(path) then
55
+ files << pathname
56
+ end
57
+ else
58
+ if File.directory?(path) then
59
+ Find.prune
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ FileSet.new(dir.to_s, files)
66
+ end
67
+ end
68
+
69
+ class Fileset < Base
70
+ def initialize(name, *params)
71
+ super(name, *params)
72
+
73
+ @directories = []
74
+ end
75
+
76
+ def directory(name, &block)
77
+ dir = Directory.new(name)
78
+ if not block.nil? then
79
+ Docile.dsl_eval(dir, &block)
80
+ end
81
+ @directories << dir
82
+ end
83
+
84
+ def get_filesets
85
+ filesets = []
86
+ @directories.each do |directory|
87
+ filesets << directory.get_fileset
88
+ end
89
+ filesets
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,22 @@
1
+ require 'rubble/resource/base'
2
+ require 'rubble/file_set'
3
+
4
+ module Rubble
5
+ module Resource
6
+ class Webapp < Base
7
+ dsl_accessor :war
8
+
9
+ def initialize(name, *params)
10
+ super(name, *params)
11
+
12
+ @war = "target/#{name}.war"
13
+ end
14
+
15
+ def get_filesets
16
+ dir = File.dirname(@war)
17
+ files = [File.basename(@war)]
18
+ [FileSet.new(dir, files)]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,44 @@
1
+ module Rubble
2
+ class Scope
3
+ attr_reader :environment
4
+ attr_reader :server
5
+ def initialize(environment, server)
6
+ @environment = environment
7
+ @server = server
8
+ end
9
+
10
+ def tool
11
+ @environment.tool
12
+ end
13
+
14
+ def configure_plan(type, *params, &block)
15
+ plan = tool.create_plan(type, @environment, @server, *params)
16
+
17
+ if not block.nil? then
18
+ Docile.dsl_eval(plan, &block)
19
+ end
20
+
21
+ @environment.add_plan(plan)
22
+ end
23
+
24
+ def method_missing(symbol, *arguments, &block)
25
+ if tool.is_plan?(symbol) then
26
+ configure_plan(symbol, *arguments, &block)
27
+ elsif tool.is_target?(symbol) then
28
+ @server.provide_target(symbol, arguments[0])
29
+ elsif tool.is_resource?(symbol) then
30
+ tool.provide_resource(symbol, arguments[0])
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def respond_to?(symbol, include_private = false)
37
+ if tool.is_plan?(symbol) or tool.is_resource?(symbol) or tool.is_target?(symbol) then
38
+ true
39
+ else
40
+ super
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,61 @@
1
+ require 'logging'
2
+ require 'shellwords'
3
+ require 'rubble/dsl'
4
+
5
+ module Rubble
6
+ class Server
7
+ attr_reader :tool
8
+ attr_reader :name
9
+ attr_reader :targets
10
+ dsl_accessor :rubble_dir
11
+ dsl_accessor :deploy_dir
12
+ dsl_accessor :user
13
+ dsl_accessor :group
14
+
15
+ def initialize(tool, name)
16
+ @tool = tool
17
+ @name = name
18
+
19
+ @log = Logging.logger[self]
20
+ @targets = {}
21
+ @rubble_dir = "/var/rubble"
22
+ @user = 'root'
23
+ @group = 'root'
24
+ @deploy_dir = '#{env.name}/#{resource.type}/#{resource.name}'
25
+ end
26
+
27
+ def provide_target(type, name)
28
+ group = @targets.fetch(type) do |k|
29
+ @targets[type] = {}
30
+ end
31
+ group.fetch(name) do |k|
32
+ group[name] = block_given? ? yield : @tool.create_target(type, name)
33
+ end
34
+ end
35
+
36
+ def configure_target(type, name, *params, &block)
37
+ target = provide_target(type, name) do
38
+ @tool.create_target(type, name, *params)
39
+ end
40
+ if not block.nil? then
41
+ Docile.dsl_eval(target, &block)
42
+ end
43
+ end
44
+
45
+ def method_missing(symbol, *arguments, &block)
46
+ if not @tool.nil? and @tool.is_target?(symbol) then
47
+ configure_target(symbol, *arguments, &block)
48
+ else
49
+ super
50
+ end
51
+ end
52
+
53
+ def respond_to?(symbol, include_private = false)
54
+ if not @tool.nil? and @tool.is_target?(symbol) then
55
+ true
56
+ else
57
+ super
58
+ end
59
+ end
60
+ end
61
+ end