You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
5.8 KiB
181 lines
5.8 KiB
# Copyright (C) 2015-2019 Splunk Inc. All Rights Reserved.
|
|
|
|
# To be used in accordance with the README file in Python for Scientific
|
|
# Computing (PSC). That is, exec_anaconda.py is available to be copied and
|
|
# placed into your applications as needed to allow for the execution of Splunk
|
|
# Custom Search Commands and cross-platform module imports. See the PSC README
|
|
# file for more details.
|
|
import json
|
|
import os
|
|
import platform
|
|
import stat
|
|
import subprocess
|
|
import time
|
|
import traceback
|
|
|
|
from util.base_util import (
|
|
get_apps_path,
|
|
get_mltk_pycache_path,
|
|
get_system_paths,
|
|
SUPPORTED_SYSTEMS,
|
|
PSC_PATH_PREFIX,
|
|
)
|
|
|
|
# NOTE: This file must be Python 2 and 3 compatible until
|
|
# Splunk Enterprise drops support for Python2.
|
|
|
|
# Prefix of the directory name where PSC is installed
|
|
MLTK_APP_NAME = 'Splunk_ML_Toolkit'
|
|
|
|
|
|
import sys
|
|
|
|
|
|
def check_python_version():
|
|
if sys.version_info[0] < 3:
|
|
raise Exception(
|
|
'This version of MLTK must be run under Python3. Please consult MLTK documentation for more information'
|
|
)
|
|
return True
|
|
|
|
|
|
def check_python_minor_version():
|
|
return sys.version_info[1] >= 8
|
|
|
|
|
|
# MLA-4296: setting pycache path to app's local directory, only works for py3.8 and above
|
|
if check_python_version() and check_python_minor_version():
|
|
sys.pycache_prefix = get_mltk_pycache_path(app_name=MLTK_APP_NAME)
|
|
|
|
|
|
def exec_anaconda():
|
|
"""Re-execute the current Python script using the Anaconda Python
|
|
interpreter included with Splunk_SA_Scientific_Python.
|
|
|
|
After executing this function, you can safely import the Python
|
|
libraries included in Splunk_SA_Scientific_Python (e.g. numpy).
|
|
|
|
Canonical usage is to put the following at the *top* of your
|
|
Python script (before any other imports):
|
|
|
|
import exec_anaconda
|
|
exec_anaconda.exec_anaconda()
|
|
|
|
# Your other imports should now work.
|
|
import numpy as np
|
|
import pandas as pd
|
|
...
|
|
"""
|
|
if PSC_PATH_PREFIX in sys.executable:
|
|
from imp import reload
|
|
|
|
fix_sys_path()
|
|
|
|
reload(json)
|
|
reload(os)
|
|
reload(platform)
|
|
reload(stat)
|
|
reload(subprocess)
|
|
reload(sys)
|
|
return
|
|
|
|
check_python_version()
|
|
|
|
sa_path, system = get_system_paths()
|
|
|
|
system_path = os.path.join(sa_path, 'bin', '%s' % (SUPPORTED_SYSTEMS[system]))
|
|
|
|
if system[0] == 'Windows':
|
|
python_path = os.path.join(system_path, 'python.exe')
|
|
# MLA-564: Windows need the DLLs to be in the PATH
|
|
dllpath = os.path.join(system_path, 'Library', 'bin')
|
|
pathsep = os.pathsep if 'PATH' in os.environ else ''
|
|
os.environ['PATH'] = os.environ.get('PATH', '') + pathsep + dllpath
|
|
else:
|
|
python_path = os.path.join(system_path, 'bin', 'python')
|
|
|
|
# MLA-996: Unset PYTHONHOME
|
|
# XXX: After migration to Python3 PYTHONPATH is not set anymore so this will
|
|
# be unnecessary. SPL-170875
|
|
os.environ.pop('PYTHONHOME', None)
|
|
|
|
# Ensure that execute bit is set on <system_path>/bin/python
|
|
if system[0] != 'Windows':
|
|
mode = os.stat(python_path).st_mode
|
|
os.chmod(python_path, mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
|
|
sys.stderr.flush()
|
|
|
|
# In Quake and later PYTHONPATH is removed or not set.
|
|
# So after shelling into PSC Python interpreter will lose
|
|
# information about what Splunk core's Python path is. So we
|
|
# stash it into an environment variable to retrieve it after
|
|
# switching into conda.
|
|
os.environ['SPLUNK_CORE_PYTHONPATH'] = json.dumps(sys.path)
|
|
|
|
try:
|
|
os.environ['MKL_NUM_THREADS'] = '4'
|
|
if system[0] == "Windows":
|
|
# os.exec* broken on Windows: http://bugs.python.org/issue19066
|
|
subprocess.check_call([python_path] + sys.argv)
|
|
os._exit(0)
|
|
else:
|
|
os.environ['VECLIB_MAXIMUM_THREADS'] = '1'
|
|
os.environ['OPENBLAS_NUM_THREADS'] = '4'
|
|
os.execl(python_path, python_path, *sys.argv)
|
|
except Exception:
|
|
traceback.print_exc(None, sys.stderr)
|
|
sys.stderr.flush()
|
|
time.sleep(0.1)
|
|
raise RuntimeError(
|
|
'Error encountered while loading Python for Scientific Computing, see search.log.'
|
|
)
|
|
|
|
|
|
def fix_sys_path():
|
|
# After shelling into PSC's Python interpreter, we no longer have access
|
|
# to Splunk core's Python path to import stuff from there. So we retrieve
|
|
# that path from the environment variable we set before.
|
|
splunk_python_path = os.environ.get('SPLUNK_CORE_PYTHONPATH')
|
|
if not splunk_python_path:
|
|
raise Exception('Can not find Splunk core Python path')
|
|
try:
|
|
splunk_python_path = json.loads(splunk_python_path)
|
|
except Exception as e:
|
|
raise Exception('Can not parse Splunk core Python path: %r' % e)
|
|
for item in splunk_python_path:
|
|
if item not in sys.path:
|
|
sys.path.append(item)
|
|
|
|
# XXX: Since PYTHONPATH is gone in Splunk 8 onwards
|
|
# the following block will have no effect, but will
|
|
# keep it for now. SPL-170875
|
|
# Update sys.path to move Splunk's PYTHONPATH to the end. We want
|
|
# to import Anaconda's built-ins before Splunk's.
|
|
pp = os.environ.get('PYTHONPATH')
|
|
if not pp:
|
|
return
|
|
for spp in pp.split(os.pathsep):
|
|
try:
|
|
sys.path.remove(spp)
|
|
sys.path.append(spp)
|
|
except Exception:
|
|
pass
|
|
|
|
# MLA-2136: update environment variable such that subprocesses
|
|
# (from watchdog) will also have Anaconda's builtins available before
|
|
# Splunk's builtins.
|
|
if platform.system() == 'Windows':
|
|
os.environ['PYTHONPATH'] = os.pathsep.join(sys.path)
|
|
|
|
|
|
def exec_anaconda_or_die():
|
|
try:
|
|
exec_anaconda()
|
|
except Exception as e:
|
|
print('Failed to activate Conda environment: %r' % e, sys.stderr)
|
|
import cexc
|
|
|
|
cexc.abort(e)
|
|
sys.exit(1)
|