Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSami Hiltunen <shiltunen@gitlab.com>2021-09-01 12:44:09 +0300
committerSami Hiltunen <shiltunen@gitlab.com>2021-09-03 16:59:53 +0300
commit34cfd2c2b4964cf1c0ad1704fd9e2c25666bcf16 (patch)
tree5dcd7d8974e491d3caa34734cd8b588d21d6a456
parent3b3bd14c16e48ba615c0bf751601682d55d2474c (diff)
Derive virtual storage's filesystem id from its name
Gitaly storages contain a UUID filesystem ID that is generated by the Gitaly for each of its storages. The ID is used to determine which storages can be accessed by Rails directly when rugged patches are enabled and to see whether two different storages point to the same directory when doing repository moves. When repository moves are performed, the worker first checks whether the repository's destination and source storage are the same. If they are, the move is not performed. The check is performed by comparing the filesystem IDs of the storages'. As Praefect is currently routing the server info RPC to a random Gitaly node, the filesystem ID can differ between calls as each of the Gitalys have their own ID. This causes the repository moving worker to occasionally delete repositories from the virtual storage as it receives two different IDs on sequential calls. The filesystem ID can identify cases when two storages refer to the same directory on a Gitaly node as the id is stored in a file in the storage. This is not really possible with Praefect. The storage's are only identified by the virtual storage's name. If the name changes, we can't really correlate the ID between the different names as Praefect would consider them different storages. Praefect also supports multiple virtual storages so it's not possible to generate a single ID and use it for all of the virtual storages. Given this, the approach taken here is to derive a stable filesystem ID from the virtual storage's name. This guarantees calls to a given virtual storage always return the same filesystem ID. Configuring two storages that point to the same filesystem should be considered an invalid configuration anyway. Historically, there's been cases when that has been done for plain Gitalys. This is not done for Praefect and wouldn't work as Praefect wouldn't find the repositories with an alternative virtual storage name. With that in mind, we don't have to consider the case where two virtual storages of different names point to the same backing Gitaly storages. The use cases for the filesystem ID seem to be limited and we may be able to remove it in the future once the rugged patches are removed. Changelog: fixed
-rw-r--r--internal/praefect/server_test.go10
-rw-r--r--internal/praefect/service/server/info.go13
2 files changed, 21 insertions, 2 deletions
diff --git a/internal/praefect/server_test.go b/internal/praefect/server_test.go
index cba0fef0c..8ca2a913e 100644
--- a/internal/praefect/server_test.go
+++ b/internal/praefect/server_test.go
@@ -33,6 +33,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/nodes/tracker"
"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/protoregistry"
+ serversvc "gitlab.com/gitlab-org/gitaly/v14/internal/praefect/service/server"
"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/service/transaction"
"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/transactions"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
@@ -150,7 +151,13 @@ func TestGitalyServerInfo(t *testing.T) {
ServerVersion: version.GetVersion(),
GitVersion: gitVersion.String(),
StorageStatuses: []*gitalypb.ServerInfoResponse_StorageStatus{
- {StorageName: conf.VirtualStorages[0].Name, Readable: true, Writeable: true, ReplicationFactor: 2},
+ {
+ StorageName: conf.VirtualStorages[0].Name,
+ FilesystemId: serversvc.DeriveFilesystemID(conf.VirtualStorages[0].Name).String(),
+ Readable: true,
+ Writeable: true,
+ ReplicationFactor: 2,
+ },
},
}
@@ -159,7 +166,6 @@ func TestGitalyServerInfo(t *testing.T) {
require.NoError(t, err)
for _, ss := range actual.StorageStatuses {
ss.FsType = ""
- ss.FilesystemId = ""
}
require.True(t, proto.Equal(expected, actual), "expected: %v, got: %v", expected, actual)
})
diff --git a/internal/praefect/service/server/info.go b/internal/praefect/service/server/info.go
index 4650981b6..1094a3ba7 100644
--- a/internal/praefect/service/server/info.go
+++ b/internal/praefect/service/server/info.go
@@ -4,11 +4,21 @@ import (
"context"
"sync"
+ "github.com/google/uuid"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
"google.golang.org/grpc"
)
+// filesystemIDNamespace is the UUID that is used as the namespace component when generating the UUIDv5 filesystem
+// ID from a virtual storage's name.
+var filesystemIDNamespace = uuid.MustParse("1ef1a8c6-cf52-4d0a-92a6-ca643e8bc7c5")
+
+// DeriveFilesystemID derives the virtual storage's filesystem ID from its name.
+func DeriveFilesystemID(virtualStorage string) uuid.UUID {
+ return uuid.NewSHA1(filesystemIDNamespace, []byte(virtualStorage))
+}
+
// ServerInfo sends ServerInfoRequest to all of a praefect server's internal gitaly nodes and aggregates the results into
// a response
func (s *Server) ServerInfo(ctx context.Context, in *gitalypb.ServerInfoRequest) (*gitalypb.ServerInfoResponse, error) {
@@ -67,6 +77,9 @@ func (s *Server) ServerInfo(ctx context.Context, in *gitalypb.ServerInfoRequest)
for _, storageStatus := range resp.GetStorageStatuses() {
if storageStatus.StorageName == storage {
storageStatuses[i] = storageStatus
+ // Each of the Gitaly nodes have a different filesystem ID they've generated. To have a stable filesystem
+ // ID for a given virtual storage, the filesystem ID is generated from the virtual storage's name.
+ storageStatuses[i].FilesystemId = DeriveFilesystemID(virtualStorage).String()
// the storage name in the response needs to be rewritten to be the virtual storage name
// because the praefect client has no concept of internal gitaly nodes that are behind praefect.
// From the perspective of the praefect client, the primary internal gitaly node's storage status is equivalent