jfoundry 0.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/LICENSE +746 -0
  2. data/Rakefile +10 -0
  3. data/lib/cc_api_stub/applications.rb +53 -0
  4. data/lib/cc_api_stub/domains.rb +32 -0
  5. data/lib/cc_api_stub/frameworks.rb +22 -0
  6. data/lib/cc_api_stub/helper.rb +139 -0
  7. data/lib/cc_api_stub/login.rb +21 -0
  8. data/lib/cc_api_stub/organization_users.rb +21 -0
  9. data/lib/cc_api_stub/organizations.rb +70 -0
  10. data/lib/cc_api_stub/routes.rb +26 -0
  11. data/lib/cc_api_stub/runtimes.rb +22 -0
  12. data/lib/cc_api_stub/service_bindings.rb +22 -0
  13. data/lib/cc_api_stub/service_instances.rb +22 -0
  14. data/lib/cc_api_stub/services.rb +21 -0
  15. data/lib/cc_api_stub/spaces.rb +49 -0
  16. data/lib/cc_api_stub/users.rb +85 -0
  17. data/lib/cc_api_stub.rb +16 -0
  18. data/lib/jfoundry/auth_token.rb +63 -0
  19. data/lib/jfoundry/baseclient.rb +177 -0
  20. data/lib/jfoundry/chatty_hash.rb +46 -0
  21. data/lib/jfoundry/client.rb +39 -0
  22. data/lib/jfoundry/concerns/proxy_options.rb +17 -0
  23. data/lib/jfoundry/errors.rb +163 -0
  24. data/lib/jfoundry/rest_client.rb +331 -0
  25. data/lib/jfoundry/signature/version.rb +27 -0
  26. data/lib/jfoundry/signer.rb +13 -0
  27. data/lib/jfoundry/test_support.rb +3 -0
  28. data/lib/jfoundry/timer.rb +13 -0
  29. data/lib/jfoundry/trace_helpers.rb +64 -0
  30. data/lib/jfoundry/upload_helpers.rb +222 -0
  31. data/lib/jfoundry/v2/app.rb +357 -0
  32. data/lib/jfoundry/v2/app_event.rb +13 -0
  33. data/lib/jfoundry/v2/base.rb +92 -0
  34. data/lib/jfoundry/v2/client.rb +78 -0
  35. data/lib/jfoundry/v2/domain.rb +20 -0
  36. data/lib/jfoundry/v2/managed_service_instance.rb +13 -0
  37. data/lib/jfoundry/v2/model.rb +209 -0
  38. data/lib/jfoundry/v2/model_magic/attribute.rb +49 -0
  39. data/lib/jfoundry/v2/model_magic/client_extensions.rb +170 -0
  40. data/lib/jfoundry/v2/model_magic/has_summary.rb +49 -0
  41. data/lib/jfoundry/v2/model_magic/queryable_by.rb +39 -0
  42. data/lib/jfoundry/v2/model_magic/to_many.rb +138 -0
  43. data/lib/jfoundry/v2/model_magic/to_one.rb +81 -0
  44. data/lib/jfoundry/v2/model_magic.rb +93 -0
  45. data/lib/jfoundry/v2/organization.rb +22 -0
  46. data/lib/jfoundry/v2/quota_definition.rb +12 -0
  47. data/lib/jfoundry/v2/route.rb +25 -0
  48. data/lib/jfoundry/v2/service.rb +20 -0
  49. data/lib/jfoundry/v2/service_auth_token.rb +10 -0
  50. data/lib/jfoundry/v2/service_binding.rb +10 -0
  51. data/lib/jfoundry/v2/service_broker.rb +11 -0
  52. data/lib/jfoundry/v2/service_instance.rb +13 -0
  53. data/lib/jfoundry/v2/service_plan.rb +13 -0
  54. data/lib/jfoundry/v2/space.rb +18 -0
  55. data/lib/jfoundry/v2/stack.rb +10 -0
  56. data/lib/jfoundry/v2/user.rb +104 -0
  57. data/lib/jfoundry/v2/user_provided_service_instance.rb +7 -0
  58. data/lib/jfoundry/validator.rb +41 -0
  59. data/lib/jfoundry/version.rb +4 -0
  60. data/lib/jfoundry/zip.rb +56 -0
  61. data/lib/jfoundry.rb +5 -0
  62. data/lib/tasks/gem_release.rake +42 -0
  63. data/vendor/errors/README.md +3 -0
  64. data/vendor/errors/v1.yml +189 -0
  65. data/vendor/errors/v2.yml +470 -0
  66. metadata +269 -0
@@ -0,0 +1,63 @@
1
+ module JFoundry
2
+ class AuthToken
3
+ class << self
4
+ def from_uaa_token_info(token_info)
5
+ new(
6
+ token_info.auth_header,
7
+ token_info.info[:refresh_token]
8
+ )
9
+ end
10
+
11
+ def from_hash(hash)
12
+ new(
13
+ hash[:token],
14
+ hash[:refresh_token]
15
+ )
16
+ end
17
+ end
18
+
19
+ def initialize(auth_header, refresh_token = nil)
20
+ @auth_header = auth_header
21
+ @refresh_token = refresh_token
22
+ end
23
+
24
+ attr_accessor :auth_header
25
+ attr_reader :refresh_token
26
+
27
+ def to_hash
28
+ {
29
+ :token => auth_header,
30
+ :refresh_token => @refresh_token
31
+ }
32
+ end
33
+
34
+ JSON_HASH = /\{.*?\}/.freeze
35
+
36
+ # TODO: rename to #data
37
+ def token_data
38
+ return @token_data if @token_data
39
+ return {} unless @auth_header
40
+
41
+ json_hashes = Base64.decode64(@auth_header.split(" ", 2).last)
42
+ data_json = json_hashes.sub(JSON_HASH, "")[JSON_HASH]
43
+ return {} unless data_json
44
+
45
+ @token_data = MultiJson.load data_json, :symbolize_keys => true
46
+ rescue MultiJson::DecodeError
47
+ {}
48
+ end
49
+
50
+ def auth_header=(auth_header)
51
+ @token_data = nil
52
+ @auth_header = auth_header
53
+ end
54
+
55
+ def expiration
56
+ Time.at(token_data[:exp])
57
+ end
58
+
59
+ def expires_soon?
60
+ (expiration.to_i - Time.now.to_i) < 60
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,177 @@
1
+ require "jfoundry/trace_helpers"
2
+ require "net/https"
3
+ require "net/http/post/multipart"
4
+ require "multi_json"
5
+ require "fileutils"
6
+ require "forwardable"
7
+
8
+ module JFoundry
9
+ class BaseClient # :nodoc:
10
+ include JFoundry::ProxyOptions
11
+
12
+ extend Forwardable
13
+
14
+ attr_reader :rest_client
15
+
16
+ def_delegators :rest_client, :target, :target=, :access_key, :secret_key, :version, #:token,
17
+ :trace, :backtrace, :backtrace=, :log, :log=,
18
+ :http_proxy, :http_proxy=, :https_proxy, :https_proxy=
19
+
20
+ def initialize(target, access_key, secret_key, version)
21
+ @rest_client = JFoundry::RestClient.new(target, access_key, secret_key, version)
22
+ self.trace = false
23
+ self.backtrace = false
24
+ self.log = false
25
+ end
26
+
27
+ def trace=(trace)
28
+ @rest_client.trace = trace
29
+ #@uaa.trace = trace if @uaa
30
+ end
31
+
32
+ # Cloud metadata
33
+ def info
34
+ get("info", :accept => :json)
35
+ end
36
+
37
+ def get(*args)
38
+ request("GET", *args)
39
+ end
40
+
41
+ def delete(*args)
42
+ request("DELETE", *args)
43
+ end
44
+
45
+ def post(*args)
46
+ request("POST", *args)
47
+ end
48
+
49
+ def put(*args)
50
+ request("PUT", *args)
51
+ end
52
+
53
+ def request(method, *args)
54
+ #puts "args: ", args
55
+ path, options = normalize_arguments(args)
56
+ #puts "path: ", path
57
+ #puts "options: ", options
58
+ request, response = request_raw(method, path, options)
59
+ handle_response(response, options, request)
60
+ end
61
+
62
+ def request_raw(method, path, options)
63
+ @rest_client.request(method, path, options)
64
+ end
65
+
66
+ def stream_url(url, &blk)
67
+ uri = URI.parse(url)
68
+
69
+ opts = {}
70
+
71
+ if uri.scheme == "https"
72
+ opts[:use_ssl] = true
73
+ opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
74
+ end
75
+
76
+ Net::HTTP.start(uri.host, uri.port, *proxy_options_for(uri), opts) do |http|
77
+ http.read_timeout = 5
78
+
79
+ req = Net::HTTP::Get.new(uri.request_uri)
80
+ #req["Authorization"] = token.auth_header if token
81
+
82
+ http.request(req) do |response|
83
+ case response
84
+ when Net::HTTPOK
85
+ response.read_body(&blk)
86
+ when Net::HTTPNotFound
87
+ raise JFoundry::NotFound.new(response.body, 404)
88
+ when Net::HTTPForbidden
89
+ raise JFoundry::Denied.new(response.body, 403)
90
+ when Net::HTTPUnauthorized
91
+ raise JFoundry::Unauthorized.new(response.body, 401)
92
+ else
93
+ raise JFoundry::BadResponse.new(response.body, response.code)
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ private
100
+
101
+ def status_is_successful?(code)
102
+ (code >= 200) && (code < 400)
103
+ end
104
+
105
+ def handle_response(response, options, request)
106
+ if status_is_successful?(response[:status].to_i)
107
+ handle_successful_response(response, options)
108
+ else
109
+ handle_error_response(response, request)
110
+ end
111
+ end
112
+
113
+ def handle_successful_response(response, options)
114
+ if options[:return_response]
115
+ response
116
+ elsif options[:accept] == :json
117
+ parse_json(response[:body])
118
+ else
119
+ response[:body]
120
+ end
121
+ end
122
+
123
+ def handle_error_response(response, request)
124
+ body_json = parse_json(response[:body])
125
+ body_code = body_json && body_json[:code]
126
+ code = body_code || response[:status].to_i
127
+
128
+ if body_code
129
+ error_class = JFoundry::APIError.error_classes[body_code] || JFoundry::APIError
130
+ raise error_class.new(body_json[:description], body_code, request, response)
131
+ end
132
+
133
+ case code
134
+ when 404
135
+ raise JFoundry::NotFound.new(nil, code, request, response)
136
+ when 403
137
+ raise JFoundry::Denied.new(nil, code, request, response)
138
+ when 401
139
+ raise JFoundry::Unauthorized.new(nil, code, request, response)
140
+ else
141
+ raise JFoundry::BadResponse.new(nil, code, request, response)
142
+ end
143
+ end
144
+
145
+ def normalize_arguments(args)
146
+ if args.last.is_a?(Hash)
147
+ options = args.pop
148
+ else
149
+ options = {}
150
+ end
151
+
152
+ [normalize_path(args), options]
153
+ end
154
+
155
+ URI_ENCODING_PATTERN = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
156
+
157
+ def normalize_path(segments)
158
+ if segments.size == 1 && segments.first =~ /^\//
159
+ segments.first
160
+ else
161
+ segments.flatten.collect { |x|
162
+ URI.encode(x.to_s, URI_ENCODING_PATTERN)
163
+ }.join("/")
164
+ end
165
+ end
166
+
167
+ def parse_json(x)
168
+ if x.empty?
169
+ raise MultiJson::DecodeError.new("Empty JSON string", [], "")
170
+ else
171
+ MultiJson.load(x, :symbolize_keys => true)
172
+ end
173
+ rescue MultiJson::DecodeError
174
+ nil
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,46 @@
1
+ module JFoundry
2
+ class ChattyHash
3
+ include Enumerable
4
+
5
+ def initialize(callback, hash = {})
6
+ @callback = callback
7
+ @hash = hash
8
+ end
9
+
10
+ def [](name)
11
+ @hash[name]
12
+ end
13
+
14
+ def []=(name, value)
15
+ @hash[name] = value
16
+ @callback.call(self)
17
+ value
18
+ end
19
+
20
+ def each(&blk)
21
+ @hash.each(&blk)
22
+ end
23
+
24
+ def delete(key)
25
+ value = @hash.delete(key)
26
+ @callback.call(self)
27
+ value
28
+ end
29
+
30
+ def to_json(*args)
31
+ @hash.to_json(*args)
32
+ end
33
+
34
+ def to_hash
35
+ @hash
36
+ end
37
+
38
+ def to_s
39
+ @hash.to_s
40
+ end
41
+
42
+ def inspect
43
+ @hash.inspect
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,39 @@
1
+ require "jfoundry/concerns/proxy_options"
2
+
3
+ require "jfoundry/baseclient"
4
+ require "jfoundry/rest_client"
5
+ #require "jfoundry/auth_token"
6
+
7
+ require "jfoundry/v2/app"
8
+ require "jfoundry/v2/service"
9
+ require "jfoundry/v2/service_binding"
10
+ require "jfoundry/v2/managed_service_instance"
11
+ require "jfoundry/v2/user_provided_service_instance"
12
+ require "jfoundry/v2/service_plan"
13
+ #require "jfoundry/v2/service_auth_token"
14
+ require "jfoundry/v2/user"
15
+ require "jfoundry/v2/organization"
16
+ require "jfoundry/v2/space"
17
+ require "jfoundry/v2/domain"
18
+ require "jfoundry/v2/route"
19
+ require "jfoundry/v2/stack"
20
+ require "jfoundry/v2/quota_definition"
21
+ require "jfoundry/v2/app_event"
22
+ require "jfoundry/v2/service_broker"
23
+
24
+ require "jfoundry/v2/base"
25
+ require "jfoundry/v2/client"
26
+ #require "jfoundry/v2/fake_client"
27
+
28
+ module JFoundry
29
+ class Client < BaseClient
30
+ def self.new(*args)
31
+ warn "DEPRECATION WARNING: Please use JFoundry::Client.get instead of JFoundry::Client.new"
32
+ get(*args)
33
+ end
34
+
35
+ def self.get(*args)
36
+ JFoundry::V2::Client.new(*args).tap { |client| client.info }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ module JFoundry
2
+ module ProxyOptions
3
+ def proxy_options_for(uri)
4
+ ssl = uri.is_a?(URI::HTTPS)
5
+ proxy_to_use = (ssl ? https_proxy : http_proxy)
6
+
7
+ if proxy_to_use.blank?
8
+ []
9
+ else
10
+ proxy_to_use = "proto://#{proxy_to_use}" unless proxy_to_use =~ /:\/\//
11
+ proxy_uri = URI.parse(proxy_to_use)
12
+ proxy_user, proxy_password = proxy_uri.userinfo.split(/:/) if proxy_uri.userinfo
13
+ [proxy_uri.host, proxy_uri.port, proxy_user, proxy_password]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,163 @@
1
+ require "net/https"
2
+ require "multi_json"
3
+ require "yaml"
4
+
5
+ module JFoundry
6
+ # Base class for JFoundry errors (not from the server).
7
+ class Error < RuntimeError
8
+ end
9
+
10
+ class Deprecated < Error
11
+ end
12
+
13
+ class Mismatch < Error
14
+ def initialize(expected, got)
15
+ @expected = expected
16
+ @got = got
17
+ end
18
+
19
+ def to_s
20
+ "Invalid value type; expected #{@expected.inspect}, got #{@got.inspect}"
21
+ end
22
+ end
23
+
24
+ class InvalidTarget < Error
25
+ attr_reader :target
26
+
27
+ def initialize(target)
28
+ @target = target
29
+ end
30
+
31
+ def to_s
32
+ "Invalid target URI: #{@target}"
33
+ end
34
+ end
35
+
36
+ class TargetRefused < Error
37
+ # Error message.
38
+ attr_reader :message
39
+
40
+ # Message varies as this represents various network errors.
41
+ def initialize(message)
42
+ @message = message
43
+ end
44
+
45
+ # Exception message.
46
+ def to_s
47
+ "target refused connection (#@message)"
48
+ end
49
+ end
50
+
51
+ class Timeout < Timeout::Error
52
+ attr_reader :method, :uri, :parent
53
+
54
+ def initialize(method, uri, parent = nil)
55
+ @method = method
56
+ @uri = uri
57
+ @parent = parent
58
+ super(to_s)
59
+ end
60
+
61
+ def to_s
62
+ "#{method} #{uri} timed out"
63
+ end
64
+ end
65
+
66
+ # Exception representing errors returned by the API.
67
+ class APIError < RuntimeError
68
+ include TraceHelpers
69
+
70
+ class << self
71
+ def error_classes
72
+ @error_classes ||= {}
73
+ end
74
+ end
75
+
76
+ attr_reader :error_code, :description, :request, :response
77
+
78
+ # Create an APIError with a given request and response.
79
+ def initialize(description = nil, error_code = nil, request = nil, response = nil)
80
+ @response = response
81
+ @request = request
82
+ @error_code = error_code || (response ? response[:status] : nil)
83
+ @description = description || parse_description
84
+ end
85
+
86
+ # Exception message.
87
+ def to_s
88
+ "#{error_code}: #{description}"
89
+ end
90
+
91
+ def request_trace
92
+ super(request)
93
+ end
94
+
95
+ def response_trace
96
+ super(response)
97
+ end
98
+
99
+ private
100
+
101
+ def parse_description
102
+ return unless response
103
+
104
+ parse_json(response[:body])[:description]
105
+ rescue MultiJson::DecodeError
106
+ response[:body]
107
+ end
108
+
109
+ def parse_json(x)
110
+ if x.empty?
111
+ raise MultiJson::DecodeError.new("Empty JSON string", [], "")
112
+ else
113
+ MultiJson.load(x, :symbolize_keys => true)
114
+ end
115
+ end
116
+ end
117
+
118
+ class NotFound < APIError
119
+ end
120
+
121
+ class Denied < APIError
122
+ end
123
+
124
+ class Unauthorized < APIError
125
+ end
126
+
127
+ class BadResponse < APIError
128
+ end
129
+
130
+ class UAAError < APIError
131
+ end
132
+
133
+ def self.define_error(class_name, code)
134
+ base =
135
+ case class_name
136
+ when /NotFound$/
137
+ NotFound
138
+ else
139
+ APIError
140
+ end
141
+
142
+ klass =
143
+ if const_defined?(class_name)
144
+ const_get(class_name)
145
+ else
146
+ Class.new(base)
147
+ end
148
+
149
+ APIError.error_classes[code] = klass
150
+
151
+ unless const_defined?(class_name)
152
+ const_set(class_name, klass)
153
+ end
154
+ end
155
+
156
+ VENDOR_DIR = File.expand_path("../../../vendor", __FILE__)
157
+
158
+ %w{errors/v1.yml errors/v2.yml}.each do |errors|
159
+ YAML.load_file("#{VENDOR_DIR}/#{errors}").each do |code, meta|
160
+ define_error(meta["name"], code)
161
+ end
162
+ end
163
+ end