warden-protocol 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +1 -0
  3. data/CHANGELOG.md +14 -0
  4. data/Gemfile +6 -0
  5. data/README.md +13 -0
  6. data/Rakefile +40 -0
  7. data/lib/warden/protocol.rb +4 -0
  8. data/lib/warden/protocol/base.rb +168 -0
  9. data/lib/warden/protocol/buffer.rb +69 -0
  10. data/lib/warden/protocol/build.sh +13 -0
  11. data/lib/warden/protocol/message.rb +50 -0
  12. data/lib/warden/protocol/pb.rb +497 -0
  13. data/lib/warden/protocol/pb/copy_in.proto +35 -0
  14. data/lib/warden/protocol/pb/copy_out.proto +39 -0
  15. data/lib/warden/protocol/pb/create.proto +65 -0
  16. data/lib/warden/protocol/pb/destroy.proto +33 -0
  17. data/lib/warden/protocol/pb/echo.proto +26 -0
  18. data/lib/warden/protocol/pb/error.proto +19 -0
  19. data/lib/warden/protocol/pb/info.proto +95 -0
  20. data/lib/warden/protocol/pb/limit_bandwidth.proto +30 -0
  21. data/lib/warden/protocol/pb/limit_disk.proto +70 -0
  22. data/lib/warden/protocol/pb/limit_memory.proto +34 -0
  23. data/lib/warden/protocol/pb/link.proto +40 -0
  24. data/lib/warden/protocol/pb/list.proto +25 -0
  25. data/lib/warden/protocol/pb/message.proto +36 -0
  26. data/lib/warden/protocol/pb/net_in.proto +39 -0
  27. data/lib/warden/protocol/pb/net_out.proto +35 -0
  28. data/lib/warden/protocol/pb/ping.proto +24 -0
  29. data/lib/warden/protocol/pb/resource_limits.proto +30 -0
  30. data/lib/warden/protocol/pb/run.proto +29 -0
  31. data/lib/warden/protocol/pb/spawn.proto +37 -0
  32. data/lib/warden/protocol/pb/stop.proto +40 -0
  33. data/lib/warden/protocol/pb/stream.proto +41 -0
  34. data/lib/warden/protocol/version.rb +7 -0
  35. data/spec/base_spec.rb +150 -0
  36. data/spec/buffer_spec.rb +65 -0
  37. data/spec/copy_in_spec.rb +51 -0
  38. data/spec/copy_out_spec.rb +56 -0
  39. data/spec/create_spec.rb +70 -0
  40. data/spec/destroy_spec.rb +36 -0
  41. data/spec/echo_spec.rb +42 -0
  42. data/spec/error_spec.rb +33 -0
  43. data/spec/info_spec.rb +122 -0
  44. data/spec/limit_bandwidth_spec.rb +57 -0
  45. data/spec/limit_disk_spec.rb +103 -0
  46. data/spec/limit_memory_spec.rb +47 -0
  47. data/spec/link_spec.rb +67 -0
  48. data/spec/list_spec.rb +41 -0
  49. data/spec/net_in_spec.rb +57 -0
  50. data/spec/net_out_spec.rb +47 -0
  51. data/spec/ping_spec.rb +32 -0
  52. data/spec/resource_limits_spec.rb +84 -0
  53. data/spec/run_spec.rb +79 -0
  54. data/spec/spawn_spec.rb +55 -0
  55. data/spec/spec_helper.rb +11 -0
  56. data/spec/stop_spec.rb +46 -0
  57. data/spec/stream_spec.rb +65 -0
  58. data/spec/support/examples/wrappable_reply.rb +26 -0
  59. data/spec/support/examples/wrappable_request.rb +26 -0
  60. data/spec/support/helper.rb +122 -0
  61. data/spec/support/matchers.rb +22 -0
  62. data/warden-protocol.gemspec +21 -0
  63. metadata +166 -0
@@ -0,0 +1,40 @@
1
+ // Link to a job.
2
+ //
3
+ // A request blocks until the job completes.
4
+ // A job is removed after it has completed and has been linked to.
5
+ //
6
+ // > **TODO** Talk about nomenclature (what is a job).
7
+ //
8
+ // ### Request
9
+ //
10
+ // * `handle`: Container handle.
11
+ // * `job_id`: Job ID.
12
+ //
13
+ // ### Response
14
+ //
15
+ // * `exit_status`: Exit status of the job.
16
+ // * `stdout`: Standard out produced by the job.
17
+ // * `stderr`: Standard error produced by the job.
18
+ //
19
+ // ### Errors
20
+ //
21
+ // * When `handle` does not refer to a container.
22
+ // * When `job_id` does not refer to a job.
23
+ //
24
+ // ### Definition
25
+ //
26
+
27
+ package warden;
28
+
29
+ message LinkRequest {
30
+ required string handle = 1;
31
+
32
+ required uint32 job_id = 2;
33
+ }
34
+
35
+ message LinkResponse {
36
+ optional uint32 exit_status = 1;
37
+ optional string stdout = 2;
38
+ optional string stderr = 3;
39
+ optional InfoResponse info = 4;
40
+ }
@@ -0,0 +1,25 @@
1
+ // Lists all containers.
2
+ //
3
+ // ### Request
4
+ //
5
+ // Empty.
6
+ //
7
+ // ### Response
8
+ //
9
+ // * `handles`: List of container handles.
10
+ //
11
+ // ### Errors
12
+ //
13
+ // None.
14
+ //
15
+ // ### Definition
16
+ //
17
+
18
+ package warden;
19
+
20
+ message ListRequest {
21
+ }
22
+
23
+ message ListResponse {
24
+ repeated string handles = 1;
25
+ }
@@ -0,0 +1,36 @@
1
+ // nodoc
2
+
3
+ package warden;
4
+
5
+ message Message {
6
+ enum Type {
7
+ Error = 1;
8
+
9
+ Create = 11;
10
+ Stop = 12;
11
+ Destroy = 13;
12
+ Info = 14;
13
+
14
+ Spawn = 21;
15
+ Link = 22;
16
+ Run = 23;
17
+ Stream = 24;
18
+
19
+ NetIn = 31;
20
+ NetOut = 32;
21
+
22
+ CopyIn = 41;
23
+ CopyOut = 42;
24
+
25
+ LimitMemory = 51;
26
+ LimitDisk = 52;
27
+ LimitBandwidth = 53;
28
+
29
+ Ping = 91;
30
+ List = 92;
31
+ Echo = 93;
32
+ }
33
+
34
+ required Type type = 1;
35
+ required bytes payload = 2;
36
+ }
@@ -0,0 +1,39 @@
1
+ // Set up a port mapping on the host to forward traffic to a specific port to a container.
2
+ //
3
+ // > **TODO** Link to page explaining how networking works.
4
+ //
5
+ // ### Request
6
+ //
7
+ // * `handle`: Container handle.
8
+ // * `host_port`: External port to be mapped.
9
+ // If not specified, a port will be acquired from the server's port pool.
10
+ // If specified, the user is expected to manage port availability.
11
+ // * `container_port`: Port on the container's interface that traffic should be forwarded to.
12
+ // If not specified, the port will be the same as `host_port`, whether it is specified or not.
13
+ //
14
+ // ### Response
15
+ //
16
+ // * `host_port`: External port that was mapped.
17
+ // * `container_port`: Port on the container's interface that traffic will be forwarded to.
18
+ //
19
+ // ### Errors
20
+ //
21
+ // * When `handle` does not refer to a container.
22
+ // * When no port can be acquired from the server's port pool.
23
+ //
24
+ // ### Definition
25
+ //
26
+
27
+ package warden;
28
+
29
+ message NetInRequest {
30
+ required string handle = 1;
31
+
32
+ optional uint32 host_port = 3;
33
+ optional uint32 container_port = 2;
34
+ }
35
+
36
+ message NetInResponse {
37
+ required uint32 host_port = 1;
38
+ required uint32 container_port = 2;
39
+ }
@@ -0,0 +1,35 @@
1
+ // Whitelist network traffic.
2
+ //
3
+ // If the configuration directive `deny_networks` is not used,
4
+ // all networks are already whitelisted and this command is effectively a no-op.
5
+ //
6
+ // > **TODO** Link to page explaining how networking works.
7
+ //
8
+ // ### Request
9
+ //
10
+ // * `handle`: Container handle.
11
+ // * `network`: Network to whitelist (in the form `1.2.3.4/8`).
12
+ // * `port`: Port to whitelist.
13
+ //
14
+ // ### Response
15
+ //
16
+ // Empty.
17
+ //
18
+ // ### Errors
19
+ //
20
+ // * When `handle` does not refer to a container.
21
+ //
22
+ // ### Definition
23
+ //
24
+
25
+ package warden;
26
+
27
+ message NetOutRequest {
28
+ required string handle = 1;
29
+
30
+ optional string network = 2;
31
+ optional uint32 port = 3;
32
+ }
33
+
34
+ message NetOutResponse {
35
+ }
@@ -0,0 +1,24 @@
1
+ // Pings.
2
+ //
3
+ // ### Request
4
+ //
5
+ // Empty.
6
+ //
7
+ // ### Response
8
+ //
9
+ // Empty.
10
+ //
11
+ // ### Errors
12
+ //
13
+ // None.
14
+ //
15
+ // ### Definition
16
+ //
17
+
18
+ package warden;
19
+
20
+ message PingRequest {
21
+ }
22
+
23
+ message PingResponse {
24
+ }
@@ -0,0 +1,30 @@
1
+ // This structure is neither a request nor a response.
2
+ //
3
+ // It is a structure that is shared between `Spawn` and `Run` requests.
4
+ //
5
+ // Please refer to the manual page of [`getrlimit(2)`][getrlimit] for a description of the individual fields.
6
+ //
7
+ // [getrlimit]: http://www.kernel.org/doc/man-pages/online/pages/man2/getrlimit.2.html
8
+ //
9
+ // ### Definition
10
+ //
11
+
12
+ package warden;
13
+
14
+ message ResourceLimits {
15
+ optional uint64 as = 1;
16
+ optional uint64 core = 2;
17
+ optional uint64 cpu = 3;
18
+ optional uint64 data = 4;
19
+ optional uint64 fsize = 5;
20
+ optional uint64 locks = 6;
21
+ optional uint64 memlock = 7;
22
+ optional uint64 msgqueue = 8;
23
+ optional uint64 nice = 9;
24
+ optional uint64 nofile = 10;
25
+ optional uint64 nproc = 11;
26
+ optional uint64 rss = 12;
27
+ optional uint64 rtprio = 13;
28
+ optional uint64 sigpending = 14;
29
+ optional uint64 stack = 15;
30
+ }
@@ -0,0 +1,29 @@
1
+ // Run a job inside a container.
2
+ //
3
+ // This request is equivalent to spawning a job and immediately linking to it.
4
+ //
5
+ // See `Spawn` and `Link` for a description of the request and response.
6
+ //
7
+ // ### Errors
8
+ //
9
+ // * When `handle` does not refer to a container.
10
+ //
11
+ // ### Definition
12
+ //
13
+
14
+ package warden;
15
+
16
+ message RunRequest {
17
+ required string handle = 1;
18
+
19
+ required string script = 2;
20
+ optional bool privileged = 3 [default = false];
21
+ optional ResourceLimits rlimits = 4;
22
+ }
23
+
24
+ message RunResponse {
25
+ optional uint32 exit_status = 1;
26
+ optional string stdout = 2;
27
+ optional string stderr = 3;
28
+ optional InfoResponse info = 4;
29
+ }
@@ -0,0 +1,37 @@
1
+ // Spawn a job inside a container.
2
+ //
3
+ // > **TODO** Talk about nomenclature (what is a job).
4
+ //
5
+ // ### Request
6
+ //
7
+ // The specified script is interpreted by `/bin/bash` inside the container.
8
+ //
9
+ // * `handle`: Container handle.
10
+ // * `script`: Script to execute.
11
+ // * `privileged`: Whether to run the script as root or not.
12
+ // * `rlimits`: Resource limits (see `ResourceLimits`).
13
+ //
14
+ // ### Response
15
+ //
16
+ // * `job_id`: Job ID.
17
+ //
18
+ // ### Errors
19
+ //
20
+ // * When `handle` does not refer to a container.
21
+ //
22
+ // ### Definition
23
+ //
24
+
25
+ package warden;
26
+
27
+ message SpawnRequest {
28
+ required string handle = 1;
29
+
30
+ required string script = 2;
31
+ optional bool privileged = 3 [default = false];
32
+ optional ResourceLimits rlimits = 4;
33
+ }
34
+
35
+ message SpawnResponse {
36
+ required uint32 job_id = 1;
37
+ }
@@ -0,0 +1,40 @@
1
+ // Stops a container.
2
+ //
3
+ // Once a container is stopped, warden does not allow spawning new processes inside the container.
4
+ // It is possible to copy files in to and out of a stopped container.
5
+ // It is only when a container is destroyed that its filesystem is cleaned up.
6
+ //
7
+ // ### Request
8
+ //
9
+ // Warden stops a container by sending the processes running inside it the `SIGTERM` signal.
10
+ // It then waits for the processes to terminate before returning a response.
11
+ // If one or more processes do not terminate within 10 seconds,
12
+ // the warden server sends these processes the `SIGKILL` signal,
13
+ // killing them ungracefully.
14
+ //
15
+ // * `handle`: Container handle.
16
+ // * `background`: Return a response immediately instead of waiting for the container to be stopped.
17
+ // * `kill`: Send SIGKILL instead of SIGTERM.
18
+ //
19
+ // ### Response
20
+ //
21
+ // Empty.
22
+ //
23
+ // ### Errors
24
+ //
25
+ // * When `handle` does not refer to a container.
26
+ //
27
+ // ### Definition
28
+ //
29
+
30
+ package warden;
31
+
32
+ message StopRequest {
33
+ required string handle = 1;
34
+
35
+ optional bool background = 10 [default = false];
36
+ optional bool kill = 20 [default = false];
37
+ }
38
+
39
+ message StopResponse {
40
+ }
@@ -0,0 +1,41 @@
1
+ // Stream a job.
2
+ //
3
+ // A stream request is followed by one or more stream responses.
4
+ //
5
+ // A job is removed after it has completed and the terminating stream response was sent.
6
+ //
7
+ // > **TODO** Talk about nomenclature (what is a job).
8
+ //
9
+ // ### Request
10
+ //
11
+ // * `handle`: Container handle.
12
+ // * `job_id`: Job ID.
13
+ //
14
+ // ### Response
15
+ //
16
+ // * `name`: Name of stream (either `stdout` or `stderr`).
17
+ // * `data`: A chunk of data from the stream specified in `name`.
18
+ // * `exit_status`: Exit status of the job. If set, this is the terminating response for the request.
19
+ //
20
+ // ### Errors
21
+ //
22
+ // * When `handle` does not refer to a container.
23
+ // * When `job_id` does not refer to a job.
24
+ //
25
+ // ### Definition
26
+ //
27
+
28
+ package warden;
29
+
30
+ message StreamRequest {
31
+ required string handle = 1;
32
+
33
+ required uint32 job_id = 2;
34
+ }
35
+
36
+ message StreamResponse {
37
+ optional string name = 1;
38
+ optional string data = 2;
39
+ optional uint32 exit_status = 3;
40
+ optional InfoResponse info = 4;
41
+ }
@@ -0,0 +1,7 @@
1
+ # coding: UTF-8
2
+
3
+ module Warden
4
+ module Protocol
5
+ VERSION = "0.1.3"
6
+ end
7
+ end
data/spec/base_spec.rb ADDED
@@ -0,0 +1,150 @@
1
+ # coding: UTF-8
2
+
3
+ require "spec_helper"
4
+ require "warden/protocol"
5
+
6
+ describe Warden::Protocol::BaseRequest do
7
+ it "should respond to #wrap" do
8
+ request = Warden::Protocol::SpawnRequest.new(:handle => "blah",
9
+ :script => "script")
10
+ wrapped = request.wrap
11
+ wrapped.should be_an_instance_of(Warden::Protocol::Message)
12
+ wrapped.type.should == Warden::Protocol::SpawnRequest.type
13
+ decoded = Warden::Protocol::SpawnRequest.decode(wrapped.payload)
14
+ decoded.handle.should == request.handle
15
+ decoded.script.should == request.script
16
+ end
17
+
18
+ it "should wrap beefcake errors" do
19
+ expect {
20
+ Warden::Protocol::SpawnRequest.new.wrap
21
+ }.to raise_error(Warden::Protocol::ProtocolError) { |e|
22
+ e.cause.class.name.should =~ /^Beefcake/
23
+ }
24
+ end
25
+ end
26
+
27
+ describe Warden::Protocol::BaseResponse do
28
+ it "should respond to #wrap" do
29
+ response = Warden::Protocol::SpawnResponse.new(:job_id => 1)
30
+ wrapped = response.wrap
31
+ wrapped.should be_an_instance_of(Warden::Protocol::Message)
32
+ wrapped.type.should == Warden::Protocol::SpawnResponse.type
33
+ decoded = Warden::Protocol::SpawnResponse.decode(wrapped.payload)
34
+ decoded.job_id.should == response.job_id
35
+ end
36
+
37
+ it "should wrap beefcake errors" do
38
+ expect {
39
+ Warden::Protocol::SpawnResponse.new.wrap
40
+ }.to raise_error(Warden::Protocol::ProtocolError) { |e|
41
+ e.cause.class.name.should =~ /^Beefcake/
42
+ }
43
+ end
44
+ end
45
+
46
+ describe "wrapped request" do
47
+ it "should respond to #request" do
48
+ w = Warden::Protocol::Message.new
49
+ w.type = Warden::Protocol::Message::Type::Spawn
50
+ w.payload = Warden::Protocol::SpawnRequest.new(:handle => "blah",
51
+ :script => "script").encode
52
+ w.should be_valid
53
+
54
+ w.request.should be_a(Warden::Protocol::SpawnRequest)
55
+ end
56
+
57
+ it "should wrap beefcake errors" do
58
+ w = Warden::Protocol::Message.new
59
+ w.type = Warden::Protocol::Message::Type::Spawn
60
+ w.payload = "bad payload"
61
+ w.should be_valid
62
+
63
+ expect { w.request }.to raise_error(Warden::Protocol::ProtocolError)
64
+ end
65
+ end
66
+
67
+ describe "wrapped response" do
68
+ it "should respond to #response" do
69
+ w = Warden::Protocol::Message.new
70
+ w.type = Warden::Protocol::Message::Type::Spawn
71
+ w.payload = Warden::Protocol::SpawnResponse.new(:handle => "blah",
72
+ :job_id => 2).encode
73
+ w.should be_valid
74
+
75
+ w.response.should be_a(Warden::Protocol::SpawnResponse)
76
+ end
77
+
78
+ it "should wrap beefcake errors" do
79
+ w = Warden::Protocol::Message.new
80
+ w.type = Warden::Protocol::Message::Type::Spawn
81
+ w.payload = "bad payload"
82
+
83
+ w.should be_valid
84
+
85
+ expect { w.response }.to raise_error(Warden::Protocol::ProtocolError)
86
+ end
87
+ end
88
+
89
+ describe Warden::Protocol do
90
+ before :all do
91
+ module Test
92
+ A = 1
93
+ B = 2
94
+ end
95
+ end
96
+
97
+ describe "#protocol_type_to_str" do
98
+ it "should return string representation of constants in a module" do
99
+ described_class.protocol_type_to_str(Test).should == "A, B"
100
+ end
101
+
102
+ it "should return string representation of symbol" do
103
+ described_class.protocol_type_to_str(:test).should == "test"
104
+ end
105
+
106
+ it "should return nil for invalid parameter" do
107
+ described_class.protocol_type_to_str(123).should be_nil
108
+ end
109
+ end
110
+
111
+ describe "#to_ruby_type" do
112
+ it "should use the type converter if is defined" do
113
+ Warden::Protocol::TypeConverter.should_receive("[]").once.
114
+ with(:uint32).and_return(lambda { |arg| Integer(arg) } )
115
+
116
+ described_class.to_ruby_type("123", :uint32).should == 123
117
+ end
118
+
119
+ it "should return value of constant defined in the module" do
120
+ Warden::Protocol::TypeConverter.should_receive("[]").once.
121
+ with(Test).and_return(nil)
122
+
123
+ described_class.to_ruby_type("A", Test).should == 1
124
+ end
125
+
126
+ it "should raise an error if a constant is not defined in a module" do
127
+ Warden::Protocol::TypeConverter.should_receive("[]").once.
128
+ with(Test).and_return(nil)
129
+
130
+ expect {
131
+ described_class.to_ruby_type("D", Test)
132
+ }.to raise_error { |error|
133
+ error.should be_an_instance_of TypeError
134
+ error.message.should == "The constant: 'D' is not defined in the module: 'Test'."
135
+ }
136
+ end
137
+
138
+ it "should raise an error if protocol type is not a module and no type converter is defined" do
139
+ Warden::Protocol::TypeConverter.should_receive("[]").once.
140
+ with(:test).and_return(nil)
141
+
142
+ expect {
143
+ described_class.to_ruby_type("test", :test)
144
+ }.to raise_error { |error|
145
+ error.should be_an_instance_of TypeError
146
+ error.message.should == "Non-existent protocol type passed: 'test'."
147
+ }
148
+ end
149
+ end
150
+ end