rubble 0.0.1

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