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)