notify nodes after owner change (#2543)

* proto: user id as identifier for move node

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>

* gen: regenr

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>

* grpc: move, use userid, one tx, send update

Updates #2467

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>

* integration: update move cli tests

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>

---------

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
Kristoffer Dalby 2025-04-30 19:33:38 +03:00 committed by GitHub
parent cfe9bbf829
commit 6b6509eeeb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 37 additions and 24 deletions

View File

@ -78,7 +78,7 @@ func init() {
log.Fatal(err.Error())
}
moveNodeCmd.Flags().StringP("user", "u", "", "New user")
moveNodeCmd.Flags().Uint64P("user", "u", 0, "New user")
moveNodeCmd.Flags().StringP("namespace", "n", "", "User")
moveNodeNamespaceFlag := moveNodeCmd.Flags().Lookup("namespace")
@ -470,7 +470,7 @@ var moveNodeCmd = &cobra.Command{
return
}
user, err := cmd.Flags().GetString("user")
user, err := cmd.Flags().GetUint64("user")
if err != nil {
ErrorOutput(
err,

View File

@ -1001,7 +1001,7 @@ func (x *ListNodesResponse) GetNodes() []*Node {
type MoveNodeRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"`
User string `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"`
User uint64 `protobuf:"varint,2,opt,name=user,proto3" json:"user,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -1043,11 +1043,11 @@ func (x *MoveNodeRequest) GetNodeId() uint64 {
return 0
}
func (x *MoveNodeRequest) GetUser() string {
func (x *MoveNodeRequest) GetUser() uint64 {
if x != nil {
return x.User
}
return ""
return 0
}
type MoveNodeResponse struct {
@ -1365,7 +1365,7 @@ const file_headscale_v1_node_proto_rawDesc = "" +
"\x05nodes\x18\x01 \x03(\v2\x12.headscale.v1.NodeR\x05nodes\">\n" +
"\x0fMoveNodeRequest\x12\x17\n" +
"\anode_id\x18\x01 \x01(\x04R\x06nodeId\x12\x12\n" +
"\x04user\x18\x02 \x01(\tR\x04user\":\n" +
"\x04user\x18\x02 \x01(\x04R\x04user\":\n" +
"\x10MoveNodeResponse\x12&\n" +
"\x04node\x18\x01 \x01(\v2\x12.headscale.v1.NodeR\x04node\"j\n" +
"\x16DebugCreateNodeRequest\x12\x12\n" +

View File

@ -800,7 +800,8 @@
"type": "object",
"properties": {
"user": {
"type": "string"
"type": "string",
"format": "uint64"
}
}
},

View File

@ -547,22 +547,31 @@ func (api headscaleV1APIServer) MoveNode(
ctx context.Context,
request *v1.MoveNodeRequest,
) (*v1.MoveNodeResponse, error) {
// TODO(kradalby): This should be done in one tx.
node, err := api.h.db.GetNodeByID(types.NodeID(request.GetNodeId()))
node, err := db.Write(api.h.db.DB, func(tx *gorm.DB) (*types.Node, error) {
node, err := db.GetNodeByID(tx, types.NodeID(request.GetNodeId()))
if err != nil {
return nil, err
}
user, err := api.h.db.GetUserByName(request.GetUser())
err = db.AssignNodeToUser(tx, node, types.UserID(request.GetUser()))
if err != nil {
return nil, err
}
err = api.h.db.AssignNodeToUser(node, types.UserID(user.ID))
return node, nil
})
if err != nil {
return nil, err
}
ctx = types.NotifyCtx(ctx, "cli-movenode-self", node.Hostname)
api.h.nodeNotifier.NotifyByNodeID(
ctx,
types.UpdateSelf(node.ID),
node.ID)
ctx = types.NotifyCtx(ctx, "cli-movenode", node.Hostname)
api.h.nodeNotifier.NotifyWithIgnore(ctx, types.UpdatePeerChanged(node.ID), node.ID)
return &v1.MoveNodeResponse{Node: node.Proto()}, nil
}

View File

@ -1580,6 +1580,9 @@ func TestNodeMoveCommand(t *testing.T) {
// Randomly generated node key
regID := types.MustRegistrationID()
userMap, err := headscale.MapUsers()
assertNoErr(t, err)
_, err = headscale.Execute(
[]string{
"headscale",
@ -1628,9 +1631,9 @@ func TestNodeMoveCommand(t *testing.T) {
"nodes",
"move",
"--identifier",
nodeID,
strconv.FormatUint(node.GetId(), 10),
"--user",
"new-user",
strconv.FormatUint(userMap["new-user"].GetId(), 10),
"--output",
"json",
},
@ -1668,7 +1671,7 @@ func TestNodeMoveCommand(t *testing.T) {
"--identifier",
nodeID,
"--user",
"non-existing-user",
"999",
"--output",
"json",
},
@ -1689,7 +1692,7 @@ func TestNodeMoveCommand(t *testing.T) {
"--identifier",
nodeID,
"--user",
"old-user",
strconv.FormatUint(userMap["old-user"].GetId(), 10),
"--output",
"json",
},
@ -1708,7 +1711,7 @@ func TestNodeMoveCommand(t *testing.T) {
"--identifier",
nodeID,
"--user",
"old-user",
strconv.FormatUint(userMap["old-user"].GetId(), 10),
"--output",
"json",
},

View File

@ -99,7 +99,7 @@ message ListNodesResponse { repeated Node nodes = 1; }
message MoveNodeRequest {
uint64 node_id = 1;
string user = 2;
uint64 user = 2;
}
message MoveNodeResponse { Node node = 1; }