def upgrade_tarball_install(config, new_tarball, preserve_old_install):
    """Performs an upgrade for an existing Scalyr Agent 2 that was previously installed using the tarball method.

    @param config: The configuration for this agent.
    @param new_tarball: The path to file containing the new tarball to install.
    @param preserve_old_install: If True, will move the old install directory to a new location rather than deleting
        it.

    @return: The exit status code.
    """
    # Create a temporary directory hold the new install as we untar it and copy files into it.
    tmp_install_dir = tempfile.mkdtemp()

    # Some variables that capture some important state that we may need to unwind if we execute
    # out the installation along the way.
    #
    # If not None, then the directory we are currently holding the old installation directory in.
    preserve_dir = None
    # True if the agent was running when the install started.
    was_running = False
    # True if the agent was successfully restarted.
    was_restarted = False

    try:
        try:
            # Ensure that this is a tarball install
            if not config.is_tarball_install():
                raise UpgradeFailure('The current agent was not installed using a tarball, so you may not use the '
                                     'upgrade tarball command.')

            # Ensure that the user has not changed the defaults for the config, data, and log directory.
            if Configuration.default_config_file_path() != config.file_path:
                raise UpgradeFailure('The agent is not using the default configuration file so you may not use the '
                                     'upgrade tarball command.')
            if Configuration.default_agent_data_path() != config.agent_data_path:
                raise UpgradeFailure('The agent is not using the default data directory so you may not use the upgrade '
                                     'tarball command.')
            if Configuration.default_agent_log_path() != config.agent_log_path:
                raise UpgradeFailure('The agent is not using the default log directory so you may not use the upgrade '
                                     'tarball command.')

            # We rely on the current installation being included in the PATH variable.
            if spawn.find_executable('scalyr-agent-2-config') is None:
                raise UpgradeFailure('Could not locate the scalyr-agent-2-config command from the current '
                                     'installation. Please ensure that the agent\'s bin directory is in the system\'s '
                                     'PATH variable.')

            if not os.path.isfile(new_tarball):
                raise UpgradeFailure('The tarball file %s does not exist.' % new_tarball)

            file_name = os.path.basename(new_tarball)
            if re.match('^scalyr-agent-2\..*\.tar\.gz$', file_name) is None:
                raise UpgradeFailure('The supplied tarball file name does not match the expected format.')
            tarball_directory = file_name[0:-7]

            # We will be installing in the same directory where scalyr-agent-2 is currently installed.  That directory
            # should be 4 levels back from this file.
            # The path to this file looks like: scalyr-agent-2/py/scalyr_agent/config_main.py

            install_directory = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file_path__))))

            if not os.path.isdir(os.path.join(install_directory, 'scalyr-agent-2')):
                raise UpgradeFailure('Could not determine the install directory.  Either the main directory is no '
                                     'longer called scalyr-agent-2, or the directory structure has changed.')

            # Compute the full paths to the scalyr-agent-2 directories for both the new install and old install.
            tmp_new_install_location = os.path.join(tmp_install_dir, tarball_directory)
            old_install_location = os.path.join(install_directory, 'scalyr-agent-2')

            # Untar the new package into the temp location.
            tar = tarfile.open(new_tarball, 'r:gz')
            for member in tar.getmembers():
                tar.extract(member, path=tmp_install_dir)

            # Check to see if the agent is running.  If so, stop it.
            was_running = run_command('scalyr-agent-2 stop', grep_for='Agent has stopped',
                                      command_name='scalyr-agent-2 stop')[0] == 0

            # Copy the config, data, and log directories.
            for dir_name in ['config', 'log', 'data']:
                copy_dir_to_new_agent(old_install_location, tmp_new_install_location, dir_name)

            # Allow the new agent code to perform any actions it deems necessary.  We do the special commandline
            # here where to pass in both directories to the --upgrade-tarball-command
            result = subprocess.call([os.path.join(tmp_new_install_location, 'bin', 'scalyr-agent-2-config'),
                                      '--upgrade-tarball', '%s%s%s' % (old_install_location, os.pathsep,
                                                                       tmp_new_install_location)])
            if result != 0:
                raise UpgradeFailure('New package failed to finish the upgrade process.')

            # Move the old install directory to a temporary location, so we can undo the next move if we need to.
            preserve_dir = tempfile.mkdtemp()
            shutil.move(old_install_location, preserve_dir)

            # Move the new install into place.
            success = False
            try:
                shutil.move(tmp_new_install_location, old_install_location)
                success = True
            finally:
                if not success:
                    # Move the old install back in place just to be safe.
                    shutil.move(os.path.join(preserve_dir, 'scalyr-agent-2'), old_install_location)
                if success and not preserve_old_install:
                    shutil.rmtree(preserve_dir)
                    preserve_dir = None

            print 'New agent installed.'

            # Start the agent if it was previously running.
            if was_running:
                if run_command('scalyr-agent-2 start', exit_on_fail=False, command_name='scalyr-agent-2 start')[0] == 0:
                    print 'Agent has successfully restarted.'
                    print '  You may execute the following command for status details:  scalyr-agent-2 status -v'
                    was_restarted = True
                else:
                    raise UpgradeFailure('Could not start the agent.  Execute the following command for more details: '
                                         'scalyr-agent-2 start')
            else:
                print 'Execute the following command to start the agent:  scalyr-agent-2 start'

            return 0

        except UpgradeFailure, error:
            print >>sys.stderr
            print >>sys.stderr, 'The upgrade failed due to the following reason: %s' % error.message
            return 1

    finally:
        # Delete the temporary directory.
        shutil.rmtree(tmp_install_dir)

        # Warn if we should have restarted the agent but did not.
        if was_running and not was_restarted:
            print ''
            print ('WARNING, due to failure, the agent may no longer be running.  Restart it with: scalyr-agent-2 '
                   'start')

        # If there is still a preserve_directory, there must be a reason for it, so tell the user where it is.
        if preserve_dir is not None:
            print ''
            print 'The previous agent installation was left in \'%s\'' % preserve_dir
            print 'You should be sure to delete this directory once you no longer need it.'
    parser.add_option("", "--preserve-old-install", action="store_true", dest="preserve_old_install", default=False,
                      help="When performing a tarball upgrade, move the old install to a temporary directory "
                           "instead of deleting it.")

    (options, args) = parser.parse_args()
    if len(args) > 1:
        print >> sys.stderr, 'Could not parse commandline arguments.'
        parser.print_help(sys.stderr)
        sys.exit(1)

    if options.executing_user and getpass.getuser() != 'root':
        print >> sys.stderr, 'You must be root to update the user account that is used to run the agent.'
        sys.exit(1)

    if options.config_filename is None:
        options.config_filename = Configuration.default_config_file_path()

    if not os.path.isabs(options.config_filename):
        options.config_filename = os.path.abspath(options.config_filename)

    try:
        config_file = Configuration(options.config_filename, None, None)
        config_file.parse()
    except Exception, e:
        print >> sys.stderr, 'Error reading configuration file: %s' % str(e)
        print >> sys.stderr, traceback.format_exc()
        print >> sys.stderr, 'Terminating, please fix the configuration file and restart agent.'
        sys.exit(1)

    if options.set_key_from_stdin:
        api_key = raw_input('Please enter key: ')