diff --git a/lib/constants.py b/lib/constants.py
index e85bd486891d5f6067adfa724126790440f52f8e..8a56e07a9afa143439128fb08c6687c89f2a13f1 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -266,6 +266,7 @@ JOB_STATUS_ERROR = "error"
 
 OP_STATUS_QUEUED = "queued"
 OP_STATUS_RUNNING = "running"
+OP_STATUS_CANCELED = "canceled"
 OP_STATUS_SUCCESS = "success"
 OP_STATUS_ERROR = "error"
 
diff --git a/lib/jqueue.py b/lib/jqueue.py
index 46219c08b4e7671c5bd470a90c02c7e353a2bc19..fd8724107771ed4c2c74aed6a1d73fc2b4e97b84 100644
--- a/lib/jqueue.py
+++ b/lib/jqueue.py
@@ -161,13 +161,19 @@ class _QueuedJob(object):
       "run_op_index": self.run_op_index,
       }
 
-  def SetUnclean(self, msg):
+  def _SetStatus(self, status, msg):
     try:
       for op in self._ops:
-        op.SetStatus(constants.OP_STATUS_ERROR, msg)
+        op.SetStatus(status, msg)
     finally:
       self.storage.UpdateJob(self)
 
+  def SetUnclean(self, msg):
+    return self._SetStatus(constants.OP_STATUS_ERROR, msg)
+
+  def SetCanceled(self, msg):
+    return self._SetStatus(constants.JOB_STATUS_CANCELED, msg)
+
   def GetStatus(self):
     status = constants.JOB_STATUS_QUEUED
 
@@ -187,6 +193,9 @@ class _QueuedJob(object):
         status = constants.JOB_STATUS_ERROR
         # The whole job fails if one opcode failed
         break
+      elif op_status == constants.OP_STATUS_CANCELED:
+        status = constants.OP_STATUS_CANCELED
+        break
 
     if all_success:
       status = constants.JOB_STATUS_SUCCESS