github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/jenkins/master_ctl.py (about) 1 #!/usr/bin/env python 2 3 # Copyright 2016 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 """Script to snapshot a jenkins master or restore those snapshots. 18 19 Note that this does not clean up old snapshots, nor does it handle problem 20 (for example duplicate build numbers) associated with restoring an old 21 snapshot. Thus the restore feature should be used in emergencies only. 22 """ 23 24 import argparse 25 import getpass 26 import subprocess 27 import sys 28 import time 29 30 31 def gcloud(project, *args, **kwargs): 32 cmd = ('gcloud', '--project=%s' % project, 'compute') + args 33 print >>sys.stderr, 'RUN:', ' '.join(cmd) 34 if not kwargs.get('output'): 35 subprocess.check_call(cmd) 36 return '' 37 return subprocess.check_output(cmd) 38 39 40 def snapshot_disks(project, zone, *disks): 41 ymd = time.strftime('%Y%m%d', time.localtime()) 42 snapshots = ['%s-%s' % (d, ymd) for d in disks] 43 gcloud( 44 project, 45 'disks', 46 'snapshot', 47 '--zone=%s' % zone, 48 '--snapshot-names=%s' % ','.join(snapshots), 49 *disks) 50 51 52 def get_disks(instance): 53 """Return a {name: size_gb} map.""" 54 return { 55 instance: 500, 56 '%s-data' % instance: 1000, 57 '%s-docker' % instance: 1000, # Only 200 in pr 58 } 59 60 61 def get_address(project, zone, instance): 62 """Return the reserved ip address of the instance.""" 63 return gcloud( 64 project, 65 'addresses', 66 'describe', 67 '%s-ip' % instance, 68 '--region=%s' % get_region(zone), 69 '--format=value(address)', 70 ) 71 72 73 74 def get_region(zone): 75 """Converts us-central1-f into us-central1.""" 76 return '-'.join(zone.split('-')[:2]) 77 78 79 def get_snapshot(project, zone, instance): 80 """Snapshot all the disks for this instance.""" 81 snapshot_disks(project, zone, *get_disks(instance)) 82 83 84 def delete(project, zone, instance): 85 """Confirm and delete instance and associated disks.""" 86 print >>sys.stderr, 'WARNING: duplicated jobs may fail/corrupt results' 87 print >>sys.stderr, ('TODO(fejta): See http://stackoverflow.com/' 88 'questions/19645430/changing-jenkins-build-number') 89 answer = raw_input('Delete %s [yes/NO]: ') 90 if not answer or answer != 'yes': 91 print >>sys.stderr, 'aborting' 92 sys.exit(1) 93 gcloud( 94 project, 95 'compute', 96 'instances', 97 'delete', 98 '--zone=%s' % zone, 99 instance, 100 ) 101 gcloud( 102 project, 103 'compute', 104 'disks', 105 'delete', 106 '--zone=%s' % zone, 107 *get_disks(instance)) 108 109 110 SCOPES = [ 111 'cloud-platform', 112 'compute-rw', 113 'logging-write', 114 'storage-rw', 115 ] 116 117 118 def restore(project, zone, instance, snapshot): 119 """Restore instance and disks from the snapshot suffix.""" 120 disks = [] 121 description = 'Created from %s by %s' % (snapshot, getpass.getuser()) 122 for disk, size in get_disks(instance).items(): 123 gcloud( 124 project, 125 'compute', 126 'disks', 127 'create', 128 '--description=%s' % description, 129 '--zone=%s' % zone, 130 '--size=%dGB' % size, 131 '--source-snapshot=%s-%s' % (disk, snapshot), 132 disk, 133 ) 134 attrs = [ 135 'name=%s' % disk, 136 'device-name=%s' % disk, 137 ] 138 if disk == instance: 139 attrs.append('boot=yes') 140 disks.append(attrs) 141 gcloud( 142 project, 143 'compute', 144 'instances', 145 'create', 146 '--description=%s' % description, 147 '--zone=%s' % zone, 148 '--machine-type=n1-highmem-32', # should reduce to 8 149 '--scopes=%s' % ','.join(SCOPES), 150 '--tag=do-not-delete,jenkins,jenkins-master', 151 '--address=%s' % get_address(project, zone, instance), 152 *('--disk=%s' % ','.join(a) for a in disks)) 153 154 155 156 def main(args): 157 if args.pr: 158 project, instance = 'kubernetes-jenkins-pull', 'pull-jenkins-master' 159 else: 160 project, instance = 'kubernetes-jenkins', 'jenkins-master' 161 zone = args.zone 162 if not args.restore: 163 get_snapshot(project, zone, instance) 164 return 165 if args.delete: 166 delete(project, zone, instance) 167 snapshot = args.restore 168 restore(project, zone, instance, snapshot) 169 170 171 if __name__ == '__main__': 172 PARSER = argparse.ArgumentParser('Tool to backup/restore the jenkins master') 173 PARSER.add_argument( 174 '--zone', default='us-central1-f', help='Jenkins zone') 175 PARSER.add_argument( 176 '--pr', action='store_true', help='Manipulate PR jenkins when set') 177 PARSER.add_argument( 178 '--restore', help='restore jenkins to the YYYYMMDD snapshot when set') 179 PARSER.add_argument( 180 '--delete', help='delete current jenkins instance before restoring') 181 ARGS = PARSER.parse_args() 182 main(ARGS)