1616import sys
1717import time
1818
19- # Define some debug logging routines to help sort out things when this
20- # all doesn't work as expected.
21-
22-
2319# Avoiding additional imports by defining PY2 manually
2420PY2 = sys .version_info [0 ] == 2
2521
22+ # Define some debug logging routines to help sort out things when this
23+ # all doesn't work as expected.
24+
2625startup_debug = os .environ .get ("NEW_RELIC_STARTUP_DEBUG" , "off" ).lower () in ("on" , "true" , "1" )
2726
2827
@@ -35,6 +34,14 @@ def log_message(text, *args, **kwargs):
3534 sys .stdout .flush ()
3635
3736
37+ def del_sys_path_entry (path ):
38+ if path and path in sys .path :
39+ try :
40+ del sys .path [sys .path .index (path )]
41+ except Exception :
42+ pass
43+
44+
3845log_message ("New Relic Bootstrap (%s)" , __file__ )
3946
4047log_message ("working_directory = %r" , os .getcwd ())
@@ -70,25 +77,19 @@ def log_message(text, *args, **kwargs):
7077# the search, and then load what was found.
7178
7279boot_directory = os .path .dirname (__file__ )
73- root_directory = os .path .dirname (os .path .dirname (boot_directory ))
74-
75- log_message ("root_directory = %r" , root_directory )
7680log_message ("boot_directory = %r" , boot_directory )
7781
78- path = list (sys .path )
79-
80- if boot_directory in path :
81- del path [path .index (boot_directory )]
82+ del_sys_path_entry (boot_directory )
8283
8384try :
8485 if PY2 :
8586 import imp
8687
87- module_spec = imp .find_module ("sitecustomize" , path )
88+ module_spec = imp .find_module ("sitecustomize" , sys . path )
8889 else :
8990 from importlib .machinery import PathFinder
9091
91- module_spec = PathFinder .find_spec ("sitecustomize" , path = path )
92+ module_spec = PathFinder .find_spec ("sitecustomize" , path = sys . path )
9293
9394except ImportError :
9495 pass
@@ -118,52 +119,91 @@ def log_message(text, *args, **kwargs):
118119
119120python_prefix_matches = expected_python_prefix == actual_python_prefix
120121python_version_matches = expected_python_version == actual_python_version
122+ k8s_operator_enabled = os .environ .get ("NEW_RELIC_K8S_OPERATOR_ENABLED" , "off" ).lower () in ("on" , "true" , "1" )
121123
122124log_message ("python_prefix_matches = %r" , python_prefix_matches )
123125log_message ("python_version_matches = %r" , python_version_matches )
126+ log_message ("k8s_operator_enabled = %r" , k8s_operator_enabled )
124127
125- if python_prefix_matches and python_version_matches :
128+ if k8s_operator_enabled or ( python_prefix_matches and python_version_matches ) :
126129 # We also need to skip agent initialisation if neither the license
127130 # key or config file environment variables are set. We do this as
128131 # some people like to use a common startup script which always uses
129132 # the wrapper script, and which controls whether the agent is
130133 # actually run based on the presence of the environment variables.
131134
132135 license_key = os .environ .get ("NEW_RELIC_LICENSE_KEY" , None )
133-
136+ developer_mode = os . environ . get ( "NEW_RELIC_DEVELOPER_MODE" , "off" ). lower () in ( "on" , "true" , "1" )
134137 config_file = os .environ .get ("NEW_RELIC_CONFIG_FILE" , None )
135138 environment = os .environ .get ("NEW_RELIC_ENVIRONMENT" , None )
139+ initialize_agent = bool (license_key or config_file or developer_mode )
140+
141+ log_message ("initialize_agent = %r" , initialize_agent )
142+
143+ if initialize_agent :
144+ if not k8s_operator_enabled :
145+ # When installed as an egg with buildout, the root directory for
146+ # packages is not listed in sys.path and scripts instead set it
147+ # after Python has started up. This will cause importing of
148+ # 'newrelic' module to fail. What we do is see if the root
149+ # directory where the package is held is in sys.path and if not
150+ # insert it. For good measure we remove it after having imported
151+ # 'newrelic' module to reduce chance that will cause any issues.
152+ # If it is a buildout created script, it will replace the whole
153+ # sys.path again later anyway.
154+ root_directory = os .path .dirname (os .path .dirname (boot_directory ))
155+ log_message ("root_directory = %r" , root_directory )
156+
157+ new_relic_path = root_directory
158+ do_insert_path = root_directory not in sys .path
159+ else :
160+ # When installed with the kubernetes operator, we need to attempt
161+ # to find a distribution from our initcontainer that matches the
162+ # current environment. For wheels, this is platform dependent and we
163+ # rely on pip to identify the correct wheel to use. If no suitable
164+ # wheel can be found, we will fall back to the sdist and disable
165+ # extensions. Once the appropriate distribution is found, we import
166+ # it and leave the entry in sys.path. This allows users to import
167+ # the 'newrelic' module later and use our APIs in their code.
168+ try :
169+ sys .path .insert (0 , boot_directory )
170+ from newrelic_k8s_operator import find_supported_newrelic_distribution
171+ finally :
172+ del_sys_path_entry (boot_directory )
136173
137- log_message ("initialize_agent = %r" , bool (license_key or config_file ))
174+ new_relic_path = find_supported_newrelic_distribution ()
175+ do_insert_path = True
138176
139- if license_key or config_file :
140- # When installed as an egg with buildout, the root directory for
141- # packages is not listed in sys.path and scripts instead set it
142- # after Python has started up. This will cause importing of
143- # 'newrelic' module to fail. What we do is see if the root
144- # directory where the package is held is in sys.path and if not
145- # insert it. For good measure we remove it after having imported
146- # 'newrelic' module to reduce chance that will cause any issues.
147- # If it is a buildout created script, it will replace the whole
148- # sys.path again later anyway.
177+ # Now that the appropriate location of the module has been identified,
178+ # either by the kubernetes operator or this script, we are ready to import
179+ # the 'newrelic' module to make it available in sys.modules. If the location
180+ # containing it was not found on sys.path, do_insert_path will be set and
181+ # the location will be inserted into sys.path. The module is then imported,
182+ # and the sys.path entry is removed afterwards to reduce chance that will
183+ # cause any issues.
149184
150- do_insert_path = root_directory not in sys .path
151- if do_insert_path :
152- sys .path .insert (0 , root_directory )
185+ log_message ("new_relic_path = %r" % new_relic_path )
186+ log_message ("do_insert_path = %r" % do_insert_path )
153187
154- import newrelic .config
188+ try :
189+ if do_insert_path :
190+ sys .path .insert (0 , new_relic_path )
155191
156- log_message ( "agent_version = %r" , newrelic . version )
192+ import newrelic
157193
158- if do_insert_path :
159- try :
160- del sys .path [sys .path .index (root_directory )]
161- except Exception :
162- pass
194+ log_message ("agent_version = %r" , newrelic .version )
195+ finally :
196+ if do_insert_path :
197+ del_sys_path_entry (new_relic_path )
163198
164199 # Finally initialize the agent.
200+ import newrelic .config
165201
166202 newrelic .config .initialize (config_file , environment )
203+ else :
204+ log_message (
205+ "New Relic could not start due to missing configuration. Either NEW_RELIC_LICENSE_KEY or NEW_RELIC_CONFIG_FILE are required."
206+ )
167207else :
168208 log_message (
169209 """New Relic could not start because the newrelic-admin script was called from a Python installation that is different from the Python installation that is currently running. To fix this problem, call the newrelic-admin script from the Python installation that is currently running (details below).
0 commit comments