Наше приложение использует два файла для подключения к серверам баз данных:
$ ls -l ../secure total 8 -rw-r----- 1 app_env_1 app 1306 Nov 27 16:12 external.properties -rw------- 1 app_env_1 app 12 Nov 27 15:51 secret.key
Задача – написать скрипт, с помощью которого их можно редактировать, не прибегая к использованию редакторов (т.к. у товарищей из Индии это вызывает… трудности…).
UPD Это была первая версия, вторая – тут: Python: модуль ConfigParser для работы с файлами конфигураций, и скрипт редактирования файлов
У нас нет возможности установки дополнительных модулей типа pysed
и argparse
, поэтому – использовался обычный sed
и if/elif
для проверки аргументов.
В результате – получился такой скрипт:
#!/usr/bin/env python import os import sys import subprocess import getpass import shutil import time _USAGE = ('nUsage: %s <--property> [env] OR <--secret>nnExample:nn%s --property main rpln' % (__file__,__file__)) if len(sys.argv) < 2: print(_USAGE) sys.exit(3) DBS = ['main', 'rpl', 'lima', 'rf', 'tcp', 'gpc'] try: SEC = os.environ['APP_SECURE_LOCATION_PWD'] PROP = os.environ['APP_EXT_PROP'] except KeyError as e: print('ERROR: %s' % e) sys.exit(2) def backup(file): ''''Create backup copy for given in argument file, with name including timestamp.''' try: bak = (file + time.strftime('_%Y-%m-%d-%H_%M_bak')) print('nCreating backup copy of %s to %s...' % (file, bak)) shutil.copyfile(file, bak) print('Done.') except IOError as e: print('ERROR: %s' % e) sys.exit(1) def answer(prompt, choice='Yes or no, please!'): '''Return OK, if input Ok, and False if input No. Thus - used in other functions, can run or pass next actios.''' while True: result = raw_input(prompt) if result in ('y', 'Y', 'yes', 'Yes'): return(True) elif result in ('n', 'N', 'no', 'No'): return(False) else: print(choice) def new_secret(file): '''Creates backup of <SEC> config; clears file; accepts new keyword twice and check if it is identical; finally - writes new line to config.''' backup(file) try: with open(SEC, 'w+') as sec: newsecret1 = getpass.getpass('nPlease, enter new secret keyword: ') newsecret2 = getpass.getpass('Repeat: ') if newsecret1 == newsecret2: print('nWriting new keyword...') sec.write(newsecret1) print('Done.nnPlease, note: you need to regenerate all passwords inside %s config.n' % PROP) else: print('New keyword must be entered.n') except KeyboardInterrupt: print('nnExit.n') sys.exit(0) def edit_entry(oldline, file): '''Edit <PROP> file, replacing old line with new raw_input() line. Uses OS 'sed' utility.''' if answer('Edit? [y/n] '): newline = raw_input('Please,set new value: ') if answer('nNew value is: %snIs it correct? [y/n] ' % newline): subprocess.call(("sed -i -e 's/%s/%s/g' %s" % (oldline.rstrip('n'), newline.rstrip('n'), file)), shell=True) print('New value witen to file.') def change_property(file, **argv): '''Can accept few databases names. If none given - uses <DBS> kist with all databases. For each database - selects it's HOST (url iside file), USER and it's Password. Offers edit each entry with edit_entry() function.''' list = sys.argv[2:] if len(list) < 2: list = DBS backup(file) try: for host in list: print('nDatabase: %s' % host) with open(PROP, 'r') as prop: for line in prop.readlines(): if host in line: if 'url' in line: print('nHOST: %s' % line.rstrip('n')) edit_entry(line, PROP) elif 'user' in line: print('nUsername: %s' % line.rstrip('n')) edit_entry(line, PROP) elif 'password' in line: print('nPassword: %s' % line.rstrip('n')) edit_entry(line, PROP) except KeyboardInterrupt: print('nnExit.n') sys.exit(0) if sys.argv[1] == '--property': change_property(PROP) elif sys.argv[1] == '--secret': new_secret(SEC) elif sys.argv[1] == '*': print(_USAGE)
При запуске – скрипт создаёт резервную копию:
$ ls -l ../secure total 12 -rw-r----- 1 app_env_1 app 1306 Nov 27 16:12 external.properties -rw-r----- 1 app_env_1 app 1306 Nov 29 12:44 external.properties_2014-11-29-12_44_bak -rw------- 1 app_env_1 app 12 Nov 27 15:51 secret.key
Как видно из скрипта – можно выбрать, подключение к какой базе или базам редактировать.
Например – для main и rpl:
$ ./app_secure.py --property main rpl Creating backup copy of /home/app_env_1/secure/external.properties to /home/app_env_1/secure/external.properties_2014-11-29-12_44_bak... Done. Database: main HOST: jdbc.main.url=jdbc:oracle:thin:@domain.com:1845:SID1 Edit? [y/n] n Username: jdbc.main.username=OLD_USER Edit? [y/n] n Password: jdbc.main.password=ENC(iFU//78v***Onk) Edit? [y/n] n
И сам процесс редактирования:
$ ./app_secure.py --property main Creating backup copy of /home/app_env_1/secure/external.properties to /home/app_env_1/secure/external.properties_2014-11-29-12_45_bak... Done. Database: main HOST: jdbc.main.url=jdbc:oracle:thin:@domain.com:1845:SID1 Edit? [y/n] n Username: jdbc.main.username=OLD_USER Edit? [y/n] y Please,set new value: jdbc.main.username=NEW_USER_NAME New value is: jdbc.main.username=NEW_USER_NAME Is it correct? [y/n] y New value witen to file.