Class: Katello::Pulp3::RepositoryMirror

Inherits:
Object
  • Object
show all
Defined in:
app/services/katello/pulp3/repository_mirror.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(repository_service) ⇒ RepositoryMirror

Returns a new instance of RepositoryMirror.



11
12
13
# File 'app/services/katello/pulp3/repository_mirror.rb', line 11

def initialize(repository_service)
  @repo_service = repository_service
end

Instance Attribute Details

#repo_serviceObject

Returns the value of attribute repo_service.



4
5
6
# File 'app/services/katello/pulp3/repository_mirror.rb', line 4

def repo_service
  @repo_service
end

Instance Method Details

#adjust_distribution_options_for_pulp_version(distro, dist_options) ⇒ Object



224
225
226
227
228
229
230
231
232
233
234
# File 'app/services/katello/pulp3/repository_mirror.rb', line 224

def adjust_distribution_options_for_pulp_version(distro, dist_options)
  # REMOVE when N-2 capsules use Pulp >= 3.105 (enables publication-free distribution for old capsules)
  if distro.respond_to?(:repository_version)
    # New Pulp supports repository_version - use it and clear publication
    dist_options[:publication] = nil if distro.publication.present?
  else
    # Old Pulp doesn't support repository_version - fall back to publication
    dist_options.delete(:repository_version)
    dist_options[:publication] = publication_href_or_create
  end
end

#backend_object_nameObject



20
21
22
23
# File 'app/services/katello/pulp3/repository_mirror.rb', line 20

def backend_object_name
  #Create repos in pulp3 instance with the name as this repo's pulp_id
  repo.pulp_id
end

#build_distribution_paramsObject



202
203
204
205
206
207
208
209
210
211
212
# File 'app/services/katello/pulp3/repository_mirror.rb', line 202

def build_distribution_params
  dist_params = {}
  if repo_service.repo.repository_type.pulp3_skip_publication
    dist_params[:repository_version] = version_href
    fail "could not lookup a version_href for repo #{repo_service.repo.id}" if version_href.nil?
  else
    dist_params[:publication] = publication_href
    fail "Could not lookup a publication_href for repo #{repo_service.repo.id}" if publication_href.nil?
  end
  dist_params
end

#common_remote_optionsObject



145
146
147
148
149
150
151
152
153
154
155
156
# File 'app/services/katello/pulp3/repository_mirror.rb', line 145

def common_remote_options
  remote_options = {
    name: backend_object_name,
    total_timeout: Setting[:sync_total_timeout],
    connect_timeout: Setting[:sync_connect_timeout_v2],
    sock_connect_timeout: Setting[:sync_sock_connect_timeout],
    sock_read_timeout: Setting[:sync_sock_read_timeout],
    rate_limit: Setting[:download_rate_limit],
  }
  remote_options.merge!({download_concurrency: repo.download_concurrency}) if repo.download_concurrency
  remote_options.merge!(ssl_remote_options)
end

#compute_remote_optionsObject



123
124
125
# File 'app/services/katello/pulp3/repository_mirror.rb', line 123

def compute_remote_options
  repo_service.compute_remote_options(remote_options)
end

#content_guard_hrefObject



15
16
17
18
# File 'app/services/katello/pulp3/repository_mirror.rb', line 15

def content_guard_href
  content_guard_api = ::Katello::Pulp3::Api::ContentGuard.new(smart_proxy)
  content_guard_api.list&.results&.first&.pulp_href
end

#count_by_pulpcore_type(service_class) ⇒ Object



300
301
302
303
304
305
306
# File 'app/services/katello/pulp3/repository_mirror.rb', line 300

def count_by_pulpcore_type(service_class)
  # Currently only supports SRPMs and Docker Manifest Lists
  fail NotImplementedError unless [::Katello::Pulp3::Srpm, ::Katello::Pulp3::DockerManifestList].include?(service_class)
  count = service_class.content_api(smart_proxy).list(service_class.page_options(limit: 1, fields: ['count'], repository_version: version_href)).count
  return 0 if count.nil?
  count
end

#create(_force = false) ⇒ Object



55
56
57
# File 'app/services/katello/pulp3/repository_mirror.rb', line 55

def create(_force = false)
  api.repositories_api.create(name: backend_object_name)
end

#create_distribution(path) ⇒ Object



320
321
322
323
# File 'app/services/katello/pulp3/repository_mirror.rb', line 320

def create_distribution(path)
  distribution_data = api.distribution_class.new(distribution_options(path))
  repo_service.distributions_api.create(distribution_data)
end

#create_entitiesObject



50
51
52
53
# File 'app/services/katello/pulp3/repository_mirror.rb', line 50

def create_entities
  create
  create_remote unless fetch_remote
end

#create_new_distribution(dist_options) ⇒ Object



236
237
238
239
240
241
# File 'app/services/katello/pulp3/repository_mirror.rb', line 236

def create_new_distribution(dist_options)
  distribution_data = api.distribution_class.new(dist_options)
  [api.distributions_api.create(distribution_data)]
rescue api.client_module::ApiError => e
  retry_distribution_create_with_publication(e, dist_options)
end

#create_publicationObject



174
175
176
177
178
179
180
181
182
183
184
# File 'app/services/katello/pulp3/repository_mirror.rb', line 174

def create_publication
  if (href = version_href)
    if repo_service.repo.content_type == "deb"
      publication_data = api.publication_verbatim_class.new({repository_version: href})
      api.publications_verbatim_api.create(publication_data)
    else
      publication_data = api.publication_class.new(repository_version: href)
      api.publications_api.create(publication_data)
    end
  end
end

#create_remoteObject



116
117
118
119
120
121
# File 'app/services/katello/pulp3/repository_mirror.rb', line 116

def create_remote
  # Do not consider remotes_uln_api, since the Katello server is not a ULN server. Even if the sync
  # to Katello used ULN, the sync from Katello server to smart proxy will use a normal RPM remote!
  remote_file_data = @repo_service.api.remote_class.new(remote_options)
  api.remotes_api.create(remote_file_data)
end

#create_version(options = {}) ⇒ Object



92
93
94
# File 'app/services/katello/pulp3/repository_mirror.rb', line 92

def create_version(options = {})
  api.repository_versions_api.create(repository_href, options)
end

#delete(href = repository_href) ⇒ Object



65
66
67
68
69
70
# File 'app/services/katello/pulp3/repository_mirror.rb', line 65

def delete(href = repository_href)
  api.repositories_api.delete(href) if href
rescue api.api_exception_class => e
  raise e if e.code != 404
  nil
end

#distribution_options(path, options = {}) ⇒ Object



96
97
98
99
100
101
102
103
104
105
# File 'app/services/katello/pulp3/repository_mirror.rb', line 96

def distribution_options(path, options = {})
  ret = {
    base_path: path,
    name: "#{backend_object_name}",
  }
  ret[:content_guard] = repo.unprotected ? nil : content_guard_href
  ret[:publication] = options[:publication] if options.key? :publication
  ret[:repository_version] = options[:repository_version] if options.key? :repository_version
  ret
end

#fetch_remoteObject



127
128
129
# File 'app/services/katello/pulp3/repository_mirror.rb', line 127

def fetch_remote
  api.remotes_list(name: backend_object_name).first
end

#fetch_repositoryObject



76
77
78
# File 'app/services/katello/pulp3/repository_mirror.rb', line 76

def fetch_repository
  repo_service.api.list_all(name: backend_object_name).first
end

#latest_content_countsObject



308
309
310
311
312
# File 'app/services/katello/pulp3/repository_mirror.rb', line 308

def latest_content_counts
  version_pulp_href = version_href
  return unless version_pulp_href
  api.repository_versions_api.read(version_pulp_href)&.content_summary&.present
end

#needs_updates?Boolean

Returns:

  • (Boolean)


39
40
41
42
43
44
# File 'app/services/katello/pulp3/repository_mirror.rb', line 39

def needs_updates?
  remote = fetch_remote
  return true if remote.blank?
  options = repo_service.compute_remote_options
  options.keys.any? { |key| remote.send(key) != options[key] }
end

#publication_hrefObject



84
85
86
87
88
89
90
# File 'app/services/katello/pulp3/repository_mirror.rb', line 84

def publication_href
  if repo_service.repo.content_type == "deb"
    api.publications_verbatim_api.list(:repository_version => version_href).results.first&.pulp_href
  else
    api.publications_api.list(:repository_version => version_href).results.first&.pulp_href
  end
end

#publication_href_or_createObject



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'app/services/katello/pulp3/repository_mirror.rb', line 274

def publication_href_or_create
  # Get existing publication href, or create one on-demand if needed (for N-1 capsule compatibility)
  pub_href = publication_href
  if pub_href.nil?
    Rails.logger.info("No publication found for capsule #{smart_proxy.name}, creating one for repo #{repo_service.repo.id}")
    task_response = create_publication
    fail "Failed to create publication task for repo #{repo_service.repo.id}" if task_response.nil?

    task = Katello::Pulp3::Task.new(smart_proxy, { 'task' => task_response.task })

    # Poll with timeout to prevent indefinite blocking
    timeout = Setting[:sync_total_timeout] || 3600
    start_time = Time.now
    until task.done?
      elapsed = Time.now - start_time
      fail "Publication creation timed out after #{elapsed.to_i} seconds for repo #{repo_service.repo.id}" if elapsed > timeout
      sleep 1
      task.poll
    end

    pub_href = Katello::Pulp3::Task.publication_href([task.task_data])
    fail "Failed to create publication for repo #{repo_service.repo.id}" if pub_href.nil?
  end
  pub_href
end

#pulp3_enabled_repo_typesObject



314
315
316
317
318
# File 'app/services/katello/pulp3/repository_mirror.rb', line 314

def pulp3_enabled_repo_types
  Katello::RepositoryTypeManager.enabled_repository_types.values.select do |repository_type|
    smart_proxy.pulp3_repository_type_support?(repository_type)
  end
end

#refresh_distributions(_options = {}) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'app/services/katello/pulp3/repository_mirror.rb', line 186

def refresh_distributions(_options = {})
  path = repo_service.relative_path
  dist_params = build_distribution_params
  dist_options = distribution_options(path, dist_params)
  dist_options.delete(:content_guard) if repo_service.repo.content_type == "docker"

  distro = repo_service.lookup_distributions(base_path: path).first ||
           repo_service.lookup_distributions(name: "#{backend_object_name}").first

  if distro
    update_existing_distribution(distro, dist_options)
  else
    create_new_distribution(dist_options)
  end
end

#refresh_entitiesObject



25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'app/services/katello/pulp3/repository_mirror.rb', line 25

def refresh_entities
  href = remote_href
  if href
    # Do not consider remotes_uln_api, since the Katello server is not a ULN server. Even if the sync
    # to Katello used ULN, the sync from Katello server to smart proxy will use a normal RPM remote!
    response = api.remotes_api.partial_update(href, remote_options)
    # Pulp 3.90+ returns polymorphic responses (PULP-734): task when changes occur, nil when no-op
    (response.respond_to?(:task) && response.task.present?) ? [response] : []
  else
    create_remote
    []
  end
end

#remote_feed_urlObject



168
169
170
171
172
# File 'app/services/katello/pulp3/repository_mirror.rb', line 168

def remote_feed_url
  uri = ::SmartProxy.pulp_primary.pulp3_uri!
  uri.path = repo_service.partial_repo_path
  uri.to_s
end

#remote_hrefObject



46
47
48
# File 'app/services/katello/pulp3/repository_mirror.rb', line 46

def remote_href
  fetch_remote.try(:pulp_href)
end

#remote_optionsObject



107
108
109
110
111
112
113
114
# File 'app/services/katello/pulp3/repository_mirror.rb', line 107

def remote_options
  base_options = common_remote_options
  base_options.merge!(url: remote_feed_url)
  if (type_specific_options = repo_service.try(:mirror_remote_options))
    base_options.merge!(type_specific_options)
  end
  base_options
end

#repairObject



325
326
327
328
329
# File 'app/services/katello/pulp3/repository_mirror.rb', line 325

def repair
  data = api.repair_class.new
  fail "Could not lookup a version_href for repo #{repo_service.repo.id}" if version_href.nil?
  api.repository_versions_api.repair(version_href, data)
end

#repository_hrefObject



72
73
74
# File 'app/services/katello/pulp3/repository_mirror.rb', line 72

def repository_href
  fetch_repository.try(:pulp_href)
end

#retry_distribution_create_with_publication(error, dist_options) ⇒ Object



259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'app/services/katello/pulp3/repository_mirror.rb', line 259

def retry_distribution_create_with_publication(error, dist_options)
  # REMOVE when N-2 capsules use Pulp >= 3.105
  # If repository_version is not supported (old Pulp), retry with publication
  if repo_service.repo.repository_type.pulp3_transitioning_from_publication &&
     error.code == 400 &&
     (error.message.include?("repository_version") || error.message.include?("publication"))
    dist_options.delete(:repository_version)
    dist_options[:publication] = publication_href_or_create
    distribution_data = api.distribution_class.new(dist_options)
    [api.distributions_api.create(distribution_data)]
  else
    fail error
  end
end

#retry_distribution_update_with_publication(error, distro, dist_options) ⇒ Object



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'app/services/katello/pulp3/repository_mirror.rb', line 243

def retry_distribution_update_with_publication(error, distro, dist_options)
  # REMOVE when N-2 capsules use Pulp >= 3.105
  # If repository_version is not supported (old Pulp), retry with publication
  if repo_service.repo.repository_type.pulp3_transitioning_from_publication &&
     error.code == 400 &&
     (error.message.include?("repository_version") || error.message.include?("publication"))
    dist_options.delete(:repository_version)
    dist_options[:publication] = publication_href_or_create
    response = api.distributions_api.partial_update(distro.pulp_href, dist_options)
    # Pulp 3.90+ returns polymorphic responses (PULP-734): task when changes occur, nil when no-op
    (response.respond_to?(:task) && response.task.present?) ? [response] : []
  else
    fail error
  end
end

#ssl_remote_optionsObject



158
159
160
161
162
163
164
165
166
# File 'app/services/katello/pulp3/repository_mirror.rb', line 158

def ssl_remote_options
  ueber_cert = ::Cert::Certs.ueber_cert(repo.root.organization)
  {
    client_cert: ueber_cert[:cert],
    client_key: ueber_cert[:key],
    ca_cert: ::Cert::Certs.ca_cert,
    tls_validation: true,
  }
end

#sync(options = {}) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'app/services/katello/pulp3/repository_mirror.rb', line 131

def sync(options = {})
  sync_params = repo_service.sync_url_params(options)
  sync_params[:remote] = remote_href
  if repo.yum?
    sync_params.delete(:skip_types) if sync_params[:skip_types]
    sync_params[:sync_policy] = 'mirror_complete'
  else
    sync_params.delete(:sync_policy)
    sync_params[:mirror] = true
  end
  repository_sync_url_data = api.repository_sync_url_class.new(sync_params)
  [api.repositories_api.sync(repository_href, repository_sync_url_data)]
end

#updateObject



59
60
61
62
63
# File 'app/services/katello/pulp3/repository_mirror.rb', line 59

def update
  response = api.repositories_api.update(repository_href, name: backend_object_name)
  # Pulp 3.90+ returns polymorphic responses (PULP-734): task when changes occur, nil when no-op
  (response.respond_to?(:task) && response.task.present?) ? [response] : []
end

#update_existing_distribution(distro, dist_options) ⇒ Object



214
215
216
217
218
219
220
221
222
# File 'app/services/katello/pulp3/repository_mirror.rb', line 214

def update_existing_distribution(distro, dist_options)
  dist_options = dist_options.except(:name)
  adjust_distribution_options_for_pulp_version(distro, dist_options) if repo_service.repo.repository_type.pulp3_transitioning_from_publication
  response = api.distributions_api.partial_update(distro.pulp_href, dist_options)
  # Pulp 3.90+ returns polymorphic responses (PULP-734): task when changes occur, nil when no-op
  (response.respond_to?(:task) && response.task.present?) ? [response] : []
rescue api.client_module::ApiError => e
  retry_distribution_update_with_publication(e, distro, dist_options)
end

#version_hrefObject



80
81
82
# File 'app/services/katello/pulp3/repository_mirror.rb', line 80

def version_href
  fetch_repository&.latest_version_href
end