module Nucleus::Adapters::V1::Heroku::Services
Public Instance Methods
add_service(application_id, service_entity, plan_entity)
click to toggle source
@see Stub#add_service
# File lib/nucleus/adapters/v1/heroku/services.rb, line 41 def add_service(application_id, service_entity, plan_entity) begin # make sure plan belongs to this service, throws 404 if no such plan # the service plan itself requires the name, e.g. 'sandbox' or the UUID service_plan(service_entity[:id], plan_entity[:id]) rescue Errors::AdapterResourceNotFoundError => e # convert to 422 raise Errors::SemanticAdapterRequestError, e.message end # the plan to choose requires the UUID of the plan OR the combination of both names plan_id = service_plan_identifier(service_entity[:id], plan_entity[:id]) created = post("/apps/#{application_id}/addons", body: { plan: plan_id }).body to_nucleus_installed_service(created) end
change_service(application_id, service_id, plan_entity)
click to toggle source
@see Stub#change_service
# File lib/nucleus/adapters/v1/heroku/services.rb, line 57 def change_service(application_id, service_id, plan_entity) # make sure service is bound to the application assignment_id = raw_installed_service(application_id, service_id)[:id] begin # make sure plan belongs to this service, throws 404 if no such plan # the service plan itself requires the name, e.g. 'sandbox' or the UUID service_plan(service_id, plan_entity[:id]) rescue Errors::AdapterResourceNotFoundError => e # convert to 422 raise Errors::SemanticAdapterRequestError, e.message end # the plan to choose requires the UUID of the plan OR the combination of both names plan_id = service_plan_identifier(service_id, plan_id) updated = patch("/apps/#{application_id}/addons/#{assignment_id}", body: { plan: plan_id }).body to_nucleus_installed_service(updated) end
installed_service(application_id, service_id)
click to toggle source
# File lib/nucleus/adapters/v1/heroku/services.rb, line 35 def installed_service(application_id, service_id) assigned_service = raw_installed_service(application_id, service_id) to_nucleus_installed_service(assigned_service) end
installed_services(application_id)
click to toggle source
# File lib/nucleus/adapters/v1/heroku/services.rb, line 30 def installed_services(application_id) get("/apps/#{application_id}/addons").body.collect { |service| to_nucleus_installed_service(service) } end
remove_service(application_id, service_id)
click to toggle source
@see Stub#remove_service
# File lib/nucleus/adapters/v1/heroku/services.rb, line 75 def remove_service(application_id, service_id) # make sure service is bound to the application assignment_id = raw_installed_service(application_id, service_id)[:id] delete("/apps/#{application_id}/addons/#{assignment_id}") end
service(service_id)
click to toggle source
@see Stub#service
# File lib/nucleus/adapters/v1/heroku/services.rb, line 12 def service(service_id) to_nucleus_service(get("/addon-services/#{service_id}").body) end
service_plan(service_id, plan_id)
click to toggle source
@see Stub#service_plan
# File lib/nucleus/adapters/v1/heroku/services.rb, line 25 def service_plan(service_id, plan_id) to_nucleus_plan(get("/addon-services/#{service_id}/plans/#{plan_id}").body) end
service_plans(service_id)
click to toggle source
@see Stub#service_plans
# File lib/nucleus/adapters/v1/heroku/services.rb, line 17 def service_plans(service_id) load_plans(service_id).collect { |plan| to_nucleus_plan(plan) }.sort_by do |plan| # only compare the first cost, covers most cases and sorting for all costs would be far too complex plan[:costs][0][:price].first[:amount].to_f end end
services()
click to toggle source
@see Stub#services
# File lib/nucleus/adapters/v1/heroku/services.rb, line 7 def services get('/addon-services').body.collect { |service| to_nucleus_service(service) } end
Private Instance Methods
free_plan?(service_id, plans = nil)
click to toggle source
Memoize this detection. The information is not critical, but takes some time to evaluate. Values are not expected to change often.
# File lib/nucleus/adapters/v1/heroku/services.rb, line 157 def free_plan?(service_id, plans = nil) @free_plans ||= {} return @free_plans[service_id] if @free_plans.key?(service_id) plans = load_plans(service_id) unless plans @free_plans[service_id] = plans.any? { |plan| plan[:price][:cents] == 0 } @free_plans[service_id] end
load_plans(service_id)
click to toggle source
# File lib/nucleus/adapters/v1/heroku/services.rb, line 150 def load_plans(service_id) get("/addon-services/#{service_id}/plans").body end
raw_installed_service(application_id, service_id)
click to toggle source
# File lib/nucleus/adapters/v1/heroku/services.rb, line 96 def raw_installed_service(application_id, service_id) # here we probably receive the ID of the service, not the service assignment ID itself installed = get("/apps/#{application_id}/addons/#{service_id}", expects: [200, 404]) if installed.status == 404 assignment_id = service_assignment_id(application_id, service_id) raise Errors::AdapterResourceNotFoundError, "Service #{service_id} is not assigned to application #{application_id}" unless assignment_id return get("/apps/#{application_id}/addons/#{assignment_id}").body end installed.body end
service_assignment_id(application_id, service_id)
click to toggle source
# File lib/nucleus/adapters/v1/heroku/services.rb, line 108 def service_assignment_id(application_id, service_id) all_services = get("/apps/#{application_id}/addons").body match = all_services.find do |addon| addon[:addon_service][:id] == service_id || addon[:addon_service][:name] == service_id end return match[:id] if match nil end
service_plan_identifier(service_id, plan_id)
click to toggle source
# File lib/nucleus/adapters/v1/heroku/services.rb, line 83 def service_plan_identifier(service_id, plan_id) # process plan id_or_name to build the unique identifier # a) is a UUID return plan_id if Regexp::UUID_PATTERN =~ plan_id # b) is valid identifier, contains ':' return plan_id if /^[-\w]+:[-\w]+$/i =~ plan_id # c) fetch id for name return "#{service_id}:#{plan_id}" unless Regexp::UUID_PATTERN =~ service_id # arriving here, service_id is UUID but plan_id is the name --> DOH! # we return the plan_id and the request will presumably fail plan_id end
to_nucleus_installed_service(installed_service)
click to toggle source
# File lib/nucleus/adapters/v1/heroku/services.rb, line 126 def to_nucleus_installed_service(installed_service) service = service(installed_service[:addon_service][:id]) # get all variables and reject all that do not belong to the addon unless installed_service[:config_vars].nil? && installed_service[:config_vars].empty? vars = get("/apps/#{installed_service[:app][:id]}/config-vars").body # ignore all vars that do not belong to the service vars = vars.delete_if { |k| !installed_service[:config_vars].include?(k.to_s) } # format to desired format vars = vars.collect { |k, v| { key: k, value: v, description: nil } } end service[:properties] = vars ? vars : [] service[:active_plan] = installed_service[:plan][:id] service[:web_url] = installed_service[:web_url] service end
to_nucleus_plan(plan)
click to toggle source
# File lib/nucleus/adapters/v1/heroku/services.rb, line 142 def to_nucleus_plan(plan) # TODO: extract payment period to enum plan[:costs] = [{ price: [amount: plan[:price][:cents] / 100.0, currency: 'USD'], period: plan[:price][:unit], per_instance: false }] plan[:free] = plan[:price][:cents] == 0 plan end
to_nucleus_service(service)
click to toggle source
# File lib/nucleus/adapters/v1/heroku/services.rb, line 117 def to_nucleus_service(service) service[:description] = service.delete(:human_name) service[:release] = service.delete(:state) service[:required_services] = [] service[:free_plan] = free_plan?(service[:id]) service[:documentation_url] = "https://addons.heroku.com/#{service[:name]}" service end