| #!/usr/bin/python |
| """ |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| """ |
| # XXXstroucki: why not use something like supervise instead? |
| |
| import os |
| import sys |
| import getopt |
| import subprocess |
| import time |
| |
| SLEEP_INTERVAL=10 |
| TASHI_PATH="/usr/local/tashi/" |
| LOG_FILE="/var/log/nodemanager.log" |
| |
| """ |
| /* This function changes (on Linux!) its oom scoring, to make it |
| * unattractive to kill |
| */ |
| """ |
| def make_invincible(): |
| # dependent on linux |
| try: |
| oom_adj_fd = os.open("/proc/self/oom_adj", os.O_WRONLY) |
| except IOError: |
| pass |
| else: |
| os.write(oom_adj_fd, "-17\n") |
| os.close(oom_adj_fd) |
| |
| """ |
| /* This function resets (on Linux!) its oom scoring to default |
| */ |
| """ |
| def make_vulnerable(): |
| # dependent on linux |
| try: |
| oom_adj_fd = os.open("/proc/self/oom_adj", os.O_WRONLY) |
| except IOError: |
| pass |
| else: |
| os.write(oom_adj_fd, "0\n") |
| os.close(oom_adj_fd) |
| |
| def main(argv=None): |
| if argv is None: |
| argv = sys.argv |
| try: |
| opts, args = getopt.getopt(argv[1:], "f", ["foreground"]) |
| except getopt.GetoptError, err: |
| # print help information and exit: |
| print str(err) # will print something like "option -a not recognized" |
| # usage() |
| return 2 |
| foreground = False |
| for o, a in opts: |
| if o in ("-f", "--foreground"): |
| foreground = True |
| else: |
| assert False, "unhandled option" |
| if foreground == False: |
| pid = os.fork(); |
| if pid != 0: |
| os._exit(0) |
| os.close(0) |
| os.close(1) |
| os.close(2) |
| |
| # adjust oom preference |
| make_invincible() |
| |
| # configure environment of children |
| env = {"PYTHONPATH":TASHI_PATH+"/src"} |
| while True: |
| pid = os.fork(); |
| if pid == 0: |
| # child |
| # nodemanagers are vulnerable, not the supervisor |
| make_vulnerable() |
| if foreground == False: |
| try: |
| lfd = os.open(LOG_FILE, os.O_APPEND|os.O_CREAT|os.O_WRONLY) |
| except IOError: |
| lfd = os.open("/dev/null", os.O_WRONLY) |
| # make this fd stdout and stderr |
| os.dup2(lfd, 1) |
| os.dup2(lfd, 2) |
| # close stdin |
| os.close(0) |
| os.chdir(TASHI_PATH) |
| os.execle("./bin/nodemanager.py", "./bin/nodemanager.py", env) |
| os._exit(-1) |
| # sleep before checking child status |
| time.sleep(SLEEP_INTERVAL) |
| os.waitpid(pid, 0) |
| return 0 |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |