clustr 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.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +29 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +5 -0
- data/bin/clustr +3 -0
- data/clustr.gemspec +38 -0
- data/lib/clustr/adapter/base.rb +18 -0
- data/lib/clustr/adapter/simpledb.rb +53 -0
- data/lib/clustr/adapter.rb +53 -0
- data/lib/clustr/cli.rb +94 -0
- data/lib/clustr/cluster.rb +57 -0
- data/lib/clustr/cluster_collection.rb +29 -0
- data/lib/clustr/config/clusters.rb +56 -0
- data/lib/clustr/config.rb +71 -0
- data/lib/clustr/log.rb +43 -0
- data/lib/clustr/node.rb +33 -0
- data/lib/clustr/node_collection.rb +8 -0
- data/lib/clustr/version.rb +4 -0
- data/lib/clustr.rb +69 -0
- data/spec/clustr/cluster_collection_spec.rb +41 -0
- data/spec/clustr/cluster_spec.rb +25 -0
- data/spec/clustr/config/clusters_spec.rb +109 -0
- data/spec/clustr/config_spec.rb +40 -0
- data/spec/clustr/log_spec.rb +27 -0
- data/spec/clustr/node_collection_spec.rb +32 -0
- data/spec/clustr/node_spec.rb +42 -0
- data/spec/clustr/version_spec.rb +9 -0
- data/spec/factories/node.rb +14 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/message_shared.rb +54 -0
- metadata +318 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZWRlNjk2ZGY1YTM1OTA2YjI4MWJiMWM3YjI1Y2VlMzlhZmIxNjEzMw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
OWRhYzAwODI2ZGQxZjU1MjljZGEwYzEwMzlkNDI2YjUzNmY4YTE1Yg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NzRiZDkzYjhhNzMwNWYxYzNlYjdiYWRiNTZlMGM5ZTFiMzhhYTU1M2FkNTdh
|
10
|
+
ZDQyMzc1NDA3ODFkOGMyZTc1YmM1MGIxZTVhZTZmYTI4YmM4YjY1OGQzN2Zj
|
11
|
+
Yzg4MTNlMTE4M2ZhZDYxNzMwNDVhN2ZmNmMxMDc1ZGMzZmZkZDE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MjJmOGEzYWY5ZDQ3OTAwYjIyZDBkYTRiMDY4NTRhNWQwNWI1NDc4MDE2MzE4
|
14
|
+
OGY3NDllNTRiMjU3NTBhZjc0MjAxMjUxMDdlZDM5NTE5Yzc0ZTcwNGJmMTE0
|
15
|
+
ZWQwYjhlZWY4NDk1NDMwMDY1YzI5ZjFjM2YzZDc4ZTYyZGVhZTA=
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
clustr
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p353
|
data/.travis.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.1.0
|
5
|
+
- 2.0.0-p353
|
6
|
+
- ruby-head
|
7
|
+
notifications:
|
8
|
+
flowdock:
|
9
|
+
secure: TI1C6kvdJrMD7m4ImSvf9cU8+1UBrpzlcsfwu2Q+1MYyEz2eBP819eBVF6g/HQM1Z8KU/7ShCtDA2NJQZXn9HfSbT4pebaAcr7FnyEDuWB/38F6/kZdzG71G10SkaRi4kIp4CbaYovaYrO7simeVoYdtK5RWgxGWcnGML8ubL8Y=
|
10
|
+
before_deploy:
|
11
|
+
- yard doc
|
12
|
+
deploy:
|
13
|
+
- provider: s3
|
14
|
+
access_key_id: AKIAIQXC7KNC6CPV3RMA
|
15
|
+
bucket: clustr.koala.im
|
16
|
+
skip_cleanup: true
|
17
|
+
local-dir: doc
|
18
|
+
edge: true
|
19
|
+
region: eu-west-1
|
20
|
+
endpoint: s3-eu-west-1.amazonaws.com
|
21
|
+
on:
|
22
|
+
branch: master
|
23
|
+
secret_access_key:
|
24
|
+
secure: dNZcJd61mj56+nCkOHpmKt+hcwB3KLpvViRLYUKR4G5isgCfkPtoe8PeYx9y/BiNuP0dXGu/Ij7Wgl/BuPGdp6VeNecPZAjWhgsTSuHp7WFlax4WPBe3qdtYWkrws1Gy4vN5da4zN3sY8qWxnu+51t1Im5nibz/fxHnY9THV9q8=
|
25
|
+
- provider: rubygems
|
26
|
+
on:
|
27
|
+
branch: master
|
28
|
+
api_key:
|
29
|
+
secure: Kkwrzg+2dJrrShwVceco8EEP8Kc9BsKvDWIK6pFrdalZRY4sDG7BC7phPOmQPW40Qvl9f3qaZFjpohN0/QLDlF48Zg2AUBGuKfWpQ7V+dTL7hd6ZewFEs/5vyoofEf7BkSE9NFrsuOymEtHH+MJjqY+aIFg4YrNRcoEvCFuEZRk=
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 davidkelley
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Clustr
|
2
|
+
|
3
|
+
[](https://coveralls.io/r/davidkelley/clustr) [](https://travis-ci.org/davidkelley/clustr) [](https://codeclimate.com/github/davidkelley/clustr) [](https://gemnasium.com/davidkelley/clustr)
|
4
|
+
|
5
|
+
TODO: Write a gem description
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'clustr'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install clustr
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( http://github.com/<my-github-username>/clustr/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/clustr
ADDED
data/clustr.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'clustr/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "clustr"
|
8
|
+
spec.version = Clustr::VERSION
|
9
|
+
spec.authors = ["davidkelley"]
|
10
|
+
spec.email = ["david.james.kelley@gmail.com"]
|
11
|
+
spec.summary = %q{Ruby gem that enables EC2 instances to cluster together.}
|
12
|
+
spec.description = %q{This gem uses Amazon SimpleDB and other adapters, to track namespaced attributes for instances that need to cluster together. It provides a simple CLI which can be used in conjunction with other shell commands. See examples/ for example Cloudformation Templates.}
|
13
|
+
spec.homepage = "https://github.com/davidkelley/clustr"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "thor"
|
22
|
+
spec.add_dependency "aws-sdk"
|
23
|
+
spec.add_dependency "terminal-table"
|
24
|
+
spec.add_dependency "nokogiri", ">= 1.4.4"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
27
|
+
spec.add_development_dependency "rspec", "~> 2.6"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "yard"
|
30
|
+
spec.add_development_dependency "faker"
|
31
|
+
spec.add_development_dependency "redcarpet"
|
32
|
+
spec.add_development_dependency "cucumber"
|
33
|
+
spec.add_development_dependency "aruba"
|
34
|
+
spec.add_development_dependency "fakefs"
|
35
|
+
spec.add_development_dependency "factory_girl"
|
36
|
+
spec.add_development_dependency "codeclimate-test-reporter"
|
37
|
+
spec.add_development_dependency 'coveralls'
|
38
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Clustr
|
2
|
+
module Adapter
|
3
|
+
# Base class for all implemented Adapters.
|
4
|
+
class Base
|
5
|
+
|
6
|
+
attr_reader :key
|
7
|
+
|
8
|
+
# Initializes a new Adapter class and associates
|
9
|
+
# the unique key for this cluster to the @key
|
10
|
+
# variable. This key is required for all Adapters.
|
11
|
+
def initialize(options)
|
12
|
+
@key = options["key"]
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Clustr
|
2
|
+
module Adapter
|
3
|
+
# Implements the SimpleDB adapter, which controls a cluster
|
4
|
+
# and its members through the usage of SimpleDB as a centralized,
|
5
|
+
# high-availability data store.
|
6
|
+
#
|
7
|
+
# SimpleDB is capable of storing unique node identifiers along
|
8
|
+
# with additional information that is to be associated with them.
|
9
|
+
class SimpleDB < Clustr::Adapter::Base
|
10
|
+
|
11
|
+
# Initializes a new SimpleDB Adapter class. If the domain
|
12
|
+
# that has been defined in the @key attribute does not exist,
|
13
|
+
# it will create it.
|
14
|
+
def initialize
|
15
|
+
super
|
16
|
+
sdb.domains.create(@key) unless domain.exists?
|
17
|
+
end
|
18
|
+
|
19
|
+
# Add a new node to the SimpleDB domain.
|
20
|
+
#
|
21
|
+
# @param [string] id Unique ID of the node to add.
|
22
|
+
# @param [integer] created timestamp of the node.
|
23
|
+
# @param [hash] properties additional properties to add for the node.
|
24
|
+
#
|
25
|
+
# @return [boolean] True if node was added successfully, false otherwise.
|
26
|
+
def add(id, created, properties = {})
|
27
|
+
item = domain.items[id]
|
28
|
+
properties.each { |k, v| item.attributes[k] = v }
|
29
|
+
item.attributes["joined"] = created
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return an array of the unique identifiers for each node
|
34
|
+
# in the cluster.
|
35
|
+
#
|
36
|
+
# @return [array] an array containing the unique ids for each node.
|
37
|
+
def members
|
38
|
+
domain.items.collect(&:name)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def domain
|
44
|
+
sdb.domains[@key]
|
45
|
+
end
|
46
|
+
|
47
|
+
def sdb
|
48
|
+
@sdb ||= AWS::SimpleDB.new
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "clustr/adapter/base"
|
2
|
+
|
3
|
+
require "clustr/adapter/simpledb"
|
4
|
+
|
5
|
+
module Clustr
|
6
|
+
# Contains different adapters for controlling the
|
7
|
+
# underlying logic for determining current members
|
8
|
+
# and adding new members to a cluster through the
|
9
|
+
# usage of different technologies,
|
10
|
+
# such as {Clustr::Adapter::SimpleDB}.
|
11
|
+
module Adapter
|
12
|
+
|
13
|
+
# Instantiates and returns a new Adapter class
|
14
|
+
# which has been determined from the options hash
|
15
|
+
# that has been passed in.
|
16
|
+
#
|
17
|
+
# @example Initializing a new adapter
|
18
|
+
# sdb = Clustr::Adapter.from_options({
|
19
|
+
# "adapter" => "SimpleDB",
|
20
|
+
# "key" => "foobar"
|
21
|
+
# })
|
22
|
+
#
|
23
|
+
# @note The named adapter must equal the defined class name.
|
24
|
+
#
|
25
|
+
# @param [hash] options to use, must contain an "adapter" key.
|
26
|
+
#
|
27
|
+
# @return [object] An instantiated adapter object.
|
28
|
+
def self.from_options(options)
|
29
|
+
name = options["adapter"]
|
30
|
+
self[name].new(options)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return the constantized adapter class.
|
34
|
+
#
|
35
|
+
# @param [string] adapter to return.
|
36
|
+
#
|
37
|
+
# @return [class] The uninitialized Adapter, nil if undefined.
|
38
|
+
def self.[](adapter)
|
39
|
+
self.const_get adapter
|
40
|
+
end
|
41
|
+
|
42
|
+
# Determines if the named adapter that has been passed in
|
43
|
+
# is a defined and implemented Adapter.
|
44
|
+
#
|
45
|
+
# @param [string] adapter name
|
46
|
+
#
|
47
|
+
# @return [boolean] True if the Adapter is implemented, false otherwise.
|
48
|
+
def self.exists?(adapter)
|
49
|
+
self.const_defined? adapter
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/lib/clustr/cli.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'clustr'
|
3
|
+
require 'terminal-table'
|
4
|
+
|
5
|
+
require 'clustr/log'
|
6
|
+
|
7
|
+
module Clustr
|
8
|
+
# Provides a Command Line Interface for the Launcher gem. See the method definitions
|
9
|
+
# for more information on its usage.
|
10
|
+
#
|
11
|
+
# @example Checking the version
|
12
|
+
# launcher version
|
13
|
+
class CLI < Thor
|
14
|
+
|
15
|
+
package_name "Clustr"
|
16
|
+
|
17
|
+
class_option :access_key_id, :type => :string
|
18
|
+
class_option :secret_access_key, :type => :string
|
19
|
+
class_option :region, :type => :string, :default => "eu-west-1"
|
20
|
+
|
21
|
+
def initialize(*args)
|
22
|
+
super
|
23
|
+
# Commit command line options to general config
|
24
|
+
Clustr::Config(options)
|
25
|
+
|
26
|
+
# Set AWS Configuration if it has been passed in
|
27
|
+
config = ["access_key_id", "secret_access_key", "region"]
|
28
|
+
::AWS.config(options.select { |k| config.include?(k) })
|
29
|
+
describe_aws_configuration
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "version", "Displays the current version number of Clustr."
|
33
|
+
# Displays the current version of the installed Clustr gem on the command line.
|
34
|
+
# For more help on this command, use `clustr help version` from the command line.
|
35
|
+
def version
|
36
|
+
Log.info Clustr::VERSION
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "join", "Insert this node into the cluster, along with any additional attributes."
|
40
|
+
method_option :clusters, :type => :array, :desc => "List of clusters this node should join."
|
41
|
+
method_option :id, :type => :string, :desc => "ID of the node joining the cluster.", :required => true
|
42
|
+
method_option :attributes, :type => :hash, :desc => "Additional attributes to store for this node", :default => {}
|
43
|
+
# Joins the node that this command is ran on, to a new, or previously existing cluster.
|
44
|
+
# For more help on this command, use `clustr help join` from the command line.
|
45
|
+
def join
|
46
|
+
node = Node.new Config[:id], Config[:attributes]
|
47
|
+
(Config[:clusters] || clusters.keys).each do |cluster|
|
48
|
+
if clusters.include?(cluster)
|
49
|
+
if clusters[cluster].add(node)
|
50
|
+
Log.ok "Joined cluster #{cluster}"
|
51
|
+
end
|
52
|
+
else
|
53
|
+
raise ArgumentError.new "Cluster #{cluster} not configured."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "list", "Output only the unique identifiers for each node in a list."
|
59
|
+
method_option :cluster, :type => :string, :desc => "The cluster to output nodes from.", :required => true
|
60
|
+
method_option :delimiter, :type => :string, :desc => "The delimiter to separate each node identifier with, defaults to space", :default => " "
|
61
|
+
def list
|
62
|
+
puts clusters[Config[:cluster]].members.join(Config[:delimiter])
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def clusters
|
68
|
+
@clusters ||= ClusterCollection.new(Config::Clusters.configuration)
|
69
|
+
end
|
70
|
+
|
71
|
+
def aws_configuration
|
72
|
+
AWS.config.credentials
|
73
|
+
end
|
74
|
+
|
75
|
+
def aws_configured?
|
76
|
+
begin
|
77
|
+
aws_configuration
|
78
|
+
rescue
|
79
|
+
false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def describe_aws_configuration
|
84
|
+
if aws_configured?
|
85
|
+
config = aws_configuration
|
86
|
+
Log.info "AWS Region #{config[:region]}"
|
87
|
+
Log.info "AWS Access Key #{config[:access_key_id]}"
|
88
|
+
else
|
89
|
+
Log.warn "No AWS config detected."
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Clustr
|
2
|
+
# Represents a cluster that has been configured and initialized
|
3
|
+
# from the options passed into it. Each Cluster has an adapter,
|
4
|
+
# which is reponsible for determining the current members
|
5
|
+
# of a cluster, and adding new nodes.
|
6
|
+
class Cluster
|
7
|
+
|
8
|
+
attr_accessor :name
|
9
|
+
|
10
|
+
# Initializes a new Cluster from the options that
|
11
|
+
# are passed into it. Information about the adapter
|
12
|
+
# that this cluster should use is required.
|
13
|
+
#
|
14
|
+
# @example Instantiating a new Cluster
|
15
|
+
# cluster = Clustr::Cluster.new "my_cluster", {
|
16
|
+
# "adapter" => "SimpleDB",
|
17
|
+
# "key" => "simpledb-domain-edfvw2031"
|
18
|
+
# }
|
19
|
+
#
|
20
|
+
# @param [string] name of the cluster
|
21
|
+
# @param [hash] options to initialize the cluster with.
|
22
|
+
def initialize(name, options)
|
23
|
+
@name = name
|
24
|
+
@adapter = Clustr::Adapter.from_options(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return an array of the unique identifiers for each
|
28
|
+
# node within the cluster.
|
29
|
+
#
|
30
|
+
# @note This method only returns the ID's for each node,
|
31
|
+
# not any accompanying attributes for the node.
|
32
|
+
#
|
33
|
+
# @return [array] Cluster members, node ID's
|
34
|
+
def members
|
35
|
+
@adapter.members
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns an array of {Node} objects. These nodes
|
39
|
+
# have been identified as members of this Cluster.
|
40
|
+
#
|
41
|
+
# @return [array] Array of {Node} objects.
|
42
|
+
def nodes
|
43
|
+
raise NotImplementedError.new
|
44
|
+
end
|
45
|
+
|
46
|
+
# Add a node to this cluster. Note that the node
|
47
|
+
# must have a compatible ID.
|
48
|
+
#
|
49
|
+
# @param [Node] node to add to this cluster.
|
50
|
+
#
|
51
|
+
# @return [boolean] True if successful, false otherwise
|
52
|
+
def add(node)
|
53
|
+
@adapter.add node.id, node.created, node.properties
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Clustr
|
2
|
+
# Represents a collection of the current {Cluster}
|
3
|
+
# configurations. This class can handle initializing
|
4
|
+
# clusters that have been defined through
|
5
|
+
# {Clustr::Config::Clusters}.
|
6
|
+
#
|
7
|
+
# @note The key for each cluster is its name, ie. "rabbitmq"
|
8
|
+
class ClusterCollection < Hash
|
9
|
+
|
10
|
+
# Initializes a collection of {Cluster} instances,
|
11
|
+
# by looping through the configurations that have been
|
12
|
+
# passed in.
|
13
|
+
#
|
14
|
+
# @example Initializing a ClusterCollection
|
15
|
+
# config = {
|
16
|
+
# "rabbitmq" => {
|
17
|
+
# "adapter" => "SimpleDB",
|
18
|
+
# "key" => "my-simpledb-domain"
|
19
|
+
# }
|
20
|
+
# }
|
21
|
+
# clusters = ClusterCollection.new(config)
|
22
|
+
def initialize(configurations = {})
|
23
|
+
configurations.each do |name, config|
|
24
|
+
self[name] = Clustr::Cluster.new(name, config)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Clustr
|
2
|
+
module Config
|
3
|
+
# Handles determining the configuration for clusters that are
|
4
|
+
# present on the machine. Note that configurations should
|
5
|
+
# be defined in "~/.clustr".
|
6
|
+
class Clusters < Hash
|
7
|
+
|
8
|
+
# Determines if there are any configured clusters.
|
9
|
+
#
|
10
|
+
# @return [boolean] True if one or more configuration
|
11
|
+
# are present, false otherwise.
|
12
|
+
def self.configured?
|
13
|
+
!configuration.empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the configuration for the clusters that have been
|
17
|
+
# defined inside the "~/.clustr/" folder. Note that the
|
18
|
+
# filename for each configuration, becomes the determined
|
19
|
+
# name for that cluster.
|
20
|
+
#
|
21
|
+
# @return [hash] A hash of the clusters and their accompanying
|
22
|
+
# configuration (including the adapter and key).
|
23
|
+
def self.configuration
|
24
|
+
clusters ||= self.new
|
25
|
+
|
26
|
+
config_files.each do |file|
|
27
|
+
cluster = Pathname.new(file).basename.to_s
|
28
|
+
clusters[cluster] = {}
|
29
|
+
File.open(file, 'r') do |fh|
|
30
|
+
fh.each_line do |line|
|
31
|
+
key, val = line.strip.split(%r(\s*=\s*))
|
32
|
+
clusters[cluster][key] = val if key && val
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
clusters
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
@@path = File.expand_path("~/.clustr")
|
43
|
+
|
44
|
+
def self.config_files
|
45
|
+
if Dir.exists?(@@path)
|
46
|
+
entries = Dir.entries(@@path)
|
47
|
+
entries = entries - [".", ".."]
|
48
|
+
entries.collect { |e| [@@path,e].join("/") }
|
49
|
+
else
|
50
|
+
[]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'clustr/config/clusters'
|
2
|
+
|
3
|
+
module Clustr
|
4
|
+
|
5
|
+
# Adds configuration values to the current static instance of Clustr.
|
6
|
+
#
|
7
|
+
# @overload self.Config(config={})
|
8
|
+
# @param [Hash] config of keys and values to add.
|
9
|
+
def self.Config(config={})
|
10
|
+
config.each do |key, value|
|
11
|
+
Clustr::Config[key] = value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Controls all configuration settings for the Clustr gem.
|
16
|
+
# @note This module should be accessed from within a static context.
|
17
|
+
module Config
|
18
|
+
|
19
|
+
# Retrieves values for the provided keys.
|
20
|
+
# @note Keys not present within the configuration will be omitted from the returned hash.
|
21
|
+
#
|
22
|
+
# @example Guided Usage
|
23
|
+
# Clustr::Config.select(:a, :b, :c, :d)
|
24
|
+
#
|
25
|
+
# @param [Splat] args of the key value pairs to retrieve.
|
26
|
+
# @return [Hash] a hash of the keys present within configuration.
|
27
|
+
def self.select(*args)
|
28
|
+
@@_.select { |key| args.include?(key) }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Accesses {Clustr::Config} as an array of key-based values.
|
32
|
+
#
|
33
|
+
# @example Retrieve a singular key using a symbol
|
34
|
+
# Clustr::Config[:a]
|
35
|
+
# @example Retrieve a singular key using a string
|
36
|
+
# Clustr::Config["a"]
|
37
|
+
#
|
38
|
+
# @param [Symbol] key of the value to retrieve.
|
39
|
+
# @return [Mixed, Nil] Will return the value of the key or nil.
|
40
|
+
def self.[](key)
|
41
|
+
@@_[key.to_sym]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Sets or modifies a key and value within the current configuration state.
|
45
|
+
#
|
46
|
+
# @example Usage
|
47
|
+
# Clustr::Config[:a] = "hello world!"
|
48
|
+
#
|
49
|
+
# @param [Symbol] key of the value to set.
|
50
|
+
# @param [Mixed] value of the element.
|
51
|
+
# @return [Mixed] the new value of the element.
|
52
|
+
def self.[]=(key,value)
|
53
|
+
@@_[key.to_sym] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
# Removes a key from the current configuration state.
|
57
|
+
#
|
58
|
+
# @example Usage
|
59
|
+
# Clustr::Config.delete!(:one, :or, :more, :keys)
|
60
|
+
#
|
61
|
+
# @param [Symbol] keys of the values to delete.
|
62
|
+
# @return [Hash] the values that have been deleted
|
63
|
+
def self.delete!(*keys)
|
64
|
+
keys.each { |k| @@_.delete(k.to_sym) }
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
@@_ = {}
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
data/lib/clustr/log.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
module Clustr
|
4
|
+
# The Log class provides a static interface to output text to STDOUT.
|
5
|
+
# It provides helpful messages types such as debug, error and ok. On
|
6
|
+
# most command line interfaces, {Clustr::Log} will also output text
|
7
|
+
# from various messages types in an appropriate color.
|
8
|
+
#
|
9
|
+
# @example Sending a log message
|
10
|
+
# Clustr::Log.fatal "My fatal error is", exception.class.name
|
11
|
+
class Log
|
12
|
+
|
13
|
+
%w(debug error info warn fatal ok).each do |type|
|
14
|
+
define_singleton_method(type) do |*msgs|
|
15
|
+
@@log.send(type, *msgs.join(' '))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Print an OK log message using a concatenation of various strings
|
20
|
+
# that have been passed in.
|
21
|
+
#
|
22
|
+
# @example Sending an OK Message
|
23
|
+
# Clustr::Log.ok "Hello", username # => "Hello David"
|
24
|
+
def self.ok(*msgs)
|
25
|
+
print format_msg("OK", *msgs.join(' ')), :ok
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def self.format_msg(severity, msg, datetime=Time.now)
|
31
|
+
"[#{datetime}] [#{severity}]: #{msg}\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
@@log = Logger.new(STDOUT)
|
37
|
+
|
38
|
+
@@log.formatter = proc { |severity, datetime, progname, msg|
|
39
|
+
format_msg severity, msg, datetime
|
40
|
+
}
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|