# File lib/rhc/commands/app.rb, line 497 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
# 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 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 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? 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}')" : '')], (["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) 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", "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
# File lib/rhc/commands/app.rb, line 272 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
# File lib/rhc/commands/app.rb, line 480 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
# File lib/rhc/commands/app.rb, line 369 def enable_ha(app) app_action :enable_ha results { say "#{app} is now highly available" } 0 end
# File lib/rhc/commands/app.rb, line 329 def force_stop(app) app_action :stop, true results { say "#{app} force stopped" } 0 end
# File lib/rhc/commands/app.rb, line 349 def reload(app) app_action :reload results { say "#{app} config reloaded" } 0 end
# File lib/rhc/commands/app.rb, line 339 def restart(app) app_action :restart results { say "#{app} restarted" } 0 end
# File lib/rhc/commands/app.rb, line 319 def scale_down(app) app_action :scale_down results { say "#{app} scaled down" } 0 end
# File lib/rhc/commands/app.rb, line 309 def scale_up(app) app_action :scale_up results { say "#{app} scaled up" } 0 end
# File lib/rhc/commands/app.rb, line 406 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| [ gear['id'], gear['state'] == 'started' ? color(gear['state'], :green) : color(gear['state'], :yellow), (gear['endpoints'].blank? ? group.cartridges : gear['endpoints']).collect{ |c| c['cartridge_name'] || 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
# File lib/rhc/commands/app.rb, line 289 def start(app) app_action :start results { say "#{app} started" } 0 end
# File lib/rhc/commands/app.rb, line 299 def stop(app) app_action :stop results { say "#{app} stopped" } 0 end
# File lib/rhc/commands/app.rb, line 359 def tidy(app) app_action :tidy results { say "#{app} cleaned up" } 0 end
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 773 def add_issue(reason, commands_header, *commands) @issues ||= [] issue = {:reason => reason, :commands_header => commands_header, :commands => commands} @issues << issue end
# File lib/rhc/commands/app.rb, line 615 def add_jenkins_app(rest_domain) create_app(jenkins_app_name, jenkins_cartridge_name, rest_domain) end
# File lib/rhc/commands/app.rb, line 619 def add_jenkins_cartridge(rest_app) rest_app.add_cartridge(jenkins_client_cartridge_name) end
# File lib/rhc/commands/app.rb, line 623 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
# File lib/rhc/commands/app.rb, line 587 def app_action(action, *args) rest_app = find_app result = rest_app.send action, *args result end
# File lib/rhc/commands/app.rb, line 562 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
# File lib/rhc/commands/app.rb, line 567 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
# File lib/rhc/commands/app.rb, line 553 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
# File lib/rhc/commands/app.rb, line 548 def check_sshkeys! return unless interactive? RHC::SSHWizard.new(rest_client, config, options).run end
# File lib/rhc/commands/app.rb, line 593 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) 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 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
# File lib/rhc/commands/app.rb, line 657 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
# File lib/rhc/commands/app.rb, line 684 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
# File lib/rhc/commands/app.rb, line 781 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
# File lib/rhc/commands/app.rb, line 582 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
# File lib/rhc/commands/app.rb, line 797 def issues? not @issues.nil? end
# File lib/rhc/commands/app.rb, line 689 def jenkins_app_name if options.enable_jenkins.is_a? String options.enable_jenkins end || "jenkins" end
# File lib/rhc/commands/app.rb, line 695 def jenkins_cartridge_name jenkins_cartridges.last.name end
# File lib/rhc/commands/app.rb, line 699 def jenkins_client_cartridge_name jenkins_client_cartridges.last.name end
# File lib/rhc/commands/app.rb, line 742 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
# File lib/rhc/commands/app.rb, line 531 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
# File lib/rhc/commands/app.rb, line 703 def run_nslookup(host) # :nocov: %xnslookup #{host}` $?.exitstatus == 0 # :nocov: end
# File lib/rhc/commands/app.rb, line 710 def run_ping(host) # :nocov: %xping #{host} -n 2` $?.exitstatus == 0 # :nocov: end
# File lib/rhc/commands/app.rb, line 801 def temporary_snapshot_filename(app_name) "#{Dir.tmpdir}/#{app_name}_temp_clone.tar.gz" end
# File lib/rhc/commands/app.rb, line 717 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