class OpenShift::ApplicationContainer

Application Container

Attributes

application_uuid[R]
cartridge_model[R]
container_name[R]
state[R]
user[R]
uuid[R]

Public Class Methods

get_build_model(user, config) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 64
def self.get_build_model(user, config)
  # TODO: When v2 is the default cartridge format change this default...
  build_model = :v1

  if user.homedir && File.exist?(user.homedir)
    build_model = :v2 if OpenShift::Utils::Sdk.new_sdk_app?(user.homedir)
  else
    build_model = OpenShift::Utils::Sdk.node_default_model(config)
  end

  build_model
end
new(application_uuid, container_uuid, user_uid = nil, app_name = nil, container_name = nil, namespace = nil, quota_blocks = nil, quota_files = nil, logger = nil) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 41
def initialize(application_uuid, container_uuid, user_uid = nil,
    app_name = nil, container_name = nil, namespace = nil, quota_blocks = nil, quota_files = nil, logger = nil)

  @config           = OpenShift::Config.new
  @uuid             = container_uuid
  @application_uuid = application_uuid
  @container_name   = container_name
  @user             = UnixUser.new(application_uuid, container_uuid, user_uid,
                                   app_name, container_name, namespace, quota_blocks, quota_files)
  @state            = OpenShift::Utils::ApplicationState.new(container_uuid)

  build_model = self.class.get_build_model(@user, @config)

  # When v2 is the default cartridge format flip the test...
  if build_model == :v1
    @cartridge_model = V1CartridgeModel.new(@config, @user)
  else
    @cartridge_model = V2CartridgeModel.new(@config, @user)
  end
  NodeLogger.logger.debug("Creating #{build_model} model for #{container_uuid}: #{__callee__}")

end

Public Instance Methods

build(cart_name) click to toggle source

build application

# File lib/openshift-origin-node/model/application_container.rb, line 375
def build(cart_name)
  @state.value = OpenShift::State::BUILDING
  @cartridge_model.do_control("build", cart_name)
end
configure(cart_name, template_git_url=nil) click to toggle source

Add cartridge to gear. This method establishes the cartridge model to use, but does not mark the application. Marking the application is the responsibility of the cart model.

This method does not enforce constraints on whether the cartridge being added is compatible with other installed cartridges. That is the responsibility of the broker.

context: root -> gear user -> root @param cart_name cartridge name

# File lib/openshift-origin-node/model/application_container.rb, line 91
def configure(cart_name, template_git_url=nil)
  @cartridge_model.configure(cart_name, template_git_url)
end
connector_execute(cart_name, connector, args) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 331
def connector_execute(cart_name, connector, args)
  @cartridge_model.connector_execute(cart_name, connector, args)
end
create() click to toggle source

create gear

  • model/unix_user.rb

context: root

# File lib/openshift-origin-node/model/application_container.rb, line 107
def create
  notify_observers(:before_container_create)

  @user.create
  if :v2 == OpenShift::Utils::Sdk.node_default_model(@config)
    Utils::Sdk.mark_new_sdk_app(@user.homedir)
  end

  notify_observers(:after_container_create)
end
create_public_endpoints(cart_name) click to toggle source

Creates public endpoints for the given cart. Public proxy mappings are created via the FrontendProxyServer, and the resulting mapped ports are written to environment variables with names based on the cart manifest endpoint entries.

Returns nil on success, or raises an exception if any errors occur: all errors here are considered fatal.

# File lib/openshift-origin-node/model/application_container.rb, line 149
def create_public_endpoints(cart_name)
  env  = Utils::Environ::for_gear(@user.homedir)
  cart = @cartridge_model.get_cartridge(cart_name)

  proxy = OpenShift::FrontendProxyServer.new

  # TODO: better error handling
  cart.public_endpoints.each do |endpoint|
    # Load the private IP from the gear
    private_ip = env[endpoint.private_ip_name]

    if private_ip == nil
      raise "Missing private IP #{endpoint.private_ip_name} for cart #{cart.name} in gear #{@uuid}, "             "required to create public endpoint #{endpoint.public_port_name}"
    end

    # Attempt the actual proxy mapping assignment
    public_port = proxy.add(@user.uid, private_ip, endpoint.private_port)

    @user.add_env_var(endpoint.public_port_name, public_port)

    logger.info("Created public endpoint for cart #{cart.name} in gear #{@uuid}: "           "[#{endpoint.public_port_name}=#{public_port}]")
  end
end
deconfigure(cart_name) click to toggle source

Remove cartridge from gear

context: root -> gear user -> root @param cart_name cartridge name

# File lib/openshift-origin-node/model/application_container.rb, line 99
def deconfigure(cart_name)
  @cartridge_model.deconfigure(cart_name)
end
delete_public_endpoints(cart_name) click to toggle source

Deletes all public endpoints for the given cart. Public port mappings are looked up and deleted using the FrontendProxyServer, and all corresponding environment variables are deleted from the gear.

Returns nil on success. Failed public port delete operations are logged and skipped.

# File lib/openshift-origin-node/model/application_container.rb, line 181
def delete_public_endpoints(cart_name)
  env  = Utils::Environ::for_gear(@user.homedir)
  cart = @cartridge_model.get_cartridge(cart_name)

  proxy = OpenShift::FrontendProxyServer.new

  public_ports     = []
  public_port_vars = []

  cart.public_endpoints.each do |endpoint|
    # Load the private IP from the gear
    private_ip = env[endpoint.private_ip_name]

    public_port_vars << endpoint.public_port_name

    public_port = proxy.find_mapped_proxy_port(@user.uid, private_ip, endpoint.private_port)

    public_ports << public_port unless public_port == nil
  end

  begin
    # Remove the proxy entries
    rc = proxy.delete_all(public_ports, true)
    logger.info("Deleted all public endpoints for cart #{cart.name} in gear #{@uuid}\n"           "Endpoints: #{public_port_vars}\n"           "Public ports: #{public_ports}")
  rescue => e
    logger.warn(%Q{Couldn't delete all public endpoints for cart #{cart.name} in gear #{@uuid}: #{e.message}
      Endpoints: #{public_port_vars}
      Public ports: #{public_ports}
                #{e.backtrace}
                })
  end

  # Clean up the environment variables
  public_port_vars.each { |var| @user.remove_env_var(var) }
end
deploy(cart_name) click to toggle source

deploy application

# File lib/openshift-origin-node/model/application_container.rb, line 381
def deploy(cart_name)
  @state.value = OpenShift::State::DEPLOYING
  @cartridge_model.do_control("deploy", cart_name)
end
deploy_httpd_proxy(cart_name) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 335
def deploy_httpd_proxy(cart_name)
  @cartridge_model.deploy_httpd_proxy(cart_name)
end
destroy(skip_hooks=false) click to toggle source

Destroy gear

  • model/unix_user.rb

context: root @param skip_hooks should destroy call the gear's hooks before destroying the gear

# File lib/openshift-origin-node/model/application_container.rb, line 123
def destroy(skip_hooks=false)
  notify_observers(:before_container_destroy)

  # possible mismatch across cart model versions
  output, errout, retcode = @cartridge_model.destroy(skip_hooks)

  notify_observers(:after_container_destroy)

  return output, errout, retcode
end
force_stop() click to toggle source

Public: Sets the app state to “stopped” and causes an immediate forced termination of all gear processes.

TODO: exception handling

# File lib/openshift-origin-node/model/application_container.rb, line 138
def force_stop
  @state.value = OpenShift::State::STOPPED
  UnixUser.kill_procs(@user.uid)
end
gear_level_tidy(gear_repo_dir, gear_tmp_dir) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 293
def gear_level_tidy(gear_repo_dir, gear_tmp_dir)
  # Git pruning
  tidy_action do
    OpenShift::Utils::ShellExec.run_as(@user.uid, @user.gid, "git prune", gear_repo_dir, false, 0)
    logger.debug("Pruned git directory at #{gear_repo_dir}")
  end

  # Git GC
  tidy_action do
    OpenShift::Utils::ShellExec.run_as(@user.uid, @user.gid, "git gc --aggressive", gear_repo_dir, false, 0)
    logger.debug("Executed git gc for repo #{gear_repo_dir}")
  end

  # Temp dir cleanup
  tidy_action do
    FileUtils.rm_rf(Dir.glob(File.join(gear_tmp_dir, "*")))
    logger.debug("Cleaned gear temp dir at #{gear_tmp_dir}")
  end
end
move(cart_name, idle) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 347
def move(cart_name, idle)
  @cartridge_model.move(cart_name, idle)
end
name() click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 77
def name
  @uuid
end
post_move(cart_name) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 355
def post_move(cart_name)
  @cartridge_model.post_move(cart_name)
end
pre_move(cart_name) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 351
def pre_move(cart_name)
  @cartridge_model.pre_move(cart_name)
end
reload(cart_name) click to toggle source

reload gear as supported by cartridges

# File lib/openshift-origin-node/model/application_container.rb, line 392
def reload(cart_name)
  @cartridge_model.do_control("reload", cart_name)
end
remove_httpd_proxy(cart_name) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 339
def remove_httpd_proxy(cart_name)
  @cartridge_model.remove_httpd_proxy(cart_name)
end
restart(cart_name) click to toggle source

restart gear as supported by cartridges

# File lib/openshift-origin-node/model/application_container.rb, line 387
def restart(cart_name)
  @cartridge_model.do_control("restart", cart_name)
end
restart_httpd_proxy(cart_name) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 343
def restart_httpd_proxy(cart_name)
  @cartridge_model.restart_httpd_proxy(cart_name)
end
restore(cart_name) click to toggle source

restore gear from tar ball

# File lib/openshift-origin-node/model/application_container.rb, line 397
def restore(cart_name)
  raise NotImplementedError.new("restore")
end
snapshot(cart_name) click to toggle source

write gear to tar ball

# File lib/openshift-origin-node/model/application_container.rb, line 402
def snapshot(cart_name)
  raise NotImplementedError.new("snapshot")
end
start(cart_name) click to toggle source

start gear Throws ShellExecutionException on failure

# File lib/openshift-origin-node/model/application_container.rb, line 363
def start(cart_name)
  @state.value = OpenShift::State::STARTED
  @cartridge_model.do_control("start", cart_name)
end
start_gear(gear_dir) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 276
def start_gear(gear_dir)
  # TODO: remove shell command
  begin
    # Start the gear, and if that fails raise an exception, as the app is now
    # in a bad state.
    out, err, rc = OpenShift::Utils::ShellExec.shellCmd("/usr/sbin/oo-admin-ctl-gears startgear #{@user.uuid}", gear_dir)
    logger.debug("Started gear #{@uuid}. Output:\n#{out}")
  rescue OpenShift::Utils::ShellExecutionException => e
    logger.error(%Q{
      Failed to restart gear #{@uuid} following tidy: #{e.message}
      --- stdout ---\n#{e.stdout}
      --- stderr ---\n#{e.stderr}
                 })
    raise "Tidy of gear #{@uuid} failed, and the gear was not successfuly restarted"
  end
end
status(cart_name) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 406
def status(cart_name)
  @cartridge_model.do_control("status", cart_name)
end
stop(cart_name) click to toggle source

stop gear

# File lib/openshift-origin-node/model/application_container.rb, line 369
def stop(cart_name)
  @state.value = OpenShift::State::STOPPED
  @cartridge_model.do_control("stop", cart_name)
end
stop_gear(gear_dir) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 260
def stop_gear(gear_dir)
  # TODO: remove shell command
  begin
    # Stop the gear. If this fails, consider the tidy a failure.
    out, err, rc = OpenShift::Utils::ShellExec.shellCmd("/usr/sbin/oo-admin-ctl-gears stopgear #{@user.uuid}", gear_dir, false, 0)
    logger.debug("Stopped gear #{@uuid}. Output:\n#{out}")
  rescue OpenShift::Utils::ShellExecutionException => e
    logger.error(%Q{
      Couldn't stop gear #{@uuid} for tidy: #{e.message}
      --- stdout ---\n#{e.stdout}
      --- stderr ---\n#{e.stderr}
                 })
    raise "Tidy failed on gear #{@uuid}; the gear couldn't be stopped successfully"
  end
end
threaddump(cart_name) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 410
def threaddump(cart_name)
  @cartridge_model.do_control("threaddump", cart_name)
end
tidy() click to toggle source

Public: Cleans up the gear, providing any installed cartridges with the opportunity to perform their own cleanup operations via the tidy hook.

The generic gear-level cleanup flow is:

  • Stop the gear

  • Git cleanup

  • Gear temp dir cleanup

  • Cartridge tidy hook executions

  • Start the gear

Raises an Exception if an internal error occurs, and ignores failed cartridge tidy hook executions.

# File lib/openshift-origin-node/model/application_container.rb, line 232
def tidy
  logger.debug("Starting tidy on gear #{@uuid}")

  env      = Utils::Environ::for_gear(@user.homedir)
  gear_dir = env['OPENSHIFT_HOMEDIR']
  app_name = env['OPENSHIFT_APP_NAME']

  gear_repo_dir = File.join(gear_dir, 'git', "#{app_name}.git")
  gear_tmp_dir  = File.join(gear_dir, '.tmp')

  stop_gear(gear_dir)

  # Perform the gear- and cart- level tidy actions.  At this point, the gear has
  # been stopped; we'll attempt to start the gear no matter what tidy operations fail.
  begin
    gear_level_tidy(gear_repo_dir, gear_tmp_dir)

    # Delegate to cartridge model to perform cart-level tidy operations for all installed carts.
    @cartridge_model.tidy
  rescue Exception => e
    logger.warn("An unknown exception occured during tidy for gear #{@uuid}: #{e.message}\n#{e.backtrace}")
  ensure
    start_gear(gear_dir)
  end

  logger.debug("Completed tidy for gear #{@uuid}")
end
tidy_action() { || ... } click to toggle source

Executes a block, trapping ShellExecutionExceptions and treating them as warnings. Any other exceptions are unexpected and will bubble out.

# File lib/openshift-origin-node/model/application_container.rb, line 315
def tidy_action
  begin
    yield
  rescue OpenShift::Utils::ShellExecutionException => e
    logger.warn(%Q{
      Tidy operation failed on gear #{@uuid}: #{e.message}
      --- stdout ---\n#{e.stdout}
      --- stderr ---\n#{e.stderr}
                })
  end
end
update_namespace(cart_name, old_namespace, new_namespace) click to toggle source
# File lib/openshift-origin-node/model/application_container.rb, line 327
def update_namespace(cart_name, old_namespace, new_namespace)
  @cartridge_model.update_namespace(cart_name, old_namespace, new_namespace)
end