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 HasCheckConstraints

HasCheckConstraints::NOT_NULL_CHECK_PATTERN

Constants included from ResetOnColumnErrors

ResetOnColumnErrors::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, nullable_column?, 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 ResetOnColumnErrors

#reset_on_union_error, #reset_on_unknown_attribute_error

Methods included from Gitlab::SensitiveSerializableHash

#serializable_hash

Instance Method Details

#after_sent_notificationObject



220
221
222
# File 'app/models/remote_mirror.rb', line 220

def after_sent_notification
  update_column(:error_notification_sent, true)
end

#backoff_delayObject



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

def backoff_delay
  if self.only_protected_branches
    PROTECTED_BACKOFF_DELAY
  else
    UNPROTECTED_BACKOFF_DELAY
  end
end

#bare_urlObject



216
217
218
# File 'app/models/remote_mirror.rb', line 216

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

#disabled?Boolean

Returns:

  • (Boolean)


148
149
150
# File 'app/models/remote_mirror.rb', line 148

def disabled?
  !enabled?
end

#enabledObject Also known as: enabled?



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

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



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

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



177
178
179
180
181
182
# File 'app/models/remote_mirror.rb', line 177

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



171
172
173
174
# File 'app/models/remote_mirror.rb', line 171

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

#mark_for_delete_if_blank_urlObject



158
159
160
# File 'app/models/remote_mirror.rb', line 158

def mark_for_delete_if_blank_url
  mark_for_destruction if url.blank?
end

#mark_for_retry!(error_message) ⇒ Object



166
167
168
169
# File 'app/models/remote_mirror.rb', line 166

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

#max_runtimeObject



232
233
234
# File 'app/models/remote_mirror.rb', line 232

def max_runtime
  last_update_at.present? ? MAX_INCREMENTAL_RUNTIME : MAX_FIRST_RUNTIME
end

#options_for_updateObject



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

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



212
213
214
# File 'app/models/remote_mirror.rb', line 212

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

#send_failure_notificationsObject



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

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



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

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)


123
124
125
# File 'app/models/remote_mirror.rb', line 123

def sync?
  enabled?
end

#update_error_message(error_message) ⇒ Object



162
163
164
# File 'app/models/remote_mirror.rb', line 162

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

#update_failed?Boolean

Returns:

  • (Boolean)


85
86
87
# File 'app/models/remote_mirror.rb', line 85

def update_failed?
  update_status == 'failed'
end

#update_in_progress?Boolean

Returns:

  • (Boolean)


89
90
91
# File 'app/models/remote_mirror.rb', line 89

def update_in_progress?
  update_status == 'started'
end

#update_repositoryObject



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

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

#updated_since?(timestamp) ⇒ Boolean

Returns:

  • (Boolean)


152
153
154
155
156
# File 'app/models/remote_mirror.rb', line 152

def updated_since?(timestamp)
  return false if failed?

  last_update_started_at && last_update_started_at > timestamp
end

#urlObject



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

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

#url=(value) ⇒ Object



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

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