require 'app42/command/user_key' require "interact/progress" require 'highline' require "interact" module App42 module Command class Base include App42::Command::UserToken include App42::Base::Util include App42::Base::HttpHelper include Interactive include Interact::Progress # @return # dup argument to get a non-frozen string def initialize(options={} ) @options = options.dup @connection = App42::Client::App42RestClient.new HOST @api_key, @secret_key = get_keys if check_key_file? App42::Command::Auth.is_authorize?(@api_key, @secret_key) @host = HOST end # collect application name from user # if application name will not available # User can try 3 more times with different application name def get_app_name_and_check_app_url_availability @aa_retry ||= 1 exit! if (@aa_retry += 1 ) >= 5 app_name = get_app_name available = app_url_availability app_name return available if available end # get supported virtual machine type by app42paas def get_vm_types vm_type = App42::Command::Config.new.get_vm_type vm_type_array = vm_type['deploymentType'].map(&:capitalize) input "Select Virtual Machine Type", vm_type_array, true end # @return iaas providers def get_iaas_providers iaas_provider_hash = {} iaas_providers = App42::Command::Config.new.get_iaas_provider iaas_providers['iaas'].select {|each_iaas| iaas_provider_hash["#{each_iaas['id']}"] = each_iaas['name'] + ' ' + each_iaas['zone']} iaas = input "Select IaaS Provider", iaas_provider_hash.values, true iaas_provider_id = nil iaas_provider_hash.each_pair{|ip| iaas_provider_id = ip[0] if ip[1] == iaas} return iaas_provider_id end # collect remaining vm configuration details from user def get_app_source app_name, iaas, vm_type collect_vm_details app_name, iaas, vm_type end # Ask application name from user and # will wait for user response (user will enter application name) def get_app_name(prompt = Paint['Application Name', :cyan]) app_name = ask(prompt) {|q| q.each = true} valid_app_name = validate_app_and_service_name "App name", app_name.strip valid_app_name ? (return valid_app_name) : get_app_name end # get supported runtime by app42paas def get_runtime runtime_hash = {} runtimes = App42::Command::Config.new.get_runtimes runtimes['runtimes'].select {|each_rt| runtime_hash["#{each_rt['id']}"] = each_rt['name'] + ' ' + each_rt['version']} rt = input "Select Runtime", runtime_hash.values, true rt_id = nil runtime_hash.each_pair{|r| rt_id = r[0] if r[1] == rt} return rt_id end # get supported frameworks def get_framework iaas, vm_type, rt framework_hash = {} frameworks = App42::Command::Config.new.get_frameworks iaas, vm_type, rt frameworks['frameworks'].select {|each_fw| framework_hash["#{each_fw['id']}"] = each_fw['name'] + ' ' + each_fw['version']} framework = input "Select Framework", framework_hash.values, true framework_id = nil framework_hash.each_pair{|f| framework_id = f[0] if f[1] == framework} return framework_id end # get supported webserver def get_webserver iaas, vm_type, rt, framework webserver_hash = {} webservers = App42::Command::Config.new.get_webservers( iaas, vm_type, rt, framework) webservers['webServer'].select {|each_ws| webserver_hash["#{each_ws['id']}"] = each_ws['name'] + ' ' + each_ws['version']} webserver = input "Select Web Server", webserver_hash.values, true webserver_id = nil webserver_hash.each_pair{|ws| webserver_id = ws[0] if ws[1] == webserver} return webserver_id end # get supported operating system for app def get_os_for_app iaas, vm_type, rt, framework, webserver os_hash = {} operating_sys = App42::Command::Config.new.get_operating_sys_for_app( iaas, vm_type, rt, framework, webserver) if operating_sys['osDetail'].length > 1 operating_sys['osDetail'].select {|each_os| os_hash["#{each_os['id']}"] = each_os['name'] + ' ' + each_os['version']} os = input "Select Operating System", os_hash.values, true os_id = nil os_hash.each_pair{|o| os_id = o[0] if o[1] == os} return os_id else return operating_sys['osDetail'][0]['id'] end end # get supported operating system for service def get_os_for_service iaas, vm_type, service os_hash = {} operating_sys = App42::Command::Config.new.get_operating_sys_for_service( iaas, vm_type, service) if operating_sys['osDetail'].length > 1 operating_sys['osDetail'].select {|each_os| os_hash["#{each_os['id']}"] = each_os['name'] + ' ' + each_os['version']} os = input "Select Operating System", os_hash.values, true os_id = nil os_hash.each_pair{|o| os_id = o[0] if o[1] == os} return os_id else return operating_sys['osDetail'][0]['id'] end end # get supported vm configuration by app42paas def get_vmconfig vm_type, iaas vmconfig_hash = {} vmconfig = App42::Command::Config.new.get_vmconfig(vm_type, iaas) vmconfig['vmconfig'].select {|each_vmcf| vmconfig_hash["#{each_vmcf['id']}"] = each_vmcf['memory'] + ' ' + each_vmcf['memoryUnit']} vm_cf = input "Memory Limit", vmconfig_hash.values, true vm_cf_id = nil vmconfig_hash.each_pair{|vmcf| vm_cf_id = vmcf[0] if vmcf[1] == vm_cf} return vm_cf_id end # collect type of application source supported by app42paas def collect_app_source app_name app_source = 'Binary' proceed = ask( Paint["Would you like to deploy from the current directory?", :cyan], :default => true ) if proceed source_url = Dir.getwd app_file_name = is_binary_exist? source_url, app_name end unless proceed source_url = get_source_path app_source if source_url.include?('.zip') || source_url.include?('.war') || source_url.include?('.tar.gz') || source_url.include?('.gzip') return app_source, source_url end app_file_name = is_binary_exist? source_url, app_name end return app_source, app_file_name end # private # check app availabilities def app_url_availability app_name query_params = params query_params.store('appName', app_name) response = with_progress(Paint["\nChecking App Name Availability", :yellow]) do |s| build_get_request query_params, 'app', 'availability' end if response["success"] print_new_line return app_name else message "#{response['description']}", true, 'red' get_app_name_and_check_app_url_availability end end # check service availabilities def service_name_availability service_name query_params = params query_params.store('serviceName', service_name) response = with_progress(Paint["Checking Service Name Availability", :yellow]) do |s| build_get_request query_params, 'service', 'availability' end if response["success"] print_new_line return service_name else message "#{response['description']}", true, 'red' return nil end end # infrastructure setup call def create_infrastructure app_name, iaas, vm_type, runtime, framework, webserver, os, vmconfig begin body = {'app42' => {"request"=> { "appName" => app_name, "iaas" => iaas, "vmType" => vm_type, "runtime" => runtime, "framework" => framework, "webServer" => webserver, "os" => os, "vmConfig" => vmconfig }}}.to_json query_params = params query_params.store('body', body) response = with_progress(Paint["Creating Infrastructure", :yellow]) do |s| build_post_request body, query_params, 'app', nil end if response["success"] == true && response["transactionId"] transaction_success = check_transaction_status response["transactionId"], previous_completed = 0, 'created' end if transaction_success transaction_params = params transaction_params.store('appName', app_name) host_response = build_get_request transaction_params, "app", "#{app_name}" end if host_response['success'] puts Paint["Default Application Deployed. URL is: #{host_response['appInfo']['appUrl']}", :green] return true else puts Paint["#{response['description']}", :red] end rescue Interrupt puts Paint[" Command cancelled.", :red] exit! end end # Binary upload call def upload_binary app_name, app_source, source_url @code_flag ||= 1 begin if source_url.include?('.war') || source_url.include?('.zip') || source_url.include?('.tar.gz') || source_url.include?('.gzip') query_params = params query_params.store('appName', app_name) message "#{Message::WAIT_FOR_WHILE}", true, 'green' response = with_progress(Paint["Deploying Application", :yellow]) do |s| @connection.multipart(signature(query_params), resource_url("app", "binary"), query_params, query_params, source_url) end else body = {'app42' => {"request"=> { "appName" => app_name, "sourcetype" => app_source, "sourceUrl" => source_url, }}}.to_json query_params = params query_params.store('body', body) response = with_progress(Paint["Deploying Application", :yellow]) do |s| build_put_request body, query_params, 'app', 'source' end end if response["success"] == true && response["transactionId"] check_transaction_status response["transactionId"], previous_completed = 0, 'Uploaded' end if response['success'] exit! else puts Paint["#{response['description']}", :red] exit 1 if ( @code_flag += 1 ) > 3 get_binary_url app_name end rescue Interrupt puts Paint[" Command cancelled.", :red] exit! rescue Exception => e puts e end return response end # It's common methods of app information like app state, info etc. # methods expect +what+ as operation and +app_name+ as Application name def app_information what, app_name query_params = params query_params.store('appName', app_name) begin response = build_get_request query_params, "#{what}", "#{app_name}" rescue Exception => e puts e exit! end return response end # Scale or descale application by no of instance, # expect +what+ as operation and instance as no of instance def scale_or_descale_app what, instance, app_name begin body = {'app42' => {"request"=> { 'appName' => app_name, "instanceCount" => instance }}}.to_json query_params = params query_params.store('body', body) response = with_progress( Paint[ what.to_s == 'scale' ? "Scaling Application #{app_name} by instance #{instance}" : "Descaling Application #{app_name} by instance #{instance}", :yellow]) do |s| build_post_request body, query_params, "app", what end check_transaction_status response["transactionId"], previous_completed = 0, "#{what}d" if response["success"] == true && response["transactionId"] response['success'] ? (return true) : (message "#{response['description']}", true, 'red') rescue Interrupt puts Paint[" Command cancelled.", :red] exit! rescue Exception => e puts e exit! end end # common methods for app42paas config request like runtimes,frameworks etc def interactive_get resource, get_obj begin response = build_get_request params, resource, get_obj rescue Exception => e puts e end return response end # All application operation will take placed like app start, stop etc. # expect +what+ as operation and +app_name+ as application name. def app_operation what, app_name begin if what.to_s == 'stop' response = with_progress(Paint[ "Stopping Application #{app_name}", :yellow]) do |s| body = {'app42' => {"request"=> { "appName" => app_name }}}.to_json query_params = params query_params.store('body', body) build_put_request body, query_params, "app", "#{what}" if what.to_s == 'restart' || what.to_s == 'stop' || what.to_s == 'start' end else response = with_progress(Paint[ what.to_s == 'delete' ? "Deleting Application #{app_name}" : "#{what.capitalize}ing Application #{app_name}", :yellow]) do |s| if what.to_s == 'delete' query_params = params query_params.store('appName', app_name) build_delete_request query_params, "app", "#{app_name}" else body = {'app42' => {"request"=> { "appName" => app_name }}}.to_json query_params = params query_params.store('body', body) build_put_request body, query_params, "app", "#{what}" if what.to_s == 'restart' || what.to_s == 'stop' || what.to_s == 'start' end end end if response["success"] == true && response["transactionId"] if what.to_s == 'delete' check_transaction_status response["transactionId"], previous_completed = 0, "#{what}d" elsif what.to_s == 'stop' check_transaction_status response["transactionId"], previous_completed = 0, "#{what}ped" else check_transaction_status response["transactionId"], previous_completed = 0, "#{what}ed" end end response['success'] ? (return true) : (message "#{response['description']}", true, 'red') rescue Interrupt puts Paint[" Command cancelled.", :red] exit! end end # create service and get all relevant service information post service creation. # # ==== Parameters # service = type of service mysql,mongodb etc # service_name = service name provided by user # database = database name provided by user # vm_type = shared OR dedicated # iaas = zone where user want to create service # vmconfig = virtual machine configuration details # os = ubuntu OR Window # # ==== return # will display service details in tabular form and # will exist console def create_service service, service_name ,database, vm_type, iaas, vmconfig, os body = {'app42' => {"request"=> { "service" => service, "serviceName" => service_name, "vmType" => vm_type, "database" => database, "iaas" => iaas, "vmconfig" => vmconfig, "os" => os }}}.to_json query_params = params query_params.store('body', body) begin response = with_progress(Paint["Creating Service", :yellow]) do |s| build_post_request body, query_params, 'service', nil end rescue Interrupt puts Paint[" Command cancelled.", :red] exit! end if response["success"] == true && response["transactionId"] transaction_response = check_transaction_status response["transactionId"], previous_completed = 0, 'created' end if transaction_response service_info_params = params service_info_params.store('serviceName', service_name) service_details = build_get_request service_info_params, "service", "#{service_name}" end if service_details['success'] rows, rows_header_final, rows_header = [], [], nil rows_header = service_details['service'].keys rows << service_details['service'].values rows_header.map { |e| rows_header_final << camel_case_to_whitespace(e) } table = Terminal::Table.new :title => Paint["=== #{service_name} Details ===", :green], :headings => rows_header_final, :rows => rows puts table else puts Paint["#{response['description']}", :red] end end # delete service, as a # # ==== Parameters # service_name = service name provided by user # # ==== return # true:: if service deleted # OR # ERROR message in case failed def delete_service service_name begin response = with_progress(Paint["Deleting Service", :yellow]) do |s| query_params = params query_params.store('serviceName', service_name) build_delete_request query_params, "service", "#{service_name}" end transaction_success = check_transaction_status response["transactionId"], previous_completed = 0, 'deleted' if response["success"] == true && response["transactionId"] response['success'] ? (return true) : (message "#{response['description']}", true, 'red') rescue Interrupt puts Paint[" Command cancelled.", :red] exit! rescue Exception => e puts e end end # reset service password and fetch service latest details # # ==== Parameters # service_name = service name provided by user # old_password = service old password # # ==== return # true:: if reset password successful # OR # ERROR message in case failed def reset_password service_name, old_password begin body = {'app42' => {"request"=> { "serviceName" => service_name, "password" => old_password }}}.to_json query_params = params query_params.store('body', body) response = with_progress(Paint["Resetting Password", :yellow]) do |s| build_put_request body, query_params, 'service', "password" end if response["success"] == true && response["transactionId"] transaction_response = check_transaction_status response["transactionId"], previous_completed = 0, 'created' end if transaction_response service_info_params = params service_info_params.store('serviceName', service_name) service_details = build_get_request service_info_params, "service", "#{service_name}" end service_details['success'] ? (return service_details) : (message "#{response['description']}", true , 'red') rescue Interrupt puts Paint[" Command cancelled.", :red] exit! rescue Exception => e puts e end end # Bind service to requested source IP and fetch service latest details # # ==== Parameters # service_name = service name provided by user # source_ip = source IP to which service will get bind # access_time = time duration user want to bind IP to service # # ==== return # display service bind details in tabular form # OR # ERROR message in case failed def create_service_tunnel service_name, source_ip begin body = {'app42' => {"request"=> { "serviceName" => service_name, "sourceIp" => source_ip }}}.to_json query_params = params query_params.store('body', body) response = with_progress(Paint["Binding IP to service", :yellow]) do |s| build_put_request body, query_params, 'service', "bind" end if response["success"] == true && response["transactionId"] transaction_response = check_transaction_status response["transactionId"], previous_completed = 0, 'created' end if transaction_response service_info_params = params service_info_params.store('serviceName', service_name) service_tunnel_details = build_get_request service_info_params, "service", "tunnel/#{service_name}" end if service_tunnel_details['success'] rows, rows_header_final, rows_header = [], [], nil rows_header = service_tunnel_details['service'].keys rows << service_tunnel_details['service'].values rows_header.map { |e| rows_header_final << camel_case_to_whitespace(e) } table = Terminal::Table.new :title => Paint["=== #{service_name} Details ===", :green], :headings => rows_header_final, :rows => rows puts table else puts Paint["#{response['description']}", :red] end rescue Interrupt puts Paint[" Command cancelled.", :red] exit! rescue Exception => e puts e end end # Unbind service to requested source IP # # ==== Parameters # service_name = service name provided by user # source_ip = source IP to which service will get bind # # ==== return # display service bind details in tabular form # OR # ERROR message in case failed def delete_service_tunnel service_name, source_ip begin body = {'app42' => {"request"=> { "serviceName" => service_name, "sourceIp" => source_ip }}}.to_json query_params = params query_params.store('body', body) response = with_progress(Paint["Unbinding IP to service", :yellow]) do |s| build_put_request body, query_params, 'service', "unbind" end if response["success"] == true && response["transactionId"] transaction_response = check_transaction_status response["transactionId"], previous_completed = 0, 'created' return true end rescue Interrupt puts Paint[" Command cancelled.", :red] exit! rescue Exception => e puts e end end # # return no of instance # def get_instance obj instance = @options[:instance] if @options[:instance] unless instance instance = nil instance = ask Paint[ obj == 'new_vm' ? "No of instances you want?" : "#{obj.capitalize} by instance(s)", :cyan] end instance_count = number_valid? instance if instance_count return instance_count else message "#{Message::NOT_A_VALID_NUM}", true, 'red' get_instance obj end end end end end