X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/7182964d1d475f77a4ae72424c06ebb447b7a14f..2a17d214467d5302e97008618ef5f560ff1fd45b:/services/api/app/models/collection.rb diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb index 1cf0a401ce..2cebd5438e 100644 --- a/services/api/app/models/collection.rb +++ b/services/api/app/models/collection.rb @@ -27,11 +27,11 @@ class Collection < ArvadosModel validate :ensure_pdh_matches_manifest_text validate :ensure_storage_classes_desired_is_not_empty validate :ensure_storage_classes_contain_non_empty_strings + validate :versioning_metadata_updates, on: :update validate :past_versions_cannot_be_updated, on: :update before_save :set_file_names - around_update :prepare_for_versioning - after_update :save_old_version, if: Proc.new { |c| c.should_preserve_version? } - after_update :sync_past_versions, if: Proc.new { |c| c.syncable_updates?(self.changes.keys) } + before_save :set_file_count_and_total_size + around_update :manage_versioning api_accessible :user, extend: :common do |t| t.add :name @@ -52,6 +52,8 @@ class Collection < ArvadosModel t.add :version t.add :current_version_uuid t.add :preserve_version + t.add :file_count + t.add :file_size_total end after_initialize do @@ -196,6 +198,15 @@ class Collection < ArvadosModel true end + def set_file_count_and_total_size + if self.manifest_text_changed? + m = Keep::Manifest.new(self.manifest_text) + self.file_size_total = m.files_size + self.file_count = m.files_count + end + true + end + def manifest_files return '' if !self.manifest_text @@ -226,23 +237,24 @@ class Collection < ArvadosModel ['current_version_uuid'] end - def prepare_for_versioning + def manage_versioning + 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 changes = self.changes - @snapshot = nil + snapshot = nil with_lock do # Copy the original state to save it as old version - if versionable_updates?(changes.keys) && 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 + 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 end # Restore requested changes on the current version changes.keys.each do |attr| - if attr == 'version' - next - elsif attr == 'preserve_version' && changes[attr].last == false + if attr == 'preserve_version' && changes[attr].last == false next # Ignore false assignment, once true it'll be true until next version end self.attributes = {attr => changes[attr].last} @@ -252,11 +264,19 @@ class Collection < ArvadosModel end end - if versionable_updates?(changes.keys) && should_preserve_version? + if should_preserve_version self.version += 1 self.preserve_version = false end + yield + + sync_past_versions if syncable_updates.any? + if snapshot + snapshot.attributes = self.syncable_updates + snapshot.manifest_text = snapshot.signed_manifest_text + snapshot.save + end end end @@ -280,7 +300,9 @@ class Collection < ArvadosModel # Use a different validation context to skip the 'old_versions_cannot_be_updated' # validator, as on this case it is legal to update some fields. leave_modified_by_user_alone do - c.save(context: :update_old_versions) + leave_modified_at_alone do + c.save(context: :update_old_versions) + end end end end @@ -293,19 +315,8 @@ class Collection < ArvadosModel ['uuid', 'owner_uuid', 'delete_at', 'trash_at', 'is_trashed', 'replication_desired', 'storage_classes_desired'] end - def syncable_updates?(attrs) - (self.syncable_attrs & attrs).any? - end - - def save_old_version - if @snapshot && should_preserve_version? - @snapshot.attributes = self.syncable_updates - @snapshot.save - end - end - def should_preserve_version? - return false if !Rails.configuration.collection_versioning + return false unless (Rails.configuration.collection_versioning && versionable_updates?(self.changes.keys)) idle_threshold = Rails.configuration.preserve_version_if_idle if !self.preserve_version_was && @@ -500,7 +511,14 @@ class Collection < ArvadosModel if loc = Keep::Locator.parse(search_term) loc.strip_hints! coll_match = readable_by(*readers).where(portable_data_hash: loc.to_s).limit(1) - return get_compatible_images(readers, pattern, coll_match) + if coll_match.any? or Rails.configuration.remote_hosts.length == 0 + return get_compatible_images(readers, pattern, coll_match) + else + # Allow bare pdh that doesn't exist in the local database so + # that federated container requests which refer to remotely + # stored containers will validate. + return [Collection.new(portable_data_hash: loc.to_s)] + end end if search_tag.nil? and (n = search_term.index(":")) @@ -631,6 +649,19 @@ class Collection < ArvadosModel end end + def versioning_metadata_updates + valid = true + if (current_version_uuid_was == uuid_was) && current_version_uuid_changed? + errors.add(:current_version_uuid, "cannot be updated") + valid = false + end + if version_changed? + errors.add(:version, "cannot be updated") + valid = false + end + valid + end + def assign_uuid super self.current_version_uuid ||= self.uuid