arborist 0.0.1.pre20160128152542 → 0.0.1.pre20160606141735
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -0
- data/ChangeLog +426 -1
- data/Manifest.txt +17 -2
- data/Nodes.md +70 -0
- data/Protocol.md +68 -9
- data/README.md +3 -5
- data/Rakefile +4 -1
- data/TODO.md +52 -20
- data/lib/arborist.rb +19 -6
- data/lib/arborist/cli.rb +39 -25
- data/lib/arborist/client.rb +97 -4
- data/lib/arborist/command/client.rb +2 -1
- data/lib/arborist/command/start.rb +51 -5
- data/lib/arborist/dependency.rb +286 -0
- data/lib/arborist/event.rb +7 -2
- data/lib/arborist/event/{node_matching.rb → node.rb} +11 -5
- data/lib/arborist/event/node_acked.rb +5 -7
- data/lib/arborist/event/node_delta.rb +30 -3
- data/lib/arborist/event/node_disabled.rb +16 -0
- data/lib/arborist/event/node_down.rb +10 -0
- data/lib/arborist/event/node_quieted.rb +11 -0
- data/lib/arborist/event/node_unknown.rb +10 -0
- data/lib/arborist/event/node_up.rb +10 -0
- data/lib/arborist/event/node_update.rb +2 -11
- data/lib/arborist/event/sys_node_added.rb +10 -0
- data/lib/arborist/event/sys_node_removed.rb +10 -0
- data/lib/arborist/exceptions.rb +4 -0
- data/lib/arborist/manager.rb +188 -18
- data/lib/arborist/manager/event_publisher.rb +1 -1
- data/lib/arborist/manager/tree_api.rb +92 -13
- data/lib/arborist/mixins.rb +17 -0
- data/lib/arborist/monitor.rb +10 -1
- data/lib/arborist/monitor/socket.rb +123 -2
- data/lib/arborist/monitor_runner.rb +6 -5
- data/lib/arborist/node.rb +420 -94
- data/lib/arborist/node/ack.rb +72 -0
- data/lib/arborist/node/host.rb +43 -8
- data/lib/arborist/node/resource.rb +73 -0
- data/lib/arborist/node/root.rb +6 -0
- data/lib/arborist/node/service.rb +89 -22
- data/lib/arborist/observer.rb +1 -1
- data/lib/arborist/subscription.rb +11 -6
- data/spec/arborist/client_spec.rb +93 -5
- data/spec/arborist/dependency_spec.rb +375 -0
- data/spec/arborist/event/node_delta_spec.rb +66 -0
- data/spec/arborist/event/node_down_spec.rb +84 -0
- data/spec/arborist/event/node_spec.rb +59 -0
- data/spec/arborist/event/node_update_spec.rb +14 -3
- data/spec/arborist/event_spec.rb +3 -3
- data/spec/arborist/manager/tree_api_spec.rb +295 -3
- data/spec/arborist/manager_spec.rb +240 -57
- data/spec/arborist/monitor_spec.rb +26 -3
- data/spec/arborist/node/ack_spec.rb +74 -0
- data/spec/arborist/node/host_spec.rb +79 -0
- data/spec/arborist/node/resource_spec.rb +56 -0
- data/spec/arborist/node/service_spec.rb +68 -2
- data/spec/arborist/node_spec.rb +288 -11
- data/spec/arborist/subscription_spec.rb +23 -14
- data/spec/arborist_spec.rb +0 -4
- data/spec/data/observers/webservices.rb +10 -2
- data/spec/spec_helper.rb +8 -0
- metadata +58 -15
- metadata.gz.sig +0 -0
- data/LICENSE +0 -29
@@ -0,0 +1,72 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'arborist/node' unless defined?( Arborist::Node )
|
5
|
+
require 'arborist/mixins'
|
6
|
+
|
7
|
+
|
8
|
+
# The inner class for the 'ack' operational property
|
9
|
+
class Arborist::Node::Ack
|
10
|
+
extend Arborist::HashUtilities
|
11
|
+
|
12
|
+
### Construct an instance from the values in the specified +hash+.
|
13
|
+
def self::from_hash( hash )
|
14
|
+
hash = symbolify_keys( hash )
|
15
|
+
|
16
|
+
message = hash.delete( :message ) or raise ArgumentError, "Missing required ACK message"
|
17
|
+
sender = hash.delete( :sender ) or raise ArgumentError, "Missing required ACK sender"
|
18
|
+
|
19
|
+
if hash[:time]
|
20
|
+
hash[:time] = Time.at( hash[:time] ) if hash[:time].is_a?( Numeric )
|
21
|
+
hash[:time] = Time.parse( hash[:time] ) unless hash[:time].is_a?( Time )
|
22
|
+
end
|
23
|
+
|
24
|
+
return new( message, sender, **hash )
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
### Create a new acknowledgement
|
29
|
+
def initialize( message, sender, via: nil, time: nil )
|
30
|
+
time ||= Time.now
|
31
|
+
|
32
|
+
@message = message
|
33
|
+
@sender = sender
|
34
|
+
@via = via
|
35
|
+
@time = time.to_time
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# The object's message, :sender, :via, :time
|
40
|
+
attr_reader :message, :sender, :via, :time
|
41
|
+
|
42
|
+
|
43
|
+
### Return a string description of the acknowledgement for logging and inspection.
|
44
|
+
def description
|
45
|
+
return "by %s%s -- %s" % [
|
46
|
+
self.sender,
|
47
|
+
self.via ? " via #{self.via}" : '',
|
48
|
+
self.message
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
### Return the Ack as a Hash.
|
54
|
+
def to_h
|
55
|
+
return {
|
56
|
+
message: self.message,
|
57
|
+
sender: self.sender,
|
58
|
+
via: self.via,
|
59
|
+
time: self.time.iso8601,
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
### Returns true if the +other+ object is an Ack with the same values.
|
65
|
+
def ==( other )
|
66
|
+
return other.is_a?( self.class ) &&
|
67
|
+
self.to_h == other.to_h
|
68
|
+
end
|
69
|
+
|
70
|
+
end # class Arborist::Node::Ack
|
71
|
+
|
72
|
+
|
data/lib/arborist/node/host.rb
CHANGED
@@ -19,7 +19,7 @@ class Arborist::Node::Host < Arborist::Node
|
|
19
19
|
|
20
20
|
|
21
21
|
### Create a new Host node.
|
22
|
-
def initialize( identifier, &block )
|
22
|
+
def initialize( identifier, attributes={}, &block )
|
23
23
|
@addresses = []
|
24
24
|
super
|
25
25
|
end
|
@@ -34,6 +34,22 @@ class Arborist::Node::Host < Arborist::Node
|
|
34
34
|
attr_reader :addresses
|
35
35
|
|
36
36
|
|
37
|
+
### Set one or more node +attributes+. Supported attributes (in addition to
|
38
|
+
### those supported by Node) are: +addresses+.
|
39
|
+
def modify( attributes )
|
40
|
+
attributes = stringify_keys( attributes )
|
41
|
+
|
42
|
+
super
|
43
|
+
|
44
|
+
if attributes['addresses']
|
45
|
+
self.addresses.clear
|
46
|
+
Array( attributes['addresses'] ).each do |addr|
|
47
|
+
self.address( addr )
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
37
53
|
### Return the host's operational attributes.
|
38
54
|
def operational_values
|
39
55
|
properties = super
|
@@ -42,7 +58,7 @@ class Arborist::Node::Host < Arborist::Node
|
|
42
58
|
|
43
59
|
|
44
60
|
### Set an IP address of the host.
|
45
|
-
def address( new_address
|
61
|
+
def address( new_address )
|
46
62
|
self.log.debug "Adding address %p to %p" % [ new_address, self ]
|
47
63
|
case new_address
|
48
64
|
when IPAddr
|
@@ -72,16 +88,35 @@ class Arborist::Node::Host < Arborist::Node
|
|
72
88
|
end
|
73
89
|
|
74
90
|
|
75
|
-
### Add a service to the host
|
76
|
-
def service( name, options={}, &block )
|
77
|
-
return Arborist::Node.create( :service, name, self, options, &block )
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
91
|
### Return host-node-specific information for #inspect.
|
82
92
|
def node_description
|
83
93
|
return "{no addresses}" if self.addresses.empty?
|
84
94
|
return "{addresses: %s}" % [ self.addresses.map(&:to_s).join(', ') ]
|
85
95
|
end
|
86
96
|
|
97
|
+
|
98
|
+
#
|
99
|
+
# Serialization
|
100
|
+
#
|
101
|
+
|
102
|
+
### Return a Hash of the host node's state.
|
103
|
+
def to_h
|
104
|
+
return super.merge( addresses: self.addresses.map(&:to_s) )
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
### Marshal API -- set up the object's state using the +hash+ from a previously-marshalled
|
109
|
+
### node. Overridden to turn the addresses back into IPAddr objects.
|
110
|
+
def marshal_load( hash )
|
111
|
+
super
|
112
|
+
@addresses = hash[:addresses].map {|addr| IPAddr.new(addr) }
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
### Equality operator -- returns +true+ if +other_node+ is equal to the
|
117
|
+
### receiver. Overridden to also compare addresses.
|
118
|
+
def ==( other_host )
|
119
|
+
return super && other_host.addresses == self.addresses
|
120
|
+
end
|
121
|
+
|
87
122
|
end # class Arborist::Node::Host
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'arborist/node'
|
5
|
+
require 'arborist/mixins'
|
6
|
+
|
7
|
+
|
8
|
+
# A node type for Arborist trees that represent arbitrary resources of a host.
|
9
|
+
class Arborist::Node::Resource < Arborist::Node
|
10
|
+
|
11
|
+
# Services live under Host nodes
|
12
|
+
parent_type :host
|
13
|
+
|
14
|
+
|
15
|
+
### Create a new Resource node.
|
16
|
+
def initialize( identifier, host, attributes={}, &block )
|
17
|
+
raise Arborist::NodeError, "no host given" unless host.is_a?( Arborist::Node::Host )
|
18
|
+
qualified_identifier = "%s-%s" % [ host.identifier, identifier ]
|
19
|
+
|
20
|
+
@host = host
|
21
|
+
|
22
|
+
super( qualified_identifier, host, attributes, &block )
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
### Returns +true+ if the node matches the specified +key+ and +val+ criteria.
|
27
|
+
def match_criteria?( key, val )
|
28
|
+
self.log.debug "Matching %p: %p against %p" % [ key, val, self ]
|
29
|
+
return case key
|
30
|
+
when 'address'
|
31
|
+
search_addr = IPAddr.new( val )
|
32
|
+
self.addresses.any? {|a| search_addr.include?(a) }
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
### Return a Hash of the operational values that are included with the node's
|
40
|
+
### monitor state.
|
41
|
+
def operational_values
|
42
|
+
return super.merge(
|
43
|
+
addresses: self.addresses.map( &:to_s )
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
### Delegate the resources's address to its host.
|
49
|
+
def addresses
|
50
|
+
return @host.addresses
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
### Overridden to disallow modification of a Resource parent, as it needs a
|
55
|
+
### reference to the Host node for delegation.
|
56
|
+
def parent( new_parent=nil )
|
57
|
+
return super unless new_parent
|
58
|
+
raise "Can't reparent a resource; replace the node instead"
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
#
|
63
|
+
# Serialization
|
64
|
+
#
|
65
|
+
|
66
|
+
### Return a Hash of the host node's state.
|
67
|
+
def to_h
|
68
|
+
return super.merge(
|
69
|
+
addresses: self.addresses.map( &:to_s )
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
end # class Arborist::Node::Resource
|
data/lib/arborist/node/root.rb
CHANGED
@@ -45,6 +45,12 @@ class Arborist::Node::Root < Arborist::Node
|
|
45
45
|
end
|
46
46
|
|
47
47
|
|
48
|
+
### Ignore restores of serialized root nodes.
|
49
|
+
def restore( other_node )
|
50
|
+
self.log.info "Ignoring restored root node."
|
51
|
+
end
|
52
|
+
|
53
|
+
|
48
54
|
### Ignore updates to the root node.
|
49
55
|
def update( properties )
|
50
56
|
self.log.warn "Update to the root node ignored."
|
@@ -6,31 +6,44 @@ require 'ipaddr'
|
|
6
6
|
require 'socket'
|
7
7
|
|
8
8
|
require 'arborist/node'
|
9
|
+
require 'arborist/mixins'
|
9
10
|
|
10
11
|
|
11
12
|
# A node type for Arborist trees that represent services running on hosts.
|
12
13
|
class Arborist::Node::Service < Arborist::Node
|
14
|
+
include Arborist::HashUtilities
|
15
|
+
|
13
16
|
|
14
17
|
# The default transport layer protocol to use for services that don't specify
|
15
18
|
# one
|
16
19
|
DEFAULT_PROTOCOL = 'tcp'
|
17
20
|
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
my_identifier = "%s-%s" % [ host.identifier, identifier ]
|
22
|
-
super( my_identifier )
|
23
|
-
|
24
|
-
@host = host
|
25
|
-
@parent = host.identifier
|
26
|
-
@app_protocol = options[:app_protocol] || identifier
|
27
|
-
@protocol = options[:protocol] || DEFAULT_PROTOCOL
|
22
|
+
# Services live under Host nodes
|
23
|
+
parent_type :host
|
28
24
|
|
29
|
-
service_port = options[:port] || default_port_for( @app_protocol, @protocol ) or
|
30
|
-
raise ArgumentError, "can't determine the port for %s/%s" % [ @app_protocol, @protocol ]
|
31
|
-
@port = Integer( service_port )
|
32
25
|
|
33
|
-
|
26
|
+
### Create a new Service node.
|
27
|
+
def initialize( identifier, host, attributes={}, &block )
|
28
|
+
raise Arborist::NodeError, "no host given" unless host.is_a?( Arborist::Node::Host )
|
29
|
+
qualified_identifier = "%s-%s" % [ host.identifier, identifier ]
|
30
|
+
|
31
|
+
@host = host
|
32
|
+
@app_protocol = nil
|
33
|
+
@protocol = nil
|
34
|
+
@port = nil
|
35
|
+
|
36
|
+
attributes[ :app_protocol ] ||= identifier
|
37
|
+
attributes[ :protocol ] ||= DEFAULT_PROTOCOL
|
38
|
+
|
39
|
+
super( qualified_identifier, host, attributes, &block )
|
40
|
+
|
41
|
+
unless @port
|
42
|
+
service_port = default_port_for( @app_protocol, @protocol ) or
|
43
|
+
raise ArgumentError, "can't determine the port for %s/%s" %
|
44
|
+
[ @app_protocol, @protocol ]
|
45
|
+
@port = Integer( service_port )
|
46
|
+
end
|
34
47
|
end
|
35
48
|
|
36
49
|
|
@@ -38,17 +51,37 @@ class Arborist::Node::Service < Arborist::Node
|
|
38
51
|
public
|
39
52
|
######
|
40
53
|
|
41
|
-
|
42
|
-
|
43
|
-
|
54
|
+
### Set service +attributes+.
|
55
|
+
def modify( attributes )
|
56
|
+
attributes = stringify_keys( attributes )
|
57
|
+
|
58
|
+
super
|
59
|
+
|
60
|
+
self.port( attributes['port'] )
|
61
|
+
self.app_protocol( attributes['app_protocol'] )
|
62
|
+
self.protocol( attributes['protocol'] )
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
### Get/set the port the service is bound to.
|
67
|
+
def port( new_port=nil )
|
68
|
+
return @port unless new_port
|
69
|
+
@port = new_port
|
70
|
+
end
|
44
71
|
|
45
|
-
##
|
46
|
-
# The transport layer protocol the service uses
|
47
|
-
attr_reader :protocol
|
48
72
|
|
49
|
-
|
50
|
-
|
51
|
-
|
73
|
+
### Get/set the (layer 7) protocol used by the service
|
74
|
+
def app_protocol( new_proto=nil )
|
75
|
+
return @app_protocol unless new_proto
|
76
|
+
@app_protocol = new_proto
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
### Get/set the transport layer protocol the service uses
|
81
|
+
def protocol( new_proto=nil )
|
82
|
+
return @protocol unless new_proto
|
83
|
+
@protocol = new_proto
|
84
|
+
end
|
52
85
|
|
53
86
|
|
54
87
|
### Delegate the service's address to its host.
|
@@ -96,6 +129,40 @@ class Arborist::Node::Service < Arborist::Node
|
|
96
129
|
end
|
97
130
|
|
98
131
|
|
132
|
+
### Overridden to disallow modification of a Service's parent, as it needs a reference to
|
133
|
+
### the Host node for delegation.
|
134
|
+
def parent( new_parent=nil )
|
135
|
+
return super unless new_parent
|
136
|
+
raise "Can't reparent a service; replace the node instead"
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
#
|
141
|
+
# Serialization
|
142
|
+
#
|
143
|
+
|
144
|
+
### Return a Hash of the host node's state.
|
145
|
+
def to_h
|
146
|
+
return super.merge(
|
147
|
+
addresses: self.addresses.map(&:to_s),
|
148
|
+
protocol: self.protocol,
|
149
|
+
app_protocol: self.app_protocol,
|
150
|
+
port: self.port
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
### Equality operator -- returns +true+ if +other_node+ is equal to the
|
156
|
+
### receiver. Overridden to also compare addresses.
|
157
|
+
def ==( other_host )
|
158
|
+
return super &&
|
159
|
+
other_host.addresses == self.addresses &&
|
160
|
+
other_host.protocol == self.protocol &&
|
161
|
+
other_host.app_protocol == self.app_protocol &&
|
162
|
+
other_host.port == self.port
|
163
|
+
end
|
164
|
+
|
165
|
+
|
99
166
|
#######
|
100
167
|
private
|
101
168
|
#######
|
data/lib/arborist/observer.rb
CHANGED
@@ -28,7 +28,7 @@ class Arborist::Observer
|
|
28
28
|
OBSERVER_FILE_PATTERN = '**/*.rb'
|
29
29
|
|
30
30
|
|
31
|
-
Arborist.add_dsl_constructor(
|
31
|
+
Arborist.add_dsl_constructor( self ) do |description, &block|
|
32
32
|
Arborist::Observer.new( description, &block )
|
33
33
|
end
|
34
34
|
|
@@ -20,8 +20,9 @@ class Arborist::Subscription
|
|
20
20
|
|
21
21
|
### Instantiate a new Subscription object given an +event+ pattern
|
22
22
|
### and event +criteria+.
|
23
|
-
def initialize(
|
24
|
-
|
23
|
+
def initialize( event_type=nil, criteria={}, &callback )
|
24
|
+
raise LocalJumpError, "requires a callback block" unless callback
|
25
|
+
@callback = callback
|
25
26
|
@event_type = event_type
|
26
27
|
@criteria = stringify_keys( criteria )
|
27
28
|
@id = self.generate_id
|
@@ -32,8 +33,8 @@ class Arborist::Subscription
|
|
32
33
|
public
|
33
34
|
######
|
34
35
|
|
35
|
-
# The
|
36
|
-
attr_reader :
|
36
|
+
# The callable that should be called when the subscription receives a matching event
|
37
|
+
attr_reader :callback
|
37
38
|
|
38
39
|
# A unique identifier for this subscription request.
|
39
40
|
attr_reader :id
|
@@ -54,7 +55,10 @@ class Arborist::Subscription
|
|
54
55
|
### Publish any of the specified +events+ which match the subscription.
|
55
56
|
def on_events( *events )
|
56
57
|
events.flatten.each do |event|
|
57
|
-
|
58
|
+
if self.interested_in?( event )
|
59
|
+
self.log.debug "Calling %p for a %s event" % [ self.callback, event.type ]
|
60
|
+
self.callback.call( self.id, event )
|
61
|
+
end
|
58
62
|
end
|
59
63
|
end
|
60
64
|
|
@@ -70,12 +74,13 @@ class Arborist::Subscription
|
|
70
74
|
|
71
75
|
### Return a String representation of the object suitable for debugging.
|
72
76
|
def inspect
|
73
|
-
return "#<%p:%#x [%s] for %s events matching: %p>" % [
|
77
|
+
return "#<%p:%#x [%s] for %s events matching: %p -> %p>" % [
|
74
78
|
self.class,
|
75
79
|
self.object_id * 2,
|
76
80
|
self.id,
|
77
81
|
self.event_type,
|
78
82
|
self.criteria,
|
83
|
+
self.callback,
|
79
84
|
]
|
80
85
|
end
|
81
86
|
|
@@ -64,6 +64,20 @@ describe Arborist::Client do
|
|
64
64
|
end
|
65
65
|
|
66
66
|
|
67
|
+
it "can list a depth-limited subtree of the node of the managed it's connected to" do
|
68
|
+
res = client.list( depth: 2 )
|
69
|
+
expect( res ).to be_an( Array )
|
70
|
+
expect( res.length ).to eq( 8 )
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
it "can list a depth-limited subtree of the nodes of the manager it's connected to" do
|
75
|
+
res = client.list( from: 'duir', depth: 1 )
|
76
|
+
expect( res ).to be_an( Array )
|
77
|
+
expect( res.length ).to eq( 5 )
|
78
|
+
end
|
79
|
+
|
80
|
+
|
67
81
|
it "can fetch all node properties for all 'up' nodes" do
|
68
82
|
res = client.fetch
|
69
83
|
expect( res ).to be_a( Hash )
|
@@ -97,6 +111,18 @@ describe Arborist::Client do
|
|
97
111
|
end
|
98
112
|
|
99
113
|
|
114
|
+
it "can fetch all node properties for 'up' nodes that don't match specified criteria" do
|
115
|
+
res = client.fetch( {}, properties: [:addresses, :status], exclude: {tag: 'testing'} )
|
116
|
+
|
117
|
+
testing_nodes = manager.nodes.values.select {|n| n.tags.include?('testing') }
|
118
|
+
|
119
|
+
expect( res ).to be_a( Hash )
|
120
|
+
expect( res ).to_not be_empty()
|
121
|
+
expect( res.length ).to eq( manager.nodes.length - testing_nodes.length )
|
122
|
+
expect( res.values ).to all( be_a(Hash) )
|
123
|
+
end
|
124
|
+
|
125
|
+
|
100
126
|
it "can fetch all properties for all nodes regardless of their status" do
|
101
127
|
# Down a node
|
102
128
|
manager.nodes['duir'].update( error: 'something happened' )
|
@@ -110,8 +136,9 @@ describe Arborist::Client do
|
|
110
136
|
|
111
137
|
|
112
138
|
it "can update the properties of managed nodes", :no_ci do
|
113
|
-
client.update( duir: { ping: {rtt: 24} } )
|
139
|
+
res = client.update( duir: { ping: {rtt: 24} } )
|
114
140
|
|
141
|
+
expect( res ).to be_truthy
|
115
142
|
expect( manager.nodes['duir'].properties ).to include( 'ping' )
|
116
143
|
expect( manager.nodes['duir'].properties['ping'] ).to include( 'rtt' )
|
117
144
|
expect( manager.nodes['duir'].properties['ping']['rtt'] ).to eq( 24 )
|
@@ -190,6 +217,66 @@ describe Arborist::Client do
|
|
190
217
|
expect( sub.event_type ).to eq( nil )
|
191
218
|
end
|
192
219
|
|
220
|
+
|
221
|
+
it "can unsubscribe from events using a subscription ID" do
|
222
|
+
sub_id = client.subscribe
|
223
|
+
res = client.unsubscribe( sub_id )
|
224
|
+
expect( res ).to be_truthy
|
225
|
+
expect( manager.subscriptions ).to_not include( sub_id )
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
it "returns nil without error when unsubscribing to a non-existant subscription" do
|
230
|
+
res = client.unsubscribe( 'a_subid' )
|
231
|
+
expect( res ).to be_nil
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
it "can prune nodes from the tree" do
|
236
|
+
res = client.prune( 'sidonie-ssh' )
|
237
|
+
|
238
|
+
expect( res ).to eq( true )
|
239
|
+
expect( manager.nodes ).to_not include( 'sidonie-ssh' )
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
it "returns nil without error when pruning a node that doesn't exist" do
|
244
|
+
res = client.prune( 'carrigor' )
|
245
|
+
expect( res ).to be_nil
|
246
|
+
end
|
247
|
+
|
248
|
+
|
249
|
+
it "can graft new nodes onto the tree" do
|
250
|
+
res = client.graft( 'breakfast-burrito', type: 'host' )
|
251
|
+
expect( res ).to eq( 'breakfast-burrito' )
|
252
|
+
expect( manager.nodes ).to include( 'breakfast-burrito' )
|
253
|
+
expect( manager.nodes['breakfast-burrito'] ).to be_a( Arborist::Node::Host )
|
254
|
+
expect( manager.nodes['breakfast-burrito'].parent ).to eq( '_' )
|
255
|
+
end
|
256
|
+
|
257
|
+
|
258
|
+
it "can graft nodes with attributes onto the tree" do
|
259
|
+
res = client.graft( 'breakfast-burrito',
|
260
|
+
type: 'service',
|
261
|
+
parent: 'duir',
|
262
|
+
port: 9999,
|
263
|
+
tags: ['yusss']
|
264
|
+
)
|
265
|
+
expect( res ).to eq( 'duir-breakfast-burrito' )
|
266
|
+
expect( manager.nodes ).to include( 'duir-breakfast-burrito' )
|
267
|
+
expect( manager.nodes['duir-breakfast-burrito'] ).to be_a( Arborist::Node::Service )
|
268
|
+
expect( manager.nodes['duir-breakfast-burrito'].parent ).to eq( 'duir' )
|
269
|
+
expect( manager.nodes['duir-breakfast-burrito'].port ).to eq( 9999 )
|
270
|
+
expect( manager.nodes['duir-breakfast-burrito'].tags ).to include( 'yusss' )
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
it "can modify operational attributes of a node" do
|
275
|
+
res = client.modify( "duir", tags: 'girlrobot' )
|
276
|
+
expect( res ).to be_truthy
|
277
|
+
expect( manager.nodes['duir'].tags ).to eq( ['girlrobot'] )
|
278
|
+
end
|
279
|
+
|
193
280
|
end
|
194
281
|
|
195
282
|
|
@@ -236,7 +323,7 @@ describe Arborist::Client do
|
|
236
323
|
expect( msg.first['version'] ).to eq( Arborist::Client::API_VERSION )
|
237
324
|
expect( msg.first['action'] ).to eq( 'fetch' )
|
238
325
|
|
239
|
-
expect( msg.last ).to eq( {} )
|
326
|
+
expect( msg.last ).to eq([ {}, {} ])
|
240
327
|
end
|
241
328
|
|
242
329
|
|
@@ -252,9 +339,10 @@ describe Arborist::Client do
|
|
252
339
|
expect( msg.first['version'] ).to eq( Arborist::Client::API_VERSION )
|
253
340
|
expect( msg.first['action'] ).to eq( 'fetch' )
|
254
341
|
|
255
|
-
|
256
|
-
expect(
|
257
|
-
expect(
|
342
|
+
body = msg.last
|
343
|
+
expect( body.first ).to be_a( Hash )
|
344
|
+
expect( body.first ).to include( 'type' )
|
345
|
+
expect( body.first['type'] ).to eq( 'host' )
|
258
346
|
end
|
259
347
|
|
260
348
|
|