class RHC::Commands::App
Constants
- DEFAULT_DELAY_THROTTLE
- MAX_RETRIES
Public Instance Methods
configure(app_name)
click to toggle source
# File lib/rhc/commands/app.rb, line 512 def configure(app_name) rest_app = find_app app_options = {} app_options[:auto_deploy] = options.auto_deploy if !options.auto_deploy.nil? app_options[:keep_deployments] = options.keep_deployments if options.keep_deployments app_options[:deployment_branch] = options.deployment_branch if options.deployment_branch app_options[:deployment_type] = options.deployment_type if options.deployment_type if app_options.present? paragraph do say "Configuring application '#{app_name}' ... " rest_app.configure(app_options) success "done" end end paragraph { display_app(find_app, nil, [:auto_deploy, :keep_deployments, :deployment_type, :deployment_branch]) } paragraph { say "Your application '#{rest_app.name}' is #{app_options.empty? ? '' : 'now '}configured as listed above." } paragraph { say "Use 'rhc show-app #{rest_app.name} --configuration' to check your configuration values any time." } if app_options.present? 0 end
create(name, cartridges)
click to toggle source
# File lib/rhc/commands/app.rb, line 68 def create(name, cartridges) check_config! check_name!(name) arg_envs, cartridges = cartridges.partition{|item| item.match(env_var_regex_pattern)} rest_domain = check_domain! rest_app = nil repo_dir = nil if options.from_app raise RHC::AppCloneNotSupportedException, "The server does not support creating apps based on others (rhc create-app --from-app)." if (!rest_domain.has_param?('ADD_APPLICATION', 'cartridges[][name]') || !rest_domain.has_param?('ADD_APPLICATION', 'cartridges[][url]')) raise ArgumentError, "Option --from-code is incompatible with --from-app. When creating an app based on another resource you can either specify a Git repository URL with --from-code or an existing app name with --from-app." if options.from_code raise ArgumentError, "Option --no-dns is incompatible with --from-app. We need to propagate the new app DNS to be able to configure it." if options.dns == false raise ArgumentError, "Do not specify cartridges when creating an app based on another one. All cartridges will be copied from the original app." if !(cartridges || []).empty? from_app = find_app(:app => options.from_app) arg_envs = from_app.environment_variables.collect {|env| "#{env.name}=#{env.value}"} + arg_envs cartridges = from_app.cartridges.reject{|c| c.tags.include?('web_proxy')}.collect{|c| c.custom? ? c.url : c.name} end cartridges = check_cartridges(cartridges, &require_one_web_cart) options.default \ :dns => true, :git => true raise ArgumentError, "You have named both your main application and your Jenkins application '#{name}'. In order to continue you'll need to specify a different name with --enable-jenkins or choose a different application name." if jenkins_app_name == name && enable_jenkins? cart_names = cartridges.collect do |c| c.usage_rate? ? "#{c.short_name} (addtl. costs may apply)" : c.short_name end.join(', ') env = collect_env_vars(arg_envs.concat(Array(options.env))) if options.env && env.empty? raise RHC::EnvironmentVariableNotProvidedException.new( "Environment variable(s) not provided.\n" + "Please provide at least one environment variable using the syntax VARIABLE=VALUE. VARIABLE can only contain letters, digits and underscore ('_') and can't begin with a digit.") end if env.present? && !rest_domain.supports_add_application_with_env_vars? env = [] warn "Server does not support environment variables." end scaling = options.scaling region = options.region gear_profile = options.gear_size ha = nil raise RHC::RegionsAndZonesNotSupportedException if region.present? && !rest_client.supports_regions_and_zones? if from_app scaling = from_app.scalable if scaling.nil? region = from_app.region if region.nil? gear_profile = from_app.gear_profile if gear_profile.nil? ha = from_app.ha? if !from_app.ha.nil? if region.present? && !rest_client.allows_region_selection? region = nil warn 'Server does not allow selecting regions. Region is being ignored.' end cartridges = from_app.cartridges.reject{|c| c.tags.include?('web_proxy')}.collect do |cartridge| { :name => (cartridge.name if !cartridge.custom?), :url => (cartridge.url if cartridge.custom?), :gear_size => options.gear_size || cartridge.gear_profile, :additional_gear_storage => (cartridge.additional_gear_storage if cartridge.additional_gear_storage > 0), :scales_from => (cartridge.scales_from if scaling && cartridge.scalable?), :scales_to => (cartridge.scales_to if scaling && cartridge.scalable?) }.reject{|k,v| v.nil? } end end paragraph do header "Application Options" say table([["Domain:", options.namespace], ["Cartridges:", cart_names], (["Source Code:", options.from_code] if options.from_code), (["From app:", from_app.name] if from_app), ["Gear Size:", options.gear_size || (from_app ? "Copied from '#{from_app.name}'" : "default")], ["Scaling:", (scaling ? "yes" : "no") + (from_app && options.scaling.nil? ? " (copied from '#{from_app.name}')" : '')], (["HA:", (ha ? "yes" : "no") + (from_app ? " (copied from '#{from_app.name}')" : '')] if ha.present?), (["Environment Variables:", env.map{|item| "#{item.name}=#{item.value}"}.join(', ')] if env.present?), (["Region:", region + (from_app && options.region.nil? ? " (copied from '#{from_app.name}')" : '')] if region), ].compact ) end paragraph do say "Creating application '#{name}' ... " # create the main app rest_app = create_app(name, cartridges, rest_domain, gear_profile, scaling, options.from_code, env, options.auto_deploy, options.keep_deployments, options.deployment_branch, options.deployment_type, region, ha) success "done" paragraph{ indent{ success rest_app.messages.map(&:strip) } } end build_app_exists = rest_app.building_app if enable_jenkins? unless build_app_exists paragraph do say "Setting up a Jenkins application ... " begin build_app_exists = add_jenkins_app(rest_domain) success "done" paragraph{ indent{ success build_app_exists.messages.map(&:strip) } } rescue Exception => e warn "not complete" add_issue("Jenkins failed to install - #{e}", "Installing jenkins and jenkins-client", "rhc create-app jenkins jenkins-1", "rhc add-cartridge jenkins-client -a #{rest_app.name}") end end end paragraph do messages = [] add_jenkins_client_to(rest_app, messages) paragraph{ indent{ success messages.map(&:strip) } } end if build_app_exists end debug "Checking SSH keys through the wizard" check_sshkeys! unless options.no_keys if options.dns paragraph do say "Waiting for your DNS name to be available ... " if dns_propagated? rest_app.host success "done" else warn "failure" add_issue("We were unable to lookup your hostname (#{rest_app.host}) in a reasonable amount of time and can not clone your application.", "Clone your git repo", "rhc git-clone #{rest_app.name}") output_issues(rest_app) return 0 end end end if from_app say "Setting deployment configuration ... " rest_app.configure({:auto_deploy => from_app.auto_deploy, :keep_deployments => from_app.keep_deployments , :deployment_branch => from_app.deployment_branch, :deployment_type => from_app.deployment_type}) success 'done' snapshot_filename = temporary_snapshot_filename(from_app.name) save_snapshot(from_app, snapshot_filename) restore_snapshot(rest_app, snapshot_filename) File.delete(snapshot_filename) if File.exist?(snapshot_filename) paragraph { warn "The application '#{from_app.name}' has aliases set which were not copied. Please configure the aliases of your new application manually." } unless from_app.aliases.empty? end if options.git section(:now => true, :top => 1, :bottom => 1) do begin if has_git? repo_dir = git_clone_application(rest_app) else warn "You do not have git installed, so your application's git repo will not be cloned" end rescue RHC::GitException => e warn "#{e}" unless RHC::Helpers.windows? and windows_nslookup_bug?(rest_app) add_issue("We were unable to clone your application's git repo - #{e}", "Clone your git repo", "rhc git-clone #{rest_app.name}") end end end end output_issues(rest_app) if issues? paragraph do say "Your application '#{rest_app.name}' is now available." paragraph do indent do say table [ ['URL:', rest_app.app_url], ['SSH to:', rest_app.ssh_string], ['Git remote:', rest_app.git_url], (['Cloned to:', repo_dir] if repo_dir) ].compact end end end paragraph{ say "Run 'rhc show-app #{name}' for more details about your app." } 0 end
delete(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 281 def delete(app) rest_app = find_app confirm_action "#{color("This is a non-reversible action! Your application code and data will be permanently deleted if you continue!", :yellow)}\n\nAre you sure you want to delete the application '#{app}'?" say "Deleting application '#{rest_app.name}' ... " rest_app.destroy success "deleted" paragraph{ rest_app.messages.each{ |s| success s } } 0 end
deploy(ref)
click to toggle source
# File lib/rhc/commands/app.rb, line 495 def deploy(ref) rest_app = find_app raise RHC::DeploymentsNotSupportedException.new if !rest_app.supports? "DEPLOY" deploy_artifact(rest_app, ref, options.hot_deploy, options.force_clean_build) 0 end
enable_ha(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 378 def enable_ha(app) app_action :enable_ha results { say "#{app} is now highly available" } 0 end
force_stop(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 338 def force_stop(app) app_action :stop, true results { say "#{app} force stopped" } 0 end
reload(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 358 def reload(app) app_action :reload results { say "#{app} config reloaded" } 0 end
restart(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 348 def restart(app) app_action :restart results { say "#{app} restarted" } 0 end
scale_down(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 328 def scale_down(app) app_action :scale_down results { say "#{app} scaled down" } 0 end
scale_up(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 318 def scale_up(app) app_action :scale_up results { say "#{app} scaled up" } 0 end
show(app_name)
click to toggle source
# File lib/rhc/commands/app.rb, line 415 def show(app_name) if options.state find_app(:with_gear_groups => true).each do |gg| say "Cartridge #{gg.cartridges.collect { |c| c['name'] }.join(', ')} is #{gear_group_state(gg.gears.map{ |g| g['state'] })}" end elsif options.gears && options.gears != true groups = find_app(:with_gear_groups => true) case options.gears when 'quota' opts = {:as => :gear, :split_cells_on => /\s*\t/, :header => ['Gear', 'Cartridges', 'Used', 'Limit'], :align => [nil, nil, :right, :right]} table_from_gears('echo "$(du --block-size=1 -s 2>/dev/null | cut -f 1)"', groups, opts) do |gear, data, group| [gear['id'], group.cartridges.collect{ |c| c['name'] }.join(' '), (human_size(data.chomp) rescue 'error'), human_size(group.quota)] end when 'ssh' groups.each{ |group| group.gears.each{ |g| say (ssh_string(g['ssh_url']) or raise NoPerGearOperations) } } else run_on_gears(ssh_command_for_op(options.gears), groups) end elsif options.gears domain, app = discover_domain_and_app gear_info = rest_client.find_application_gear_groups_endpoints(domain, app).map do |group| group.gears.map do |gear| color_cart = if gear['endpoints'].present? e = gear['endpoints'].collect{ |c| c['cartridge_name'] }.uniq lambda { |c| e.include?(c) ? color(c, :green) : c } else lambda { |c| c } end [ gear['id'], gear['state'] == 'started' ? color(gear['state'], :green) : color(gear['state'], :yellow), group.cartridges.collect{ |c| color_cart.call(c['name']) }.join(' '), group.gear_profile, gear['region'], gear['zone'], ssh_string(gear['ssh_url']) ] end end.flatten(1) explicit_regions = gear_info.select{|i| !i[4].nil?}.present? explicit_zones = gear_info.select{|i| !i[5].nil?}.present? say table(gear_info.map(&:compact), :header => ['ID', 'State', 'Cartridges', 'Size', explicit_regions ? 'Region' : nil, explicit_zones ? 'Zone' : nil, 'SSH URL'].compact) elsif options.configuration display_app_configurations(find_app) paragraph { say "Use 'rhc configure-app' to change the configuration values of this application." } else app = find_app(:include => :cartridges) display_app(app, app.cartridges, nil, options.verbose) end 0 end
start(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 298 def start(app) app_action :start results { say "#{app} started" } 0 end
stop(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 308 def stop(app) app_action :stop results { say "#{app} stopped" } 0 end
tidy(app)
click to toggle source
# File lib/rhc/commands/app.rb, line 368 def tidy(app) app_action :tidy results { say "#{app} cleaned up" } 0 end
Private Instance Methods
add_issue(reason, commands_header, *commands)
click to toggle source
Issues collector collects a set of recoverable issues and steps to fix them for output at the end of a complex command
# File lib/rhc/commands/app.rb, line 789 def add_issue(reason, commands_header, *commands) @issues ||= [] issue = {:reason => reason, :commands_header => commands_header, :commands => commands} @issues << issue end
add_jenkins_app(rest_domain)
click to toggle source
# File lib/rhc/commands/app.rb, line 631 def add_jenkins_app(rest_domain) create_app(jenkins_app_name, jenkins_cartridge_name, rest_domain) end
add_jenkins_cartridge(rest_app)
click to toggle source
# File lib/rhc/commands/app.rb, line 635 def add_jenkins_cartridge(rest_app) rest_app.add_cartridge(jenkins_client_cartridge_name) end
add_jenkins_client_to(rest_app, messages)
click to toggle source
# File lib/rhc/commands/app.rb, line 639 def add_jenkins_client_to(rest_app, messages) say "Setting up Jenkins build ... " successful, attempts, exit_code, exit_message = false, 1, 157, nil while (!successful && exit_code == 157 && attempts < MAX_RETRIES) begin cartridge = add_jenkins_cartridge(rest_app) successful = true success "done" messages.concat(cartridge.messages) rescue RHC::Rest::ServerErrorException => e if (e.code == 157) # error downloading Jenkins /jnlpJars/jenkins-cli.jar attempts += 1 debug "Jenkins server could not be contacted, sleep and then retry: attempt #{attempts}\n #{e.message}" Kernel.sleep(10) end exit_code = e.code exit_message = e.message rescue Exception => e # timeout and other exceptions exit_code = 1 exit_message = e.message end end unless successful warn "not complete" add_issue("Jenkins client failed to install - #{exit_message}", "Install the jenkins client", "rhc add-cartridge jenkins-client -a #{rest_app.name}") end end
app_action(action, *args)
click to toggle source
# File lib/rhc/commands/app.rb, line 602 def app_action(action, *args) rest_app = find_app result = rest_app.send action, *args result end
check_config!()
click to toggle source
# File lib/rhc/commands/app.rb, line 577 def check_config! return if not interactive? or (!options.clean && config.has_local_config?) or (options.server && (options.rhlogin || options.token)) RHC::EmbeddedWizard.new(config, options).run end
check_domain!()
click to toggle source
# File lib/rhc/commands/app.rb, line 582 def check_domain! if options.namespace rest_client.find_domain(options.namespace) else if rest_client.domains.empty? raise RHC::Rest::DomainNotFoundException, "No domains found. Please create a domain with 'rhc create-domain <namespace>' before creating applications." unless interactive? RHC::DomainWizard.new(config, options, rest_client).run end domain = rest_client.domains.first raise RHC::Rest::DomainNotFoundException, "No domains found. Please create a domain with 'rhc create-domain <namespace>' before creating applications." unless domain options.namespace = domain.name domain end end
check_name!(name)
click to toggle source
# File lib/rhc/commands/app.rb, line 568 def check_name!(name) return unless name.blank? paragraph{ say "When creating an application, you must provide a name and a cartridge from the list below:" } paragraph{ list_cartridges(standalone_cartridges) } raise ArgumentError, "Please specify the name of the application and the web cartridge to install" end
check_sshkeys!()
click to toggle source
# File lib/rhc/commands/app.rb, line 563 def check_sshkeys! return unless interactive? RHC::SSHWizard.new(rest_client, config, options).run end
create_app(name, cartridges, rest_domain, gear_profile=nil, scale=nil, from_code=nil, environment_variables=nil, auto_deploy=nil, keep_deployments=nil, deployment_branch=nil, deployment_type=nil, region=nil, ha=nil)
click to toggle source
# File lib/rhc/commands/app.rb, line 608 def create_app(name, cartridges, rest_domain, gear_profile=nil, scale=nil, from_code=nil, environment_variables=nil, auto_deploy=nil, keep_deployments=nil, deployment_branch=nil, deployment_type=nil, region=nil, ha=nil) app_options = {:cartridges => Array(cartridges)} app_options[:gear_profile] = gear_profile if gear_profile app_options[:scale] = scale if scale app_options[:initial_git_url] = from_code if from_code app_options[:debug] = true if @debug app_options[:environment_variables] = environment_variables.map{|i| i.to_hash}.group_by{|i| i[:name]}.values.map(&:last) if environment_variables.present? app_options[:auto_deploy] = auto_deploy if !auto_deploy.nil? app_options[:keep_deployments] = keep_deployments if keep_deployments app_options[:deployment_branch] = deployment_branch if deployment_branch app_options[:deployment_type] = deployment_type if deployment_type app_options[:region] = region if region app_options[:ha] = ha if ha debug "Creating application '#{name}' with these options - #{app_options.inspect}" rest_domain.add_application(name, app_options) rescue RHC::Rest::Exception => e if e.code == 109 paragraph{ say "Valid cartridge types:" } paragraph{ list_cartridges(standalone_cartridges) } end raise end
dns_propagated?(host, sleep_time=2)
click to toggle source
# File lib/rhc/commands/app.rb, line 673 def dns_propagated?(host, sleep_time=2) # # Confirm that the host exists in DNS # debug "Start checking for application dns @ '#{host}'" found = false # Allow DNS to propagate Kernel.sleep 5 # Now start checking for DNS host_found = hosts_file_contains?(host) or 1.upto(MAX_RETRIES) { |i| host_found = host_exists?(host) break found if host_found say " retry # #{i} - Waiting for DNS: #{host}" Kernel.sleep sleep_time.to_i sleep_time *= DEFAULT_DELAY_THROTTLE } debug "End checking for application dns @ '#{host} - found=#{host_found}'" host_found end
enable_jenkins?()
click to toggle source
# File lib/rhc/commands/app.rb, line 700 def enable_jenkins? # legacy issue, commander 4.0.x will place the option in the hash with nil value (BZ878407) options.__hash__.has_key?(:enable_jenkins) end
format_issues(indent)
click to toggle source
# File lib/rhc/commands/app.rb, line 797 def format_issues(indent) return nil unless issues? indentation = " " * indent reasons = "" steps = "" @issues.each_with_index do |issue, i| reasons << "#{indentation}#{i+1}. #{issue[:reason].strip}\n" steps << "#{indentation}#{i+1}. #{issue[:commands_header].strip}\n" issue[:commands].each { |cmd| steps << "#{indentation} $ #{cmd}\n" } end [reasons, steps] end
gear_group_state(states)
click to toggle source
# File lib/rhc/commands/app.rb, line 597 def gear_group_state(states) return states[0] if states.length == 1 || states.uniq.length == 1 "#{states.select{ |s| s == 'started' }.count}/#{states.length} started" end
issues?()
click to toggle source
# File lib/rhc/commands/app.rb, line 813 def issues? not @issues.nil? end
jenkins_app_name()
click to toggle source
# File lib/rhc/commands/app.rb, line 705 def jenkins_app_name if options.enable_jenkins.is_a? String options.enable_jenkins end || "jenkins" end
jenkins_cartridge_name()
click to toggle source
# File lib/rhc/commands/app.rb, line 711 def jenkins_cartridge_name jenkins_cartridges.last.name end
jenkins_client_cartridge_name()
click to toggle source
# File lib/rhc/commands/app.rb, line 715 def jenkins_client_cartridge_name jenkins_client_cartridges.last.name end
output_issues(rest_app)
click to toggle source
# File lib/rhc/commands/app.rb, line 758 def output_issues(rest_app) reasons, steps = format_issues(4) warn <<WARNING_OUTPUT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING: Your application was created successfully but had problems during configuration. Below is a list of the issues and steps you can take to complete the configuration of your application. Application URL: #{rest_app.app_url} Issues: #{reasons} Steps to complete your configuration: #{steps} If you continue to experience problems after completing these steps, you can try destroying and recreating the application: $ rhc app delete #{rest_app.name} --confirm Please contact us if you are unable to successfully create your application: Support - https://www.openshift.com/support !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING_OUTPUT end
require_one_web_cart()
click to toggle source
# File lib/rhc/commands/app.rb, line 546 def require_one_web_cart lambda{ |carts| match, ambiguous = carts.partition{ |c| not c.is_a?(Array) } selected_web = match.any?{ |c| not c.only_in_existing? } possible_web = ambiguous.flatten.any?{ |c| not c.only_in_existing? } if not (selected_web or possible_web) section(:bottom => 1){ list_cartridges(standalone_cartridges) } raise RHC::CartridgeNotFoundException, "Every application needs a web cartridge to handle incoming web requests. Please provide the short name of one of the carts listed above." end if selected_web carts.map! &other_carts_only elsif possible_web && ambiguous.length == 1 carts.map! &web_carts_only end } end
run_nslookup(host)
click to toggle source
# File lib/rhc/commands/app.rb, line 719 def run_nslookup(host) # :nocov: `nslookup #{host}` $?.exitstatus == 0 # :nocov: end
run_ping(host)
click to toggle source
# File lib/rhc/commands/app.rb, line 726 def run_ping(host) # :nocov: `ping #{host} -n 2` $?.exitstatus == 0 # :nocov: end
temporary_snapshot_filename(app_name)
click to toggle source
# File lib/rhc/commands/app.rb, line 817 def temporary_snapshot_filename(app_name) "#{Dir.tmpdir}/#{app_name}_temp_clone.tar.gz" end
windows_nslookup_bug?(rest_app)
click to toggle source
# File lib/rhc/commands/app.rb, line 733 def windows_nslookup_bug?(rest_app) windows_nslookup = run_nslookup(rest_app.host) windows_ping = run_ping(rest_app.host) if windows_nslookup and !windows_ping # this is related to BZ #826769 issue = <<WINSOCKISSUE We were unable to lookup your hostname (#{rest_app.host}) in a reasonable amount of time. This can happen periodically and may take up to 10 extra minutes to propagate depending on where you are in the world. This may also be related to an issue with Winsock on Windows [1][2]. We recommend you wait a few minutes then clone your git repository manually. [1] http://support.microsoft.com/kb/299357 [2] http://support.microsoft.com/kb/811259 WINSOCKISSUE add_issue(issue, "Clone your git repo", "rhc git-clone #{rest_app.name}") return true end false end