14406: Merge branch 'master'
[arvados.git] / services / api / app / models / container.rb
index 86201955aa6a4137f27835a65f5908e4765b5b63..cd763a8e7e1eb0d851f08517b730ddf9f230a113 100644 (file)
@@ -67,6 +67,8 @@ class Container < ArvadosModel
     t.add :state
     t.add :auth_uuid
     t.add :scheduling_parameters
+    t.add :runtime_user_uuid
+    t.add :runtime_auth_scopes
   end
 
   # Supported states for a container
@@ -284,7 +286,7 @@ class Container < ArvadosModel
     log_reuse_info(candidates) { "after filtering on runtime_user_uuid #{attrs[:runtime_user_uuid].inspect}" }
 
     candidates = candidates.where('runtime_auth_scopes = ? or (runtime_user_uuid is NULL and runtime_auth_scopes is NULL)',
-                                  SafeJSON.dump(attrs[:runtime_auth_scopes]))
+                                  SafeJSON.dump(attrs[:runtime_auth_scopes].sort))
     log_reuse_info(candidates) { "after filtering on runtime_auth_scopes #{attrs[:runtime_auth_scopes].inspect}" }
 
     log_reuse_info { "checking for state=Complete with readable output and log..." }
@@ -390,6 +392,19 @@ class Container < ArvadosModel
     [Complete, Cancelled].include?(self.state)
   end
 
+  def self.for_current_token
+    return if !current_api_client_authorization
+    _, _, _, container_uuid = Thread.current[:token].split('/')
+    if container_uuid.nil?
+      Container.where(auth_uuid: current_api_client_authorization.uuid).first
+    else
+      Container.where('auth_uuid=? or (uuid=? and runtime_token=?)',
+                      current_api_client_authorization.uuid,
+                      container_uuid,
+                      current_api_client_authorization.token).first
+    end
+  end
+
   protected
 
   def fill_field_defaults
@@ -478,10 +493,14 @@ class Container < ArvadosModel
       return false
     end
 
-    if current_api_client_authorization.andand.uuid.andand == self.auth_uuid
-      # The contained process itself can update progress indicators,
-      # but can't change priority etc.
-      permitted = permitted & (progress_attrs + final_attrs + [:state] - [:log])
+    if self.state == Running &&
+       !current_api_client_authorization.nil? &&
+       (current_api_client_authorization.uuid == self.auth_uuid ||
+        current_api_client_authorization.token == self.runtime_token)
+      # The contained process itself can write final attrs but can't
+      # change priority or log.
+      permitted.push *final_attrs
+      permitted = permitted - [:log, :priority]
     elsif self.locked_by_uuid && self.locked_by_uuid != current_api_client_authorization.andand.uuid
       # When locked, progress fields cannot be updated by the wrong
       # dispatcher, even though it has admin privileges.
@@ -540,7 +559,7 @@ class Container < ArvadosModel
 
   def assign_auth
     if self.auth_uuid_changed?
-      return errors.add :auth_uuid, 'is readonly'
+         return errors.add :auth_uuid, 'is readonly'
     end
     if not [Locked, Running].include? self.state
       # don't need one
@@ -553,6 +572,10 @@ class Container < ArvadosModel
     end
     if self.runtime_token.nil?
       if self.runtime_user_uuid.nil?
+        # legacy behavior, we don't have a runtime_user_uuid so get
+        # the user from the highest priority container request, needed
+        # when performing an upgrade and there are queued containers,
+        # and some tests.
         cr = ContainerRequest.
                where('container_uuid=? and priority>0', self.uuid).
                order('priority desc').
@@ -569,12 +592,6 @@ class Container < ArvadosModel
                     create!(user_id: User.find_by_uuid(self.runtime_user_uuid).id,
                             api_client_id: 0,
                             scopes: self.runtime_auth_scopes)
-    else
-      # using runtime_token
-      self.auth = ApiClientAuthorization.validate(token: self.runtime_token)
-      if self.auth.nil?
-        raise ArgumentError.new "Invalid runtime token"
-      end
     end
   end
 
@@ -591,6 +608,9 @@ class Container < ArvadosModel
     if self.scheduling_parameters_changed?
       self.scheduling_parameters = self.class.deep_sort_hash(self.scheduling_parameters)
     end
+    if self.runtime_auth_scopes_changed?
+      self.runtime_auth_scopes = self.runtime_auth_scopes.sort
+    end
   end
 
   def update_secret_mounts_md5
@@ -638,7 +658,11 @@ class Container < ArvadosModel
             container_image: self.container_image,
             mounts: self.mounts,
             runtime_constraints: self.runtime_constraints,
-            scheduling_parameters: self.scheduling_parameters
+            scheduling_parameters: self.scheduling_parameters,
+            secret_mounts: self.secret_mounts_was,
+            runtime_token: self.runtime_token_was,
+            runtime_user_uuid: self.runtime_user_uuid,
+            runtime_auth_scopes: self.runtime_auth_scopes
           }
           c = Container.create! c_attrs
           retryable_requests.each do |cr|