github.com/maxgio92/test-infra@v0.1.0/scenarios/kubernetes_e2e.py (about) 1 #!/usr/bin/env python3 2 3 # Copyright 2017 The Kubernetes Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 # Need to figure out why this only fails on travis 18 # pylint: disable=bad-continuation 19 20 """Runs kubernetes e2e test with specified config""" 21 22 import argparse 23 import hashlib 24 import os 25 import random 26 import re 27 import shutil 28 import subprocess 29 import sys 30 import urllib.request, urllib.error, urllib.parse 31 import time 32 33 ORIG_CWD = os.getcwd() # Checkout changes cwd 34 35 # The zones below are the zones available in the CNCF account (in theory, zones vary by account) 36 # We aim for 3 zones per region to try to maintain even spreading. 37 # We also remove a few zones where our preferred instance type is not available, 38 # though really this needs a better fix (likely in kops) 39 DEFAULT_AWS_ZONES = [ 40 'ap-northeast-1a', 41 'ap-northeast-1c', 42 'ap-northeast-1d', 43 'ap-northeast-2a', 44 #'ap-northeast-2b' - AZ does not exist, so we're breaking the 3 AZs per region target here 45 'ap-northeast-2c', 46 'ap-south-1a', 47 'ap-south-1b', 48 'ap-southeast-1a', 49 'ap-southeast-1b', 50 'ap-southeast-1c', 51 'ap-southeast-2a', 52 'ap-southeast-2b', 53 'ap-southeast-2c', 54 'ca-central-1a', 55 'ca-central-1b', 56 'eu-central-1a', 57 'eu-central-1b', 58 'eu-central-1c', 59 'eu-west-1a', 60 'eu-west-1b', 61 'eu-west-1c', 62 'eu-west-2a', 63 'eu-west-2b', 64 'eu-west-2c', 65 #'eu-west-3a', documented to not support c4 family 66 #'eu-west-3b', documented to not support c4 family 67 #'eu-west-3c', documented to not support c4 family 68 'sa-east-1a', 69 #'sa-east-1b', AZ does not exist, so we're breaking the 3 AZs per region target here 70 'sa-east-1c', 71 #'us-east-1a', # temporarily removing due to lack of quota #10043 72 #'us-east-1b', # temporarily removing due to lack of quota #10043 73 #'us-east-1c', # temporarily removing due to lack of quota #10043 74 #'us-east-1d', # limiting to 3 zones to not overallocate 75 #'us-east-1e', # limiting to 3 zones to not overallocate 76 #'us-east-1f', # limiting to 3 zones to not overallocate 77 #'us-east-2a', InsufficientInstanceCapacity for c4.large 2018-05-30 78 #'us-east-2b', InsufficientInstanceCapacity for c4.large 2018-05-30 79 #'us-east-2c', InsufficientInstanceCapacity for c4.large 2018-05-30 80 'us-west-1a', 81 'us-west-1b', 82 #'us-west-1c', AZ does not exist, so we're breaking the 3 AZs per region target here 83 #'us-west-2a', # temporarily removing due to lack of quota #10043 84 #'us-west-2b', # temporarily removing due to lack of quota #10043 85 #'us-west-2c', # temporarily removing due to lack of quota #10043 86 ] 87 88 def test_infra(*paths): 89 """Return path relative to root of test-infra repo.""" 90 return os.path.join(ORIG_CWD, os.path.dirname(__file__), '..', *paths) 91 92 93 def check(*cmd): 94 """Log and run the command, raising on errors.""" 95 print('Run:', cmd, file=sys.stderr) 96 subprocess.check_call(cmd) 97 98 99 def check_output(*cmd): 100 """Log and run the command, raising on errors, return output""" 101 print('Run:', cmd, file=sys.stderr) 102 return subprocess.check_output(cmd) 103 104 105 def check_env(env, *cmd): 106 """Log and run the command with a specific env, raising on errors.""" 107 print('Environment:', file=sys.stderr) 108 for key, value in sorted(env.items()): 109 print('%s=%s' % (key, value), file=sys.stderr) 110 print('Run:', cmd, file=sys.stderr) 111 subprocess.check_call(cmd, env=env) 112 113 114 def kubekins(tag): 115 """Return full path to kubekins-e2e:tag.""" 116 return 'gcr.io/k8s-staging-test-infra/kubekins-e2e:%s' % tag 117 118 def parse_env(env): 119 """Returns (FOO, BAR=MORE) for FOO=BAR=MORE.""" 120 return env.split('=', 1) 121 122 def aws_role_config(profile, arn): 123 return (('[profile jenkins-assumed-role]\n' + 124 'role_arn = %s\n' + 125 'source_profile = %s\n') % 126 (arn, profile)) 127 128 class LocalMode(object): 129 """Runs e2e tests by calling kubetest.""" 130 def __init__(self, workspace, artifacts): 131 self.command = 'kubetest' 132 self.workspace = workspace 133 self.artifacts = artifacts 134 self.env = [] 135 self.os_env = [] 136 self.env_files = [] 137 self.add_environment( 138 'HOME=%s' % workspace, 139 'WORKSPACE=%s' % workspace, 140 'PATH=%s' % os.getenv('PATH'), 141 ) 142 143 def add_environment(self, *envs): 144 """Adds FOO=BAR to the list of environment overrides.""" 145 self.env.extend(parse_env(e) for e in envs) 146 147 def add_os_environment(self, *envs): 148 """Adds FOO=BAR to the list of os environment overrides.""" 149 self.os_env.extend(parse_env(e) for e in envs) 150 151 def add_file(self, env_file): 152 """Reads all FOO=BAR lines from env_file.""" 153 with open(env_file) as fp: 154 for line in fp: 155 line = line.rstrip() 156 if not line or line.startswith('#'): 157 continue 158 self.env_files.append(parse_env(line)) 159 160 def add_env(self, env): 161 self.env_files.append(parse_env(env)) 162 163 def add_aws_cred(self, priv, pub, cred): 164 """Sets aws keys and credentials.""" 165 ssh_dir = os.path.join(self.workspace, '.ssh') 166 if not os.path.isdir(ssh_dir): 167 os.makedirs(ssh_dir) 168 169 cred_dir = os.path.join(self.workspace, '.aws') 170 if not os.path.isdir(cred_dir): 171 os.makedirs(cred_dir) 172 173 aws_ssh = os.path.join(ssh_dir, 'kube_aws_rsa') 174 aws_pub = os.path.join(ssh_dir, 'kube_aws_rsa.pub') 175 aws_cred = os.path.join(cred_dir, 'credentials') 176 shutil.copy(priv, aws_ssh) 177 shutil.copy(pub, aws_pub) 178 shutil.copy(cred, aws_cred) 179 180 self.add_environment( 181 'AWS_SSH_PRIVATE_KEY_FILE=%s' % priv, 182 'AWS_SSH_PUBLIC_KEY_FILE=%s' % pub, 183 'AWS_SHARED_CREDENTIALS_FILE=%s' % cred, 184 ) 185 186 def add_aws_role(self, profile, arn): 187 with open(os.path.join(self.workspace, '.aws', 'config'), 'w') as cfg: 188 cfg.write(aws_role_config(profile, arn)) 189 self.add_environment('AWS_SDK_LOAD_CONFIG=true') 190 return 'jenkins-assumed-role' 191 192 def add_gce_ssh(self, priv, pub): 193 """Copies priv, pub keys to $WORKSPACE/.ssh.""" 194 ssh_dir = os.path.join(self.workspace, '.ssh') 195 if not os.path.isdir(ssh_dir): 196 os.makedirs(ssh_dir) 197 198 gce_ssh = os.path.join(ssh_dir, 'google_compute_engine') 199 gce_pub = os.path.join(ssh_dir, 'google_compute_engine.pub') 200 shutil.copy(priv, gce_ssh) 201 shutil.copy(pub, gce_pub) 202 self.add_environment( 203 'JENKINS_GCE_SSH_PRIVATE_KEY_FILE=%s' % gce_ssh, 204 'JENKINS_GCE_SSH_PUBLIC_KEY_FILE=%s' % gce_pub, 205 ) 206 207 @staticmethod 208 def add_service_account(path): 209 """Returns path.""" 210 return path 211 212 def add_k8s(self, *a, **kw): 213 """Add specified k8s.io repos (noop).""" 214 pass 215 216 def add_aws_runner(self): 217 """Start with kops-e2e-runner.sh""" 218 # TODO(Krzyzacy):retire kops-e2e-runner.sh 219 self.command = os.path.join(self.workspace, 'kops-e2e-runner.sh') 220 221 def start(self, args): 222 """Starts kubetest.""" 223 print('starts with local mode', file=sys.stderr) 224 env = {} 225 env.update(self.os_env) 226 env.update(self.env_files) 227 env.update(self.env) 228 check_env(env, self.command, *args) 229 230 231 def cluster_name(cluster, tear_down_previous=False): 232 """Return or select a cluster name.""" 233 if cluster: 234 return cluster 235 # Create a suffix based on the build number and job name. 236 # This ensures no conflict across runs of different jobs (see #7592). 237 # For PR jobs, we use PR number instead of build number to ensure the 238 # name is constant across different runs of the presubmit on the PR. 239 # This helps clean potentially leaked resources from earlier run that 240 # could've got evicted midway (see #7673). 241 job_type = os.getenv('JOB_TYPE') 242 if job_type == 'batch': 243 suffix = 'batch-%s' % os.getenv('BUILD_ID', 0) 244 elif job_type == 'presubmit' and tear_down_previous: 245 suffix = '%s' % os.getenv('PULL_NUMBER', 0) 246 else: 247 suffix = '%s' % os.getenv('BUILD_ID', 0) 248 if len(suffix) > 10: 249 suffix = hashlib.md5(suffix.encode('utf-8')).hexdigest()[:10] 250 job_hash = hashlib.md5(os.getenv('JOB_NAME', '').encode('utf-8')).hexdigest()[:5] 251 return 'e2e-%s-%s' % (suffix, job_hash) 252 253 254 # TODO(krzyzacy): Move this into kubetest 255 def build_kops(kops, mode): 256 """Build kops, set kops related envs.""" 257 if not os.path.basename(kops) == 'kops': 258 raise ValueError(kops) 259 version = 'pull-' + check_output('git', 'describe', '--always').strip() 260 job = os.getenv('JOB_NAME', 'pull-kops-e2e-kubernetes-aws') 261 gcs = 'gs://kops-ci/pulls/%s' % job 262 gapi = 'https://storage.googleapis.com/kops-ci/pulls/%s' % job 263 mode.add_environment( 264 'KOPS_BASE_URL=%s/%s' % (gapi, version), 265 'GCS_LOCATION=%s' % gcs 266 ) 267 check('make', 'gcs-publish-ci', 'VERSION=%s' % version, 'GCS_LOCATION=%s' % gcs) 268 269 270 def set_up_kops_gce(workspace, args, mode, cluster, runner_args): 271 """Set up kops on GCE envs.""" 272 for path in [args.gce_ssh, args.gce_pub]: 273 if not os.path.isfile(os.path.expandvars(path)): 274 raise IOError(path, os.path.expandvars(path)) 275 mode.add_gce_ssh(args.gce_ssh, args.gce_pub) 276 277 gce_ssh = os.path.join(workspace, '.ssh', 'google_compute_engine') 278 279 zones = args.kops_zones or random.choice([ 280 'us-central1-a', 281 'us-central1-b', 282 'us-central1-c', 283 'us-central1-f', 284 ]) 285 286 runner_args.extend([ 287 '--kops-cluster=%s' % cluster, 288 '--kops-zones=%s' % zones, 289 '--kops-state=%s' % args.kops_state_gce, 290 '--kops-nodes=%s' % args.kops_nodes, 291 '--kops-ssh-key=%s' % gce_ssh, 292 ]) 293 294 295 def set_up_kops_aws(workspace, args, mode, cluster, runner_args): 296 """Set up aws related envs for kops. Will replace set_up_aws.""" 297 for path in [args.aws_ssh, args.aws_pub, args.aws_cred]: 298 if not os.path.isfile(os.path.expandvars(path)): 299 raise IOError(path, os.path.expandvars(path)) 300 mode.add_aws_cred(args.aws_ssh, args.aws_pub, args.aws_cred) 301 302 aws_ssh = os.path.join(workspace, '.ssh', 'kube_aws_rsa') 303 profile = args.aws_profile 304 if args.aws_role_arn: 305 profile = mode.add_aws_role(profile, args.aws_role_arn) 306 307 # kubetest for kops now support select random regions and zones. 308 # For initial testing we are not sending in zones when the 309 # --kops-multiple-zones flag is set. If the flag is not set then 310 # we use the older functionality of passing in zones. 311 if args.kops_multiple_zones: 312 runner_args.extend(["--kops-multiple-zones"]) 313 else: 314 # TODO(@chrislovecnm): once we have tested we can remove the zones 315 # and region logic from this code and have kubetest handle that 316 # logic 317 zones = args.kops_zones or random.choice(DEFAULT_AWS_ZONES) 318 regions = ','.join([zone[:-1] for zone in zones.split(',')]) 319 runner_args.extend(['--kops-zones=%s' % zones]) 320 mode.add_environment( 321 'KOPS_REGIONS=%s' % regions, 322 ) 323 324 mode.add_environment( 325 'AWS_PROFILE=%s' % profile, 326 'AWS_DEFAULT_PROFILE=%s' % profile, 327 ) 328 329 if args.aws_cluster_domain: 330 cluster = '%s.%s' % (cluster, args.aws_cluster_domain) 331 332 # AWS requires a username (and it varies per-image) 333 ssh_user = args.kops_ssh_user or 'admin' 334 335 runner_args.extend([ 336 '--kops-cluster=%s' % cluster, 337 '--kops-state=%s' % args.kops_state, 338 '--kops-nodes=%s' % args.kops_nodes, 339 '--kops-ssh-key=%s' % aws_ssh, 340 '--kops-ssh-user=%s' % ssh_user, 341 ]) 342 343 344 def set_up_aws(workspace, args, mode, cluster, runner_args): 345 """Set up aws related envs. Legacy; will be replaced by set_up_kops_aws.""" 346 for path in [args.aws_ssh, args.aws_pub, args.aws_cred]: 347 if not os.path.isfile(os.path.expandvars(path)): 348 raise IOError(path, os.path.expandvars(path)) 349 mode.add_aws_cred(args.aws_ssh, args.aws_pub, args.aws_cred) 350 351 aws_ssh = os.path.join(workspace, '.ssh', 'kube_aws_rsa') 352 profile = args.aws_profile 353 if args.aws_role_arn: 354 profile = mode.add_aws_role(profile, args.aws_role_arn) 355 356 zones = args.kops_zones or random.choice(DEFAULT_AWS_ZONES) 357 regions = ','.join([zone[:-1] for zone in zones.split(',')]) 358 359 mode.add_environment( 360 'AWS_PROFILE=%s' % profile, 361 'AWS_DEFAULT_PROFILE=%s' % profile, 362 'KOPS_REGIONS=%s' % regions, 363 ) 364 365 if args.aws_cluster_domain: 366 cluster = '%s.%s' % (cluster, args.aws_cluster_domain) 367 368 # AWS requires a username (and it varies per-image) 369 ssh_user = args.kops_ssh_user or 'admin' 370 371 runner_args.extend([ 372 '--kops-cluster=%s' % cluster, 373 '--kops-zones=%s' % zones, 374 '--kops-state=%s' % args.kops_state, 375 '--kops-nodes=%s' % args.kops_nodes, 376 '--kops-ssh-key=%s' % aws_ssh, 377 '--kops-ssh-user=%s' % ssh_user, 378 ]) 379 # TODO(krzyzacy):Remove after retire kops-e2e-runner.sh 380 mode.add_aws_runner() 381 382 def read_gcs_path(gcs_path): 383 """reads a gcs path (gs://...) by HTTP GET to storage.googleapis.com""" 384 link = gcs_path.replace('gs://', 'https://storage.googleapis.com/') 385 loc = urllib.request.urlopen(link).read() 386 print("Read GCS Path: %s" % loc, file=sys.stderr) 387 return loc 388 389 def get_shared_gcs_path(gcs_shared, use_shared_build): 390 """return the shared path for this set of jobs using args and $PULL_REFS.""" 391 build_file = '' 392 if use_shared_build: 393 build_file += use_shared_build + '-' 394 build_file += 'build-location.txt' 395 return os.path.join(gcs_shared, os.getenv('PULL_REFS', ''), build_file) 396 397 def inject_bazelrc(lines): 398 if not lines: 399 return 400 lines = [l + '\n' for l in lines] 401 with open('/etc/bazel.bazelrc', 'a') as fp: 402 fp.writelines(lines) 403 path = os.path.join(os.getenv('HOME'), '.bazelrc') 404 with open(path, 'a') as fp: 405 fp.writelines(lines) 406 407 def main(args): 408 """Set up env, start kubekins-e2e, handle termination. """ 409 # pylint: disable=too-many-branches,too-many-statements,too-many-locals 410 411 # Rules for env var priority here in docker: 412 # -e FOO=a -e FOO=b -> FOO=b 413 # --env-file FOO=a --env-file FOO=b -> FOO=b 414 # -e FOO=a --env-file FOO=b -> FOO=a(!!!!) 415 # --env-file FOO=a -e FOO=b -> FOO=b 416 # 417 # So if you overwrite FOO=c for a local run it will take precedence. 418 # 419 420 # Set up workspace/artifacts dir 421 workspace = os.environ.get('WORKSPACE', os.getcwd()) 422 artifacts = os.environ.get('ARTIFACTS', os.path.join(workspace, '_artifacts')) 423 if not os.path.isdir(artifacts): 424 os.makedirs(artifacts) 425 426 inject_bazelrc(args.inject_bazelrc) 427 428 mode = LocalMode(workspace, artifacts) 429 430 for env_file in args.env_file: 431 mode.add_file(test_infra(env_file)) 432 for env in args.env: 433 mode.add_env(env) 434 435 # TODO(fejta): remove after next image push 436 mode.add_environment('KUBETEST_MANUAL_DUMP=y') 437 if args.dump_before_and_after: 438 before_dir = os.path.join(mode.artifacts, 'before') 439 if not os.path.exists(before_dir): 440 os.makedirs(before_dir) 441 after_dir = os.path.join(mode.artifacts, 'after') 442 if not os.path.exists(after_dir): 443 os.makedirs(after_dir) 444 445 runner_args = [ 446 '--dump-pre-test-logs=%s' % before_dir, 447 '--dump=%s' % after_dir, 448 ] 449 else: 450 runner_args = [ 451 '--dump=%s' % mode.artifacts, 452 ] 453 454 if args.service_account: 455 runner_args.append( 456 '--gcp-service-account=%s' % mode.add_service_account(args.service_account)) 457 458 shared_build_gcs_path = "" 459 if args.use_shared_build is not None: 460 # find shared build location from GCS 461 gcs_path = get_shared_gcs_path(args.gcs_shared, args.use_shared_build) 462 print('Getting shared build location from: '+gcs_path, file=sys.stderr) 463 # retry loop for reading the location 464 attempts_remaining = 12 465 while True: 466 attempts_remaining -= 1 467 try: 468 # tell kubetest to extract from this location 469 shared_build_gcs_path = read_gcs_path(gcs_path) 470 args.kubetest_args.append('--extract=' + shared_build_gcs_path) 471 args.build = None 472 break 473 except urllib.error.URLError as err: 474 print('Failed to get shared build location: %s' % err, file=sys.stderr) 475 if attempts_remaining > 0: 476 print('Waiting 5 seconds and retrying...', file=sys.stderr) 477 time.sleep(5) 478 else: 479 raise RuntimeError('Failed to get shared build location too many times!') 480 481 elif args.build is not None: 482 if args.build == '': 483 # Empty string means --build was passed without any arguments; 484 # if --build wasn't passed, args.build would be None 485 runner_args.append('--build') 486 else: 487 runner_args.append('--build=%s' % args.build) 488 k8s = os.getcwd() 489 if not os.path.basename(k8s) == 'kubernetes': 490 raise ValueError(k8s) 491 mode.add_k8s(os.path.dirname(k8s), 'kubernetes', 'release') 492 493 if args.build_federation is not None: 494 if args.build_federation == '': 495 runner_args.append('--build-federation') 496 else: 497 runner_args.append('--build-federation=%s' % args.build_federation) 498 fed = os.getcwd() 499 if not os.path.basename(fed) == 'federation': 500 raise ValueError(fed) 501 mode.add_k8s(os.path.dirname(fed), 'federation', 'release') 502 503 if args.kops_build: 504 build_kops(os.getcwd(), mode) 505 506 if args.stage is not None: 507 runner_args.append('--stage=%s' % args.stage) 508 if args.aws: 509 for line in check_output('hack/print-workspace-status.sh').split('\n'): 510 if 'gitVersion' in line: 511 _, version = line.strip().split(' ') 512 break 513 else: 514 raise ValueError('kubernetes version not found in workspace status') 515 runner_args.append('--kops-kubernetes-version=%s/%s' % ( 516 args.stage.replace('gs://', 'https://storage.googleapis.com/'), 517 version)) 518 519 # TODO(fejta): move these out of this file 520 if args.up == 'true': 521 runner_args.append('--up') 522 if args.down == 'true': 523 runner_args.append('--down') 524 if args.test == 'true': 525 runner_args.append('--test') 526 527 # Passthrough some args to kubetest 528 if args.deployment: 529 runner_args.append('--deployment=%s' % args.deployment) 530 if args.provider: 531 runner_args.append('--provider=%s' % args.provider) 532 533 cluster = cluster_name(args.cluster, args.tear_down_previous) 534 runner_args.append('--cluster=%s' % cluster) 535 runner_args.append('--gcp-network=%s' % cluster) 536 runner_args.extend(args.kubetest_args) 537 538 if args.use_logexporter: 539 runner_args.append('--logexporter-gcs-path=%s' % args.logexporter_gcs_path) 540 541 if args.aws: 542 # Legacy - prefer passing --deployment=kops, --provider=aws, 543 # which does not use kops-e2e-runner.sh 544 set_up_aws(mode.workspace, args, mode, cluster, runner_args) 545 elif args.deployment == 'kops' and args.provider == 'aws': 546 set_up_kops_aws(mode.workspace, args, mode, cluster, runner_args) 547 elif args.deployment == 'kops' and args.provider == 'gce': 548 set_up_kops_gce(mode.workspace, args, mode, cluster, runner_args) 549 elif args.deployment != 'kind' and args.gce_ssh: 550 mode.add_gce_ssh(args.gce_ssh, args.gce_pub) 551 552 # TODO(fejta): delete this? 553 mode.add_os_environment(*( 554 '%s=%s' % (k, v) for (k, v) in list(os.environ.items()))) 555 556 mode.add_environment( 557 # Boilerplate envs 558 # Skip gcloud update checking 559 'CLOUDSDK_COMPONENT_MANAGER_DISABLE_UPDATE_CHECK=true', 560 # Use default component update behavior 561 'CLOUDSDK_EXPERIMENTAL_FAST_COMPONENT_UPDATE=false', 562 # AWS 563 'KUBE_AWS_INSTANCE_PREFIX=%s' % cluster, 564 # GCE 565 'INSTANCE_PREFIX=%s' % cluster, 566 'KUBE_GCE_INSTANCE_PREFIX=%s' % cluster, 567 ) 568 569 mode.start(runner_args) 570 571 def create_parser(): 572 """Create argparser.""" 573 parser = argparse.ArgumentParser() 574 parser.add_argument( 575 '--env-file', default=[], action="append", 576 help='Job specific environment file') 577 parser.add_argument( 578 '--env', default=[], action="append", 579 help='Job specific environment setting ' + 580 '(usage: "--env=VAR=SETTING" will set VAR to SETTING).') 581 parser.add_argument( 582 '--gce-ssh', 583 default=os.environ.get('JENKINS_GCE_SSH_PRIVATE_KEY_FILE'), 584 help='Path to .ssh/google_compute_engine keys') 585 parser.add_argument( 586 '--gce-pub', 587 default=os.environ.get('JENKINS_GCE_SSH_PUBLIC_KEY_FILE'), 588 help='Path to pub gce ssh key') 589 parser.add_argument( 590 '--service-account', 591 default=os.environ.get('GOOGLE_APPLICATION_CREDENTIALS'), 592 help='Path to service-account.json') 593 parser.add_argument( 594 '--build', nargs='?', default=None, const='', 595 help='Build kubernetes binaries if set, optionally specifying strategy') 596 parser.add_argument( 597 '--inject-bazelrc', default=[], action='append', 598 help='Inject /etc/bazel.bazelrc and ~/.bazelrc lines') 599 parser.add_argument( 600 '--build-federation', nargs='?', default=None, const='', 601 help='Build federation binaries if set, optionally specifying strategy') 602 parser.add_argument( 603 '--use-shared-build', nargs='?', default=None, const='', 604 help='Use prebuilt kubernetes binaries if set, optionally specifying strategy') 605 parser.add_argument( 606 '--gcs-shared', 607 default='gs://kubernetes-jenkins/shared-results/', 608 help='Get shared build from this bucket') 609 parser.add_argument( 610 '--cluster', default='bootstrap-e2e', help='Name of the cluster') 611 parser.add_argument( 612 '--stage', default=None, help='Stage release to GCS path provided') 613 parser.add_argument( 614 '--test', default='true', help='If we need to run any actual test within kubetest') 615 parser.add_argument( 616 '--down', default='true', help='If we need to tear down the e2e cluster') 617 parser.add_argument( 618 '--up', default='true', help='If we need to bring up a e2e cluster') 619 parser.add_argument( 620 '--tear-down-previous', action='store_true', 621 help='If we need to tear down previous e2e cluster') 622 parser.add_argument( 623 '--use-logexporter', 624 action='store_true', 625 help='If we need to use logexporter tool to upload logs from nodes to GCS directly') 626 parser.add_argument( 627 '--logexporter-gcs-path', 628 default=os.environ.get('GCS_ARTIFACTS_DIR',''), 629 help='GCS path where logexporter tool will upload logs if enabled') 630 parser.add_argument( 631 '--kubetest_args', 632 action='append', 633 default=[], 634 help='Send unrecognized args directly to kubetest') 635 parser.add_argument( 636 '--dump-before-and-after', action='store_true', 637 help='Dump artifacts from both before and after the test run') 638 639 640 # kops & aws 641 # TODO(justinsb): replace with --provider=aws --deployment=kops 642 parser.add_argument( 643 '--aws', action='store_true', help='E2E job runs in aws') 644 parser.add_argument( 645 '--aws-profile', 646 default=( 647 os.environ.get('AWS_PROFILE') or 648 os.environ.get('AWS_DEFAULT_PROFILE') or 649 'default' 650 ), 651 help='Profile within --aws-cred to use') 652 parser.add_argument( 653 '--aws-role-arn', 654 default=os.environ.get('KOPS_E2E_ROLE_ARN'), 655 help='Use --aws-profile to run as --aws-role-arn if set') 656 parser.add_argument( 657 '--aws-ssh', 658 default=os.environ.get('AWS_SSH_PRIVATE_KEY_FILE'), 659 help='Path to private aws ssh keys') 660 parser.add_argument( 661 '--aws-pub', 662 default=os.environ.get('AWS_SSH_PUBLIC_KEY_FILE'), 663 help='Path to pub aws ssh key') 664 parser.add_argument( 665 '--aws-cred', 666 default=os.environ.get('AWS_SHARED_CREDENTIALS_FILE'), 667 help='Path to aws credential file') 668 parser.add_argument( 669 '--aws-cluster-domain', help='Domain of the aws cluster for aws-pr jobs') 670 parser.add_argument( 671 '--kops-nodes', default=4, type=int, help='Number of nodes to start') 672 parser.add_argument( 673 '--kops-ssh-user', default='', 674 help='Username for ssh connections to instances') 675 parser.add_argument( 676 '--kops-state', default='s3://k8s-kops-prow/', 677 help='Name of the aws state storage') 678 parser.add_argument( 679 '--kops-state-gce', default='gs://k8s-kops-gce/', 680 help='Name of the kops state storage for GCE') 681 parser.add_argument( 682 '--kops-zones', help='Comma-separated list of zones else random choice') 683 parser.add_argument( 684 '--kops-build', action='store_true', help='If we need to build kops locally') 685 parser.add_argument( 686 '--kops-multiple-zones', action='store_true', help='Use multiple zones') 687 688 689 # kubetest flags that also trigger behaviour here 690 parser.add_argument( 691 '--provider', help='provider flag as used by kubetest') 692 parser.add_argument( 693 '--deployment', help='deployment flag as used by kubetest') 694 695 return parser 696 697 698 def parse_args(args=None): 699 """Return args, adding unrecognized args to kubetest_args.""" 700 parser = create_parser() 701 args, extra = parser.parse_known_args(args) 702 args.kubetest_args += extra 703 704 if args.aws or args.provider == 'aws': 705 # If aws keys are missing, try to fetch from HOME dir 706 if not args.aws_ssh or not args.aws_pub or not args.aws_cred: 707 home = os.environ.get('HOME') 708 if not home: 709 raise ValueError('HOME dir not set!') 710 if not args.aws_ssh: 711 args.aws_ssh = '%s/.ssh/kube_aws_rsa' % home 712 print('-aws-ssh key not set. Defaulting to %s' % args.aws_ssh, file=sys.stderr) 713 if not args.aws_pub: 714 args.aws_pub = '%s/.ssh/kube_aws_rsa.pub' % home 715 print('--aws-pub key not set. Defaulting to %s' % args.aws_pub, file=sys.stderr) 716 if not args.aws_cred: 717 args.aws_cred = '%s/.aws/credentials' % home 718 print('--aws-cred not set. Defaulting to %s' % args.aws_cred, file=sys.stderr) 719 return args 720 721 722 if __name__ == '__main__': 723 main(parse_args())