pantry 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +9 -0
- data/.ruby-version +1 -0
- data/.travis.yml +19 -0
- data/Gemfile +15 -0
- data/Guardfile +16 -0
- data/LICENSE +20 -0
- data/README.md +53 -0
- data/Rakefile +18 -0
- data/Vagrantfile +86 -0
- data/bin/pantry +11 -0
- data/bin/pantry-client +38 -0
- data/bin/pantry-server +33 -0
- data/dist/client.yml +79 -0
- data/dist/server.yml +56 -0
- data/dist/upstart/pantry-client.conf +12 -0
- data/dist/upstart/pantry-server.conf +12 -0
- data/doc/message_packet.dot +19 -0
- data/doc/message_packet.dot.png +0 -0
- data/doc/network_topology.dot +42 -0
- data/doc/network_topology.dot.png +0 -0
- data/lib/celluloid_zmq_patches.rb +16 -0
- data/lib/opt_parse_plus.rb +184 -0
- data/lib/pantry.rb +197 -0
- data/lib/pantry/cli.rb +154 -0
- data/lib/pantry/client.rb +131 -0
- data/lib/pantry/client_info.rb +34 -0
- data/lib/pantry/client_registry.rb +104 -0
- data/lib/pantry/command.rb +194 -0
- data/lib/pantry/command_handler.rb +53 -0
- data/lib/pantry/command_line.rb +115 -0
- data/lib/pantry/commands/create_client.rb +30 -0
- data/lib/pantry/commands/download_directory.rb +35 -0
- data/lib/pantry/commands/echo.rb +32 -0
- data/lib/pantry/commands/edit_application.rb +60 -0
- data/lib/pantry/commands/register_client.rb +38 -0
- data/lib/pantry/commands/status.rb +78 -0
- data/lib/pantry/commands/sync_directory.rb +50 -0
- data/lib/pantry/commands/update_application.rb +45 -0
- data/lib/pantry/commands/upload_file.rb +68 -0
- data/lib/pantry/communication.rb +20 -0
- data/lib/pantry/communication/client.rb +75 -0
- data/lib/pantry/communication/client_filter.rb +117 -0
- data/lib/pantry/communication/file_service.rb +125 -0
- data/lib/pantry/communication/file_service/file_progress.rb +164 -0
- data/lib/pantry/communication/file_service/receive_file.rb +97 -0
- data/lib/pantry/communication/file_service/send_file.rb +74 -0
- data/lib/pantry/communication/publish_socket.rb +20 -0
- data/lib/pantry/communication/reading_socket.rb +89 -0
- data/lib/pantry/communication/receive_socket.rb +23 -0
- data/lib/pantry/communication/security.rb +44 -0
- data/lib/pantry/communication/security/authentication.rb +98 -0
- data/lib/pantry/communication/security/curve_key_store.rb +120 -0
- data/lib/pantry/communication/security/curve_security.rb +70 -0
- data/lib/pantry/communication/security/null_security.rb +32 -0
- data/lib/pantry/communication/send_socket.rb +19 -0
- data/lib/pantry/communication/serialize_message.rb +84 -0
- data/lib/pantry/communication/server.rb +97 -0
- data/lib/pantry/communication/subscribe_socket.rb +33 -0
- data/lib/pantry/communication/wait_list.rb +45 -0
- data/lib/pantry/communication/writing_socket.rb +46 -0
- data/lib/pantry/config.rb +182 -0
- data/lib/pantry/file_editor.rb +67 -0
- data/lib/pantry/logger.rb +78 -0
- data/lib/pantry/message.rb +134 -0
- data/lib/pantry/multi_command.rb +36 -0
- data/lib/pantry/server.rb +132 -0
- data/lib/pantry/test/acceptance.rb +83 -0
- data/lib/pantry/test/support/fake_fs.rb +31 -0
- data/lib/pantry/test/support/matchers.rb +13 -0
- data/lib/pantry/test/support/minitest.rb +13 -0
- data/lib/pantry/test/support/mock_ui.rb +23 -0
- data/lib/pantry/test/unit.rb +13 -0
- data/lib/pantry/ui.rb +68 -0
- data/lib/pantry/version.rb +3 -0
- data/pantry.gemspec +40 -0
- data/test/acceptance/cli/error_handling_test.rb +7 -0
- data/test/acceptance/cli/execute_command_on_clients_test.rb +32 -0
- data/test/acceptance/cli/request_info_from_server_test.rb +44 -0
- data/test/acceptance/communication/client_requests_info_from_server_test.rb +28 -0
- data/test/acceptance/communication/heartbeat_test.rb +19 -0
- data/test/acceptance/communication/pub_sub_communication_test.rb +53 -0
- data/test/acceptance/communication/security_test.rb +117 -0
- data/test/acceptance/communication/server_requests_info_from_client_test.rb +41 -0
- data/test/acceptance/test_helper.rb +25 -0
- data/test/fixtures/config.yml +22 -0
- data/test/fixtures/empty.yml +2 -0
- data/test/fixtures/file_to_upload +3 -0
- data/test/root_dir/.gitkeep +0 -0
- data/test/unit/cli_test.rb +173 -0
- data/test/unit/client_registry_test.rb +61 -0
- data/test/unit/client_test.rb +128 -0
- data/test/unit/command_handler_test.rb +79 -0
- data/test/unit/command_line_test.rb +5 -0
- data/test/unit/command_test.rb +206 -0
- data/test/unit/commands/create_client_test.rb +25 -0
- data/test/unit/commands/download_directory_test.rb +58 -0
- data/test/unit/commands/echo_test.rb +22 -0
- data/test/unit/commands/edit_application_test.rb +84 -0
- data/test/unit/commands/register_client_test.rb +41 -0
- data/test/unit/commands/status_test.rb +81 -0
- data/test/unit/commands/sync_directory_test.rb +75 -0
- data/test/unit/commands/update_application_test.rb +35 -0
- data/test/unit/commands/upload_file_test.rb +51 -0
- data/test/unit/communication/client_filter_test.rb +262 -0
- data/test/unit/communication/client_test.rb +99 -0
- data/test/unit/communication/file_service/receive_file_test.rb +214 -0
- data/test/unit/communication/file_service/send_file_test.rb +110 -0
- data/test/unit/communication/file_service_test.rb +56 -0
- data/test/unit/communication/publish_socket_test.rb +19 -0
- data/test/unit/communication/reading_socket_test.rb +110 -0
- data/test/unit/communication/receive_socket_test.rb +20 -0
- data/test/unit/communication/security/authentication_test.rb +97 -0
- data/test/unit/communication/security/curve_key_store_test.rb +110 -0
- data/test/unit/communication/security/curve_security_test.rb +44 -0
- data/test/unit/communication/security/null_security_test.rb +15 -0
- data/test/unit/communication/security_test.rb +49 -0
- data/test/unit/communication/send_socket_test.rb +19 -0
- data/test/unit/communication/serialize_message_test.rb +128 -0
- data/test/unit/communication/server_test.rb +106 -0
- data/test/unit/communication/subscribe_socket_test.rb +46 -0
- data/test/unit/communication/wait_list_test.rb +60 -0
- data/test/unit/communication/writing_socket_test.rb +46 -0
- data/test/unit/config_test.rb +150 -0
- data/test/unit/logger_test.rb +79 -0
- data/test/unit/message_test.rb +179 -0
- data/test/unit/multi_command_test.rb +45 -0
- data/test/unit/opt_parse_plus_test.rb +218 -0
- data/test/unit/pantry_test.rb +82 -0
- data/test/unit/server_test.rb +166 -0
- data/test/unit/test_helper.rb +25 -0
- data/test/unit/ui_test.rb +58 -0
- metadata +389 -13
@@ -0,0 +1,31 @@
|
|
1
|
+
gem 'fakefs'
|
2
|
+
require 'fakefs/safe'
|
3
|
+
|
4
|
+
# Hook up FakeFS into Minitest
|
5
|
+
class MiniTest::Test
|
6
|
+
def self.fake_fs!
|
7
|
+
before do
|
8
|
+
FakeFS.activate!
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
FakeFS.deactivate!
|
13
|
+
FakeFS::FileSystem.clear
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Minitest uses Tempfiles for figuring out more complicated diffs
|
19
|
+
# This causes FakeFS to explode, so make sure this is run without FakeFS
|
20
|
+
# enabled.
|
21
|
+
module Minitest
|
22
|
+
module Assertions
|
23
|
+
alias :actual_diff :diff
|
24
|
+
|
25
|
+
def diff exp, act
|
26
|
+
FakeFS.without do
|
27
|
+
actual_diff exp, act
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Some custom MiniTest matchers used throughout the system
|
2
|
+
|
3
|
+
module Minitest::Assertions
|
4
|
+
|
5
|
+
# I don't like the refute_ syntax, sorry =/
|
6
|
+
|
7
|
+
alias assert_not_nil refute_nil
|
8
|
+
alias assert_not refute
|
9
|
+
alias assert_false refute
|
10
|
+
alias assert_not_equal refute_equal
|
11
|
+
alias assert_no_match refute_match
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# For actions that print out or use the console via
|
2
|
+
# Pantry.ui, these helpers mock out stdout/stderr to make it easy
|
3
|
+
# to grab what's printed and to inject keypresses
|
4
|
+
class MiniTest::Test
|
5
|
+
def self.mock_ui!
|
6
|
+
before do
|
7
|
+
@mock_stdin = StringIO.new
|
8
|
+
@mock_stdout = StringIO.new
|
9
|
+
Pantry.reset_ui!
|
10
|
+
Pantry.ui(@mock_stdin, @mock_stdout)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Return the strings added to stdout through the test
|
15
|
+
def stdout
|
16
|
+
@mock_stdout.string
|
17
|
+
end
|
18
|
+
|
19
|
+
# Get access to the mock of STDIN to add values
|
20
|
+
def stdin
|
21
|
+
@mock_stdin
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#
|
2
|
+
# Require this file to grab the Pantry unit test environment.
|
3
|
+
# This environment includes setup helpers to ensure Celluloid is running,
|
4
|
+
# as well as a few mocks (ui and fakefs) as well as helpers to facilitate
|
5
|
+
# testing Pantry plugins.
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'pantry'
|
9
|
+
require 'celluloid/test'
|
10
|
+
require 'pantry/test/support/minitest'
|
11
|
+
require 'pantry/test/support/matchers'
|
12
|
+
require 'pantry/test/support/mock_ui'
|
13
|
+
require 'pantry/test/support/fake_fs'
|
data/lib/pantry/ui.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
module Pantry
|
2
|
+
|
3
|
+
# Global access to Pantry's UI handler. This object offers up
|
4
|
+
# a set of methods used to interact with the User via the CLI.
|
5
|
+
def self.ui(input = $stdin, output = $stdout)
|
6
|
+
@@ui ||= Pantry::UI.new(input, output)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.reset_ui!
|
10
|
+
@@ui = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
class UI
|
14
|
+
|
15
|
+
def initialize(input = $stdin, output = $stdout)
|
16
|
+
require 'highline'
|
17
|
+
@output = output
|
18
|
+
@input = input
|
19
|
+
@highline = HighLine.new(input, output)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Send a message to STDOUT
|
23
|
+
def say(message)
|
24
|
+
@highline.say(message)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Print out a list, attempting to make it look somewhat reasonable
|
28
|
+
def list(array)
|
29
|
+
say(array.join("\n") + "\n")
|
30
|
+
end
|
31
|
+
|
32
|
+
def color(string, color)
|
33
|
+
HighLine.color(string, color)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Show the user a message and ask them to continue by hitting Enter,
|
37
|
+
# or they can cancel with "No"
|
38
|
+
def continue?(message)
|
39
|
+
@highline.agree(message) do |q|
|
40
|
+
q.default = "yes"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Start a new progress meter with the given number of ticks
|
45
|
+
def progress_start(tick_count)
|
46
|
+
require 'ruby-progressbar'
|
47
|
+
@progress = ProgressBar.create(
|
48
|
+
total: tick_count, output: @output,
|
49
|
+
format: "Progress: %P%% |%B| %c/%C %e"
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Increment the running progress meter the given number of ticks
|
54
|
+
def progress_step(tick_count)
|
55
|
+
if @progress.progress + tick_count > @progress.total
|
56
|
+
tick_count = @progress.total - @progress.progress
|
57
|
+
end
|
58
|
+
|
59
|
+
@progress.progress += tick_count
|
60
|
+
end
|
61
|
+
|
62
|
+
# Complete and close down the current progress meter
|
63
|
+
def progress_finish
|
64
|
+
@progress.finish
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
data/pantry.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "pantry/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "pantry"
|
6
|
+
s.version = Pantry::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Collective Idea", "Jason Roelofs"]
|
9
|
+
s.email = ["code@collectiveidea.com", "jasongroelofs@gmail.com"]
|
10
|
+
s.license = "MIT"
|
11
|
+
s.homepage = "http://pantryops.org"
|
12
|
+
|
13
|
+
s.summary = "Modern DevOps Automation"
|
14
|
+
s.description = <<-EOS
|
15
|
+
Pantry is a framework that provides answers to common questions encoutered when setting up a DevOps, server configuration, or server provisioning pipeline.
|
16
|
+
EOS
|
17
|
+
|
18
|
+
s.required_ruby_version = ">= 2.0.0"
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
22
|
+
s.require_path = "lib"
|
23
|
+
s.bindir = "bin"
|
24
|
+
|
25
|
+
s.executables = %w(pantry-client pantry-server pantry)
|
26
|
+
|
27
|
+
s.requirements << "zeromq 3.x or 4.x"
|
28
|
+
s.requirements << "libsodium for Curve security"
|
29
|
+
|
30
|
+
s.add_runtime_dependency "ffi-rzmq", "~> 2.0", ">= 2.0.0"
|
31
|
+
s.add_runtime_dependency "celluloid", "~> 0.15", ">= 0.15.0"
|
32
|
+
s.add_runtime_dependency "celluloid-zmq", "~> 0.15", ">= 0.15.0"
|
33
|
+
s.add_runtime_dependency "highline", "~> 1.6", ">= 1.6.21"
|
34
|
+
s.add_runtime_dependency "json", "~> 1.8", ">= 1.8.1"
|
35
|
+
s.add_runtime_dependency "ruby-progressbar", "~> 1.4", ">= 1.4.2"
|
36
|
+
s.add_runtime_dependency "safe_yaml", "~> 1.0", ">= 1.0.1"
|
37
|
+
|
38
|
+
s.add_development_dependency "mocha", "~> 1.0", ">= 1.0.0"
|
39
|
+
s.add_development_dependency "fakefs", "~> 0.5", ">= 0.5.1"
|
40
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'acceptance/test_helper'
|
2
|
+
|
3
|
+
describe "CLI requests information from individual clients" do
|
4
|
+
|
5
|
+
mock_ui!
|
6
|
+
|
7
|
+
it "receives responses from each client asked" do
|
8
|
+
set_up_environment(ports_start_at: 10100)
|
9
|
+
|
10
|
+
Pantry::CLI.new(
|
11
|
+
["-a", "pantry", "echo", "This is Neat"],
|
12
|
+
identity: "cli1"
|
13
|
+
).run
|
14
|
+
|
15
|
+
assert_match %r|Expecting response from 2 clients|, stdout
|
16
|
+
assert_match %r|#{@client1.identity} echo's "This is Neat"|, stdout
|
17
|
+
assert_match %r|#{@client2.identity} echo's "This is Neat"|, stdout
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can target specific clients for the commands sent" do
|
21
|
+
set_up_environment(ports_start_at: 10110)
|
22
|
+
|
23
|
+
Pantry::CLI.new(
|
24
|
+
["-a", "pantry", "-e", "test", "-r", "app1", "echo", "This is Neat"],
|
25
|
+
identity: "cli1"
|
26
|
+
).run
|
27
|
+
|
28
|
+
assert_match %r|Expecting response from 1 client|, stdout
|
29
|
+
assert_match %r|#{@client1.identity} echo's \"This is Neat\"|, stdout
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'acceptance/test_helper'
|
2
|
+
|
3
|
+
describe "CLI can ask Server for information" do
|
4
|
+
|
5
|
+
mock_ui!
|
6
|
+
|
7
|
+
it "can ask for all known nodes" do
|
8
|
+
set_up_environment(ports_start_at: 10200)
|
9
|
+
|
10
|
+
Pantry::CLI.new(
|
11
|
+
["status"],
|
12
|
+
identity: "test_client"
|
13
|
+
).run
|
14
|
+
|
15
|
+
assert_match /#{@client1.identity}/, stdout, "Did not contain line for client1"
|
16
|
+
assert_match /#{@client2.identity}/, stdout, "Did not contain line for client2"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can limit the query to a subset of clients" do
|
20
|
+
set_up_environment(ports_start_at: 10210)
|
21
|
+
|
22
|
+
cli = Pantry::CLI.new(
|
23
|
+
["-a", "chatbot", "status"],
|
24
|
+
identity: "test_client"
|
25
|
+
)
|
26
|
+
|
27
|
+
client3 = Pantry::Client.new(application: "chatbot", identity: "client3")
|
28
|
+
client3.run
|
29
|
+
|
30
|
+
client4 = Pantry::Client.new(application: "chatbot", identity: "client4")
|
31
|
+
client4.run
|
32
|
+
|
33
|
+
cli.run
|
34
|
+
|
35
|
+
assert_equal 2, stdout.split("\n").length
|
36
|
+
|
37
|
+
assert_match /client3/, stdout, "Did not contain line for client3"
|
38
|
+
assert_match /client4/, stdout, "Did not contain line for client4"
|
39
|
+
|
40
|
+
client3.shutdown
|
41
|
+
client4.shutdown
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'acceptance/test_helper'
|
2
|
+
|
3
|
+
describe "Client requests information from the Server" do
|
4
|
+
|
5
|
+
it "asks the server for information and waits for a response" do
|
6
|
+
set_up_environment(ports_start_at: 10300)
|
7
|
+
|
8
|
+
message = ServerEchoCommand.new("Hello Server").to_message
|
9
|
+
response_future = @client1.send_request(message)
|
10
|
+
|
11
|
+
assert_equal ["Hello Server"], response_future.value(2).body
|
12
|
+
end
|
13
|
+
|
14
|
+
it "handles multiple requests in the proper order" do
|
15
|
+
set_up_environment(ports_start_at: 10310)
|
16
|
+
|
17
|
+
futures = []
|
18
|
+
10.times do |i|
|
19
|
+
message = ServerEchoCommand.new("Hello Server #{i}").to_message
|
20
|
+
futures << @client1.send_request(message)
|
21
|
+
end
|
22
|
+
|
23
|
+
futures.each_with_index do |future, idx|
|
24
|
+
assert_equal ["Hello Server #{idx}"], future.value(1).body
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'acceptance/test_helper'
|
2
|
+
|
3
|
+
describe "Client / Server heartbeats" do
|
4
|
+
|
5
|
+
describe "Client" do
|
6
|
+
it "re-registers with the server every interval seconds" do
|
7
|
+
set_up_environment(ports_start_at: 10500, heartbeat: 1)
|
8
|
+
|
9
|
+
# Clean out the server registry then wait for clients to re-register themselves
|
10
|
+
@server.client_registry.clear!
|
11
|
+
|
12
|
+
sleep 2
|
13
|
+
|
14
|
+
assert @server.client_registry.include?(@client1), "Client1 did not check in again"
|
15
|
+
assert @server.client_registry.include?(@client2), "Client2 did not check in again"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'acceptance/test_helper'
|
2
|
+
|
3
|
+
describe "Pub/Sub Communication" do
|
4
|
+
|
5
|
+
describe "Server" do
|
6
|
+
it "can publish a message to all connected clients" do
|
7
|
+
set_up_environment(ports_start_at: 10400)
|
8
|
+
|
9
|
+
@server.publish_message(
|
10
|
+
Pantry::Message.new("test_message"),
|
11
|
+
Pantry::Communication::ClientFilter.new(application: "pantry")
|
12
|
+
)
|
13
|
+
|
14
|
+
# Give communication time to happen
|
15
|
+
sleep 1
|
16
|
+
|
17
|
+
assert_equal "test_message", @client1.last_received_message.type
|
18
|
+
assert_equal "test_message", @client2.last_received_message.type
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can publish a message to a subset of all connected clients" do
|
22
|
+
set_up_environment(ports_start_at: 10410)
|
23
|
+
|
24
|
+
client3 = Pantry::Client.new(roles: %w(database), identity: "client3")
|
25
|
+
client3.run
|
26
|
+
|
27
|
+
client4 = Pantry::Client.new(roles: %w(database task), identity: "client4")
|
28
|
+
client4.run
|
29
|
+
|
30
|
+
sleep 1
|
31
|
+
|
32
|
+
@server.publish_message(Pantry::Message.new("to_databases"),
|
33
|
+
Pantry::Communication::ClientFilter.new(roles: %w(database)))
|
34
|
+
|
35
|
+
# Give communication time to happen
|
36
|
+
sleep 1
|
37
|
+
|
38
|
+
assert_equal "to_databases", client3.last_received_message.type
|
39
|
+
assert_equal "to_databases", client4.last_received_message.type
|
40
|
+
|
41
|
+
@server.publish_message(Pantry::Message.new("to_tasks"),
|
42
|
+
Pantry::Communication::ClientFilter.new(roles: %w(task)))
|
43
|
+
|
44
|
+
# Give communication time to happen
|
45
|
+
sleep 1
|
46
|
+
|
47
|
+
assert_equal "to_tasks", client4.last_received_message.type
|
48
|
+
|
49
|
+
client3.shutdown
|
50
|
+
client4.shutdown
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'acceptance/test_helper'
|
2
|
+
|
3
|
+
describe "ZMQ4 CURVE security" do
|
4
|
+
|
5
|
+
break unless Pantry::Communication::Security.curve_supported?
|
6
|
+
|
7
|
+
def set_up_encrypted(ports_start_at, options = {})
|
8
|
+
Celluloid.boot
|
9
|
+
configure_pantry(ports_start_at: ports_start_at, security: "curve")
|
10
|
+
|
11
|
+
server_public, server_private = ZMQ::Util.curve_keypair
|
12
|
+
client_public, client_private = ZMQ::Util.curve_keypair
|
13
|
+
|
14
|
+
known_clients = options[:known_clients] || [client_public]
|
15
|
+
|
16
|
+
key_dir = Pantry.root.join("security", "curve")
|
17
|
+
FileUtils.mkdir_p(key_dir)
|
18
|
+
|
19
|
+
File.open(key_dir.join("server_keys.yml"), "w+") do |f|
|
20
|
+
f.write(YAML.dump({
|
21
|
+
"private_key" => server_private,
|
22
|
+
"public_key" => options[:server_public_key] || server_public,
|
23
|
+
"client_keys" => known_clients
|
24
|
+
}))
|
25
|
+
end
|
26
|
+
|
27
|
+
File.open(key_dir.join("client_keys.yml"), "w+") do |f|
|
28
|
+
f.write(YAML.dump({
|
29
|
+
"private_key" => client_private, "public_key" => client_public,
|
30
|
+
"server_public_key" => options[:server_public_key] || server_public
|
31
|
+
}))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "connectivity" do
|
36
|
+
def assert_message_timeout(client)
|
37
|
+
message = ServerEchoCommand.new("Hello Server").to_message
|
38
|
+
response_future = client.send_request(message)
|
39
|
+
|
40
|
+
assert_raises(Celluloid::TimeoutError) do
|
41
|
+
response_future.value(1).body
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def assert_successful_message(client)
|
46
|
+
message = ServerEchoCommand.new("Hello Server").to_message
|
47
|
+
response_future = client.send_request(message)
|
48
|
+
|
49
|
+
assert_equal ["Hello Server"], response_future.value(2).body
|
50
|
+
end
|
51
|
+
|
52
|
+
it "configures CURVE security for encrypted server/client communication" do
|
53
|
+
set_up_encrypted(15000)
|
54
|
+
|
55
|
+
server = Pantry::Server.new
|
56
|
+
server.identity = "Encrypted Server"
|
57
|
+
server.run
|
58
|
+
|
59
|
+
client = Pantry::Client.new identity: "encrypted-client"
|
60
|
+
client.run
|
61
|
+
|
62
|
+
assert_successful_message(client)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "rejects clients who connect with the wrong server key" do
|
66
|
+
set_up_encrypted(15010, server_public_key: "invalid security token1234567890")
|
67
|
+
|
68
|
+
server = Pantry::Server.new
|
69
|
+
server.identity = "Encrypted Server"
|
70
|
+
server.run
|
71
|
+
|
72
|
+
client = Pantry::Client.new identity: "encrypted-client"
|
73
|
+
client.run
|
74
|
+
|
75
|
+
assert_message_timeout(client)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "rejects a client whos public key is not known by the server" do
|
79
|
+
set_up_encrypted(15020, known_clients: ["some other client here1234567890"])
|
80
|
+
|
81
|
+
server = Pantry::Server.new
|
82
|
+
server.identity = "Encrypted Server"
|
83
|
+
server.run
|
84
|
+
|
85
|
+
client = Pantry::Client.new identity: "encrypted-client"
|
86
|
+
client.run
|
87
|
+
|
88
|
+
assert_message_timeout(client)
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "requesting new client keys" do
|
94
|
+
|
95
|
+
mock_ui!
|
96
|
+
|
97
|
+
it "returns a new set of client keys as requested" do
|
98
|
+
set_up_encrypted(15030)
|
99
|
+
|
100
|
+
server = Pantry::Server.new
|
101
|
+
server.identity = "Encrypted Server"
|
102
|
+
server.run
|
103
|
+
|
104
|
+
cli = Pantry::CLI.new(
|
105
|
+
["client:create"],
|
106
|
+
identity: "encrypted-client"
|
107
|
+
)
|
108
|
+
cli.run
|
109
|
+
|
110
|
+
assert_match /server_public_key/, stdout
|
111
|
+
assert_match /public_key/, stdout
|
112
|
+
assert_match /private_key/, stdout
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|