nucleus 0.2.0 → 0.3.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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +9 -0
  4. data/README.md +43 -72
  5. data/lib/nucleus/adapter_resolver.rb +3 -3
  6. data/lib/nucleus/adapters/base_adapter.rb +109 -109
  7. data/lib/nucleus/adapters/v1/cloud_foundry_v2/application.rb +111 -111
  8. data/lib/nucleus/adapters/v1/cloud_foundry_v2/cloud_foundry_v2.rb +141 -141
  9. data/lib/nucleus/adapters/v1/cloud_foundry_v2/data.rb +97 -97
  10. data/lib/nucleus/adapters/v1/cloud_foundry_v2/domains.rb +5 -5
  11. data/lib/nucleus/adapters/v1/cloud_foundry_v2/lifecycle.rb +41 -41
  12. data/lib/nucleus/adapters/v1/cloud_foundry_v2/logs.rb +6 -6
  13. data/lib/nucleus/adapters/v1/cloud_foundry_v2/regions.rb +33 -33
  14. data/lib/nucleus/adapters/v1/cloud_foundry_v2/services.rb +6 -6
  15. data/lib/nucleus/adapters/v1/cloud_foundry_v2/vars.rb +80 -80
  16. data/lib/nucleus/adapters/v1/heroku/app_states.rb +57 -57
  17. data/lib/nucleus/adapters/v1/heroku/data.rb +78 -78
  18. data/lib/nucleus/adapters/v1/heroku/heroku.rb +146 -146
  19. data/lib/nucleus/adapters/v1/heroku/lifecycle.rb +51 -51
  20. data/lib/nucleus/adapters/v1/heroku/logs.rb +2 -2
  21. data/lib/nucleus/adapters/v1/heroku/regions.rb +42 -42
  22. data/lib/nucleus/adapters/v1/heroku/services.rb +168 -168
  23. data/lib/nucleus/adapters/v1/heroku/vars.rb +65 -65
  24. data/lib/nucleus/adapters/v1/openshift_v2/app_states.rb +68 -68
  25. data/lib/nucleus/adapters/v1/openshift_v2/application.rb +1 -1
  26. data/lib/nucleus/adapters/v1/openshift_v2/data.rb +96 -96
  27. data/lib/nucleus/adapters/v1/openshift_v2/lifecycle.rb +60 -60
  28. data/lib/nucleus/adapters/v1/openshift_v2/logs.rb +106 -106
  29. data/lib/nucleus/adapters/v1/openshift_v2/openshift_v2.rb +125 -125
  30. data/lib/nucleus/adapters/v1/openshift_v2/regions.rb +58 -58
  31. data/lib/nucleus/adapters/v1/openshift_v2/services.rb +173 -173
  32. data/lib/nucleus/adapters/v1/openshift_v2/vars.rb +49 -49
  33. data/lib/nucleus/adapters/v1/stub_adapter.rb +464 -464
  34. data/lib/nucleus/core/adapter_extensions/auth/auth_client.rb +44 -44
  35. data/lib/nucleus/core/adapter_extensions/auth/expiring_token_auth_client.rb +53 -53
  36. data/lib/nucleus/core/adapter_extensions/auth/http_basic_auth_client.rb +3 -3
  37. data/lib/nucleus/core/adapter_extensions/auth/o_auth2_auth_client.rb +95 -95
  38. data/lib/nucleus/core/adapter_extensions/auth/token_auth_client.rb +36 -36
  39. data/lib/nucleus/core/adapter_extensions/http_client.rb +5 -5
  40. data/lib/nucleus/core/common/files/archive_extractor.rb +1 -1
  41. data/lib/nucleus/core/common/files/archiver.rb +2 -2
  42. data/lib/nucleus/core/file_handling/file_manager.rb +64 -64
  43. data/lib/nucleus/core/file_handling/git_deployer.rb +133 -133
  44. data/lib/nucleus/core/import/adapter_configuration.rb +53 -53
  45. data/lib/nucleus/scripts/initialize_config_defaults.rb +26 -26
  46. data/lib/nucleus/version.rb +1 -1
  47. data/nucleus.gemspec +2 -2
  48. data/spec/integration/api/auth_spec.rb +3 -3
  49. data/spec/spec_helper.rb +98 -98
  50. data/spec/test_suites.rake +1 -1
  51. data/spec/unit/adapters/git_deployer_spec.rb +262 -262
  52. data/spec/unit/common/helpers/auth_helper_spec.rb +1 -1
  53. data/tasks/evaluation.rake +1 -1
  54. data/wiki/adapter_tests.md +0 -7
  55. data/wiki/implement_new_adapter.md +1 -1
  56. metadata +4 -20
  57. data/config/adapters/cloud_control.yml +0 -32
  58. data/lib/nucleus/adapters/v1/cloud_control/application.rb +0 -108
  59. data/lib/nucleus/adapters/v1/cloud_control/authentication.rb +0 -27
  60. data/lib/nucleus/adapters/v1/cloud_control/buildpacks.rb +0 -23
  61. data/lib/nucleus/adapters/v1/cloud_control/cloud_control.rb +0 -153
  62. data/lib/nucleus/adapters/v1/cloud_control/data.rb +0 -76
  63. data/lib/nucleus/adapters/v1/cloud_control/domains.rb +0 -68
  64. data/lib/nucleus/adapters/v1/cloud_control/lifecycle.rb +0 -27
  65. data/lib/nucleus/adapters/v1/cloud_control/log_poller.rb +0 -71
  66. data/lib/nucleus/adapters/v1/cloud_control/logs.rb +0 -103
  67. data/lib/nucleus/adapters/v1/cloud_control/regions.rb +0 -32
  68. data/lib/nucleus/adapters/v1/cloud_control/scaling.rb +0 -17
  69. data/lib/nucleus/adapters/v1/cloud_control/semantic_errors.rb +0 -31
  70. data/lib/nucleus/adapters/v1/cloud_control/services.rb +0 -162
  71. data/lib/nucleus/adapters/v1/cloud_control/token.rb +0 -17
  72. data/lib/nucleus/adapters/v1/cloud_control/vars.rb +0 -88
@@ -1,111 +1,111 @@
1
- module Nucleus
2
- module Adapters
3
- module V1
4
- class CloudFoundryV2 < Stub
5
- module Application
6
- # @see Stub#applications
7
- def applications
8
- response = get('/v2/apps')
9
- apps = []
10
- response.body[:resources].each do |application_resource|
11
- apps << to_nucleus_app(application_resource)
12
- end
13
- apps
14
- end
15
-
16
- # @see Stub#application
17
- def application(application_name_or_id)
18
- app_guid = app_guid(application_name_or_id)
19
- get_response = get("/v2/apps/#{app_guid}")
20
- to_nucleus_app(get_response.body)
21
- end
22
-
23
- # @see Stub#create_application
24
- def create_application(application)
25
- if application.key? :region
26
- unless application[:region].casecmp('default') == 0
27
- fail Errors::SemanticAdapterRequestError,
28
- "Region '#{application[:region]}' does not exist at the endpoint. "\
29
- 'Please check which regions are actually available on this endpoint.'
30
- end
31
- # there is no region in Cloud Foundry --> remove from request
32
- application.delete :region
33
- end
34
-
35
- apply_buildpack(application)
36
-
37
- # apply default values, if not overridden by custom params
38
- default_params = { space_guid: user_space_guid }
39
- application = default_params.merge(application)
40
-
41
- # WORKAROUND: requires numeric input, but rack-test provides characters :/
42
- application['memory'] = application['memory'].to_i if application.key?('memory')
43
-
44
- response = post('/v2/apps', body: application).body
45
-
46
- # now create the default route (similar to when using an UI, e.g. Pivotal, Stackato or Bluemix) == web_url
47
- create_cf_domain(response[:metadata][:guid], @endpoint_app_domain, response[:metadata][:guid])
48
-
49
- # finally build the application response
50
- application(response[:metadata][:guid])
51
- end
52
-
53
- # @see Stub#update_application
54
- def update_application(application_name_or_id, application_form)
55
- app_guid = app_guid(application_name_or_id)
56
- apply_buildpack(application_form)
57
- # update by guid
58
- update_response = put("/v2/apps/#{app_guid}", body: application_form)
59
- to_nucleus_app(update_response.body)
60
- end
61
-
62
- # @see Stub#delete_application
63
- def delete_application(application_name_or_id)
64
- app_guid = app_guid(application_name_or_id)
65
- # first delete all service bindings
66
- remove_all_services(app_guid)
67
- # then delete the default route (otherwise it would remain as orphaned route)
68
- routes = get("/v2/apps/#{app_guid}/routes?q=host:#{app_guid}&inline-relations-depth=1").body[:resources]
69
- default_route = routes.find { |route| route[:entity][:domain][:entity][:name] == @endpoint_app_domain }
70
- delete("/v2/routes/#{default_route[:metadata][:guid]}") if default_route
71
- # and finally delete the app
72
- delete("/v2/apps/#{app_guid}")
73
- end
74
-
75
- private
76
-
77
- def apply_buildpack(application)
78
- # handle desired runtime(s)
79
- runtimes = application.delete(:runtimes)
80
- return unless runtimes
81
- fail_with(:only_one_runtime) if runtimes.length > 1
82
-
83
- buildpack = find_runtime(runtimes[0])
84
- # use the translated buildpack name if available, otherwise pass on the given runtime name
85
- application[:buildpack] = buildpack ? buildpack : runtimes[0]
86
- end
87
-
88
- def to_nucleus_app(app_resource)
89
- metadata = app_resource[:metadata]
90
- app = app_resource[:entity]
91
-
92
- app[:id] = metadata[:guid]
93
- app[:created_at] = metadata[:created_at]
94
- app[:updated_at] = metadata[:updated_at] || metadata[:created_at]
95
- app[:state] = application_state(app_resource)
96
- app[:web_url] = "http://#{app_web_url(metadata[:guid])}"
97
- # route could have been deleted by the user
98
- app[:web_url] = nil unless domain?(metadata[:guid], app[:web_url])
99
- # Stackato does support autoscaling
100
- app[:autoscaled] = app.delete(:autoscale_enabled) || false
101
- app[:region] = 'default'
102
- app[:active_runtime] = app[:detected_buildpack]
103
- app[:runtimes] = app[:buildpack] ? [app[:buildpack]] : []
104
- app[:release_version] = app.delete(:version)
105
- app
106
- end
107
- end
108
- end
109
- end
110
- end
111
- end
1
+ module Nucleus
2
+ module Adapters
3
+ module V1
4
+ class CloudFoundryV2 < Stub
5
+ module Application
6
+ # @see Stub#applications
7
+ def applications
8
+ response = get('/v2/apps')
9
+ apps = []
10
+ response.body[:resources].each do |application_resource|
11
+ apps << to_nucleus_app(application_resource)
12
+ end
13
+ apps
14
+ end
15
+
16
+ # @see Stub#application
17
+ def application(application_name_or_id)
18
+ app_guid = app_guid(application_name_or_id)
19
+ get_response = get("/v2/apps/#{app_guid}")
20
+ to_nucleus_app(get_response.body)
21
+ end
22
+
23
+ # @see Stub#create_application
24
+ def create_application(application)
25
+ if application.key? :region
26
+ unless application[:region].casecmp('default') == 0
27
+ raise Errors::SemanticAdapterRequestError,
28
+ "Region '#{application[:region]}' does not exist at the endpoint. "\
29
+ 'Please check which regions are actually available on this endpoint.'
30
+ end
31
+ # there is no region in Cloud Foundry --> remove from request
32
+ application.delete :region
33
+ end
34
+
35
+ apply_buildpack(application)
36
+
37
+ # apply default values, if not overridden by custom params
38
+ default_params = { space_guid: user_space_guid }
39
+ application = default_params.merge(application)
40
+
41
+ # WORKAROUND: requires numeric input, but rack-test provides characters :/
42
+ application['memory'] = application['memory'].to_i if application.key?('memory')
43
+
44
+ response = post('/v2/apps', body: application).body
45
+
46
+ # now create the default route (similar to when using an UI, e.g. Pivotal, Stackato or Bluemix) == web_url
47
+ create_cf_domain(response[:metadata][:guid], @endpoint_app_domain, response[:metadata][:guid])
48
+
49
+ # finally build the application response
50
+ application(response[:metadata][:guid])
51
+ end
52
+
53
+ # @see Stub#update_application
54
+ def update_application(application_name_or_id, application_form)
55
+ app_guid = app_guid(application_name_or_id)
56
+ apply_buildpack(application_form)
57
+ # update by guid
58
+ update_response = put("/v2/apps/#{app_guid}", body: application_form)
59
+ to_nucleus_app(update_response.body)
60
+ end
61
+
62
+ # @see Stub#delete_application
63
+ def delete_application(application_name_or_id)
64
+ app_guid = app_guid(application_name_or_id)
65
+ # first delete all service bindings
66
+ remove_all_services(app_guid)
67
+ # then delete the default route (otherwise it would remain as orphaned route)
68
+ routes = get("/v2/apps/#{app_guid}/routes?q=host:#{app_guid}&inline-relations-depth=1").body[:resources]
69
+ default_route = routes.find { |route| route[:entity][:domain][:entity][:name] == @endpoint_app_domain }
70
+ delete("/v2/routes/#{default_route[:metadata][:guid]}") if default_route
71
+ # and finally delete the app
72
+ delete("/v2/apps/#{app_guid}")
73
+ end
74
+
75
+ private
76
+
77
+ def apply_buildpack(application)
78
+ # handle desired runtime(s)
79
+ runtimes = application.delete(:runtimes)
80
+ return unless runtimes
81
+ fail_with(:only_one_runtime) if runtimes.length > 1
82
+
83
+ buildpack = find_runtime(runtimes[0])
84
+ # use the translated buildpack name if available, otherwise pass on the given runtime name
85
+ application[:buildpack] = buildpack ? buildpack : runtimes[0]
86
+ end
87
+
88
+ def to_nucleus_app(app_resource)
89
+ metadata = app_resource[:metadata]
90
+ app = app_resource[:entity]
91
+
92
+ app[:id] = metadata[:guid]
93
+ app[:created_at] = metadata[:created_at]
94
+ app[:updated_at] = metadata[:updated_at] || metadata[:created_at]
95
+ app[:state] = application_state(app_resource)
96
+ app[:web_url] = "http://#{app_web_url(metadata[:guid])}"
97
+ # route could have been deleted by the user
98
+ app[:web_url] = nil unless domain?(metadata[:guid], app[:web_url])
99
+ # Stackato does support autoscaling
100
+ app[:autoscaled] = app.delete(:autoscale_enabled) || false
101
+ app[:region] = 'default'
102
+ app[:active_runtime] = app[:detected_buildpack]
103
+ app[:runtimes] = app[:buildpack] ? [app[:buildpack]] : []
104
+ app[:release_version] = app.delete(:version)
105
+ app
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -1,141 +1,141 @@
1
- module Nucleus
2
- module Adapters
3
- module V1
4
- # The {CloudFoundryV2} adapter is designed to support the Cloud Foundry API and uses only commands
5
- # of the API version 2.<br>
6
- # <br>
7
- # Besides native Cloud Foundry installations, this adapter shall also work with forks, such as Stackato 3.4.2.<br>
8
- # <br>
9
- # The Nucleus API is fully supported, there are no known issues.
10
- # @see http://apidocs.cloudfoundry.org The latest Cloud Foundry API documentation
11
- class CloudFoundryV2 < Stub
12
- include Nucleus::Logging
13
- include Nucleus::Adapters::V1::CloudFoundryV2::Authentication
14
- include Nucleus::Adapters::V1::CloudFoundryV2::AppStates
15
- include Nucleus::Adapters::V1::CloudFoundryV2::Buildpacks
16
- include Nucleus::Adapters::V1::CloudFoundryV2::Application
17
- include Nucleus::Adapters::V1::CloudFoundryV2::Domains
18
- include Nucleus::Adapters::V1::CloudFoundryV2::Data
19
- include Nucleus::Adapters::V1::CloudFoundryV2::Lifecycle
20
- include Nucleus::Adapters::V1::CloudFoundryV2::Logs
21
- include Nucleus::Adapters::V1::CloudFoundryV2::Regions
22
- include Nucleus::Adapters::V1::CloudFoundryV2::Scaling
23
- include Nucleus::Adapters::V1::CloudFoundryV2::SemanticErrors
24
- include Nucleus::Adapters::V1::CloudFoundryV2::Services
25
- include Nucleus::Adapters::V1::CloudFoundryV2::Vars
26
-
27
- def initialize(endpoint_url, endpoint_app_domain = nil, check_certificates = true)
28
- super(endpoint_url, endpoint_app_domain, check_certificates)
29
- end
30
-
31
- def handle_error(error)
32
- cf_error = error.body.is_a?(Hash) ? error.body[:code] : nil
33
- case error.status
34
- when 400
35
- handle_400_error(error, cf_error)
36
- when 404
37
- fail Errors::AdapterResourceNotFoundError, error.body[:description] if cf_error > 10_000
38
- else
39
- if [1001].include? cf_error
40
- fail Errors::AdapterRequestError, "#{error.body[:description]} (#{cf_error} - #{error.body[:error_code]})"
41
- elsif [10_002].include?(cf_error) || error.status == 401
42
- fail Errors::EndpointAuthenticationError, 'Endpoint authentication failed with OAuth2 token'
43
- end
44
- end
45
- # error still unhandled, will result in a 500, server error
46
- log.warn "Cloud Foundry error still unhandled: #{error}"
47
- end
48
-
49
- private
50
-
51
- def handle_400_error(error, cf_error)
52
- if cf_error == 150_001 || cf_error == 160_001 || cf_error > 100_000 && cf_error < 109_999
53
- # Indicating semantically invalid parameters
54
- fail Errors::SemanticAdapterRequestError, error.body[:description]
55
- elsif cf_error == 170_002
56
- fail_with(:build_in_progress)
57
- elsif cf_error == 60_002
58
- fail Errors::SemanticAdapterRequestError, 'Service is already assigned to the application'
59
- end
60
- end
61
-
62
- def guid?(name_or_id)
63
- Regexp::UUID_PATTERN.match(name_or_id) ? true : false
64
- end
65
-
66
- def default_organization_guid
67
- get("/v2/spaces/#{user_space_guid}").body[:entity][:organization_guid]
68
- end
69
-
70
- def app_guid(app_name_or_id)
71
- # app name is a UUID and therefore most likely the CF GUID
72
- return app_name_or_id if guid?(app_name_or_id)
73
- find_app_guid_by_name(app_name_or_id)
74
- end
75
-
76
- def find_app_guid_by_name(application_name)
77
- filtered_list_response = get('/v2/apps', query: { q: "name:#{application_name}" })
78
- if filtered_list_response.body[:resources].length == 0
79
- fail Errors::AdapterResourceNotFoundError,
80
- "Couldn't find app with name '#{application_name}' on the platform"
81
- end
82
- # return the found guid
83
- filtered_list_response.body[:resources][0][:metadata][:guid]
84
- end
85
-
86
- def find_app_id_by_name(application_name, previous_response)
87
- filtered_list_response = get('/v2/apps', query: { q: "name:#{application_name}" })
88
- # fail as expected if the app can also not be found by its name
89
- fail Errors::AdapterResourceNotFoundError,
90
- previous_response.body[:description] if filtered_list_response.body[:resources].length == 0
91
- # return the found guid
92
- filtered_list_response.body[:resources][0][:metadata][:guid]
93
- end
94
-
95
- def endpoint_info
96
- get('/v2/info', headers: {}).body
97
- end
98
-
99
- def user_info
100
- get("#{endpoint_info[:authorization_endpoint]}/userinfo").body
101
- end
102
-
103
- def user
104
- get("/v2/users/#{user_info[:user_id]}").body
105
- end
106
-
107
- def user_space_guid
108
- users_spaces = get('/v2/spaces').body[:resources]
109
- # only once space accessible
110
- return users_spaces[0][:metadata][:guid] if users_spaces.length == 1
111
- # use default space (stackato feature)
112
- default_space = users_spaces.detect { |space_resource| space_resource[:entity][:is_default] == true }
113
- return default_space[:metadata][:guid] if default_space
114
- # check the users spaces for default
115
- user_default_space_guid = user[:entity][:default_space_guid]
116
- return user_default_space_guid if user_default_space_guid
117
- # TODO: find a more suitable approach to detect the right space !?
118
- # multiple spaces and no default space (dammit), choose the first one...
119
- return users_spaces[0][:metadata][:guid] if users_spaces
120
- # user has no space assigned, fail since we cant determine a space guid
121
- fail_with(:no_space_assigned)
122
- end
123
-
124
- def headers
125
- super.merge('Basic' => 'Y2Y6', 'Content-Type' => 'application/json')
126
- end
127
-
128
- def deployed?(application_guid)
129
- response = head("/v2/apps/#{application_guid}/download", follow_redirects: false, expects: [200, 302, 404])
130
- return true if response.status == 200 || response.status == 302
131
- return false if response.status == 404
132
- # if the response is neither one of the codes, the call fails anyway...
133
- end
134
-
135
- def app_web_url(app_guid)
136
- "#{app_guid}.#{@endpoint_app_domain}" if @endpoint_app_domain
137
- end
138
- end
139
- end
140
- end
141
- end
1
+ module Nucleus
2
+ module Adapters
3
+ module V1
4
+ # The {CloudFoundryV2} adapter is designed to support the Cloud Foundry API and uses only commands
5
+ # of the API version 2.<br>
6
+ # <br>
7
+ # Besides native Cloud Foundry installations, this adapter shall also work with forks, such as Stackato 3.4.2.<br>
8
+ # <br>
9
+ # The Nucleus API is fully supported, there are no known issues.
10
+ # @see http://apidocs.cloudfoundry.org The latest Cloud Foundry API documentation
11
+ class CloudFoundryV2 < Stub
12
+ include Nucleus::Logging
13
+ include Nucleus::Adapters::V1::CloudFoundryV2::Authentication
14
+ include Nucleus::Adapters::V1::CloudFoundryV2::AppStates
15
+ include Nucleus::Adapters::V1::CloudFoundryV2::Buildpacks
16
+ include Nucleus::Adapters::V1::CloudFoundryV2::Application
17
+ include Nucleus::Adapters::V1::CloudFoundryV2::Domains
18
+ include Nucleus::Adapters::V1::CloudFoundryV2::Data
19
+ include Nucleus::Adapters::V1::CloudFoundryV2::Lifecycle
20
+ include Nucleus::Adapters::V1::CloudFoundryV2::Logs
21
+ include Nucleus::Adapters::V1::CloudFoundryV2::Regions
22
+ include Nucleus::Adapters::V1::CloudFoundryV2::Scaling
23
+ include Nucleus::Adapters::V1::CloudFoundryV2::SemanticErrors
24
+ include Nucleus::Adapters::V1::CloudFoundryV2::Services
25
+ include Nucleus::Adapters::V1::CloudFoundryV2::Vars
26
+
27
+ def initialize(endpoint_url, endpoint_app_domain = nil, check_certificates = true)
28
+ super(endpoint_url, endpoint_app_domain, check_certificates)
29
+ end
30
+
31
+ def handle_error(error)
32
+ cf_error = error.body.is_a?(Hash) ? error.body[:code] : nil
33
+ case error.status
34
+ when 400
35
+ handle_400_error(error, cf_error)
36
+ when 404
37
+ raise Errors::AdapterResourceNotFoundError, error.body[:description] if cf_error > 10_000
38
+ else
39
+ if [1001].include? cf_error
40
+ raise Errors::AdapterRequestError, "#{error.body[:description]} (#{cf_error} - #{error.body[:error_code]})"
41
+ elsif [10_002].include?(cf_error) || error.status == 401
42
+ raise Errors::EndpointAuthenticationError, 'Endpoint authentication failed with OAuth2 token'
43
+ end
44
+ end
45
+ # error still unhandled, will result in a 500, server error
46
+ log.warn "Cloud Foundry error still unhandled: #{error}"
47
+ end
48
+
49
+ private
50
+
51
+ def handle_400_error(error, cf_error)
52
+ if cf_error == 150_001 || cf_error == 160_001 || cf_error > 100_000 && cf_error < 109_999
53
+ # Indicating semantically invalid parameters
54
+ raise Errors::SemanticAdapterRequestError, error.body[:description]
55
+ elsif cf_error == 170_002
56
+ fail_with(:build_in_progress)
57
+ elsif cf_error == 60_002
58
+ raise Errors::SemanticAdapterRequestError, 'Service is already assigned to the application'
59
+ end
60
+ end
61
+
62
+ def guid?(name_or_id)
63
+ Regexp::UUID_PATTERN.match(name_or_id) ? true : false
64
+ end
65
+
66
+ def default_organization_guid
67
+ get("/v2/spaces/#{user_space_guid}").body[:entity][:organization_guid]
68
+ end
69
+
70
+ def app_guid(app_name_or_id)
71
+ # app name is a UUID and therefore most likely the CF GUID
72
+ return app_name_or_id if guid?(app_name_or_id)
73
+ find_app_guid_by_name(app_name_or_id)
74
+ end
75
+
76
+ def find_app_guid_by_name(application_name)
77
+ filtered_list_response = get('/v2/apps', query: { q: "name:#{application_name}" })
78
+ if filtered_list_response.body[:resources].empty?
79
+ raise Errors::AdapterResourceNotFoundError,
80
+ "Couldn't find app with name '#{application_name}' on the platform"
81
+ end
82
+ # return the found guid
83
+ filtered_list_response.body[:resources][0][:metadata][:guid]
84
+ end
85
+
86
+ def find_app_id_by_name(application_name, previous_response)
87
+ filtered_list_response = get('/v2/apps', query: { q: "name:#{application_name}" })
88
+ # fail as expected if the app can also not be found by its name
89
+ raise Errors::AdapterResourceNotFoundError,
90
+ previous_response.body[:description] if filtered_list_response.body[:resources].empty?
91
+ # return the found guid
92
+ filtered_list_response.body[:resources][0][:metadata][:guid]
93
+ end
94
+
95
+ def endpoint_info
96
+ get('/v2/info', headers: {}).body
97
+ end
98
+
99
+ def user_info
100
+ get("#{endpoint_info[:authorization_endpoint]}/userinfo").body
101
+ end
102
+
103
+ def user
104
+ get("/v2/users/#{user_info[:user_id]}").body
105
+ end
106
+
107
+ def user_space_guid
108
+ users_spaces = get('/v2/spaces').body[:resources]
109
+ # only once space accessible
110
+ return users_spaces[0][:metadata][:guid] if users_spaces.length == 1
111
+ # use default space (stackato feature)
112
+ default_space = users_spaces.detect { |space_resource| space_resource[:entity][:is_default] == true }
113
+ return default_space[:metadata][:guid] if default_space
114
+ # check the users spaces for default
115
+ user_default_space_guid = user[:entity][:default_space_guid]
116
+ return user_default_space_guid if user_default_space_guid
117
+ # TODO: find a more suitable approach to detect the right space !?
118
+ # multiple spaces and no default space (dammit), choose the first one...
119
+ return users_spaces[0][:metadata][:guid] if users_spaces
120
+ # user has no space assigned, fail since we cant determine a space guid
121
+ fail_with(:no_space_assigned)
122
+ end
123
+
124
+ def headers
125
+ super.merge('Basic' => 'Y2Y6', 'Content-Type' => 'application/json')
126
+ end
127
+
128
+ def deployed?(application_guid)
129
+ response = head("/v2/apps/#{application_guid}/download", follow_redirects: false, expects: [200, 302, 404])
130
+ return true if response.status == 200 || response.status == 302
131
+ return false if response.status == 404
132
+ # if the response is neither one of the codes, the call fails anyway...
133
+ end
134
+
135
+ def app_web_url(app_guid)
136
+ "#{app_guid}.#{@endpoint_app_domain}" if @endpoint_app_domain
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end