1. 問題
在自動化應用的時候 ,有時候環境變量與運行需要不一致。這時候有兩種選擇:
- 改變節點環境變量,使得其和運行需求保持一致;
- 在自動化腳本中設置環境變量,其范圍只在腳本運行環境中有效。
顯然,當需要運行多個自動化腳本,每個的需求不一致的時候,選擇2是更好的設計。
2. 解決方案和案例
假設我們有兩個java的運行版本,一個是本節點上的java,版本7;另一個是雲盤上共享的版本8。我們需要運行elasticsearch 6.2.3,它需要java8。而我們不希望更新節點上的java:
- java 8路徑:/shared/java8/bin
- elasticsearch 6.2.3路徑:/opt/elasticsearch6.2.3/bin
- elasticsearch用戶:elasticsearch
import subprocess, re, os, socket, resource, pwd, crypt, logging, sys, platform def demote(user_uid, user_gid): def result(): os.setgid(user_gid) os.setuid(user_uid) return result class setuputil: @staticmethod def run_command(args, username=None, usercwd=None): try: if username: pw_record = pwd.getpwnam(username) env = os.environ.copy() env['HOME'] = pw_record.pw_dir env['LOGNAME'] = username env['USER'] = username if usercwd: env['PWD'] = usercwd p = subprocess.Popen(args, preexec_fn=demote(pw_record.pw_uid, pw_record.pw_gid), cwd=usercwd, env=env, close_fds=True) else: p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds = True) outputs = p.communicate() for out in outputs: if out: return (p.returncode, out) except OSError as os_e: return (os_e.errno, os_e.strerror) except ValueError as val_e: return (val_e.errno, val_e.strerror) else: return (p.returncode, outputs) @staticmethod def java_version(): java_ver_pattern = '\"(\d+\.\d+).*\"' java_cmd = "java" if 'JAVA_HOME' in os.environ: java_cmd = os.environ['JAVA_HOME'] + "/bin/java" version = subprocess.check_output([java_cmd, '-version'], stderr=subprocess.STDOUT) if version: return re.search(java_ver_pattern, version).groups()[0] else: return None @staticmethod def start_app(es_exec, pid_file, es_user): rtcode, msg = setuputil.run_command([es_exec, '-d', '-p', pid_file], es_user) if rtcode: return (rtcode, msg) else: return (0, "OK") MIN_JAVA_VERSION = 1.8 ELASTIC_USER = 'elastic' ELASTIC_PASSWORD = 'elastic' ELASTIC_PID = '/tmp/elasticpid' def main(): # set up java home os.environ['JAVA_HOME'] = '/shared/java8' j_ver = setuputil.java_version() if not j_ver or float(j_ver) < MIN_JAVA_VERSION: logging.error("Java isn't installed or java version is not up to date: %s", j_ver if j_ver else "None") return (1, "Java isn't installed or java version is not up to date: %s"%(j_ver if j_ver else "None")) rtcode, msg = setuputil.start_app('/opt/elasticsearch6.2.3/bin/elasticsearch', ELASTIC_PID, ELASTIC_USER) if rtcode: logging.error("Failed to start elasticsearch: %d, %s", rtcode, msg) return (rtcode, msg) else: logging.debug("Start elasticsearch: %s", msg) return (0, None) if __name__ == '__main__': main()
3. 注意的問題
有幾個需要注意的問題:
- 環境變量的適用范圍(scope)
- 一般只在運行的當前shell有效
- 就上例而言,JAVA_HOME只在運行腳本的進程里是有效
- 在哪里設置環境變量?
- 需要在運行命令之前設置
- 就上例而言,JAVA_HOME需要在運行java版本檢查,和運行elasticsearch之前設置