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 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,9 @@
1
+ module Bosh
2
+ module Agent
3
+
4
+ class Error < StandardError; end
5
+ class AuthError < Error; end
6
+ class HandlerError < StandardError; end
7
+
8
+ end
9
+ 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
@@ -0,0 +1,7 @@
1
+ module Bosh
2
+ module Agent
3
+ class Client
4
+ VERSION = "0.1.1"
5
+ end
6
+ end
7
+ end
@@ -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
@@ -0,0 +1,10 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
4
+
5
+ require "rubygems"
6
+ require "bundler"
7
+ Bundler.setup(:default, :test)
8
+
9
+ require "rspec"
10
+ require "agent_client"
@@ -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