Commit d1df1c5c authored by Patrick Steinhardt's avatar Patrick Steinhardt

Explicitly put timestamp into Gitaly requests

When creating git commits, the resulting commit hash is computed over
all contents of the commit. This not only includes hashes of referenced
objects like e.g. its tree, but also soft information like the author's
and committer's timestamps. As a result, commits generated at different
points in time have different object IDs.

This hasn't been a problem for Gitaly until now, a standalone Gitaly
instance still doesn't care. But this is slowly changing with the
not-so-recent introduction of Praefect and reference transactions. If
any RPC is called under a transaction, then the result will only be
committed if all Gitaly nodes taking part in the transaction arrive at
the same result. If any node tries to update a git reference to
something else than the others, then it will abort the transaction and
not modify the on-disk state.

This is where the problem is: when for example two Gitalies are part of
a transaction where the RPC shall compute a commit and update a branch
to point to that commit, then both Gitaly instances need to compute the
exact same commit, including the date. If there is time drift between
both nodes or if they didn't compute the the commit at the exact same
point in time, then chances are high they arrive at different commits
and thus fail the transaction.

Gitaly has thus introduced a new "timestamp" field for RPCs which create
commits. If it is set, its date will be used for the author and/or
committer signature. Given that this same request is then distrisbuted
to all Gitalies, they stop relying on their own local time and only use
what was provided.

The only remaining piece is that there needs to be a central location
where this time is reliably set, and the GitLab app is the natural
location to do so. So this commit starts injecting timestamps into the
requests to make transactions work reliably.
parent 4fa3ff69
......@@ -67,7 +67,8 @@ module Gitlab
source_branch: encode_binary(source_branch),
target_branch: encode_binary(target_branch),
commit_message: encode_binary(resolution.commit_message),
user: Gitlab::Git::User.from_gitlab(resolution.user).to_gitaly
user: Gitlab::Git::User.from_gitlab(resolution.user).to_gitaly,
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
end
end
......
......@@ -32,7 +32,8 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
tag_name: encode_binary(tag_name),
target_revision: encode_binary(target),
message: encode_binary(message.to_s)
message: encode_binary(message.to_s),
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
response = GitalyClient.call(@repository.storage, :operation_service, :user_create_tag, request, timeout: GitalyClient.long_timeout)
......@@ -111,7 +112,8 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
message: encode_binary(message),
first_parent_ref: encode_binary(first_parent_ref),
allow_conflicts: allow_conflicts
allow_conflicts: allow_conflicts,
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
response = GitalyClient.call(@repository.storage, :operation_service,
......@@ -140,7 +142,8 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
commit_id: source_sha,
branch: encode_binary(target_branch),
message: encode_binary(message)
message: encode_binary(message),
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
)
......@@ -234,7 +237,8 @@ module Gitlab
branch_sha: branch_sha,
remote_repository: remote_repository.gitaly_repository,
remote_branch: encode_binary(remote_branch),
git_push_options: push_options
git_push_options: push_options,
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
)
)
......@@ -255,7 +259,7 @@ module Gitlab
request_enum.close
end
def user_squash(user, squash_id, start_sha, end_sha, author, message)
def user_squash(user, squash_id, start_sha, end_sha, author, message, time = Time.now.utc)
request = Gitaly::UserSquashRequest.new(
repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
......@@ -263,7 +267,8 @@ module Gitlab
start_sha: start_sha,
end_sha: end_sha,
author: Gitlab::Git::User.from_gitlab(author).to_gitaly,
commit_message: encode_binary(message)
commit_message: encode_binary(message),
timestamp: Google::Protobuf::Timestamp.new(seconds: time.to_i)
)
response = GitalyClient.call(
......@@ -288,7 +293,8 @@ module Gitlab
commit_sha: commit_sha,
branch: encode_binary(branch),
submodule: encode_binary(submodule),
commit_message: encode_binary(message)
commit_message: encode_binary(message),
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
response = GitalyClient.call(
......@@ -357,7 +363,8 @@ module Gitlab
header = Gitaly::UserApplyPatchRequest::Header.new(
repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
target_branch: encode_binary(branch_name)
target_branch: encode_binary(branch_name),
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
reader = binary_io(patches)
......@@ -446,7 +453,8 @@ module Gitlab
start_branch_name: encode_binary(start_branch_name),
start_repository: start_repository.gitaly_repository,
force: force,
start_sha: encode_binary(start_sha)
start_sha: encode_binary(start_sha),
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
end
# rubocop:enable Metrics/ParameterLists
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment