blob: b27d7d1886996068e62df55a9ac7b215bf38c6a1 [file] [log] [blame]
#!/usr/bin/env 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.
'''
from PythonExecutor import PythonExecutor
from resource_management.core.exceptions import ClientComponentHasNoStatus, ComponentIsNotRunning
import imp
import sys
import os
import pprint
import logging
import copy
logger = logging.getLogger()
class PythonReflectiveExecutor(PythonExecutor):
"""
Some commands like STATUS, SECURITY_STATUS commands are run a lot, and need to be run really fast.
Otherwise agent will hang waiting for them to complete every X seconds.
Running the commands not in new proccess, but reflectively makes this really fast.
"""
def __init__(self, tmpDir, config):
super(PythonReflectiveExecutor, self).__init__(tmpDir, config)
def run_file(self, script, script_params, tmpoutfile, tmperrfile,
timeout, tmpstructedoutfile, callback, task_id,
override_output_files = True, backup_log_files = True,
handle = None, log_info_on_failure=True):
pythonCommand = self.python_command(script, script_params)
logger.debug("Running command reflectively " + pprint.pformat(pythonCommand))
script_dir = os.path.dirname(script)
self.open_subprocess_files(tmpoutfile, tmperrfile, override_output_files, backup_log_files)
returncode = 1
try:
current_context = PythonContext(script_dir, pythonCommand)
PythonReflectiveExecutor.last_context = current_context
with current_context:
imp.load_source('__main__', script)
except SystemExit as e:
returncode = e.code
if returncode:
logger.debug("Reflective command failed with return_code=" + str(e))
except (ClientComponentHasNoStatus, ComponentIsNotRunning):
logger.debug("Reflective command failed with exception:", exc_info=1)
except Exception:
logger.info("Reflective command failed with exception:", exc_info=1)
else:
returncode = 0
return self.prepare_process_result(returncode, tmpoutfile, tmperrfile, tmpstructedoutfile, timeout=timeout)
class PythonContext:
"""
Sets and resets some context like imports, pythonpath, args.
Also it disable logging into ambari-agent.log for reflectively called scripts.
"""
def __init__(self, script_dir, pythonCommand):
self.script_dir = script_dir
self.pythonCommand = pythonCommand
self.is_reverted = False
self.is_forced_revert = False
def __enter__(self):
self.old_sys_path = copy.copy(sys.path)
self.old_agv = copy.copy(sys.argv)
self.old_sys_modules = copy.copy(sys.modules)
self.old_logging_disable = logging.root.manager.disable
logging.disable(logging.ERROR)
sys.path.insert(0, self.script_dir)
sys.argv = self.pythonCommand[1:]
def __exit__(self, exc_type, exc_val, exc_tb):
self.revert(is_forced_revert=False)
return False
def revert(self, is_forced_revert=True):
if not self.is_reverted:
self.is_forced_revert = is_forced_revert
self.is_reverted = True
sys.path = self.old_sys_path
sys.argv = self.old_agv
logging.disable(self.old_logging_disable)
self.revert_sys_modules(self.old_sys_modules)
def revert_sys_modules(self, value):
sys.modules.update(value)
for k in copy.copy(sys.modules):
if not k in value:
del sys.modules[k]