cluster_management 0.5.1 → 0.5.2

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.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