You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aurora.apache.org by ma...@apache.org on 2016/02/02 20:07:27 UTC

aurora git commit: Reverting deprecated field removal patches.

Repository: aurora
Updated Branches:
  refs/heads/master e1b55fa54 -> 4c34015c2


Reverting deprecated field removal patches.

This reverts commit e1b55fa544765c12251ce6c1736e6352da3f7edb.

This reverts commit 89fad5a8895482b6c3fa45356137aa250d766dfe.

Bugs closed: AURORA-1603

Reviewed at https://reviews.apache.org/r/43104/


Project: http://git-wip-us.apache.org/repos/asf/aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/4c34015c
Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/4c34015c
Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/4c34015c

Branch: refs/heads/master
Commit: 4c34015c2160fbaf350906d81c1c12fd691e5101
Parents: e1b55fa
Author: Maxim Khutornenko <ma...@apache.org>
Authored: Tue Feb 2 11:07:08 2016 -0800
Committer: Maxim Khutornenko <ma...@apache.org>
Committed: Tue Feb 2 11:07:08 2016 -0800

----------------------------------------------------------------------
 NEWS                                            |  5 --
 .../thrift/org/apache/aurora/gen/api.thrift     |  9 ++
 .../org/apache/aurora/scheduler/base/Query.java |  9 +-
 .../aurora/scheduler/base/TaskTestUtil.java     |  4 +-
 .../configuration/ConfigurationManager.java     | 66 +++++++++++++--
 .../storage/db/views/DbTaskConfig.java          |  4 +
 .../thrift/SchedulerThriftInterface.java        | 11 ++-
 src/main/python/apache/aurora/admin/admin.py    |  6 +-
 src/main/python/apache/aurora/client/api/sla.py |  6 +-
 .../python/apache/aurora/client/cli/jobs.py     |  6 +-
 .../python/apache/aurora/client/cli/task.py     |  2 +-
 src/main/python/apache/aurora/config/thrift.py  |  4 +-
 .../apache/aurora/executor/common/announcer.py  |  5 +-
 .../apache/aurora/executor/common/sandbox.py    |  2 +-
 .../scheduler/storage/db/CronJobMapper.xml      |  1 +
 .../scheduler/storage/db/TaskConfigMapper.xml   |  3 +
 .../aurora/scheduler/storage/db/TaskMapper.xml  |  3 +
 .../scheduler/assets/js/controllers.js          |  2 +-
 .../resources/scheduler/assets/js/services.js   | 24 +++++-
 .../configuration/ConfigurationManagerTest.java | 42 ++++++----
 .../aurora/scheduler/cron/quartz/CronIT.java    |  4 +-
 .../scheduler/cron/quartz/QuartzTestUtil.java   |  2 +-
 .../preemptor/PreemptionVictimFilterTest.java   |  7 +-
 .../storage/AbstractCronJobStoreTest.java       |  2 +-
 .../scheduler/storage/log/LogManagerTest.java   |  8 +-
 .../aurora/scheduler/thrift/Fixtures.java       |  8 +-
 .../thrift/ReadOnlySchedulerImplTest.java       | 64 +++++++++-----
 .../thrift/SchedulerThriftInterfaceTest.java    | 88 ++++++++++++++++----
 .../aurora/scheduler/updater/JobDiffTest.java   |  5 +-
 .../python/apache/aurora/admin/test_admin.py    |  6 +-
 .../python/apache/aurora/client/api/test_api.py |  3 +
 .../python/apache/aurora/client/api/test_sla.py |  6 +-
 .../apache/aurora/client/cli/test_status.py     | 15 ++++
 .../python/apache/aurora/client/cli/util.py     |  4 +
 .../python/apache/aurora/config/test_thrift.py  |  5 +-
 .../aurora/executor/common/test_announcer.py    |  4 +
 .../common/test_resource_manager_integration.py |  9 +-
 .../aurora/executor/test_thermos_executor.py    |  6 +-
 38 files changed, 350 insertions(+), 110 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/NEWS
----------------------------------------------------------------------
diff --git a/NEWS b/NEWS
index aef8a1a..a6c2a90 100644
--- a/NEWS
+++ b/NEWS
@@ -49,11 +49,6 @@
 - Removed the following deprecated `HealthCheckConfig` client-side configuration fields: `endpoint`,
   `expected_response`, `expected_response_code`.  These are now set exclusively in like-named fields
   of `HttpHealthChecker.`
-- Removed deprecated (now redundant) fields:
-  - `Identity.role`
-  - `TaskConfig.environment`
-  - `TaskConfig.jobName`
-  - `TaskQuery.owner`
 
 0.11.0
 ------

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/api/src/main/thrift/org/apache/aurora/gen/api.thrift
----------------------------------------------------------------------
diff --git a/api/src/main/thrift/org/apache/aurora/gen/api.thrift b/api/src/main/thrift/org/apache/aurora/gen/api.thrift
index 8409c9b..95313a0 100644
--- a/api/src/main/thrift/org/apache/aurora/gen/api.thrift
+++ b/api/src/main/thrift/org/apache/aurora/gen/api.thrift
@@ -38,6 +38,7 @@ const string AURORA_EXECUTOR_NAME = 'AuroraExecutor'
 
 // TODO(maxim): Remove in 0.7.0. (AURORA-749)
 struct Identity {
+  1: string role
   2: string user
 }
 
@@ -217,6 +218,12 @@ struct TaskConfig {
  // TODO(maxim): Remove in 0.7.0. (AURORA-749)
  /** contains the role component of JobKey */
  17: Identity owner
+ // TODO(maxim): Remove in 0.7.0. (AURORA-749)
+ /** contains the environment component of JobKey */
+ 26: string environment
+ // TODO(maxim): Remove in 0.7.0. (AURORA-749)
+ /** contains the name component of JobKey */
+  3: string jobName
   7: bool isService
   8: double numCpus
   9: i64 ramMb
@@ -503,6 +510,8 @@ struct GetJobsResult {
  * (terms are AND'ed together).
  */
 struct TaskQuery {
+  // TODO(maxim): Remove in 0.7.0. (AURORA-749)
+  8: Identity owner
   14: string role
   9: string environment
   2: string jobName

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/java/org/apache/aurora/scheduler/base/Query.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/base/Query.java b/src/main/java/org/apache/aurora/scheduler/base/Query.java
index ee01eaa..fbadfd3 100644
--- a/src/main/java/org/apache/aurora/scheduler/base/Query.java
+++ b/src/main/java/org/apache/aurora/scheduler/base/Query.java
@@ -130,8 +130,15 @@ public final class Query {
       this.query = new TaskQuery();
     }
 
-    Builder(TaskQuery query) {
+    Builder(final TaskQuery query) {
       // It is expected that the caller calls deepCopy.
+      // TODO(maxim): Safe to keep only Role here as TaskQuery is not returned back to the client.
+      // Remove in 0.7.0. (AURORA-749)
+      if (query.isSetOwner()) {
+        query.setRole(query.getOwner().getRole());
+        query.unsetOwner();
+      }
+
       this.query = query;
     }
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/java/org/apache/aurora/scheduler/base/TaskTestUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/base/TaskTestUtil.java b/src/main/java/org/apache/aurora/scheduler/base/TaskTestUtil.java
index 4c64a1c..02ba1e3 100644
--- a/src/main/java/org/apache/aurora/scheduler/base/TaskTestUtil.java
+++ b/src/main/java/org/apache/aurora/scheduler/base/TaskTestUtil.java
@@ -60,7 +60,9 @@ public final class TaskTestUtil {
   public static ITaskConfig makeConfig(IJobKey job) {
     return ITaskConfig.build(new TaskConfig()
         .setJob(job.newBuilder())
-        .setOwner(new Identity().setUser(job.getRole() + "-user"))
+        .setJobName(job.getName())
+        .setEnvironment(job.getEnvironment())
+        .setOwner(new Identity(job.getRole(), job.getRole() + "-user"))
         .setIsService(true)
         .setNumCpus(1.0)
         .setRamMb(1024)

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java b/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
index 6300e5f..e4dbf06 100644
--- a/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
+++ b/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
@@ -37,6 +37,7 @@ import org.apache.aurora.scheduler.base.JobKeys;
 import org.apache.aurora.scheduler.base.UserProvidedStrings;
 import org.apache.aurora.scheduler.storage.entities.IConstraint;
 import org.apache.aurora.scheduler.storage.entities.IContainer;
+import org.apache.aurora.scheduler.storage.entities.IIdentity;
 import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
 import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
 import org.apache.aurora.scheduler.storage.entities.ITaskConstraint;
@@ -112,6 +113,28 @@ public class ConfigurationManager {
     this.defaultDockerParameters = Objects.requireNonNull(defaultDockerParameters);
   }
 
+  private static void requireNonNull(Object value, String error) throws TaskDescriptionException {
+    if (value == null) {
+      throw new TaskDescriptionException(error);
+    }
+  }
+
+  private static void assertOwnerValidity(IIdentity jobOwner) throws TaskDescriptionException {
+    requireNonNull(jobOwner, "No job owner specified!");
+    requireNonNull(jobOwner.getRole(), "No job role specified!");
+    requireNonNull(jobOwner.getUser(), "No job user specified!");
+
+    if (!UserProvidedStrings.isGoodIdentifier(jobOwner.getRole())) {
+      throw new TaskDescriptionException(
+          "Job role contains illegal characters: " + jobOwner.getRole());
+    }
+
+    if (!UserProvidedStrings.isGoodIdentifier(jobOwner.getUser())) {
+      throw new TaskDescriptionException(
+          "Job user contains illegal characters: " + jobOwner.getUser());
+    }
+  }
+
   private static String getRole(IValueConstraint constraint) {
     return Iterables.getOnlyElement(constraint.getValues()).split("/")[0];
   }
@@ -157,9 +180,12 @@ public class ConfigurationManager {
       throw new TaskDescriptionException("Job key " + job.getKey() + " is invalid.");
     }
 
-    if (job.isSetOwner() && !UserProvidedStrings.isGoodIdentifier(job.getOwner().getUser())) {
-      throw new TaskDescriptionException(
-          "Job user contains illegal characters: " + job.getOwner().getUser());
+    if (job.isSetOwner()) {
+      assertOwnerValidity(job.getOwner());
+
+      if (!job.getKey().getRole().equals(job.getOwner().getRole())) {
+        throw new TaskDescriptionException("Role in job key must match job owner.");
+      }
     }
 
     builder.setTaskConfig(
@@ -193,13 +219,39 @@ public class ConfigurationManager {
 
     maybeFillLinks(builder);
 
+    if (!UserProvidedStrings.isGoodIdentifier(config.getJobName())) {
+      throw new TaskDescriptionException(
+          "Job name contains illegal characters: " + config.getJobName());
+    }
+
+    if (!UserProvidedStrings.isGoodIdentifier(config.getEnvironment())) {
+      throw new TaskDescriptionException(
+          "Environment contains illegal characters: " + config.getEnvironment());
+    }
+
     if (config.isSetTier() && !UserProvidedStrings.isGoodIdentifier(config.getTier())) {
       throw new TaskDescriptionException("Tier contains illegal characters: " + config.getTier());
     }
 
-    if (!JobKeys.isValid(config.getJob())) {
-      // Job key is set but invalid
-      throw new TaskDescriptionException("Job key " + config.getJob() + " is invalid.");
+    if (config.isSetJob()) {
+      if (!JobKeys.isValid(config.getJob())) {
+        // Job key is set but invalid
+        throw new TaskDescriptionException("Job key " + config.getJob() + " is invalid.");
+      }
+
+      if (!config.getJob().getRole().equals(config.getOwner().getRole())) {
+        // Both owner and job key are set but don't match
+        throw new TaskDescriptionException("Role must match job owner.");
+      }
+    } else {
+      // TODO(maxim): Make sure both key and owner are populated to support older clients.
+      // Remove in 0.7.0. (AURORA-749).
+      // Job key is not set -> populate from owner, environment and name
+      assertOwnerValidity(config.getOwner());
+      builder.setJob(JobKeys.from(
+          config.getOwner().getRole(),
+          config.getEnvironment(),
+          config.getJobName()).newBuilder());
     }
 
     if (!builder.isSetExecutorConfig()) {
@@ -224,7 +276,7 @@ public class ConfigurationManager {
       }
 
       String dedicatedRole = getRole(valueConstraint);
-      if (!config.getJob().getRole().equals(dedicatedRole)) {
+      if (!config.getOwner().getRole().equals(dedicatedRole)) {
         throw new TaskDescriptionException(
             "Only " + dedicatedRole + " may use hosts dedicated for that role.");
       }

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/java/org/apache/aurora/scheduler/storage/db/views/DbTaskConfig.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/storage/db/views/DbTaskConfig.java b/src/main/java/org/apache/aurora/scheduler/storage/db/views/DbTaskConfig.java
index eb848ad..16f2cb1 100644
--- a/src/main/java/org/apache/aurora/scheduler/storage/db/views/DbTaskConfig.java
+++ b/src/main/java/org/apache/aurora/scheduler/storage/db/views/DbTaskConfig.java
@@ -32,6 +32,8 @@ public final class DbTaskConfig {
   private long rowId;
   private JobKey job;
   private Identity owner;
+  private String environment;
+  private String jobName;
   private boolean isService;
   private double numCpus;
   private long ramMb;
@@ -59,6 +61,8 @@ public final class DbTaskConfig {
     return new TaskConfig()
         .setJob(job)
         .setOwner(owner)
+        .setEnvironment(environment)
+        .setJobName(jobName)
         .setIsService(isService)
         .setNumCpus(numCpus)
         .setRamMb(ramMb)

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
index d217faf..6767024 100644
--- a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
+++ b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
@@ -23,6 +23,7 @@ import javax.inject.Inject;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ContiguousSet;
 import com.google.common.collect.DiscreteDomain;
 import com.google.common.collect.FluentIterable;
@@ -452,6 +453,9 @@ class SchedulerThriftInterface implements AnnotatedAuroraAdmin {
       }
 
       query = implicitKillQuery(Query.arbitrary(mutableQuery));
+      Preconditions.checkState(
+          !mutableQuery.isSetOwner(),
+          "The owner field in a query should have been unset by Query.Builder.");
     }
 
     return storage.write(storeProvider -> {
@@ -915,6 +919,12 @@ class SchedulerThriftInterface implements AnnotatedAuroraAdmin {
   public Response startJobUpdate(JobUpdateRequest mutableRequest, @Nullable String message) {
     requireNonNull(mutableRequest);
 
+    // TODO(maxim): Switch to key field instead when AURORA-749 is fixed.
+    IJobKey job = JobKeys.assertValid(IJobKey.build(new JobKey()
+        .setRole(mutableRequest.getTaskConfig().getOwner().getRole())
+        .setEnvironment(mutableRequest.getTaskConfig().getEnvironment())
+        .setName(mutableRequest.getTaskConfig().getJobName())));
+
     if (!mutableRequest.getTaskConfig().isIsService()) {
       return invalidRequest(NON_SERVICE_TASK);
     }
@@ -955,7 +965,6 @@ class SchedulerThriftInterface implements AnnotatedAuroraAdmin {
     }
 
     return storage.write(storeProvider -> {
-      IJobKey job = request.getTaskConfig().getJob();
       if (getCronJob(storeProvider, job).isPresent()) {
         return invalidRequest(NO_CRON);
       }

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/python/apache/aurora/admin/admin.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/admin/admin.py b/src/main/python/apache/aurora/admin/admin.py
index 750b616..b68f546 100644
--- a/src/main/python/apache/aurora/admin/admin.py
+++ b/src/main/python/apache/aurora/admin/admin.py
@@ -79,7 +79,7 @@ def make_admin_client(cluster):
 @app.command_option('--states', dest='states', default='RUNNING',
     help='Only match tasks with given state(s).')
 @app.command_option('-l', '--listformat', dest='listformat',
-    default="%role%/%name%/%instanceId% %status%",
+    default="%role%/%jobName%/%instanceId% %status%",
     help='Format string of job/task items to print out.')
 # TODO(ksweeney): Allow query by environment here.
 def query(args, options):
@@ -273,8 +273,8 @@ def scheduler_print_recovery_tasks(cluster):
   for task in resp.result.queryRecoveryResult.tasks:
     assigned = task.assignedTask
     conf = assigned.task
-    log.info('\t'.join((conf.job.role,
-                        conf.job.name,
+    log.info('\t'.join((conf.job.role if conf.job else conf.owner.role,
+                        conf.job.name if conf.job else conf.jobName,
                         str(assigned.instanceId),
                         ScheduleStatus._VALUES_TO_NAMES[task.status],
                         assigned.taskId)))

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/python/apache/aurora/client/api/sla.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/api/sla.py b/src/main/python/apache/aurora/client/api/sla.py
index e282ec9..5855685 100644
--- a/src/main/python/apache/aurora/client/api/sla.py
+++ b/src/main/python/apache/aurora/client/api/sla.py
@@ -35,9 +35,9 @@ def job_key_from_scheduled(task, cluster):
   config = task.assignedTask.task
   return AuroraJobKey(
       cluster=cluster.name,
-      role=config.job.role,
-      env=config.job.environment,
-      name=config.job.name
+      role=config.job.role if config.job else config.owner.role,
+      env=config.job.environment if config.job else config.environment,
+      name=config.job.name if config.job else config.jobName
   )
 
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/python/apache/aurora/client/cli/jobs.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/jobs.py b/src/main/python/apache/aurora/client/cli/jobs.py
index 67ab4f0..deba3a9 100644
--- a/src/main/python/apache/aurora/client/cli/jobs.py
+++ b/src/main/python/apache/aurora/client/cli/jobs.py
@@ -650,9 +650,9 @@ class StatusCommand(Verb):
       task_info = assigned_task.task
       task_strings = []
       task_strings.append("\tTask role: %s, env: %s, name: %s, instance: %s, status: %s on %s" %
-             (task_info.job.role,
-              task_info.job.environment,
-              task_info.job.name,
+             (task_info.job.role if task_info.job else task_info.owner.role,
+              task_info.job.environment if task_info.job else task_info.environment,
+              task_info.job.name if task_info.job else task_info.jobName,
               assigned_task.instanceId,
               ScheduleStatus._VALUES_TO_NAMES[scheduled_task.status],
               assigned_task.slaveHost))

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/python/apache/aurora/client/cli/task.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/task.py b/src/main/python/apache/aurora/client/cli/task.py
index a8a4edc..b722cd8 100644
--- a/src/main/python/apache/aurora/client/cli/task.py
+++ b/src/main/python/apache/aurora/client/cli/task.py
@@ -124,7 +124,7 @@ class SshCommand(Verb):
     ssh_command = ['ssh', '-t']
     ssh_command += context.options.ssh_options if context.options.ssh_options else []
     assigned = first_task.assignedTask
-    role = assigned.task.job.role
+    role = assigned.task.job.role if assigned.task.job else assigned.task.owner.role
     slave_host = assigned.slaveHost
 
     for tunnel in context.options.tunnels:

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/python/apache/aurora/config/thrift.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/config/thrift.py b/src/main/python/apache/aurora/config/thrift.py
index be0cd68..b40a7fd 100644
--- a/src/main/python/apache/aurora/config/thrift.py
+++ b/src/main/python/apache/aurora/config/thrift.py
@@ -176,7 +176,7 @@ THERMOS_TASK_ID_REF = Ref.from_address('thermos.task_id')
 def convert(job, metadata=frozenset(), ports=frozenset()):
   """Convert a Pystachio MesosJob to an Aurora Thrift JobConfiguration."""
 
-  owner = Identity(user=getpass.getuser())
+  owner = Identity(role=fully_interpolated(job.role()), user=getpass.getuser())
   key = JobKey(
     role=assert_valid_field('role', fully_interpolated(job.role())),
     environment=assert_valid_field('environment', fully_interpolated(job.environment())),
@@ -191,6 +191,8 @@ def convert(job, metadata=frozenset(), ports=frozenset()):
     return default if item is Empty else fully_interpolated(item)
 
   # job components
+  task.jobName = fully_interpolated(job.name())
+  task.environment = fully_interpolated(job.environment())
   task.production = fully_interpolated(job.production(), bool)
   task.isService = select_service_bit(job)
   task.maxTaskFailures = fully_interpolated(job.max_task_failures())

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/python/apache/aurora/executor/common/announcer.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/executor/common/announcer.py b/src/main/python/apache/aurora/executor/common/announcer.py
index 34e36e0..c89cf4c 100644
--- a/src/main/python/apache/aurora/executor/common/announcer.py
+++ b/src/main/python/apache/aurora/executor/common/announcer.py
@@ -121,7 +121,10 @@ class DefaultAnnouncerCheckerProvider(AnnouncerCheckerProvider):
 
   def make_zk_path(self, assigned_task):
     config = assigned_task.task
-    role, environment, name = (config.job.role, config.job.environment, config.job.name)
+    role, environment, name = (
+        config.job.role if config.job else config.owner.role,
+        config.job.environment if config.job else config.environment,
+        config.job.name if config.job else config.jobName)
     return posixpath.join(self.__root, role, environment, name)
 
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/python/apache/aurora/executor/common/sandbox.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/executor/common/sandbox.py b/src/main/python/apache/aurora/executor/common/sandbox.py
index 4780232..d4c366e 100644
--- a/src/main/python/apache/aurora/executor/common/sandbox.py
+++ b/src/main/python/apache/aurora/executor/common/sandbox.py
@@ -51,7 +51,7 @@ class SandboxInterface(Interface):
 
 class SandboxProvider(Interface):
   def _get_sandbox_user(self, assigned_task):
-    return assigned_task.task.job.role
+    return assigned_task.task.job.role if assigned_task.task.job else assigned_task.task.owner.role
 
   @abstractmethod
   def from_assigned_task(self, assigned_task):

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/resources/org/apache/aurora/scheduler/storage/db/CronJobMapper.xml
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/aurora/scheduler/storage/db/CronJobMapper.xml b/src/main/resources/org/apache/aurora/scheduler/storage/db/CronJobMapper.xml
index 1434f45..ee603f4 100644
--- a/src/main/resources/org/apache/aurora/scheduler/storage/db/CronJobMapper.xml
+++ b/src/main/resources/org/apache/aurora/scheduler/storage/db/CronJobMapper.xml
@@ -65,6 +65,7 @@
       type="org.apache.aurora.scheduler.storage.db.views.DbJobConfiguration">
 
     <id column="c_id" />
+    <result property="owner.role" column="j_role"/>
     <result property="owner.user" column="creator_user"/>
     <result
         property="cronCollisionPolicy"

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml b/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml
index b1394cf..4e8966d 100644
--- a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml
+++ b/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml
@@ -128,6 +128,9 @@
 
   <resultMap id="taskConfigMap" type="org.apache.aurora.scheduler.storage.db.views.DbTaskConfig">
     <id column="id" property="rowId" />
+    <result column="j_role" property="owner.role"/>
+    <result column="j_environment" property="environment"/>
+    <result column="j_name" property="jobName"/>
     <result column="creator_user" property="owner.user"/>
     <result column="executor_name" property="executorConfig.name"/>
     <result column="executor_data" property="executorConfig.data"/>

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml b/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml
index ae52c40..db6c642 100644
--- a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml
+++ b/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml
@@ -121,6 +121,9 @@
       <if test="role != null">
         j.role = #{role}
       </if>
+      <if test="owner != null and owner.role != null">
+        AND j.role = #{owner.role}
+      </if>
       <if test="environment != null">
         AND j.environment = #{environment}
       </if>

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/resources/scheduler/assets/js/controllers.js
----------------------------------------------------------------------
diff --git a/src/main/resources/scheduler/assets/js/controllers.js b/src/main/resources/scheduler/assets/js/controllers.js
index 84417eb..dff6645 100644
--- a/src/main/resources/scheduler/assets/js/controllers.js
+++ b/src/main/resources/scheduler/assets/js/controllers.js
@@ -133,7 +133,7 @@
             return {
               role: $scope.role, // required for roleEnvLink directive
               environment: summary.job.key.environment,
-              jobName: summary.job.key.name,
+              jobName: summary.job.taskConfig.jobName,
               jobType: getJobType(summary.job),
               isProduction: summary.job.taskConfig.production ? 'yes' : '',
               pendingTasks: summary.stats.pendingTaskCount,

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/main/resources/scheduler/assets/js/services.js
----------------------------------------------------------------------
diff --git a/src/main/resources/scheduler/assets/js/services.js b/src/main/resources/scheduler/assets/js/services.js
index d9ce520..f9e8580 100644
--- a/src/main/resources/scheduler/assets/js/services.js
+++ b/src/main/resources/scheduler/assets/js/services.js
@@ -17,6 +17,7 @@
     ACTIVE_STATES:false,
     ACTIVE_JOB_UPDATE_STATES: false,
     CronCollisionPolicy: false,
+    Identity:false,
     JobKey: false,
     JobUpdateQuery:false,
     JobUpdateAction:false,
@@ -28,8 +29,10 @@
   'use strict';
 
   function makeJobTaskQuery(role, environment, jobName, instance) {
+    var id = new Identity();
+    id.role = role;
     var taskQuery = new TaskQuery();
-    taskQuery.role = role;
+    taskQuery.owner = id;
     taskQuery.environment = environment;
     taskQuery.jobName = jobName;
 
@@ -85,6 +88,23 @@
             });
           },
 
+          getTasks: function (role, environment, jobName) {
+            var id = new Identity();
+            id.role = role;
+            var taskQuery = new TaskQuery();
+            taskQuery.owner = id;
+            taskQuery.environment = environment;
+            taskQuery.jobName = jobName;
+            return async(function (deferred) {
+              auroraClient.getSchedulerClient().getTasksStatus(taskQuery, function (response) {
+                var result = auroraClient.processResponse(response);
+                result.tasks = response.result !== null ?
+                  response.result.scheduleStatusResult.tasks : [];
+                deferred.resolve(result);
+              });
+            });
+          },
+
           getTasksWithoutConfigs: function (role, environment, jobName, instance) {
             var query = makeJobTaskQuery(role, environment, jobName, instance);
 
@@ -491,7 +511,7 @@
                   var job = summary.job;
                   return job.cronSchedule !== null &&
                     job.key.environment === env &&
-                    job.key.name === jobName;
+                    job.taskConfig.jobName === jobName;
                 })
                 .map(function (summary) {
                   var collisionPolicy =

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/configuration/ConfigurationManagerTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/configuration/ConfigurationManagerTest.java b/src/test/java/org/apache/aurora/scheduler/configuration/ConfigurationManagerTest.java
index d2789d0..317506e 100644
--- a/src/test/java/org/apache/aurora/scheduler/configuration/ConfigurationManagerTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/configuration/ConfigurationManagerTest.java
@@ -13,9 +13,9 @@
  */
 package org.apache.aurora.scheduler.configuration;
 
+import java.util.Arrays;
 import java.util.List;
 
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.ImmutableSet;
@@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableSet;
 import org.apache.aurora.gen.Constraint;
 import org.apache.aurora.gen.Container;
 import org.apache.aurora.gen.CronCollisionPolicy;
+import org.apache.aurora.gen.DockerContainer;
 import org.apache.aurora.gen.DockerParameter;
 import org.apache.aurora.gen.ExecutorConfig;
 import org.apache.aurora.gen.Identity;
@@ -32,8 +33,6 @@ import org.apache.aurora.gen.LimitConstraint;
 import org.apache.aurora.gen.TaskConfig;
 import org.apache.aurora.gen.TaskConstraint;
 import org.apache.aurora.gen.ValueConstraint;
-import org.apache.aurora.scheduler.base.JobKeys;
-import org.apache.aurora.scheduler.base.TaskTestUtil;
 import org.apache.aurora.scheduler.configuration.ConfigurationManager.TaskDescriptionException;
 import org.apache.aurora.scheduler.storage.entities.IDockerParameter;
 import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
@@ -70,7 +69,9 @@ public class ConfigurationManagerTest {
               .setIsService(false)
               .setTaskLinks(ImmutableMap.of())
               .setExecutorConfig(new ExecutorConfig("aurora", "config"))
+              .setEnvironment("devel")
               .setRequestedPorts(ImmutableSet.of())
+              .setJobName(null)
               .setPriority(0)
               .setOwner(null)
               .setContactEmail("foo@twitter.com")
@@ -96,9 +97,19 @@ public class ConfigurationManagerTest {
                           .setName(DEDICATED_ATTRIBUTE)
                           .setConstraint(TaskConstraint.value(new ValueConstraint(
                               false, ImmutableSet.of("foo"))))))
-              .setOwner(new Identity().setUser("owner-user")));
-  private static final ITaskConfig CONFIG_WITH_CONTAINER =
-      TaskTestUtil.makeConfig(JobKeys.from("role", "env", "job"));
+              .setOwner(new Identity()
+                  .setRole("owner-role")
+                  .setUser("owner-user")));
+  private static final TaskConfig CONFIG_WITH_CONTAINER = ITaskConfig.build(new TaskConfig()
+      .setJobName("container-test")
+      .setEnvironment("devel")
+      .setExecutorConfig(new ExecutorConfig())
+      .setOwner(new Identity("role", "user"))
+      .setNumCpus(1)
+      .setRamMb(1)
+      .setDiskMb(1)
+      .setContainer(Container.docker(new DockerContainer("testimage"))))
+      .newBuilder();
 
   private ConfigurationManager configurationManager;
   private ConfigurationManager dockerConfigurationManager;
@@ -124,7 +135,7 @@ public class ConfigurationManagerTest {
 
   @Test
   public void testBadContainerConfig() throws TaskDescriptionException {
-    TaskConfig taskConfig = CONFIG_WITH_CONTAINER.newBuilder();
+    TaskConfig taskConfig = CONFIG_WITH_CONTAINER.deepCopy();
     taskConfig.getContainer().getDocker().setImage(null);
 
     expectTaskDescriptionException("A container must specify an image");
@@ -133,7 +144,7 @@ public class ConfigurationManagerTest {
 
   @Test
   public void testDisallowedDockerParameters() throws TaskDescriptionException {
-    TaskConfig taskConfig = CONFIG_WITH_CONTAINER.newBuilder();
+    TaskConfig taskConfig = CONFIG_WITH_CONTAINER.deepCopy();
     taskConfig.getContainer().getDocker().addToParameters(new DockerParameter("foo", "bar"));
 
     ConfigurationManager noParamsManager = new ConfigurationManager(
@@ -146,6 +157,8 @@ public class ConfigurationManagerTest {
   @Test
   public void testInvalidTier() throws TaskDescriptionException {
     ITaskConfig config = ITaskConfig.build(UNSANITIZED_JOB_CONFIGURATION.deepCopy().getTaskConfig()
+        .setJobName("job")
+        .setEnvironment("env")
         .setTier("pr/d"));
 
     expectTaskDescriptionException("Tier contains illegal characters");
@@ -154,20 +167,18 @@ public class ConfigurationManagerTest {
 
   @Test
   public void testDefaultDockerParameters() throws TaskDescriptionException {
-    TaskConfig builder = CONFIG_WITH_CONTAINER.newBuilder();
-    builder.getContainer().getDocker().setParameters(ImmutableList.of());
-
-    ITaskConfig result = dockerConfigurationManager.validateAndPopulate(ITaskConfig.build(builder));
+    ITaskConfig result = dockerConfigurationManager.validateAndPopulate(
+        ITaskConfig.build(CONFIG_WITH_CONTAINER.deepCopy()));
 
     // The resulting task config should contain parameters supplied to the ConfigurationManager.
     List<IDockerParameter> params = result.getContainer().getDocker().getParameters();
     assertThat(
-        params, is(ImmutableList.of(IDockerParameter.build(new DockerParameter("foo", "bar")))));
+        params, is(Arrays.asList(IDockerParameter.build(new DockerParameter("foo", "bar")))));
   }
 
   @Test
   public void testPassthroughDockerParameters() throws TaskDescriptionException {
-    TaskConfig taskConfig = CONFIG_WITH_CONTAINER.newBuilder();
+    TaskConfig taskConfig = CONFIG_WITH_CONTAINER.deepCopy();
     DockerParameter userParameter = new DockerParameter("bar", "baz");
     taskConfig.getContainer().getDocker().getParameters().clear();
     taskConfig.getContainer().getDocker().addToParameters(userParameter);
@@ -177,7 +188,8 @@ public class ConfigurationManagerTest {
 
     // The resulting task config should contain parameters supplied from user config.
     List<IDockerParameter> params = result.getContainer().getDocker().getParameters();
-    assertThat(params, is(ImmutableList.of(IDockerParameter.build(userParameter))));
+    assertThat(
+        params, is(Arrays.asList(IDockerParameter.build(userParameter))));
   }
 
   private void expectTaskDescriptionException(String message) {

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronIT.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronIT.java b/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronIT.java
index 469b53b..3ce78e3 100644
--- a/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronIT.java
+++ b/src/test/java/org/apache/aurora/scheduler/cron/quartz/CronIT.java
@@ -57,7 +57,9 @@ public class CronIT extends EasyMockTest {
   public static final CrontabEntry CRONTAB_ENTRY = CrontabEntry.parse("* * * * *");
 
   private static final IJobKey JOB_KEY = JobKeys.from("roll", "b", "c");
-  private static final Identity IDENTITY = new Identity().setUser("user");
+  private static final Identity IDENTITY = new Identity()
+      .setRole(JOB_KEY.getRole())
+      .setUser("user");
 
   private static final IJobConfiguration CRON_JOB = IJobConfiguration.build(
       new JobConfiguration()

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/cron/quartz/QuartzTestUtil.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/cron/quartz/QuartzTestUtil.java b/src/test/java/org/apache/aurora/scheduler/cron/quartz/QuartzTestUtil.java
index 3c5ecd6..ef9aae1 100644
--- a/src/test/java/org/apache/aurora/scheduler/cron/quartz/QuartzTestUtil.java
+++ b/src/test/java/org/apache/aurora/scheduler/cron/quartz/QuartzTestUtil.java
@@ -38,7 +38,7 @@ final class QuartzTestUtil {
       new JobConfiguration()
           .setCronSchedule("* * * * SUN")
           .setInstanceCount(10)
-          .setOwner(new Identity().setUser("user"))
+          .setOwner(new Identity("role", "user"))
           .setKey(AURORA_JOB_KEY.newBuilder())
           .setTaskConfig(TaskTestUtil.makeConfig(AURORA_JOB_KEY)
               .newBuilder()

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java b/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java
index b6f5e46..ef20641 100644
--- a/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java
@@ -13,6 +13,7 @@
  */
 package org.apache.aurora.scheduler.preemptor;
 
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -20,13 +21,13 @@ import com.google.common.base.Optional;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 
 import org.apache.aurora.common.quantity.Amount;
 import org.apache.aurora.common.quantity.Data;
 import org.apache.aurora.common.testing.easymock.EasyMockTest;
 import org.apache.aurora.gen.AssignedTask;
 import org.apache.aurora.gen.Attribute;
+import org.apache.aurora.gen.Constraint;
 import org.apache.aurora.gen.HostAttributes;
 import org.apache.aurora.gen.JobKey;
 import org.apache.aurora.gen.ScheduleStatus;
@@ -549,7 +550,9 @@ public class PreemptionVictimFilterTest extends EasyMockTest {
             .setJob(new JobKey(role, env, job))
             .setPriority(priority)
             .setProduction(production)
-            .setConstraints(Sets.newHashSet()));
+            .setJobName(job)
+            .setEnvironment(env)
+            .setConstraints(new HashSet<Constraint>()));
     return new ScheduledTask().setAssignedTask(assignedTask);
   }
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/storage/AbstractCronJobStoreTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/storage/AbstractCronJobStoreTest.java b/src/test/java/org/apache/aurora/scheduler/storage/AbstractCronJobStoreTest.java
index c316e49..22a6b43 100644
--- a/src/test/java/org/apache/aurora/scheduler/storage/AbstractCronJobStoreTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/storage/AbstractCronJobStoreTest.java
@@ -138,7 +138,7 @@ public abstract class AbstractCronJobStoreTest {
         IJobConfiguration.build(
             new JobConfiguration()
                 .setKey(job.newBuilder())
-                .setOwner(new Identity().setUser("user"))
+                .setOwner(new Identity(job.getRole(), "user"))
                 .setCronSchedule("schedule")
                 .setCronCollisionPolicy(CronCollisionPolicy.CANCEL_NEW)
                 .setTaskConfig(config.newBuilder())

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/storage/log/LogManagerTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/storage/log/LogManagerTest.java b/src/test/java/org/apache/aurora/scheduler/storage/log/LogManagerTest.java
index 0256c06..0443bb3 100644
--- a/src/test/java/org/apache/aurora/scheduler/storage/log/LogManagerTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/storage/log/LogManagerTest.java
@@ -39,7 +39,9 @@ import org.apache.aurora.common.testing.easymock.EasyMockTest;
 import org.apache.aurora.gen.AssignedTask;
 import org.apache.aurora.gen.Attribute;
 import org.apache.aurora.gen.HostAttributes;
+import org.apache.aurora.gen.ScheduleStatus;
 import org.apache.aurora.gen.ScheduledTask;
+import org.apache.aurora.gen.TaskConfig;
 import org.apache.aurora.gen.storage.DeduplicatedSnapshot;
 import org.apache.aurora.gen.storage.Frame;
 import org.apache.aurora.gen.storage.FrameChunk;
@@ -54,7 +56,6 @@ import org.apache.aurora.gen.storage.Snapshot;
 import org.apache.aurora.gen.storage.Transaction;
 import org.apache.aurora.gen.storage.storageConstants;
 import org.apache.aurora.scheduler.base.JobKeys;
-import org.apache.aurora.scheduler.base.TaskTestUtil;
 import org.apache.aurora.scheduler.log.Log.Entry;
 import org.apache.aurora.scheduler.log.Log.Position;
 import org.apache.aurora.scheduler.log.Log.Stream;
@@ -513,7 +514,10 @@ public class LogManagerTest extends EasyMockTest {
         .setTimestamp(1L)
         .setHostAttributes(ImmutableSet.of(new HostAttributes("host",
             ImmutableSet.of(new Attribute("hostname", ImmutableSet.of("abc"))))))
-        .setTasks(ImmutableSet.of(TaskTestUtil.makeTask("task_id", TaskTestUtil.JOB).newBuilder()));
+        .setTasks(ImmutableSet.of(
+            new ScheduledTask().setStatus(ScheduleStatus.RUNNING)
+                .setAssignedTask(new AssignedTask().setTaskId("task_id")
+                    .setTask(new TaskConfig().setJobName("job_name")))));
   }
 
   private SaveTasks createSaveTasks(String... taskIds) {

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/thrift/Fixtures.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/thrift/Fixtures.java b/src/test/java/org/apache/aurora/scheduler/thrift/Fixtures.java
index be98f38..e456056 100644
--- a/src/test/java/org/apache/aurora/scheduler/thrift/Fixtures.java
+++ b/src/test/java/org/apache/aurora/scheduler/thrift/Fixtures.java
@@ -62,7 +62,7 @@ import static org.junit.Assert.assertEquals;
 final class Fixtures {
   static final String ROLE = "bar_role";
   static final String USER = "foo_user";
-  static final Identity IDENTITY = new Identity().setUser(USER);
+  static final Identity ROLE_IDENTITY = new Identity(ROLE, USER);
   static final String JOB_NAME = "job_foo";
   static final IJobKey JOB_KEY = JobKeys.from(ROLE, "devel", JOB_NAME);
   static final ILockKey LOCK_KEY = ILockKey.build(LockKey.job(JOB_KEY.newBuilder()));
@@ -94,7 +94,7 @@ final class Fixtures {
 
   static JobConfiguration makeJob(TaskConfig task, int shardCount) {
     return new JobConfiguration()
-        .setOwner(IDENTITY)
+        .setOwner(ROLE_IDENTITY)
         .setInstanceCount(shardCount)
         .setTaskConfig(task)
         .setKey(JOB_KEY.newBuilder());
@@ -103,7 +103,9 @@ final class Fixtures {
   static TaskConfig defaultTask(boolean production) {
     return new TaskConfig()
         .setJob(JOB_KEY.newBuilder())
-        .setOwner(IDENTITY)
+        .setOwner(new Identity(ROLE, USER))
+        .setEnvironment("devel")
+        .setJobName(JOB_NAME)
         .setContactEmail("testing@twitter.com")
         .setExecutorConfig(new ExecutorConfig("aurora", "data"))
         .setNumCpus(1)

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java b/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java
index 3ba0342..0428c77 100644
--- a/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java
@@ -98,11 +98,11 @@ import static org.apache.aurora.scheduler.base.Numbers.convertRanges;
 import static org.apache.aurora.scheduler.base.Numbers.toRanges;
 import static org.apache.aurora.scheduler.thrift.Fixtures.CRON_JOB;
 import static org.apache.aurora.scheduler.thrift.Fixtures.CRON_SCHEDULE;
-import static org.apache.aurora.scheduler.thrift.Fixtures.IDENTITY;
 import static org.apache.aurora.scheduler.thrift.Fixtures.JOB_KEY;
 import static org.apache.aurora.scheduler.thrift.Fixtures.LOCK;
 import static org.apache.aurora.scheduler.thrift.Fixtures.QUOTA;
 import static org.apache.aurora.scheduler.thrift.Fixtures.ROLE;
+import static org.apache.aurora.scheduler.thrift.Fixtures.ROLE_IDENTITY;
 import static org.apache.aurora.scheduler.thrift.Fixtures.UPDATE_KEY;
 import static org.apache.aurora.scheduler.thrift.Fixtures.USER;
 import static org.apache.aurora.scheduler.thrift.Fixtures.assertOkResponse;
@@ -148,21 +148,27 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest {
   @Test
   public void testGetJobSummary() throws Exception {
     long nextCronRunMs = 100;
-    TaskConfig ownedCronJobTask = nonProductionTask().setJob(JOB_KEY.newBuilder());
+    TaskConfig ownedCronJobTask = nonProductionTask()
+        .setJob(JOB_KEY.newBuilder())
+        .setJobName(JOB_KEY.getName())
+        .setOwner(ROLE_IDENTITY)
+        .setEnvironment(JOB_KEY.getEnvironment());
     JobConfiguration ownedCronJob = makeJob()
         .setCronSchedule(CRON_SCHEDULE)
         .setTaskConfig(ownedCronJobTask);
     IScheduledTask ownedCronJobScheduledTask = IScheduledTask.build(new ScheduledTask()
         .setAssignedTask(new AssignedTask().setTask(ownedCronJobTask))
         .setStatus(ScheduleStatus.ASSIGNED));
-    Identity otherOwner = new Identity().setUser("other");
+    Identity otherOwner = new Identity("other", "other");
     JobConfiguration unownedCronJob = makeJob()
         .setOwner(otherOwner)
         .setCronSchedule(CRON_SCHEDULE)
         .setKey(JOB_KEY.newBuilder().setRole("other"))
         .setTaskConfig(ownedCronJobTask.deepCopy().setOwner(otherOwner));
     TaskConfig ownedImmediateTaskInfo = defaultTask(false)
-        .setJob(JOB_KEY.newBuilder().setName("immediate"));
+        .setJob(JOB_KEY.newBuilder().setName("immediate"))
+        .setJobName("immediate")
+        .setOwner(ROLE_IDENTITY);
     Set<JobConfiguration> ownedCronJobOnly = ImmutableSet.of(ownedCronJob);
     Set<JobSummary> ownedCronJobSummaryOnly = ImmutableSet.of(
         new JobSummary()
@@ -182,7 +188,7 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest {
         .setStatus(ScheduleStatus.ASSIGNED));
     JobConfiguration ownedImmediateJob = new JobConfiguration()
         .setKey(JOB_KEY.newBuilder().setName("immediate"))
-        .setOwner(IDENTITY)
+        .setOwner(ROLE_IDENTITY)
         .setInstanceCount(1)
         .setTaskConfig(ownedImmediateTaskInfo);
     Builder query = Query.roleScoped(ROLE);
@@ -237,8 +243,9 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest {
     String cronSchedule = "* * 31 2 *";
 
     TaskConfig task = nonProductionTask()
-        .setJob(JOB_KEY.newBuilder())
-        .setOwner(IDENTITY);
+        .setJobName(JOB_KEY.getName())
+        .setOwner(ROLE_IDENTITY)
+        .setEnvironment(JOB_KEY.getEnvironment());
     JobConfiguration job = makeJob()
         .setCronSchedule(cronSchedule)
         .setTaskConfig(task);
@@ -386,13 +393,15 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest {
         .setKey(jobKey2)
         .setTaskConfig(nonProductionTask());
     TaskConfig immediateTaskConfig = defaultTask(false)
-        .setJob(JOB_KEY.newBuilder().setName("immediate"));
+        .setJob(JOB_KEY.newBuilder().setName("immediate"))
+        .setJobName("immediate")
+        .setOwner(ROLE_IDENTITY);
     IScheduledTask immediateTask = IScheduledTask.build(new ScheduledTask()
         .setAssignedTask(new AssignedTask().setTask(immediateTaskConfig))
         .setStatus(ScheduleStatus.ASSIGNED));
     JobConfiguration immediateJob = new JobConfiguration()
         .setKey(JOB_KEY.newBuilder().setName("immediate"))
-        .setOwner(IDENTITY)
+        .setOwner(ROLE_IDENTITY)
         .setInstanceCount(1)
         .setTaskConfig(immediateTaskConfig);
 
@@ -412,21 +421,26 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest {
 
   @Test
   public void testGetJobs() throws Exception {
-    TaskConfig ownedCronJobTask = nonProductionTask();
+    TaskConfig ownedCronJobTask = nonProductionTask()
+        .setJobName(JOB_KEY.getName())
+        .setOwner(ROLE_IDENTITY)
+        .setEnvironment(JOB_KEY.getEnvironment());
     JobConfiguration ownedCronJob = makeJob()
         .setCronSchedule(CRON_SCHEDULE)
         .setTaskConfig(ownedCronJobTask);
     IScheduledTask ownedCronJobScheduledTask = IScheduledTask.build(new ScheduledTask()
         .setAssignedTask(new AssignedTask().setTask(ownedCronJobTask))
         .setStatus(ScheduleStatus.ASSIGNED));
-    Identity otherOwner = new Identity().setUser("other");
+    Identity otherOwner = new Identity("other", "other");
     JobConfiguration unownedCronJob = makeJob()
         .setOwner(otherOwner)
         .setCronSchedule(CRON_SCHEDULE)
         .setKey(JOB_KEY.newBuilder().setRole("other"))
         .setTaskConfig(ownedCronJobTask.deepCopy().setOwner(otherOwner));
     TaskConfig ownedImmediateTaskInfo = defaultTask(false)
-        .setJob(JOB_KEY.newBuilder().setName("immediate"));
+        .setJob(JOB_KEY.newBuilder().setName("immediate"))
+        .setJobName("immediate")
+        .setOwner(ROLE_IDENTITY);
     Set<JobConfiguration> ownedCronJobOnly = ImmutableSet.of(ownedCronJob);
     Set<JobConfiguration> unownedCronJobOnly = ImmutableSet.of(unownedCronJob);
     Set<JobConfiguration> bothCronJobs = ImmutableSet.of(ownedCronJob, unownedCronJob);
@@ -435,7 +449,7 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest {
         .setStatus(ScheduleStatus.ASSIGNED));
     JobConfiguration ownedImmediateJob = new JobConfiguration()
         .setKey(JOB_KEY.newBuilder().setName("immediate"))
-        .setOwner(IDENTITY)
+        .setOwner(ROLE_IDENTITY)
         .setInstanceCount(1)
         .setTaskConfig(ownedImmediateTaskInfo);
     Query.Builder query = Query.roleScoped(ROLE).active();
@@ -635,8 +649,8 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest {
 
   @Test
   public void testGetRoleSummary() throws Exception {
-    String bazRole = "baz_role";
-    Identity bazRoleIdentity = new Identity().setUser(USER);
+    final String BAZ_ROLE = "baz_role";
+    final Identity BAZ_ROLE_IDENTITY = new Identity(BAZ_ROLE, USER);
 
     JobConfiguration cronJobOne = makeJob()
         .setCronSchedule("1 * * * *")
@@ -649,28 +663,32 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest {
 
     JobConfiguration cronJobThree = makeJob()
         .setCronSchedule("3 * * * *")
-        .setKey(JOB_KEY.newBuilder().setRole(bazRole))
+        .setKey(JOB_KEY.newBuilder().setRole(BAZ_ROLE))
         .setTaskConfig(nonProductionTask())
-        .setOwner(bazRoleIdentity);
+        .setOwner(BAZ_ROLE_IDENTITY);
 
     Set<JobConfiguration> crons = ImmutableSet.of(cronJobOne, cronJobTwo, cronJobThree);
 
     TaskConfig immediateTaskConfig = defaultTask(false)
-        .setJob(JOB_KEY.newBuilder().setName("immediate"));
+        .setJob(JOB_KEY.newBuilder().setName("immediate"))
+        .setJobName("immediate")
+        .setOwner(ROLE_IDENTITY);
     IScheduledTask task1 = IScheduledTask.build(new ScheduledTask()
         .setAssignedTask(new AssignedTask().setTask(immediateTaskConfig)));
     IScheduledTask task2 = IScheduledTask.build(new ScheduledTask()
         .setAssignedTask(new AssignedTask().setTask(immediateTaskConfig.setNumCpus(2))));
 
     TaskConfig immediateTaskConfigTwo = defaultTask(false)
-        .setJob(JOB_KEY.newBuilder().setRole(bazRole).setName("immediateTwo"))
-        .setOwner(bazRoleIdentity);
+        .setJob(JOB_KEY.newBuilder().setRole(BAZ_ROLE_IDENTITY.getRole()).setName("immediateTwo"))
+        .setJobName("immediateTwo")
+        .setOwner(BAZ_ROLE_IDENTITY);
     IScheduledTask task3 = IScheduledTask.build(new ScheduledTask()
         .setAssignedTask(new AssignedTask().setTask(immediateTaskConfigTwo)));
 
     TaskConfig immediateTaskConfigThree = defaultTask(false)
-        .setJob(JOB_KEY.newBuilder().setRole(bazRole).setName("immediateThree"))
-        .setOwner(bazRoleIdentity);
+        .setJob(JOB_KEY.newBuilder().setRole(BAZ_ROLE_IDENTITY.getRole()).setName("immediateThree"))
+        .setJobName("immediateThree")
+        .setOwner(BAZ_ROLE_IDENTITY);
     IScheduledTask task4 = IScheduledTask.build(new ScheduledTask()
         .setAssignedTask(new AssignedTask().setTask(immediateTaskConfigThree)));
 
@@ -684,7 +702,7 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest {
     expectedResult.addToSummaries(
         new RoleSummary().setRole(ROLE).setCronJobCount(2).setJobCount(1));
     expectedResult.addToSummaries(
-        new RoleSummary().setRole(bazRole).setCronJobCount(1).setJobCount(2));
+        new RoleSummary().setRole(BAZ_ROLE).setCronJobCount(1).setJobCount(2));
 
     control.replay();
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java b/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
index c774ac0..4ad9211 100644
--- a/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
@@ -126,7 +126,6 @@ import static org.apache.aurora.scheduler.configuration.ConfigurationManager.DED
 import static org.apache.aurora.scheduler.storage.backup.Recovery.RecoveryException;
 import static org.apache.aurora.scheduler.thrift.Fixtures.CRON_JOB;
 import static org.apache.aurora.scheduler.thrift.Fixtures.ENOUGH_QUOTA;
-import static org.apache.aurora.scheduler.thrift.Fixtures.IDENTITY;
 import static org.apache.aurora.scheduler.thrift.Fixtures.INSTANCE_KEY;
 import static org.apache.aurora.scheduler.thrift.Fixtures.INVALID_TASK_CONFIG;
 import static org.apache.aurora.scheduler.thrift.Fixtures.JOB_KEY;
@@ -135,6 +134,7 @@ import static org.apache.aurora.scheduler.thrift.Fixtures.LOCK;
 import static org.apache.aurora.scheduler.thrift.Fixtures.LOCK_KEY;
 import static org.apache.aurora.scheduler.thrift.Fixtures.NOT_ENOUGH_QUOTA;
 import static org.apache.aurora.scheduler.thrift.Fixtures.ROLE;
+import static org.apache.aurora.scheduler.thrift.Fixtures.ROLE_IDENTITY;
 import static org.apache.aurora.scheduler.thrift.Fixtures.TASK_ID;
 import static org.apache.aurora.scheduler.thrift.Fixtures.UPDATE_KEY;
 import static org.apache.aurora.scheduler.thrift.Fixtures.USER;
@@ -255,6 +255,10 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
 
   @Test
   public void testCreateJobNoLock() throws Exception {
+    // Validate key is populated during sanitizing.
+    JobConfiguration jobConfig = makeProdJob();
+    jobConfig.getTaskConfig().unsetJob();
+
     IJobConfiguration job = IJobConfiguration.build(makeProdJob());
     SanitizedConfiguration sanitized = fromUnsanitized(job);
     lockManager.validateIfLocked(LOCK_KEY, java.util.Optional.empty());
@@ -271,7 +275,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
 
     control.replay();
 
-    assertOkResponse(thrift.createJob(makeProdJob(), null));
+    assertOkResponse(thrift.createJob(jobConfig, null));
   }
 
   @Test
@@ -415,7 +419,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
     control.replay();
 
     JobConfiguration job =
-        new JobConfiguration().setKey(JOB_KEY.newBuilder()).setOwner(IDENTITY);
+        new JobConfiguration().setKey(JOB_KEY.newBuilder()).setOwner(ROLE_IDENTITY);
     assertResponse(INVALID_REQUEST, thrift.createJob(job, null));
   }
 
@@ -497,9 +501,10 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
         .setDiskMb(1024)
         .setIsService(true)
         .setProduction(true)
-        .setOwner(IDENTITY)
+        .setOwner(ROLE_IDENTITY)
+        .setEnvironment("devel")
         .setContainer(Container.mesos(new MesosContainer()))
-        .setJob(JOB_KEY.newBuilder());
+        .setJobName(JOB_NAME);
     JobConfiguration job = makeJob(task);
 
     JobConfiguration sanitized = job.deepCopy();
@@ -514,7 +519,8 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
         .setRequestedPorts(ImmutableSet.of())
         .setTaskLinks(ImmutableMap.of())
         .setConstraints(ImmutableSet.of())
-        .setMaxTaskFailures(0);
+        .setMaxTaskFailures(0)
+        .setEnvironment("devel");
 
     lockManager.validateIfLocked(LOCK_KEY, java.util.Optional.empty());
     storageUtil.expectTaskFetch(Query.jobScoped(JOB_KEY).active());
@@ -584,7 +590,9 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
             .setInstanceId(0)
             .setTask(new TaskConfig()
                 .setJob(JOB_KEY.newBuilder().setName(jobName))
-                .setOwner(IDENTITY))));
+                .setOwner(ROLE_IDENTITY)
+                .setEnvironment("devel")
+                .setJobName(jobName))));
   }
 
   private void expectTransitionsToKilling() {
@@ -670,7 +678,9 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
 
   @Test
   public void testKillTasksInvalidJobName() throws Exception {
-    TaskQuery query = new TaskQuery().setJobName("");
+    TaskQuery query = new TaskQuery()
+        .setOwner(ROLE_IDENTITY)
+        .setJobName("");
 
     control.replay();
 
@@ -864,7 +874,10 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
     cronJobManager.updateJob(anyObject(SanitizedCronJob.class));
     control.replay();
 
-    assertOkResponse(thrift.replaceCronTemplate(CRON_JOB, null));
+    // Validate key is populated during sanitizing.
+    JobConfiguration jobConfig = CRON_JOB;
+    jobConfig.getTaskConfig().unsetJob();
+    assertOkResponse(thrift.replaceCronTemplate(jobConfig, null));
   }
 
   @Test
@@ -953,7 +966,10 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
     cronJobManager.updateJob(SanitizedCronJob.from(sanitized));
     control.replay();
 
-    assertResponse(OK, thrift.scheduleCronJob(CRON_JOB, null));
+    // Validate key is populated during sanitizing.
+    JobConfiguration jobConfig = CRON_JOB;
+    jobConfig.getTaskConfig().unsetJob();
+    assertResponse(OK, thrift.scheduleCronJob(jobConfig, null));
   }
 
   @Test
@@ -1065,7 +1081,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
 
     IJobConfiguration job = IJobConfiguration.build(makeJob());
     JobKey rewrittenJobKey = JobKeys.from("a", "b", "c").newBuilder();
-    Identity rewrittenIdentity = new Identity().setUser("steve");
+    Identity rewrittenIdentity = new Identity(rewrittenJobKey.getRole(), "steve");
     RewriteConfigsRequest request = new RewriteConfigsRequest(
         ImmutableList.of(ConfigRewrite.jobRewrite(new JobConfigRewrite(
             job.newBuilder(),
@@ -1084,7 +1100,12 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
         storedConfig.deepCopy().setExecutorConfig(new ExecutorConfig("aurora", "rewritten"));
     IScheduledTask storedTask = IScheduledTask.build(
         new ScheduledTask().setAssignedTask(new AssignedTask().setTask(storedConfig)));
-    InstanceKey instance = new InstanceKey(storedConfig.getJob(), 0);
+    InstanceKey instance = new InstanceKey(
+        JobKeys.from(
+            storedConfig.getOwner().getRole(),
+            storedConfig.getEnvironment(),
+            storedConfig.getJobName()).newBuilder(),
+        0);
 
     storageUtil.expectTaskFetch(
         Query.instanceScoped(IInstanceKey.build(instance)).active(), storedTask);
@@ -1107,7 +1128,12 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
         new AssignedTask()
             .setTaskId(taskId)
             .setTask(storedConfig)));
-    InstanceKey instanceKey = new InstanceKey(storedConfig.getJob(), 0);
+    InstanceKey instanceKey = new InstanceKey(
+        JobKeys.from(
+            storedConfig.getOwner().getRole(),
+            storedConfig.getEnvironment(),
+            storedConfig.getJobName()).newBuilder(),
+        0);
 
     storageUtil.expectTaskFetch(
         Query.instanceScoped(IInstanceKey.build(instanceKey)).active(), storedTask);
@@ -1129,7 +1155,12 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
         new AssignedTask()
             .setTaskId(taskId)
             .setTask(config)));
-    InstanceKey instanceKey = new InstanceKey(config.getJob(), 0);
+    InstanceKey instanceKey = new InstanceKey(
+        JobKeys.from(
+            config.getOwner().getRole(),
+            config.getEnvironment(),
+            config.getJobName()).newBuilder(),
+        0);
 
     storageUtil.expectTaskFetch(
         Query.instanceScoped(IInstanceKey.build(instanceKey)).active(), task);
@@ -1189,6 +1220,10 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
 
     control.replay();
 
+    // Validate key is populated during sanitizing.
+    JobConfiguration requestConfig = oldJob.deepCopy();
+    requestConfig.getTaskConfig().unsetJob();
+
     RewriteConfigsRequest request = new RewriteConfigsRequest(
         ImmutableList.of(ConfigRewrite.jobRewrite(
             new JobConfigRewrite(oldJob, newJob))));
@@ -1303,7 +1338,9 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
 
     control.replay();
 
+    // Validate key is populated during sanitizing.
     AddInstancesConfig config = createInstanceConfig(populatedTask.newBuilder());
+    config.getTaskConfig().unsetJob();
     assertOkResponse(deprecatedAddInstances(config, LOCK.newBuilder()));
   }
 
@@ -1573,8 +1610,11 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
 
     control.replay();
 
-    Response response =
-        assertOkResponse(thrift.startJobUpdate(buildJobUpdateRequest(update), AUDIT_MESSAGE));
+    // Validate key is populated during sanitizing.
+    JobUpdateRequest request = buildJobUpdateRequest(update);
+    request.getTaskConfig().unsetJob();
+
+    Response response = assertOkResponse(thrift.startJobUpdate(request, AUDIT_MESSAGE));
     assertEquals(
         new StartJobUpdateResult(UPDATE_KEY.newBuilder()),
         response.getResult().getStartJobUpdateResult());
@@ -1642,6 +1682,20 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
         AUDIT_MESSAGE);
   }
 
+  @Test(expected = IllegalArgumentException.class)
+  public void testStartUpdateFailsInvalidJobKey() throws Exception {
+    control.replay();
+    thrift.startJobUpdate(
+        new JobUpdateRequest(
+            new TaskConfig()
+                .setJobName("&")
+                .setEnvironment("devel")
+                .setOwner(new Identity(ROLE, null)),
+            5,
+            buildJobUpdateSettings()),
+        AUDIT_MESSAGE);
+  }
+
   @Test
   public void testStartUpdateFailsInvalidGroupSize() throws Exception {
     control.replay();
@@ -2121,7 +2175,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
     return IJobUpdate.build(new JobUpdate()
         .setSummary(new JobUpdateSummary()
             .setKey(UPDATE_KEY.newBuilder())
-            .setUser(IDENTITY.getUser()))
+            .setUser(ROLE_IDENTITY.getUser()))
         .setInstructions(new JobUpdateInstructions()
             .setSettings(buildJobUpdateSettings())
             .setDesiredState(new InstanceTaskConfig()

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/java/org/apache/aurora/scheduler/updater/JobDiffTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/updater/JobDiffTest.java b/src/test/java/org/apache/aurora/scheduler/updater/JobDiffTest.java
index 09d13a3..67fe14b 100644
--- a/src/test/java/org/apache/aurora/scheduler/updater/JobDiffTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/updater/JobDiffTest.java
@@ -228,8 +228,9 @@ public class JobDiffTest extends EasyMockTest {
 
   private static ITaskConfig makeTask(String job, String config) {
     return ITaskConfig.build(new TaskConfig()
-        .setJob(JobKeys.from("role", "test", job).newBuilder())
-        .setOwner(new Identity().setUser("owner"))
+        .setOwner(new Identity("owner", "owner"))
+        .setEnvironment("test")
+        .setJobName(job)
         .setExecutorConfig(new ExecutorConfig().setData(config)));
   }
 }

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/python/apache/aurora/admin/test_admin.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/admin/test_admin.py b/src/test/python/apache/aurora/admin/test_admin.py
index 22605ec..e8da335 100644
--- a/src/test/python/apache/aurora/admin/test_admin.py
+++ b/src/test/python/apache/aurora/admin/test_admin.py
@@ -26,6 +26,7 @@ from gen.apache.aurora.api.ttypes import (
     AssignedTask,
     GetLocksResult,
     GetQuotaResult,
+    Identity,
     JobKey,
     Lock,
     LockKey,
@@ -53,7 +54,7 @@ class TestQueryCommand(AuroraClientCommandTest):
     mock_options.force = force
     mock_options.shards = shards
     mock_options.states = states
-    mock_options.listformat = listformat or '%role%/%name%/%instanceId% %status%'
+    mock_options.listformat = listformat or '%role%/%jobName%/%instanceId% %status%'
     mock_options.verbosity = False
     return mock_options
 
@@ -69,8 +70,7 @@ class TestQueryCommand(AuroraClientCommandTest):
     return [ScheduledTask(
         assignedTask=AssignedTask(
             instanceId=0,
-            task=TaskConfig(job=JobKey(role='role', environment='test', name='job'))
-        ),
+            task=TaskConfig(owner=Identity(role='test_role'), jobName='test_job')),
         status=ScheduleStatus.RUNNING
     )]
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/python/apache/aurora/client/api/test_api.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/api/test_api.py b/src/test/python/apache/aurora/client/api/test_api.py
index 974fc7e..1f041f4 100644
--- a/src/test/python/apache/aurora/client/api/test_api.py
+++ b/src/test/python/apache/aurora/client/api/test_api.py
@@ -106,6 +106,9 @@ class TestJobUpdateApis(unittest.TestCase):
     mock_task_config = create_autospec(spec=JobConfiguration, instance=True)
     mock_task_config.taskConfig = TaskConfig()
     config.job.return_value = mock_task_config
+    config.role.return_value = "role"
+    config.environment.return_value = "env"
+    config.name.return_value = "name"
     config.instances.return_value = 5
     return config
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/python/apache/aurora/client/api/test_sla.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/api/test_sla.py b/src/test/python/apache/aurora/client/api/test_sla.py
index 2bc2dd9..674e7f8 100644
--- a/src/test/python/apache/aurora/client/api/test_sla.py
+++ b/src/test/python/apache/aurora/client/api/test_sla.py
@@ -26,6 +26,7 @@ from apache.aurora.common.cluster import Cluster
 from gen.apache.aurora.api.constants import LIVE_STATES
 from gen.apache.aurora.api.ttypes import (
     AssignedTask,
+    Identity,
     JobKey,
     Response,
     ResponseCode,
@@ -68,7 +69,10 @@ class SlaTest(unittest.TestCase):
             slaveHost=host,
             task=TaskConfig(
                 production=prod if prod is not None else True,
-                job=JobKey(role=self._role, environment=self._env, name=name or self._name))),
+                job=JobKey(role=self._role, environment=self._env, name=name or self._name),
+                jobName=name or self._name,
+                owner=Identity(role=self._role),
+                environment=self._env)),
         status=ScheduleStatus.RUNNING,
         taskEvents=[TaskEvent(
             status=ScheduleStatus.RUNNING,

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/python/apache/aurora/client/cli/test_status.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_status.py b/src/test/python/apache/aurora/client/cli/test_status.py
index 7f36b46..a75f15e 100644
--- a/src/test/python/apache/aurora/client/cli/test_status.py
+++ b/src/test/python/apache/aurora/client/cli/test_status.py
@@ -28,6 +28,7 @@ from .util import AuroraClientCommandTest, FakeAuroraCommandContext
 from gen.apache.aurora.api.ttypes import (
     AssignedTask,
     GetJobsResult,
+    Identity,
     JobConfiguration,
     JobKey,
     Metadata,
@@ -51,6 +52,7 @@ class TestJobStatus(AuroraClientCommandTest):
       instance += 1
       task.assignedTask.instanceId = instance
       task.assignedTask.task.job = JobKey(role='bozo', environment='test', name='woops')
+      task.assignedTask.task.jobName = 'woops'
     return tasks
 
   @classmethod
@@ -147,6 +149,9 @@ class TestJobStatus(AuroraClientCommandTest):
           slaveHost="junk.nothing",
           task=TaskConfig(
             job=JobKey(role="nobody", environment="prod", name='flibber'),
+            owner=Identity(role="nobody"),
+            environment="prod",
+            jobName="flibber",
             isService=False,
             numCpus=2,
             ramMb=2048,
@@ -432,13 +437,18 @@ class TestJobStatus(AuroraClientCommandTest):
                 "assignedTask": {
                   "task": {
                     "isService": False,
+                    "environment": "prod",
                     "container": {
                       "mesos": {}
                     },
                     "requestedPorts": [
                       "http"
                     ],
+                    "jobName": "flibber",
                     "priority": 7,
+                    "owner": {
+                      "role": "nobody"
+                    },
                     "job": {
                       "environment": "prod",
                       "role": "nobody",
@@ -483,13 +493,18 @@ class TestJobStatus(AuroraClientCommandTest):
                 "assignedTask": {
                   "task": {
                     "isService": False,
+                    "environment": "prod",
                     "container": {
                       "mesos": {}
                     },
                     "requestedPorts": [
                       "http"
                     ],
+                    "jobName": "flibber",
                     "priority": 7,
+                    "owner": {
+                      "role": "nobody"
+                    },
                     "job": {
                       "environment": "prod",
                       "role": "nobody",

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/python/apache/aurora/client/cli/util.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/util.py b/src/test/python/apache/aurora/client/cli/util.py
index 7b4558e..7ae5886 100644
--- a/src/test/python/apache/aurora/client/cli/util.py
+++ b/src/test/python/apache/aurora/client/cli/util.py
@@ -29,6 +29,7 @@ from gen.apache.aurora.api.constants import ACTIVE_STATES
 from gen.apache.aurora.api.ttypes import (
     AssignedTask,
     ExecutorConfig,
+    Identity,
     JobKey,
     Response,
     ResponseCode,
@@ -215,6 +216,9 @@ class AuroraClientCommandTest(unittest.TestCase):
         executorConfig=ExecutorConfig(data='fake data'),
         metadata=[],
         job=JobKey(role=cls.TEST_ROLE, environment=cls.TEST_ENV, name=name),
+        owner=Identity(role=cls.TEST_ROLE),
+        environment=cls.TEST_ENV,
+        jobName=name,
         numCpus=2,
         ramMb=2,
         diskMb=2)

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/python/apache/aurora/config/test_thrift.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/config/test_thrift.py b/src/test/python/apache/aurora/config/test_thrift.py
index 88292d3..1bd7459 100644
--- a/src/test/python/apache/aurora/config/test_thrift.py
+++ b/src/test/python/apache/aurora/config/test_thrift.py
@@ -56,9 +56,10 @@ def test_simple_config():
   assert job.instanceCount == 1
   tti = job.taskConfig
   assert job.key == expected_key
-  assert job.owner == Identity(user=getpass.getuser())
+  assert job.owner == Identity(role=HELLO_WORLD.role().get(), user=getpass.getuser())
   assert job.cronSchedule is None
   assert tti.job == expected_key
+  assert tti.jobName == 'hello_world'
   assert tti.isService is False
   assert tti.numCpus == 0.1
   assert tti.ramMb == 64
@@ -69,6 +70,7 @@ def test_simple_config():
   assert tti.maxTaskFailures == 1
   assert tti.constraints == set()
   assert tti.metadata == set()
+  assert tti.environment == HELLO_WORLD.environment().get()
   assert tti.tier is None
 
 
@@ -109,6 +111,7 @@ def test_config_with_options():
   assert tti.isService
   assert job.cronCollisionPolicy == CronCollisionPolicy.RUN_OVERLAP
   assert len(tti.constraints) == 2
+  assert tti.environment == 'prod'
   assert job.key.environment == 'prod'
 
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/python/apache/aurora/executor/common/test_announcer.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/executor/common/test_announcer.py b/src/test/python/apache/aurora/executor/common/test_announcer.py
index f4032c7..bb9e4b0 100644
--- a/src/test/python/apache/aurora/executor/common/test_announcer.py
+++ b/src/test/python/apache/aurora/executor/common/test_announcer.py
@@ -189,6 +189,7 @@ def make_assigned_task(thermos_config, assigned_ports=None):
   from gen.apache.aurora.api.ttypes import (
       AssignedTask,
       ExecutorConfig,
+      Identity,
       JobKey,
       TaskConfig
   )
@@ -200,6 +201,9 @@ def make_assigned_task(thermos_config, assigned_ports=None):
           role=thermos_config.role().get(),
           environment="prod",
           name=thermos_config.name().get()),
+      owner=Identity(role=thermos_config.role().get(), user=thermos_config.role().get()),
+      environment=thermos_config.environment().get(),
+      jobName=thermos_config.name().get(),
       executorConfig=executor_config)
 
   return AssignedTask(

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/python/apache/aurora/executor/common/test_resource_manager_integration.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/executor/common/test_resource_manager_integration.py b/src/test/python/apache/aurora/executor/common/test_resource_manager_integration.py
index fe74bd1..c473808 100644
--- a/src/test/python/apache/aurora/executor/common/test_resource_manager_integration.py
+++ b/src/test/python/apache/aurora/executor/common/test_resource_manager_integration.py
@@ -31,15 +31,14 @@ from gen.apache.thermos.ttypes import RunnerCkpt, RunnerHeader
 # TODO(jcohen): There should really be a single canonical source for creating test jobs/tasks
 def make_assigned_task(thermos_config, assigned_ports=None):
   from gen.apache.aurora.api.constants import AURORA_EXECUTOR_NAME
-  from gen.apache.aurora.api.ttypes import AssignedTask, ExecutorConfig, JobKey, TaskConfig
+  from gen.apache.aurora.api.ttypes import AssignedTask, ExecutorConfig, Identity, TaskConfig
 
   assigned_ports = assigned_ports or {}
   executor_config = ExecutorConfig(name=AURORA_EXECUTOR_NAME, data=thermos_config.json_dumps())
   task_config = TaskConfig(
-      job=JobKey(
-          role=thermos_config.role().get(),
-          environment='test',
-          name=thermos_config.name().get()),
+      owner=Identity(role=thermos_config.role().get(), user=thermos_config.role().get()),
+      environment=thermos_config.environment().get(),
+      jobName=thermos_config.name().get(),
       executorConfig=executor_config)
 
   return AssignedTask(

http://git-wip-us.apache.org/repos/asf/aurora/blob/4c34015c/src/test/python/apache/aurora/executor/test_thermos_executor.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/executor/test_thermos_executor.py b/src/test/python/apache/aurora/executor/test_thermos_executor.py
index ef60ec2..32e8b9b 100644
--- a/src/test/python/apache/aurora/executor/test_thermos_executor.py
+++ b/src/test/python/apache/aurora/executor/test_thermos_executor.py
@@ -57,7 +57,7 @@ from apache.thermos.core.runner import TaskRunner
 from apache.thermos.monitoring.monitor import TaskMonitor
 
 from gen.apache.aurora.api.constants import AURORA_EXECUTOR_NAME
-from gen.apache.aurora.api.ttypes import AssignedTask, ExecutorConfig, JobKey, TaskConfig
+from gen.apache.aurora.api.ttypes import AssignedTask, ExecutorConfig, Identity, JobKey, TaskConfig
 
 if 'THERMOS_DEBUG' in os.environ:
   LogOptions.set_stderr_log_level('google:DEBUG')
@@ -139,7 +139,8 @@ def make_task(thermos_config, assigned_ports={}, **kw):
           executorConfig=ExecutorConfig(
               name=AURORA_EXECUTOR_NAME,
               data=thermos_config.json_dumps()),
-          job=JobKey(role=role, environment='env', name='name')),
+          job=JobKey(role=role, environment='env', name='name'),
+          owner=Identity(role=role, user=role)),
       assignedPorts=assigned_ports,
       **kw)
   td = mesos_pb2.TaskInfo()
@@ -539,6 +540,7 @@ class TestThermosExecutor(object):
         AssignedTask(
             task=TaskConfig(
                 job=JobKey(role=role, environment='env', name='name'),
+                owner=Identity(role=role, user=role),
                 executorConfig=ExecutorConfig(name=AURORA_EXECUTOR_NAME, data='garbage'))))
 
     te = FastThermosExecutor(