# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# This implements the APIs defined at
# https://github.com/luci/luci-py/blob/master/appengine/
# swarming/swarming_bot/bot_config.py


"""This file is meant to be overriden by the server's specific copy.

You can upload a new version via /restricted/upload/bot_config.

There's 3 types of functions in this file:
  - get_*() to return properties to describe this bot.
  - on_*() as hooks based on events happening on the bot.
  - setup_*() to setup global state on the host.

This file shouldn't import from other scripts in this directory except
os_utilities which is guaranteed to be usable as an API. It's fine to import
from stdlib.

Set the environment variable SWARMING_LOAD_TEST=1 to disable the use of
server-provided bot_config.py. This permits safe load testing.

TODO(fdeng):
    Restrict the command to run_suite/abort_suite
"""

import json
import re
import os

from api import os_utilities

# Unused argument 'bot' - pylint: disable=W0613


CMD_WHITELIST = {'/usr/local/autotest/site_utils/run_suite.py',
                 '/usr/local/autotest/site_utils/abort_suite.py'}


def get_dimensions(bot=None):
    """Returns dict with the bot's dimensions.

    The dimensions are what are used to select the bot that can run each task.

    By default, the bot id will be automatically selected based on
    the hostname with os_utilities.get_dimensions(). This method
    overrides the default id returned by os_utilities.get_dimensions().

    Assume the bot's working directory is like BOT_ROOT/bot_23/
    we will parse the id "23" from the directory name and append it to the
    hostname to form the bot id. so the bot id would look like
    chromeos-server31-23

    See https://github.com/luci/luci-py/blob/master/appengine/
    swarming/doc/Magic-Values.md

    @returns: Dict with the bot's dimentions.

    """
    d = os_utilities.get_dimensions()
    m = re.match('.*/bot_([\d]+).*', os.getcwd())
    suffix = ''
    if m:
        suffix = '-'+ m.group(1)
    d[u'id'] = [os_utilities.get_hostname_short() + suffix]
    return d


def get_state(bot=None):
    """Returns dict with a state of the bot reported to the server with each poll.

    It is only for dynamic state that changes while bot is running for information
    for the sysadmins.

    The server can not use this state for immediate scheduling purposes (use
    'dimensions' for that), but it can use it for maintenance and bookkeeping
    tasks.

    See https://github.com/luci/luci-py/blob/master/appengine/
    swarming/doc/Magic-Values.md

    """
    return os_utilities.get_state()


### Hooks


def on_before_task(bot, bot_file=None):
    """Hook function called before running a task.

    It shouldn't do much, since it can't cancel the task so it shouldn't do
    anything too fancy.
    @param bot: bot.Bot instance.
    @param bot_file: Path to file to write information about the state of the
                     bot. This file can be used to pass certain info about the
                     bot to tasks, such as which connected android devices to
                     run on. See
                     https://github.com/luci/luci-py/tree/master/appengine/swarming/doc/Magic-Values.md#run_isolated
                     TODO(bpastene): Remove default value None.
    """
    # TODO(fdeng): it is possible that the format gets updated
    # without warning. It would be better to find a long term solution.
    path = os.path.join(bot.base_dir, 'w', 'task_runner_in.json')
    if not os.path.isfile(path):
        # For older version.
        path = os.path.join(bot.base_dir, 'work', 'task_runner_in.json')
        if not os.path.isfile(path):
            bot.post_error('Failed to process task_runner_in.json')
            return
    manifest = {}
    with open(path) as f:
        manifest = json.load(f)
    full_command = manifest.get('command')
    if full_command and not full_command[0] in CMD_WHITELIST:
        # override the command with a safe "echo"
        manifest['command'] = ['echo', '"Command not allowed"']
        with open(path, 'wb') as f:
            f.write(json.dumps(manifest))
        raise Exception('Command not allowed: %s' % full_command)


### Setup


def setup_bot(bot):
    """Does one time initialization for this bot.

    Returns True if it's fine to start the bot right away. Otherwise, the calling
    script should exit.

    Example: making this script starts automatically on user login via
    os_utilities.set_auto_startup_win() or os_utilities.set_auto_startup_osx().

    @param bot: bot.Bot instance.

    @returns: Boolean. See above.

    """
    return True
