X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/7653054635e3f4f84da3f2b6862cd2c02fbe3fd4..c3481a62091153eb0f74cd2f769d46c552765fcb:/services/api/app/models/collection.rb diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb index ac00e5d39c..1bbe8cc661 100644 --- a/services/api/app/models/collection.rb +++ b/services/api/app/models/collection.rb @@ -17,7 +17,7 @@ class Collection < ArvadosModel # Posgresql JSONB columns should NOT be declared as serialized, Rails 5 # already know how to properly treat them. attribute :properties, :jsonbHash, default: {} - attribute :storage_classes_desired, :jsonbArray, default: ["default"] + attribute :storage_classes_desired, :jsonbArray, default: lambda { Rails.configuration.DefaultStorageClasses } attribute :storage_classes_confirmed, :jsonbArray, default: [] before_validation :default_empty_manifest @@ -28,6 +28,7 @@ class Collection < ArvadosModel before_validation :check_signatures before_validation :strip_signatures_and_update_replication_confirmed before_validation :name_null_if_empty + validate :ensure_filesystem_compatible_name validate :ensure_pdh_matches_manifest_text validate :ensure_storage_classes_desired_is_not_empty validate :ensure_storage_classes_contain_non_empty_strings @@ -61,6 +62,8 @@ class Collection < ArvadosModel t.add :file_size_total end + UNLOGGED_CHANGES = ['preserve_version', 'updated_at'] + after_initialize do @signatures_checked = false @computed_pdh_for_manifest_text = false @@ -147,7 +150,9 @@ class Collection < ArvadosModel def strip_signatures_and_update_replication_confirmed if self.manifest_text_changed? in_old_manifest = {} - if not self.replication_confirmed.nil? + # manifest_text_was could be nil when dealing with a freshly created snapshot, + # so we skip this case because there was no real manifest change. (Bug #18005) + if (not self.replication_confirmed.nil?) and (not self.manifest_text_was.nil?) self.class.each_manifest_locator(manifest_text_was) do |match| in_old_manifest[match[1]] = true end @@ -258,20 +263,22 @@ class Collection < ArvadosModel should_preserve_version = should_preserve_version? # Time sensitive, cache value return(yield) unless (should_preserve_version || syncable_updates.any?) - # Put aside the changes because with_lock forces a record reload + # Put aside the changes because with_lock does a record reload changes = self.changes snapshot = nil + restore_attributes with_lock do # Copy the original state to save it as old version if should_preserve_version snapshot = self.dup snapshot.uuid = nil # Reset UUID so it's created as a new record snapshot.created_at = self.created_at + snapshot.modified_at = self.modified_at_was end # Restore requested changes on the current version changes.keys.each do |attr| - if attr == 'preserve_version' && changes[attr].last == false + if attr == 'preserve_version' && changes[attr].last == false && !should_preserve_version next # Ignore false assignment, once true it'll be true until next version end self.attributes = {attr => changes[attr].last} @@ -283,7 +290,6 @@ class Collection < ArvadosModel if should_preserve_version self.version += 1 - self.preserve_version = false end yield @@ -292,22 +298,36 @@ class Collection < ArvadosModel if snapshot snapshot.attributes = self.syncable_updates leave_modified_by_user_alone do - act_as_system_user do - snapshot.save + leave_modified_at_alone do + act_as_system_user do + snapshot.save + end end end end end end + def maybe_update_modified_by_fields + if !(self.changes.keys - ['updated_at', 'preserve_version']).empty? + super + end + end + def syncable_updates updates = {} - (syncable_attrs & self.changes.keys).each do |attr| + if self.changes.any? + changes = self.changes + else + # If called after save... + changes = self.saved_changes + end + (syncable_attrs & changes.keys).each do |attr| if attr == 'uuid' # Point old versions to current version's new UUID - updates['current_version_uuid'] = self.changes[attr].last + updates['current_version_uuid'] = changes[attr].last else - updates[attr] = self.changes[attr].last + updates[attr] = changes[attr].last end end return updates @@ -315,7 +335,7 @@ class Collection < ArvadosModel def sync_past_versions updates = self.syncable_updates - Collection.where('current_version_uuid = ? AND uuid != ?', self.uuid_was, self.uuid_was).each do |c| + Collection.where('current_version_uuid = ? AND uuid != ?', self.uuid_before_last_save, self.uuid_before_last_save).each do |c| c.attributes = updates # Use a different validation context to skip the 'past_versions_cannot_be_updated' # validator, as on this case it is legal to update some fields. @@ -348,6 +368,7 @@ class Collection < ArvadosModel idle_threshold = Rails.configuration.Collections.PreserveVersionIfIdle if !self.preserve_version_was && + !self.preserve_version && (idle_threshold < 0 || (idle_threshold > 0 && self.modified_at_was > db_current_time-idle_threshold.seconds)) return false @@ -521,7 +542,7 @@ class Collection < ArvadosModel joins("JOIN collections ON links.head_uuid = collections.uuid"). order("links.created_at DESC") - docker_image_formats = Rails.configuration.Containers.SupportedDockerImageFormats + docker_image_formats = Rails.configuration.Containers.SupportedDockerImageFormats.keys.map(&:to_s) if (docker_image_formats.include? 'v1' and docker_image_formats.include? 'v2') or filter_compatible_format == false @@ -611,7 +632,7 @@ class Collection < ArvadosModel # validation on empty desired storage classes return an error. def default_storage_classes if self.storage_classes_desired.nil? || self.storage_classes_desired.empty? - self.storage_classes_desired = ["default"] + self.storage_classes_desired = Rails.configuration.DefaultStorageClasses end self.storage_classes_confirmed ||= [] end @@ -623,10 +644,10 @@ class Collection < ArvadosModel return end (managed_props.keys - self.properties.keys).each do |key| - if managed_props[key].has_key?('Value') - self.properties[key] = managed_props[key]['Value'] - elsif managed_props[key]['Function'].andand == 'original_owner' + if managed_props[key]['Function'] == 'original_owner' self.properties[key] = self.user_owner_uuid + elsif managed_props[key]['Value'] + self.properties[key] = managed_props[key]['Value'] else logger.warn "Unidentified default property definition '#{key}': #{managed_props[key].inspect}" end @@ -731,4 +752,8 @@ class Collection < ArvadosModel self.current_version_uuid ||= self.uuid true end + + def log_update + super unless (saved_changes.keys - UNLOGGED_CHANGES).empty? + end end