diff --git a/cuebot/src/main/java/com/imageworks/spcue/DispatchFrame.java b/cuebot/src/main/java/com/imageworks/spcue/DispatchFrame.java index 4c669d438..9644fc0c1 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/DispatchFrame.java +++ b/cuebot/src/main/java/com/imageworks/spcue/DispatchFrame.java @@ -19,6 +19,7 @@ package com.imageworks.spcue; +import java.util.Optional; import com.imageworks.spcue.grpc.job.FrameState; public class DispatchFrame extends FrameEntity implements FrameInterface { @@ -29,7 +30,7 @@ public class DispatchFrame extends FrameEntity implements FrameInterface { public String show; public String shot; public String owner; - public int uid; + public Optional uid; public String logDir; public String command; public String range; diff --git a/cuebot/src/main/java/com/imageworks/spcue/JobDetail.java b/cuebot/src/main/java/com/imageworks/spcue/JobDetail.java index cc654a2eb..ac4df0e77 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/JobDetail.java +++ b/cuebot/src/main/java/com/imageworks/spcue/JobDetail.java @@ -15,10 +15,10 @@ * limitations under the License. */ - - package com.imageworks.spcue; +import java.util.Optional; + import com.imageworks.spcue.grpc.job.JobState; public class JobDetail extends JobEntity implements JobInterface, DepartmentInterface { @@ -28,7 +28,7 @@ public class JobDetail extends JobEntity implements JobInterface, DepartmentInte public String shot; public String user; public String email; - public int uid; + public Optional uid; public String logDir; public boolean isPaused; public boolean isAutoEat; diff --git a/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/FrameDaoJdbc.java b/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/FrameDaoJdbc.java index 5008954df..ede7a923c 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/FrameDaoJdbc.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/FrameDaoJdbc.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.List; +import java.util.Optional; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.support.JdbcDaoSupport; @@ -265,7 +266,8 @@ public DispatchFrame mapRow(ResultSet rs, int rowNum) throws SQLException { frame.shot = rs.getString("str_shot"); frame.show = rs.getString("show_name"); frame.owner = rs.getString("str_user"); - frame.uid = rs.getInt("int_uid"); + int uid = rs.getInt("int_uid"); + frame.uid = rs.wasNull() ? Optional.empty() : Optional.of(uid); frame.state = FrameState.valueOf(rs.getString("frame_state")); frame.minCores = rs.getInt("int_cores_min"); frame.maxCores = rs.getInt("int_cores_max"); diff --git a/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/JobDaoJdbc.java b/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/JobDaoJdbc.java index 7559ad0d3..3b2e72211 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/JobDaoJdbc.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/JobDaoJdbc.java @@ -28,6 +28,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -119,7 +120,8 @@ public JobDetail mapRow(ResultSet rs, int rowNum) throws SQLException { job.priority = rs.getInt("int_priority"); job.shot = rs.getString("str_shot"); job.state = JobState.valueOf(rs.getString("str_state")); - job.uid = rs.getInt("int_uid"); + int uid = rs.getInt("int_uid"); + job.uid = rs.wasNull() ? Optional.empty() : Optional.of(uid); job.user = rs.getString("str_user"); job.email = rs.getString("str_email"); job.totalFrames = rs.getInt("int_frame_count"); @@ -449,7 +451,7 @@ public void insertJob(JobDetail j, JobLogUtil jobLogUtil) { getJdbcTemplate().update(INSERT_JOB, j.id, j.showId, j.groupId, j.facilityId, j.deptId, j.name, j.name, j.showName, j.shot, j.user, j.email, j.state.toString(), - j.logDir, j.os, j.uid, j.isPaused, j.isAutoEat, j.maxRetries); + j.logDir, j.os, j.uid.orElse(null), j.isPaused, j.isAutoEat, j.maxRetries); } private static final String JOB_EXISTS = diff --git a/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/NestedWhiteboardDaoJdbc.java b/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/NestedWhiteboardDaoJdbc.java index bf827ae5e..3746d24f5 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/NestedWhiteboardDaoJdbc.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/NestedWhiteboardDaoJdbc.java @@ -261,13 +261,18 @@ private static final NestedJob mapResultSetToJob(ResultSet rs) throws SQLExcepti .setFacility(rs.getString("facility_name")) .setGroup(rs.getString("group_name")) .setState(JobState.valueOf(rs.getString("str_state"))) - .setUid(rs.getInt("int_uid")) .setUser(rs.getString("str_user")) .setIsPaused(rs.getBoolean("b_paused")) .setHasComment(rs.getBoolean("b_comment")) .setAutoEat(rs.getBoolean("b_autoeat")) .setStartTime((int) (rs.getTimestamp("ts_started").getTime() / 1000)) .setStats(WhiteboardDaoJdbc.mapJobStats(rs)); + + int uid = rs.getInt("int_uid"); + if (!rs.wasNull()) { + jobBuilder.setUid(uid); + } + Timestamp ts = rs.getTimestamp("ts_stopped"); if (ts != null) { jobBuilder.setStopTime((int) (ts.getTime() / 1000)); diff --git a/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/WhiteboardDaoJdbc.java b/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/WhiteboardDaoJdbc.java index 05c7fc961..99c3e695b 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/WhiteboardDaoJdbc.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dao/oracle/WhiteboardDaoJdbc.java @@ -1163,7 +1163,6 @@ public Job mapRow(ResultSet rs, int rowNum) throws SQLException { .setFacility(SqlUtil.getString(rs, "facility_name")) .setGroup(SqlUtil.getString(rs, "group_name")) .setState(JobState.valueOf(SqlUtil.getString(rs, "str_state"))) - .setUid(rs.getInt("int_uid")) .setUser(SqlUtil.getString(rs, "str_user")) .setIsPaused(rs.getBoolean("b_paused")) .setHasComment(rs.getBoolean("b_comment")) @@ -1171,6 +1170,11 @@ public Job mapRow(ResultSet rs, int rowNum) throws SQLException { .setStartTime((int) (rs.getTimestamp("ts_started").getTime() / 1000)) .setOs(SqlUtil.getString(rs, "str_os")); + int uid = rs.getInt("int_uid"); + if (!rs.wasNull()) { + jobBuilder.setUid(uid); + } + Timestamp ts = rs.getTimestamp("ts_stopped"); if (ts != null) { jobBuilder.setStopTime((int) (ts.getTime() / 1000)); diff --git a/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/FrameDaoJdbc.java b/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/FrameDaoJdbc.java index f1083d696..69cd2df47 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/FrameDaoJdbc.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/FrameDaoJdbc.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.List; +import java.util.Optional; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.support.JdbcDaoSupport; @@ -267,7 +268,8 @@ public DispatchFrame mapRow(ResultSet rs, int rowNum) throws SQLException { frame.shot = rs.getString("str_shot"); frame.show = rs.getString("show_name"); frame.owner = rs.getString("str_user"); - frame.uid = rs.getInt("int_uid"); + int uid = rs.getInt("int_uid"); + frame.uid = rs.wasNull() ? Optional.empty() : Optional.of(uid); frame.state = FrameState.valueOf(rs.getString("frame_state")); frame.minCores = rs.getInt("int_cores_min"); frame.maxCores = rs.getInt("int_cores_max"); diff --git a/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/JobDaoJdbc.java b/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/JobDaoJdbc.java index 2b7ac5456..0b103f747 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/JobDaoJdbc.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/JobDaoJdbc.java @@ -27,6 +27,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -118,7 +119,8 @@ public JobDetail mapRow(ResultSet rs, int rowNum) throws SQLException { job.priority = rs.getInt("int_priority"); job.shot = rs.getString("str_shot"); job.state = JobState.valueOf(rs.getString("str_state")); - job.uid = rs.getInt("int_uid"); + int uid = rs.getInt("int_uid"); + job.uid = rs.wasNull() ? Optional.empty() : Optional.of(uid); job.user = rs.getString("str_user"); job.email = rs.getString("str_email"); job.totalFrames = rs.getInt("int_frame_count"); @@ -447,7 +449,7 @@ public void insertJob(JobDetail j, JobLogUtil jobLogUtil) { getJdbcTemplate().update(INSERT_JOB, j.id, j.showId, j.groupId, j.facilityId, j.deptId, j.name, j.name, j.showName, j.shot, j.user, j.email, j.state.toString(), - j.logDir, j.os, j.uid, j.isPaused, j.isAutoEat, j.maxRetries); + j.logDir, j.os, j.uid.orElse(null), j.isPaused, j.isAutoEat, j.maxRetries); } private static final String JOB_EXISTS = diff --git a/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/NestedWhiteboardDaoJdbc.java b/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/NestedWhiteboardDaoJdbc.java index 84c885529..de2766346 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/NestedWhiteboardDaoJdbc.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/NestedWhiteboardDaoJdbc.java @@ -262,13 +262,18 @@ private static final NestedJob mapResultSetToJob(ResultSet rs) throws SQLExcepti .setFacility(rs.getString("facility_name")) .setGroup(rs.getString("group_name")) .setState(JobState.valueOf(rs.getString("str_state"))) - .setUid(rs.getInt("int_uid")) .setUser(rs.getString("str_user")) .setIsPaused(rs.getBoolean("b_paused")) .setHasComment(rs.getBoolean("b_comment")) .setAutoEat(rs.getBoolean("b_autoeat")) .setStartTime((int) (rs.getTimestamp("ts_started").getTime() / 1000)) .setStats(WhiteboardDaoJdbc.mapJobStats(rs)); + + int uid = rs.getInt("int_uid"); + if (!rs.wasNull()) { + jobBuilder.setUid(uid); + } + Timestamp ts = rs.getTimestamp("ts_stopped"); if (ts != null) { jobBuilder.setStopTime((int) (ts.getTime() / 1000)); diff --git a/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/WhiteboardDaoJdbc.java b/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/WhiteboardDaoJdbc.java index 7798ab645..1f777a6b8 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/WhiteboardDaoJdbc.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dao/postgres/WhiteboardDaoJdbc.java @@ -1163,7 +1163,6 @@ public Job mapRow(ResultSet rs, int rowNum) throws SQLException { .setFacility(SqlUtil.getString(rs,"facility_name")) .setGroup(SqlUtil.getString(rs,"group_name")) .setState(JobState.valueOf(SqlUtil.getString(rs,"str_state"))) - .setUid(rs.getInt("int_uid")) .setUser(SqlUtil.getString(rs,"str_user")) .setIsPaused(rs.getBoolean("b_paused")) .setHasComment(rs.getBoolean("b_comment")) @@ -1171,6 +1170,11 @@ public Job mapRow(ResultSet rs, int rowNum) throws SQLException { .setStartTime((int) (rs.getTimestamp("ts_started").getTime() / 1000)) .setOs(SqlUtil.getString(rs,"str_os")); + int uid = rs.getInt("int_uid"); + if (!rs.wasNull()) { + jobBuilder.setUid(uid); + } + Timestamp ts = rs.getTimestamp("ts_stopped"); if (ts != null) { jobBuilder.setStopTime((int) (ts.getTime() / 1000)); diff --git a/cuebot/src/main/java/com/imageworks/spcue/dispatcher/DispatchSupportService.java b/cuebot/src/main/java/com/imageworks/spcue/dispatcher/DispatchSupportService.java index 2e2708d40..b131fcbd7 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dispatcher/DispatchSupportService.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dispatcher/DispatchSupportService.java @@ -351,11 +351,10 @@ public RunFrame prepareRqdRunFrame(VirtualProc proc, DispatchFrame frame) { int startFrameIndex = fs.index(frameNumber); String frameSpec = fs.getChunk(startFrameIndex, frame.chunkSize); - return RunFrame.newBuilder() + RunFrame.Builder builder = RunFrame.newBuilder() .setShot(frame.shot) .setShow(frame.show) .setUserName(frame.owner) - .setUid(frame.uid) .setLogDir(frame.logDir) .setJobId(frame.jobId) .setJobName(frame.jobName) @@ -395,8 +394,11 @@ public RunFrame prepareRqdRunFrame(VirtualProc proc, DispatchFrame frame) { .replaceAll("#LAYER#", frame.layerName) .replaceAll("#JOB#", frame.jobName) .replaceAll("#FRAMESPEC#", frameSpec) - .replaceAll("#FRAME#", frame.name)) - .build(); + .replaceAll("#FRAME#", frame.name)); + + frame.uid.ifPresent(builder::setUid); + + return builder.build(); } diff --git a/cuebot/src/main/java/com/imageworks/spcue/service/JobSpec.java b/cuebot/src/main/java/com/imageworks/spcue/service/JobSpec.java index 21cd9f2c4..788df3e81 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/service/JobSpec.java +++ b/cuebot/src/main/java/com/imageworks/spcue/service/JobSpec.java @@ -26,6 +26,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -63,7 +64,7 @@ public class JobSpec { private String email; - private int uid; + private Optional uid; private int totalFrames = 0; @@ -194,13 +195,14 @@ private void handleSpecTag() { if (facility != null) { facility = facility.toLowerCase(); } + show = rootElement.getChildTextTrim("show"); shot = rootElement.getChildTextTrim("shot"); user = rootElement.getChildTextTrim("user"); - uid = Integer.parseInt(rootElement.getChildTextTrim("uid")); + uid = Optional.ofNullable(rootElement.getChildTextTrim("uid")).map(Integer::parseInt); email = rootElement.getChildTextTrim("email"); - if (user == "root" || uid == 0) { + if (user == "root" || uid.equals(Optional.of(0))) { throw new SpecBuilderException("Cannot launch jobs as root."); } } @@ -214,6 +216,7 @@ private void handleJobsTag() { if (elements == null) { return; } + for (Object tmpElement : elements) { Element jobElement = (Element) tmpElement; jobs.add(handleJobTag(jobElement)); @@ -880,7 +883,7 @@ public String getShow() { return show; } - public int getUid() { + public Optional getUid() { return uid; } diff --git a/cuebot/src/main/resources/conf/ddl/postgres/migrations/V6__Allow_NULL_UID.sql b/cuebot/src/main/resources/conf/ddl/postgres/migrations/V6__Allow_NULL_UID.sql new file mode 100644 index 000000000..3eed77223 --- /dev/null +++ b/cuebot/src/main/resources/conf/ddl/postgres/migrations/V6__Allow_NULL_UID.sql @@ -0,0 +1,5 @@ +-- Allow a NULL UID field, meaning 'RQD current user'. + +ALTER TABLE "job" ALTER COLUMN "int_uid" DROP NOT NULL; +ALTER TABLE "job" ALTER COLUMN "int_uid" DROP DEFAULT; + diff --git a/cuebot/src/main/resources/public/dtd/cjsl-1.9.dtd b/cuebot/src/main/resources/public/dtd/cjsl-1.9.dtd new file mode 100644 index 000000000..c945f948f --- /dev/null +++ b/cuebot/src/main/resources/public/dtd/cjsl-1.9.dtd @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proto/job.proto b/proto/job.proto index 91d603ba7..4b33c015d 100644 --- a/proto/job.proto +++ b/proto/job.proto @@ -546,7 +546,9 @@ message Job { string group = 7; string facility = 8; string os = 9; - int32 uid = 10; + oneof uid_optional { + int32 uid = 10; + } int32 priority = 11; float min_cores = 12; float max_cores = 13; @@ -680,7 +682,9 @@ message NestedJob { string group = 7; string facility = 8; string os = 9; - int32 uid = 10; + oneof uid_optional { + int32 uid = 10; + } int32 priority = 11; float min_cores = 12; float max_cores = 13; diff --git a/proto/rqd.proto b/proto/rqd.proto index 5df41ac20..a4b83f0c3 100644 --- a/proto/rqd.proto +++ b/proto/rqd.proto @@ -102,7 +102,9 @@ message RunFrame { string log_file = 14; string log_dir_file = 15; int64 start_time = 16; - int32 uid = 17; + oneof uid_optional { + int32 uid = 17; + } int32 num_cores = 18; int32 gid = 19; bool ignore_nimby = 20; diff --git a/pycue/opencue/wrappers/job.py b/pycue/opencue/wrappers/job.py index f8e1877dc..b656e9221 100644 --- a/pycue/opencue/wrappers/job.py +++ b/pycue/opencue/wrappers/job.py @@ -390,9 +390,9 @@ def logDir(self): def uid(self): """Returns the uid of the person who owns the job. - :rtype: int + :rtype: Optional[int] :return: Uid of job owner""" - return self.data.uid + return self.data.uid if self.data.HasField("uid") else None def user(self): """Returns the username of the person who owns the job. @@ -897,7 +897,7 @@ def asJob(self): group=self.data.group, facility=self.data.facility, os=self.data.os, - uid=self.data.uid, + uid=self.data.uid if self.data.HasField("uid") else None, priority=self.data.priority, min_cores=self.data.min_cores, max_cores=self.data.max_cores, diff --git a/pyoutline/outline/backend/cue.py b/pyoutline/outline/backend/cue.py index 8a5b7fd54..0234fd299 100644 --- a/pyoutline/outline/backend/cue.py +++ b/pyoutline/outline/backend/cue.py @@ -215,7 +215,9 @@ def _serialize(launcher, use_pycuerun): if not launcher.get("nomail"): sub_element(root, "email", "%s@%s" % (user, config.get("outline", "domain"))) - sub_element(root, "uid", str(util.get_uid())) + uid = util.get_uid() + if uid is not None: + sub_element(root, "uid", str(uid)) j = Et.SubElement(root, "job", {"name": ol.get_name()}) sub_element(j, "paused", str(launcher.get("pause"))) @@ -314,7 +316,7 @@ def _serialize(launcher, use_pycuerun): xml = [ '', '', + '"http://localhost:8080/spcue/dtd/cjsl-1.9.dtd">', Et.tostring(root).decode() ] diff --git a/pyoutline/outline/util.py b/pyoutline/outline/util.py index e1f2afca5..bff3c2076 100644 --- a/pyoutline/outline/util.py +++ b/pyoutline/outline/util.py @@ -21,6 +21,7 @@ from __future__ import division from builtins import str + import getpass import os import platform @@ -119,11 +120,12 @@ def get_user(): return os.environ.get('USER', getpass.getuser()) + def get_uid(): """ Return the current users id """ if platform.system() == 'Windows': - return 12345 # TODO: this value is currently not used, but it might be in future + return None return os.getuid() diff --git a/rqd/rqd/rqcore.py b/rqd/rqd/rqcore.py index 96b3b0da0..128a9de04 100644 --- a/rqd/rqd/rqcore.py +++ b/rqd/rqd/rqcore.py @@ -421,12 +421,14 @@ def run(self): runFrame.frame_name) runFrame.log_dir_file = os.path.join(runFrame.log_dir, runFrame.log_file) - try: # Exception block for all exceptions - # Do everything as launching user - runFrame.gid = rqd.rqconstants.LAUNCH_FRAME_USER_GID + try: # Exception block for all exceptions + + # Change to frame user if needed: + if runFrame.HasField("uid"): + # Do everything as launching user: + runFrame.gid = rqd.rqconstants.LAUNCH_FRAME_USER_GID + rqd.rqutil.permissionsUser(runFrame.uid, runFrame.gid) - # Change to job user - rqd.rqutil.permissionsUser(runFrame.uid, runFrame.gid) try: # # Setup proc to allow launching of frame @@ -777,7 +779,7 @@ def launchFrame(self, runFrame): log.critical(err) raise rqd.rqexceptions.DuplicateFrameViolationException(err) - if runFrame.uid <= 0: + if runFrame.HasField("uid") and runFrame.uid <= 0: err = "Not launching, will not run frame as uid=%d" % runFrame.uid log.warning(err) raise rqd.rqexceptions.InvalidUserException(err)