warden-protocol 0.1.3

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/.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