ayon-core/openpype/modules/royalrender/api.py
2023-03-23 15:56:53 +01:00

180 lines
5.8 KiB
Python

# -*- coding: utf-8 -*-
"""Wrapper around Royal Render API."""
import sys
import os
from openpype.lib.local_settings import OpenPypeSettingsRegistry
from openpype.lib import Logger, run_subprocess
from .rr_job import RRJob, SubmitFile, SubmitterParameter
from openpype.lib.vendor_bin_utils import find_tool_in_custom_paths
class Api:
_settings = None
RR_SUBMIT_CONSOLE = 1
RR_SUBMIT_API = 2
def __init__(self, rr_path=None):
self.log = Logger.get_logger("RoyalRender")
self._rr_path = rr_path
os.environ["RR_ROOT"] = rr_path
@staticmethod
def get_rr_bin_path(rr_root, tool_name=None):
# type: (str, str) -> str
"""Get path to RR bin folder.
Args:
tool_name (str): Name of RR executable you want.
rr_root (str): Custom RR root if needed.
Returns:
str: Path to the tool based on current platform.
"""
is_64bit_python = sys.maxsize > 2 ** 32
rr_bin_parts = [rr_root, "bin"]
if sys.platform.lower() == "win32":
rr_bin_parts.append("win")
if sys.platform.lower() == "darwin":
rr_bin_parts.append("mac")
if sys.platform.lower().startswith("linux"):
rr_bin_parts.append("lx")
rr_bin_path = os.sep.join(rr_bin_parts)
paths_to_check = []
# if we use 64bit python, append 64bit specific path first
if is_64bit_python:
if not tool_name:
return rr_bin_path + "64"
paths_to_check.append(rr_bin_path + "64")
# otherwise use 32bit
if not tool_name:
return rr_bin_path
paths_to_check.append(rr_bin_path)
return find_tool_in_custom_paths(paths_to_check, tool_name)
def _initialize_module_path(self):
# type: () -> None
"""Set RR modules for Python."""
# default for linux
rr_bin = self.get_rr_bin_path(self._rr_path)
rr_module_path = os.path.join(rr_bin, "lx64/lib")
if sys.platform.lower() == "win32":
rr_module_path = rr_bin
rr_module_path = rr_module_path.replace(
"/", os.path.sep
)
if sys.platform.lower() == "darwin":
rr_module_path = os.path.join(rr_bin, "lib/python/27")
sys.path.append(os.path.join(self._rr_path, rr_module_path))
@staticmethod
def create_submission(jobs, submitter_attributes):
# type: (list[RRJob], list[SubmitterParameter]) -> SubmitFile
"""Create jobs submission file.
Args:
jobs (list): List of :class:`RRJob`
submitter_attributes (list): List of submitter attributes
:class:`SubmitterParameter` for whole submission batch.
Returns:
str: XML data of job submission files.
"""
return SubmitFile(SubmitterParameters=submitter_attributes, Jobs=jobs)
def submit_file(self, file, mode=RR_SUBMIT_CONSOLE):
# type: (SubmitFile, int) -> None
if mode == self.RR_SUBMIT_CONSOLE:
self._submit_using_console(file)
return
# RR v7 supports only Python 2.7, so we bail out in fear
# until there is support for Python 3 😰
raise NotImplementedError(
"Submission via RoyalRender API is not supported yet")
# self._submit_using_api(file)
def _submit_using_console(self, job_file):
# type: (SubmitFile) -> None
rr_start_local = self.get_rr_bin_path(
self._rr_path, "rrStartLocal")
self.log.info("rr_console: {}".format(rr_start_local))
args = [rr_start_local, "rrSubmitterconsole", job_file]
self.log.info("Executing: {}".format(" ".join(args)))
env = os.environ
env["RR_ROOT"] = self._rr_path
run_subprocess(args, logger=self.log, env=env)
def _submit_using_api(self, file):
# type: (SubmitFile) -> None
"""Use RR API to submit jobs.
Args:
file (SubmitFile): Submit jobs definition.
Throws:
RoyalRenderException: When something fails.
"""
self._initialize_module_path()
import libpyRR2 as rrLib # noqa
from rrJob import getClass_JobBasics # noqa
import libpyRR2 as _RenderAppBasic # noqa
tcp = rrLib._rrTCP("") # noqa
rr_server = tcp.getRRServer()
if len(rr_server) == 0:
self.log.info("Got RR IP address {}".format(rr_server))
# TODO: Port is hardcoded in RR? If not, move it to Settings
if not tcp.setServer(rr_server, 7773):
self.log.error(
"Can not set RR server: {}".format(tcp.errorMessage()))
raise RoyalRenderException(tcp.errorMessage())
# TODO: This need UI and better handling of username/password.
# We can't store password in keychain as it is pulled multiple
# times and users on linux must enter keychain password every time.
# Probably best way until we setup our own user management would be
# to encrypt password and save it to json locally. Not bulletproof
# but at least it is not stored in plaintext.
reg = OpenPypeSettingsRegistry()
try:
rr_user = reg.get_item("rr_username")
rr_password = reg.get_item("rr_password")
except ValueError:
# user has no rr credentials set
pass
else:
# login to RR
tcp.setLogin(rr_user, rr_password)
job = getClass_JobBasics()
renderer = _RenderAppBasic()
# iterate over SubmitFile, set _JobBasic (job) and renderer
# and feed it to jobSubmitNew()
# not implemented yet
job.renderer = renderer
tcp.jobSubmitNew(job)
class RoyalRenderException(Exception):
"""Exception used in various error states coming from RR."""
pass