require 'netrc' require 'faraday' require 'json' require 'acquia_toolbelt/version' module AcquiaToolbelt class CLI class API USER_AGENT = "AcquiaToolbelt/#{AcquiaToolbelt::VERSION}" ENDPOINT = 'https://cloudapi.acquia.com' ENDPOINT_VERSION = 'v1' # Internal: Send a request to the Acquia API. # # Build a HTTP request to connect to the Acquia API and handle the JSON # response accordingly. # # resource - The resource URI that is after the version in the API # URI. # method - HTTP verb to use on the request. # data - Data to send to the endpoint. # parse_request - Whether to JSON parse the body before returning or just # return the whole request object. The whole request is # returned during tests whereas only the body is required # for the application. # # Retuns JSON object from the response body. def self.request(resource, method = 'GET', data = {}, parse_request = true) # If the netrc file has incorrect permissions, let the user know. begin n = Netrc.read rescue => e puts e.message end # Make sure there is an entry for the Acquia API before generating the # requests. if n['cloudapi.acquia.com'].nil? puts 'No entry for cloudapi.acquia.com within your netrc file.' puts 'You can login/reset your user credentials by running `acquia auth:login`' return end @acquia_user, @acquia_password = n['cloudapi.acquia.com'] # Check if the user is behind a proxy and add the proxy settings if # they are. conn = (using_proxy?) ? Faraday.new(:proxy => ENV['HTTPS_PROXY']) : Faraday.new conn.basic_auth(@acquia_user, @acquia_password) # Be nice and send a user agent - help tracking and issue detection on # Acquia's end as well as the client. conn.headers['User-Agent'] = "#{AcquiaToolbelt::CLI::API::USER_AGENT}" case method when 'GET' response = conn.get "#{endpoint_uri}/#{resource}.json" successful_response? response if parse_request == true JSON.parse(response.body) else response end when 'POST' response = conn.post "#{endpoint_uri}/#{resource}.json", data.to_json successful_response? response if parse_request == true JSON.parse(response.body) else response end when 'QUERY-STRING-POST' response = conn.post "#{endpoint_uri}/#{resource}.json?#{data[:key]}=#{data[:value]}", data.to_json successful_response? response if parse_request == true JSON.parse(response.body) else response end when 'DELETE' response = conn.delete "#{endpoint_uri}/#{resource}.json" successful_response? response if parse_request == true JSON.parse(response.body) else response end else end end # Internal: Get defined subscription environments. # # This is a helper method that fetches all the available environments for # a subscription and returns them for use in other methods. # # Returns an array of environments. def self.environments subscription = default_subscription env_data = request "sites/#{subscription}/envs" envs = [] env_data.each do |env| envs << env['name'] end envs end # Internal: Use the default environment the user has access to. # # If the -s (subscription) flag is not set, just use the first # subscription the user has access to. This is handy for users that # primarily only deal with a specific subscription. # # Returns the first subscription name. def self.default_subscription sites = request 'sites' sites.first end # Internal: Build the endpoint URI. # # By building the URI here, we ensure that it is consistent throughout the # application and also allows a single point to update should it be # needed. # # Returns a URI string. def self.endpoint_uri "#{AcquiaToolbelt::CLI::API::ENDPOINT}/#{AcquiaToolbelt::CLI::API::ENDPOINT_VERSION}" end # Internal: Check whether a proxy is in use. # # Return boolean based on whether HTTPS_PROXY is set. def self.using_proxy? ENV['HTTPS_PROXY'] ? true : false end # Internal: Show the error message from the response. # # If the API request fails, this will get the "message" and allow that to # be outputted to the end user to be a little more helpful. # # Returns string of the message. def self.display_error(response) "Oops, an error occurred! Reason: #{response['message']}" end # Internal: Ensure the response returns a HTTP 200. # # If the response status isn't a HTTP 200, we need to find out why. This # helps identify the issues earlier on and will prevent extra API calls # that won't complete. # # Returns false if the response code isn't a HTTP 200. def self.successful_response?(response) if response.status != 200 puts display_error(JSON.parse(response.body)) return end end end end end