arborist 0.0.1.pre20160128152542 → 0.0.1.pre20160606141735
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
- 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
|
|