siffer 0.0.4
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.
- data/LICENSE +20 -0
- data/README.rdoc +65 -0
- data/Rakefile +64 -0
- data/bin/siffer +71 -0
- data/doc/SIF ImplementationSpecification.pdf +0 -0
- data/doc/rdoc/classes/Siffer.html +374 -0
- data/doc/rdoc/classes/Siffer/Agent.html +296 -0
- data/doc/rdoc/classes/Siffer/Container.html +286 -0
- data/doc/rdoc/classes/Siffer/Messages.html +141 -0
- data/doc/rdoc/classes/Siffer/Messages/Ack.html +216 -0
- data/doc/rdoc/classes/Siffer/Messages/Acl.html +160 -0
- data/doc/rdoc/classes/Siffer/Messages/Error.html +248 -0
- data/doc/rdoc/classes/Siffer/Messages/Message.html +359 -0
- data/doc/rdoc/classes/Siffer/Messages/Message/Header.html +181 -0
- data/doc/rdoc/classes/Siffer/Messages/Register.html +257 -0
- data/doc/rdoc/classes/Siffer/Messages/RequestBody.html +300 -0
- data/doc/rdoc/classes/Siffer/Messages/Status.html +269 -0
- data/doc/rdoc/classes/Siffer/Messaging.html +331 -0
- data/doc/rdoc/classes/Siffer/Protocol.html +388 -0
- data/doc/rdoc/classes/Siffer/Protocol/NonPostRequest.html +111 -0
- data/doc/rdoc/classes/Siffer/Protocol/UnknownPath.html +111 -0
- data/doc/rdoc/classes/Siffer/Registration.html +391 -0
- data/doc/rdoc/classes/Siffer/Request.html +209 -0
- data/doc/rdoc/classes/Siffer/RequestLogger.html +211 -0
- data/doc/rdoc/classes/Siffer/Response.html +182 -0
- data/doc/rdoc/classes/Siffer/Server.html +242 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/LICENSE.html +129 -0
- data/doc/rdoc/files/README_rdoc.html +184 -0
- data/doc/rdoc/files/lib/agent_rb.html +101 -0
- data/doc/rdoc/files/lib/container_rb.html +108 -0
- data/doc/rdoc/files/lib/messages/ack_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/acl_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/error_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/message_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/register_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/request_body_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/status_rb.html +101 -0
- data/doc/rdoc/files/lib/messages_rb.html +114 -0
- data/doc/rdoc/files/lib/messaging_rb.html +101 -0
- data/doc/rdoc/files/lib/protocol_rb.html +101 -0
- data/doc/rdoc/files/lib/registration_rb.html +101 -0
- data/doc/rdoc/files/lib/request_logger_rb.html +101 -0
- data/doc/rdoc/files/lib/request_rb.html +101 -0
- data/doc/rdoc/files/lib/response_rb.html +101 -0
- data/doc/rdoc/files/lib/server_rb.html +101 -0
- data/doc/rdoc/files/lib/siffer_rb.html +115 -0
- data/doc/rdoc/fr_class_index.html +47 -0
- data/doc/rdoc/fr_file_index.html +46 -0
- data/doc/rdoc/fr_method_index.html +96 -0
- data/doc/rdoc/index.html +24 -0
- data/doc/rdoc/rdoc-style.css +208 -0
- data/lib/agent.rb +43 -0
- data/lib/container.rb +96 -0
- data/lib/messages.rb +7 -0
- data/lib/messages/ack.rb +43 -0
- data/lib/messages/acl.rb +25 -0
- data/lib/messages/error.rb +174 -0
- data/lib/messages/message.rb +71 -0
- data/lib/messages/register.rb +60 -0
- data/lib/messages/request_body.rb +66 -0
- data/lib/messages/status.rb +55 -0
- data/lib/messaging.rb +96 -0
- data/lib/protocol.rb +159 -0
- data/lib/registration.rb +87 -0
- data/lib/request.rb +25 -0
- data/lib/request_logger.rb +31 -0
- data/lib/response.rb +26 -0
- data/lib/server.rb +40 -0
- data/lib/siffer.rb +44 -0
- data/spec/agent_spec.rb +53 -0
- data/spec/cli_spec.rb +40 -0
- data/spec/container_spec.rb +103 -0
- data/spec/default_agent +6 -0
- data/spec/default_server +5 -0
- data/spec/message_specs/ack_spec.rb +28 -0
- data/spec/message_specs/error_spec.rb +24 -0
- data/spec/message_specs/header_spec.rb +25 -0
- data/spec/message_specs/message_spec.rb +57 -0
- data/spec/message_specs/register_spec.rb +86 -0
- data/spec/message_specs/request_body_spec.rb +58 -0
- data/spec/message_specs/status_spec.rb +25 -0
- data/spec/messaging_spec.rb +88 -0
- data/spec/protocol_spec.rb +49 -0
- data/spec/registration_spec.rb +33 -0
- data/spec/request_logger_spec.rb +15 -0
- data/spec/request_spec.rb +10 -0
- data/spec/response_spec.rb +24 -0
- data/spec/server_spec.rb +35 -0
- data/spec/spec_helper.rb +26 -0
- metadata +191 -0
data/lib/protocol.rb
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
# The Protocol module deals with the transport validation. Provides
|
|
3
|
+
# constants for HTTP statuses as well as acceptable paths for Siffer
|
|
4
|
+
# Servers and Agents.
|
|
5
|
+
module Protocol
|
|
6
|
+
|
|
7
|
+
include Siffer::Messages
|
|
8
|
+
include Siffer::Messaging
|
|
9
|
+
|
|
10
|
+
class UnknownPath < Exception; end #:nodoc:
|
|
11
|
+
class NonPostRequest < Exception; end #:nodoc:
|
|
12
|
+
|
|
13
|
+
# Checks the incoming request against the following protocol constraints:
|
|
14
|
+
# * Unknown PATH
|
|
15
|
+
# * Non-POST request
|
|
16
|
+
def request_failed_protocol?
|
|
17
|
+
begin
|
|
18
|
+
check_path_against_protocol
|
|
19
|
+
rescue UnknownPath
|
|
20
|
+
# TODO: Make a better Not Found response
|
|
21
|
+
@response = Response.new(HTTP_STATUS_CODES[404],
|
|
22
|
+
404,
|
|
23
|
+
{"Content-Type" => Siffer::Messaging::MIME_TYPES["htm"]})
|
|
24
|
+
rescue NonPostRequest
|
|
25
|
+
# TODO: Make a better Method Not Allowed response
|
|
26
|
+
@response = Response.new(HTTP_STATUS_CODES[405],
|
|
27
|
+
405,
|
|
28
|
+
{"Content-Type" => Siffer::Messaging::MIME_TYPES["htm"]})
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Validates the request object against the Acceptable Paths (Siffer spec)
|
|
33
|
+
# and that the request is a POST.
|
|
34
|
+
def check_path_against_protocol
|
|
35
|
+
unless ACCEPTABLE_PATHS.has_value? @request.path_info
|
|
36
|
+
raise UnknownPath
|
|
37
|
+
end
|
|
38
|
+
unless @request.post?
|
|
39
|
+
raise NonPostRequest
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns the URI of the component (Server or Agent)
|
|
44
|
+
def uri
|
|
45
|
+
URI.parse("http://#{host}:#{port}").to_s
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Provides a context for each request. Creates the @request, @response and
|
|
49
|
+
# @original objects to use throughout the call.
|
|
50
|
+
# Validates against Protocol as well as Messaging using #request_failed
|
|
51
|
+
# predicates respectively.
|
|
52
|
+
#
|
|
53
|
+
# Yields the block if provided to allow further processing.
|
|
54
|
+
#
|
|
55
|
+
#Finishes by calling #finish on the response object or returns the generic
|
|
56
|
+
# response message.
|
|
57
|
+
def with_each_request(env, &block)
|
|
58
|
+
@request = Request.new(env)
|
|
59
|
+
unless request_failed_protocol? or request_failed_messaging?
|
|
60
|
+
using_message_from @request do # possibly a concurrency issue here
|
|
61
|
+
yield if block_given?
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
@response.finish unless no_response_available
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Sets the @response to a Siffer::Messages::Ack message with the
|
|
68
|
+
# appropriate Error category and code. Optional description is allowed
|
|
69
|
+
# and placed in the ExtendedDesc node.
|
|
70
|
+
def error_response(category,code, desc = nil)
|
|
71
|
+
error = Error.new(category,code,desc)
|
|
72
|
+
ack = Ack.new(self.name, @request.original, :error => error)
|
|
73
|
+
@response = Response.new(ack)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Determines if there is a response instance created. If not
|
|
77
|
+
# it creates one with an Ack/Error describing not having
|
|
78
|
+
# anything to process.
|
|
79
|
+
def no_response_available
|
|
80
|
+
if @response.nil?
|
|
81
|
+
err = <<"ERR"
|
|
82
|
+
You are receiving this message because you failed to
|
|
83
|
+
provide enough information to respond to. This is likely due
|
|
84
|
+
to the message type missing (i.e. Register,Provide) or possibly
|
|
85
|
+
not enough information to process effectively. Please check the
|
|
86
|
+
message you are sending and resend after any corrections.
|
|
87
|
+
ERR
|
|
88
|
+
!error_response(12,1,err)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Paths that comply with the messaging protocol determined
|
|
93
|
+
# by the SIF Specification. These are Siffer specific and not
|
|
94
|
+
# spelled out in SIF Specification (rather implied). Each path
|
|
95
|
+
# will generate it's own predicate method (i.e. #ping?) that can
|
|
96
|
+
# be used to determine the requests path based on the content of the
|
|
97
|
+
# message or the path-info of the request.
|
|
98
|
+
ACCEPTABLE_PATHS = {
|
|
99
|
+
:root => "/",
|
|
100
|
+
:ping => "/ping",
|
|
101
|
+
:status => "/status",
|
|
102
|
+
:register => "/register"
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
ACCEPTABLE_PATHS.each do |name,path|
|
|
106
|
+
define_method("#{name.to_s}?") do
|
|
107
|
+
@request.message.type.downcase == name.to_s
|
|
108
|
+
# The difference in these lines is the difference between allowing
|
|
109
|
+
# any message to come through any PATH or forcing PATH and message
|
|
110
|
+
# to match. What is better?
|
|
111
|
+
# TODO: Decide on protocol validations !
|
|
112
|
+
#@request.path_info == path || req_body.type.downcase == name.to_s
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Every standard HTTP code mapped to the appropriate message.
|
|
117
|
+
# Stolen from Mongrel.
|
|
118
|
+
HTTP_STATUS_CODES = {
|
|
119
|
+
100 => 'Continue',
|
|
120
|
+
101 => 'Switching Protocols',
|
|
121
|
+
200 => 'OK',
|
|
122
|
+
201 => 'Created',
|
|
123
|
+
202 => 'Accepted',
|
|
124
|
+
203 => 'Non-Authoritative Information',
|
|
125
|
+
204 => 'No Content',
|
|
126
|
+
205 => 'Reset Content',
|
|
127
|
+
206 => 'Partial Content',
|
|
128
|
+
300 => 'Multiple Choices',
|
|
129
|
+
301 => 'Moved Permanently',
|
|
130
|
+
302 => 'Moved Temporarily',
|
|
131
|
+
303 => 'See Other',
|
|
132
|
+
304 => 'Not Modified',
|
|
133
|
+
305 => 'Use Proxy',
|
|
134
|
+
400 => 'Bad Request',
|
|
135
|
+
401 => 'Unauthorized',
|
|
136
|
+
402 => 'Payment Required',
|
|
137
|
+
403 => 'Forbidden',
|
|
138
|
+
404 => 'Not Found',
|
|
139
|
+
405 => 'Method Not Allowed',
|
|
140
|
+
406 => 'Not Acceptable',
|
|
141
|
+
407 => 'Proxy Authentication Required',
|
|
142
|
+
408 => 'Request Time-out',
|
|
143
|
+
409 => 'Conflict',
|
|
144
|
+
410 => 'Gone',
|
|
145
|
+
411 => 'Length Required',
|
|
146
|
+
412 => 'Precondition Failed',
|
|
147
|
+
413 => 'Request Entity Too Large',
|
|
148
|
+
414 => 'Request-URI Too Large',
|
|
149
|
+
415 => 'Unsupported Media Type',
|
|
150
|
+
500 => 'Internal Server Error',
|
|
151
|
+
501 => 'Not Implemented',
|
|
152
|
+
502 => 'Bad Gateway',
|
|
153
|
+
503 => 'Service Unavailable',
|
|
154
|
+
504 => 'Gateway Time-out',
|
|
155
|
+
505 => 'HTTP Version not supported'
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
end
|
|
159
|
+
end
|
data/lib/registration.rb
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
# The Registration module manages Register message types and processes
|
|
3
|
+
# registration requests.
|
|
4
|
+
module Registration
|
|
5
|
+
|
|
6
|
+
include Siffer::Messages
|
|
7
|
+
|
|
8
|
+
class AgentNotRegistered < Exception #:nodoc:
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# The request (message) is processed for registration requests.
|
|
12
|
+
def process_registration
|
|
13
|
+
begin
|
|
14
|
+
check_for_registration
|
|
15
|
+
register
|
|
16
|
+
rescue AgentNotRegistered
|
|
17
|
+
error_response(4,9)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Parses the request body with RequestBody to determine if the
|
|
22
|
+
# the request is a registration message. If it is or if the
|
|
23
|
+
# source is already registered it passes through, otherwise raises
|
|
24
|
+
# AgentNotRegistered exception.
|
|
25
|
+
def check_for_registration
|
|
26
|
+
unless register? or registered?(@request.message.source_id)
|
|
27
|
+
raise AgentNotRegistered
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Process the message for registration by validating:
|
|
32
|
+
# * source_id
|
|
33
|
+
# * permissions to register with ZIS
|
|
34
|
+
# * version compatibility
|
|
35
|
+
# * buffer size compatibility
|
|
36
|
+
# If all validations pass the registration is stored by the ZIS and
|
|
37
|
+
# the agent is added to the list of agents available to the zone.
|
|
38
|
+
def register
|
|
39
|
+
if register?
|
|
40
|
+
@registration = Register.parse(@request.body)
|
|
41
|
+
validate_source_id
|
|
42
|
+
validate_permission
|
|
43
|
+
validate_version
|
|
44
|
+
validate_max_buffer_size
|
|
45
|
+
# ignore the fact we haven't stored away any registration information !!!!!!
|
|
46
|
+
# ignore the fact we haven't even built a data model for objects and permissions for the acl !!!!!
|
|
47
|
+
ack = Ack.new(name, @request.original, :status => Status.success(Acl.new))
|
|
48
|
+
@response = Response.new(ack)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# We may not do anything here - will we pre-permit sources to register?
|
|
53
|
+
# We could possibly call the Central Admin to qualify the source there?
|
|
54
|
+
def validate_source_id
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# We need to check for permissions previously assigned for this
|
|
59
|
+
# agent (possibly from Central Admin).
|
|
60
|
+
def validate_permission
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Currently only validating that the registration version matches
|
|
64
|
+
# identically to the SIF version implemented by Siffer.
|
|
65
|
+
# TODO: This will need refinement to provide broader version support.
|
|
66
|
+
def validate_version
|
|
67
|
+
if @registration.version != Siffer.sif_version
|
|
68
|
+
error_response(5,4,"Unsupported version: #{@registration.version}")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Validates the registration buffer size is greater than the
|
|
73
|
+
# minimum buffer set by the ZIS.
|
|
74
|
+
def validate_max_buffer_size
|
|
75
|
+
if @registration.max_buffer < min_buffer
|
|
76
|
+
error_response(5,6)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns true if the agent is included in the list of Agents
|
|
81
|
+
# previously registered.
|
|
82
|
+
def registered?(agent)
|
|
83
|
+
agents.has_key? agent
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
end
|
data/lib/request.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
|
|
3
|
+
# Request represents each message received by the Server or Agent in Siffer.
|
|
4
|
+
class Request < Rack::Request
|
|
5
|
+
|
|
6
|
+
# Constructor will assure that #message is always populated with the body
|
|
7
|
+
# of the request for easy access throughout the call.
|
|
8
|
+
def initialize(env)
|
|
9
|
+
env["CONTENT_TYPE"] ||= Siffer::Messaging::MIME_TYPES["appxml"]
|
|
10
|
+
super(env)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Provides access to the request message in Siffer::Messages::Message
|
|
14
|
+
# format.
|
|
15
|
+
def message
|
|
16
|
+
if body.is_a?(StringIO) && body.pos == body.length
|
|
17
|
+
body.rewind
|
|
18
|
+
end
|
|
19
|
+
Siffer::Messages::RequestBody.parse(body)
|
|
20
|
+
end
|
|
21
|
+
alias :original :message
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
class RequestLogger
|
|
3
|
+
def initialize(app, log=nil)
|
|
4
|
+
@app = app
|
|
5
|
+
@log = log || STDERR
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def call(env)
|
|
9
|
+
@env = env
|
|
10
|
+
# Maybe there is a better way to pick the body of the input
|
|
11
|
+
# instead of reading it then stuffing it back in ??
|
|
12
|
+
@msg = env["rack.input"].read
|
|
13
|
+
log_request
|
|
14
|
+
env["rack.input"] = StringIO.new(@msg)
|
|
15
|
+
@app.call(env)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def log_request
|
|
19
|
+
@now = Time.now
|
|
20
|
+
message = Siffer::Messages::RequestBody.parse(@msg)
|
|
21
|
+
@log << %{%s request made by %s on %s at %s\n} %
|
|
22
|
+
[
|
|
23
|
+
message.type,
|
|
24
|
+
@env["REMOTE_USER"],
|
|
25
|
+
@now.strftime("%b/%d/%Y"),
|
|
26
|
+
@now.strftime("%H:%M:%S")
|
|
27
|
+
]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/response.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
|
|
3
|
+
class Response < Rack::Response
|
|
4
|
+
|
|
5
|
+
def initialize(body=[], status=200, header={}, &block)
|
|
6
|
+
header["Content-Type"] ||= Siffer::Messaging::MIME_TYPES["appxml"]
|
|
7
|
+
super(body,status,header,&block)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.from(url,data)
|
|
11
|
+
uri = URI.parse(url)
|
|
12
|
+
begin
|
|
13
|
+
response = Net::HTTP.start(uri.host,uri.port) { |http|
|
|
14
|
+
post = Net::HTTP::Post.new(uri.path, {})
|
|
15
|
+
post.body = (data.respond_to?("read")) ? data.read : data
|
|
16
|
+
post.content_type = Siffer::Messaging::MIME_TYPES["appxml"]
|
|
17
|
+
http.request(post)
|
|
18
|
+
}
|
|
19
|
+
Response.new(response.body,response.code.to_i,response.header.to_hash)
|
|
20
|
+
rescue Errno::ECONNREFUSED => e
|
|
21
|
+
Response.new(e.message, 500, {})
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
data/lib/server.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
|
|
3
|
+
# Zone Integration Server
|
|
4
|
+
# Facilitates communication between Agents. Acts as a central point
|
|
5
|
+
# where Agents can send their events/requests and receive the response
|
|
6
|
+
# from other Agents.
|
|
7
|
+
class Server
|
|
8
|
+
include Siffer::Protocol
|
|
9
|
+
include Siffer::Registration
|
|
10
|
+
|
|
11
|
+
attr_reader :name, :host, :port, :min_buffer, :agents
|
|
12
|
+
|
|
13
|
+
## options Parameter
|
|
14
|
+
# name = The name of the ZIS
|
|
15
|
+
# host = The host this instance is started on
|
|
16
|
+
# port = The port to connect to this ZIS
|
|
17
|
+
# admin = The administration site managing this ZIS
|
|
18
|
+
# min_buffer = The minimum buffer size this ZIS will facilitate
|
|
19
|
+
def initialize(options = {})
|
|
20
|
+
raise ArgumentError, "Administration URL required" unless options.include? "admin"
|
|
21
|
+
@name = options["name"] || "Default Server"
|
|
22
|
+
@host = options["host"] || "localhost"
|
|
23
|
+
@port = options["port"] || 8300
|
|
24
|
+
@min_buffer = options["min_buffer"] || 1024
|
|
25
|
+
@agents = {}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Process the request with all the SIF protocols
|
|
29
|
+
def call(env)
|
|
30
|
+
with_each_request(env) do
|
|
31
|
+
process_registration
|
|
32
|
+
# process_provision
|
|
33
|
+
# process_subscription
|
|
34
|
+
# process_event
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
data/lib/siffer.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'uuid'
|
|
3
|
+
require 'rack'
|
|
4
|
+
require 'builder'
|
|
5
|
+
require 'net/http'
|
|
6
|
+
require 'net/https'
|
|
7
|
+
require 'rexml/document'
|
|
8
|
+
require 'hpricot'
|
|
9
|
+
|
|
10
|
+
$: << File.expand_path(File.dirname(__FILE__))
|
|
11
|
+
|
|
12
|
+
module Siffer
|
|
13
|
+
|
|
14
|
+
VENDOR = "h3o(software)" unless defined?(Siffer::VENDOR)
|
|
15
|
+
VERSION = [0,0,4] unless defined?(Siffer::VERSION)
|
|
16
|
+
SIF_VERSION = [2,2,0] unless defined?(Siffer::SIF_VERSION)
|
|
17
|
+
SIF_XMLNS = "http://www.sifinfo.org/infrastructure/2.x" unless defined?(Siffer::SIF_XMLNS)
|
|
18
|
+
|
|
19
|
+
# The vendor of this SIF implementation (self describing for Agents)
|
|
20
|
+
def self.vendor() VENDOR end
|
|
21
|
+
|
|
22
|
+
# The version of the h3o(software) SIF implementation
|
|
23
|
+
def self.version() VERSION.join(".") end
|
|
24
|
+
|
|
25
|
+
# The version of SIF being implemented - based on the specification
|
|
26
|
+
def self.sif_version() SIF_VERSION.join(".") end
|
|
27
|
+
|
|
28
|
+
# The SIF XML namespace to be used across this implementation
|
|
29
|
+
def self.sif_xmlns() SIF_XMLNS end
|
|
30
|
+
|
|
31
|
+
# The root directory that the SIF implementation is running from
|
|
32
|
+
def self.root() @root ||= Dir.pwd end
|
|
33
|
+
def self.root=(value) @root = value end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
Siffer.autoload :Messages, "messages"
|
|
38
|
+
Siffer.autoload :Protocol, "protocol"
|
|
39
|
+
Siffer.autoload :Messaging, "messaging"
|
|
40
|
+
Siffer.autoload :Registration, "registration"
|
|
41
|
+
|
|
42
|
+
%w(server agent response request container request_logger).each do |component|
|
|
43
|
+
require component
|
|
44
|
+
end
|
data/spec/agent_spec.rb
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
|
2
|
+
require 'webrick'
|
|
3
|
+
|
|
4
|
+
describe Siffer::Agent do
|
|
5
|
+
it "should instantiate with default host, port, name" do
|
|
6
|
+
agent = Siffer::Agent.new("servers" => 'none', "admin" => 'none')
|
|
7
|
+
agent.host.should == "localhost"
|
|
8
|
+
agent.port.should == 8300
|
|
9
|
+
agent.name.should == "Default Agent"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should allow defaults to be overriden" do
|
|
13
|
+
agent = Siffer::Agent.new("admin" => 'none',
|
|
14
|
+
"servers" => 'none',
|
|
15
|
+
"name" => "name",
|
|
16
|
+
"host" => "test",
|
|
17
|
+
"port" => 222)
|
|
18
|
+
agent.host.should == "test"
|
|
19
|
+
agent.name.should == "name"
|
|
20
|
+
agent.port.should == 222
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should require a server url to register with" do
|
|
24
|
+
lambda {
|
|
25
|
+
agent = Siffer::Agent.new
|
|
26
|
+
}.should raise_error("Server URL(s) required")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should require an admin URL" do
|
|
30
|
+
lambda {
|
|
31
|
+
agent = Siffer::Agent.new("servers" => "none")
|
|
32
|
+
}.should raise_error("Administration URL required")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should respond to uri" do
|
|
36
|
+
agent = Siffer::Agent.new("admin" => 'none', "servers" => 'none')
|
|
37
|
+
agent.uri.should == "http://localhost:8300"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should register with server(s) on wake-up" do
|
|
41
|
+
with_fake_server(Siffer::Server.new("admin" => "none")) do |url|
|
|
42
|
+
agent = Siffer::Agent.new("admin" => 'none', "servers" => url)
|
|
43
|
+
agent.wake_up
|
|
44
|
+
agent.should be_registered
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should be unregistered by default" do
|
|
49
|
+
agent = Siffer::Agent.new("admin" => 'none', "servers" => 'none')
|
|
50
|
+
agent.should_not be_registered
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|