shift-nanite 0.4.1.2

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.
Files changed (63) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +430 -0
  3. data/Rakefile +76 -0
  4. data/TODO +24 -0
  5. data/bin/nanite-admin +65 -0
  6. data/bin/nanite-agent +79 -0
  7. data/bin/nanite-mapper +50 -0
  8. data/lib/nanite.rb +74 -0
  9. data/lib/nanite/actor.rb +71 -0
  10. data/lib/nanite/actor_registry.rb +26 -0
  11. data/lib/nanite/admin.rb +138 -0
  12. data/lib/nanite/agent.rb +264 -0
  13. data/lib/nanite/amqp.rb +58 -0
  14. data/lib/nanite/cluster.rb +250 -0
  15. data/lib/nanite/config.rb +112 -0
  16. data/lib/nanite/console.rb +39 -0
  17. data/lib/nanite/daemonize.rb +13 -0
  18. data/lib/nanite/identity.rb +16 -0
  19. data/lib/nanite/job.rb +104 -0
  20. data/lib/nanite/local_state.rb +38 -0
  21. data/lib/nanite/log.rb +66 -0
  22. data/lib/nanite/log/formatter.rb +39 -0
  23. data/lib/nanite/mapper.rb +309 -0
  24. data/lib/nanite/mapper_proxy.rb +67 -0
  25. data/lib/nanite/nanite_dispatcher.rb +92 -0
  26. data/lib/nanite/packets.rb +365 -0
  27. data/lib/nanite/pid_file.rb +52 -0
  28. data/lib/nanite/reaper.rb +39 -0
  29. data/lib/nanite/security/cached_certificate_store_proxy.rb +24 -0
  30. data/lib/nanite/security/certificate.rb +55 -0
  31. data/lib/nanite/security/certificate_cache.rb +66 -0
  32. data/lib/nanite/security/distinguished_name.rb +34 -0
  33. data/lib/nanite/security/encrypted_document.rb +46 -0
  34. data/lib/nanite/security/rsa_key_pair.rb +53 -0
  35. data/lib/nanite/security/secure_serializer.rb +68 -0
  36. data/lib/nanite/security/signature.rb +46 -0
  37. data/lib/nanite/security/static_certificate_store.rb +35 -0
  38. data/lib/nanite/security_provider.rb +47 -0
  39. data/lib/nanite/serializer.rb +52 -0
  40. data/lib/nanite/state.rb +168 -0
  41. data/lib/nanite/streaming.rb +125 -0
  42. data/lib/nanite/util.rb +58 -0
  43. data/spec/actor_registry_spec.rb +60 -0
  44. data/spec/actor_spec.rb +77 -0
  45. data/spec/agent_spec.rb +240 -0
  46. data/spec/cached_certificate_store_proxy_spec.rb +34 -0
  47. data/spec/certificate_cache_spec.rb +49 -0
  48. data/spec/certificate_spec.rb +27 -0
  49. data/spec/cluster_spec.rb +622 -0
  50. data/spec/distinguished_name_spec.rb +24 -0
  51. data/spec/encrypted_document_spec.rb +21 -0
  52. data/spec/job_spec.rb +251 -0
  53. data/spec/local_state_spec.rb +130 -0
  54. data/spec/nanite_dispatcher_spec.rb +136 -0
  55. data/spec/packet_spec.rb +220 -0
  56. data/spec/rsa_key_pair_spec.rb +33 -0
  57. data/spec/secure_serializer_spec.rb +41 -0
  58. data/spec/serializer_spec.rb +107 -0
  59. data/spec/signature_spec.rb +30 -0
  60. data/spec/spec_helper.rb +33 -0
  61. data/spec/static_certificate_store_spec.rb +30 -0
  62. data/spec/util_spec.rb +63 -0
  63. metadata +129 -0
@@ -0,0 +1,220 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ class TestPacket < Nanite::Packet
4
+ @@cls_attr = "ignore"
5
+ def initialize(attr1)
6
+ @attr1 = attr1
7
+ end
8
+ end
9
+
10
+ describe "Packet: Base class" do
11
+
12
+ before(:all) do
13
+ end
14
+
15
+ it "should be an abstract class" do
16
+ lambda { Nanite::Packet.new }.should raise_error(NotImplementedError, "Nanite::Packet is an abstract class.")
17
+ end
18
+
19
+ it "should know how to dump itself to JSON" do
20
+ packet = TestPacket.new(1)
21
+ packet.should respond_to(:to_json)
22
+ end
23
+
24
+ it "should dump the class name in 'json_class' JSON key" do
25
+ packet = TestPacket.new(42)
26
+ packet.to_json().should =~ /\"json_class\":\"TestPacket\"/
27
+ end
28
+
29
+ it "should dump instance variables in 'data' JSON key" do
30
+ packet = TestPacket.new(188)
31
+ packet.to_json().should =~ /\"data\":\{\"attr1\":188\}/
32
+ end
33
+
34
+ it "should not dump class variables" do
35
+ packet = TestPacket.new(382)
36
+ packet.to_json().should_not =~ /cls_attr/
37
+ end
38
+
39
+ it "should store instance variables in 'data' JSON key as JSON object" do
40
+ packet = TestPacket.new(382)
41
+ packet.to_json().should =~ /\"data\":\{[\w:"]+\}/
42
+ end
43
+
44
+ it "should remove '@' from instance variables" do
45
+ packet = TestPacket.new(2)
46
+ packet.to_json().should_not =~ /@attr1/
47
+ packet.to_json().should =~ /attr1/
48
+ end
49
+ end
50
+
51
+
52
+ describe "Packet: FileStart" do
53
+ it "should dump/load as JSON objects" do
54
+ packet = Nanite::FileStart.new('foo.txt', 'somewhere/foo.txt', '0xdeadbeef')
55
+ packet2 = JSON.parse(packet.to_json)
56
+ packet.filename.should == packet2.filename
57
+ packet.dest.should == packet2.dest
58
+ packet.token.should == packet2.token
59
+ end
60
+
61
+ it "should dump/load as Marshalled ruby objects" do
62
+ packet = Nanite::FileStart.new('foo.txt', 'somewhere/foo.txt', '0xdeadbeef')
63
+ packet2 = Marshal.load(Marshal.dump(packet))
64
+ packet.filename.should == packet2.filename
65
+ packet.dest.should == packet2.dest
66
+ packet.token.should == packet2.token
67
+ end
68
+ end
69
+
70
+
71
+ describe "Packet: FileEnd" do
72
+ it "should dump/load as JSON objects" do
73
+ packet = Nanite::FileEnd.new('0xdeadbeef', 'metadata')
74
+ packet2 = JSON.parse(packet.to_json)
75
+ packet.meta.should == packet2.meta
76
+ packet.token.should == packet2.token
77
+ end
78
+
79
+ it "should dump/load as Marshalled ruby objects" do
80
+ packet = Nanite::FileEnd.new('0xdeadbeef', 'metadata')
81
+ packet2 = Marshal.load(Marshal.dump(packet))
82
+ packet.meta.should == packet2.meta
83
+ packet.token.should == packet2.token
84
+ end
85
+ end
86
+
87
+
88
+ describe "Packet: FileChunk" do
89
+ it "should dump/load as JSON objects" do
90
+ packet = Nanite::FileChunk.new('chunk','0xdeadbeef')
91
+ packet2 = JSON.parse(packet.to_json)
92
+ packet.chunk.should == packet2.chunk
93
+ packet.token.should == packet2.token
94
+ end
95
+
96
+ it "should dump/load as Marshalled ruby objects" do
97
+ packet = Nanite::FileChunk.new('chunk','0xdeadbeef')
98
+ packet2 = Marshal.load(Marshal.dump(packet))
99
+ packet.chunk.should == packet2.chunk
100
+ packet.token.should == packet2.token
101
+ end
102
+ end
103
+
104
+
105
+ describe "Packet: Request" do
106
+ it "should dump/load as JSON objects" do
107
+ packet = Nanite::Request.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef', :reply_to => 'reply_to')
108
+ packet2 = JSON.parse(packet.to_json)
109
+ packet.type.should == packet2.type
110
+ packet.payload.should == packet2.payload
111
+ packet.from.should == packet2.from
112
+ packet.token.should == packet2.token
113
+ packet.reply_to.should == packet2.reply_to
114
+ end
115
+
116
+ it "should dump/load as Marshalled ruby objects" do
117
+ packet = Nanite::Request.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef', :reply_to => 'reply_to')
118
+ packet2 = Marshal.load(Marshal.dump(packet))
119
+ packet.type.should == packet2.type
120
+ packet.payload.should == packet2.payload
121
+ packet.from.should == packet2.from
122
+ packet.token.should == packet2.token
123
+ packet.reply_to.should == packet2.reply_to
124
+ end
125
+ end
126
+
127
+
128
+ describe "Packet: Result" do
129
+ it "should dump/load as JSON objects" do
130
+ packet = Nanite::Result.new('0xdeadbeef', 'to', 'results', 'from')
131
+ packet2 = JSON.parse(packet.to_json)
132
+ packet.token.should == packet2.token
133
+ packet.to.should == packet2.to
134
+ packet.results.should == packet2.results
135
+ packet.from.should == packet2.from
136
+ end
137
+
138
+ it "should dump/load as Marshalled ruby objects" do
139
+ packet = Nanite::Result.new('0xdeadbeef', 'to', 'results', 'from')
140
+ packet2 = Marshal.load(Marshal.dump(packet))
141
+ packet.token.should == packet2.token
142
+ packet.to.should == packet2.to
143
+ packet.results.should == packet2.results
144
+ packet.from.should == packet2.from
145
+ end
146
+ end
147
+
148
+
149
+ describe "Packet: IntermediateMessage" do
150
+ it "should dump/load as JSON objects" do
151
+ packet = Nanite::IntermediateMessage.new('0xdeadbeef', 'to', 'from', 'messagekey', 'message')
152
+ packet2 = JSON.parse(packet.to_json)
153
+ packet.token.should == packet2.token
154
+ packet.to.should == packet2.to
155
+ packet.from.should == packet2.from
156
+ packet.messagekey.should == packet2.messagekey
157
+ packet.message.should == packet2.message
158
+ end
159
+
160
+ it "should dump/load as Marshalled ruby objects" do
161
+ packet = Nanite::IntermediateMessage.new('0xdeadbeef', 'to', 'from', 'messagekey', 'message')
162
+ packet2 = Marshal.load(Marshal.dump(packet))
163
+ packet.token.should == packet2.token
164
+ packet.to.should == packet2.to
165
+ packet.from.should == packet2.from
166
+ packet.messagekey.should == packet2.messagekey
167
+ packet.message.should == packet2.message
168
+ end
169
+ end
170
+
171
+
172
+ describe "Packet: Register" do
173
+ it "should dump/load as JSON objects" do
174
+ packet = Nanite::Register.new('0xdeadbeef', ['/foo/bar', '/nik/qux'], 0.8, ['foo'])
175
+ packet2 = JSON.parse(packet.to_json)
176
+ packet.identity.should == packet2.identity
177
+ packet.services.should == packet2.services
178
+ packet.status.should == packet2.status
179
+ end
180
+
181
+ it "should dump/load as Marshalled ruby objects" do
182
+ packet = Nanite::Register.new('0xdeadbeef', ['/foo/bar', '/nik/qux'], 0.8, ['foo'])
183
+ packet2 = Marshal.load(Marshal.dump(packet))
184
+ packet.identity.should == packet2.identity
185
+ packet.services.should == packet2.services
186
+ packet.status.should == packet2.status
187
+ end
188
+ end
189
+
190
+
191
+ describe "Packet: UnRegister" do
192
+ it "should dump/load as JSON objects" do
193
+ packet = Nanite::UnRegister.new('0xdeadbeef')
194
+ packet2 = JSON.parse(packet.to_json)
195
+ packet.identity.should == packet2.identity
196
+ end
197
+
198
+ it "should dump/load as Marshalled ruby objects" do
199
+ packet = Nanite::UnRegister.new('0xdeadbeef')
200
+ packet2 = Marshal.load(Marshal.dump(packet))
201
+ packet.identity.should == packet2.identity
202
+ end
203
+ end
204
+
205
+
206
+ describe "Packet: Ping" do
207
+ it "should dump/load as JSON objects" do
208
+ packet = Nanite::Ping.new('0xdeadbeef', 0.8)
209
+ packet2 = JSON.parse(packet.to_json)
210
+ packet.identity.should == packet2.identity
211
+ packet.status.should == packet2.status
212
+ end
213
+
214
+ it "should dump/load as Marshalled ruby objects" do
215
+ packet = Nanite::Ping.new('0xdeadbeef', 0.8)
216
+ packet2 = Marshal.load(Marshal.dump(packet))
217
+ packet.identity.should == packet2.identity
218
+ packet.status.should == packet2.status
219
+ end
220
+ end
@@ -0,0 +1,33 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Nanite::RsaKeyPair do
4
+
5
+ before(:all) do
6
+ @pair = Nanite::RsaKeyPair.new
7
+ end
8
+
9
+ it 'should create a private and a public keys' do
10
+ @pair.has_private?.should be_true
11
+ end
12
+
13
+ it 'should strip out private key in to_public' do
14
+ @pair.to_public.has_private?.should be_false
15
+ end
16
+
17
+ it 'should save' do
18
+ filename = File.join(File.dirname(__FILE__), "key.pem")
19
+ @pair.save(filename)
20
+ File.size(filename).should be > 0
21
+ File.delete(filename)
22
+ end
23
+
24
+ it 'should load' do
25
+ filename = File.join(File.dirname(__FILE__), "key.pem")
26
+ @pair.save(filename)
27
+ key = Nanite::RsaKeyPair.load(filename)
28
+ File.delete(filename)
29
+ key.should_not be_nil
30
+ key.data.should == @pair.data
31
+ end
32
+
33
+ end
@@ -0,0 +1,41 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ module Nanite
4
+
5
+ # Add the ability to compare pings for test purposes
6
+ class Ping
7
+ def ==(other)
8
+ @status == other.status && @identity == other.identity
9
+ end
10
+ end
11
+
12
+ end
13
+
14
+ describe Nanite::SecureSerializer do
15
+
16
+ include SpecHelpers
17
+
18
+ before(:all) do
19
+ @certificate, @key = issue_cert
20
+ @store = Nanite::StaticCertificateStore.new(@certificate, @certificate)
21
+ @identity = "id"
22
+ @data = Nanite::Ping.new("Test", 0.5)
23
+ end
24
+
25
+ it 'should raise when not initialized' do
26
+ lambda { Nanite::SecureSerializer.dump(@data) }.should raise_error
27
+ end
28
+
29
+ it 'should deserialize signed data' do
30
+ Nanite::SecureSerializer.init(@identity, @certificate, @key, @store, false)
31
+ data = Nanite::SecureSerializer.dump(@data)
32
+ Nanite::SecureSerializer.load(data).should == @data
33
+ end
34
+
35
+ it 'should deserialize encrypted data' do
36
+ Nanite::SecureSerializer.init(@identity, @certificate, @key, @store, true)
37
+ data = Nanite::SecureSerializer.dump(@data)
38
+ Nanite::SecureSerializer.load(data).should == @data
39
+ end
40
+
41
+ end
@@ -0,0 +1,107 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Nanite::Serializer do
4
+
5
+ describe "Format" do
6
+
7
+ it "supports JSON format" do
8
+ [ :json, "json" ].each do |format|
9
+ serializer = Nanite::Serializer.new(format)
10
+ serializer.instance_eval { @serializers.first }.should == JSON
11
+ end
12
+ end
13
+
14
+ it "supports Marshal format" do
15
+ [ :marshal, "marshal" ].each do |format|
16
+ serializer = Nanite::Serializer.new(format)
17
+ serializer.instance_eval { @serializers.first }.should == Marshal
18
+ end
19
+ end
20
+
21
+ it "supports YAML format" do
22
+ [ :yaml, "yaml" ].each do |format|
23
+ serializer = Nanite::Serializer.new(format)
24
+ serializer.instance_eval { @serializers.first }.should == YAML
25
+ end
26
+ end
27
+
28
+ it "should default to Marshal format if not specified" do
29
+ serializer = Nanite::Serializer.new
30
+ serializer.instance_eval { @serializers.first }.should == Marshal
31
+ serializer = Nanite::Serializer.new(nil)
32
+ serializer.instance_eval { @serializers.first }.should == Marshal
33
+ end
34
+
35
+ end # Format
36
+
37
+ describe "Serialization of Packet" do
38
+
39
+ it "should cascade through available serializers" do
40
+ serializer = Nanite::Serializer.new
41
+ serializer.should_receive(:cascade_serializers).with(:dump, "hello")
42
+ serializer.dump("hello")
43
+ end
44
+
45
+ it "should try all three supported formats (JSON, Marshal, YAML)" do
46
+ JSON.should_receive(:dump).with("hello").and_raise(StandardError)
47
+ Marshal.should_receive(:dump).with("hello").and_raise(StandardError)
48
+ YAML.should_receive(:dump).with("hello").and_raise(StandardError)
49
+
50
+ lambda { Nanite::Serializer.new.dump("hello") }.should raise_error(Nanite::Serializer::SerializationError)
51
+ end
52
+
53
+ it "should raise SerializationError if packet could not be serialized" do
54
+ JSON.should_receive(:dump).with("hello").and_raise(StandardError)
55
+ Marshal.should_receive(:dump).with("hello").and_raise(StandardError)
56
+ YAML.should_receive(:dump).with("hello").and_raise(StandardError)
57
+
58
+ serializer = Nanite::Serializer.new
59
+ lambda { serializer.dump("hello") }.should raise_error(Nanite::Serializer::SerializationError)
60
+ end
61
+
62
+ it "should return serialized packet" do
63
+ serialized_packet = mock("Packet")
64
+ Marshal.should_receive(:dump).with("hello").and_return(serialized_packet)
65
+
66
+ serializer = Nanite::Serializer.new(:marshal)
67
+ serializer.dump("hello").should == serialized_packet
68
+ end
69
+
70
+ end # Serialization of Packet
71
+
72
+ describe "De-Serialization of Packet" do
73
+
74
+ it "should cascade through available serializers" do
75
+ serializer = Nanite::Serializer.new
76
+ serializer.should_receive(:cascade_serializers).with(:load, "olleh")
77
+ serializer.load("olleh")
78
+ end
79
+
80
+ it "should try all three supported formats (JSON, Marshal, YAML)" do
81
+ JSON.should_receive(:load).with("olleh").and_raise(StandardError)
82
+ Marshal.should_receive(:load).with("olleh").and_raise(StandardError)
83
+ YAML.should_receive(:load).with("olleh").and_raise(StandardError)
84
+
85
+ lambda { Nanite::Serializer.new.load("olleh") }.should raise_error(Nanite::Serializer::SerializationError)
86
+ end
87
+
88
+ it "should raise SerializationError if packet could not be de-serialized" do
89
+ JSON.should_receive(:load).with("olleh").and_raise(StandardError)
90
+ Marshal.should_receive(:load).with("olleh").and_raise(StandardError)
91
+ YAML.should_receive(:load).with("olleh").and_raise(StandardError)
92
+
93
+ serializer = Nanite::Serializer.new
94
+ lambda { serializer.load("olleh") }.should raise_error(Nanite::Serializer::SerializationError)
95
+ end
96
+
97
+ it "should return de-serialized packet" do
98
+ deserialized_packet = mock("Packet")
99
+ Marshal.should_receive(:load).with("olleh").and_return(deserialized_packet)
100
+
101
+ serializer = Nanite::Serializer.new(:marshal)
102
+ serializer.load("olleh").should == deserialized_packet
103
+ end
104
+
105
+ end # De-Serialization of Packet
106
+
107
+ end # Nanite::Serializer
@@ -0,0 +1,30 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Nanite::Signature do
4
+
5
+ include SpecHelpers
6
+
7
+ before(:all) do
8
+ @test_data = "Test Data"
9
+ @cert, @key = issue_cert
10
+ @sig = Nanite::Signature.new(@test_data, @cert, @key)
11
+ end
12
+
13
+ it 'should create signed data' do
14
+ @sig.to_s.should_not be_empty
15
+ end
16
+
17
+ it 'should verify the signature' do
18
+ cert2, key2 = issue_cert
19
+
20
+ @sig.should be_a_match(@cert)
21
+ @sig.should_not be_a_match(cert2)
22
+ end
23
+
24
+ it 'should load from serialized signature' do
25
+ sig2 = Nanite::Signature.from_data(@sig.data)
26
+ sig2.should_not be_nil
27
+ sig2.should be_a_match(@cert)
28
+ end
29
+
30
+ end
@@ -0,0 +1,33 @@
1
+ $TESTING=true
2
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'rubygems'
5
+ require 'spec'
6
+ require 'nanite'
7
+
8
+ module SpecHelpers
9
+
10
+ # Initialize logger so it writes to file instead of STDOUT
11
+ Nanite::Log.init('test', File.join(File.dirname(__FILE__)))
12
+
13
+ # Create test certificate
14
+ def issue_cert
15
+ test_dn = { 'C' => 'US',
16
+ 'ST' => 'California',
17
+ 'L' => 'Santa Barbara',
18
+ 'O' => 'Nanite',
19
+ 'OU' => 'Certification Services',
20
+ 'CN' => 'Nanite test' }
21
+ dn = Nanite::DistinguishedName.new(test_dn)
22
+ key = Nanite::RsaKeyPair.new
23
+ [ Nanite::Certificate.new(key, dn, dn), key ]
24
+ end
25
+
26
+ def run_in_em(stop_event_loop = true)
27
+ EM.run do
28
+ yield
29
+ EM.stop_event_loop if stop_event_loop
30
+ end
31
+ end
32
+
33
+ end