Skip to content

Commit

Permalink
Rqd config file from env var and copy rqd host env var (AcademySoftwa…
Browse files Browse the repository at this point in the history
…reFoundation#1270)

* feat: load rqd config file from env var `RQD_CONFIG_FILE`

* feat: new variable `RQD_HOST_ENV_VARS` used to copy env variables from the submitter to the RQD worker

* feat: renamed variable `__section` to `__override_section` to accomodate multiple sections
feat: added `__host_env_var_section`
feat: Allow config file to contain keys without value
feat: Respect case from the config file keys
fix: Added optionnal `OVERRIDE_IS_DESKTOP` from the config file (detection does not work on Windows so we have to force it somehow)
feat: Added `CHECK_INTERVAL_LOCKED` and `MINIMUM_IDLE` for nimby configuration
feat: added `RQD_HOST_ENV_VARS` for config file

* feat: renamed variable `__section` to `__override_section` to accomodate multiple sections
feat: added `__host_env_var_section`
feat: Allow config file to contain keys without value
feat: Respect case from the config file keys
fix: Added optionnal `OVERRIDE_IS_DESKTOP` from the config file (detection does not work on Windows so we have to force it somehow)
feat: Added `CHECK_INTERVAL_LOCKED` and `MINIMUM_IDLE` for nimby configuration
feat: added `RQD_HOST_ENV_VARS` for config file

* feat: use the list of env var from `RQD_HOST_ENV_VARS` to copy them in the frame env.

* docs: fix misleading comment

* doc: add example rqd.conf file

* doc: header for example config file

* fix: add newline

Signed-off-by: Kern Attila GERMAIN <[email protected]>

* doc: added a description for the new UseHostEnvVar section in the example file.

* doc: Added some notes about usage and rez alternative

* chores: pylint line too long

---------

Signed-off-by: Kern Attila GERMAIN <[email protected]>
  • Loading branch information
KernAttila authored and carlosfelgarcia committed May 22, 2024
1 parent 58c9d8d commit 87ee8e6
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 44 deletions.
27 changes: 27 additions & 0 deletions rqd/rqd.example.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# An Example rqd config file.
# It can be placed anywhere on your filesystem and referenced with
# the RQD_CONFIG_FILE environment variable or the -c flag when launching rqd.
# If this file is not found the defaults in rqconstants.py will be used.

[Override]
RQD_USE_PATH_ENV_VAR=1
RQD_USE_IP_AS_HOSTNAME=0
OVERRIDE_IS_DESKTOP=True
OVERRIDE_NIMBY=True
# Number of seconds to wait before checking if the user has become idle.
CHECK_INTERVAL_LOCKED = 60
# Seconds of idle time required before nimby unlocks.
MINIMUM_IDLE = 900

# This section tells RQD which env var it should copy from the worker machine to the job's environment.
# For instance you could need to copy PIXAR_LICENSE_FILE if you launch a renderman job.
# Note: - environment variables will be copied from the machine executing the job, not the sender !
# - this is useful mostly if you execute RQD in a virtual env.
# - you should ignore this section if rez is used to manage your env.
[UseHostEnvVar]
# SYSTEMDRIVE is mandatory to allow maya to run in batch via RQD's virtualenv
SYSTEMDRIVE
# Studio specific
MAYA_MODULE_PATH
MAYA_SCRIPT_PATH
PIXAR_LICENSE_FILE
110 changes: 66 additions & 44 deletions rqd/rqd/rqconstants.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@

# Use the PATH environment variable from the RQD host.
RQD_USE_PATH_ENV_VAR = False
# Copy specific environment variable from the RQD host to the frame env.
RQD_HOST_ENV_VARS = []

RQD_BECOME_JOB_USER = True
RQD_CREATE_USER_IF_NOT_EXISTS = True
Expand Down Expand Up @@ -115,11 +117,16 @@
if platform.system() == 'Linux':
SYS_HERTZ = os.sysconf('SC_CLK_TCK')

# First retrieve local configuration file
if platform.system() == 'Windows':
CONFIG_FILE = os.path.expandvars('%LOCALAPPDATA%/OpenCue/rqd.conf')
else:
CONFIG_FILE = '/etc/opencue/rqd.conf'

# Then overwrites with an eventual shared configuration file
CONFIG_FILE = os.environ.get('RQD_CONFIG_FILE', CONFIG_FILE)

# Finally get the one passed as argument when launching rqd
if '-c' in sys.argv:
CONFIG_FILE = sys.argv[sys.argv.index('-c') + 1]

Expand Down Expand Up @@ -147,61 +154,76 @@
try:
if os.path.isfile(CONFIG_FILE):
# Hostname can come from here: rqutil.getHostname()
__section = "Override"
__override_section = "Override"
__host_env_var_section = "UseHostEnvVar"
import six
from six.moves import configparser
if six.PY2:
ConfigParser = configparser.SafeConfigParser
else:
ConfigParser = configparser.RawConfigParser
config = ConfigParser()
# Allow some config file sections to contain only keys
config = ConfigParser(allow_no_value=True)
# Respect case from the config file keys
config.optionxform = str
config.read(CONFIG_FILE)
logging.warning('Loading config %s', CONFIG_FILE)

if config.has_option(__section, "RQD_GRPC_PORT"):
RQD_GRPC_PORT = config.getint(__section, "RQD_GRPC_PORT")
if config.has_option(__section, "CUEBOT_GRPC_PORT"):
CUEBOT_GRPC_PORT = config.getint(__section, "CUEBOT_GRPC_PORT")
if config.has_option(__section, "OVERRIDE_CORES"):
OVERRIDE_CORES = config.getint(__section, "OVERRIDE_CORES")
if config.has_option(__section, "OVERRIDE_PROCS"):
OVERRIDE_PROCS = config.getint(__section, "OVERRIDE_PROCS")
if config.has_option(__section, "OVERRIDE_MEMORY"):
OVERRIDE_MEMORY = config.getint(__section, "OVERRIDE_MEMORY")
if config.has_option(__section, "OVERRIDE_CUEBOT"):
CUEBOT_HOSTNAME = config.get(__section, "OVERRIDE_CUEBOT")
if config.has_option(__section, "OVERRIDE_NIMBY"):
OVERRIDE_NIMBY = config.getboolean(__section, "OVERRIDE_NIMBY")
if config.has_option(__section, "USE_NIMBY_PYNPUT"):
USE_NIMBY_PYNPUT = config.getboolean(__section, "USE_NIMBY_PYNPUT")
if config.has_option(__section, "OVERRIDE_HOSTNAME"):
OVERRIDE_HOSTNAME = config.get(__section, "OVERRIDE_HOSTNAME")
if config.has_option(__section, "GPU"):
ALLOW_GPU = config.getboolean(__section, "GPU")
if config.has_option(__section, "LOAD_MODIFIER"):
LOAD_MODIFIER = config.getint(__section, "LOAD_MODIFIER")
if config.has_option(__section, "RQD_USE_IP_AS_HOSTNAME"):
RQD_USE_IP_AS_HOSTNAME = config.getboolean(__section, "RQD_USE_IP_AS_HOSTNAME")
if config.has_option(__section, "RQD_USE_IPV6_AS_HOSTNAME"):
RQD_USE_IPV6_AS_HOSTNAME = config.getboolean(__section, "RQD_USE_IPV6_AS_HOSTNAME")
if config.has_option(__section, "RQD_USE_PATH_ENV_VAR"):
RQD_USE_PATH_ENV_VAR = config.getboolean(__section, "RQD_USE_PATH_ENV_VAR")
if config.has_option(__section, "RQD_BECOME_JOB_USER"):
RQD_BECOME_JOB_USER = config.getboolean(__section, "RQD_BECOME_JOB_USER")
if config.has_option(__section, "RQD_TAGS"):
RQD_TAGS = config.get(__section, "RQD_TAGS")
if config.has_option(__section, "DEFAULT_FACILITY"):
DEFAULT_FACILITY = config.get(__section, "DEFAULT_FACILITY")
if config.has_option(__section, "LAUNCH_FRAME_USER_GID"):
LAUNCH_FRAME_USER_GID = config.getint(__section, "LAUNCH_FRAME_USER_GID")
if config.has_option(__section, "CONSOLE_LOG_LEVEL"):
level = config.get(__section, "CONSOLE_LOG_LEVEL")
if config.has_option(__override_section, "RQD_GRPC_PORT"):
RQD_GRPC_PORT = config.getint(__override_section, "RQD_GRPC_PORT")
if config.has_option(__override_section, "CUEBOT_GRPC_PORT"):
CUEBOT_GRPC_PORT = config.getint(__override_section, "CUEBOT_GRPC_PORT")
if config.has_option(__override_section, "OVERRIDE_CORES"):
OVERRIDE_CORES = config.getint(__override_section, "OVERRIDE_CORES")
if config.has_option(__override_section, "OVERRIDE_PROCS"):
OVERRIDE_PROCS = config.getint(__override_section, "OVERRIDE_PROCS")
if config.has_option(__override_section, "OVERRIDE_MEMORY"):
OVERRIDE_MEMORY = config.getint(__override_section, "OVERRIDE_MEMORY")
if config.has_option(__override_section, "OVERRIDE_CUEBOT"):
CUEBOT_HOSTNAME = config.get(__override_section, "OVERRIDE_CUEBOT")
if config.has_option(__override_section, "OVERRIDE_NIMBY"):
OVERRIDE_NIMBY = config.getboolean(__override_section, "OVERRIDE_NIMBY")
if config.has_option(__override_section, "USE_NIMBY_PYNPUT"):
USE_NIMBY_PYNPUT = config.getboolean(__override_section, "USE_NIMBY_PYNPUT")
if config.has_option(__override_section, "OVERRIDE_IS_DESKTOP"):
OVERRIDE_IS_DESKTOP = config.getboolean(__override_section, "OVERRIDE_IS_DESKTOP")
if config.has_option(__override_section, "OVERRIDE_HOSTNAME"):
OVERRIDE_HOSTNAME = config.get(__override_section, "OVERRIDE_HOSTNAME")
if config.has_option(__override_section, "GPU"):
ALLOW_GPU = config.getboolean(__override_section, "GPU")
if config.has_option(__override_section, "LOAD_MODIFIER"):
LOAD_MODIFIER = config.getint(__override_section, "LOAD_MODIFIER")
if config.has_option(__override_section, "RQD_USE_IP_AS_HOSTNAME"):
RQD_USE_IP_AS_HOSTNAME = config.getboolean(__override_section, "RQD_USE_IP_AS_HOSTNAME")
if config.has_option(__override_section, "RQD_USE_IPV6_AS_HOSTNAME"):
RQD_USE_IPV6_AS_HOSTNAME = config.getboolean(__override_section,
"RQD_USE_IPV6_AS_HOSTNAME")
if config.has_option(__override_section, "RQD_USE_PATH_ENV_VAR"):
RQD_USE_PATH_ENV_VAR = config.getboolean(__override_section, "RQD_USE_PATH_ENV_VAR")
if config.has_option(__override_section, "RQD_BECOME_JOB_USER"):
RQD_BECOME_JOB_USER = config.getboolean(__override_section, "RQD_BECOME_JOB_USER")
if config.has_option(__override_section, "RQD_TAGS"):
RQD_TAGS = config.get(__override_section, "RQD_TAGS")
if config.has_option(__override_section, "DEFAULT_FACILITY"):
DEFAULT_FACILITY = config.get(__override_section, "DEFAULT_FACILITY")
if config.has_option(__override_section, "LAUNCH_FRAME_USER_GID"):
LAUNCH_FRAME_USER_GID = config.getint(__override_section, "LAUNCH_FRAME_USER_GID")
if config.has_option(__override_section, "CONSOLE_LOG_LEVEL"):
level = config.get(__override_section, "CONSOLE_LOG_LEVEL")
CONSOLE_LOG_LEVEL = logging.getLevelName(level)
if config.has_option(__section, "FILE_LOG_LEVEL"):
level = config.get(__section, "FILE_LOG_LEVEL")
if config.has_option(__override_section, "FILE_LOG_LEVEL"):
level = config.get(__override_section, "FILE_LOG_LEVEL")
FILE_LOG_LEVEL = logging.getLevelName(level)
if config.has_option(__section, "RQD_PREPEND_TIMESTAMP"):
RQD_PREPEND_TIMESTAMP = config.getboolean(__section, "RQD_PREPEND_TIMESTAMP")
if config.has_option(__override_section, "RQD_PREPEND_TIMESTAMP"):
RQD_PREPEND_TIMESTAMP = config.getboolean(__override_section, "RQD_PREPEND_TIMESTAMP")
if config.has_option(__override_section, "CHECK_INTERVAL_LOCKED"):
CHECK_INTERVAL_LOCKED = config.getint(__override_section, "CHECK_INTERVAL_LOCKED")
if config.has_option(__override_section, "MINIMUM_IDLE"):
MINIMUM_IDLE = config.getint(__override_section, "MINIMUM_IDLE")

if config.has_section(__host_env_var_section):
RQD_HOST_ENV_VARS = config.options(__host_env_var_section)

# pylint: disable=broad-except
except Exception as e:
logging.warning(
Expand Down
3 changes: 3 additions & 0 deletions rqd/rqd/rqcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ def __createEnvVariables(self):
for variable in ["SYSTEMROOT", "APPDATA", "TMP", "COMMONPROGRAMFILES", "SYSTEMDRIVE"]:
if variable in os.environ:
self.frameEnv[variable] = os.environ[variable]
for variable in rqd.rqconstants.RQD_HOST_ENV_VARS:
# Fallback to empty string, easy to spot what is missing in the log
self.frameEnv[variable] = os.environ.get(variable, '')

for key, value in self.runFrame.environment.items():
if key == 'PATH':
Expand Down

0 comments on commit 87ee8e6

Please sign in to comment.