jfoundry 0.1.0.pre

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 (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