Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

vrscene creator Deadline webservice URL handling #2580

Merged
merged 2 commits into from
Jan 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 121 additions & 29 deletions openpype/hosts/maya/plugins/create/create_vrayscene.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import json
import appdirs
import requests
import six
import sys

from maya import cmds
import maya.app.renderSetup.model.renderSetup as renderSetup
Expand All @@ -12,7 +14,15 @@
lib,
plugin
)
from openpype.api import get_system_settings
from openpype.api import (
get_system_settings,
get_project_settings
)

from openpype.modules import ModulesManager

from avalon.api import Session
from avalon.api import CreatorError


class CreateVRayScene(plugin.Creator):
Expand All @@ -22,11 +32,40 @@ class CreateVRayScene(plugin.Creator):
family = "vrayscene"
icon = "cubes"

_project_settings = None

def __init__(self, *args, **kwargs):
"""Entry."""
super(CreateVRayScene, self).__init__(*args, **kwargs)
self._rs = renderSetup.instance()
self.data["exportOnFarm"] = False
deadline_settings = get_system_settings()["modules"]["deadline"]
if not deadline_settings["enabled"]:
self.deadline_servers = {}
return
self._project_settings = get_project_settings(
Session["AVALON_PROJECT"])

try:
default_servers = deadline_settings["deadline_urls"]
project_servers = (
self._project_settings["deadline"]["deadline_servers"]
)
self.deadline_servers = {
k: default_servers[k]
for k in project_servers
if k in default_servers
}

if not self.deadline_servers:
self.deadline_servers = default_servers

except AttributeError:
# Handle situation were we had only one url for deadline.
manager = ModulesManager()
deadline_module = manager.modules_by_name["deadline"]
# get default deadline webservice url from deadline module
self.deadline_servers = deadline_module.deadline_urls

def process(self):
"""Entry point."""
Expand All @@ -37,21 +76,30 @@ def process(self):
use_selection = self.options.get("useSelection")
with lib.undo_chunk():
self._create_vray_instance_settings()
instance = super(CreateVRayScene, self).process()
self.instance = super(CreateVRayScene, self).process()

index = 1
namespace_name = "_{}".format(str(instance))
namespace_name = "_{}".format(str(self.instance))
try:
cmds.namespace(rm=namespace_name)
except RuntimeError:
# namespace is not empty, so we leave it untouched
pass

while(cmds.namespace(exists=namespace_name)):
namespace_name = "_{}{}".format(str(instance), index)
namespace_name = "_{}{}".format(str(self.instance), index)
index += 1

namespace = cmds.namespace(add=namespace_name)

# add Deadline server selection list
if self.deadline_servers:
cmds.scriptJob(
attributeChange=[
"{}.deadlineServers".format(self.instance),
self._deadline_webservice_changed
])

# create namespace with instance
layers = self._rs.getRenderLayers()
if use_selection:
Expand All @@ -62,7 +110,7 @@ def process(self):
render_set = cmds.sets(
n="{}:{}".format(namespace, layer.name()))
sets.append(render_set)
cmds.sets(sets, forceElement=instance)
cmds.sets(sets, forceElement=self.instance)

# if no render layers are present, create default one with
# asterix selector
Expand All @@ -71,6 +119,52 @@ def process(self):
collection = render_layer.createCollection("defaultCollection")
collection.getSelector().setPattern('*')

def _deadline_webservice_changed(self):
"""Refresh Deadline server dependent options."""
# get selected server
from maya import cmds
webservice = self.deadline_servers[
self.server_aliases[
cmds.getAttr("{}.deadlineServers".format(self.instance))
]
]
pools = self._get_deadline_pools(webservice)
cmds.deleteAttr("{}.primaryPool".format(self.instance))
cmds.deleteAttr("{}.secondaryPool".format(self.instance))
cmds.addAttr(self.instance, longName="primaryPool",
attributeType="enum",
enumName=":".join(pools))
cmds.addAttr(self.instance, longName="secondaryPool",
attributeType="enum",
enumName=":".join(["-"] + pools))

def _get_deadline_pools(self, webservice):
# type: (str) -> list
"""Get pools from Deadline.
Args:
webservice (str): Server url.
Returns:
list: Pools.
Throws:
RuntimeError: If deadline webservice is unreachable.

"""
argument = "{}/api/pools?NamesOnly=true".format(webservice)
try:
response = self._requests_get(argument)
except requests.exceptions.ConnectionError as exc:
msg = 'Cannot connect to deadline web service'
self.log.error(msg)
six.reraise(
CreatorError,
CreatorError('{} - {}'.format(msg, exc)),
sys.exc_info()[2])
if not response.ok:
self.log.warning("No pools retrieved")
return []

return response.json()

def _create_vray_instance_settings(self):
# get pools
pools = []
Expand All @@ -79,31 +173,29 @@ def _create_vray_instance_settings(self):

deadline_enabled = system_settings["deadline"]["enabled"]
muster_enabled = system_settings["muster"]["enabled"]
deadline_url = system_settings["deadline"]["DEADLINE_REST_URL"]
muster_url = system_settings["muster"]["MUSTER_REST_URL"]

if deadline_enabled and muster_enabled:
self.log.error(
"Both Deadline and Muster are enabled. " "Cannot support both."
)
raise RuntimeError("Both Deadline and Muster are enabled")
raise CreatorError("Both Deadline and Muster are enabled")

self.server_aliases = self.deadline_servers.keys()
self.data["deadlineServers"] = self.server_aliases

if deadline_enabled:
argument = "{}/api/pools?NamesOnly=true".format(deadline_url)
# if default server is not between selected, use first one for
# initial list of pools.
try:
response = self._requests_get(argument)
except requests.exceptions.ConnectionError as e:
msg = 'Cannot connect to deadline web service'
self.log.error(msg)
raise RuntimeError('{} - {}'.format(msg, e))
if not response.ok:
self.log.warning("No pools retrieved")
else:
pools = response.json()
self.data["primaryPool"] = pools
# We add a string "-" to allow the user to not
# set any secondary pools
self.data["secondaryPool"] = ["-"] + pools
deadline_url = self.deadline_servers["default"]
except KeyError:
deadline_url = [
self.deadline_servers[k]
for k in self.deadline_servers.keys()
][0]

pool_names = self._get_deadline_pools(deadline_url)

if muster_enabled:
self.log.info(">>> Loading Muster credentials ...")
Expand All @@ -115,10 +207,10 @@ def _create_vray_instance_settings(self):
if e.startswith("401"):
self.log.warning("access token expired")
self._show_login()
raise RuntimeError("Access token expired")
raise CreatorError("Access token expired")
except requests.exceptions.ConnectionError:
self.log.error("Cannot connect to Muster API endpoint.")
raise RuntimeError("Cannot connect to {}".format(muster_url))
raise CreatorError("Cannot connect to {}".format(muster_url))
pool_names = []
for pool in pools:
self.log.info(" - pool: {}".format(pool["name"]))
Expand All @@ -140,7 +232,7 @@ def _load_credentials(self):
``MUSTER_PASSWORD``, ``MUSTER_REST_URL`` is loaded from presets.

Raises:
RuntimeError: If loaded credentials are invalid.
CreatorError: If loaded credentials are invalid.
AttributeError: If ``MUSTER_REST_URL`` is not set.

"""
Expand All @@ -152,7 +244,7 @@ def _load_credentials(self):
self._token = muster_json.get("token", None)
if not self._token:
self._show_login()
raise RuntimeError("Invalid access token for Muster")
raise CreatorError("Invalid access token for Muster")
file.close()
self.MUSTER_REST_URL = os.environ.get("MUSTER_REST_URL")
if not self.MUSTER_REST_URL:
Expand All @@ -162,7 +254,7 @@ def _get_muster_pools(self):
"""Get render pools from Muster.

Raises:
Exception: If pool list cannot be obtained from Muster.
CreatorError: If pool list cannot be obtained from Muster.

"""
params = {"authToken": self._token}
Expand All @@ -178,12 +270,12 @@ def _get_muster_pools(self):
("Cannot get pools from "
"Muster: {}").format(response.status_code)
)
raise Exception("Cannot get pools from Muster")
raise CreatorError("Cannot get pools from Muster")
try:
pools = response.json()["ResponseData"]["pools"]
except ValueError as e:
self.log.error("Invalid response from Muster server {}".format(e))
raise Exception("Invalid response from Muster server")
raise CreatorError("Invalid response from Muster server")

return pools

Expand All @@ -196,7 +288,7 @@ def _show_login(self):
login_response = self._requests_get(api_url, timeout=1)
if login_response.status_code != 200:
self.log.error("Cannot show login form to Muster")
raise Exception("Cannot show login form to Muster")
raise CreatorError("Cannot show login form to Muster")

def _requests_post(self, *args, **kwargs):
"""Wrap request post method.
Expand Down
2 changes: 1 addition & 1 deletion openpype/hosts/maya/plugins/publish/collect_vrayscene.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import pyblish.api
from avalon import api
from openpype.hosts.maya import lib
from openpype.hosts.maya.api import lib


class CollectVrayScene(pyblish.api.InstancePlugin):
Expand Down