rightscale-nanite 0.4.1 → 0.4.1.1

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 (56) hide show
  1. data/lib/nanite.rb +71 -0
  2. data/lib/nanite/actor.rb +60 -0
  3. data/lib/nanite/actor_registry.rb +24 -0
  4. data/lib/nanite/admin.rb +153 -0
  5. data/lib/nanite/agent.rb +250 -0
  6. data/lib/nanite/amqp.rb +47 -0
  7. data/lib/nanite/cluster.rb +203 -0
  8. data/lib/nanite/config.rb +102 -0
  9. data/lib/nanite/console.rb +39 -0
  10. data/lib/nanite/daemonize.rb +13 -0
  11. data/lib/nanite/dispatcher.rb +90 -0
  12. data/lib/nanite/identity.rb +16 -0
  13. data/lib/nanite/job.rb +104 -0
  14. data/lib/nanite/local_state.rb +34 -0
  15. data/lib/nanite/log.rb +64 -0
  16. data/lib/nanite/log/formatter.rb +39 -0
  17. data/lib/nanite/mapper.rb +277 -0
  18. data/lib/nanite/mapper_proxy.rb +56 -0
  19. data/lib/nanite/packets.rb +231 -0
  20. data/lib/nanite/pid_file.rb +52 -0
  21. data/lib/nanite/reaper.rb +38 -0
  22. data/lib/nanite/security/cached_certificate_store_proxy.rb +24 -0
  23. data/lib/nanite/security/certificate.rb +55 -0
  24. data/lib/nanite/security/certificate_cache.rb +66 -0
  25. data/lib/nanite/security/distinguished_name.rb +34 -0
  26. data/lib/nanite/security/encrypted_document.rb +46 -0
  27. data/lib/nanite/security/rsa_key_pair.rb +53 -0
  28. data/lib/nanite/security/secure_serializer.rb +67 -0
  29. data/lib/nanite/security/signature.rb +40 -0
  30. data/lib/nanite/security/static_certificate_store.rb +35 -0
  31. data/lib/nanite/security_provider.rb +47 -0
  32. data/lib/nanite/serializer.rb +52 -0
  33. data/lib/nanite/state.rb +164 -0
  34. data/lib/nanite/streaming.rb +125 -0
  35. data/lib/nanite/util.rb +51 -0
  36. data/spec/actor_registry_spec.rb +62 -0
  37. data/spec/actor_spec.rb +59 -0
  38. data/spec/agent_spec.rb +235 -0
  39. data/spec/cached_certificate_store_proxy_spec.rb +34 -0
  40. data/spec/certificate_cache_spec.rb +49 -0
  41. data/spec/certificate_spec.rb +27 -0
  42. data/spec/cluster_spec.rb +300 -0
  43. data/spec/dispatcher_spec.rb +136 -0
  44. data/spec/distinguished_name_spec.rb +24 -0
  45. data/spec/encrypted_document_spec.rb +21 -0
  46. data/spec/job_spec.rb +219 -0
  47. data/spec/local_state_spec.rb +112 -0
  48. data/spec/packet_spec.rb +218 -0
  49. data/spec/rsa_key_pair_spec.rb +33 -0
  50. data/spec/secure_serializer_spec.rb +41 -0
  51. data/spec/serializer_spec.rb +107 -0
  52. data/spec/signature_spec.rb +30 -0
  53. data/spec/spec_helper.rb +23 -0
  54. data/spec/static_certificate_store_spec.rb +30 -0
  55. data/spec/util_spec.rb +63 -0
  56. metadata +62 -1
@@ -0,0 +1,218 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe "Packet: Base class" do
4
+ before(:all) do
5
+ class TestPacket < Nanite::Packet
6
+ @@cls_attr = "ignore"
7
+ def initialize(attr1)
8
+ @attr1 = attr1
9
+ end
10
+ end
11
+ end
12
+
13
+ it "should be an abstract class" do
14
+ lambda { Nanite::Packet.new }.should raise_error(NotImplementedError, "Nanite::Packet is an abstract class.")
15
+ end
16
+
17
+ it "should know how to dump itself to JSON" do
18
+ packet = TestPacket.new(1)
19
+ packet.should respond_to(:to_json)
20
+ end
21
+
22
+ it "should dump the class name in 'json_class' JSON key" do
23
+ packet = TestPacket.new(42)
24
+ packet.to_json().should =~ /\"json_class\":\"TestPacket\"/
25
+ end
26
+
27
+ it "should dump instance variables in 'data' JSON key" do
28
+ packet = TestPacket.new(188)
29
+ packet.to_json().should =~ /\"data\":\{\"attr1\":188\}/
30
+ end
31
+
32
+ it "should not dump class variables" do
33
+ packet = TestPacket.new(382)
34
+ packet.to_json().should_not =~ /cls_attr/
35
+ end
36
+
37
+ it "should store instance variables in 'data' JSON key as JSON object" do
38
+ packet = TestPacket.new(382)
39
+ packet.to_json().should =~ /\"data\":\{[\w:"]+\}/
40
+ end
41
+
42
+ it "should remove '@' from instance variables" do
43
+ packet = TestPacket.new(2)
44
+ packet.to_json().should_not =~ /@attr1/
45
+ packet.to_json().should =~ /attr1/
46
+ end
47
+ end
48
+
49
+
50
+ describe "Packet: FileStart" do
51
+ it "should dump/load as JSON objects" do
52
+ packet = Nanite::FileStart.new('foo.txt', 'somewhere/foo.txt', '0xdeadbeef')
53
+ packet2 = JSON.parse(packet.to_json)
54
+ packet.filename.should == packet2.filename
55
+ packet.dest.should == packet2.dest
56
+ packet.token.should == packet2.token
57
+ end
58
+
59
+ it "should dump/load as Marshalled ruby objects" do
60
+ packet = Nanite::FileStart.new('foo.txt', 'somewhere/foo.txt', '0xdeadbeef')
61
+ packet2 = Marshal.load(Marshal.dump(packet))
62
+ packet.filename.should == packet2.filename
63
+ packet.dest.should == packet2.dest
64
+ packet.token.should == packet2.token
65
+ end
66
+ end
67
+
68
+
69
+ describe "Packet: FileEnd" do
70
+ it "should dump/load as JSON objects" do
71
+ packet = Nanite::FileEnd.new('0xdeadbeef', 'metadata')
72
+ packet2 = JSON.parse(packet.to_json)
73
+ packet.meta.should == packet2.meta
74
+ packet.token.should == packet2.token
75
+ end
76
+
77
+ it "should dump/load as Marshalled ruby objects" do
78
+ packet = Nanite::FileEnd.new('0xdeadbeef', 'metadata')
79
+ packet2 = Marshal.load(Marshal.dump(packet))
80
+ packet.meta.should == packet2.meta
81
+ packet.token.should == packet2.token
82
+ end
83
+ end
84
+
85
+
86
+ describe "Packet: FileChunk" do
87
+ it "should dump/load as JSON objects" do
88
+ packet = Nanite::FileChunk.new('chunk','0xdeadbeef')
89
+ packet2 = JSON.parse(packet.to_json)
90
+ packet.chunk.should == packet2.chunk
91
+ packet.token.should == packet2.token
92
+ end
93
+
94
+ it "should dump/load as Marshalled ruby objects" do
95
+ packet = Nanite::FileChunk.new('chunk','0xdeadbeef')
96
+ packet2 = Marshal.load(Marshal.dump(packet))
97
+ packet.chunk.should == packet2.chunk
98
+ packet.token.should == packet2.token
99
+ end
100
+ end
101
+
102
+
103
+ describe "Packet: Request" do
104
+ it "should dump/load as JSON objects" do
105
+ packet = Nanite::Request.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef', :reply_to => 'reply_to')
106
+ packet2 = JSON.parse(packet.to_json)
107
+ packet.type.should == packet2.type
108
+ packet.payload.should == packet2.payload
109
+ packet.from.should == packet2.from
110
+ packet.token.should == packet2.token
111
+ packet.reply_to.should == packet2.reply_to
112
+ end
113
+
114
+ it "should dump/load as Marshalled ruby objects" do
115
+ packet = Nanite::Request.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef', :reply_to => 'reply_to')
116
+ packet2 = Marshal.load(Marshal.dump(packet))
117
+ packet.type.should == packet2.type
118
+ packet.payload.should == packet2.payload
119
+ packet.from.should == packet2.from
120
+ packet.token.should == packet2.token
121
+ packet.reply_to.should == packet2.reply_to
122
+ end
123
+ end
124
+
125
+
126
+ describe "Packet: Result" do
127
+ it "should dump/load as JSON objects" do
128
+ packet = Nanite::Result.new('0xdeadbeef', 'to', 'results', 'from')
129
+ packet2 = JSON.parse(packet.to_json)
130
+ packet.token.should == packet2.token
131
+ packet.to.should == packet2.to
132
+ packet.results.should == packet2.results
133
+ packet.from.should == packet2.from
134
+ end
135
+
136
+ it "should dump/load as Marshalled ruby objects" do
137
+ packet = Nanite::Result.new('0xdeadbeef', 'to', 'results', 'from')
138
+ packet2 = Marshal.load(Marshal.dump(packet))
139
+ packet.token.should == packet2.token
140
+ packet.to.should == packet2.to
141
+ packet.results.should == packet2.results
142
+ packet.from.should == packet2.from
143
+ end
144
+ end
145
+
146
+
147
+ describe "Packet: IntermediateMessage" do
148
+ it "should dump/load as JSON objects" do
149
+ packet = Nanite::IntermediateMessage.new('0xdeadbeef', 'to', 'from', 'messagekey', 'message')
150
+ packet2 = JSON.parse(packet.to_json)
151
+ packet.token.should == packet2.token
152
+ packet.to.should == packet2.to
153
+ packet.from.should == packet2.from
154
+ packet.messagekey.should == packet2.messagekey
155
+ packet.message.should == packet2.message
156
+ end
157
+
158
+ it "should dump/load as Marshalled ruby objects" do
159
+ packet = Nanite::IntermediateMessage.new('0xdeadbeef', 'to', 'from', 'messagekey', 'message')
160
+ packet2 = Marshal.load(Marshal.dump(packet))
161
+ packet.token.should == packet2.token
162
+ packet.to.should == packet2.to
163
+ packet.from.should == packet2.from
164
+ packet.messagekey.should == packet2.messagekey
165
+ packet.message.should == packet2.message
166
+ end
167
+ end
168
+
169
+
170
+ describe "Packet: Register" do
171
+ it "should dump/load as JSON objects" do
172
+ packet = Nanite::Register.new('0xdeadbeef', ['/foo/bar', '/nik/qux'], 0.8, ['foo'])
173
+ packet2 = JSON.parse(packet.to_json)
174
+ packet.identity.should == packet2.identity
175
+ packet.services.should == packet2.services
176
+ packet.status.should == packet2.status
177
+ end
178
+
179
+ it "should dump/load as Marshalled ruby objects" do
180
+ packet = Nanite::Register.new('0xdeadbeef', ['/foo/bar', '/nik/qux'], 0.8, ['foo'])
181
+ packet2 = Marshal.load(Marshal.dump(packet))
182
+ packet.identity.should == packet2.identity
183
+ packet.services.should == packet2.services
184
+ packet.status.should == packet2.status
185
+ end
186
+ end
187
+
188
+
189
+ describe "Packet: UnRegister" do
190
+ it "should dump/load as JSON objects" do
191
+ packet = Nanite::UnRegister.new('0xdeadbeef')
192
+ packet2 = JSON.parse(packet.to_json)
193
+ packet.identity.should == packet2.identity
194
+ end
195
+
196
+ it "should dump/load as Marshalled ruby objects" do
197
+ packet = Nanite::UnRegister.new('0xdeadbeef')
198
+ packet2 = Marshal.load(Marshal.dump(packet))
199
+ packet.identity.should == packet2.identity
200
+ end
201
+ end
202
+
203
+
204
+ describe "Packet: Ping" do
205
+ it "should dump/load as JSON objects" do
206
+ packet = Nanite::Ping.new('0xdeadbeef', 0.8)
207
+ packet2 = JSON.parse(packet.to_json)
208
+ packet.identity.should == packet2.identity
209
+ packet.status.should == packet2.status
210
+ end
211
+
212
+ it "should dump/load as Marshalled ruby objects" do
213
+ packet = Nanite::Ping.new('0xdeadbeef', 0.8)
214
+ packet2 = Marshal.load(Marshal.dump(packet))
215
+ packet.identity.should == packet2.identity
216
+ packet.status.should == packet2.status
217
+ end
218
+ 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,23 @@
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
+ # Create test certificate
11
+ def issue_cert
12
+ test_dn = { 'C' => 'US',
13
+ 'ST' => 'California',
14
+ 'L' => 'Santa Barbara',
15
+ 'O' => 'Nanite',
16
+ 'OU' => 'Certification Services',
17
+ 'CN' => 'Nanite test' }
18
+ dn = Nanite::DistinguishedName.new(test_dn)
19
+ key = Nanite::RsaKeyPair.new
20
+ [ Nanite::Certificate.new(key, dn, dn), key ]
21
+ end
22
+
23
+ end