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 included from MirrorAuthentication

MirrorAuthentication::SSH_PRIVATE_KEY_OPTS

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

at_most, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, underscore, without_order

Instance Method Details

#after_sent_notificationObject


222
223
224
# File 'app/models/remote_mirror.rb', line 222

def after_sent_notification
  update_column(:error_notification_sent, true)
end

#backoff_delayObject


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

def backoff_delay
  if self.only_protected_branches
    PROTECTED_BACKOFF_DELAY
  else
    UNPROTECTED_BACKOFF_DELAY
  end
end

#disabled?Boolean

Returns:

  • (Boolean)

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

def disabled?
  !enabled?
end

#enabledObject Also known as: enabled?


153
154
155
156
157
158
159
160
# File 'app/models/remote_mirror.rb', line 153

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?

  true
end

#ensure_remote!Object


213
214
215
216
217
218
219
220
# File 'app/models/remote_mirror.rb', line 213

def ensure_remote!
  return unless project
  return unless remote_name && remote_url

  # If this fails or the remote already exists, we won't know due to
  # https://gitlab.com/gitlab-org/gitaly/issues/1317
  project.repository.add_remote(remote_name, remote_url)
end

#mark_as_failed!(error_message) ⇒ Object


186
187
188
189
# File 'app/models/remote_mirror.rb', line 186

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

#mark_for_delete_if_blank_urlObject


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

def mark_for_delete_if_blank_url
  mark_for_destruction if url.blank?
end

#mark_for_retry!(error_message) ⇒ Object


181
182
183
184
# File 'app/models/remote_mirror.rb', line 181

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

#max_runtimeObject


234
235
236
# File 'app/models/remote_mirror.rb', line 234

def max_runtime
  last_update_at.present? ? MAX_INCREMENTAL_RUNTIME : MAX_FIRST_RUNTIME
end

#options_for_updateObject


117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'app/models/remote_mirror.rb', line 117

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

#remote_nameObject


97
98
99
# File 'app/models/remote_mirror.rb', line 97

def remote_name
  super || fallback_remote_name
end

#safe_urlObject


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

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

#syncObject


143
144
145
146
147
148
149
150
151
# File 'app/models/remote_mirror.rb', line 143

def sync
  return unless sync?

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

#sync?Boolean

Returns:

  • (Boolean)

139
140
141
# File 'app/models/remote_mirror.rb', line 139

def sync?
  enabled?
end

#update_error_message(error_message) ⇒ Object


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

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

#update_failed?Boolean

Returns:

  • (Boolean)

101
102
103
# File 'app/models/remote_mirror.rb', line 101

def update_failed?
  update_status == 'failed'
end

#update_in_progress?Boolean

Returns:

  • (Boolean)

105
106
107
# File 'app/models/remote_mirror.rb', line 105

def update_in_progress?
  update_status == 'started'
end

#update_repositoryObject


109
110
111
112
113
114
115
# File 'app/models/remote_mirror.rb', line 109

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

#updated_since?(timestamp) ⇒ Boolean

Returns:

  • (Boolean)

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

def updated_since?(timestamp)
  return false if failed?

  last_update_started_at && last_update_started_at > timestamp
end

#urlObject


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

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

#url=(value) ⇒ Object


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

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