agent_client 0.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.
- data/README +1 -0
- data/Rakefile +52 -0
- data/lib/agent_client/base.rb +28 -0
- data/lib/agent_client/errors.rb +9 -0
- data/lib/agent_client/http_client.rb +64 -0
- data/lib/agent_client/version.rb +7 -0
- data/lib/agent_client.rb +25 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/unit/http_agent_client_spec.rb +135 -0
- metadata +83 -0
data/README
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Agent client for VMware BOSH.
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path("../../rake", __FILE__))
|
4
|
+
|
5
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
|
6
|
+
|
7
|
+
require "rubygems"
|
8
|
+
require "bundler"
|
9
|
+
Bundler.setup(:default, :test)
|
10
|
+
|
11
|
+
require "rake"
|
12
|
+
require "rake"
|
13
|
+
begin
|
14
|
+
require "rspec/core/rake_task"
|
15
|
+
rescue LoadError
|
16
|
+
end
|
17
|
+
|
18
|
+
require "bundler_task"
|
19
|
+
require "ci_task"
|
20
|
+
|
21
|
+
gem_helper = Bundler::GemHelper.new(Dir.pwd)
|
22
|
+
|
23
|
+
desc "Build BOSH Agent Client gem into the pkg directory"
|
24
|
+
task "build" do
|
25
|
+
gem_helper.build_gem
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Build and install BOSH Agent Client into system gems"
|
29
|
+
task "install" do
|
30
|
+
Rake::Task["bundler:install"].invoke
|
31
|
+
gem_helper.install_gem
|
32
|
+
end
|
33
|
+
|
34
|
+
BundlerTask.new
|
35
|
+
|
36
|
+
if defined?(RSpec)
|
37
|
+
namespace :spec do
|
38
|
+
desc "Run Unit Tests"
|
39
|
+
rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
|
40
|
+
t.gemfile = "Gemfile"
|
41
|
+
t.pattern = "spec/unit/**/*_spec.rb"
|
42
|
+
t.rspec_opts = %w(--format progress --colour)
|
43
|
+
end
|
44
|
+
|
45
|
+
CiTask.new do |task|
|
46
|
+
task.rspec_task = rspec_task
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Install dependencies and run tests"
|
51
|
+
task :spec => %w(bundler:install:test spec:unit)
|
52
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Bosh
|
2
|
+
module Agent
|
3
|
+
class BaseClient
|
4
|
+
|
5
|
+
def run_task(method, *args)
|
6
|
+
task = send(method.to_sym, *args)
|
7
|
+
|
8
|
+
while task["state"] == "running"
|
9
|
+
sleep(1.0)
|
10
|
+
task = get_task(task["agent_task_id"])
|
11
|
+
end
|
12
|
+
|
13
|
+
task
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(method_name, *args)
|
17
|
+
result = handle_method(method_name, args)
|
18
|
+
|
19
|
+
raise HandlerError, result["exception"] if result.has_key?("exception")
|
20
|
+
result["value"]
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
def handle_method(method_name, args)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Bosh; module Agent; end; end
|
2
|
+
|
3
|
+
require "httpclient"
|
4
|
+
|
5
|
+
module Bosh::Agent
|
6
|
+
class HTTPClient < BaseClient
|
7
|
+
|
8
|
+
IO_TIMEOUT = 86400 * 3
|
9
|
+
CONNECT_TIMEOUT = 30
|
10
|
+
|
11
|
+
def initialize(base_uri, options = {})
|
12
|
+
@base_uri = base_uri
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def handle_method(method, args)
|
19
|
+
payload = {
|
20
|
+
"method" => method, "arguments" => args,
|
21
|
+
"reply_to" => @options["reply_to"] || self.class.name
|
22
|
+
}
|
23
|
+
result = post_json("/agent", Yajl::Encoder.encode(payload))
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def request(method, uri, content_type = nil, payload = nil, headers = {})
|
29
|
+
headers = headers.dup
|
30
|
+
headers["Content-Type"] = content_type if content_type
|
31
|
+
|
32
|
+
http_client = ::HTTPClient.new
|
33
|
+
|
34
|
+
http_client.send_timeout = IO_TIMEOUT
|
35
|
+
http_client.receive_timeout = IO_TIMEOUT
|
36
|
+
http_client.connect_timeout = CONNECT_TIMEOUT
|
37
|
+
|
38
|
+
if @options['user'] && @options['password']
|
39
|
+
http_client.set_auth(@base_uri, @options['user'], @options['password'])
|
40
|
+
end
|
41
|
+
|
42
|
+
http_client.request(method, @base_uri + uri,
|
43
|
+
:body => payload, :header => headers)
|
44
|
+
|
45
|
+
rescue URI::Error, SocketError, Errno::ECONNREFUSED => e
|
46
|
+
raise Error, "cannot access agent (%s)" % [ e.message ]
|
47
|
+
rescue SystemCallError => e
|
48
|
+
raise Error, "System call error while talking to agent: #{e}"
|
49
|
+
rescue ::HTTPClient::BadResponseError => e
|
50
|
+
raise Error, "Received bad HTTP response from agent: #{e}"
|
51
|
+
rescue => e
|
52
|
+
raise Error, "Agent call exception: #{e}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def post_json(url, payload)
|
56
|
+
response = request(:post, url, "application/json", payload)
|
57
|
+
status = response.code
|
58
|
+
raise AuthError, "Authentication failed" if status == 401
|
59
|
+
raise Error, "Agent HTTP #{status}" if status != 200
|
60
|
+
Yajl::Parser.parse(response.body)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/agent_client.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Bosh; module Agent; end; end
|
2
|
+
|
3
|
+
require "agent_client/version"
|
4
|
+
require "agent_client/errors"
|
5
|
+
require "agent_client/base"
|
6
|
+
require "agent_client/http_client"
|
7
|
+
|
8
|
+
require "uri"
|
9
|
+
require "yajl"
|
10
|
+
|
11
|
+
module Bosh
|
12
|
+
module Agent
|
13
|
+
class Client
|
14
|
+
def self.create(uri, options = { })
|
15
|
+
scheme = URI.parse(uri).scheme
|
16
|
+
case scheme
|
17
|
+
when "http"
|
18
|
+
HTTPClient.new(uri, options)
|
19
|
+
else
|
20
|
+
raise "Invalid client scheme, available providers are: 'http'"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Bosh::Agent::HTTPClient do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@httpclient = mock("httpclient")
|
7
|
+
HTTPClient.stub!(:new).and_return(@httpclient)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "options" do
|
11
|
+
|
12
|
+
it "should set up authentication when present" do
|
13
|
+
response = mock("response")
|
14
|
+
response.stub!(:code).and_return(200)
|
15
|
+
response.stub!(:body).and_return('{"value": "pong"}')
|
16
|
+
|
17
|
+
[:send_timeout=, :receive_timeout=, :connect_timeout=].each do |method|
|
18
|
+
@httpclient.should_receive(method)
|
19
|
+
end
|
20
|
+
|
21
|
+
@httpclient.should_receive(:set_auth).with("http://localhost", "john", "smith")
|
22
|
+
@httpclient.should_receive(:request).and_return(response)
|
23
|
+
|
24
|
+
@client = Bosh::Agent::HTTPClient.new("http://localhost",
|
25
|
+
{ "user" => "john",
|
26
|
+
"password" => "smith" })
|
27
|
+
@client.ping
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should encode arguments" do
|
31
|
+
response = mock("response")
|
32
|
+
response.stub!(:code).and_return(200)
|
33
|
+
response.stub!(:body).and_return('{"value": "iam"}')
|
34
|
+
|
35
|
+
[:send_timeout=, :receive_timeout=, :connect_timeout=].each do |method|
|
36
|
+
@httpclient.should_receive(method)
|
37
|
+
end
|
38
|
+
|
39
|
+
headers = { "Content-Type" => "application/json" }
|
40
|
+
payload = '{"method":"shh","arguments":["hunting","wabbits"],"reply_to":"elmer"}'
|
41
|
+
|
42
|
+
@httpclient.should_receive(:request).with(:post, "http://localhost/agent",
|
43
|
+
:body => payload, :header => headers).and_return(response)
|
44
|
+
|
45
|
+
@client = Bosh::Agent::HTTPClient.new("http://localhost", {"reply_to" => "elmer"})
|
46
|
+
|
47
|
+
@client.shh("hunting", "wabbits").should == "iam"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should receive a message value" do
|
51
|
+
response = mock("response")
|
52
|
+
response.stub!(:code).and_return(200)
|
53
|
+
response.stub!(:body).and_return('{"value": "pong"}')
|
54
|
+
|
55
|
+
[:send_timeout=, :receive_timeout=, :connect_timeout=].each do |method|
|
56
|
+
@httpclient.should_receive(method)
|
57
|
+
end
|
58
|
+
|
59
|
+
headers = { "Content-Type" => "application/json" }
|
60
|
+
payload = '{"method":"ping","arguments":[],"reply_to":"fudd"}'
|
61
|
+
|
62
|
+
@httpclient.should_receive(:request).with(:post, "http://localhost/agent",
|
63
|
+
:body => payload, :header => headers).and_return(response)
|
64
|
+
|
65
|
+
@client = Bosh::Agent::HTTPClient.new("http://localhost", {"reply_to" => "fudd"})
|
66
|
+
|
67
|
+
@client.ping.should == "pong"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should run_task" do
|
71
|
+
response = mock("response")
|
72
|
+
response.stub!(:code).and_return(200)
|
73
|
+
response.stub!(:body).and_return('{"value": {"state": "running", "agent_task_id": "task_id_foo"}}')
|
74
|
+
|
75
|
+
[:send_timeout=, :receive_timeout=, :connect_timeout=].each do |method|
|
76
|
+
@httpclient.should_receive(method)
|
77
|
+
end
|
78
|
+
|
79
|
+
headers = { "Content-Type" => "application/json" }
|
80
|
+
payload = '{"method":"compile_package","arguments":["id","sha1"],"reply_to":"bugs"}'
|
81
|
+
|
82
|
+
@httpclient.should_receive(:request).with(:post, "http://localhost/agent",
|
83
|
+
:body => payload, :header => headers).and_return(response)
|
84
|
+
|
85
|
+
response2 = mock("response2")
|
86
|
+
response2.stub!(:code).and_return(200)
|
87
|
+
response2.stub!(:body).and_return('{"value": {"state": "done"}')
|
88
|
+
|
89
|
+
payload = '{"method":"get_task","arguments":["task_id_foo"],"reply_to":"bugs"}'
|
90
|
+
|
91
|
+
[:send_timeout=, :receive_timeout=, :connect_timeout=].each do |method|
|
92
|
+
@httpclient.should_receive(method)
|
93
|
+
end
|
94
|
+
|
95
|
+
@httpclient.should_receive(:request).with(:post, "http://localhost/agent",
|
96
|
+
:body => payload, :header => headers).and_return(response2)
|
97
|
+
|
98
|
+
@client = Bosh::Agent::HTTPClient.new("http://localhost", {"reply_to" => "bugs"})
|
99
|
+
|
100
|
+
@client.run_task(:compile_package, "id", "sha1").should == { "state" => "done" }
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should raise handler exception when method is invalid" do
|
104
|
+
response = mock("response")
|
105
|
+
response.stub!(:code).and_return(200)
|
106
|
+
response.stub!(:body).and_return('{"exception": "no such method"}')
|
107
|
+
|
108
|
+
[:send_timeout=, :receive_timeout=, :connect_timeout=].each do |method|
|
109
|
+
@httpclient.should_receive(method)
|
110
|
+
end
|
111
|
+
|
112
|
+
@httpclient.should_receive(:request).and_return(response)
|
113
|
+
|
114
|
+
@client = Bosh::Agent::HTTPClient.new("http://localhost")
|
115
|
+
|
116
|
+
lambda { @client.no_such_method }.should raise_error(Bosh::Agent::HandlerError)
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should raise authentication exception when 401 is returned" do
|
121
|
+
response = mock("response")
|
122
|
+
response.stub!(:code).and_return(401)
|
123
|
+
|
124
|
+
[:send_timeout=, :receive_timeout=, :connect_timeout=].each do |method|
|
125
|
+
@httpclient.should_receive(method)
|
126
|
+
end
|
127
|
+
|
128
|
+
@httpclient.should_receive(:request).and_return(response)
|
129
|
+
|
130
|
+
@client = Bosh::Agent::HTTPClient.new("http://localhost")
|
131
|
+
|
132
|
+
lambda { @client.ping }.should raise_error(Bosh::Agent::AuthError)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: agent_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- VMware
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-13 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: httpclient
|
16
|
+
requirement: &18710880 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *18710880
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: yajl-ruby
|
27
|
+
requirement: &18710200 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *18710200
|
36
|
+
description: BOSH agent client
|
37
|
+
email: support@vmware.com
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
extra_rdoc_files: []
|
41
|
+
files:
|
42
|
+
- lib/agent_client.rb
|
43
|
+
- lib/agent_client/base.rb
|
44
|
+
- lib/agent_client/errors.rb
|
45
|
+
- lib/agent_client/http_client.rb
|
46
|
+
- lib/agent_client/version.rb
|
47
|
+
- README
|
48
|
+
- Rakefile
|
49
|
+
- spec/spec_helper.rb
|
50
|
+
- spec/unit/http_agent_client_spec.rb
|
51
|
+
homepage: http://www.vmware.com
|
52
|
+
licenses: []
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
hash: 12617920935854716
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
hash: 12617920935854716
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.8.10
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: BOSH agent client
|
81
|
+
test_files:
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
- spec/unit/http_agent_client_spec.rb
|