Module: ObjectStorage::Concern

Defined Under Namespace

Classes: OpenFile

Instance Method Summary collapse

Methods included from Gitlab::Utils::Override

extended, extensions, included, method_added, override, prepended, queue_verification, verify!

Instance Method Details

#cache!(new_file = sanitized_file) ⇒ Object



439
440
441
442
443
444
445
446
447
# File 'app/uploaders/object_storage.rb', line 439

def cache!(new_file = sanitized_file)
  # We intercept ::UploadedFile which might be stored on remote storage
  # We use that for "accelerated" uploads, where we store result on remote storage
  if new_file.is_a?(::UploadedFile) && new_file.remote_id.present?
    return cache_remote_file!(new_file.remote_id, new_file.original_filename)
  end

  super
end

#delete_migrated_file(migrated_file) ⇒ Object



396
397
398
# File 'app/uploaders/object_storage.rb', line 396

def delete_migrated_file(migrated_file)
  migrated_file.delete
end

#delete_tmp_file_after_storageObject



463
464
465
466
467
468
469
# File 'app/uploaders/object_storage.rb', line 463

def delete_tmp_file_after_storage
  # If final path is present then the file is not on temporary location
  # so we don't want carrierwave to delete it.
  return false if direct_upload_final_path.present?

  super
end

#direct_download_enabled?Boolean

Returns:

  • (Boolean)


291
292
293
# File 'app/uploaders/object_storage.rb', line 291

def direct_download_enabled?
  self.class.direct_download_enabled?
end

#exclusive_lease_keyObject



458
459
460
# File 'app/uploaders/object_storage.rb', line 458

def exclusive_lease_key
  "object_storage_migrate:#{model.class}:#{model.id}"
end

#exists?Boolean

Returns:

  • (Boolean)


400
401
402
# File 'app/uploaders/object_storage.rb', line 400

def exists?
  file.present?
end

#file_cache_storage?Boolean

Returns:

  • (Boolean)


308
309
310
# File 'app/uploaders/object_storage.rb', line 308

def file_cache_storage?
  cache_storage.is_a?(CarrierWave::Storage::File)
end

#file_storage?Boolean

Returns:

  • (Boolean)


304
305
306
# File 'app/uploaders/object_storage.rb', line 304

def file_storage?
  storage.is_a?(CarrierWave::Storage::File)
end

#filenameObject

allow to configure and overwrite the filename



296
297
298
# File 'app/uploaders/object_storage.rb', line 296

def filename
  @filename || super || file&.filename # rubocop:disable Gitlab/ModuleWithInstanceVariables
end

#filename=(filename) ⇒ Object



300
301
302
# File 'app/uploaders/object_storage.rb', line 300

def filename=(filename)
  @filename = filename # rubocop:disable Gitlab/ModuleWithInstanceVariables
end

#fog_attributesObject



385
386
387
# File 'app/uploaders/object_storage.rb', line 385

def fog_attributes
  @fog_attributes ||= self.class.object_store_config.fog_attributes
end

#fog_credentialsObject



381
382
383
# File 'app/uploaders/object_storage.rb', line 381

def fog_credentials
  self.class.object_store_credentials
end

#fog_directoryObject



377
378
379
# File 'app/uploaders/object_storage.rb', line 377

def fog_directory
  self.class.remote_store_path
end

#fog_publicObject

Set ACL of uploaded objects to not-public (fog-aws) or no ACL at all (fog-google). Value is ignored by fog-aliyun [1]: github.com/fog/fog-aws/blob/daa50bb3717a462baf4d04d0e0cbfc18baacb541/lib/fog/aws/models/storage/file.rb#L152-L159



392
393
394
# File 'app/uploaders/object_storage.rb', line 392

def fog_public
  nil
end

#migrate!(new_store) ⇒ Object

Move the file to another store

new_store: Enum (Store::LOCAL, Store::REMOTE)


371
372
373
374
375
# File 'app/uploaders/object_storage.rb', line 371

def migrate!(new_store)
  with_exclusive_lease do
    unsafe_migrate!(new_store)
  end
end

#object_storeObject



312
313
314
315
# File 'app/uploaders/object_storage.rb', line 312

def object_store
  # We use Store::LOCAL as null value indicates the local storage
  @object_store ||= model.try(store_serialization_column) || Store::LOCAL
end

#object_store=(value) ⇒ Object

rubocop:disable Gitlab/ModuleWithInstanceVariables



318
319
320
321
322
# File 'app/uploaders/object_storage.rb', line 318

def object_store=(value)
  @object_store = value || Store::LOCAL
  model[store_serialization_column] = @object_store if sync_model_object_store? && persist_object_store?
  @storage = storage_for(object_store)
end

#persist_object_store!Object

Save the current @object_store to the model <mounted_as>_store column



332
333
334
335
336
337
# File 'app/uploaders/object_storage.rb', line 332

def persist_object_store!
  return unless persist_object_store?

  updated = model.update_column(store_serialization_column, object_store)
  raise 'Failed to update object store' unless updated
end

#persist_object_store?Boolean

Return true if the current file is part or the model (i.e. is mounted in the model)

Returns:

  • (Boolean)


327
328
329
# File 'app/uploaders/object_storage.rb', line 327

def persist_object_store?
  model.respond_to?(:"#{store_serialization_column}=")
end

#proxy_download_enabled?Boolean

Returns:

  • (Boolean)


287
288
289
# File 'app/uploaders/object_storage.rb', line 287

def proxy_download_enabled?
  self.class.proxy_download_enabled?
end

#retrieve_from_store!(identifier) ⇒ Object



471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
# File 'app/uploaders/object_storage.rb', line 471

def retrieve_from_store!(identifier)
  Gitlab::PathTraversal.check_path_traversal!(identifier)

  # We need to force assign the value of @filename so that we will still
  # get the original_filename in cases wherein the file points to a random generated
  # path format. This happens for direct uploaded files to final location.
  #
  # If we don't set @filename value here, the result of uploader.filename (see ObjectStorage#filename) will result
  # to the value of uploader.file.filename which will then contain the random generated path.
  # The `identifier` variable contains the value of the `file` column which is the original_filename.
  #
  # In cases wherein we are not uploading to final location, it is still fine to set the
  # @filename with the `identifier` value because it still contains the original filename from the `file` column,
  # which is what we want in either case.
  @filename = identifier # rubocop: disable Gitlab/ModuleWithInstanceVariables

  super
end

#store!(new_file = nil) ⇒ Object



449
450
451
452
453
454
455
456
# File 'app/uploaders/object_storage.rb', line 449

def store!(new_file = nil)
  # when direct upload is enabled, always store on remote storage
  if self.class.direct_upload_to_object_store?
    self.object_store = Store::REMOTE
  end

  super
end

#store_dir(store = nil) ⇒ Object



404
405
406
# File 'app/uploaders/object_storage.rb', line 404

def store_dir(store = nil)
  store_dirs[store || object_store]
end

#store_dirsObject



408
409
410
411
412
413
# File 'app/uploaders/object_storage.rb', line 408

def store_dirs
  {
    Store::LOCAL => File.join(base_dir, dynamic_segment),
    Store::REMOTE => File.join(dynamic_segment)
  }
end

#store_path(*args) ⇒ Object



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'app/uploaders/object_storage.rb', line 415

def store_path(*args)
  if self.object_store == Store::REMOTE
    path = direct_upload_final_path
    path ||= super

    # We allow administrators to create "sub buckets" by setting a prefix.
    # This makes it possible to deploy GitLab with only one object storage
    # bucket. Because the prefix is configuration data we do not want to
    # store it in the uploads table via RecordsUploads. That means that the
    # prefix cannot be part of store_dir. This is why we chose to implement
    # the prefix support here in store_path.
    self.class.with_bucket_prefix(path)
  else
    super
  end
end

#upload_paths(identifier) ⇒ Object

Returns all the possible paths for an upload. the ‘upload.path` is a lookup parameter, and it may change depending on the `store` param.



435
436
437
# File 'app/uploaders/object_storage.rb', line 435

def upload_paths(identifier)
  store_dirs.map { |store, path| File.join(path, identifier) }
end

#use_file(&blk) ⇒ Object



339
340
341
342
343
# File 'app/uploaders/object_storage.rb', line 339

def use_file(&blk)
  with_exclusive_lease do
    unsafe_use_file(&blk)
  end
end

#use_open_file(unlink_early: true) ⇒ Object



345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'app/uploaders/object_storage.rb', line 345

def use_open_file(unlink_early: true)
  Tempfile.open(path) do |file|
    file.unlink if unlink_early
    file.binmode

    if file_storage?
      IO.copy_stream(path, file)
    else
      Faraday.get(url) do |req|
        req.options.on_data = proc { |chunk, _| file.write(chunk) }
      end
    end

    file.seek(0, IO::SEEK_SET)

    yield OpenFile.new(file)
  ensure
    file.unlink unless unlink_early
  end
end