bin/acquia in acquia_toolbelt-1.5.1 vs bin/acquia in acquia_toolbelt-2.0.0

- old
+ new

@@ -1,568 +1,9 @@ #!/usr/bin/env ruby +$:.unshift(File.expand_path('../../lib', __FILE__)) +require 'acquia_toolbelt/cli' -require "thor" -require "netrc" -require "highline/import" -require "faraday" -require "json" -require "rainbow" - -class Acquia < Thor - # A no_commands block is designed to show the methods that cannot be invoked - # and as such, do not have a description. - no_commands { - # Internal: Used for outputting a pretty success message. - # - # Returns the coloured and formatted string. - def success(text) - puts "#{text}".foreground(:green) - end - - # Internal: Used for outputting a pretty error message. - # - # Returns the coloured and formatted string. - def fail(text) - puts "#{text}".foreground(:red) - end - - # Internal: Used for outputting a pretty info message. - # - # Returns the coloured and formatted string. - def info(text) - puts "#{text}".foreground(:cyan) - end - - # Internal: Create a request to the Acquia API. - # - # The request generated contains all the correct user authentication and - # headers. - # - # Returns a JSON string of the body. - def acquia_api_call(resource, method = "GET", data = {}) - n = Netrc.read - @acquia_user, @acquia_password = n["cloudapi.acquia.com"] - - # Check if the user is behind a proxy and add the proxy settings if found. - if using_proxy? - conn = Faraday.new(:proxy => ENV["HTTPS_PROXY"]) - else - conn = Faraday.new - end - - conn.basic_auth(@acquia_user, @acquia_password) - - case method - when "GET" - response = conn.get "https://cloudapi.acquia.com/v1/#{resource}.json" - JSON.parse response.body - when "POST" - response = conn.post "https://cloudapi.acquia.com/v1/#{resource}.json", data.to_json - JSON.parse response.body - when "CODE-DEPLOY-POST" - response = conn.post "https://cloudapi.acquia.com/v1/#{resource}.json?path=#{data[:release]}" - JSON.parse response.body - when "DELETE" - response = conn.delete "https://cloudapi.acquia.com/v1/#{resource}.json" - JSON.parse response.body - 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 get_acquia_environments(subscription) - env_data = acquia_api_call "sites/#{subscription}/envs" - - envs = [] - env_data.each do |env| - envs << env["name"] - end - - envs - end - - # Internal: Truncate a SSH key to a secure and recognisable size. - # - # Displaying whole SSH keys is probably a bad idea so instead we are getting - # the first 30 characters and the last 100 characters of the key and - # separating them with an ellipis. This allows you to recognise the - # important parts of the key instead of the whole thing. - # - # Returns string. - def truncate_ssh_key(ssh_key) - front_part = ssh_key[0...30] - back_part = ssh_key[-50, 50] - new_ssh_key = "#{front_part}...#{back_part}" - end - - # Internal: Send a request to purge a domain's cache. - # - # Purge the web cache via an API call. - # - # Returns a status message. - def purge_acquia_domain(subscription, environment, domain) - # Ensure all the required fields are available. - if subscription.nil? || environment.nil? || domain.nil? - fail "Purge request is missing a required parameter." - return - end - - purge_request = acquia_api_call "sites/#{subscription}/envs/#{environment}/domains/#{domain}/cache", "DELETE" - success "#{domain} has been successfully purged." if purge_request["id"] - end - - # Internal: Check whether a proxy is in use. - # - # Return boolean based on whether HTTPS_PROXY is set. - def using_proxy? - if ENV["HTTPS_PROXY"] - true - else - false - end - end - - # Internal: Output information on a database instance. - def output_database_instance(database) - say "> Username: #{database["username"]}" - say "> Password: #{database["password"]}" - say "> Host: #{database["host"]}" - say "> DB cluster: #{database["db_cluster"]}" - say "> Instance name: #{database["instance_name"]}" - end - - # Internal: Output information for a single task item. - def output_task_item(task) - completion_time = (task["completed"].to_i - task["started"].to_i) / 60 - say - say "Task ID: #{task["id"].to_i}" - say "Description: #{task["description"]}" - say "Status: #{task["state"]}" - - # If the completion time is greater then 0, output it in minutes otherwise - # just say it was less then a minute. - if completion_time > 0 - say "Compeletion time: About #{completion_time} minutes" - else - say "Compeletion time: Less than 1 minute" - end - - say "Queue: #{task["queue"]}" - end - } - - # Public: Log into the Acquia Cloud API. - # - # This sets up the user account within the netrc file so that subsequent - # calls can reuse the authentication without the user being prompted for it. - # - # Returns the status of your login attempt. - desc "login", "Login to your Acquia account." - def login - user = ask "Enter your username:" - password = ask "Enter your password:" - - # Update (or create if needed) the netrc file that will contain the user - # authentication details. - n = Netrc.read - n.new_item_prefix = "# This entry was added for connecting to the Acquia Cloud API\n" - n["cloudapi.acquia.com"] = user, password - n.save - - success "Your user credentials have been successfully set." - end - - # Public: Display an overview of the subscriptions. - # - # Returns all subscriptions with their respective data. - desc "list-subscriptions", "Find all subscriptions that you have access to." - def list_subscriptions - subscriptions = acquia_api_call "sites" - - subscriptions.each do |subscription| - say - # Get the individual subscription information. - subscription_info = acquia_api_call "sites/#{subscription}" - say "#{subscription_info["title"]}" - say "> Username: #{subscription_info["unix_username"]}" - say "> Subscription: #{subscription_info["name"]}" - - # If the VCS type is SVN, we want it in all uppercase, otherwise just - # capitilise it. - if subscription_info["vcs_type"] == 'svn' - say "> #{subscription_info["vcs_type"].upcase} URL: #{subscription_info["vcs_url"]}" - else - say "> #{subscription_info["vcs_type"].capitalize} URL: #{subscription_info["vcs_url"]}" - end - end - end - - # Public: Provide an overview of the environments in your subscription. - # - # Returns the environment data in a pretty format. - desc "list-environments <subscription>", "Provide an overview of the environments in your subscription." - option :environment, :aliases => "-e" - def list_environments(subscription) - # If the environment option is set, just fetch a single environment. - if options[:environment] - subscription_envs = [options[:environment]] - else - subscription_envs = get_acquia_environments(subscription) - end - - subscription_envs.each do |environment| - env_info = acquia_api_call "sites/#{subscription}/envs/#{environment}" - say - say "> Host: #{env_info["ssh_host"]}" - say "> Environment: #{env_info["name"]}" - say "> Current release: #{env_info["vcs_path"]}" - say "> DB clusters: #{env_info["db_clusters"].to_s unless env_info["db_clusters"].nil?}" - say "> Default domain: #{env_info["default_domain"]}" - end - end - - # Public: Get server specs and information from an environment. - # - # This allows the ability to get all the server data from all server types - # that are available within the subscription's environments. - # - # Returns server information on a per environment basis. - desc "list-servers <subscription>", "Get a list of servers specifications for an environment." - option :environment, :aliases => "-e" - def list_servers(subscription) - # Determine if we want just a single environment, or all of them at once. - if options[:environment] - subscription_envs = [options[:environment]] - else - subscription_envs = get_acquia_environments(subscription) - end - - # Loop over each environment and get all the associated server data. - subscription_envs.each do |environment| - if options[:environment].nil? - say - say "Environment: #{environment}" - end - - server_env = acquia_api_call "sites/#{subscription}/envs/#{environment}/servers" - server_env.each do |server| - say - say "> Host: #{server["fqdn"]}" - say "> EC2 region: #{server["ec2_region"]}" - say "> Availability zone: #{server["ec2_availability_zone"]}" - say "> EC2 instance type: #{server["ami_type"]}" - - # Show how many PHP processes this node can have. Note, this is only - # available on the web servers. - if server["services"] && server["services"]["php_max_procs"] - say "> PHP max processes: #{server["services"]["php_max_procs"]}" - end - - if server["services"] && server["services"]["status"] - say "> Status: #{server["services"]["status"]}" - end - - if server["services"] && server["services"]["web"] - say "> Web status: #{server["services"]["web"]["status"]}" - end - - # The state of varnish. - if server["services"] && server["services"]["varnish"] - say "> Varnish status: #{server["services"]["varnish"]["status"]}" - end - - # Only load balancers will have the "external IP" property. - if server["services"] && server["services"]["external_ip"] - say "> External IP: #{server["services"]["external_ip"]}" - end - end - end - end - - # Public: Get information regarding the database instances. - # - # Within this method we have a few different options to get the information we - # require. If just an environment is passed, only the names are returned. Pass - # the environment param and the username, pasword, host, db cluster and - # instance name are returned for each database available. Passing a database - # name and the environment will only return that particular database. - # - # Returns database information. - desc "list-databases <subscription>", "See information about the databases within a subscription." - option :environment, :aliases => "-e" - option :database, :aliases => "-d" - def list_databases(subscription) - # If we have both the database name and environment, only fetch a single - # result. - if options[:database] && options[:environment] - database = acquia_api_call "sites/#{subscription}/envs/#{options[:environment]}/dbs/#{options[:database]}" - say - output_database_instance(database) - return - end - - # Fetch all the databases in a specific environment. - if options[:environment] - databases = acquia_api_call "sites/#{subscription}/envs/#{options[:environment]}/dbs" - databases.each do |db| - say - say "#{db["name"]}" - output_database_instance(db) - end - else - subscription_envs = [options[:environment]] - databases = acquia_api_call "sites/#{subscription}/dbs" - - say - databases.each do |db| - say "> #{db["name"]}" - end - end - end - - # Public: List all backups for a database instance. - # - # Fetching all database backups for an instance is a pretty heavy call as the - # data isn't restricted in any way by time, id's, etc. - # - # Returns a database backup listing. - desc "list-database-backups <subscription> <environment> <database>", "Get all backups for a database instance." - def list_database_backups(subscription, environment, database) - backups = acquia_api_call "sites/#{subscription}/envs/#{environment}/dbs/#{database}/backups" - backups.each do |backup| - say - say "> ID: #{backup["id"]}" - say "> MD5: #{backup["checksum"]}" - say "> Type: #{backup["type"]}" - say "> Path: #{backup["path"]}" - say "> Link: #{backup["link"]}" - say "> Started: #{Time.at(backup["started"].to_i)}" - say "> Completed: #{Time.at(backup["completed"].to_i)}" - end - end - - # Public: Create a new database instance. - # - # Returns a success message upon creation. - desc "add-database <subscription> <database>", "Create a new database instance." - def add_database(subscription, database) - add_database = acquia_api_call "sites/#{subscription}/dbs", "POST", :db => "#{database}" - success "A new database has been created." if add_database["id"] - end - - # Public: Delete a database instance. - # - # Returns a status message based on the task completion. - desc "delete-database <subscription> <database>", "Remove all instances of a database." - def delete_database(subscription, database) - delete_db = acquia_api_call "sites/#{subscription}/dbs/#{database}?backup=0", "DELETE" - success "Database has been successfully deleted." if delete_db["id"] - end - - # Public: Copy a database from one environment to another. - # - # Returns the status message. - desc "copy-database <subscription> <database> <source> <destination>", "Copy a database one from environment to another." - def copy_database(subscription, database, source, destination) - copy_database = acquia_api_call "sites/#{subscription}/dbs/#{database}/db-copy/#{source}/#{destination}", "POST" - success "Database #{database} has been copied from #{source} to #{destination}." if copy_database["id"] - end - - # Public: Restore a previous database backup to a site. - # - # Returns a status message. - desc "restore-database-backup <subscription> <environment> <database> <backup_id>", "Restore a database backup." - def restore_database_backup(subscription, environment, database, backup_id) - restore_db = acquia_api_call "sites/#{subscription}/envs/#{environment}/dbs/#{database}/backups/#{backup_id}/restore", "POST" - success "Database backup #{backup_id} has been restored to #{database} in #{environment}." if restore_db["id"] - end - - # Public: Show all the available domains for a subscription. - # - # Returns a list of the domains available. - desc "list-domains <subscription>", "Show all available domains for a subscription." - option :environment, :aliases => "-e" - def list_domains(subscription) - if options[:environment] - subscription_envs = [options[:environment]] - else - subscription_envs = get_acquia_environments(subscription) - end - - subscription_envs.each do |environment| - domains = acquia_api_call "sites/#{subscription}/envs/#{environment}/domains" - # Got top padding? - if options[:environment] - say - else - say - say "Environment: #{environment}" - end - domains.each do |domain| - say "> #{domain["name"]}" - end - end - end - - # Public: Add a domain to an environment. - # - # Returns a status message on successful addition. - desc "add-domain <subscription> <environment> <domain>", "Add a domain to an environment." - def add_domain(subscription, environment, domain) - add_domain = acquia_api_call "/sites/#{subscription}/envs/#{environment}/domains/#{domain}", "POST" - success "Domain #{domain} has been successfully added to #{environment}." if add_domain["id"] - end - - # Public: Remove a domain from an environment. - # - # Returns a status message on successful deletion. - desc "delete-domain <subscription> <environment> <domain>", "Delete a domain from an environment." - def delete_domain(subscription, environment, domain) - delete_domain = acquia_api_call "/sites/#{subscription}/envs/#{environment}/domains/#{domain}", "DELETE" - success "Domain #{domain} has been successfully deleted from #{environment}." if delete_domain["id"] - end - - # Public: Clear a web cache on a domain. - # - # Send off a DELETE request to clear the web cache for a particular domain or - # environment. - # - # Note: Clearing a whole environment is pretty performance heavy - use with - # caution! - # - # Returns a status message form the purge request. - desc "purge-domain <subscription> <environment>", "Clear the web cache of an environment or domain." - option :domain, :aliases => "-d" - def purge_domain(subscription, environment) - domain = options[:domain] - - # If the domain is not defined, we are going to clear a whole environment. - # This can have severe performance impacts on your environments. We need to - # be sure this is definitely what you want to do. - if domain - purge_acquia_domain(subscription, environment, domain) - else - all_env_clear = ask "You are about to clear all domains in the #{environment} environment. Are you sure? (y/n)" - # Last chance to bail out. - if all_env_clear == "y" - domains = acquia_api_call "sites/#{subscription}/envs/#{environment}/domains" - domains.each do |domain| - purge_acquia_domain("#{subscription}", "#{environment}", "#{domain["name"]}") - end - else - info "Ok, no action has been taken." - end - end - end - - # Public: Get all the SVN users. - # - # Returns a list of the SVN users. - desc "list-svn-users <subscription>", "See all the SVN users on a subscription." - def list_svn_users(subscription) - svn_users = acquia_api_call "sites/#{subscription}/svnusers" - - svn_users.each do |user| - say - say "> ID: #{user["id"]}" - say "> Name: #{user["username"]}" - end - end - - desc "delete-svn-user <subscription> <userid>", "Delete a SVN user." - def delete_svn_user(subscription, userid) - svn_user_removal = acquia_api_call "sites/#{subscription}/svnusers/#{userid}", "DELETE" - success "#{userid} has been removed from the SVN users." if svn_user_removal["id"] - end - - # Public: Get users on the subscription. - # - # Display a user listing with a truncated SSH key for security and ease of - # use. - # - # Returns a list of users and truncated SSH keys. - desc "list-ssh-users <subscription>", "Find out who has access and SSH keys." - def list_ssh_users(subscription) - users = acquia_api_call "sites/#{subscription}/sshkeys" - - users.each do |user| - say - say "> ID: #{user["id"]}" - say "> Name: #{user["nickname"]}" - say "> Key: #{truncate_ssh_key user["ssh_pub_key"]}" - end - end - - # Public: Delete a SSH key from the subscription. - # - # Returns a status message. - desc "delete-ssh-user <subscription> <id>", "Delete a SSH key from the subscription." - def delete_ssh_user(subscription, id) - delete_ssh_request = acquia_api_call "sites/#{subscription}/sshkeys/#{id}", "DELETE" - success "SSH key #{id} has been successfully removed." if delete_ssh_request["id"] - end - - # Public: Copy files from one environment to another. - # - # Returns a status message. - desc "copy-files <subscription> <source> <destination>", "Copy files from one environment to another." - def copy_files(subscription, source, destination) - file_copy = acquia_api_call "/sites/#{subscription}/files-copy/#{source}/#{target}", "POST" - success "File copy from #{source} to #{destination} has started." if file_copy["id"] - end - - # Public: Deploy a VCS branch or tag to an environment. - # - # NB: Unfortunately the API endpoint for this functionality is formed a little - # differently to the others. It requires that the VCS path is appended to the - # URL compared to plain old POST request with parameters as a payload. To - # combat this, a pseudo request is made. It is a POST request at heart, just - # named differently to allow this functionality to be separated out. - # - # Returns a status message string. - desc "deploy-code <subscription> <environment> <release>", "Deploy a specific VCS branch or tag to an environment." - def deploy_code(subscription, environment, release) - deploy_code = acquia_api_call "sites/#{subscription}/envs/#{environment}/code-deploy", "CODE-DEPLOY-POST", :release => "#{release}" - success "#{release} has been deployed to #{environment}." if deploy_code["id"] - end - - # Public: Show tasks for a subscription. - # - # Returns a listing of tasks for a subscription. - desc "list-tasks <subscription>", "Display tasks associated with a subscription." - option :count, :aliases => "-c" - option :queue, :aliases => "-q" - def list_tasks(subscription) - all_tasks = acquia_api_call "sites/#{subscription}/tasks" - tasks = [] - - # Fetch a single queue from the tasks list if the queue parameter is set - # otherwise just add all the tasks. - if options[:queue] - all_tasks.each do |task| - if task["queue"] == options[:queue] - tasks << task - end - end - else - all_tasks.each do |task| - tasks << task - end - end - - # If there is a count to return, restrict it to that required amount. - if options[:count] && tasks.any? - tasks = tasks.last(options[:count].to_i) - end - - tasks.each do |task| - output_task_item(task) - end - end +begin + AcquiaToolbelt::CLI.start +rescue + exit(1) end - -Acquia.start