hosties 1.1.0.alpha → 1.1.0.alpha2
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 +4 -4
- data/lib/hosties/definitions.rb +118 -111
- data/lib/hosties/easydata.rb +35 -8
- data/lib/hosties/reification.rb +87 -83
- data/spec/definitions_spec.rb +33 -6
- data/spec/easydata_spec.rb +2 -2
- data/spec/hosties_spec.rb +23 -5
- data/spec/reification_spec.rb +5 -5
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c5aad13eda9a31ed69dda41c369424d5311e4d60
|
|
4
|
+
data.tar.gz: 3a37f4fed44c321a37ec488580e164e7c521fd55
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2c27fff8d37d95deb87f6387c360e5eb7a259aced2e88fd1ea730928100b1b9990bad978261b6ed0ce20d8806a8dc1b575dd1b75d12f24142965d9e8db120c8e
|
|
7
|
+
data.tar.gz: 0e18fd57a070555657954bb4433a147e6c4a9dd10a51e9a5e59b28976cf9f892de63459219147cacb71d58a9e710008fd5123e98f6e708335415e7b8af0e8470
|
data/lib/hosties/definitions.rb
CHANGED
|
@@ -4,138 +4,145 @@
|
|
|
4
4
|
# have in order to be valid. #
|
|
5
5
|
#######################################################################
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
# for
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
module Hosties
|
|
8
|
+
# Constrains a named attribute to a provided set of values. This is good
|
|
9
|
+
# for things like describing environments that a set of hosts can be in,
|
|
10
|
+
# for instance Dev, QA, etc
|
|
11
|
+
class AttributeConstraint
|
|
12
|
+
attr_reader :name, :possible_vals
|
|
13
|
+
|
|
14
|
+
def initialize(name)
|
|
15
|
+
@name = name
|
|
16
|
+
@possible_vals = []
|
|
17
|
+
end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
def can_be(val, *more)
|
|
20
|
+
@possible_vals += (more << val)
|
|
21
|
+
end
|
|
20
22
|
end
|
|
21
|
-
end
|
|
22
23
|
|
|
23
|
-
# Superclass for the host and environment requirement types. This
|
|
24
|
-
# class handles the plumbing of tracking, constraining, and eventually
|
|
25
|
-
# reifying attributes.
|
|
26
|
-
class HasAttributes
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
# Superclass for the host and environment requirement types. This
|
|
25
|
+
# class handles the plumbing of tracking, constraining, and eventually
|
|
26
|
+
# reifying attributes.
|
|
27
|
+
class HasAttributes
|
|
28
|
+
attr_accessor :constraints
|
|
29
|
+
attr_accessor :attributes
|
|
30
|
+
|
|
31
|
+
def initialize(verbotten = [])
|
|
32
|
+
@constraints = {}
|
|
33
|
+
@attributes = []
|
|
34
|
+
@verbotten = verbotten
|
|
35
|
+
end
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
# Specify symbols that will later be reified into attributes
|
|
38
|
+
def have_attributes(attr, *more)
|
|
39
|
+
sum = (more << attr)
|
|
40
|
+
sum.each do |name|
|
|
41
|
+
raise ArgumentError, "Reserved attribute name #{name}" if @verbotten.include?(name)
|
|
42
|
+
end
|
|
43
|
+
@attributes += sum
|
|
44
|
+
end
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
alias_method :have_attribute, :have_attributes
|
|
47
|
+
alias_method :has_attribute, :have_attribute
|
|
48
|
+
alias_method :has_attributes, :have_attributes
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
# Helpful method to define constraints
|
|
51
|
+
def where(name)
|
|
52
|
+
# Must define the attributes before constraining them
|
|
53
|
+
raise ArgumentError, "Unknown attribute: #{name}" unless @attributes.include? name
|
|
54
|
+
@constraints[name] = AttributeConstraint.new(name)
|
|
55
|
+
end
|
|
49
56
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
# Check if a given name-value pair is valid given the constraints
|
|
58
|
+
def valid?(name, value)
|
|
59
|
+
if @constraints.include? name then
|
|
60
|
+
constraints[name].possible_vals.include? value
|
|
61
|
+
else true end
|
|
62
|
+
end
|
|
55
63
|
end
|
|
56
|
-
end
|
|
57
64
|
|
|
58
|
-
# Defines what a host of a certain type looks like
|
|
59
|
-
class HostRequirement < HasAttributes
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
# Defines what a host of a certain type looks like
|
|
66
|
+
class HostRequirement < HasAttributes
|
|
67
|
+
attr_reader :type, :services
|
|
68
|
+
def initialize(type)
|
|
69
|
+
super([:hostname, :type])
|
|
70
|
+
@type = type
|
|
71
|
+
@services = []
|
|
72
|
+
end
|
|
66
73
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
# Services will be provided with a host definition. In order for
|
|
75
|
+
# a host definition to be valid, it must provide service details
|
|
76
|
+
# for all of the services specified by its matching
|
|
77
|
+
# HostRequirement
|
|
78
|
+
def have_services(service, *more)
|
|
79
|
+
@services += (more << service)
|
|
80
|
+
end
|
|
74
81
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
alias_method :have_service, :have_services
|
|
83
|
+
alias_method :has_service, :have_service
|
|
84
|
+
alias_method :has_services, :have_services
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
def finished
|
|
87
|
+
Hosties::HostDefinitions[@type] = self
|
|
88
|
+
end
|
|
81
89
|
end
|
|
82
|
-
end
|
|
83
90
|
|
|
84
|
-
# Builder method
|
|
85
|
-
def host_type(symbol, &block)
|
|
86
|
-
builder = HostRequirement.new(symbol)
|
|
87
|
-
begin
|
|
88
|
-
builder.instance_eval(&block)
|
|
89
|
-
builder.finished
|
|
90
|
-
rescue ArgumentError => ex
|
|
91
|
-
# TODO: There must be a better way!
|
|
92
|
-
# I'd like to provide some feedback in this case, but I don't
|
|
93
|
-
# like having this show up in test output.
|
|
94
|
-
#puts "Problem defining host \"#{symbol}\": #{ex}"
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
91
|
|
|
98
|
-
# Used to describe an environment.
|
|
99
|
-
class EnvironmentRequirement < HasAttributes
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
92
|
+
# Used to describe an environment.
|
|
93
|
+
class EnvironmentRequirement < HasAttributes
|
|
94
|
+
attr_reader :type, :hosts, :grouping, :host_attributes
|
|
95
|
+
def initialize(type)
|
|
96
|
+
super([:type, :hosts])
|
|
97
|
+
@type = type
|
|
98
|
+
@host_attributes = []
|
|
99
|
+
@hosts = []
|
|
100
|
+
end
|
|
106
101
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
102
|
+
# Define the hosts that an environment needs to be valid,
|
|
103
|
+
# for instance, maybe you need a :logger host and a
|
|
104
|
+
# :service host at a minimum.
|
|
105
|
+
def need(host1, *more)
|
|
106
|
+
sum = more << host1
|
|
107
|
+
# Array doesn't have an 'exists' method, so behold - map reduce wankery!
|
|
108
|
+
unless sum.map { |x| Hosties::HostDefinitions.include? x }.reduce(true) { |xs, x| x & xs }
|
|
109
|
+
raise ArgumentError, "Unrecognized host type"
|
|
110
|
+
end
|
|
111
|
+
@hosts += sum
|
|
115
112
|
end
|
|
116
|
-
@hosts += sum
|
|
117
|
-
end
|
|
118
113
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
114
|
+
alias_method :needs, :need
|
|
115
|
+
|
|
116
|
+
def hosts_inherit(attr)
|
|
117
|
+
unless self.attributes.include? attr then
|
|
118
|
+
raise ArgumentError, "Unrecognized attribute #{attr}"
|
|
119
|
+
end
|
|
120
|
+
@host_attributes << attr
|
|
121
|
+
end
|
|
125
122
|
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
# Optionally specify an attribute to group by when registering
|
|
124
|
+
# environments of this type.
|
|
125
|
+
def grouped_by(attr)
|
|
126
|
+
raise ArgumentError, "Unknown attribute #{attr}" unless @attributes.include?(attr)
|
|
127
|
+
@grouping = attr
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def finished
|
|
131
|
+
Hosties::EnvironmentDefinitions[@type] = self
|
|
132
|
+
end
|
|
128
133
|
end
|
|
129
134
|
end
|
|
130
135
|
|
|
131
|
-
|
|
136
|
+
## Globally accessible builder methods
|
|
137
|
+
|
|
132
138
|
def environment_type(symbol, &block)
|
|
133
|
-
builder = EnvironmentRequirement.new(symbol)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
builder = Hosties::EnvironmentRequirement.new(symbol)
|
|
140
|
+
builder.instance_eval(&block)
|
|
141
|
+
builder.finished
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def host_type(symbol, &block)
|
|
145
|
+
builder = Hosties::HostRequirement.new(symbol)
|
|
146
|
+
builder.instance_eval(&block)
|
|
147
|
+
builder.finished
|
|
141
148
|
end
|
data/lib/hosties/easydata.rb
CHANGED
|
@@ -2,23 +2,33 @@
|
|
|
2
2
|
# Provide a more convenient data structure to work with once #
|
|
3
3
|
# environment declarations have been read. #
|
|
4
4
|
###############################################################
|
|
5
|
-
class DataWrapper
|
|
6
|
-
def metaclass
|
|
7
|
-
class << self
|
|
8
|
-
self
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
5
|
module Hosties
|
|
14
6
|
module EasyData
|
|
7
|
+
class DataWrapper
|
|
8
|
+
def metaclass
|
|
9
|
+
class << self
|
|
10
|
+
self
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
15
|
def self.fromHost(hash)
|
|
16
16
|
result = DataWrapper.new
|
|
17
17
|
hash.each do |k, v|
|
|
18
18
|
result.metaclass.send(:define_method, k) do v end
|
|
19
19
|
end
|
|
20
|
+
# Define a human-friendly to_s
|
|
21
|
+
# NOTE: Application behavior should not rely on the stability of this
|
|
22
|
+
# string representation! It is subject to change whenever I'm feeling
|
|
23
|
+
# squirrely.
|
|
24
|
+
filtered_hash = hash.reject { |k,v| k == :type or k == :hostname }
|
|
25
|
+
attr_string = filtered_hash.map{|k,v| "#{k}: #{v}"}.join(", ")
|
|
26
|
+
result.metaclass.send(:define_method, :to_s) do
|
|
27
|
+
"<#{hash[:type]} host @ #{hash[:hostname]} attrs: #{attr_string}>"
|
|
28
|
+
end
|
|
20
29
|
result
|
|
21
30
|
end
|
|
31
|
+
|
|
22
32
|
def self.fromEnv(hash)
|
|
23
33
|
result = DataWrapper.new
|
|
24
34
|
hash.each do |k, v|
|
|
@@ -34,6 +44,23 @@ module Hosties
|
|
|
34
44
|
result.metaclass.send(:define_method, :each_host) do |&block|
|
|
35
45
|
yield self.hosts
|
|
36
46
|
end
|
|
47
|
+
# Apply all of the host_attributes to our little host children
|
|
48
|
+
definition = Hosties::EnvironmentDefinitions[hash[:type]]
|
|
49
|
+
inheritance = definition.host_attributes
|
|
50
|
+
hash[:hosts].each do |host|
|
|
51
|
+
inheritance.each do |attr|
|
|
52
|
+
val = hash[attr]
|
|
53
|
+
host.metaclass.send(:define_method, attr) do val end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
# Human friendly to_s
|
|
57
|
+
# NOTE: As above, this representation is subject to change whenever,
|
|
58
|
+
# don't rely on it for application behavior!
|
|
59
|
+
filtered_hash = hash.reject { |k,v| k == :type or k == :hosts }
|
|
60
|
+
attr_string = filtered_hash.map{|k,v| "#{k}: #{v}"}.join(", ")
|
|
61
|
+
result.metaclass.send(:define_method, :to_s) do
|
|
62
|
+
"<#{hash[:type]} environment, attrs: #{attr_string}, hosts: #{hash[:hosts].join(", ")}>"
|
|
63
|
+
end
|
|
37
64
|
result
|
|
38
65
|
end
|
|
39
66
|
end
|
data/lib/hosties/reification.rb
CHANGED
|
@@ -2,113 +2,117 @@
|
|
|
2
2
|
# Provide some classes to turn a declarative host definition into something
|
|
3
3
|
# more useful in code, applying rules from the definition files to ensure we
|
|
4
4
|
# only get valid stuff.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
|
|
6
|
+
module Hosties
|
|
7
|
+
class UsesAttributes
|
|
8
|
+
# Oh this old thing...
|
|
9
|
+
def metaclass
|
|
10
|
+
class << self
|
|
11
|
+
self
|
|
12
|
+
end
|
|
10
13
|
end
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
def initialize(has_attributes)
|
|
15
|
+
@attributes = has_attributes.attributes
|
|
16
|
+
# Magic.
|
|
17
|
+
has_attributes.attributes.each do |attr|
|
|
18
|
+
# Add in the attribute
|
|
19
|
+
self.metaclass.send(:attr_accessor, attr)
|
|
20
|
+
# Define a constrained setter
|
|
21
|
+
self.metaclass.send(:define_method, attr) do |val|
|
|
22
|
+
raise ArgumentError, "Invalid value" unless has_attributes.valid?(attr, val)
|
|
23
|
+
instance_variable_set "@#{attr}", val
|
|
24
|
+
end
|
|
22
25
|
end
|
|
23
26
|
end
|
|
24
|
-
end
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
# Return a hash after verifying everything was set correctly
|
|
29
|
+
def finish
|
|
30
|
+
retval = {}
|
|
31
|
+
# Ensure all required attributes have been set
|
|
32
|
+
@attributes.each do |attr|
|
|
33
|
+
val = instance_variable_get "@#{attr}"
|
|
34
|
+
raise ArgumentError, "Missing attribute #{attr}" if val.nil?
|
|
35
|
+
retval[attr] = val
|
|
36
|
+
end
|
|
37
|
+
retval
|
|
34
38
|
end
|
|
35
|
-
retval
|
|
36
39
|
end
|
|
37
|
-
end
|
|
38
40
|
|
|
39
|
-
class HostBuilder < UsesAttributes
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
41
|
+
class HostBuilder < UsesAttributes
|
|
42
|
+
def initialize(type, hostname)
|
|
43
|
+
if Hosties::HostDefinitions[type].nil? then
|
|
44
|
+
raise ArgumentError, "Unrecognized host type"
|
|
45
|
+
end
|
|
46
|
+
@type = type
|
|
47
|
+
@definition = Hosties::HostDefinitions[@type]
|
|
48
|
+
@hostname = hostname
|
|
49
|
+
@service_ports = {} # Map of service type to port
|
|
50
|
+
super(@definition) # Creates attribute code
|
|
51
|
+
# Services are really just a special kind of attribute, but for now I'll
|
|
52
|
+
# keep them separate. I'm thinking maybe I could add a new type of attribute
|
|
53
|
+
# constraint that let's a user specify that an attribute must be numeric, or
|
|
54
|
+
# a string for instance.
|
|
55
|
+
@definition.services.each do |service_type|
|
|
56
|
+
self.metaclass.send(:attr_accessor, service_type)
|
|
57
|
+
self.metaclass.send(:define_method, service_type) do |port|
|
|
58
|
+
raise ArgumentError, "Port number required" unless port.is_a? Integer
|
|
59
|
+
@service_ports[service_type] = port
|
|
60
|
+
end
|
|
58
61
|
end
|
|
59
62
|
end
|
|
60
|
-
end
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
def finish
|
|
65
|
+
# Ensure all services have been set
|
|
66
|
+
@definition.services.each do |svc|
|
|
67
|
+
raise ArgumentError, "Missing service #{svc}" if @service_ports[svc].nil?
|
|
68
|
+
end
|
|
69
|
+
# TODO: Declare these reserved names
|
|
70
|
+
super.merge({ :hostname => @hostname, :type => @type }).merge(@service_ports)
|
|
66
71
|
end
|
|
67
|
-
# TODO: Declare these reserved names
|
|
68
|
-
super.merge({ :hostname => @hostname, :type => @type }).merge(@service_ports)
|
|
69
72
|
end
|
|
70
|
-
end
|
|
71
73
|
|
|
72
|
-
# Turn a description into a useful data structure - and it's validated!
|
|
73
|
-
class EnvironmentBuilder < UsesAttributes
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
74
|
+
# Turn a description into a useful data structure - and it's validated!
|
|
75
|
+
class EnvironmentBuilder < UsesAttributes
|
|
76
|
+
def initialize(type)
|
|
77
|
+
if Hosties::EnvironmentDefinitions[type].nil? then
|
|
78
|
+
raise ArgumentError, "Unrecognized environment type"
|
|
79
|
+
end
|
|
80
|
+
@hosts = []
|
|
81
|
+
@type = type
|
|
82
|
+
@definition = Hosties::EnvironmentDefinitions[@type]
|
|
83
|
+
super(@definition) # Creates attribute code
|
|
84
|
+
# More magic, this time create a parameterized host builder based
|
|
85
|
+
# on the type of hosts this environment wants. Poor man's currying
|
|
86
|
+
@definition.hosts.each do |host_type|
|
|
87
|
+
self.metaclass.send(:define_method, host_type) do |hostname, &block|
|
|
88
|
+
begin
|
|
89
|
+
builder = HostBuilder.new(host_type, hostname)
|
|
90
|
+
builder.instance_eval(&block)
|
|
91
|
+
@hosts << Hosties::EasyData.fromHost(builder.finish)
|
|
92
|
+
rescue ArgumentError => ex
|
|
93
|
+
#puts "Problem declaring host: #{ex}"
|
|
94
|
+
raise ex
|
|
95
|
+
end
|
|
93
96
|
end
|
|
94
97
|
end
|
|
95
98
|
end
|
|
96
|
-
end
|
|
97
99
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
def finish
|
|
101
|
+
# Verify all of the required hosts were set
|
|
102
|
+
@definition.hosts.each do |host_type|
|
|
103
|
+
unless @hosts.detect { |host| host.type == host_type } then
|
|
104
|
+
raise ArgumentError, "Missing #{host_type} host"
|
|
105
|
+
end
|
|
103
106
|
end
|
|
107
|
+
super.merge({ :type => @type, :hosts => @hosts })
|
|
104
108
|
end
|
|
105
|
-
super.merge({ :hosts => @hosts })
|
|
106
109
|
end
|
|
107
110
|
end
|
|
108
111
|
|
|
112
|
+
## Globally accessible builder methods
|
|
109
113
|
def environment_for(type, &block)
|
|
110
114
|
begin
|
|
111
|
-
builder = EnvironmentBuilder.new(type)
|
|
115
|
+
builder = Hosties::EnvironmentBuilder.new(type)
|
|
112
116
|
builder.instance_eval(&block)
|
|
113
117
|
data = builder.finish
|
|
114
118
|
nice_version = Hosties::EasyData.fromEnv(data)
|
data/spec/definitions_spec.rb
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
describe HasAttributes do
|
|
3
|
+
describe Hosties::HasAttributes do
|
|
4
4
|
it 'rejects definitions with constraints on nonexistent attributes' do
|
|
5
|
-
instance = HasAttributes.new
|
|
5
|
+
instance = Hosties::HasAttributes.new
|
|
6
6
|
instance.have_attributes :foo, :bar
|
|
7
7
|
expect { instance.where(:baz).can_be("anything") }.to raise_error(ArgumentError)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
describe HostRequirement do
|
|
11
|
+
describe Hosties::HostRequirement do
|
|
12
12
|
it 'defines host types' do
|
|
13
13
|
# Declare a host type
|
|
14
14
|
host_type :logger do
|
|
@@ -16,9 +16,17 @@ describe HostRequirement do
|
|
|
16
16
|
have_attributes :control_mbean, :default_user
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
|
+
|
|
20
|
+
it 'rejects definitions with reserved attribute names' do
|
|
21
|
+
builder = Hosties::HostRequirement.new(:failsauce)
|
|
22
|
+
# hostname
|
|
23
|
+
expect { builder.have_attributes(:hostname) }.to raise_error(ArgumentError)
|
|
24
|
+
# type
|
|
25
|
+
expect { builder.have_attributes(:type) }.to raise_error(ArgumentError)
|
|
26
|
+
end
|
|
19
27
|
end
|
|
20
28
|
|
|
21
|
-
describe EnvironmentRequirement do
|
|
29
|
+
describe Hosties::EnvironmentRequirement do
|
|
22
30
|
it 'defines environments with host and attribute requirements' do
|
|
23
31
|
host_type :mutant_maker do end
|
|
24
32
|
host_type :turkey_blaster do end
|
|
@@ -28,13 +36,32 @@ describe EnvironmentRequirement do
|
|
|
28
36
|
end
|
|
29
37
|
end
|
|
30
38
|
|
|
39
|
+
it 'rejects definitions with reserved attribute names' do
|
|
40
|
+
builder = Hosties::EnvironmentRequirement.new(:failsauce)
|
|
41
|
+
# hosts
|
|
42
|
+
expect { builder.have_attributes(:hosts) }.to raise_error(ArgumentError)
|
|
43
|
+
# type
|
|
44
|
+
expect { builder.have_attributes(:type) }.to raise_error(ArgumentError)
|
|
45
|
+
end
|
|
46
|
+
|
|
31
47
|
it 'rejects environment definitions that need undefined host types' do
|
|
32
|
-
builder = EnvironmentRequirement.new(:failure)
|
|
48
|
+
builder = Hosties::EnvironmentRequirement.new(:failure)
|
|
33
49
|
expect { builder.need(:nonexistent) }.to raise_error(ArgumentError)
|
|
34
50
|
end
|
|
35
51
|
|
|
36
52
|
it 'rejects groupings for unknown attributes' do
|
|
37
|
-
builder = EnvironmentRequirement.new(:failure)
|
|
53
|
+
builder = Hosties::EnvironmentRequirement.new(:failure)
|
|
38
54
|
expect { builder.grouped_by(:nonexistent) }.to raise_error(ArgumentError)
|
|
39
55
|
end
|
|
56
|
+
|
|
57
|
+
it 'can define host-inherited attributes ' do
|
|
58
|
+
builder = Hosties::EnvironmentRequirement.new(:inherit_provider)
|
|
59
|
+
builder.has_attribute :to_inherit
|
|
60
|
+
builder.hosts_inherit :to_inherit
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'catches faulty hosts_inherit clauses' do
|
|
64
|
+
builder = Hosties::EnvironmentRequirement.new(:inherit_failure)
|
|
65
|
+
expect { builder.hosts_inherit :to_inherit }.to raise_error(ArgumentError)
|
|
66
|
+
end
|
|
40
67
|
end
|
data/spec/easydata_spec.rb
CHANGED
|
@@ -6,7 +6,7 @@ describe Hosties::EasyData do
|
|
|
6
6
|
have_service :http
|
|
7
7
|
have_attribute :attr_one
|
|
8
8
|
end
|
|
9
|
-
builder = HostBuilder.new(:easydata_one, "localhost")
|
|
9
|
+
builder = Hosties::HostBuilder.new(:easydata_one, "localhost")
|
|
10
10
|
builder.http 80
|
|
11
11
|
builder.attr_one "One!"
|
|
12
12
|
result = Hosties::EasyData.fromHost(builder.finish)
|
|
@@ -24,7 +24,7 @@ describe Hosties::EasyData do
|
|
|
24
24
|
have_attribute :environment
|
|
25
25
|
where(:environment).can_be :dev, :testing
|
|
26
26
|
end
|
|
27
|
-
builder = EnvironmentBuilder.new :easydata_one
|
|
27
|
+
builder = Hosties::EnvironmentBuilder.new :easydata_one
|
|
28
28
|
builder.easydata_two "0.0.0.0" do end
|
|
29
29
|
builder.easydata_three "1.1.1.1" do end
|
|
30
30
|
builder.environment :dev
|
data/spec/hosties_spec.rb
CHANGED
|
@@ -4,7 +4,7 @@ describe Hosties do
|
|
|
4
4
|
it 'can declare a host' do
|
|
5
5
|
host_type :special_host do
|
|
6
6
|
end
|
|
7
|
-
instance = HostBuilder.new(:special_host, "0.0.0.0")
|
|
7
|
+
instance = Hosties::HostBuilder.new(:special_host, "0.0.0.0")
|
|
8
8
|
expect(instance.finish).to eq({ :hostname => "0.0.0.0", :type => :special_host})
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ describe Hosties do
|
|
|
12
12
|
host_type :web_host do
|
|
13
13
|
have_service :http
|
|
14
14
|
end
|
|
15
|
-
instance = HostBuilder.new(:web_host, "0.0.0.0")
|
|
15
|
+
instance = Hosties::HostBuilder.new(:web_host, "0.0.0.0")
|
|
16
16
|
expect { instance.finish }.to raise_error(ArgumentError)
|
|
17
17
|
end
|
|
18
18
|
|
|
@@ -20,7 +20,7 @@ describe Hosties do
|
|
|
20
20
|
host_type :mud_server do
|
|
21
21
|
have_attribute :version
|
|
22
22
|
end
|
|
23
|
-
instance = HostBuilder.new(:mud_server, "0.0.0.0")
|
|
23
|
+
instance = Hosties::HostBuilder.new(:mud_server, "0.0.0.0")
|
|
24
24
|
expect { instance.finish }.to raise_error(ArgumentError)
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -28,7 +28,7 @@ describe Hosties do
|
|
|
28
28
|
host_type :web_host do
|
|
29
29
|
have_service :http
|
|
30
30
|
end
|
|
31
|
-
instance = HostBuilder.new(:web_host, "0.0.0.0")
|
|
31
|
+
instance = Hosties::HostBuilder.new(:web_host, "0.0.0.0")
|
|
32
32
|
expect { instance.http 10.4 }.to raise_error(ArgumentError)
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -40,7 +40,7 @@ describe Hosties do
|
|
|
40
40
|
environment_type :needy_environment do
|
|
41
41
|
need :type_a, :type_b
|
|
42
42
|
end
|
|
43
|
-
builder = EnvironmentBuilder.new(:needy_environment)
|
|
43
|
+
builder = Hosties::EnvironmentBuilder.new(:needy_environment)
|
|
44
44
|
builder.type_a "0.0.0.0" do end
|
|
45
45
|
# No type_b specified
|
|
46
46
|
expect { builder.finish }.to raise_error(ArgumentError)
|
|
@@ -85,6 +85,7 @@ describe Hosties do
|
|
|
85
85
|
expect(data.hosts_by_type(:monitoring).size).to eq(2) # Two monitoring hosts
|
|
86
86
|
expect(data.hosts_by_type(:service_host).size).to eq(1)
|
|
87
87
|
service_host = data.hosts_by_type(:service_host).first
|
|
88
|
+
expect(service_host.hostname).to eq("192.168.0.3")
|
|
88
89
|
expect(service_host.service_port).to eq(1234)
|
|
89
90
|
expect(service_host.uuid).to eq("81E3C1D4-C040-4D59-A56F-4273384D576B")
|
|
90
91
|
end
|
|
@@ -111,4 +112,21 @@ describe Hosties do
|
|
|
111
112
|
expect(Hosties::GroupedEnvironments[:foobar][:dev].size).to eq(1)
|
|
112
113
|
expect(Hosties::GroupedEnvironments[:foobar][:qa].size).to eq(1)
|
|
113
114
|
end
|
|
115
|
+
|
|
116
|
+
it 'lets hosts inherit attributes' do
|
|
117
|
+
host_type :beneficiary do end# ha.
|
|
118
|
+
environment_type :benefactor do
|
|
119
|
+
need :beneficiary
|
|
120
|
+
has_attribute :monies
|
|
121
|
+
hosts_inherit :monies # Lucky!
|
|
122
|
+
end
|
|
123
|
+
amount = 1000000
|
|
124
|
+
environment_for :benefactor do
|
|
125
|
+
beneficiary "0.0.0.0" do end
|
|
126
|
+
# Prove that ordering doesn't matter here
|
|
127
|
+
monies amount
|
|
128
|
+
end
|
|
129
|
+
beneficiary = Hosties::Environments[:benefactor].first.hosts.first
|
|
130
|
+
expect(beneficiary.monies).to eq(amount)
|
|
131
|
+
end
|
|
114
132
|
end
|
data/spec/reification_spec.rb
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
describe UsesAttributes do
|
|
3
|
+
describe Hosties::UsesAttributes do
|
|
4
4
|
it 'can enforce attribute constraints' do
|
|
5
|
-
definition = HasAttributes.new
|
|
5
|
+
definition = Hosties::HasAttributes.new
|
|
6
6
|
definition.have_attributes(:x)
|
|
7
7
|
definition.where(:x).can_be("hello")
|
|
8
|
-
instance = UsesAttributes.new(definition)
|
|
8
|
+
instance = Hosties::UsesAttributes.new(definition)
|
|
9
9
|
instance.x "hello"
|
|
10
10
|
expect { instance.x 31 }.to raise_error(ArgumentError)
|
|
11
11
|
end
|
|
12
12
|
it 'catches missing attributes' do
|
|
13
|
-
definition = HasAttributes.new
|
|
13
|
+
definition = Hosties::HasAttributes.new
|
|
14
14
|
definition.have_attributes(:x)
|
|
15
|
-
instance = UsesAttributes.new(definition)
|
|
15
|
+
instance = Hosties::UsesAttributes.new(definition)
|
|
16
16
|
expect { instance.finish }.to raise_error(ArgumentError)
|
|
17
17
|
end
|
|
18
18
|
end
|