<commit_before>#!/usr/bin/env python

# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Need to figure out why this only fails on travis
# pylint: disable=bad-continuation

"""Runs kubernetes e2e test with specified config"""

import argparse
import hashlib
import os
import random
import re
import shutil
import subprocess
import sys
import urllib2
import time

ORIG_CWD = os.getcwd()  # Checkout changes cwd

# The zones below are the zones available in the CNCF account (in theory, zones vary by account)
# We comment out zones below because we want to stay proportional to the limits
# We do one zone for every 10 t2.medium instances allowed
DEFAULT_AWS_ZONES = [
    #'ap-northeast-1a', # insufficient quota
    #'ap-northeast-1c', # insufficient quota
    #'ap-northeast-2a', # insufficient quota
    #'ap-northeast-2b', # insufficient quota
    #'ap-south-1a', # no c4.large instances available
    #'ap-south-1b', # no c4.large instances available
    #'ap-southeast-1a', # insufficient quota
    #'ap-southeast-1b', # insufficient quota
    #'ap-southeast-1c', # insufficient quota
    #'ap-southeast-2a', # insufficient quota
    #'ap-southeast-2b', # insufficient quota
    #'ap-southeast-2c', # insufficient quota
    #'ca-central-1a', # insufficient quota
    #'ca-central-1b', # insufficient quota
    #'eu-central-1a', # insufficient quota
    #'eu-central-1b', # insufficient quota
    #'eu-central-1c', # insufficient quota
    #'eu-west-1a', # insufficient quota
    #'eu-west-1b', # insufficient quota
    #'eu-west-1c', # insufficient quota
    #'eu-west-2a', # insufficient quota
    #'eu-west-2b', # insufficient quota
    #'eu-west-2c', # insufficient quota
    #'eu-west-3a', # insufficient quota
    #'eu-west-3b', # insufficient quota
    #'eu-west-3c', # insufficient quota
    #'sa-east-1a', # insufficient quota
    #'sa-east-1c' # insufficient quota
    'us-east-1a',
    'us-east-1b',
    #'us-east-1c', # limiting to 2 zones to not overallocate
    #'us-east-1d', # limiting to 2 zones to not overallocate
    #'us-east-1e', # limiting to 2 zones to not overallocate
    #'us-east-1f', # limiting to 2 zones to not overallocate
    #'us-east-2a', # no c4.large instances available
    #'us-east-2b', # no c4.large instances available
    #'us-east-2c', # no c4.large instances available
    'us-west-1a',
    #'us-west-1b', # overall limit is 10 instances
    'us-west-2a',
    'us-west-2b',
    #'us-west-2c' # limiting to 2 zones to not overallocate
]

def test_infra(*paths):
    """Return path relative to root of test-infra repo."""
    return os.path.join(ORIG_CWD, os.path.dirname(__file__), '..', *paths)


def check(*cmd):
    """Log and run the command, raising on errors."""
    print >>sys.stderr, 'Run:', cmd
    subprocess.check_call(cmd)


def check_output(*cmd):
    """Log and run the command, raising on errors, return output"""
    print >>sys.stderr, 'Run:', cmd
    return subprocess.check_output(cmd)


def check_env(env, *cmd):
    """Log and run the command with a specific env, raising on errors."""
    print >>sys.stderr, 'Environment:'
    for key, value in sorted(env.items()):
        print >>sys.stderr, '%s=%s' % (key, value)
    print >>sys.stderr, 'Run:', cmd
    subprocess.check_call(cmd, env=env)


def kubekins(tag):
    """Return full path to kubekins-e2e:tag."""
    return 'gcr.io/k8s-testimages/kubekins-e2e:%s' % tag

def parse_env(env):
    """Returns (FOO, BAR=MORE) for FOO=BAR=MORE."""
    return env.split('=', 1)

def aws_role_config(profile, arn):
    return (('[profile jenkins-assumed-role]\n' +
             'role_arn = %s\n' +
             'source_profile = %s\n') %
            (arn, profile))

def kubeadm_version(mode, shared_build_gcs_path):
    """Return string to use for kubeadm version, given the job's mode (ci/pull/periodic)."""
    version = ''
    if mode in ['ci', 'periodic']:
        # This job only runs against the kubernetes repo, and bootstrap.py leaves the
        # current working directory at the repository root. Grab the SCM_REVISION so we
        # can use the .debs built during the bazel-build job that should have already
        # succeeded.
        status = re.search(
            r'STABLE_BUILD_SCM_REVISION ([^\n]+)',
            check_output('hack/print-workspace-status.sh')
        )
        if not status:
            raise ValueError('STABLE_BUILD_SCM_REVISION not found')
        version = status.group(1)

        # The path given here should match ci-kubernetes-bazel-build
        return 'gs://kubernetes-release-dev/ci/%s-bazel/bin/linux/amd64/' % version

    elif mode == 'pull':
        # The format of shared_build_gcs_path looks like:
        # gs://kubernetes-release-dev/bazel/<git-describe-output>
        # Add bin/linux/amd64 yet to that path so it points to the dir with the debs
        return '%s/bin/linux/amd64/' % shared_build_gcs_path

    elif mode == 'stable':
        # This job need not run against the kubernetes repo and uses the stable version
        # of kubeadm packages. This mode may be desired when kubeadm itself is not the
        # SUT (System Under Test).
        return 'stable'

    else:
        raise ValueError("Unknown kubeadm mode given: %s" % mode)

class LocalMode(object):
    """Runs e2e tests by calling kubetest."""
    def __init__(self, workspace, artifacts):
        self.command = 'kubetest'
        self.workspace = workspace
        self.artifacts = artifacts
        self.env = []
        self.os_env = []
        self.env_files = []
        self.add_environment(
            'HOME=%s' % workspace,
            'WORKSPACE=%s' % workspace,
            'PATH=%s' % os.getenv('PATH'),
        )

    def add_environment(self, *envs):
        """Adds FOO=BAR to the list of environment overrides."""
        self.env.extend(parse_env(e) for e in envs)

    def add_os_environment(self, *envs):
        """Adds FOO=BAR to the list of os environment overrides."""
        self.os_env.extend(parse_env(e) for e in envs)

    def add_file(self, env_file):
        """Reads all FOO=BAR lines from env_file."""
        with open(env_file) as fp:
            for line in fp:
                line = line.rstrip()
                if not line or line.startswith('#'):
                    continue
                self.env_files.append(parse_env(line))

    def add_env(self, env):
        self.env_files.append(parse_env(env))

    def add_aws_cred(self, priv, pub, cred):
        """Sets aws keys and credentials."""
        ssh_dir = os.path.join(self.workspace, '.ssh')
        if not os.path.isdir(ssh_dir):
            os.makedirs(ssh_dir)

        cred_dir = os.path.join(self.workspace, '.aws')
        if not os.path.isdir(cred_dir):
            os.makedirs(cred_dir)

        aws_ssh = os.path.join(ssh_dir, 'kube_aws_rsa')
        aws_pub = os.path.join(ssh_dir, 'kube_aws_rsa.pub')
        aws_cred = os.path.join(cred_dir, 'credentials')
        shutil.copy(priv, aws_ssh)
        shutil.copy(pub, aws_pub)
        shutil.copy(cred, aws_cred)

        self.add_environment(
            'JENKINS_AWS_SSH_PRIVATE_KEY_FILE=%s' % priv,
            'JENKINS_AWS_SSH_PUBLIC_KEY_FILE=%s' % pub,
            'JENKINS_AWS_CREDENTIALS_FILE=%s' % cred,
        )

    def add_aws_role(self, profile, arn):
        with open(os.path.join(self.workspace, '.aws', 'config'), 'w') as cfg:
            cfg.write(aws_role_config(profile, arn))
        self.add_environment('AWS_SDK_LOAD_CONFIG=true')
        return 'jenkins-assumed-role'

    def add_gce_ssh(self, priv, pub):
        """Copies priv, pub keys to $WORKSPACE/.ssh."""
        ssh_dir = os.path.join(self.workspace, '.ssh')
        if not os.path.isdir(ssh_dir):
            os.makedirs(ssh_dir)

        gce_ssh = os.path.join(ssh_dir, 'google_compute_engine')
        gce_pub = os.path.join(ssh_dir, 'google_compute_engine.pub')
        shutil.copy(priv, gce_ssh)
        shutil.copy(pub, gce_pub)
        self.add_environment(
            'JENKINS_GCE_SSH_PRIVATE_KEY_FILE=%s' % gce_ssh,
            'JENKINS_GCE_SSH_PUBLIC_KEY_FILE=%s' % gce_pub,
        )

    @staticmethod
    def add_service_account(path):
        """Returns path."""
        return path

    def add_k8s(self, *a, **kw):
        """Add specified k8s.io repos (noop)."""
        pass

    def add_aws_runner(self):
        """Start with kops-e2e-runner.sh"""
        # TODO(Krzyzacy):retire kops-e2e-runner.sh
        self.command = os.path.join(self.workspace, 'kops-e2e-runner.sh')

    def start(self, args):
        """Starts kubetest."""
        print >>sys.stderr, 'starts with local mode'
        env = {}
        env.update(self.os_env)
        env.update(self.env_files)
        env.update(self.env)
        check_env(env, self.command, *args)


def cluster_name(cluster, build):
    """Return or select a cluster name."""
    if cluster:
        return cluster
    if len(build) < 20:
        return 'e2e-%s' % build
    return 'e2e-%s' % hashlib.md5(build).hexdigest()[:10]


# TODO(krzyzacy): Move this into kubetest
def build_kops(kops, mode):
    """Build kops, set kops related envs."""
    if not os.path.basename(kops) == 'kops':
        raise ValueError(kops)<commit_msg>Append random string to cluster name to avoid conflicts b/w presubmits<commit_after>#!/usr/bin/env python

# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Need to figure out why this only fails on travis
# pylint: disable=bad-continuation

"""Runs kubernetes e2e test with specified config"""

import argparse
import hashlib
import os
import random
import re
import shutil
import subprocess
import sys
import urllib2
import time

ORIG_CWD = os.getcwd()  # Checkout changes cwd

# The zones below are the zones available in the CNCF account (in theory, zones vary by account)
# We comment out zones below because we want to stay proportional to the limits
# We do one zone for every 10 t2.medium instances allowed
DEFAULT_AWS_ZONES = [
    #'ap-northeast-1a', # insufficient quota
    #'ap-northeast-1c', # insufficient quota
    #'ap-northeast-2a', # insufficient quota
    #'ap-northeast-2b', # insufficient quota
    #'ap-south-1a', # no c4.large instances available
    #'ap-south-1b', # no c4.large instances available
    #'ap-southeast-1a', # insufficient quota
    #'ap-southeast-1b', # insufficient quota
    #'ap-southeast-1c', # insufficient quota
    #'ap-southeast-2a', # insufficient quota
    #'ap-southeast-2b', # insufficient quota
    #'ap-southeast-2c', # insufficient quota
    #'ca-central-1a', # insufficient quota
    #'ca-central-1b', # insufficient quota
    #'eu-central-1a', # insufficient quota
    #'eu-central-1b', # insufficient quota
    #'eu-central-1c', # insufficient quota
    #'eu-west-1a', # insufficient quota
    #'eu-west-1b', # insufficient quota
    #'eu-west-1c', # insufficient quota
    #'eu-west-2a', # insufficient quota
    #'eu-west-2b', # insufficient quota
    #'eu-west-2c', # insufficient quota
    #'eu-west-3a', # insufficient quota
    #'eu-west-3b', # insufficient quota
    #'eu-west-3c', # insufficient quota
    #'sa-east-1a', # insufficient quota
    #'sa-east-1c' # insufficient quota
    'us-east-1a',
    'us-east-1b',
    #'us-east-1c', # limiting to 2 zones to not overallocate
    #'us-east-1d', # limiting to 2 zones to not overallocate
    #'us-east-1e', # limiting to 2 zones to not overallocate
    #'us-east-1f', # limiting to 2 zones to not overallocate
    #'us-east-2a', # no c4.large instances available
    #'us-east-2b', # no c4.large instances available
    #'us-east-2c', # no c4.large instances available
    'us-west-1a',
    #'us-west-1b', # overall limit is 10 instances
    'us-west-2a',
    'us-west-2b',
    #'us-west-2c' # limiting to 2 zones to not overallocate
]

def test_infra(*paths):
    """Return path relative to root of test-infra repo."""
    return os.path.join(ORIG_CWD, os.path.dirname(__file__), '..', *paths)


def check(*cmd):
    """Log and run the command, raising on errors."""
    print >>sys.stderr, 'Run:', cmd
    subprocess.check_call(cmd)


def check_output(*cmd):
    """Log and run the command, raising on errors, return output"""
    print >>sys.stderr, 'Run:', cmd
    return subprocess.check_output(cmd)


def check_env(env, *cmd):
    """Log and run the command with a specific env, raising on errors."""
    print >>sys.stderr, 'Environment:'
    for key, value in sorted(env.items()):
        print >>sys.stderr, '%s=%s' % (key, value)
    print >>sys.stderr, 'Run:', cmd
    subprocess.check_call(cmd, env=env)


def kubekins(tag):
    """Return full path to kubekins-e2e:tag."""
    return 'gcr.io/k8s-testimages/kubekins-e2e:%s' % tag

def parse_env(env):
    """Returns (FOO, BAR=MORE) for FOO=BAR=MORE."""
    return env.split('=', 1)

def aws_role_config(profile, arn):
    return (('[profile jenkins-assumed-role]\n' +
             'role_arn = %s\n' +
             'source_profile = %s\n') %
            (arn, profile))

def kubeadm_version(mode, shared_build_gcs_path):
    """Return string to use for kubeadm version, given the job's mode (ci/pull/periodic)."""
    version = ''
    if mode in ['ci', 'periodic']:
        # This job only runs against the kubernetes repo, and bootstrap.py leaves the
        # current working directory at the repository root. Grab the SCM_REVISION so we
        # can use the .debs built during the bazel-build job that should have already
        # succeeded.
        status = re.search(
            r'STABLE_BUILD_SCM_REVISION ([^\n]+)',
            check_output('hack/print-workspace-status.sh')
        )
        if not status:
            raise ValueError('STABLE_BUILD_SCM_REVISION not found')
        version = status.group(1)

        # The path given here should match ci-kubernetes-bazel-build
        return 'gs://kubernetes-release-dev/ci/%s-bazel/bin/linux/amd64/' % version

    elif mode == 'pull':
        # The format of shared_build_gcs_path looks like:
        # gs://kubernetes-release-dev/bazel/<git-describe-output>
        # Add bin/linux/amd64 yet to that path so it points to the dir with the debs
        return '%s/bin/linux/amd64/' % shared_build_gcs_path

    elif mode == 'stable':
        # This job need not run against the kubernetes repo and uses the stable version
        # of kubeadm packages. This mode may be desired when kubeadm itself is not the
        # SUT (System Under Test).
        return 'stable'

    else:
        raise ValueError("Unknown kubeadm mode given: %s" % mode)

class LocalMode(object):
    """Runs e2e tests by calling kubetest."""
    def __init__(self, workspace, artifacts):
        self.command = 'kubetest'
        self.workspace = workspace
        self.artifacts = artifacts
        self.env = []
        self.os_env = []
        self.env_files = []
        self.add_environment(
            'HOME=%s' % workspace,
            'WORKSPACE=%s' % workspace,
            'PATH=%s' % os.getenv('PATH'),
        )

    def add_environment(self, *envs):
        """Adds FOO=BAR to the list of environment overrides."""
        self.env.extend(parse_env(e) for e in envs)

    def add_os_environment(self, *envs):
        """Adds FOO=BAR to the list of os environment overrides."""
        self.os_env.extend(parse_env(e) for e in envs)

    def add_file(self, env_file):
        """Reads all FOO=BAR lines from env_file."""
        with open(env_file) as fp:
            for line in fp:
                line = line.rstrip()
                if not line or line.startswith('#'):
                    continue
                self.env_files.append(parse_env(line))

    def add_env(self, env):
        self.env_files.append(parse_env(env))

    def add_aws_cred(self, priv, pub, cred):
        """Sets aws keys and credentials."""
        ssh_dir = os.path.join(self.workspace, '.ssh')
        if not os.path.isdir(ssh_dir):
            os.makedirs(ssh_dir)

        cred_dir = os.path.join(self.workspace, '.aws')
        if not os.path.isdir(cred_dir):
            os.makedirs(cred_dir)

        aws_ssh = os.path.join(ssh_dir, 'kube_aws_rsa')
        aws_pub = os.path.join(ssh_dir, 'kube_aws_rsa.pub')
        aws_cred = os.path.join(cred_dir, 'credentials')
        shutil.copy(priv, aws_ssh)
        shutil.copy(pub, aws_pub)
        shutil.copy(cred, aws_cred)

        self.add_environment(
            'JENKINS_AWS_SSH_PRIVATE_KEY_FILE=%s' % priv,
            'JENKINS_AWS_SSH_PUBLIC_KEY_FILE=%s' % pub,
            'JENKINS_AWS_CREDENTIALS_FILE=%s' % cred,
        )

    def add_aws_role(self, profile, arn):
        with open(os.path.join(self.workspace, '.aws', 'config'), 'w') as cfg:
            cfg.write(aws_role_config(profile, arn))
        self.add_environment('AWS_SDK_LOAD_CONFIG=true')
        return 'jenkins-assumed-role'

    def add_gce_ssh(self, priv, pub):
        """Copies priv, pub keys to $WORKSPACE/.ssh."""
        ssh_dir = os.path.join(self.workspace, '.ssh')
        if not os.path.isdir(ssh_dir):
            os.makedirs(ssh_dir)

        gce_ssh = os.path.join(ssh_dir, 'google_compute_engine')
        gce_pub = os.path.join(ssh_dir, 'google_compute_engine.pub')
        shutil.copy(priv, gce_ssh)
        shutil.copy(pub, gce_pub)
        self.add_environment(
            'JENKINS_GCE_SSH_PRIVATE_KEY_FILE=%s' % gce_ssh,
            'JENKINS_GCE_SSH_PUBLIC_KEY_FILE=%s' % gce_pub,
        )

    @staticmethod
    def add_service_account(path):
        """Returns path."""
        return path

    def add_k8s(self, *a, **kw):
        """Add specified k8s.io repos (noop)."""
        pass

    def add_aws_runner(self):
        """Start with kops-e2e-runner.sh"""
        # TODO(Krzyzacy):retire kops-e2e-runner.sh
        self.command = os.path.join(self.workspace, 'kops-e2e-runner.sh')

    def start(self, args):
        """Starts kubetest."""
        print >>sys.stderr, 'starts with local mode'
        env = {}
        env.update(self.os_env)
        env.update(self.env_files)
        env.update(self.env)
        check_env(env, self.command, *args)


def cluster_name(cluster, build):
    """Return or select a cluster name."""
    if cluster:
        return cluster
    # Create a suffix based on the build number. Append a random string to it for
    # avoiding potential conflicts across different jobs' runs (see issue #7592).
    suffix = build if len(build) < 10 else hashlib.md5(build).hexdigest()[:10]
    return 'e2e-%s-%s' % (suffix, os.urandom(3).encode('hex'))


# TODO(krzyzacy): Move this into kubetest
def build_kops(kops, mode):
    """Build kops, set kops related envs."""
    if not os.path.basename(kops) == 'kops':
        raise ValueError(kops)
{'fraction_non_alphanumeric': 0.12523459294953082, 'fraction_numerical': 0.009434440781131119, 'mean_word_length': 2.773397129186603, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3598269', 'n_tokens_mistral': 6777, 'n_tokens_neox': 6374, 'n_words': 1768}