#!/usr/bin/env python

# 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.

"""Tool to sync lab servers to the "Allowed Networks" of a CloudSQL instance.

For a lab server to access CloudSQL instance, the server's IP must be added to
the "Allowed Networks" list of the CloudSQL instance. This tool is to be used to
read the list of lab servers from server database and update the list of
"Allowed Networks" of a given CloudSQL instance.

The tool also reads CLOUD/tko_access_servers from global config to add these
servers to the "Allowed Networks" list of the CloudSQL instance. This allows
servers that do not run Autotest code can access the CloudSQL instance.

Note that running this tool will overwrite existing IPs in the "Allowed
Networks" list. Therefore, manually editing that list from CloudSQL console
should be prohibited. Instead, the servers should be added to
CLOUD/tko_access_servers in shadow_config.ini.

"""

import argparse
import socket
import sys

import common
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import global_config
from autotest_lib.client.common_lib.cros import retry
from autotest_lib.server import frontend


ROLES_REQUIRE_TKO_ACCESS = {
        'afe',
        'database',
        'drone',
        'scheduler',
        'sentinel',
        'shard',
}


def gcloud_login(project):
    """Login to Google Cloud service for gcloud command to run.

    @param project: Name of the Google Cloud project.
    """
    # Login with user account. If the user hasn't log in yet, the script will
    # print a url and ask for a verification code. User should load the url in
    # browser, and copy the verification code from the web page. When private IP
    # can be supported to be added using non-corp account, the login can be done
    # through service account and key file, e.g.,
    # gcloud auth activate-service-account --key-file ~/key.json
    utils.run('gcloud auth login', stdout_tee=sys.stdout,
              stderr_tee=sys.stderr, stdin=sys.stdin)


@retry.retry(error.CmdError, timeout_min=3)
def _fetch_external_ip(server_name):
    return utils.run('ssh %s curl -s ifconfig.me' % server_name).stdout.rstrip()


def update_allowed_networks(project, instance, afe=None, extra_servers=None,
                            dryrun=False):
    """Update the "Allowed Networks" list of the given CloudSQL instance.

    @param project: Name of the Google Cloud project.
    @param instance: Name of the CloudSQL instance.
    @param afe: Server of the frontend RPC, default to None to use the server
                specified in global config.
    @param extra_servers: Extra servers to be included in the "Allowed Networks"
                          list. Default is None.
    @param dryrun: Boolean indicating whether this is a dryrun.
    """
    # Get the IP address of all servers need access to CloudSQL instance.
    rpc = frontend.AFE(server=afe)
    servers = [s['hostname'] for s in rpc.run('get_servers')
               if s['status'] != 'repair_required' and
               ROLES_REQUIRE_TKO_ACCESS.intersection(s['roles'])]
    if extra_servers:
        servers.extend(extra_servers.split(','))
    # Extra servers can be listed in CLOUD/tko_access_servers shadow config.
    tko_servers = global_config.global_config.get_config_value(
            'CLOUD', 'tko_access_servers', default='')
    if tko_servers:
        servers.extend(tko_servers.split(','))
    print 'Adding servers %s to access list for projects %s' % (servers,
                                                                instance)
    print 'Fetching their IP addresses...'
    ips = []
    for name in servers:
        try:
            # collect internal ips
            ips.append(socket.gethostbyname(name))
            # collect external ips
            ips.append(_fetch_external_ip(name))
        except socket.gaierror:
            print 'Failed to resolve internal IP address for name %s' % name
            raise
        except error.TimeoutException:
            print 'Failed to resolve external IP address for %s' % name
            raise

    print '...Done: %s' % ips

    cidr_ips = [str(ip) + '/32' for ip in ips]

    if dryrun:
        print 'This is a dryrun: skip updating glcoud sql whitelists.'
        return

    login = False
    while True:
        try:
            utils.run('gcloud config set project %s -q' % project)
            cmd = ('gcloud sql instances patch %s --authorized-networks %s '
                   '-q' % (instance, ','.join(cidr_ips)))
            print 'Running command to update whitelists: "%s"' % cmd
            utils.run(cmd, stdout_tee=sys.stdout, stderr_tee=sys.stderr)
            return
        except error.CmdError:
            if login:
                raise

            # Try to login and retry if the command failed.
            gcloud_login(project)
            login = True


def main():
    """main script."""
    parser = argparse.ArgumentParser()
    parser.add_argument('--project', type=str, dest='project',
                        help='Name of the Google Cloud project.')
    parser.add_argument('--instance', type=str, dest='instance',
                        help='Name of the CloudSQL instance.')
    parser.add_argument('--afe', type=str, dest='afe',
                        help='Name of the RPC server to get server list.',
                        default=None)
    parser.add_argument('--extra_servers', type=str, dest='extra_servers',
                        help=('Extra servers to be included in the "Allowed '
                              'Networks" list separated by comma.'),
                        default=None)
    parser.add_argument('--dryrun', dest='dryrun', action='store_true',
                        default=False,
                        help='Fetch IPs without updating whitelists in gcloud.')
    options = parser.parse_args()

    update_allowed_networks(options.project, options.instance, options.afe,
                            options.extra_servers, options.dryrun)


if __name__ == '__main__':
    main()
