cluster_management 0.5.1 → 0.5.2

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/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rake_ext'
2
2
 
3
3
  project(
4
4
  name: "cluster_management",
5
- version: "0.5.1",
5
+ version: "0.5.2",
6
6
  summary: "Simple cluster management tools",
7
7
 
8
8
  author: "Alexey Petrushin",
@@ -0,0 +1,21 @@
1
+ module ClusterManagement
2
+ class Config < SafeHash
3
+ def merge_config! file_path
4
+ raise("config file must have .yml extension (#{file_path})!") unless file_path.end_with? '.yml'
5
+ data = ::YAML.load_file file_path
6
+ if data
7
+ data.must_be.a ::Hash
8
+ self.deep_merge! data
9
+ end
10
+ end
11
+ end
12
+
13
+ def self.load_config file
14
+ @config = Config.new
15
+ @config.merge_config! file
16
+ end
17
+
18
+ def self.config
19
+ @config || raise("config nod defined (use ClusterManagement.load_config to use config)!")
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ gem 'tilt'
2
+
3
+ if respond_to? :fake_gem
4
+ fake_gem 'ruby_ext'
5
+ fake_gem 'vos'
6
+ end
@@ -0,0 +1,8 @@
1
+ module Vfs
2
+ class File
3
+ def render *args
4
+ args.unshift Object.new if args.size == 1 and args.first.is_a?(Hash)
5
+ Tilt::ERBTemplate.new(path).render *args
6
+ end
7
+ end
8
+ end
@@ -1,4 +1,38 @@
1
- ClusterManagement.integration = {
2
- has_mark?: -> box, mark {box.has_mark? mark},
3
- mark: -> box, mark {box.mark mark}
4
- }
1
+ module Vos
2
+ class ServicesHelper < BasicObject
3
+ def initialize box, class_namespace
4
+ @box, @class_namespace = box, class_namespace
5
+ end
6
+
7
+ class ServiceCallback < BasicObject
8
+ def initialize box, class_namespace, class_name
9
+ @box, @class_namespace, @class_name = box, class_namespace, class_name
10
+ end
11
+
12
+ protected
13
+ def method_missing m, *a, &b
14
+ klass = "::#{@class_namespace.to_s.camelize}::#{@class_name.to_s.camelize}".constantize
15
+ klass.new(@box).send m, *a, &b
16
+ end
17
+ end
18
+
19
+ protected
20
+ def method_missing class_name
21
+ ServiceCallback.new(@box, @class_namespace, class_name)
22
+ end
23
+ end
24
+
25
+ class Box
26
+ def self.define_service_namespace class_namespace
27
+ define_method class_namespace do
28
+ ServicesHelper.new self, class_namespace
29
+ end
30
+ end
31
+ define_service_namespace :services
32
+ define_service_namespace :projects
33
+
34
+ def already_required_services
35
+ @already_required_services ||= Set.new
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,26 @@
1
+ require 'logger'
2
+
3
+ module ClusterManagement
4
+ class CustomLogger < Logger
5
+ def info msg
6
+ super "#{msg}\n"
7
+ end
8
+
9
+ def warn msg
10
+ super "#{msg}\n"
11
+ end
12
+
13
+ def error msg
14
+ super "#{msg}\n"
15
+ end
16
+ end
17
+
18
+ attr_writer :logger
19
+ def self.logger
20
+ unless @logger
21
+ @logger = CustomLogger.new STDOUT
22
+ @logger.formatter = -> severity, datetime, progname, msg {msg}
23
+ end
24
+ @logger
25
+ end
26
+ end
@@ -0,0 +1,67 @@
1
+ module ClusterManagement
2
+ class Service
3
+ attr_reader :box
4
+
5
+ #
6
+ # Helpers
7
+ #
8
+ def logger; ClusterManagement.logger end
9
+ def config; ClusterManagement.config end
10
+
11
+
12
+ #
13
+ # Business Logic
14
+ #
15
+ def initialize box
16
+ @box = box
17
+ end
18
+
19
+ def mark! extra_mark = nil
20
+ box.mark! self.class.marker(extra_mark)
21
+ end
22
+
23
+ def has_mark? extra_mark = nil
24
+ box.has_mark? self.class.marker(extra_mark)
25
+ end
26
+
27
+ def apply_once extra_mark = nil, &block
28
+ unless has_mark? extra_mark
29
+ block.call
30
+ mark! extra_mark
31
+ end
32
+ end
33
+
34
+ def require *args
35
+ if args.size == 1 and args.first.is_a?(Hash)
36
+ services = args.first
37
+ elsif args.size == 2 and args.first.is_a?(Array)
38
+ services = {}
39
+ args.first.each{|klass| services[klass] = args.last}
40
+ else
41
+ raise 'invalid arguments'
42
+ end
43
+
44
+ services.each do |klass, method|
45
+ key = "#{klass}.#{method}"
46
+ unless box.already_required_services.include? key
47
+ klass.new(box).send method if klass.method_defined? method
48
+ box.already_required_services << key
49
+ end
50
+ end
51
+ end
52
+
53
+ class << self
54
+ def version version = nil
55
+ if version
56
+ @version = version
57
+ else
58
+ @version ||= 1
59
+ end
60
+ end
61
+
62
+ def marker extra_mark = nil
63
+ %(#{name}:#{version}#{":#{extra_mark}" if extra_mark})
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,7 +1,12 @@
1
- %w(
2
- support
3
- package
4
- cluster_management
5
- ).each{|f| require "cluster_management/#{f}"}
1
+ require 'ruby_ext'
2
+ require 'vos'
3
+ require 'yaml'
4
+ require 'tilt'
6
5
 
7
- require 'cluster_management/integration/vos' unless $cluster_management_dont_include_integration
6
+ %w(
7
+ config
8
+ logger
9
+ service
10
+ integration/vfs
11
+ integration/vos
12
+ ).each{|f| require "cluster_management/#{f}"}
data/readme.md CHANGED
@@ -1,31 +1,70 @@
1
1
  # Simple cluster management tools
2
2
 
3
3
  It may be **usefull if Your claster has about 1-10 boxes**, and tools like Chef, Puppet, Capistrano are too complex and proprietary for your needs.
4
- **It's extremely easy**, there are only 3 methods.
4
+ **It's extremely easy**, there are only 3 methods.
5
5
 
6
- ## Package management
6
+ You probably already familiar with Rake and have it in Your project, and because ClusterManagement is just a small Rake
7
+ addon it should be easy to add and get started with it.
8
+
9
+ It's ssh-agnostic and has no extra dependencies. You can use whatever ssh-tool you like (even pure Net::SSH / Net::SFTP),
10
+ samples below are done by using [Virtual Operating System][vos] and [Virtual File System][vfs] tools.
11
+
12
+ ## BoxTask Management
7
13
 
8
14
  Define your packages, they are just rake tasks, so you probably know how to work with them:
9
15
 
16
+ desc 'ruby 1.9.2'
17
+ package ruby: :system_tools do
18
+ apply_once do
19
+ installation_dir = '/usr/local/ruby'
20
+ ruby_name = "ruby-1.9.2-p136"
21
+
22
+ box.tmp do |tmp|
23
+ tmp.bash "wget ftp://ftp.ruby-lang.org//pub/ruby/1.9/#{ruby_name}.tar.gz"
24
+ tmp.bash "tar -xvzf #{ruby_name}.tar.gz"
25
+
26
+ src_dir = tmp[ruby_name]
27
+ src_dir.bash "./configure --prefix=#{installation_dir}"
28
+ src_dir.bash 'make && make install'
29
+ end
30
+
31
+ box.home('.gemrc').write! "gem: --no-ri --no-rdoc\n"
32
+
33
+ bindir = "#{installation_dir}/bin"
34
+ unless box.env_file.content =~ /PATH.*#{bindir}/
35
+ box.env_file.append %(\nexport PATH="$PATH:#{bindir}"\n)
36
+ box.reload_env
37
+ end
38
+ end
39
+ verify{box.bash('ruby -v') =~ /ruby 1.9.2/}
40
+ end
41
+
42
+ Or you can use a little more explicit notation with custom :applied? logic (:apply_once is a shortcut for :applied? & :after_applying):
43
+
10
44
  package :ruby do
11
45
  applied?{box.has_mark? :ruby}
12
46
  apply do
13
- box.bash 'apt-get install ruby'
47
+ ...
14
48
  end
15
49
  after_applying{box.mark :ruby}
16
50
  end
17
-
18
- or you can use a little shorter notation (it's equivalent to the previous):
19
-
51
+
52
+ Let's define another package:
53
+
20
54
  package rails: :ruby, version: 3 do
21
55
  apply_once do
22
56
  box.bash 'gem install rails'
23
57
  end
24
58
  end
25
59
 
26
- And it's understands dependencies, so the :rails package will apply :ruby before applying itself.
27
- It also support iterative development, so you don't need to write all the config at once, do it by small steps, adding one package after another.
28
- And you can use versioning to update already installed packages - if you change version of some package it will be reapplied next run.
60
+ It's understands dependencies, so the :rails package will apply :ruby before applying itself.
61
+
62
+ It checks if the package already has been applied to box, so you can evolve your configuration and apply it multiple times,
63
+ it will apply only missing packages (or drop the applied? clause and it will be applied every run). It allows you
64
+ to use **iterative development**, you don't need to write all the config at once, do it by small steps, adding one package after another.
65
+
66
+ You can also use versioning to update already installed packages - if You change version it will be reapplied next run.
67
+ And by the way, the box.mark ... is just an example check, you can use anything there.
29
68
 
30
69
  And, last step - define (I intentionally leave implementation of this method to You, it's very specific to Your environment)
31
70
  to what machines it should be applied:
@@ -47,7 +86,7 @@ Now, you can press the enter:
47
86
 
48
87
  $ rake os:rails host=myapp.com
49
88
 
50
- and packager will do all the job of installing and configuring your cluster boxes, and prints you something like that
89
+ and box_task will do all the job of installing and configuring your cluster boxes, and prints you something like that
51
90
  (it's a sample output of some of my own box, you can see config details here [my_cluster][my_cluster]):
52
91
 
53
92
  $ rake app_server host=universal.xxx.com
@@ -80,7 +119,7 @@ You can also use standard Rake -T command to see docs (it's also from my config,
80
119
  rake db # db
81
120
  rake db:mongodb # MongoDB
82
121
 
83
- ## Runtime services
122
+ ## Service Management
84
123
 
85
124
  [add details here]
86
125
 
@@ -89,10 +128,7 @@ You can also use standard Rake -T command to see docs (it's also from my config,
89
128
  [add more details here]
90
129
 
91
130
  **You can use it also for deployment**, exactly the same way, configure it the way you like, it's just rake
92
- tasks. And by the way, the *box.mark ...* is just an example check, you can use anything there.
93
-
94
- It checks if the package already has been applied to box, so you can evolve your configuration and apply
95
- it multiple times, it will apply only missing packages (or drop the *applied?* clause and it will be applied every run).
131
+ tasks.
96
132
 
97
133
  # Temporarry stuff, don't bother to read it
98
134
 
@@ -100,4 +136,6 @@ it multiple times, it will apply only missing packages (or drop the *applied?* c
100
136
  - uses well known tools (rake and anytingh ssh-enabled)
101
137
  - support iterative development
102
138
 
103
- [my_cluster]: https://github.com/alexeypetrushin/my_cluster/tree/master/lib/packages
139
+ [my_cluster]: http://github.com/alexeypetrushin/my_cluster/tree/master/lib/packages
140
+ [vos]: http://github.com/alexeypetrushin/vos
141
+ [vfs]: http://github.com/alexeypetrushin/vfs
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cluster_management
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 5
8
- - 1
9
- version: 0.5.1
4
+ prerelease:
5
+ version: 0.5.2
10
6
  platform: ruby
11
7
  authors:
12
8
  - Alexey Petrushin
@@ -14,10 +10,42 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2011-02-09 00:00:00 +03:00
13
+ date: 2011-02-16 00:00:00 +03:00
18
14
  default_executable:
19
- dependencies: []
20
-
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: tilt
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: ruby_ext
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: vos
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id003
21
49
  description:
22
50
  email:
23
51
  executables: []
@@ -29,13 +57,13 @@ extra_rdoc_files: []
29
57
  files:
30
58
  - Rakefile
31
59
  - readme.md
32
- - lib/cluster_management/cluster_management.rb
60
+ - lib/cluster_management/config.rb
61
+ - lib/cluster_management/gems.rb
62
+ - lib/cluster_management/integration/vfs.rb
33
63
  - lib/cluster_management/integration/vos.rb
34
- - lib/cluster_management/package.rb
35
- - lib/cluster_management/support.rb
64
+ - lib/cluster_management/logger.rb
65
+ - lib/cluster_management/service.rb
36
66
  - lib/cluster_management.rb
37
- - spec/package_spec.rb
38
- - spec/spec_helper.rb
39
67
  has_rdoc: true
40
68
  homepage: http://github.com/alexeypetrushin/cluster_management
41
69
  licenses: []
@@ -50,21 +78,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
50
78
  requirements:
51
79
  - - ">="
52
80
  - !ruby/object:Gem::Version
53
- segments:
54
- - 0
55
81
  version: "0"
56
82
  required_rubygems_version: !ruby/object:Gem::Requirement
57
83
  none: false
58
84
  requirements:
59
85
  - - ">="
60
86
  - !ruby/object:Gem::Version
61
- segments:
62
- - 0
63
87
  version: "0"
64
88
  requirements: []
65
89
 
66
90
  rubyforge_project:
67
- rubygems_version: 1.3.7
91
+ rubygems_version: 1.5.1
68
92
  signing_key:
69
93
  specification_version: 3
70
94
  summary: Simple cluster management tools
@@ -1,39 +0,0 @@
1
- module ClusterManagement
2
- class << self
3
- #
4
- # use :integration attribute to provide integration with your tool (use integration/rsh as a sample).
5
- #
6
- attr_writer :integration
7
- def integration
8
- unless @integration
9
- not_supported = -> *args {raise "you must provide your own implementation!"}
10
- @integration = {
11
- has_mark?: not_supported,
12
- mark: not_supported
13
- }
14
- end
15
- @integration
16
- end
17
-
18
-
19
- #
20
- # you must override this method to provide your own implementation
21
- #
22
- attr_writer :boxes
23
- def boxes
24
- unless @boxes
25
- warn('you must override :boxes method to provide your own behaviour')
26
- return []
27
- end
28
- @boxes
29
- end
30
-
31
-
32
- #
33
- # Rake integration
34
- #
35
- def rake_task *args, &block
36
- task *args, &block
37
- end
38
- end
39
- end
@@ -1,75 +0,0 @@
1
- module ClusterManagement
2
- class Package < Hash
3
- class Dsl
4
- attr_reader :package, :box
5
-
6
- def initialize package, box
7
- @package, @box = package, box
8
- end
9
-
10
- def version; package.version end
11
-
12
- def applied? &b; package.applied = b end
13
- def apply &b; package.apply = b end
14
- def verify &b; package.verify = b end
15
- def after_applying &b; package.after_applying = b end
16
-
17
- def apply_once &b
18
- mark = package.version ? "#{package.name}:#{package.version}" : package.name.to_s
19
- applied?{ClusterManagement.integration[:has_mark?].call box, mark}
20
- apply &b
21
- after_applying{ClusterManagement.integration[:mark].call box, mark}
22
- end
23
- end
24
-
25
- attr_accessor :applied, :apply, :verify, :after_applying, :name, :version
26
-
27
- def initialize name, version
28
- @name, @version = name, version
29
- end
30
-
31
- def configure box, &b
32
- dsl = Dsl.new self, box
33
- dsl.instance_eval &b
34
-
35
- if applied
36
- package_applied = applied.call box
37
- # ensure_boolean! package_applied, :applied?
38
- else
39
- package_applied = false
40
- end
41
-
42
- if apply and !package_applied
43
- ClusterManagement.logger.info %(applying '#{name}#{version ? ":#{version}" : ''}' to '#{box}'\n)
44
- apply.call box
45
- end
46
-
47
- if verify
48
- verified = verify.call box
49
- # ensure_boolean! verified, 'verify'
50
- raise "invalid '#{name}' package for '#{box}'!" unless verified
51
- end
52
- after_applying && after_applying.call(box)
53
- # print "done\n" if apply and !package_applied
54
- end
55
-
56
- protected
57
- def ensure_boolean! value, method
58
- unless value.eql?(true) or value.eql?(false)
59
- raise "invalid return value in '#{name}.#{method}' (only true/false allowed)!"
60
- end
61
- end
62
- end
63
- end
64
-
65
- def package name_or_options, version = nil, &block
66
- version ||= name_or_options.delete :version if name_or_options.is_a? Hash
67
- ClusterManagement.rake_task name_or_options do |task, *args|
68
- if block
69
- ClusterManagement.boxes.each do |box|
70
- package = ClusterManagement::Package.new task.name, version
71
- package.configure box, &block
72
- end
73
- end
74
- end
75
- end
@@ -1,17 +0,0 @@
1
- require 'logger'
2
-
3
- module ClusterManagement
4
- class << self
5
- #
6
- # Logger
7
- #
8
- attr_writer :logger
9
- def logger
10
- unless @logger
11
- @logger = Logger.new STDOUT
12
- @logger.formatter = -> severity, datetime, progname, msg {msg}
13
- end
14
- @logger
15
- end
16
- end
17
- end
data/spec/package_spec.rb DELETED
@@ -1,136 +0,0 @@
1
- require 'spec_helper'
2
- require 'cluster_management/package'
3
-
4
- describe 'Package' do
5
- before :each do
6
- ClusterManagement.box = :box
7
- end
8
-
9
- it 'should allow empty declaration' do
10
- package :tools
11
- ClusterManagement.last_task.should_not be_nil
12
-
13
- ClusterManagement.last_task = nil
14
- package(:tools){}
15
- ClusterManagement.last_task.should_not be_nil
16
- end
17
-
18
- it "basic" do
19
- check = mock()
20
- check.should_receive(:applied?).ordered.and_return(false)
21
- check.should_receive(:apply).ordered
22
- check.should_receive(:verify).ordered.and_return(true)
23
- check.should_receive(:after_applying).ordered
24
-
25
- the_package, the_box = nil, nil
26
- package :tools, 1 do
27
- package.is_a?(ClusterManagement::Package).should == true
28
- version.should == 1
29
- box.should == :box
30
-
31
-
32
- applied?{check.applied?(box)}
33
- apply{check.apply(box)}
34
- verify{check.verify(box)}
35
- after_applying{check.after_applying(box)}
36
- end
37
- end
38
-
39
- it "should not reapply package but always verify it" do
40
- check = mock()
41
- check.should_not_receive(:apply)
42
- check.should_receive(:verify).and_return(true)
43
-
44
- package :tools do
45
- applied?{true}
46
- apply{check.apply}
47
- verify{check.verify}
48
- end
49
- end
50
-
51
- it "should verify packages" do
52
- -> {
53
- package :tools do
54
- verify{false}
55
- end
56
- }.should raise_error(/invalid.*tools/)
57
- end
58
-
59
- it "should apply to all boxes" do
60
- boxes = [:a, :b]
61
- ClusterManagement.stub(:boxes).and_return(boxes)
62
-
63
- check = []
64
- package :tools do
65
- apply{check << box}
66
- end
67
- check.should == boxes
68
- end
69
-
70
- it 'should support version attribute' do
71
- package :tools, 2 do
72
- version.should == 2
73
- end
74
-
75
- package tools: :os, version: 2 do
76
- version.should == 2
77
- end
78
- end
79
-
80
- describe "apply_once" do
81
- def build_box_for key, has_mark
82
- box = mock()
83
- box.should_receive(:has_mark?).ordered.with(key).and_return(has_mark)
84
- box.should_receive(:mark).ordered.with(key)
85
- ClusterManagement.box = box
86
- box
87
- end
88
-
89
- it "should apply if not applied" do
90
- box = build_box_for('tools', false)
91
-
92
- check = mock()
93
- check.should_receive(:apply_once).with(box)
94
-
95
- package :tools do
96
- apply_once{check.apply_once(box)}
97
- end
98
- end
99
-
100
- it "should not apply if applied" do
101
- box = build_box_for('tools', true)
102
-
103
- check = mock()
104
- check.should_not_receive(:apply_once)
105
-
106
- package :tools do
107
- apply_once{check.apply_once}
108
- end
109
- end
110
-
111
- it "should support versioning" do
112
- box = build_box_for('tools:2', false)
113
-
114
- check = mock()
115
- check.should_receive(:apply_once)
116
-
117
- package :tools, 2 do
118
- apply_once{check.apply_once}
119
- end
120
- end
121
- end
122
- end
123
-
124
-
125
- # def version version; package.version = version end
126
- # def applied? &b; package.applied = b end
127
- # def apply &b; package.apply = b end
128
- # def verify &b; package.verify = b end
129
- # def after_applying &b; package.after_applying = b end
130
- #
131
- # def apply_once &b
132
- # mark = package.version ? "#{package.name}:#{package.version}" : package.name
133
- # applied?{INTEGRATION[:has_mark?].call box, mark}
134
- # apply &b
135
- # after_applying{INTEGRATION[:mark].call box, mark}
136
- # end
data/spec/spec_helper.rb DELETED
@@ -1,67 +0,0 @@
1
- require 'rspec_ext'
2
-
3
- require 'cluster_management/support'
4
- require 'cluster_management/cluster_management'
5
-
6
-
7
- #
8
- # Boxes stub
9
- #
10
- module ClusterManagement
11
- class << self
12
- attr_accessor :box
13
-
14
- def boxes
15
- [box]
16
- end
17
- end
18
- end
19
-
20
-
21
- #
22
- # Integration stub
23
- #
24
- ClusterManagement.integration = {
25
- has_mark?: -> box, mark {box.has_mark? mark},
26
- mark: -> box, mark {box.mark mark}
27
- }
28
-
29
-
30
- #
31
- # Task stub
32
- #
33
- module ClusterManagement
34
- class Task
35
- attr_accessor :name
36
- def initialize name
37
- @name = name
38
- end
39
- end
40
-
41
- class << self
42
- attr_accessor :last_task
43
-
44
- def rake_task name_or_options, &block
45
- name = if name_or_options.is_a? Hash
46
- name_or_options.first.first
47
- else
48
- name_or_options
49
- end
50
- task = Task.new name
51
- block.call task if block
52
- self.last_task = task
53
- end
54
- end
55
- end
56
-
57
-
58
- #
59
- # Logger stub
60
- #
61
- module ClusterManagement
62
- class << self
63
- def logger
64
- @logger ||= Logger.new nil
65
- end
66
- end
67
- end