Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python2.7
- import sys
- import argparse
- import os, re
- from csv import DictReader,reader
- import shutil
- import commands
- import fileinput
- import getpass
- import subprocess
- '''
- CURRENT VERSION is 3.0
- This script is to improve the way we currently use to create AddLinksToLag CMs.
- It relies on a cutsheets format file with the information of Routers, Ports and
- LAGs to be implemented. Based on that it will do the following:
- 1- Check for unstaged changes on GB & CM repo
- 2- Updating GB using arepa.py
- 3- Call gen.sh and generate config files locally on GB out folder.
- 4- Generate var file using cutsheet.py and create the CM folder to hold it on the ~/NetengIS_CM2015 repo.
- 5- Create all the push files from GB out folder to the CM folder.
- 6- Generate diffs within the CM folder.
- 7- Commit all the changes.
- 8- Update commit ID on VAR file, push and lock the CM.
- '''
- #######
- ##### Getting Vars from Arguments ######
- parser = argparse.ArgumentParser(description= 'Automatic way to create an AddLinksToLag CM within Border space.'
- ,epilog="Example: ./addlinkstolag_cm_prep_v3.py -t ~/cutsheet_test_all.csv -v --mcm MCM-13091682")
- parser.add_argument("-c","--mcm", help="MCM number",required=True)
- parser.add_argument("-t","--cutsheet", help="Name of the cutsheet file",required=True)
- parser.add_argument("-p","--cutsheetsdotpy", help="Full path to cutsheets.py. By default is ~/NetengISRepo/scripts/cutsheet.py ",required=False)
- parser.add_argument("-v","--verbose", help="Enable verbose output",action="store_true",default=False)
- parser.add_argument("-l","--lock", help="Lock the CM after VAR, Config and diffs has been created",action="store_true",default=False)
- parser.add_argument("-g","--skip-gb-update", help="If GB has been updated manually, skip this step during CM creation.",action="store_true",default=False)
- parser.add_argument("-d","--snow-forted-region", help="Adds the no-cred extra attr to gen.sh the config. Type password manually for diff creation.",action="store_true",default=False)
- parser.add_argument("-x","--dx-peer", help="Enables this script to AddLinksToLag on border side only towards VC-CAR.",action="store_true",default=False)
- args = parser.parse_args()
- # Display function.
- def say(msg, level=1,f_verbose = 1):
- if verbose:
- f_verbose = 2
- if (level <= f_verbose):
- print msg
- # Getting username
- def get_username():
- user = getpass.getuser()
- return user
- def get_password():
- password = getpass.getpass()
- return password
- def load_csv(cfile):
- lines = []
- cparts = []
- skipped = 0
- columns = ['a_hostname', 'a_lag', 'a_interface', 'z_hostname', 'z_lag', 'z_interface','action']
- say("\033[93mLoading cutsheet from %s.\033[0m" % (cfile),2)
- try:
- CSHEET = open(cfile, "rb")
- try:
- headers = reader(CSHEET).next()
- rdr = DictReader(CSHEET, headers)
- for col in columns:
- if (not col in rdr.fieldnames):
- CSHEET.close()
- say("Could not locate field %s in cutsheet.\033[0m" % (col))
- sys.exit()
- for row in rdr:
- parts = [ row['a_hostname'], row['a_lag'], row['a_interface'], row['z_interface'], row['z_lag'], row['z_hostname'], row['action'] ]
- parts = [p.strip() for p in parts]
- if ("" in parts):
- say("\033[93mSkipping line: %s\033[0m" % (",".join(parts)),2)
- skipped += 1
- continue
- lines.append(parts)
- finally:
- CSHEET.close()
- except IOError, e:
- say("Cannot open %s.\n%s\033[0m" % (cfile, e))
- say("\033[93mCutsheet loaded: %d rows - %d rows skipped\033[0m" % (len(lines), skipped),2)
- return lines
- # Getting a uniq list of routers based on cutsheets
- def router_list_uniq_function(rows):
- router_list_uniq = []
- for row in rows:
- if row[0] not in router_list_uniq and re.search("-(br|en)-",row[0]):
- router_list_uniq.append(row[0])
- if row[5] not in router_list_uniq and re.search("-(br|en)-",row[5]):
- router_list_uniq.append(row[5])
- return sorted(router_list_uniq)
- # Getting a Router:Lag dict from cutsheet file
- def router_lag_dict_list_function(rows):
- router_lag_dict_list = []
- for row in rows:
- router_lag_l_dict = {}
- router_lag_r_dict = {}
- r=row[0]
- l=row[1]
- rr=row[5]
- rl=row[4]
- router_lag_l_dict[r]=l
- router_lag_r_dict[rr]=rl
- if router_lag_l_dict not in router_lag_dict_list and re.search("-(br|en)-", router_lag_l_dict.keys()[0]):
- router_lag_dict_list.append(router_lag_l_dict)
- if router_lag_r_dict not in router_lag_dict_list and re.search("-(br|en)-", router_lag_r_dict.keys()[0]):
- router_lag_dict_list.append(router_lag_r_dict)
- return sorted(router_lag_dict_list)
- # Merge created branch with mailine and push changes
- def merge_and_push(repo,push=False):
- try:
- msj = "Cannot merge CM branch with mainline on {0} repo.".format(repo)
- os.chdir("/home/{0}/{1}/".format(alias,repo))
- say("\033[93mMerging branches\033[0m",2)
- subprocess.check_call(['git','checkout','mainline'])
- subprocess.check_call(['git','pull','--rebase'])
- msj = "Changes has been merged with mainline on {0}".format(repo)
- subprocess.check_call(['git','merge','{0}_{1}'.format(alias,args.mcm)])
- if push:
- msj = "Changes has been pushed on {0}".format(repo)
- subprocess.check_call(['git','push'])
- #print "\033[92mGIT PUSH\033[0m"
- say("\033[92m[PASS]\033[0m {0}".format(msj),2)
- except:
- say("\033[91m[FAIL]\033[0m {0}".format(msj))
- sys.exit()
- #Create and delete branches on any repo where is needed
- def git_branch(repo,action="none",msj="none"):
- try:
- os.chdir("/home/{0}/{1}/".format(alias,repo))
- say("\033[93mDeleting branch {0}_{1} if exist!\033[0m".format(alias,args.mcm),2)
- subprocess.check_call(['git','checkout','mainline'])
- subprocess.check_call(['git','branch','-D','{0}_{1}'.format(alias,args.mcm)])
- except:
- say("\033[93mSkipping step since branch {0}_{1} was not found.\033[0m".format(alias,args.mcm),2)
- if action == "set":
- try:
- subprocess.check_call(['git','pull','--rebase'])
- subprocess.check_call(['git','checkout','-b','{0}_{1}'.format(alias,args.mcm)])
- subprocess.check_call(['git','branch'])
- say("\033[93mNew branch {0}_{1} has been created in {2}\033[0m".format(alias,args.mcm,repo),2)
- except:
- msj = "Cannot create branch in {0}".format(repo)
- say("\033[91m[FAIL]\033[0m {0}".format(msj))
- sys.exit()
- #Check if a directory exist and delete it
- def file_exist(path):
- if os.path.exists(path):
- shutil.rmtree(path)
- #Check if a directory exist and trigger an error if it doesnt
- def check_file_exist(file_path):
- try:
- with open(file_path) as f:
- f.read()
- except:
- say("\033[91m[FAIL]\033[0m This file doesn't exist --> {0}".format(file_path))
- sys.exit()
- # Validate path to cutshets.py
- def check_cutsheetsdotpy_path(cdotpy_path=None):
- if cdotpy_path:
- try:
- check_file_exist(cdotpy_path)
- return cdotpy_path
- except:
- say("\033[91m[FAIL]\033[0m Seems like {0} doesn't exist.Please check the path to cutsheet.py".format(cdotpy_path))
- else:
- try:
- cdotpy_path = "/home/{0}/NetengISRepo/scripts/cutsheet.py".format(alias)
- check_file_exist(cdotpy_path)
- return cdotpy_path
- except:
- say("\033[91m[FAIL]\033[0m Seems like {0} doesn't exist.Please check the path to cutsheet.py".format(cdotpy_path))
- # Find config in the out folder when ALTL to a vc-car
- def get_out_cfg_file(text_to_find,br_router):
- gb_out_path = "/home/{0}/GenevaBuilder/out/{1}/dxpeer_substreams/".format(get_username(),br_router)
- try:
- for attr in os.listdir(gb_out_path):
- with open('{0}/{1}'.format(gb_out_path,attr), 'r') as file :
- attrdata = file.read()
- if text_to_find in attrdata:
- out_cfg_file = '{0}/{1}'.format(gb_out_path,attr)
- return out_cfg_file
- except:
- sys.exit("Fail while attempting to find config in GB out folder!")
- #1.- Checking it there is any unstaged change on GB or NetengIS_CM2015 repo
- def check_for_unstaged_changes():
- try:
- cmpath = os.path.isdir("/home/{0}/{1}/cm/{0}".format(alias,"NetengIS_CM2015"))
- gbpath = os.path.isdir("/home/{0}/{1}".format(alias,"GenevaBuilder"))
- if cmpath == False:
- errmsg = "Your alias folder doesn't exist as /home/{0}/{1}/cm/{0}".format(alias,"NetengIS_CM2015")
- sys.exit()
- elif gbpath == False:
- errmsg = "GenevaBuilder repo does't not exist as /home/{0}/{1}".format(alias,"GenevaBuilder")
- sys.exit()
- errmsg = "You have unstaged changes. Please clear out your {0} repo.".format("NetengIS_CM2015")
- os.chdir("/home/{0}/{1}/".format(alias,"NetengIS_CM2015"))
- subprocess.check_call(['git','checkout','mainline'])
- subprocess.check_call(['git','pull','--rebase'])
- errmsg = "You have unstaged changes. Please clear out your {0} repo.".format("GenevaBuilder")
- os.chdir("/home/{0}/{1}/".format(alias,"GenevaBuilder"))
- subprocess.check_call(['git','checkout','mainline'])
- subprocess.check_call(['git','pull','--rebase'])
- say("\033[92m[PASS]\033[0m..",2)
- except:
- say("\033[91m[FAIL]\033[0m {0}".format(errmsg))
- sys.exit()
- #2.- Udating GB
- def generate_lag_attr(cutsheet,pwd,skip_gb=False):
- if skip_gb:
- say("\033[92m[PASS]\033[0m Skipping this step since '--skip-gb-update' flag was included.")
- else:
- try:
- #fail_msj = "Cannot create a branch of GenevaBuilder repo"
- #os.chdir("/home/{}/{}/".format(alias,"GenevaBuilder"))
- #git_branch("GenevaBuilder","set",fail_msj)
- os.chdir(pwd)
- subprocess.check_call(['/home/{0}/NetengISRepo/people/chezlo/arepa.py'.format(alias),'-c','{0}'.format(cutsheet)])
- os.chdir("/home/{0}/GenevaBuilder/".format(alias))
- #subprocess.check_call(['git','add','-A'])
- commit_msg="\"Updating GB for {0}\"".format(args.mcm)
- #say("\033[96mCommiting changes\033[0m",2)
- #subprocess.check_call(['git','commit','-a','-m',commit_msg])
- #merge_and_push("GenevaBuilder")
- #git_branch("GenevaBuilder")
- say("\033[92m[PASS]\033[0m..",2)
- except:
- say("\033[91m[FAIL]\033[0m Something went wrong while updating GB ATTR! Check above log!")
- git_branch("GenevaBuilder")
- sys.exit()
- #3.- Generating config files
- def config_gen_gb(device_list,snow_forted_region=False):
- try:
- say("\033[96mGenerating configuration for:\033[0m")
- for i in range(0,len(device_list)):
- file_exist("/home/{0}/GenevaBuilder/out/{1}".format(alias,device_list[i]))
- say("\033[96m - {0}\033[0m".format(device_list[i]))
- os.chdir("/home/{0}/GenevaBuilder/".format(alias))
- if snow_forted_region:
- os.system("\n./gen.sh {0} --max-workers 16 --load-only {1}.* --extra-attrs extra-attrs/nocreds.attr".format(" ".join(device_list),device_list[0][:3]))
- else:
- os.system("\n./gen.sh {0} --max-workers 16 --load-only {1}.*".format(" ".join(device_list),device_list[0][:3]))
- for i in range(0,len(device_list)):
- check_file_exist("/home/{0}/GenevaBuilder/out/{1}/lagmembers".format(alias,device_list[i]))
- except:
- say("\033[91m[FAIL]\033[0m Couldn't generate config files for {0}".format(" ".join(device_list)))
- sys.exit()
- #4.- Creating VAR file on CM folder. Your CM directory will be created on this step.
- def create_varfile(cutsheet_path,cdotpy_path,pwd,fail_msj="none"):
- source_file="/home/{0}/NetengIS_CM2015/cm/{0}/{1}/{1}".format(alias,args.mcm)
- dest_file="/home/{0}/NetengIS_CM2015/cm/{0}/{1}/{1}.var".format(alias,args.mcm)
- rm_file="/home/{0}/NetengIS_CM2015/cm/{0}/{1}/{1}.ds".format(alias,args.mcm)
- try:
- fail_msj = "Cannot create CM folder in ~/NetengIS_CM2015/cm/{0}/{1}".format(alias,args.mcm)
- git_branch("NetengIS_CM2015","set",fail_msj)
- file_exist("/home/{0}/NetengIS_CM2015/cm/{0}/{1}".format(alias,args.mcm))
- say("\033[93mCreating new {0} folder on \"NetengIS_CM2015\" repository.....\033[0m".format(args.mcm),2)
- os.makedirs("/home/{0}/NetengIS_CM2015/cm/{0}/{1}".format(alias,args.mcm))
- fail_msj = "Something when wrong while creating your VAR file. Please check above log!!"
- os.chdir(pwd)
- os.system("{0} -c --cutsheet={1} --out=~/NetengIS_CM2015/cm/{2}/{3} --cm={3}".format(cdotpy_path,cutsheet_path,alias,args.mcm))
- #TODO subprocess.check_call(['{}'.format(args.cutsheetsdotpy),'-c','--cutsheet','{}'format(cutsheets),'--out','~/NetengIS_CM2015/cm/{}/{}'.format(alias,args.mcm),'--cm','{}'.format(args.mcm)])
- os.rename(source_file,dest_file)
- os.remove(rm_file)
- say("\033[92m[PASS]\033[0m Your VAR file has been generating and compiled successfully..",2)
- except:
- say("\033[91m[FAIL]\033[0m {0}".format(fail_msj))
- git_branch("NetengIS_CM2015")
- sys.exit()
- #5.- Copying config files from GB out folder to the CM directory.
- def copy_push_files(router_lag_dict_list,dxpeer=False):
- for i in router_lag_dict_list:
- try:
- rou=i.keys()[0]
- ae=i.values()[0]
- if dxpeer:
- source_file=get_out_cfg_file(ae,rou)
- else:
- source_file="/home/{0}/GenevaBuilder/out/{1}/lagmembers_substreams/{2}".format(alias,rou,ae)
- dest_file="/home/{0}/NetengIS_CM2015/cm/{1}/{2}/{3}_{4}.push".format(alias,alias,args.mcm,rou,ae)
- say("\033[93mCopying config files from GB out folder to the CM directory!!\033[0m",2)
- check_file_exist(source_file)
- shutil.copyfile(source_file,dest_file)
- say("Copying \"{0}\" to \"{1}\"".format(source_file,dest_file),2)
- except:
- say("\033[91m[FAIL]\033[0m Cannot copy {0} to {1}".format(source_file,dest_file))
- sys.exit()
- say("\033[92m[PASS]\033[0m..",2)
- #6.- Generating Diffs
- def create_diff(router_lag_dict_list,password,snow_forted_region=False):
- for i in router_lag_dict_list:
- try:
- rou=i.keys()[0]
- ae=i.values()[0]
- os.chdir("/home/{0}/NetengIS_CM2015/cm/{0}/{1}".format(alias,args.mcm))
- if snow_forted_region == True:
- subprocess.check_call(['jdop','-l','{0}'.format(alias),'-p','{0}'.format(password),'-d','{0}_{1}.diff'.format(rou,ae),'diff','{0}'.format(rou),'{0}_{1}.push'.format(rou,ae)])
- else:
- credentials = "com.amazon.networking.managed.prod.tacacs-user.neteng-auto-rw"
- subprocess.check_call(['jdop','-x',credentials,'-d','{0}_{1}.diff'.format(rou,ae),'diff','{0}'.format(rou),'{0}_{1}.push'.format(rou,ae)])
- check_file_exist("{0}_{1}.diff".format(rou,ae))
- say("\033[93m{0}_{1}.diff has been created successfully\n\033[0m".format(rou,ae),2)
- except:
- say("\033[91m[FAIL]\033[0m This diff was not created => {0}_{1}.diff".format(rou,ae))
- sys.exit()
- say("\033[92m[PASS]\033[0m..",2)
- #7.- Commiting changes to NetengIS_CM2015 repo.
- def commit_changes_CM_repo(commit_msg="\"adding VAR, PUSH and DIFFs for {0}\"".format(args.mcm)):
- try:
- say("\033[93mGit adding changes to commit!!\033[0m",2)
- os.chdir("/home/{0}/NetengIS_CM2015/".format(alias))
- subprocess.check_call(['git','add','-A'])
- say("\033[93mCommiting changes\033[0m",2)
- subprocess.check_call(['git','commit','-a','-m',commit_msg])
- #git_branch("NetengIS_CM2015")
- say("\033[92m[PASS]\033[0m..",2)
- except:
- say("\033[91m[FAIL]\033[0m Couldn't commit the changes. Check above log")
- sys.exit()
- #8.- Updating commit id, merge braches and lock the CM
- def update_cid_lockcm(lock_cm):
- try:
- error_msg = "Cannot update commit ID for {0}".format(args.mcm)
- os.chdir("/home/{0}/NetengIS_CM2015/".format(alias))
- output = commands.getoutput("git rev-parse HEAD")
- updated_wdir = "set_working_dir(\"brazil://NetengIS_CM2015/cm/{0}/{1}\",\"{2}\")".format(alias,args.mcm,output)
- sed_path = "/home/{1}/NetengIS_CM2015/cm/{1}/{0}/{0}.var".format(args.mcm,alias)
- sed_find = '/set_working_dir/c\{0}'.format(updated_wdir)
- subprocess.check_call(['sed','-i',sed_find,sed_path])
- commit_changes_CM_repo("\"Updating Commit ID for {0}\"".format(args.mcm))
- say("\033[93mCommit ID on {0}.var has been updated with: {1}\033[0m".format(args.mcm,output),2)
- error_msg = "Cannot lock MCM {0}. Check above log".format(args.mcm)
- merge_and_push("NetengIS_CM2015",True)
- if lock_cm:
- subprocess.check_call(['/apollo/env/Daryl/bin/darylscriptc','--lock','--cm','{0}'.format(args.mcm)])
- say("\033[92m[PASS]\033[0m CM has been locked.. https://mcm.amazon.com/{0}\n".format(args.mcm))
- else:
- say("\033[92m[PASS]\033[0m Skipping lock step since '--lock' flag was not included.")
- except:
- say("\033[91m[FAIL]\033[0m {0}".format(error_msg))
- sys.exit()
- def main():
- global verbose,alias
- verbose = args.verbose
- alias = get_username()
- lock_cm = args.lock
- skip_gb = args.skip_gb_update
- snow_forted_region = args.snow_forted_region
- dxpeer = args.dx_peer
- if snow_forted_region:
- password = get_password()
- else:
- password = "None"
- pwd = os.getcwd()
- cutsheets = load_csv(args.cutsheet)
- device_list = router_list_uniq_function(cutsheets)
- router_lag_dict_list = router_lag_dict_list_function(cutsheets)
- cdotpy_path = check_cutsheetsdotpy_path(args.cutsheetsdotpy)
- say("\033[96m[STEP 1 of 8]\033[0m Checking for unstaged changes on CM & GB repo..")
- check_for_unstaged_changes()
- say("\033[96m[STEP 2 of 8]\033[0m Updating GenevaBuilder.")
- generate_lag_attr(args.cutsheet,pwd,skip_gb)
- say("\033[96m[STEP 3 of 8]\033[0m Generating config on GB out folder.")
- config_gen_gb(device_list,snow_forted_region)
- say("\033[96m[STEP 4 of 8]\033[0m Creating variable file")
- create_varfile(args.cutsheet,cdotpy_path,pwd)
- say("\033[96m[STEP 5 of 8]\033[0m Creating PUSH files on the CM folder")
- copy_push_files(router_lag_dict_list,dxpeer)
- say("\033[96m[STEP 6 of 8]\033[0m Generating DIFFs")
- create_diff(router_lag_dict_list,password,snow_forted_region)
- say("\033[96m[STEP 7 of 8]\033[0m Commiting all changes")
- commit_changes_CM_repo()
- say("\033[96m[STEP 8 of 8]\033[0m Updating commit ID and locking the CM")
- update_cid_lockcm(lock_cm)
- say("\033[96m[ALL STEPS EXECUTED] Don't forget to push GB changes.\033[0m")
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement