Class: RemoteMirror

Inherits:
ApplicationRecord show all
Includes:
AfterCommitQueue, MirrorAuthentication, SafeUrl
Defined in:
app/models/remote_mirror.rb

Constant Summary collapse

MAX_FIRST_RUNTIME =
3.hours
MAX_INCREMENTAL_RUNTIME =
1.hour
PROTECTED_BACKOFF_DELAY =
1.minute
UNPROTECTED_BACKOFF_DELAY =
5.minutes

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Constants included from ResetOnUnionError

ResetOnUnionError::MAX_RESET_PERIOD

Instance Attribute Summary

Attributes included from MirrorAuthentication

#regenerate_ssh_private_key

Instance Method Summary collapse

Methods included from MirrorAuthentication

#auth_method, #generate_ssh_private_key!, #password_auth?, #ssh_key_auth?, #ssh_known_hosts_fingerprints, #ssh_known_hosts_verified_by, #ssh_mirror_url?, #ssh_public_key

Methods included from AfterCommitQueue

#run_after_commit, #run_after_commit_or_now

Methods inherited from ApplicationRecord

cached_column_list, #create_or_load_association, declarative_enum, default_select_columns, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, #readable_by?, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order

Methods included from SensitiveSerializableHash

#serializable_hash

Instance Method Details

#after_sent_notificationObject



218
219
220
# File 'app/models/remote_mirror.rb', line 218

def after_sent_notification
  update_column(:error_notification_sent, true)
end

#backoff_delayObject



222
223
224
225
226
227
228
# File 'app/models/remote_mirror.rb', line 222

def backoff_delay
  if self.only_protected_branches
    PROTECTED_BACKOFF_DELAY
  else
    UNPROTECTED_BACKOFF_DELAY
  end
end

#bare_urlObject



214
215
216
# File 'app/models/remote_mirror.rb', line 214

def bare_url
  Gitlab::UrlSanitizer.new(read_attribute(:url)).full_url
end

#disabled?Boolean

Returns:

  • (Boolean)


146
147
148
# File 'app/models/remote_mirror.rb', line 146

def disabled?
  !enabled?
end

#enabledObject Also known as: enabled?



135
136
137
138
139
140
141
142
143
# File 'app/models/remote_mirror.rb', line 135

def enabled
  return false unless project && super
  return false unless project.remote_mirror_available?
  return false unless project.repository_exists?
  return false if project.pending_delete?
  return false if Gitlab::SilentMode.enabled?

  true
end

#hard_fail!(error_message) ⇒ Object

Force the mirror into the failed state



183
184
185
186
187
188
189
190
# File 'app/models/remote_mirror.rb', line 183

def hard_fail!(error_message)
  update_error_message(error_message)
  self.update_status = :failed

  save!(validate: false)

  send_failure_notifications
end

#hard_retry!(error_message) ⇒ Object

Force the mrror into the retry state



175
176
177
178
179
180
# File 'app/models/remote_mirror.rb', line 175

def hard_retry!(error_message)
  update_error_message(error_message)
  self.update_status = :to_retry

  save!(validate: false)
end

#mark_as_failed!(error_message) ⇒ Object



169
170
171
172
# File 'app/models/remote_mirror.rb', line 169

def mark_as_failed!(error_message)
  update_error_message(error_message)
  update_fail!
end

#mark_for_delete_if_blank_urlObject



156
157
158
# File 'app/models/remote_mirror.rb', line 156

def mark_for_delete_if_blank_url
  mark_for_destruction if url.blank?
end

#mark_for_retry!(error_message) ⇒ Object



164
165
166
167
# File 'app/models/remote_mirror.rb', line 164

def mark_for_retry!(error_message)
  update_error_message(error_message)
  update_retry!
end

#max_runtimeObject



230
231
232
# File 'app/models/remote_mirror.rb', line 230

def max_runtime
  last_update_at.present? ? MAX_INCREMENTAL_RUNTIME : MAX_FIRST_RUNTIME
end

#options_for_updateObject



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'app/models/remote_mirror.rb', line 99

def options_for_update
  options = {
    keep_divergent_refs: keep_divergent_refs?
  }

  if only_protected_branches?
    options[:only_branches_matching] = project.protected_branches.pluck(:name)
  end

  if ssh_mirror_url?
    if ssh_key_auth? && ssh_private_key.present?
      options[:ssh_key] = ssh_private_key
    end

    if ssh_known_hosts.present?
      options[:known_hosts] = ssh_known_hosts
    end
  end

  options
end

#safe_urlObject



210
211
212
# File 'app/models/remote_mirror.rb', line 210

def safe_url
  super(allowed_usernames: %w[git])
end

#send_failure_notificationsObject



234
235
236
237
238
239
240
241
242
243
# File 'app/models/remote_mirror.rb', line 234

def send_failure_notifications
  Gitlab::Metrics.add_event(:remote_mirrors_failed)

  run_after_commit do
    RemoteMirrorNotificationWorker.perform_async(id)
  end

  self.last_update_at = Time.current
  save!(validate: false)
end

#syncObject



125
126
127
128
129
130
131
132
133
# File 'app/models/remote_mirror.rb', line 125

def sync
  return unless sync?

  if schedule_with_delay?
    RepositoryUpdateRemoteMirrorWorker.perform_in(backoff_delay, self.id, Time.current)
  else
    RepositoryUpdateRemoteMirrorWorker.perform_async(self.id, Time.current)
  end
end

#sync?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'app/models/remote_mirror.rb', line 121

def sync?
  enabled?
end

#update_error_message(error_message) ⇒ Object



160
161
162
# File 'app/models/remote_mirror.rb', line 160

def update_error_message(error_message)
  self.last_error = Gitlab::UrlSanitizer.sanitize(error_message)
end

#update_failed?Boolean

Returns:

  • (Boolean)


83
84
85
# File 'app/models/remote_mirror.rb', line 83

def update_failed?
  update_status == 'failed'
end

#update_in_progress?Boolean

Returns:

  • (Boolean)


87
88
89
# File 'app/models/remote_mirror.rb', line 87

def update_in_progress?
  update_status == 'started'
end

#update_repositoryObject



91
92
93
94
95
96
97
# File 'app/models/remote_mirror.rb', line 91

def update_repository
  Gitlab::Git::RemoteMirror.new(
    project.repository.raw,
    remote_url,
    **options_for_update
  ).update
end

#updated_since?(timestamp) ⇒ Boolean

Returns:

  • (Boolean)


150
151
152
153
154
# File 'app/models/remote_mirror.rb', line 150

def updated_since?(timestamp)
  return false if failed?

  last_update_started_at && last_update_started_at > timestamp
end

#urlObject



202
203
204
205
206
207
208
# File 'app/models/remote_mirror.rb', line 202

def url
  if super
    Gitlab::UrlSanitizer.new(super, credentials: credentials).full_url
  end
rescue StandardError
  super
end

#url=(value) ⇒ Object



192
193
194
195
196
197
198
199
200
# File 'app/models/remote_mirror.rb', line 192

def url=(value)
  super(value) && return unless Gitlab::UrlSanitizer.valid?(value)

  mirror_url = Gitlab::UrlSanitizer.new(value)
  self.credentials ||= {}
  self.credentials = self.credentials.merge(mirror_url.credentials)

  super(mirror_url.sanitized_url)
end