One thing that you may find challenging in Fabric (at least I have) is keeping your host lists up to date. This is now not a problem is you leverage Foreman to store your system information!
This is an interactive script that pulls your system hostnames out of Foreman (using the rest API) and then allows you to run a regex against the hostnames to narrow that list down. I've used someone else's yes/no logic so I can't take credit for that one (sorry, I can't recall where I pulled it from - I wrote this a few weeks ago)
I've named this sprinkler.py but you can name it what you want. Be sure to edit your Foreman FQDN and mark the file as executable....and remember that you can do great & terrible things with this script:
#!/usr/bin/python
import urllib2, base64, sys, getpass, json, os, re
from fabric.api import *
from fabric.tasks import execute
##
#Set variables we need to use
##
string_o_machines = ""
if len(sys.argv) == 1:
print ("\n Usage ./sprinkler.py is required\n")
sys.exit(0)
else:
myname = sys.argv[1]
#
foreman_fqdn = "my_foreman_hostname.company.com"
#
def query_yes_no(question, default="yes"):
valid = {"yes":"yes", "y":"yes", "ye":"yes",
"no":"no", "n":"no"}
if default == None:
prompt = " [y/n] "
elif default == "yes":
prompt = " [Y/n] "
elif default == "no":
prompt = " [y/N] "
else:
raise ValueError("invalid default answer: '%s'" % default)
while 1:
sys.stdout.write(question + prompt)
choice = raw_input().lower()
if default is not None and choice == '':
return default
elif choice in valid.keys():
return valid[choice]
else:
sys.stdout.write("Please respond with 'yes' or 'no' "\
"(or 'y' or 'n').\n")
#
print ("")
print ("Username is " + myname)
pw = getpass.getpass() #Get password from person running script
print ("")
#
print ("What command should I issue?")
send_command = raw_input('')
print ("")
#
print ("What systems should I send this to? Use regex like .*domain.com app0?.*.com")
domain = raw_input('')
print ("")
#
needs_sudo = query_yes_no("Does this command require sudo rights?")
#
request = urllib2.Request("https://" + foreman_fqdn + "/api/hosts?per_page=10000")
#
#
#
# You need the replace to handle encodestring adding a trailing newline
# (https://docs.python.org/2/library/base64.html#base64.encodestring)
base64string = base64.encodestring('%s:%s' % (myname, pw)).replace('\n', '')
request.add_header("Authorization", "Basic %s" % base64string)
json_obj = urllib2.urlopen(request)
#
#
#
data = json.load(json_obj)
hostlist = []
for item in data:
hostname = item['host']['name']
hostlist.append(hostname)
x=re.compile(domain)
sub_list = filter(x.match, hostlist)
#print sub_list
this_many = len(sub_list)
#
#
print ('')
keep_going = query_yes_no("Command will be send to " + str(this_many) + " systems. Would you like to continue?\n (No will list systems that it would have run on and exit)")
if keep_going == "no":
print (sub_list)
sys.exit()
#
#
env.user = myname
env.hosts = sub_list
env.password = pw
#
@parallel(pool_size=5)
def command_to_run():
if needs_sudo == "no":
with settings(warn_only=True):
run( send_command )
else:
with settings(warn_only=True):
sudo( send_command )
#
if __name__ == '__main__':
execute(command_to_run)
Have fun using this! (You may also customize how many parallel systems this runs on at any given time by adjusting the pool size on that.)
No comments:
Post a Comment