2018-07-25 05:30:33 -04:00
# frozen_string_literal: true
2019-03-28 09:17:42 -04:00
class ContainerRepository < ApplicationRecord
2019-01-10 09:22:58 -05:00
include Gitlab :: Utils :: StrongMemoize
2020-04-27 20:09:33 -04:00
include Gitlab :: SQL :: Pattern
2020-10-26 14:08:27 -04:00
include EachBatch
2021-02-09 13:09:59 -05:00
include Sortable
2020-10-26 14:08:27 -04:00
WAITING_CLEANUP_STATUSES = % i [ cleanup_scheduled cleanup_unfinished ] . freeze
2021-05-12 08:10:24 -04:00
REQUIRING_CLEANUP_STATUSES = % i [ cleanup_unscheduled cleanup_scheduled ] . freeze
2019-01-10 09:22:58 -05:00
2016-11-23 11:50:30 -05:00
belongs_to :project
2017-03-24 07:31:34 -04:00
validates :name , length : { minimum : 0 , allow_nil : false }
2017-04-03 05:51:13 -04:00
validates :name , uniqueness : { scope : :project_id }
2017-03-24 07:31:34 -04:00
2020-04-07 08:09:34 -04:00
enum status : { delete_scheduled : 0 , delete_failed : 1 }
2020-10-26 14:08:27 -04:00
enum expiration_policy_cleanup_status : { cleanup_unscheduled : 0 , cleanup_scheduled : 1 , cleanup_unfinished : 2 , cleanup_ongoing : 3 }
2020-04-07 08:09:34 -04:00
2017-03-24 07:31:34 -04:00
delegate :client , to : :registry
2017-03-31 09:10:15 -04:00
2019-01-10 09:22:58 -05:00
scope :ordered , - > { order ( :name ) }
2019-10-24 20:06:14 -04:00
scope :with_api_entity_associations , - > { preload ( project : [ :route , { namespace : :route } ] ) }
2019-11-04 10:07:36 -05:00
scope :for_group_and_its_subgroups , - > ( group ) do
2020-06-11 08:08:54 -04:00
project_scope = Project
. for_group_and_its_subgroups ( group )
. with_container_registry
. select ( :id )
2020-11-24 10:09:13 -05:00
joins ( " INNER JOIN ( #{ project_scope . to_sql } ) projects on projects.id=container_repositories.project_id " )
2019-11-04 10:07:36 -05:00
end
2020-10-26 14:08:27 -04:00
scope :for_project_id , - > ( project_id ) { where ( project_id : project_id ) }
2020-04-27 20:09:33 -04:00
scope :search_by_name , - > ( query ) { fuzzy_search ( query , [ :name ] , use_minimum_char_limit : false ) }
2020-10-26 14:08:27 -04:00
scope :waiting_for_cleanup , - > { where ( expiration_policy_cleanup_status : WAITING_CLEANUP_STATUSES ) }
2021-05-12 08:10:24 -04:00
scope :expiration_policy_started_at_nil_or_before , - > ( timestamp ) { where ( 'expiration_policy_started_at < ? OR expiration_policy_started_at IS NULL' , timestamp ) }
2019-01-10 09:22:58 -05:00
2020-03-30 05:07:58 -04:00
def self . exists_by_path? ( path )
where (
project : path . repository_project ,
name : path . repository_name
) . exists?
end
2021-05-12 08:10:24 -04:00
def self . with_enabled_policy
joins ( " INNER JOIN container_expiration_policies ON container_repositories.project_id = container_expiration_policies.project_id " )
. where ( container_expiration_policies : { enabled : true } )
end
def self . requiring_cleanup
where (
container_repositories : { expiration_policy_cleanup_status : REQUIRING_CLEANUP_STATUSES } ,
project_id : :: ContainerExpirationPolicy . runnable_schedules
. select ( :project_id )
)
end
def self . with_unfinished_cleanup
with_enabled_policy . cleanup_unfinished
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ServiceClass
2017-03-22 07:28:23 -04:00
def registry
2017-03-23 09:37:17 -04:00
@registry || = begin
token = Auth :: ContainerRegistryAuthenticationService . full_access_token ( path )
url = Gitlab . config . registry . api_url
host_port = Gitlab . config . registry . host_port
ContainerRegistry :: Registry . new ( url , token : token , path : host_port )
end
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ServiceClass
2017-03-23 09:37:17 -04:00
def path
2017-04-13 05:54:02 -04:00
@path || = [ project . full_path , name ]
. select ( & :present? ) . join ( '/' ) . downcase
2016-11-01 22:33:35 -04:00
end
2017-04-10 06:57:19 -04:00
def location
File . join ( registry . path , path )
end
2016-11-01 22:33:35 -04:00
def tag ( tag )
ContainerRegistry :: Tag . new ( self , tag )
end
def manifest
2017-04-05 08:44:35 -04:00
@manifest || = client . repository_tags ( path )
2016-11-01 22:33:35 -04:00
end
def tags
return [ ] unless manifest && manifest [ 'tags' ]
2019-01-10 09:22:58 -05:00
strong_memoize ( :tags ) do
manifest [ 'tags' ] . sort . map do | tag |
ContainerRegistry :: Tag . new ( self , tag )
end
2016-11-01 22:33:35 -04:00
end
end
2020-05-25 17:08:00 -04:00
def tags_count
return 0 unless manifest && manifest [ 'tags' ]
manifest [ 'tags' ] . size
end
2016-11-01 22:33:35 -04:00
def blob ( config )
ContainerRegistry :: Blob . new ( self , config )
end
2017-03-29 06:14:29 -04:00
def has_tags?
2017-04-05 08:44:35 -04:00
tags . any?
2017-03-29 06:14:29 -04:00
end
2017-04-03 06:49:54 -04:00
def root_repository?
name . empty?
end
2017-03-31 05:54:09 -04:00
def delete_tags!
return unless has_tags?
2019-10-16 08:06:32 -04:00
digests = tags . map { | tag | tag . digest } . compact . to_set
2016-11-01 22:33:35 -04:00
2019-10-16 11:06:17 -04:00
digests . map ( & method ( :delete_tag_by_digest ) ) . all?
2016-11-01 22:33:35 -04:00
end
2017-03-30 07:31:33 -04:00
2019-08-01 08:03:08 -04:00
def delete_tag_by_digest ( digest )
2020-02-12 10:09:37 -05:00
client . delete_repository_tag_by_digest ( self . path , digest )
end
def delete_tag_by_name ( name )
client . delete_repository_tag_by_name ( self . path , name )
2019-08-01 08:03:08 -04:00
end
2020-09-22 20:09:45 -04:00
def reset_expiration_policy_started_at!
update! ( expiration_policy_started_at : nil )
end
def start_expiration_policy!
update! ( expiration_policy_started_at : Time . zone . now )
end
2017-04-03 06:49:54 -04:00
def self . build_from_path ( path )
self . new ( project : path . repository_project ,
name : path . repository_name )
end
2017-03-31 06:27:05 -04:00
def self . create_from_path! ( path )
2017-04-03 06:49:54 -04:00
build_from_path ( path ) . tap ( & :save! )
2017-03-30 07:31:33 -04:00
end
2017-04-04 06:57:38 -04:00
def self . build_root_repository ( project )
self . new ( project : project , name : '' )
end
2019-07-09 11:59:52 -04:00
def self . find_by_path! ( path )
self . find_by! ( project : path . repository_project ,
name : path . repository_name )
end
2016-11-01 22:33:35 -04:00
end
2019-09-13 09:26:31 -04:00
2021-05-11 17:10:21 -04:00
ContainerRepository . prepend_mod_with ( 'ContainerRepository' )