nucleus 0.1.0 → 0.2.0

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +18 -4
  4. data/README.md +28 -40
  5. data/Rakefile +137 -137
  6. data/config/nucleus_config.rb +0 -4
  7. data/lib/nucleus/adapter_resolver.rb +115 -115
  8. data/lib/nucleus/adapters/buildpack_translator.rb +79 -79
  9. data/lib/nucleus/adapters/v1/cloud_control/application.rb +108 -108
  10. data/lib/nucleus/adapters/v1/cloud_control/authentication.rb +27 -27
  11. data/lib/nucleus/adapters/v1/cloud_control/cloud_control.rb +153 -153
  12. data/lib/nucleus/adapters/v1/cloud_control/domains.rb +68 -68
  13. data/lib/nucleus/adapters/v1/cloud_control/logs.rb +103 -103
  14. data/lib/nucleus/adapters/v1/cloud_control/vars.rb +88 -88
  15. data/lib/nucleus/adapters/v1/cloud_foundry_v2/domains.rb +149 -149
  16. data/lib/nucleus/adapters/v1/cloud_foundry_v2/logs.rb +303 -303
  17. data/lib/nucleus/adapters/v1/cloud_foundry_v2/services.rb +286 -286
  18. data/lib/nucleus/adapters/v1/heroku/heroku.rb +2 -2
  19. data/lib/nucleus/adapters/v1/heroku/logs.rb +108 -108
  20. data/lib/nucleus/core/adapter_authentication_inductor.rb +0 -2
  21. data/lib/nucleus/core/adapter_extensions/auth/http_basic_auth_client.rb +37 -37
  22. data/lib/nucleus/core/adapter_extensions/http_client.rb +177 -177
  23. data/lib/nucleus/core/common/files/archive_extractor.rb +112 -112
  24. data/lib/nucleus/core/common/files/archiver.rb +91 -91
  25. data/lib/nucleus/core/common/logging/request_log_formatter.rb +48 -48
  26. data/lib/nucleus/core/error_messages.rb +127 -127
  27. data/lib/nucleus/core/models/abstract_model.rb +29 -29
  28. data/lib/nucleus/scripts/load_dependencies.rb +0 -1
  29. data/lib/nucleus/scripts/setup_config.rb +28 -28
  30. data/lib/nucleus/version.rb +3 -3
  31. data/nucleus.gemspec +10 -12
  32. data/spec/factories/models.rb +63 -61
  33. data/spec/integration/api/auth_spec.rb +58 -58
  34. data/spec/test_suites.rake +31 -31
  35. data/spec/unit/common/helpers/auth_helper_spec.rb +73 -73
  36. data/spec/unit/common/oauth2_auth_client_spec.rb +1 -1
  37. data/tasks/compatibility.rake +113 -113
  38. data/tasks/evaluation.rake +162 -162
  39. metadata +16 -30
@@ -1,103 +1,103 @@
1
- module Nucleus
2
- module Adapters
3
- module V1
4
- class CloudControl < Stub
5
- # cloud control application's log management operations
6
- module Logs
7
- # Cloud control log types. The +key+ and +id+ shall match the Nucleus definitions of log files,
8
- # whereas the +name+ shall match the cloud control log id.
9
- LOG_TYPES = {
10
- all: { id: 'all', name: 'all', type: Enums::ApplicationLogfileType::OTHER },
11
- request: { id: 'request', name: 'access', type: Enums::ApplicationLogfileType::REQUEST },
12
- application: { id: 'application', name: 'error', type: Enums::ApplicationLogfileType::APPLICATION },
13
- api: { id: 'api', name: 'deploy', type: Enums::ApplicationLogfileType::API },
14
- system: { id: 'system', name: 'worker', type: Enums::ApplicationLogfileType::SYSTEM }
15
- }
16
-
17
- # @see Stub#logs
18
- def logs(application_name)
19
- # fails with 404 if application is not available and serves for timestamps
20
- app = get("/app/#{application_name}").body
21
-
22
- LOG_TYPES.values.collect do |log|
23
- log[:created_at] = app[:date_created]
24
- log[:updated_at] = app[:date_modified]
25
- log
26
- end
27
- end
28
-
29
- # @see Stub#log?
30
- def log?(application_name, log_id)
31
- # fails with 404 if application is not available
32
- get("/app/#{application_name}")
33
-
34
- LOG_TYPES.key? log_id.to_sym
35
- end
36
-
37
- # cloud control shows the last 500 log messages if applicable
38
- # @see Stub#tail
39
- def tail(application_name, log_id, stream)
40
- # cache headers as they are bound to a request and could be lost with the next tick
41
- headers_to_use = headers
42
- logs_to_poll = log_id == 'all' ? LOG_TYPES.keys - [:all] : [log_id]
43
- poller = LogPoller.new(self, headers_to_use)
44
- poller.start(application_name, logs_to_poll, stream)
45
- TailStopper.new(poller, :stop)
46
- end
47
-
48
- # cloud control shows the last 500 log messages if applicable
49
- # @see Stub#log_entries
50
- def log_entries(application_name, log_id)
51
- unless log?(application_name, log_id)
52
- fail Errors::AdapterResourceNotFoundError,
53
- "Invalid log file '#{log_id}', not available for application '#{application_name}'"
54
- end
55
- if log_id == 'all'
56
- fetched_lines = []
57
- (LOG_TYPES.keys - [:all]).each do |current_log_id|
58
- cc_log_entries(application_name, current_log_id).each do |line|
59
- line[:nucleus_origin] = current_log_id
60
- fetched_lines.push(line)
61
- end
62
- end
63
- fetched_lines.sort_by! { |line| line[:time] }
64
- fetched_lines.collect { |line| format_log_entry(line[:nucleus_origin], line) }
65
- else
66
- cc_log_entries(application_name, log_id).collect { |line| format_log_entry(log_id, line) }
67
- end
68
- end
69
-
70
- private
71
-
72
- def cc_log_entries(app_name, log_id, time = nil, headers_to_use = nil)
73
- log_name = LOG_TYPES[log_id.to_sym][:name]
74
- # Hack, do not create fresh headers (which would fail) when in a deferred action
75
- headers_to_use = headers unless headers_to_use
76
- if time
77
- get("/app/#{app_name}/deployment/#{NUCLEUS_DEPLOYMENT}/log/#{log_name}?timestamp=#{time}",
78
- headers: headers_to_use).body
79
- else
80
- get("/app/#{app_name}/deployment/#{NUCLEUS_DEPLOYMENT}/log/#{log_name}", headers: headers_to_use).body
81
- end
82
- end
83
-
84
- def format_log_entry(log_id, line)
85
- # format according to: https://github.com/cloudControl/cctrl/blob/master/cctrl/output.py
86
- case log_id.to_sym
87
- when :request
88
- "#{line[:remote_host]} #{line[:remote_user]} #{line[:remote_logname]} [#{Time.at(line[:time]).iso8601}] "\
89
- "#{line[:first_request_line]} #{line[:status]} #{line[:response_size_CLF]} #{line[:referer]} "\
90
- "#{line[:user_agent]}"
91
- when :system
92
- "#{line[:time]} #{line[:wrk_id]} #{line[:message]}"
93
- when :build
94
- "#{Time.at(line[:time]).iso8601} [#{line[:hostname]}/#{line[:depl_id]}] #{line[:level]} #{line[:message]}"
95
- when :error
96
- "#{line[:time]} #{line[:type]} #{line[:message]}"
97
- end
98
- end
99
- end
100
- end
101
- end
102
- end
103
- end
1
+ module Nucleus
2
+ module Adapters
3
+ module V1
4
+ class CloudControl < Stub
5
+ # cloud control application's log management operations
6
+ module Logs
7
+ # Cloud control log types. The +key+ and +id+ shall match the Nucleus definitions of log files,
8
+ # whereas the +name+ shall match the cloud control log id.
9
+ LOG_TYPES = {
10
+ all: { id: 'all', name: 'all', type: Enums::ApplicationLogfileType::OTHER },
11
+ request: { id: 'request', name: 'access', type: Enums::ApplicationLogfileType::REQUEST },
12
+ application: { id: 'application', name: 'error', type: Enums::ApplicationLogfileType::APPLICATION },
13
+ api: { id: 'api', name: 'deploy', type: Enums::ApplicationLogfileType::API },
14
+ system: { id: 'system', name: 'worker', type: Enums::ApplicationLogfileType::SYSTEM }
15
+ }.freeze
16
+
17
+ # @see Stub#logs
18
+ def logs(application_name)
19
+ # fails with 404 if application is not available and serves for timestamps
20
+ app = get("/app/#{application_name}").body
21
+
22
+ LOG_TYPES.values.collect do |log|
23
+ log[:created_at] = app[:date_created]
24
+ log[:updated_at] = app[:date_modified]
25
+ log
26
+ end
27
+ end
28
+
29
+ # @see Stub#log?
30
+ def log?(application_name, log_id)
31
+ # fails with 404 if application is not available
32
+ get("/app/#{application_name}")
33
+
34
+ LOG_TYPES.key? log_id.to_sym
35
+ end
36
+
37
+ # cloud control shows the last 500 log messages if applicable
38
+ # @see Stub#tail
39
+ def tail(application_name, log_id, stream)
40
+ # cache headers as they are bound to a request and could be lost with the next tick
41
+ headers_to_use = headers
42
+ logs_to_poll = log_id == 'all' ? LOG_TYPES.keys - [:all] : [log_id]
43
+ poller = LogPoller.new(self, headers_to_use)
44
+ poller.start(application_name, logs_to_poll, stream)
45
+ TailStopper.new(poller, :stop)
46
+ end
47
+
48
+ # cloud control shows the last 500 log messages if applicable
49
+ # @see Stub#log_entries
50
+ def log_entries(application_name, log_id)
51
+ unless log?(application_name, log_id)
52
+ fail Errors::AdapterResourceNotFoundError,
53
+ "Invalid log file '#{log_id}', not available for application '#{application_name}'"
54
+ end
55
+ if log_id == 'all'
56
+ fetched_lines = []
57
+ (LOG_TYPES.keys - [:all]).each do |current_log_id|
58
+ cc_log_entries(application_name, current_log_id).each do |line|
59
+ line[:nucleus_origin] = current_log_id
60
+ fetched_lines.push(line)
61
+ end
62
+ end
63
+ fetched_lines.sort_by! { |line| line[:time] }
64
+ fetched_lines.collect { |line| format_log_entry(line[:nucleus_origin], line) }
65
+ else
66
+ cc_log_entries(application_name, log_id).collect { |line| format_log_entry(log_id, line) }
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def cc_log_entries(app_name, log_id, time = nil, headers_to_use = nil)
73
+ log_name = LOG_TYPES[log_id.to_sym][:name]
74
+ # Hack, do not create fresh headers (which would fail) when in a deferred action
75
+ headers_to_use = headers unless headers_to_use
76
+ if time
77
+ get("/app/#{app_name}/deployment/#{NUCLEUS_DEPLOYMENT}/log/#{log_name}?timestamp=#{time}",
78
+ headers: headers_to_use).body
79
+ else
80
+ get("/app/#{app_name}/deployment/#{NUCLEUS_DEPLOYMENT}/log/#{log_name}", headers: headers_to_use).body
81
+ end
82
+ end
83
+
84
+ def format_log_entry(log_id, line)
85
+ # format according to: https://github.com/cloudControl/cctrl/blob/master/cctrl/output.py
86
+ case log_id.to_sym
87
+ when :request
88
+ "#{line[:remote_host]} #{line[:remote_user]} #{line[:remote_logname]} [#{Time.at(line[:time]).iso8601}] "\
89
+ "#{line[:first_request_line]} #{line[:status]} #{line[:response_size_CLF]} #{line[:referer]} "\
90
+ "#{line[:user_agent]}"
91
+ when :system
92
+ "#{line[:time]} #{line[:wrk_id]} #{line[:message]}"
93
+ when :build
94
+ "#{Time.at(line[:time]).iso8601} [#{line[:hostname]}/#{line[:depl_id]}] #{line[:level]} #{line[:message]}"
95
+ when :error
96
+ "#{line[:time]} #{line[:type]} #{line[:message]}"
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -1,88 +1,88 @@
1
- module Nucleus
2
- module Adapters
3
- module V1
4
- class CloudControl < Stub
5
- # cloud control, CRUD operations for the application's environment variable object,
6
- # which is referred to as +config addon+ on the platform.
7
- module Vars
8
- # @see Stub#env_vars
9
- def env_vars(application_id)
10
- cc_vars = cc_vars(application_id)
11
- cc_vars.collect do |key, value|
12
- { id: key, key: key, value: value }
13
- end
14
- end
15
-
16
- # @see Stub#env_var
17
- def env_var(application_id, env_var_key)
18
- cc_vars = cc_vars(application_id)
19
- fail Errors::AdapterResourceNotFoundError,
20
- "Env. var key '#{env_var_key}' does not exist" unless env_var?(application_id, env_var_key, cc_vars)
21
- { id: env_var_key, key: env_var_key, value: cc_vars[env_var_key.to_sym] }
22
- end
23
-
24
- # @see Stub#create_env_var
25
- def create_env_var(application_id, env_var)
26
- cc_vars = cc_vars(application_id)
27
- fail Errors::SemanticAdapterRequestError,
28
- "Env. var key '#{env_var[:key]}' already taken" if env_var?(application_id, env_var[:key], cc_vars)
29
- set_var(application_id, env_var[:key], env_var[:value])
30
- end
31
-
32
- # @see Stub#update_env_var
33
- def update_env_var(application_id, env_var_key, env_var)
34
- cc_vars = cc_vars(application_id)
35
- fail Errors::AdapterResourceNotFoundError,
36
- "Env. var key '#{env_var_key}' does not exist" unless env_var?(application_id, env_var_key, cc_vars)
37
- set_var(application_id, env_var_key, env_var[:value])
38
- end
39
-
40
- # @see Stub#delete_env_var
41
- def delete_env_var(application_id, env_var_key)
42
- cc_vars = cc_vars(application_id)
43
- fail Errors::AdapterResourceNotFoundError,
44
- "Env. var key '#{env_var_key}' does not exist" unless env_var?(application_id, env_var_key, cc_vars)
45
- set_var(application_id, env_var_key, nil)
46
- end
47
-
48
- private
49
-
50
- def cc_vars(application_id)
51
- cc_vars_response = get("app/#{application_id}/deployment/#{NUCLEUS_DEPLOYMENT}/addon/config.free")
52
- cc_vars_response.body[:settings][:CONFIG_VARS]
53
- end
54
-
55
- # Set the variable value (create or update)
56
- # @param [String] application_id id of the cloud control application
57
- # @param [Symbol] key variable key name
58
- # @param [String, Integer, Float, Double] value value to apply to the variable
59
- # @return [Hash] Nucleus representation of the modified variable
60
- def set_var(application_id, key, value)
61
- if value.nil?
62
- # delete the var, set to 'null'
63
- settings = "{\"#{key}\":null}"
64
- else
65
- settings = "{\"#{key}\":\"#{value}\"}"
66
- end
67
- response = put("/app/#{application_id}/deployment/#{NUCLEUS_DEPLOYMENT}/addon/config.free",
68
- body: { addon: 'config.free',
69
- settings: settings,
70
- force: true })
71
- all_vars = response.body[:settings][:CONFIG_VARS]
72
- { id: key, key: key, value: all_vars[key.to_sym] }
73
- end
74
-
75
- # Checks if a variable with the env_var_key already exists.
76
- # @param [String] application_id id of the cloud control application
77
- # @param [Symbol] env_var_key key name that shall be checked for existence
78
- # @param [Hash] all_vars collection of currently existing variables for the application
79
- # @return [Boolean] true if there is a variable with the env_var_key, otherwise false
80
- def env_var?(application_id, env_var_key, all_vars = nil)
81
- all_vars = cc_vars(application_id) if all_vars.nil?
82
- all_vars.key? env_var_key.to_sym
83
- end
84
- end
85
- end
86
- end
87
- end
88
- end
1
+ module Nucleus
2
+ module Adapters
3
+ module V1
4
+ class CloudControl < Stub
5
+ # cloud control, CRUD operations for the application's environment variable object,
6
+ # which is referred to as +config addon+ on the platform.
7
+ module Vars
8
+ # @see Stub#env_vars
9
+ def env_vars(application_id)
10
+ cc_vars = cc_vars(application_id)
11
+ cc_vars.collect do |key, value|
12
+ { id: key, key: key, value: value }
13
+ end
14
+ end
15
+
16
+ # @see Stub#env_var
17
+ def env_var(application_id, env_var_key)
18
+ cc_vars = cc_vars(application_id)
19
+ fail Errors::AdapterResourceNotFoundError,
20
+ "Env. var key '#{env_var_key}' does not exist" unless env_var?(application_id, env_var_key, cc_vars)
21
+ { id: env_var_key, key: env_var_key, value: cc_vars[env_var_key.to_sym] }
22
+ end
23
+
24
+ # @see Stub#create_env_var
25
+ def create_env_var(application_id, env_var)
26
+ cc_vars = cc_vars(application_id)
27
+ fail Errors::SemanticAdapterRequestError,
28
+ "Env. var key '#{env_var[:key]}' already taken" if env_var?(application_id, env_var[:key], cc_vars)
29
+ set_var(application_id, env_var[:key], env_var[:value])
30
+ end
31
+
32
+ # @see Stub#update_env_var
33
+ def update_env_var(application_id, env_var_key, env_var)
34
+ cc_vars = cc_vars(application_id)
35
+ fail Errors::AdapterResourceNotFoundError,
36
+ "Env. var key '#{env_var_key}' does not exist" unless env_var?(application_id, env_var_key, cc_vars)
37
+ set_var(application_id, env_var_key, env_var[:value])
38
+ end
39
+
40
+ # @see Stub#delete_env_var
41
+ def delete_env_var(application_id, env_var_key)
42
+ cc_vars = cc_vars(application_id)
43
+ fail Errors::AdapterResourceNotFoundError,
44
+ "Env. var key '#{env_var_key}' does not exist" unless env_var?(application_id, env_var_key, cc_vars)
45
+ set_var(application_id, env_var_key, nil)
46
+ end
47
+
48
+ private
49
+
50
+ def cc_vars(application_id)
51
+ cc_vars_response = get("app/#{application_id}/deployment/#{NUCLEUS_DEPLOYMENT}/addon/config.free")
52
+ cc_vars_response.body[:settings][:CONFIG_VARS]
53
+ end
54
+
55
+ # Set the variable value (create or update)
56
+ # @param [String] application_id id of the cloud control application
57
+ # @param [Symbol] key variable key name
58
+ # @param [String, Integer, Float, Double] value value to apply to the variable
59
+ # @return [Hash] Nucleus representation of the modified variable
60
+ def set_var(application_id, key, value)
61
+ settings = if value.nil?
62
+ # delete the var, set to 'null'
63
+ "{\"#{key}\":null}"
64
+ else
65
+ "{\"#{key}\":\"#{value}\"}"
66
+ end
67
+ response = put("/app/#{application_id}/deployment/#{NUCLEUS_DEPLOYMENT}/addon/config.free",
68
+ body: { addon: 'config.free',
69
+ settings: settings,
70
+ force: true })
71
+ all_vars = response.body[:settings][:CONFIG_VARS]
72
+ { id: key, key: key, value: all_vars[key.to_sym] }
73
+ end
74
+
75
+ # Checks if a variable with the env_var_key already exists.
76
+ # @param [String] application_id id of the cloud control application
77
+ # @param [Symbol] env_var_key key name that shall be checked for existence
78
+ # @param [Hash] all_vars collection of currently existing variables for the application
79
+ # @return [Boolean] true if there is a variable with the env_var_key, otherwise false
80
+ def env_var?(application_id, env_var_key, all_vars = nil)
81
+ all_vars = cc_vars(application_id) if all_vars.nil?
82
+ all_vars.key? env_var_key.to_sym
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,149 +1,149 @@
1
- module Nucleus
2
- module Adapters
3
- module V1
4
- class CloudFoundryV2 < Stub
5
- # Application domain / route functionality to support the Cloud Foundry API.<br>
6
- module Domains
7
- # @see Stub#domains
8
- def domains(domain_id)
9
- app_guid = app_guid(domain_id)
10
- assigned_routes = get("/v2/apps/#{app_guid}/routes").body
11
- domains = []
12
- assigned_routes[:resources].each do |assigned_route|
13
- nucleus_domain = route_to_nucleus_domain(assigned_route)
14
- domains.push(nucleus_domain) unless nucleus_domain[:name] == app_web_url(app_guid)
15
- end
16
- domains
17
- end
18
-
19
- # @see Stub#domain
20
- def domain(application_name_or_id, domain_id)
21
- app_guid = app_guid(application_name_or_id)
22
- assigned_routes = get("/v2/apps/#{app_guid}/routes").body
23
- assigned_routes[:resources].each do |assigned_route|
24
- return route_to_nucleus_domain(assigned_route) if assigned_route[:metadata][:guid] == domain_id
25
- end
26
- end
27
-
28
- # @see Stub#create_domain
29
- def create_domain(application_name_or_id, domain)
30
- domains(application_name_or_id).each do |existing_domain|
31
- if existing_domain[:name] == domain[:name]
32
- fail Errors::SemanticAdapterRequestError,
33
- "Domain '#{domain[:name]}' is already assigned to the application"
34
- end
35
- end
36
-
37
- app_guid = app_guid(application_name_or_id)
38
- # extract the hostname and the domain name from the FQDN
39
- /(?<domain_host>([-\w]+\.)*)(?<domain_name>([-\w]+\.[-\w]+))/ =~ domain[:name]
40
- domain_host.chomp!('.') unless domain_host.nil?
41
-
42
- # finally build the response
43
- route_to_nucleus_domain(create_cf_domain(app_guid, domain_name, domain_host))
44
- end
45
-
46
- # @see Stub#delete_domain
47
- def delete_domain(application_name_or_id, route_id)
48
- app_guid = app_guid(application_name_or_id)
49
- # remove route from the app
50
- delete_response = delete("/v2/apps/#{app_guid}/routes/#{route_id}", expects: [201, 400])
51
- if delete_response.status == 400
52
- cf_error = delete_response.body[:code]
53
- if cf_error == 1002
54
- fail Errors::AdapterResourceNotFoundError, 'Domain not found. '\
55
- 'CF context specific: Route does not exist or is not assigned with this application'
56
- else
57
- # delete failed with 400, but not due to invalid domain
58
- fail Errors::AdapterRequestError,
59
- "#{delete_response.body[:description]} (#{cf_error} - #{delete_response.body[:error_code]})"
60
- end
61
- end
62
-
63
- # check route usage
64
- route_in_apps = get("/v2/routes/#{route_id}/apps").body
65
- return unless route_in_apps[:total_results] == 0
66
-
67
- # route is no longer needed, delete
68
- delete("/v2/routes/#{route_id}")
69
- end
70
-
71
- private
72
-
73
- def domain?(application_name_or_id, domain_name)
74
- app_guid = app_guid(application_name_or_id)
75
- domain_without_protocol = %r{([a-zA-Z]+://)?([-\.\w]*)}.match(domain_name)[2]
76
- assigned_routes = get("/v2/apps/#{app_guid}/routes").body
77
- assigned_routes[:resources].each do |route|
78
- route_domain = get(route[:entity][:domain_url]).body
79
- return true if "#{route[:entity][:host]}.#{route_domain[:entity][:name]}" == domain_without_protocol
80
- end
81
- false
82
- end
83
-
84
- def route_to_nucleus_domain(route_resource)
85
- route_entity = route_resource[:entity]
86
- route_metadata = route_resource[:metadata]
87
- assigned_domain = get(route_entity[:domain_url]).body
88
- domain = { id: route_metadata[:guid], created_at: route_metadata[:created_at] }
89
- if route_metadata[:updated_at].to_s == ''
90
- domain[:updated_at] = route_metadata[:created_at]
91
- else
92
- domain[:updated_at] = route_metadata[:updated_at]
93
- end
94
-
95
- if route_entity[:host].to_s == ''
96
- domain[:name] = assigned_domain[:entity][:name]
97
- else
98
- domain[:name] = "#{route_entity[:host]}.#{assigned_domain[:entity][:name]}"
99
- end
100
- domain
101
- end
102
-
103
- def cf_domain(domain_name)
104
- %w(private shared).each do |domain_type|
105
- response = get("/v2/#{domain_type}_domains").body
106
- response[:resources].each do |domain|
107
- return domain if domain[:entity][:name] == domain_name
108
- end
109
- end
110
- nil
111
- end
112
-
113
- def cf_route(domain_guid, domain_host)
114
- # There is no way to check if a root domain (empty hostname) is already taken.
115
- # Therefore we must iterate through all routes and find matches...
116
- all_routes = get('/v2/routes').body[:resources]
117
- all_routes.each do |route|
118
- return route if route[:entity][:domain_guid] == domain_guid && route[:entity][:host] == domain_host
119
- end
120
- nil
121
- end
122
-
123
- def create_cf_domain(app_guid, domain_name, domain_host)
124
- created_domain = cf_domain(domain_name)
125
- unless created_domain
126
- # domain does not exist, create!
127
- domain_request_body = { name: domain_name, owning_organization_guid: default_organization_guid }
128
- created_domain = post('/v2/private_domains', body: domain_request_body).body
129
- end
130
-
131
- created_route = cf_route(created_domain[:metadata][:guid], domain_host)
132
- unless created_route
133
- # route does not exist, create!
134
- route_request_body = { domain_guid: created_domain[:metadata][:guid],
135
- host: domain_host, space_guid: user_space_guid }
136
- created_route = post('/v2/routes', body: route_request_body).body
137
- end
138
-
139
- # assign the route to the application
140
- put("/v2/apps/#{app_guid}/routes/#{created_route[:metadata][:guid]}").body
141
-
142
- # return the actual route, not the association response
143
- created_route
144
- end
145
- end
146
- end
147
- end
148
- end
149
- end
1
+ module Nucleus
2
+ module Adapters
3
+ module V1
4
+ class CloudFoundryV2 < Stub
5
+ # Application domain / route functionality to support the Cloud Foundry API.<br>
6
+ module Domains
7
+ # @see Stub#domains
8
+ def domains(domain_id)
9
+ app_guid = app_guid(domain_id)
10
+ assigned_routes = get("/v2/apps/#{app_guid}/routes").body
11
+ domains = []
12
+ assigned_routes[:resources].each do |assigned_route|
13
+ nucleus_domain = route_to_nucleus_domain(assigned_route)
14
+ domains.push(nucleus_domain) unless nucleus_domain[:name] == app_web_url(app_guid)
15
+ end
16
+ domains
17
+ end
18
+
19
+ # @see Stub#domain
20
+ def domain(application_name_or_id, domain_id)
21
+ app_guid = app_guid(application_name_or_id)
22
+ assigned_routes = get("/v2/apps/#{app_guid}/routes").body
23
+ assigned_routes[:resources].each do |assigned_route|
24
+ return route_to_nucleus_domain(assigned_route) if assigned_route[:metadata][:guid] == domain_id
25
+ end
26
+ end
27
+
28
+ # @see Stub#create_domain
29
+ def create_domain(application_name_or_id, domain)
30
+ domains(application_name_or_id).each do |existing_domain|
31
+ if existing_domain[:name] == domain[:name]
32
+ fail Errors::SemanticAdapterRequestError,
33
+ "Domain '#{domain[:name]}' is already assigned to the application"
34
+ end
35
+ end
36
+
37
+ app_guid = app_guid(application_name_or_id)
38
+ # extract the hostname and the domain name from the FQDN
39
+ /(?<domain_host>([-\w]+\.)*)(?<domain_name>([-\w]+\.[-\w]+))/ =~ domain[:name]
40
+ domain_host.chomp!('.') unless domain_host.nil?
41
+
42
+ # finally build the response
43
+ route_to_nucleus_domain(create_cf_domain(app_guid, domain_name, domain_host))
44
+ end
45
+
46
+ # @see Stub#delete_domain
47
+ def delete_domain(application_name_or_id, route_id)
48
+ app_guid = app_guid(application_name_or_id)
49
+ # remove route from the app
50
+ delete_response = delete("/v2/apps/#{app_guid}/routes/#{route_id}", expects: [201, 400])
51
+ if delete_response.status == 400
52
+ cf_error = delete_response.body[:code]
53
+ if cf_error == 1002
54
+ fail Errors::AdapterResourceNotFoundError, 'Domain not found. '\
55
+ 'CF context specific: Route does not exist or is not assigned with this application'
56
+ else
57
+ # delete failed with 400, but not due to invalid domain
58
+ fail Errors::AdapterRequestError,
59
+ "#{delete_response.body[:description]} (#{cf_error} - #{delete_response.body[:error_code]})"
60
+ end
61
+ end
62
+
63
+ # check route usage
64
+ route_in_apps = get("/v2/routes/#{route_id}/apps").body
65
+ return unless route_in_apps[:total_results] == 0
66
+
67
+ # route is no longer needed, delete
68
+ delete("/v2/routes/#{route_id}")
69
+ end
70
+
71
+ private
72
+
73
+ def domain?(application_name_or_id, domain_name)
74
+ app_guid = app_guid(application_name_or_id)
75
+ domain_without_protocol = %r{([a-zA-Z]+://)?([-\.\w]*)}.match(domain_name)[2]
76
+ assigned_routes = get("/v2/apps/#{app_guid}/routes").body
77
+ assigned_routes[:resources].each do |route|
78
+ route_domain = get(route[:entity][:domain_url]).body
79
+ return true if "#{route[:entity][:host]}.#{route_domain[:entity][:name]}" == domain_without_protocol
80
+ end
81
+ false
82
+ end
83
+
84
+ def route_to_nucleus_domain(route_resource)
85
+ route_entity = route_resource[:entity]
86
+ route_metadata = route_resource[:metadata]
87
+ assigned_domain = get(route_entity[:domain_url]).body
88
+ domain = { id: route_metadata[:guid], created_at: route_metadata[:created_at] }
89
+ domain[:updated_at] = if route_metadata[:updated_at].to_s == ''
90
+ route_metadata[:created_at]
91
+ else
92
+ route_metadata[:updated_at]
93
+ end
94
+
95
+ domain[:name] = if route_entity[:host].to_s == ''
96
+ assigned_domain[:entity][:name]
97
+ else
98
+ "#{route_entity[:host]}.#{assigned_domain[:entity][:name]}"
99
+ end
100
+ domain
101
+ end
102
+
103
+ def cf_domain(domain_name)
104
+ %w(private shared).each do |domain_type|
105
+ response = get("/v2/#{domain_type}_domains").body
106
+ response[:resources].each do |domain|
107
+ return domain if domain[:entity][:name] == domain_name
108
+ end
109
+ end
110
+ nil
111
+ end
112
+
113
+ def cf_route(domain_guid, domain_host)
114
+ # There is no way to check if a root domain (empty hostname) is already taken.
115
+ # Therefore we must iterate through all routes and find matches...
116
+ all_routes = get('/v2/routes').body[:resources]
117
+ all_routes.each do |route|
118
+ return route if route[:entity][:domain_guid] == domain_guid && route[:entity][:host] == domain_host
119
+ end
120
+ nil
121
+ end
122
+
123
+ def create_cf_domain(app_guid, domain_name, domain_host)
124
+ created_domain = cf_domain(domain_name)
125
+ unless created_domain
126
+ # domain does not exist, create!
127
+ domain_request_body = { name: domain_name, owning_organization_guid: default_organization_guid }
128
+ created_domain = post('/v2/private_domains', body: domain_request_body).body
129
+ end
130
+
131
+ created_route = cf_route(created_domain[:metadata][:guid], domain_host)
132
+ unless created_route
133
+ # route does not exist, create!
134
+ route_request_body = { domain_guid: created_domain[:metadata][:guid],
135
+ host: domain_host, space_guid: user_space_guid }
136
+ created_route = post('/v2/routes', body: route_request_body).body
137
+ end
138
+
139
+ # assign the route to the application
140
+ put("/v2/apps/#{app_guid}/routes/#{created_route[:metadata][:guid]}").body
141
+
142
+ # return the actual route, not the association response
143
+ created_route
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end