
This adds a script that will put the jenkins master in shutdown mode, wait for all jobs to finish running, then optionally delete any offline slaves. Once this is complete you can restart the jenkins master in whatever fashion you choose safely. Change-Id: I0cb858665de0e733267b5f45b071b076167ee63a
93 lines
3.3 KiB
Python
Executable File
93 lines
3.3 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright 2015 OpenStack Foundation
|
|
#
|
|
# 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.
|
|
|
|
import argparse
|
|
import time
|
|
|
|
import jenkins
|
|
|
|
|
|
def delete_offline_nodes(server, timeout):
|
|
start = time.time()
|
|
end = start + timeout
|
|
while True:
|
|
nodes = server.get_nodes()
|
|
offline_nodes = [node for node in nodes if node['offline']]
|
|
if not offline_nodes:
|
|
# We have converged to no offline nodes state
|
|
break
|
|
elif time.time() > end:
|
|
raise Exception("Offline slave deletion timeout exceeded.")
|
|
try:
|
|
for n in offline_nodes:
|
|
server.delete_node(n['name'])
|
|
# This may have raced an external system deleting nodes
|
|
# after jobs complete. Just retry as we should
|
|
# converage on no jobs running and no deletions.
|
|
except jenkins.NotFoundException:
|
|
pass
|
|
except jenkins.JenkinsException as e:
|
|
if '[500]' in e.message:
|
|
pass
|
|
else:
|
|
raise
|
|
time.sleep(1)
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(description='Safely stop Jenkins.')
|
|
parser.add_argument('--url', default='http://localhost:8080',
|
|
help='Base url for Jenkins master.')
|
|
parser.add_argument('--user', required=True,
|
|
help='Username to connect to Jenkins with.')
|
|
parser.add_argument('--password', required=True,
|
|
help='Password to auth with.')
|
|
parser.add_argument('--no-delete', dest='delete', action='store_false',
|
|
default=True, help="Don't delete offline slaves.")
|
|
parser.add_argument('--delete-timeout', type=int, default=300,
|
|
help="Seconds to spend deleting offline slaves.")
|
|
args = parser.parse_args()
|
|
return args
|
|
|
|
def main():
|
|
args = parse_args()
|
|
server = jenkins.Jenkins(args.url,
|
|
username=args.user,
|
|
password=args.password)
|
|
|
|
# Put in shutdown mode
|
|
server.quiet_down()
|
|
while True:
|
|
try:
|
|
if not server.get_running_builds():
|
|
break
|
|
# This may have raced an external system deleting executors
|
|
# while listing the running jobs. Just retry as we should
|
|
# converage on no jobs running and no deletions.
|
|
except jenkins.NotFoundException:
|
|
pass
|
|
except jenkins.JenkinsException as e:
|
|
if '[500]' in e.message:
|
|
pass
|
|
else:
|
|
raise
|
|
# Jobs are slow wait a minute between polls
|
|
time.sleep(60)
|
|
if args.delete:
|
|
# Remove any offline nodes so they don't go online after restart.
|
|
delete_offline_nodes(server, args.delete_timeout)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|