5416: Add read-only clone_urls attribute to Repository resources, deprecate push_url...
[arvados.git] / services / api / app / models / job.rb
index 4cd25e6b6c4e5dae6ec9c0095ca56ff47954bf8c..0923a6f4f304863f307e49c69f5648bff3144d89 100644 (file)
@@ -16,6 +16,7 @@ class Job < ArvadosModel
   validate :validate_status
   validate :validate_state_change
   validate :ensure_no_collection_uuids_in_script_params
+  before_save :tag_version_in_internal_repository
   before_save :update_timestamps_when_state_changes
 
   has_many :commit_ancestors, :foreign_key => :descendant, :primary_key => :script_version
@@ -63,7 +64,7 @@ class Job < ArvadosModel
            ]
 
   def assert_finished
-    update_attributes(finished_at: finished_at || Time.now,
+    update_attributes(finished_at: finished_at || db_current_time,
                       success: success.nil? ? false : success,
                       running: false)
   end
@@ -124,21 +125,43 @@ class Job < ArvadosModel
   end
 
   def ensure_script_version_is_commit
-    if self.state == Running
+    if state == Running
       # Apparently client has already decided to go for it. This is
       # needed to run a local job using a local working directory
       # instead of a commit-ish.
       return true
     end
-    if new_record? or script_version_changed?
-      sha1 = Commit.find_commit_range(current_user, self.repository, nil, self.script_version, nil)[0] rescue nil
-      if sha1
-        self.supplied_script_version = self.script_version if self.supplied_script_version.nil? or self.supplied_script_version.empty?
-        self.script_version = sha1
-      else
-        self.errors.add :script_version, "#{self.script_version} does not resolve to a commit"
+    if new_record? or repository_changed? or script_version_changed?
+      sha1 = Commit.find_commit_range(repository,
+                                      nil, script_version, nil).first
+      if not sha1
+        errors.add :script_version, "#{script_version} does not resolve to a commit"
         return false
       end
+      if supplied_script_version.nil? or supplied_script_version.empty?
+        self.supplied_script_version = script_version
+      end
+      self.script_version = sha1
+    end
+    true
+  end
+
+  def tag_version_in_internal_repository
+    if state == Running
+      # No point now. See ensure_script_version_is_commit.
+      true
+    elsif errors.any?
+      # Won't be saved, and script_version might not even be valid.
+      true
+    elsif new_record? or repository_changed? or script_version_changed?
+      uuid_was = uuid
+      begin
+        assign_uuid
+        Commit.tag_in_internal_repository repository, script_version, uuid
+      rescue
+        uuid = uuid_was
+        raise
+      end
     end
   end
 
@@ -169,9 +192,9 @@ class Job < ArvadosModel
   def find_arvados_sdk_version
     resolve_runtime_constraint("arvados_sdk_version",
                                :arvados_sdk_version) do |git_search|
-      commits = Commit.find_commit_range(current_user, "arvados",
+      commits = Commit.find_commit_range("arvados",
                                          nil, git_search, nil)
-      if commits.nil? or commits.empty?
+      if commits.empty?
         [false, "#{git_search} does not resolve to a commit"]
       elsif not runtime_constraints["docker_image"]
         [false, "cannot be specified without a Docker image constraint"]
@@ -193,24 +216,6 @@ class Job < ArvadosModel
     end
   end
 
-  # def dependencies
-  #   deps = {}
-  #   queue = self.script_parameters.values
-  #   while not queue.empty?
-  #     queue = queue.flatten.compact.collect do |v|
-  #       if v.is_a? Hash
-  #         v.values
-  #       elsif v.is_a? String
-  #         v.match(/^(([0-9a-f]{32})\b(\+[^,]+)?,?)*$/) do |locator|
-  #           deps[locator.to_s] = true
-  #         end
-  #         nil
-  #       end
-  #     end
-  #   end
-  #   deps.keys
-  # end
-
   def permission_to_update
     if is_locked_by_uuid_was and !(current_user and
                                    (current_user.uuid == is_locked_by_uuid_was or
@@ -257,7 +262,7 @@ class Job < ArvadosModel
       # Ensure cancelled_at cannot be set to arbitrary non-now times,
       # or changed once it is set.
       if self.cancelled_at and not self.cancelled_at_was
-        self.cancelled_at = Time.now
+        self.cancelled_at = db_current_time
         self.cancelled_by_user_uuid = current_user.uuid
         self.cancelled_by_client_uuid = current_api_client.andand.uuid
         @need_crunch_dispatch_trigger = true
@@ -283,11 +288,11 @@ class Job < ArvadosModel
 
     case state
     when Running
-      self.started_at ||= Time.now
+      self.started_at ||= db_current_time
     when Failed, Complete
-      self.finished_at ||= Time.now
+      self.finished_at ||= db_current_time
     when Cancelled
-      self.cancelled_at ||= Time.now
+      self.cancelled_at ||= db_current_time
     end
 
     # TODO: Remove the following case block when old "success" and