cluster_management 0.0.1 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rake_ext'
2
2
 
3
3
  project(
4
4
  name: "cluster_management",
5
- version: "0.0.1",
5
+ version: "0.5.1",
6
6
  summary: "Simple cluster management tools",
7
7
 
8
8
  author: "Alexey Petrushin",
@@ -0,0 +1,39 @@
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
@@ -0,0 +1,4 @@
1
+ ClusterManagement.integration = {
2
+ has_mark?: -> box, mark {box.has_mark? mark},
3
+ mark: -> box, mark {box.mark mark}
4
+ }
@@ -1,39 +1,75 @@
1
- module Ros
1
+ module ClusterManagement
2
2
  class Package < Hash
3
3
  class Dsl
4
- attr_reader :package
4
+ attr_reader :package, :box
5
5
 
6
- def initialize package
7
- @package = package
6
+ def initialize package, box
7
+ @package, @box = package, box
8
8
  end
9
9
 
10
- def version version; package.version = version end
10
+ def version; package.version end
11
+
11
12
  def applied? &b; package.applied = b end
12
13
  def apply &b; package.apply = b end
13
14
  def verify &b; package.verify = b end
14
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
15
23
  end
16
24
 
17
25
  attr_accessor :applied, :apply, :verify, :after_applying, :name, :version
18
26
 
19
- def initialize name
20
- @name = name
21
- end
22
-
23
- def configure_with &b
24
- dsl = Dsl.new self
25
- b.call dsl
27
+ def initialize name, version
28
+ @name, @version = name, version
26
29
  end
27
30
 
28
- def apply_to box
29
- package_applied = applied && applied.call(box)
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
+
30
42
  if apply and !package_applied
31
- print "applying '#{name}#{version}' to '#{box}'\n"
43
+ ClusterManagement.logger.info %(applying '#{name}#{version ? ":#{version}" : ''}' to '#{box}'\n)
32
44
  apply.call box
33
45
  end
34
- raise "invalid '#{name}' package for '#{box}'!" if verify and !verify.call(box)
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
35
52
  after_applying && after_applying.call(box)
36
- # print "done\n" if apply and !package_applied
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
37
73
  end
38
74
  end
39
75
  end
@@ -0,0 +1,17 @@
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
@@ -1,12 +1,7 @@
1
1
  %w(
2
- rake
2
+ support
3
3
  package
4
+ cluster_management
4
5
  ).each{|f| require "cluster_management/#{f}"}
5
6
 
6
- #
7
- # you must override this method to provide your own implementation
8
- #
9
- def boxes
10
- warn 'you must override :boxes method to provide your own behaviour'
11
- []
12
- end
7
+ require 'cluster_management/integration/vos' unless $cluster_management_dont_include_integration
data/readme.md CHANGED
@@ -3,37 +3,90 @@
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
4
  **It's extremely easy**, there are only 3 methods.
5
5
 
6
+ ## Package management
7
+
6
8
  Define your packages, they are just rake tasks, so you probably know how to work with them:
7
9
 
8
- namespace :os do
9
- package :ruby do
10
- applied?{|box| box.has_mark? :ruby}
11
- apply do |box|
12
- box.bash 'apt-get install ruby'
13
- box.mark :ruby
14
- end
10
+ package :ruby do
11
+ applied?{box.has_mark? :ruby}
12
+ apply do
13
+ box.bash 'apt-get install ruby'
15
14
  end
15
+ after_applying{box.mark :ruby}
16
+ end
17
+
18
+ or you can use a little shorter notation (it's equivalent to the previous):
16
19
 
17
- package :rails => :ruby do
18
- applied?{|box| box.has_mark? :rails}
19
- apply do |box|
20
- box.bash 'gem install rails'
21
- box.mark :rails
22
- end
20
+ package rails: :ruby, version: 3 do
21
+ apply_once do
22
+ box.bash 'gem install rails'
23
23
  end
24
24
  end
25
25
 
26
- Define to what it should be applied:
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.
29
+
30
+ And, last step - define (I intentionally leave implementation of this method to You, it's very specific to Your environment)
31
+ to what machines it should be applied:
27
32
 
28
- def each_box &b
29
- host = ENV['host'] || raise(":host not defined!")
30
- box = Rsh::Box.new host: host, ssh: {user: 'root', password: 'secret'}
31
- b.call box
33
+ module ClusterManagement
34
+ def self.boxes
35
+ unless @boxes
36
+ host = ENV['host'] || raise(":host not defined!")
37
+ box = Vos::Box.new host: host, ssh: config.ssh!.to_h
38
+ box.open
39
+
40
+ @boxes = [box]
41
+ end
42
+ @boxes
43
+ end
32
44
  end
33
45
 
34
- Run it:
46
+ Now, you can press the enter:
47
+
48
+ $ rake os:rails host=myapp.com
49
+
50
+ and packager will do all the job of installing and configuring your cluster boxes, and prints you something like that
51
+ (it's a sample output of some of my own box, you can see config details here [my_cluster][my_cluster]):
52
+
53
+ $ rake app_server host=universal.xxx.com
54
+ applying 'basic:os:5' to '<Box: universal.xxx.com>'
55
+ applying 'basic:apt' to '<Box: universal.xxx.com>'
56
+ applying 'basic:system_tools' to '<Box: universal.xxx.com>'
57
+ applying 'basic:ruby' to '<Box: universal.xxx.com>'
58
+ building ... done
59
+ updating path ... done
60
+ applying 'basic:git' to '<Box: universal.xxx.com>'
61
+ applying 'basic:security:6' to '<Box: universal.xxx.com>'
62
+ applying 'basic:manual_management:2' to '<Box: universal.xxx.com>'
63
+ applying 'app_server:fake_gem:2' to '<Box: universal.xxx.com>'
64
+ applying 'app_server:custom_ruby:3' to '<Box: universal.xxx.com>'
65
+
66
+ You can also use standard Rake -T command to see docs (it's also from my config, details are here [my_cluster][my_cluster]):
67
+
68
+ $ rake -T
69
+ rake app_server # app server
70
+ rake app_server:custom_ruby # custom ruby (with encoding globally set to unicode and enabled fake_gem hack)
71
+ rake app_server:fake_gem # fake_gem
72
+ rake basic # Box with basic packages installed
73
+ rake basic:apt # apt
74
+ rake basic:git # git
75
+ rake basic:manual_management # Makes box handy for manual management
76
+ rake basic:os # Checks OS version and add some very basic stuff
77
+ rake basic:ruby # ruby
78
+ rake basic:security # security
79
+ rake basic:system_tools # System tools, mainly for build support
80
+ rake db # db
81
+ rake db:mongodb # MongoDB
82
+
83
+ ## Runtime services
35
84
 
36
- $ rake os:rails host=webapp.com
85
+ [add details here]
86
+
87
+ ## Deployment
88
+
89
+ [add more details here]
37
90
 
38
91
  **You can use it also for deployment**, exactly the same way, configure it the way you like, it's just rake
39
92
  tasks. And by the way, the *box.mark ...* is just an example check, you can use anything there.
@@ -41,6 +94,10 @@ tasks. And by the way, the *box.mark ...* is just an example check, you can use
41
94
  It checks if the package already has been applied to box, so you can evolve your configuration and apply
42
95
  it multiple times, it will apply only missing packages (or drop the *applied?* clause and it will be applied every run).
43
96
 
97
+ # Temporarry stuff, don't bother to read it
98
+
44
99
  - small
45
100
  - uses well known tools (rake and anytingh ssh-enabled)
46
- - support iterative development
101
+ - support iterative development
102
+
103
+ [my_cluster]: https://github.com/alexeypetrushin/my_cluster/tree/master/lib/packages
@@ -0,0 +1,136 @@
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
@@ -0,0 +1,67 @@
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
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 0
7
+ - 5
8
8
  - 1
9
- version: 0.0.1
9
+ version: 0.5.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Alexey Petrushin
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-02-01 00:00:00 +03:00
17
+ date: 2011-02-09 00:00:00 +03:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -29,9 +29,13 @@ extra_rdoc_files: []
29
29
  files:
30
30
  - Rakefile
31
31
  - readme.md
32
+ - lib/cluster_management/cluster_management.rb
33
+ - lib/cluster_management/integration/vos.rb
32
34
  - lib/cluster_management/package.rb
33
- - lib/cluster_management/rake.rb
35
+ - lib/cluster_management/support.rb
34
36
  - lib/cluster_management.rb
37
+ - spec/package_spec.rb
38
+ - spec/spec_helper.rb
35
39
  has_rdoc: true
36
40
  homepage: http://github.com/alexeypetrushin/cluster_management
37
41
  licenses: []
@@ -1,11 +0,0 @@
1
- def package *a, &b
2
- task *a do |task, *args|
3
- if b
4
- boxes.each do |box|
5
- package = Ros::Package.new task.name
6
- package.configure_with &b
7
- package.apply_to box
8
- end
9
- end
10
- end
11
- end