mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
machine: make each machine the source of truth for its configuration, sync it to cluster store
This commit is contained in:
@@ -70,7 +70,8 @@ At least one flag must be specified to perform an update.`,
|
||||
fmt.Sprintf("WireGuard endpoint address that other machines in the cluster should use to establish "+
|
||||
"WireGuard connections\n"+
|
||||
"to this machine. This doesn't change the address/port WireGuard listens on the machine.\n"+
|
||||
"Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is %d if omitted.\n", network.DefaultWireGuardPort)+
|
||||
"Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is %d if omitted.\n",
|
||||
network.DefaultWireGuardPort)+
|
||||
"Multiple endpoints can be specified by repeating the flag or using a comma-separated list.",
|
||||
)
|
||||
|
||||
@@ -89,16 +90,13 @@ func update(ctx context.Context, uncli *cli.CLI, cmd *cobra.Command, opts update
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// First, resolve the machine to get its ID
|
||||
// Resolve the machine to capture its current configuration for the before/after report and to validate existence.
|
||||
machine, err := client.InspectMachine(ctx, machineNameOrID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("find machine: %w", err)
|
||||
}
|
||||
|
||||
// Build the update request
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: machine.Machine.Id,
|
||||
}
|
||||
req := &pb.UpdateMachineRequest{}
|
||||
|
||||
if opts.name != "" {
|
||||
req.Name = &opts.name
|
||||
@@ -131,8 +129,7 @@ func update(ctx context.Context, uncli *cli.CLI, cmd *cobra.Command, opts update
|
||||
req.Endpoints = endpoints
|
||||
}
|
||||
|
||||
// Perform the update operation
|
||||
updatedMachine, err := client.UpdateMachine(ctx, req)
|
||||
updatedMachine, err := client.UpdateMachine(ctx, machine.Machine.Id, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update machine: %w", err)
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ func (x DNSRecord_RecordType) Number() protoreflect.EnumNumber {
|
||||
|
||||
// Deprecated: Use DNSRecord_RecordType.Descriptor instead.
|
||||
func (DNSRecord_RecordType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{11, 0}
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{9, 0}
|
||||
}
|
||||
|
||||
type AddMachineRequest struct {
|
||||
@@ -339,126 +339,6 @@ func (x *ListMachinesResponse) GetMachines() []*MachineMember {
|
||||
return nil
|
||||
}
|
||||
|
||||
type UpdateMachineRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Machine to update
|
||||
MachineId string `protobuf:"bytes,1,opt,name=machine_id,json=machineId,proto3" json:"machine_id,omitempty"`
|
||||
// Updated machine information
|
||||
Name *string `protobuf:"bytes,2,opt,name=name,proto3,oneof" json:"name,omitempty"`
|
||||
PublicIp *IP `protobuf:"bytes,3,opt,name=public_ip,json=publicIp,proto3,oneof" json:"public_ip,omitempty"`
|
||||
Endpoints []*IPPort `protobuf:"bytes,4,rep,name=endpoints,proto3" json:"endpoints,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateMachineRequest) Reset() {
|
||||
*x = UpdateMachineRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *UpdateMachineRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateMachineRequest) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateMachineRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UpdateMachineRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateMachineRequest) Descriptor() ([]byte, []int) {
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *UpdateMachineRequest) GetMachineId() string {
|
||||
if x != nil {
|
||||
return x.MachineId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UpdateMachineRequest) GetName() string {
|
||||
if x != nil && x.Name != nil {
|
||||
return *x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UpdateMachineRequest) GetPublicIp() *IP {
|
||||
if x != nil {
|
||||
return x.PublicIp
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UpdateMachineRequest) GetEndpoints() []*IPPort {
|
||||
if x != nil {
|
||||
return x.Endpoints
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UpdateMachineResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Machine *MachineInfo `protobuf:"bytes,1,opt,name=machine,proto3" json:"machine,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateMachineResponse) Reset() {
|
||||
*x = UpdateMachineResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *UpdateMachineResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateMachineResponse) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateMachineResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UpdateMachineResponse.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateMachineResponse) Descriptor() ([]byte, []int) {
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *UpdateMachineResponse) GetMachine() *MachineInfo {
|
||||
if x != nil {
|
||||
return x.Machine
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RemoveMachineRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -470,7 +350,7 @@ type RemoveMachineRequest struct {
|
||||
func (x *RemoveMachineRequest) Reset() {
|
||||
*x = RemoveMachineRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[6]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -483,7 +363,7 @@ func (x *RemoveMachineRequest) String() string {
|
||||
func (*RemoveMachineRequest) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveMachineRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[6]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -496,7 +376,7 @@ func (x *RemoveMachineRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RemoveMachineRequest.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveMachineRequest) Descriptor() ([]byte, []int) {
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{6}
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *RemoveMachineRequest) GetId() string {
|
||||
@@ -517,7 +397,7 @@ type Domain struct {
|
||||
func (x *Domain) Reset() {
|
||||
*x = Domain{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[7]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -530,7 +410,7 @@ func (x *Domain) String() string {
|
||||
func (*Domain) ProtoMessage() {}
|
||||
|
||||
func (x *Domain) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[7]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -543,7 +423,7 @@ func (x *Domain) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Domain.ProtoReflect.Descriptor instead.
|
||||
func (*Domain) Descriptor() ([]byte, []int) {
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{7}
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *Domain) GetName() string {
|
||||
@@ -564,7 +444,7 @@ type ReserveDomainRequest struct {
|
||||
func (x *ReserveDomainRequest) Reset() {
|
||||
*x = ReserveDomainRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[8]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -577,7 +457,7 @@ func (x *ReserveDomainRequest) String() string {
|
||||
func (*ReserveDomainRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ReserveDomainRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[8]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -590,7 +470,7 @@ func (x *ReserveDomainRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ReserveDomainRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ReserveDomainRequest) Descriptor() ([]byte, []int) {
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{8}
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *ReserveDomainRequest) GetEndpoint() string {
|
||||
@@ -611,7 +491,7 @@ type CreateDomainRecordsRequest struct {
|
||||
func (x *CreateDomainRecordsRequest) Reset() {
|
||||
*x = CreateDomainRecordsRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[9]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -624,7 +504,7 @@ func (x *CreateDomainRecordsRequest) String() string {
|
||||
func (*CreateDomainRecordsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CreateDomainRecordsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[9]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[7]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -637,7 +517,7 @@ func (x *CreateDomainRecordsRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CreateDomainRecordsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CreateDomainRecordsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{9}
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *CreateDomainRecordsRequest) GetRecords() []*DNSRecord {
|
||||
@@ -658,7 +538,7 @@ type CreateDomainRecordsResponse struct {
|
||||
func (x *CreateDomainRecordsResponse) Reset() {
|
||||
*x = CreateDomainRecordsResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[10]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -671,7 +551,7 @@ func (x *CreateDomainRecordsResponse) String() string {
|
||||
func (*CreateDomainRecordsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CreateDomainRecordsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[10]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -684,7 +564,7 @@ func (x *CreateDomainRecordsResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CreateDomainRecordsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CreateDomainRecordsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{10}
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *CreateDomainRecordsResponse) GetRecords() []*DNSRecord {
|
||||
@@ -707,7 +587,7 @@ type DNSRecord struct {
|
||||
func (x *DNSRecord) Reset() {
|
||||
*x = DNSRecord{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[11]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -720,7 +600,7 @@ func (x *DNSRecord) String() string {
|
||||
func (*DNSRecord) ProtoMessage() {}
|
||||
|
||||
func (x *DNSRecord) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[11]
|
||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[9]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -733,7 +613,7 @@ func (x *DNSRecord) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use DNSRecord.ProtoReflect.Descriptor instead.
|
||||
func (*DNSRecord) Descriptor() ([]byte, []int) {
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{11}
|
||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *DNSRecord) GetName() string {
|
||||
@@ -797,87 +677,66 @@ var file_internal_machine_api_pb_cluster_proto_rawDesc = []byte{
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63,
|
||||
0x68, 0x69, 0x6e, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x68,
|
||||
0x69, 0x6e, 0x65, 0x73, 0x22, 0xbb, 0x01, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d,
|
||||
0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
|
||||
0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49,
|
||||
0x50, 0x48, 0x01, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x70, 0x88, 0x01, 0x01,
|
||||
0x12, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x50, 0x50, 0x6f, 0x72, 0x74,
|
||||
0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x5f,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
|
||||
0x69, 0x70, 0x22, 0x43, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68,
|
||||
0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x07, 0x6d,
|
||||
0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07,
|
||||
0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x26, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76,
|
||||
0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22,
|
||||
0x1c, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x32, 0x0a,
|
||||
0x14, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
|
||||
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
|
||||
0x74, 0x22, 0x46, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x28, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64,
|
||||
0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x47, 0x0a, 0x1b, 0x43, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f,
|
||||
0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72,
|
||||
0x64, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x09, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0e, 0x32, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f,
|
||||
0x72, 0x64, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
|
||||
0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x2e, 0x0a, 0x0a, 0x52,
|
||||
0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53,
|
||||
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x05, 0x0a, 0x01, 0x41, 0x10,
|
||||
0x01, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x41, 0x41, 0x41, 0x10, 0x02, 0x32, 0x92, 0x04, 0x0a, 0x07,
|
||||
0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x4d, 0x61,
|
||||
0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64, 0x64, 0x4d,
|
||||
0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61,
|
||||
0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0d, 0x55, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x42, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
||||
0x6e, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d,
|
||||
0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x37, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x30,
|
||||
0x0a, 0x09, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
|
||||
0x70, 0x74, 0x79, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x12, 0x34, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x58, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x1f, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70,
|
||||
0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b, 0x69, 0x2f, 0x75, 0x6e, 0x63, 0x6c, 0x6f, 0x75,
|
||||
0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
||||
0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x69, 0x6e, 0x65, 0x73, 0x22, 0x26, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x61,
|
||||
0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1c, 0x0a, 0x06,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x32, 0x0a, 0x14, 0x52, 0x65,
|
||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x46,
|
||||
0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65,
|
||||
0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x07,
|
||||
0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72,
|
||||
0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x47, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53,
|
||||
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22,
|
||||
0x96, 0x01, 0x0a, 0x09, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e,
|
||||
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09,
|
||||
0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x2e, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f,
|
||||
0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
|
||||
0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x05, 0x0a, 0x01, 0x41, 0x10, 0x01, 0x12, 0x08,
|
||||
0x0a, 0x04, 0x41, 0x41, 0x41, 0x41, 0x10, 0x02, 0x32, 0xca, 0x03, 0x0a, 0x07, 0x43, 0x6c, 0x75,
|
||||
0x73, 0x74, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
||||
0x6e, 0x65, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68,
|
||||
0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
||||
0x6e, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65,
|
||||
0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x37, 0x0a, 0x0d, 0x52, 0x65,
|
||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x6d,
|
||||
0x61, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44,
|
||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0b,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x58, 0x0a, 0x13, 0x43,
|
||||
0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72,
|
||||
0x64, 0x73, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44,
|
||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b, 0x69, 0x2f, 0x75,
|
||||
0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
||||
0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -893,7 +752,7 @@ func file_internal_machine_api_pb_cluster_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_internal_machine_api_pb_cluster_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_internal_machine_api_pb_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
|
||||
var file_internal_machine_api_pb_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_internal_machine_api_pb_cluster_proto_goTypes = []any{
|
||||
(MachineMember_MembershipState)(0), // 0: api.MachineMember.MembershipState
|
||||
(DNSRecord_RecordType)(0), // 1: api.DNSRecord.RecordType
|
||||
@@ -901,54 +760,46 @@ var file_internal_machine_api_pb_cluster_proto_goTypes = []any{
|
||||
(*AddMachineResponse)(nil), // 3: api.AddMachineResponse
|
||||
(*MachineMember)(nil), // 4: api.MachineMember
|
||||
(*ListMachinesResponse)(nil), // 5: api.ListMachinesResponse
|
||||
(*UpdateMachineRequest)(nil), // 6: api.UpdateMachineRequest
|
||||
(*UpdateMachineResponse)(nil), // 7: api.UpdateMachineResponse
|
||||
(*RemoveMachineRequest)(nil), // 8: api.RemoveMachineRequest
|
||||
(*Domain)(nil), // 9: api.Domain
|
||||
(*ReserveDomainRequest)(nil), // 10: api.ReserveDomainRequest
|
||||
(*CreateDomainRecordsRequest)(nil), // 11: api.CreateDomainRecordsRequest
|
||||
(*CreateDomainRecordsResponse)(nil), // 12: api.CreateDomainRecordsResponse
|
||||
(*DNSRecord)(nil), // 13: api.DNSRecord
|
||||
(*NetworkConfig)(nil), // 14: api.NetworkConfig
|
||||
(*IP)(nil), // 15: api.IP
|
||||
(*MachineInfo)(nil), // 16: api.MachineInfo
|
||||
(*IPPort)(nil), // 17: api.IPPort
|
||||
(*emptypb.Empty)(nil), // 18: google.protobuf.Empty
|
||||
(*RemoveMachineRequest)(nil), // 6: api.RemoveMachineRequest
|
||||
(*Domain)(nil), // 7: api.Domain
|
||||
(*ReserveDomainRequest)(nil), // 8: api.ReserveDomainRequest
|
||||
(*CreateDomainRecordsRequest)(nil), // 9: api.CreateDomainRecordsRequest
|
||||
(*CreateDomainRecordsResponse)(nil), // 10: api.CreateDomainRecordsResponse
|
||||
(*DNSRecord)(nil), // 11: api.DNSRecord
|
||||
(*NetworkConfig)(nil), // 12: api.NetworkConfig
|
||||
(*IP)(nil), // 13: api.IP
|
||||
(*MachineInfo)(nil), // 14: api.MachineInfo
|
||||
(*emptypb.Empty)(nil), // 15: google.protobuf.Empty
|
||||
}
|
||||
var file_internal_machine_api_pb_cluster_proto_depIdxs = []int32{
|
||||
14, // 0: api.AddMachineRequest.network:type_name -> api.NetworkConfig
|
||||
15, // 1: api.AddMachineRequest.public_ip:type_name -> api.IP
|
||||
16, // 2: api.AddMachineResponse.machine:type_name -> api.MachineInfo
|
||||
16, // 3: api.MachineMember.machine:type_name -> api.MachineInfo
|
||||
12, // 0: api.AddMachineRequest.network:type_name -> api.NetworkConfig
|
||||
13, // 1: api.AddMachineRequest.public_ip:type_name -> api.IP
|
||||
14, // 2: api.AddMachineResponse.machine:type_name -> api.MachineInfo
|
||||
14, // 3: api.MachineMember.machine:type_name -> api.MachineInfo
|
||||
0, // 4: api.MachineMember.state:type_name -> api.MachineMember.MembershipState
|
||||
4, // 5: api.ListMachinesResponse.machines:type_name -> api.MachineMember
|
||||
15, // 6: api.UpdateMachineRequest.public_ip:type_name -> api.IP
|
||||
17, // 7: api.UpdateMachineRequest.endpoints:type_name -> api.IPPort
|
||||
16, // 8: api.UpdateMachineResponse.machine:type_name -> api.MachineInfo
|
||||
13, // 9: api.CreateDomainRecordsRequest.records:type_name -> api.DNSRecord
|
||||
13, // 10: api.CreateDomainRecordsResponse.records:type_name -> api.DNSRecord
|
||||
1, // 11: api.DNSRecord.type:type_name -> api.DNSRecord.RecordType
|
||||
2, // 12: api.Cluster.AddMachine:input_type -> api.AddMachineRequest
|
||||
18, // 13: api.Cluster.ListMachines:input_type -> google.protobuf.Empty
|
||||
6, // 14: api.Cluster.UpdateMachine:input_type -> api.UpdateMachineRequest
|
||||
8, // 15: api.Cluster.RemoveMachine:input_type -> api.RemoveMachineRequest
|
||||
10, // 16: api.Cluster.ReserveDomain:input_type -> api.ReserveDomainRequest
|
||||
18, // 17: api.Cluster.GetDomain:input_type -> google.protobuf.Empty
|
||||
18, // 18: api.Cluster.ReleaseDomain:input_type -> google.protobuf.Empty
|
||||
11, // 19: api.Cluster.CreateDomainRecords:input_type -> api.CreateDomainRecordsRequest
|
||||
3, // 20: api.Cluster.AddMachine:output_type -> api.AddMachineResponse
|
||||
5, // 21: api.Cluster.ListMachines:output_type -> api.ListMachinesResponse
|
||||
7, // 22: api.Cluster.UpdateMachine:output_type -> api.UpdateMachineResponse
|
||||
18, // 23: api.Cluster.RemoveMachine:output_type -> google.protobuf.Empty
|
||||
9, // 24: api.Cluster.ReserveDomain:output_type -> api.Domain
|
||||
9, // 25: api.Cluster.GetDomain:output_type -> api.Domain
|
||||
9, // 26: api.Cluster.ReleaseDomain:output_type -> api.Domain
|
||||
12, // 27: api.Cluster.CreateDomainRecords:output_type -> api.CreateDomainRecordsResponse
|
||||
20, // [20:28] is the sub-list for method output_type
|
||||
12, // [12:20] is the sub-list for method input_type
|
||||
12, // [12:12] is the sub-list for extension type_name
|
||||
12, // [12:12] is the sub-list for extension extendee
|
||||
0, // [0:12] is the sub-list for field type_name
|
||||
11, // 6: api.CreateDomainRecordsRequest.records:type_name -> api.DNSRecord
|
||||
11, // 7: api.CreateDomainRecordsResponse.records:type_name -> api.DNSRecord
|
||||
1, // 8: api.DNSRecord.type:type_name -> api.DNSRecord.RecordType
|
||||
2, // 9: api.Cluster.AddMachine:input_type -> api.AddMachineRequest
|
||||
15, // 10: api.Cluster.ListMachines:input_type -> google.protobuf.Empty
|
||||
6, // 11: api.Cluster.RemoveMachine:input_type -> api.RemoveMachineRequest
|
||||
8, // 12: api.Cluster.ReserveDomain:input_type -> api.ReserveDomainRequest
|
||||
15, // 13: api.Cluster.GetDomain:input_type -> google.protobuf.Empty
|
||||
15, // 14: api.Cluster.ReleaseDomain:input_type -> google.protobuf.Empty
|
||||
9, // 15: api.Cluster.CreateDomainRecords:input_type -> api.CreateDomainRecordsRequest
|
||||
3, // 16: api.Cluster.AddMachine:output_type -> api.AddMachineResponse
|
||||
5, // 17: api.Cluster.ListMachines:output_type -> api.ListMachinesResponse
|
||||
15, // 18: api.Cluster.RemoveMachine:output_type -> google.protobuf.Empty
|
||||
7, // 19: api.Cluster.ReserveDomain:output_type -> api.Domain
|
||||
7, // 20: api.Cluster.GetDomain:output_type -> api.Domain
|
||||
7, // 21: api.Cluster.ReleaseDomain:output_type -> api.Domain
|
||||
10, // 22: api.Cluster.CreateDomainRecords:output_type -> api.CreateDomainRecordsResponse
|
||||
16, // [16:23] is the sub-list for method output_type
|
||||
9, // [9:16] is the sub-list for method input_type
|
||||
9, // [9:9] is the sub-list for extension type_name
|
||||
9, // [9:9] is the sub-list for extension extendee
|
||||
0, // [0:9] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_internal_machine_api_pb_cluster_proto_init() }
|
||||
@@ -1008,30 +859,6 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
||||
}
|
||||
}
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*UpdateMachineRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*UpdateMachineResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*RemoveMachineRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -1043,7 +870,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*Domain); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -1055,7 +882,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[8].Exporter = func(v any, i int) any {
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ReserveDomainRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -1067,7 +894,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[9].Exporter = func(v any, i int) any {
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*CreateDomainRecordsRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -1079,7 +906,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[10].Exporter = func(v any, i int) any {
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[8].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*CreateDomainRecordsResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -1091,7 +918,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[11].Exporter = func(v any, i int) any {
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[9].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*DNSRecord); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -1104,14 +931,13 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
||||
}
|
||||
}
|
||||
}
|
||||
file_internal_machine_api_pb_cluster_proto_msgTypes[4].OneofWrappers = []any{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_internal_machine_api_pb_cluster_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumMessages: 12,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@@ -11,7 +11,6 @@ import "internal/machine/api/pb/machine.proto";
|
||||
service Cluster {
|
||||
rpc AddMachine(AddMachineRequest) returns (AddMachineResponse);
|
||||
rpc ListMachines(google.protobuf.Empty) returns (ListMachinesResponse);
|
||||
rpc UpdateMachine(UpdateMachineRequest) returns (UpdateMachineResponse);
|
||||
rpc RemoveMachine(RemoveMachineRequest) returns (google.protobuf.Empty);
|
||||
|
||||
rpc ReserveDomain(ReserveDomainRequest) returns (Domain);
|
||||
@@ -51,20 +50,6 @@ message ListMachinesResponse {
|
||||
repeated MachineMember machines = 1;
|
||||
}
|
||||
|
||||
message UpdateMachineRequest {
|
||||
// Machine to update
|
||||
string machine_id = 1;
|
||||
|
||||
// Updated machine information
|
||||
optional string name = 2;
|
||||
optional IP public_ip = 3;
|
||||
repeated IPPort endpoints = 4;
|
||||
}
|
||||
|
||||
message UpdateMachineResponse {
|
||||
MachineInfo machine = 1;
|
||||
}
|
||||
|
||||
message RemoveMachineRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ const _ = grpc.SupportPackageIsVersion9
|
||||
const (
|
||||
Cluster_AddMachine_FullMethodName = "/api.Cluster/AddMachine"
|
||||
Cluster_ListMachines_FullMethodName = "/api.Cluster/ListMachines"
|
||||
Cluster_UpdateMachine_FullMethodName = "/api.Cluster/UpdateMachine"
|
||||
Cluster_RemoveMachine_FullMethodName = "/api.Cluster/RemoveMachine"
|
||||
Cluster_ReserveDomain_FullMethodName = "/api.Cluster/ReserveDomain"
|
||||
Cluster_GetDomain_FullMethodName = "/api.Cluster/GetDomain"
|
||||
@@ -36,7 +35,6 @@ const (
|
||||
type ClusterClient interface {
|
||||
AddMachine(ctx context.Context, in *AddMachineRequest, opts ...grpc.CallOption) (*AddMachineResponse, error)
|
||||
ListMachines(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ListMachinesResponse, error)
|
||||
UpdateMachine(ctx context.Context, in *UpdateMachineRequest, opts ...grpc.CallOption) (*UpdateMachineResponse, error)
|
||||
RemoveMachine(ctx context.Context, in *RemoveMachineRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
ReserveDomain(ctx context.Context, in *ReserveDomainRequest, opts ...grpc.CallOption) (*Domain, error)
|
||||
GetDomain(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Domain, error)
|
||||
@@ -72,16 +70,6 @@ func (c *clusterClient) ListMachines(ctx context.Context, in *emptypb.Empty, opt
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clusterClient) UpdateMachine(ctx context.Context, in *UpdateMachineRequest, opts ...grpc.CallOption) (*UpdateMachineResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UpdateMachineResponse)
|
||||
err := c.cc.Invoke(ctx, Cluster_UpdateMachine_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clusterClient) RemoveMachine(ctx context.Context, in *RemoveMachineRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(emptypb.Empty)
|
||||
@@ -138,7 +126,6 @@ func (c *clusterClient) CreateDomainRecords(ctx context.Context, in *CreateDomai
|
||||
type ClusterServer interface {
|
||||
AddMachine(context.Context, *AddMachineRequest) (*AddMachineResponse, error)
|
||||
ListMachines(context.Context, *emptypb.Empty) (*ListMachinesResponse, error)
|
||||
UpdateMachine(context.Context, *UpdateMachineRequest) (*UpdateMachineResponse, error)
|
||||
RemoveMachine(context.Context, *RemoveMachineRequest) (*emptypb.Empty, error)
|
||||
ReserveDomain(context.Context, *ReserveDomainRequest) (*Domain, error)
|
||||
GetDomain(context.Context, *emptypb.Empty) (*Domain, error)
|
||||
@@ -160,9 +147,6 @@ func (UnimplementedClusterServer) AddMachine(context.Context, *AddMachineRequest
|
||||
func (UnimplementedClusterServer) ListMachines(context.Context, *emptypb.Empty) (*ListMachinesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListMachines not implemented")
|
||||
}
|
||||
func (UnimplementedClusterServer) UpdateMachine(context.Context, *UpdateMachineRequest) (*UpdateMachineResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateMachine not implemented")
|
||||
}
|
||||
func (UnimplementedClusterServer) RemoveMachine(context.Context, *RemoveMachineRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RemoveMachine not implemented")
|
||||
}
|
||||
@@ -235,24 +219,6 @@ func _Cluster_ListMachines_Handler(srv interface{}, ctx context.Context, dec fun
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Cluster_UpdateMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateMachineRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClusterServer).UpdateMachine(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Cluster_UpdateMachine_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClusterServer).UpdateMachine(ctx, req.(*UpdateMachineRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Cluster_RemoveMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RemoveMachineRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -358,10 +324,6 @@ var Cluster_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "ListMachines",
|
||||
Handler: _Cluster_ListMachines_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateMachine",
|
||||
Handler: _Cluster_UpdateMachine_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RemoveMachine",
|
||||
Handler: _Cluster_RemoveMachine_Handler,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,8 @@ service Machine {
|
||||
rpc Inspect(google.protobuf.Empty) returns (MachineInfo);
|
||||
// InspectMachine retrieves detailed information about the machine. Supports broadcasting to multiple machines.
|
||||
rpc InspectMachine(google.protobuf.Empty) returns (InspectMachineResponse);
|
||||
// UpdateMachine updates the configuration of the machine.
|
||||
rpc UpdateMachine(UpdateMachineRequest) returns (UpdateMachineResponse);
|
||||
// InspectWireGuardNetwork retrieves the current WireGuard network configuration and peer status.
|
||||
rpc InspectWireGuardNetwork(google.protobuf.Empty) returns (InspectWireGuardNetworkResponse);
|
||||
// Reset restores the machine to a clean state, removing all cluster-related configuration and data.
|
||||
@@ -45,6 +47,17 @@ message NetworkConfig {
|
||||
bytes public_key = 4;
|
||||
}
|
||||
|
||||
message UpdateMachineRequest {
|
||||
// Updated machine information. Only the set fields are applied.
|
||||
optional string name = 1;
|
||||
optional IP public_ip = 2;
|
||||
repeated IPPort endpoints = 3;
|
||||
}
|
||||
|
||||
message UpdateMachineResponse {
|
||||
MachineInfo machine = 1;
|
||||
}
|
||||
|
||||
message CheckPrerequisitesResponse {
|
||||
// Overall status of the checks.
|
||||
bool satisfied = 1;
|
||||
|
||||
@@ -26,6 +26,7 @@ const (
|
||||
Machine_Token_FullMethodName = "/api.Machine/Token"
|
||||
Machine_Inspect_FullMethodName = "/api.Machine/Inspect"
|
||||
Machine_InspectMachine_FullMethodName = "/api.Machine/InspectMachine"
|
||||
Machine_UpdateMachine_FullMethodName = "/api.Machine/UpdateMachine"
|
||||
Machine_InspectWireGuardNetwork_FullMethodName = "/api.Machine/InspectWireGuardNetwork"
|
||||
Machine_Reset_FullMethodName = "/api.Machine/Reset"
|
||||
Machine_InspectService_FullMethodName = "/api.Machine/InspectService"
|
||||
@@ -45,6 +46,8 @@ type MachineClient interface {
|
||||
Inspect(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MachineInfo, error)
|
||||
// InspectMachine retrieves detailed information about the machine. Supports broadcasting to multiple machines.
|
||||
InspectMachine(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*InspectMachineResponse, error)
|
||||
// UpdateMachine updates the configuration of the machine.
|
||||
UpdateMachine(ctx context.Context, in *UpdateMachineRequest, opts ...grpc.CallOption) (*UpdateMachineResponse, error)
|
||||
// InspectWireGuardNetwork retrieves the current WireGuard network configuration and peer status.
|
||||
InspectWireGuardNetwork(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*InspectWireGuardNetworkResponse, error)
|
||||
// Reset restores the machine to a clean state, removing all cluster-related configuration and data.
|
||||
@@ -121,6 +124,16 @@ func (c *machineClient) InspectMachine(ctx context.Context, in *emptypb.Empty, o
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *machineClient) UpdateMachine(ctx context.Context, in *UpdateMachineRequest, opts ...grpc.CallOption) (*UpdateMachineResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UpdateMachineResponse)
|
||||
err := c.cc.Invoke(ctx, Machine_UpdateMachine_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *machineClient) InspectWireGuardNetwork(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*InspectWireGuardNetworkResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(InspectWireGuardNetworkResponse)
|
||||
@@ -183,6 +196,8 @@ type MachineServer interface {
|
||||
Inspect(context.Context, *emptypb.Empty) (*MachineInfo, error)
|
||||
// InspectMachine retrieves detailed information about the machine. Supports broadcasting to multiple machines.
|
||||
InspectMachine(context.Context, *emptypb.Empty) (*InspectMachineResponse, error)
|
||||
// UpdateMachine updates the configuration of the machine.
|
||||
UpdateMachine(context.Context, *UpdateMachineRequest) (*UpdateMachineResponse, error)
|
||||
// InspectWireGuardNetwork retrieves the current WireGuard network configuration and peer status.
|
||||
InspectWireGuardNetwork(context.Context, *emptypb.Empty) (*InspectWireGuardNetworkResponse, error)
|
||||
// Reset restores the machine to a clean state, removing all cluster-related configuration and data.
|
||||
@@ -217,6 +232,9 @@ func (UnimplementedMachineServer) Inspect(context.Context, *emptypb.Empty) (*Mac
|
||||
func (UnimplementedMachineServer) InspectMachine(context.Context, *emptypb.Empty) (*InspectMachineResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method InspectMachine not implemented")
|
||||
}
|
||||
func (UnimplementedMachineServer) UpdateMachine(context.Context, *UpdateMachineRequest) (*UpdateMachineResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateMachine not implemented")
|
||||
}
|
||||
func (UnimplementedMachineServer) InspectWireGuardNetwork(context.Context, *emptypb.Empty) (*InspectWireGuardNetworkResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method InspectWireGuardNetwork not implemented")
|
||||
}
|
||||
@@ -358,6 +376,24 @@ func _Machine_InspectMachine_Handler(srv interface{}, ctx context.Context, dec f
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Machine_UpdateMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateMachineRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(MachineServer).UpdateMachine(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Machine_UpdateMachine_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MachineServer).UpdateMachine(ctx, req.(*UpdateMachineRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Machine_InspectWireGuardNetwork_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(emptypb.Empty)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -454,6 +490,10 @@ var Machine_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "InspectMachine",
|
||||
Handler: _Machine_InspectMachine_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateMachine",
|
||||
Handler: _Machine_UpdateMachine_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "InspectWireGuardNetwork",
|
||||
Handler: _Machine_InspectWireGuardNetwork_Handler,
|
||||
|
||||
@@ -32,6 +32,8 @@ import (
|
||||
// the WireGuard network, API server listening the WireGuard network, Corrosion service, Docker network and containers,
|
||||
// and others.
|
||||
type clusterController struct {
|
||||
// machine is the parent machine.
|
||||
machine *Machine
|
||||
state *State
|
||||
store *store.Store
|
||||
|
||||
@@ -63,7 +65,7 @@ type clusterController struct {
|
||||
}
|
||||
|
||||
func newClusterController(
|
||||
state *State,
|
||||
machine *Machine,
|
||||
store *store.Store,
|
||||
server *grpc.Server,
|
||||
corroService corroservice.Service,
|
||||
@@ -85,14 +87,15 @@ func newClusterController(
|
||||
endpointChanges := wgnet.WatchEndpoints()
|
||||
|
||||
return &clusterController{
|
||||
state: state,
|
||||
machine: machine,
|
||||
state: machine.state,
|
||||
store: store,
|
||||
wgnet: wgnet,
|
||||
endpointChanges: endpointChanges,
|
||||
server: server,
|
||||
corroService: corroService,
|
||||
corrosionDir: corrosionDir,
|
||||
dockerCtrl: docker.NewController(state.ID, dockerService, store),
|
||||
dockerCtrl: docker.NewController(machine.state.ID, dockerService, store),
|
||||
dockerReady: dockerReady,
|
||||
clusterReady: clusterReady,
|
||||
caddyconfigCtrl: caddyfileCtrl,
|
||||
@@ -191,6 +194,12 @@ func (cc *clusterController) Run(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Republish this machine's info from local state (the source of truth) to the cluster store. This keeps the
|
||||
// store consistent with the actual machine state on every start.
|
||||
if err = cc.syncMachineInfo(ctx); err != nil {
|
||||
return fmt.Errorf("sync machine info to cluster store: %w", err)
|
||||
}
|
||||
|
||||
errGroup.Go(func() error {
|
||||
slog.Info("Starting metrics server.")
|
||||
if err := cc.metricsServer.Run(ctx); err != nil {
|
||||
@@ -485,6 +494,69 @@ func (cc *clusterController) waitKnownMissingChanges(ctx context.Context) error
|
||||
}
|
||||
}
|
||||
|
||||
// syncMachineInfo republishes this machine's info from local state to the cluster store. The local state is the
|
||||
// source of truth for the machine's own MachineInfo.
|
||||
func (cc *clusterController) syncMachineInfo(ctx context.Context) error {
|
||||
if err := cc.backfillMachineState(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info := cc.machine.Info()
|
||||
if err := cc.store.UpdateMachine(ctx, info); err != nil {
|
||||
if errors.Is(err, store.ErrMachineNotFound) {
|
||||
// This should not happen but let's try to recreate it.
|
||||
if createErr := cc.store.CreateMachine(ctx, info); createErr != nil {
|
||||
return fmt.Errorf("create machine in store: %w", createErr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("update machine in store: %w", err)
|
||||
}
|
||||
|
||||
slog.Info("Synced machine info to cluster store.", "id", info.Id, "name", info.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// backfillMachineState backfills legacy local state that predates local ownership of endpoints/public IP
|
||||
// (implemented in 0.20) from the cluster store.
|
||||
func (cc *clusterController) backfillMachineState(ctx context.Context) error {
|
||||
cc.state.mu.Lock()
|
||||
defer cc.state.mu.Unlock()
|
||||
|
||||
if len(cc.state.Network.Endpoints) > 0 && cc.state.PublicIP.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
existing, err := cc.store.GetMachine(ctx, cc.state.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrMachineNotFound) {
|
||||
// No existing row to backfill from. syncMachineInfo will create it.
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("get machine from store: %w", err)
|
||||
}
|
||||
|
||||
changed := false
|
||||
if len(cc.state.Network.Endpoints) == 0 {
|
||||
if endpoints := endpointsToAddrPorts(existing.Network.GetEndpoints()); len(endpoints) > 0 {
|
||||
cc.state.Network.Endpoints = endpoints
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if !cc.state.PublicIP.IsValid() && existing.PublicIp != nil {
|
||||
if ip, _ := existing.PublicIp.ToAddr(); ip.IsValid() {
|
||||
cc.state.PublicIP = ip
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
if err = cc.state.Save(); err != nil {
|
||||
return fmt.Errorf("save backfilled machine state: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// syncDockerContainers watches local Docker containers and syncs them to the cluster store.
|
||||
// TODO: move this to the Docker controller.
|
||||
func (cc *clusterController) syncDockerContainers(ctx context.Context) error {
|
||||
|
||||
@@ -195,89 +195,6 @@ func (c *Cluster) network(ctx context.Context) (netip.Prefix, error) {
|
||||
return prefix, nil
|
||||
}
|
||||
|
||||
// UpdateMachine updates machine configuration in the cluster.
|
||||
func (c *Cluster) UpdateMachine(ctx context.Context, req *pb.UpdateMachineRequest) (*pb.UpdateMachineResponse, error) {
|
||||
if err := c.checkReady(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.MachineId == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "machine_id not set")
|
||||
}
|
||||
|
||||
// Get the current machine info
|
||||
currentMachine, err := c.store.GetMachine(ctx, req.MachineId)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrMachineNotFound) {
|
||||
return nil, status.Errorf(codes.NotFound, "machine not found: %s", req.MachineId)
|
||||
}
|
||||
return nil, status.Errorf(codes.Internal, "failed to get machine: %v", err)
|
||||
}
|
||||
|
||||
// Create a copy of the current machine for updating
|
||||
updatedMachine := &pb.MachineInfo{
|
||||
Id: currentMachine.Id,
|
||||
Name: currentMachine.Name,
|
||||
Network: currentMachine.Network,
|
||||
PublicIp: currentMachine.PublicIp,
|
||||
}
|
||||
|
||||
// Apply updates from the request
|
||||
if req.Name != nil {
|
||||
// Check for empty name
|
||||
if *req.Name == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "machine name cannot be empty")
|
||||
}
|
||||
// Check for duplicate names (excluding the current machine)
|
||||
if *req.Name != currentMachine.Name {
|
||||
machines, err := c.store.ListMachines(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "list machines: %v", err)
|
||||
}
|
||||
for _, m := range machines {
|
||||
if m.Id != req.MachineId && m.Name == *req.Name {
|
||||
return nil, status.Errorf(codes.AlreadyExists, "machine with name %q already exists", *req.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
updatedMachine.Name = *req.Name
|
||||
}
|
||||
if req.PublicIp != nil {
|
||||
// Check if this is an empty IP (used to signal removal)
|
||||
if len(req.PublicIp.Ip) == 0 {
|
||||
// User wants to remove public IP
|
||||
updatedMachine.PublicIp = nil
|
||||
} else {
|
||||
// Validate and set the new IP
|
||||
ip, err := req.PublicIp.ToAddr()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid public IP: %v", err)
|
||||
}
|
||||
if !ip.IsValid() {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid public IP")
|
||||
}
|
||||
updatedMachine.PublicIp = req.PublicIp
|
||||
}
|
||||
}
|
||||
if len(req.Endpoints) > 0 {
|
||||
updatedMachine.Network.Endpoints = req.Endpoints
|
||||
}
|
||||
|
||||
// Update the machine in the store
|
||||
if err = c.store.UpdateMachine(ctx, updatedMachine); err != nil {
|
||||
if errors.Is(err, store.ErrMachineNotFound) {
|
||||
return nil, status.Errorf(codes.NotFound, "machine not found: %s", req.MachineId)
|
||||
}
|
||||
return nil, status.Errorf(codes.Internal, "update machine: %v", err)
|
||||
}
|
||||
|
||||
slog.Info("Machine configuration updated in the cluster.",
|
||||
"id", updatedMachine.Id, "name", updatedMachine.Name)
|
||||
|
||||
resp := &pb.UpdateMachineResponse{Machine: updatedMachine}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ListMachines lists all machines in the cluster including their membership states.
|
||||
func (c *Cluster) ListMachines(ctx context.Context, _ *emptypb.Empty) (*pb.ListMachinesResponse, error) {
|
||||
if err := c.checkReady(); err != nil {
|
||||
|
||||
+140
-18
@@ -516,7 +516,7 @@ func (m *Machine) Run(ctx context.Context) error {
|
||||
|
||||
m.mu.Lock()
|
||||
m.clusterCtrl, err = newClusterController(
|
||||
m.state,
|
||||
m,
|
||||
m.store,
|
||||
proxyServer,
|
||||
m.config.CorrosionService,
|
||||
@@ -838,7 +838,8 @@ func (m *Machine) InitCluster(ctx context.Context, req *pb.InitClusterRequest) (
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
// Update the machine state with the new cluster configuration.
|
||||
// Update the machine state with the new cluster configuration. The machine owns its MachineInfo,
|
||||
// so persist the data locally as the source of truth.
|
||||
m.state.ID = addResp.Machine.Id
|
||||
m.state.Name = addResp.Machine.Name
|
||||
m.state.Network = &network.Config{
|
||||
@@ -848,6 +849,10 @@ func (m *Machine) InitCluster(ctx context.Context, req *pb.InitClusterRequest) (
|
||||
MTU: wgMTU,
|
||||
PrivateKey: m.state.Network.PrivateKey,
|
||||
PublicKey: m.state.Network.PublicKey,
|
||||
Endpoints: endpointsToAddrPorts(addResp.Machine.Network.Endpoints),
|
||||
}
|
||||
if addResp.Machine.PublicIp != nil {
|
||||
m.state.PublicIP, _ = addResp.Machine.PublicIp.ToAddr()
|
||||
}
|
||||
if err = m.state.Save(); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "save machine state: %v", err)
|
||||
@@ -889,6 +894,14 @@ func (m *Machine) JoinCluster(_ context.Context, req *pb.JoinClusterRequest) (*e
|
||||
// Update the machine state with the provided cluster configuration.
|
||||
subnet, _ := req.Machine.Network.Subnet.ToPrefix()
|
||||
manageIP, _ := req.Machine.Network.ManagementIp.ToAddr()
|
||||
var publicIP netip.Addr
|
||||
if req.Machine.PublicIp != nil {
|
||||
var err error
|
||||
publicIP, err = req.Machine.PublicIp.ToAddr()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "invalid public IP: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the WireGuard listen port from the request, falling back to the default.
|
||||
wgPort := int(req.WireguardPort)
|
||||
@@ -901,6 +914,8 @@ func (m *Machine) JoinCluster(_ context.Context, req *pb.JoinClusterRequest) (*e
|
||||
wgMTU = network.DetectMTU()
|
||||
}
|
||||
|
||||
// Update the machine state with the new cluster configuration. The machine owns its MachineInfo,
|
||||
// so persist the data locally as the source of truth.
|
||||
m.state.ID = req.Machine.Id
|
||||
m.state.Name = req.Machine.Name
|
||||
m.state.Network = &network.Config{
|
||||
@@ -910,7 +925,9 @@ func (m *Machine) JoinCluster(_ context.Context, req *pb.JoinClusterRequest) (*e
|
||||
MTU: wgMTU,
|
||||
PrivateKey: m.state.Network.PrivateKey,
|
||||
PublicKey: m.state.Network.PublicKey,
|
||||
Endpoints: endpointsToAddrPorts(req.Machine.Network.Endpoints),
|
||||
}
|
||||
m.state.PublicIP = publicIP
|
||||
m.state.MinStoreVersion = req.MinStoreVersion
|
||||
|
||||
// Build a peers config from other cluster machines.
|
||||
@@ -955,6 +972,22 @@ func (m *Machine) JoinCluster(_ context.Context, req *pb.JoinClusterRequest) (*e
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
// endpointsToAddrPorts converts pb.IPPort endpoints to netip.AddrPort, skipping any that fail to parse.
|
||||
func endpointsToAddrPorts(endpoints []*pb.IPPort) []netip.AddrPort {
|
||||
if len(endpoints) == 0 {
|
||||
return nil
|
||||
}
|
||||
addrPorts := make([]netip.AddrPort, 0, len(endpoints))
|
||||
for _, ep := range endpoints {
|
||||
ap, err := ep.ToAddrPort()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
addrPorts = append(addrPorts, ap)
|
||||
}
|
||||
return addrPorts
|
||||
}
|
||||
|
||||
// Token returns the local machine's token that can be used for adding the machine to a cluster.
|
||||
func (m *Machine) Token(_ context.Context, _ *emptypb.Empty) (*pb.TokenResponse, error) {
|
||||
if len(m.state.Network.PublicKey) == 0 {
|
||||
@@ -984,22 +1017,41 @@ func (m *Machine) Token(_ context.Context, _ *emptypb.Empty) (*pb.TokenResponse,
|
||||
return &pb.TokenResponse{Token: tokenStr}, nil
|
||||
}
|
||||
|
||||
// Deprecated: use InspectMachine instead.
|
||||
func (m *Machine) Inspect(_ context.Context, _ *emptypb.Empty) (*pb.MachineInfo, error) {
|
||||
return &pb.MachineInfo{
|
||||
// Info returns the machine configuration and runtime details.
|
||||
func (m *Machine) Info() *pb.MachineInfo {
|
||||
m.state.mu.RLock()
|
||||
defer m.state.mu.RUnlock()
|
||||
|
||||
hostname, _ := os.Hostname()
|
||||
|
||||
endpoints := make([]*pb.IPPort, len(m.state.Network.Endpoints))
|
||||
for i, ep := range m.state.Network.Endpoints {
|
||||
endpoints[i] = pb.NewIPPort(ep)
|
||||
}
|
||||
|
||||
info := &pb.MachineInfo{
|
||||
Id: m.state.ID,
|
||||
Name: m.state.Name,
|
||||
Hostname: hostname,
|
||||
Network: &pb.NetworkConfig{
|
||||
Subnet: pb.NewIPPrefix(m.state.Network.Subnet),
|
||||
ManagementIp: pb.NewIP(m.state.Network.ManagementIP),
|
||||
Endpoints: endpoints,
|
||||
PublicKey: m.state.Network.PublicKey,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
if m.state.PublicIP.IsValid() {
|
||||
info.PublicIp = pb.NewIP(m.state.PublicIP)
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// Deprecated: use InspectMachine instead.
|
||||
func (m *Machine) Inspect(_ context.Context, _ *emptypb.Empty) (*pb.MachineInfo, error) {
|
||||
return m.Info(), nil
|
||||
}
|
||||
|
||||
func (m *Machine) InspectMachine(ctx context.Context, _ *emptypb.Empty) (*pb.InspectMachineResponse, error) {
|
||||
hostname, _ := os.Hostname()
|
||||
|
||||
storeVersion, err := m.store.Version(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "get cluster store version: %v", err)
|
||||
@@ -1017,16 +1069,7 @@ func (m *Machine) InspectMachine(ctx context.Context, _ *emptypb.Empty) (*pb.Ins
|
||||
Machines: []*pb.MachineDetails{
|
||||
{
|
||||
// Metadata is injected by the gRPC proxy.
|
||||
Machine: &pb.MachineInfo{
|
||||
Id: m.state.ID,
|
||||
Name: m.state.Name,
|
||||
Hostname: hostname,
|
||||
Network: &pb.NetworkConfig{
|
||||
Subnet: pb.NewIPPrefix(m.state.Network.Subnet),
|
||||
ManagementIp: pb.NewIP(m.state.Network.ManagementIP),
|
||||
PublicKey: m.state.Network.PublicKey,
|
||||
},
|
||||
},
|
||||
Machine: m.Info(),
|
||||
StoreVersion: storeVersion,
|
||||
Rtts: rtts,
|
||||
},
|
||||
@@ -1034,6 +1077,85 @@ func (m *Machine) InspectMachine(ctx context.Context, _ *emptypb.Empty) (*pb.Ins
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateMachine updates the configuration of this machine in its local state (the source of truth) and syncs
|
||||
// the result to the cluster store.
|
||||
func (m *Machine) UpdateMachine(ctx context.Context, req *pb.UpdateMachineRequest) (*pb.UpdateMachineResponse, error) {
|
||||
if !m.Initialised() {
|
||||
return nil, status.Error(codes.FailedPrecondition, "machine is not configured as a cluster member")
|
||||
}
|
||||
|
||||
if err := m.applyMachineUpdate(ctx, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
info := m.Info()
|
||||
if err := m.store.UpdateMachine(ctx, info); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "sync machine to cluster store: %v", err)
|
||||
}
|
||||
|
||||
slog.Info("Machine configuration updated.", "id", info.Id, "name", info.Name)
|
||||
return &pb.UpdateMachineResponse{Machine: info}, nil
|
||||
}
|
||||
|
||||
// applyMachineUpdate validates the request and applies it to the local machine state under the write lock,
|
||||
// then persists the state to disk.
|
||||
func (m *Machine) applyMachineUpdate(ctx context.Context, req *pb.UpdateMachineRequest) error {
|
||||
m.state.mu.Lock()
|
||||
defer m.state.mu.Unlock()
|
||||
|
||||
if req.Name != nil {
|
||||
if *req.Name == "" {
|
||||
return status.Error(codes.InvalidArgument, "machine name cannot be empty")
|
||||
}
|
||||
// Check for duplicate names across the cluster, excluding this machine.
|
||||
if *req.Name != m.state.Name {
|
||||
machines, err := m.store.ListMachines(ctx)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Internal, "list machines: %v", err)
|
||||
}
|
||||
for _, other := range machines {
|
||||
if other.Id != m.state.ID && other.Name == *req.Name {
|
||||
return status.Errorf(codes.AlreadyExists, "machine with name '%s' already exists", *req.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
m.state.Name = *req.Name
|
||||
}
|
||||
|
||||
if req.PublicIp != nil {
|
||||
// An empty IP signals removal of the public IP.
|
||||
if len(req.PublicIp.Ip) == 0 {
|
||||
m.state.PublicIP = netip.Addr{}
|
||||
} else {
|
||||
ip, err := req.PublicIp.ToAddr()
|
||||
if err != nil {
|
||||
return status.Errorf(codes.InvalidArgument, "invalid public IP: %v", err)
|
||||
}
|
||||
m.state.PublicIP = ip
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.Endpoints) > 0 {
|
||||
endpoints := make([]netip.AddrPort, len(req.Endpoints))
|
||||
for i, ep := range req.Endpoints {
|
||||
ap, err := ep.ToAddrPort()
|
||||
if err != nil {
|
||||
return status.Errorf(codes.InvalidArgument, "invalid endpoint: %v", err)
|
||||
}
|
||||
endpoints[i] = ap
|
||||
}
|
||||
m.state.Network.Endpoints = endpoints
|
||||
}
|
||||
|
||||
if err := m.state.Save(); err != nil {
|
||||
return status.Errorf(codes.Internal, "save machine state: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getMachineRTTs retrieves round-trip times to other machines in the cluster.
|
||||
func (m *Machine) getMachineRTTs(ctx context.Context) (map[string]*pb.RTTStats, error) {
|
||||
rtts, err := m.cluster.MemberRTTs()
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package machine
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||
"github.com/psviderski/uncloud/internal/machine/network"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMachineInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
subnet := netip.MustParsePrefix("10.210.1.0/24")
|
||||
manageIP := netip.MustParseAddr("fdcc:1::1")
|
||||
publicKey := []byte("public-key")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
state *State
|
||||
wantPublicIP bool
|
||||
wantEndpoints int
|
||||
}{
|
||||
{
|
||||
name: "with endpoints and public IP",
|
||||
state: &State{
|
||||
ID: "machine-id",
|
||||
Name: "machine-1",
|
||||
Network: &network.Config{
|
||||
Subnet: subnet,
|
||||
ManagementIP: manageIP,
|
||||
PublicKey: publicKey,
|
||||
Endpoints: []netip.AddrPort{
|
||||
netip.MustParseAddrPort("203.0.113.5:51820"),
|
||||
netip.MustParseAddrPort("10.0.0.2:51820"),
|
||||
},
|
||||
},
|
||||
PublicIP: netip.MustParseAddr("203.0.113.5"),
|
||||
},
|
||||
wantPublicIP: true,
|
||||
wantEndpoints: 2,
|
||||
},
|
||||
{
|
||||
name: "without endpoints or public IP",
|
||||
state: &State{
|
||||
ID: "machine-id",
|
||||
Name: "machine-1",
|
||||
Network: &network.Config{
|
||||
Subnet: subnet,
|
||||
ManagementIP: manageIP,
|
||||
PublicKey: publicKey,
|
||||
},
|
||||
},
|
||||
wantPublicIP: false,
|
||||
wantEndpoints: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
m := &Machine{state: tt.state}
|
||||
info := m.Info()
|
||||
|
||||
assert.Equal(t, tt.state.ID, info.Id)
|
||||
assert.Equal(t, tt.state.Name, info.Name)
|
||||
assert.Equal(t, publicKey, info.Network.PublicKey)
|
||||
|
||||
gotSubnet, err := info.Network.Subnet.ToPrefix()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, subnet, gotSubnet)
|
||||
|
||||
gotManageIP, err := info.Network.ManagementIp.ToAddr()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, manageIP, gotManageIP)
|
||||
|
||||
assert.Len(t, info.Network.Endpoints, tt.wantEndpoints)
|
||||
// Endpoints must round-trip back to the original AddrPorts.
|
||||
for i, ep := range info.Network.Endpoints {
|
||||
ap, err := ep.ToAddrPort()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.state.Network.Endpoints[i], ap)
|
||||
}
|
||||
|
||||
if tt.wantPublicIP {
|
||||
require.NotNil(t, info.PublicIp)
|
||||
gotIP, err := info.PublicIp.ToAddr()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.state.PublicIP, gotIP)
|
||||
} else {
|
||||
assert.Nil(t, info.PublicIp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEndpointsToAddrPorts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ap1 := netip.MustParseAddrPort("203.0.113.5:51820")
|
||||
ap2 := netip.MustParseAddrPort("10.0.0.2:51820")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
endpoints []*pb.IPPort
|
||||
want []netip.AddrPort
|
||||
}{
|
||||
{"nil", nil, nil},
|
||||
{"empty", []*pb.IPPort{}, nil},
|
||||
{
|
||||
name: "valid",
|
||||
endpoints: []*pb.IPPort{pb.NewIPPort(ap1), pb.NewIPPort(ap2)},
|
||||
want: []netip.AddrPort{ap1, ap2},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, tt.want, endpointsToAddrPorts(tt.endpoints))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ type Config struct {
|
||||
MTU int `json:",omitempty"`
|
||||
PrivateKey secret.Secret
|
||||
PublicKey secret.Secret
|
||||
// Endpoints are this machine's own WireGuard endpoints advertised to other machines.
|
||||
Endpoints []netip.AddrPort `json:",omitempty"`
|
||||
Peers []PeerConfig `json:",omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package machine
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
@@ -25,6 +26,8 @@ type State struct {
|
||||
Name string
|
||||
// Network specifies the network configuration for this machine.
|
||||
Network *network.Config
|
||||
// PublicIP is this machine's advertised public IP for ingress. Zero value if unset.
|
||||
PublicIP netip.Addr `json:",omitempty"`
|
||||
// MinStoreVersion is the cluster store version this machine must reach before participating.
|
||||
// Per-actor vector (Corrosion actor UUID → max applied db_version) captured from an existing
|
||||
// member at join time. Cleared once reached.
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ type LogsClient interface {
|
||||
type MachineClient interface {
|
||||
InspectMachine(ctx context.Context, id string) (*pb.MachineMember, error)
|
||||
ListMachines(ctx context.Context, filter *MachineFilter) (MachineMembersList, error)
|
||||
UpdateMachine(ctx context.Context, req *pb.UpdateMachineRequest) (*pb.MachineInfo, error)
|
||||
UpdateMachine(ctx context.Context, nameOrID string, req *pb.UpdateMachineRequest) (*pb.MachineInfo, error)
|
||||
RenameMachine(ctx context.Context, nameOrID, newName string) (*pb.MachineInfo, error)
|
||||
}
|
||||
|
||||
|
||||
+7
-13
@@ -74,9 +74,12 @@ func (cli *Client) ListMachines(ctx context.Context, filter *api.MachineFilter)
|
||||
return machines, nil
|
||||
}
|
||||
|
||||
// UpdateMachine updates machine configuration in the cluster.
|
||||
func (cli *Client) UpdateMachine(ctx context.Context, req *pb.UpdateMachineRequest) (*pb.MachineInfo, error) {
|
||||
resp, err := cli.ClusterClient.UpdateMachine(ctx, req)
|
||||
// UpdateMachine updates the configuration of the machine identified by nameOrID.
|
||||
func (cli *Client) UpdateMachine(
|
||||
ctx context.Context, nameOrID string, req *pb.UpdateMachineRequest,
|
||||
) (*pb.MachineInfo, error) {
|
||||
ctx = cli.ProxySingleMachineContext(ctx, nameOrID)
|
||||
resp, err := cli.MachineClient.UpdateMachine(ctx, req)
|
||||
if err != nil {
|
||||
if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound {
|
||||
return nil, api.ErrNotFound
|
||||
@@ -88,19 +91,10 @@ func (cli *Client) UpdateMachine(ctx context.Context, req *pb.UpdateMachineReque
|
||||
|
||||
// RenameMachine renames an existing machine in the cluster.
|
||||
func (cli *Client) RenameMachine(ctx context.Context, nameOrID, newName string) (*pb.MachineInfo, error) {
|
||||
// First, resolve the machine to get its ID
|
||||
machine, err := cli.InspectMachine(ctx, nameOrID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Update the machine with the new name
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: machine.Machine.Id,
|
||||
Name: &newName,
|
||||
}
|
||||
|
||||
return cli.UpdateMachine(ctx, req)
|
||||
return cli.UpdateMachine(ctx, nameOrID, req)
|
||||
}
|
||||
|
||||
// WaitMachineReady waits for the machine API on the connected machine to respond.
|
||||
|
||||
+79
-61
@@ -25,6 +25,17 @@ func TestMachineOperations(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer cli.Close()
|
||||
|
||||
// waitMachineName waits until the connected machine's store view reports the given name for the machine.
|
||||
// Updates are applied on the target machine and replicated through the cluster store, so they are not
|
||||
// immediately visible when read back from the connected machine.
|
||||
waitMachineName := func(t *testing.T, id, name string) {
|
||||
t.Helper()
|
||||
require.Eventually(t, func() bool {
|
||||
m, err := cli.InspectMachine(ctx, id)
|
||||
return err == nil && m.Machine.Name == name
|
||||
}, 15*time.Second, 100*time.Millisecond, "machine %s should be visible as %q", id, name)
|
||||
}
|
||||
|
||||
// RenameMachine subtests.
|
||||
|
||||
t.Run("rename machine by name", func(t *testing.T) {
|
||||
@@ -44,23 +55,18 @@ func TestMachineOperations(t *testing.T) {
|
||||
assert.Equal(t, newName, updatedMachine.Name)
|
||||
assert.Equal(t, originalMachine.Machine.Id, updatedMachine.Id)
|
||||
|
||||
// Verify the machine list reflects the change.
|
||||
// Wait for the rename to propagate to the connected machine's store view.
|
||||
waitMachineName(t, originalMachine.Machine.Id, newName)
|
||||
|
||||
// Ensure other machines are unaffected.
|
||||
machines, err = cli.ListMachines(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, machines, 3)
|
||||
|
||||
// Find the renamed machine.
|
||||
var found bool
|
||||
for _, m := range machines {
|
||||
if m.Machine.Id == originalMachine.Machine.Id {
|
||||
assert.Equal(t, newName, m.Machine.Name)
|
||||
found = true
|
||||
} else {
|
||||
// Ensure other machines are unaffected.
|
||||
if m.Machine.Id != originalMachine.Machine.Id {
|
||||
assert.NotEqual(t, newName, m.Machine.Name)
|
||||
}
|
||||
}
|
||||
assert.True(t, found, "Renamed machine should be in the list")
|
||||
|
||||
// Verify we can inspect the machine by its new name.
|
||||
inspectedMachine, err := cli.InspectMachine(ctx, newName)
|
||||
@@ -99,6 +105,9 @@ func TestMachineOperations(t *testing.T) {
|
||||
assert.Equal(t, newName, updatedMachine.Name)
|
||||
assert.Equal(t, machineID, updatedMachine.Id)
|
||||
|
||||
// Wait for the rename to propagate to the connected machine's store view.
|
||||
waitMachineName(t, machineID, newName)
|
||||
|
||||
// Verify the rename was successful.
|
||||
inspectedMachine, err := cli.InspectMachine(ctx, newName)
|
||||
require.NoError(t, err)
|
||||
@@ -113,11 +122,7 @@ func TestMachineOperations(t *testing.T) {
|
||||
t.Run("rename non-existent machine", func(t *testing.T) {
|
||||
// Try to rename a machine that doesn't exist.
|
||||
_, err := cli.RenameMachine(ctx, "non-existent-machine", "new-name")
|
||||
assert.ErrorIs(t, err, api.ErrNotFound)
|
||||
|
||||
// Try with a non-existent ID.
|
||||
_, err = cli.RenameMachine(ctx, "non-existent-id-12345", "new-name")
|
||||
assert.ErrorIs(t, err, api.ErrNotFound)
|
||||
assert.ErrorContains(t, err, "machine not found")
|
||||
})
|
||||
|
||||
t.Run("rename to existing name", func(t *testing.T) {
|
||||
@@ -126,12 +131,21 @@ func TestMachineOperations(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Len(t, machines, 3)
|
||||
|
||||
// Try to rename machine 0 to the name of machine 1.
|
||||
machine0Name := machines[0].Machine.Name
|
||||
machine1Name := machines[1].Machine.Name
|
||||
// Rename the connected machine to another machine's name. The uniqueness check runs on the connected
|
||||
// machine, which already sees the other machine's name, so the collision is detected deterministically
|
||||
// (a remote target's store view may lag behind the connected machine's).
|
||||
connectedID := c.Machines[0].ID
|
||||
var otherName string
|
||||
for _, m := range machines {
|
||||
if m.Machine.Id != connectedID {
|
||||
otherName = m.Machine.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
require.NotEmpty(t, otherName)
|
||||
|
||||
// This should fail because the name is already taken.
|
||||
_, err = cli.RenameMachine(ctx, machine0Name, machine1Name)
|
||||
_, err = cli.RenameMachine(ctx, connectedID, otherName)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
@@ -198,6 +212,7 @@ func TestMachineOperations(t *testing.T) {
|
||||
newMachineName := "renamed-for-service-test"
|
||||
_, err = cli.RenameMachine(ctx, originalMachineName, newMachineName)
|
||||
require.NoError(t, err)
|
||||
waitMachineName(t, targetMachine.Machine.Id, newMachineName)
|
||||
|
||||
// Verify service is still running on the renamed machine.
|
||||
svc, err = cli.InspectService(ctx, serviceName)
|
||||
@@ -224,18 +239,15 @@ func TestMachineOperations(t *testing.T) {
|
||||
|
||||
// Update the machine name using UpdateMachine directly.
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: targetMachine.Machine.Id,
|
||||
Name: &newName,
|
||||
}
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, req)
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, targetMachine.Machine.Id, req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newName, updatedMachine.Name)
|
||||
assert.Equal(t, targetMachine.Machine.Id, updatedMachine.Id)
|
||||
|
||||
// Verify the change persisted.
|
||||
inspected, err := cli.InspectMachine(ctx, updatedMachine.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newName, inspected.Machine.Name)
|
||||
// Wait for the change to propagate to the connected machine's store view.
|
||||
waitMachineName(t, targetMachine.Machine.Id, newName)
|
||||
|
||||
// Verify old name no longer works.
|
||||
_, err = cli.InspectMachine(ctx, originalName)
|
||||
@@ -264,17 +276,18 @@ func TestMachineOperations(t *testing.T) {
|
||||
|
||||
// Update the public IP.
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: targetMachine.Machine.Id,
|
||||
PublicIp: newPublicIP,
|
||||
}
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, req)
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, targetMachine.Machine.Id, req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newPublicIP.Ip, updatedMachine.PublicIp.Ip)
|
||||
|
||||
// Verify the change persisted.
|
||||
// Verify the change propagated to the connected machine's store view.
|
||||
require.Eventually(t, func() bool {
|
||||
inspected, err := cli.InspectMachine(ctx, targetMachine.Machine.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newPublicIP.Ip, inspected.Machine.PublicIp.Ip)
|
||||
return err == nil && inspected.Machine.PublicIp != nil &&
|
||||
string(inspected.Machine.PublicIp.Ip) == string(newPublicIP.Ip)
|
||||
}, 15*time.Second, 100*time.Millisecond, "public IP should be updated")
|
||||
})
|
||||
|
||||
t.Run("remove machine public IP", func(t *testing.T) {
|
||||
@@ -286,10 +299,9 @@ func TestMachineOperations(t *testing.T) {
|
||||
// First, set a public IP on a machine.
|
||||
targetMachine := machines[0]
|
||||
setIPReq := &pb.UpdateMachineRequest{
|
||||
MachineId: targetMachine.Machine.Id,
|
||||
PublicIp: &pb.IP{Ip: []byte{192, 0, 2, 1}}, // TEST-NET-1 address.
|
||||
}
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, setIPReq)
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, targetMachine.Machine.Id, setIPReq)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, updatedMachine.PublicIp)
|
||||
|
||||
@@ -298,17 +310,17 @@ func TestMachineOperations(t *testing.T) {
|
||||
// Remove the public IP by setting it to empty.
|
||||
emptyIP := &pb.IP{}
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: updatedMachine.Id,
|
||||
PublicIp: emptyIP,
|
||||
}
|
||||
removedIPMachine, err := cli.UpdateMachine(ctx, req)
|
||||
removedIPMachine, err := cli.UpdateMachine(ctx, updatedMachine.Id, req)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, removedIPMachine.PublicIp)
|
||||
|
||||
// Verify the change persisted.
|
||||
// Verify the removal propagated to the connected machine's store view.
|
||||
require.Eventually(t, func() bool {
|
||||
inspected, err := cli.InspectMachine(ctx, updatedMachine.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, inspected.Machine.PublicIp)
|
||||
return err == nil && inspected.Machine.PublicIp == nil
|
||||
}, 15*time.Second, 100*time.Millisecond, "public IP should be removed")
|
||||
})
|
||||
|
||||
t.Run("update machine endpoints", func(t *testing.T) {
|
||||
@@ -329,10 +341,9 @@ func TestMachineOperations(t *testing.T) {
|
||||
}
|
||||
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: targetMachine.Machine.Id,
|
||||
Endpoints: newEndpoints,
|
||||
}
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, req)
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, targetMachine.Machine.Id, req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(newEndpoints), len(updatedMachine.Network.Endpoints))
|
||||
|
||||
@@ -370,48 +381,57 @@ func TestMachineOperations(t *testing.T) {
|
||||
}
|
||||
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: targetMachine.Machine.Id,
|
||||
Name: &newName,
|
||||
PublicIp: newPublicIP,
|
||||
}
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, req)
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, targetMachine.Machine.Id, req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newName, updatedMachine.Name)
|
||||
assert.Equal(t, newPublicIP.Ip, updatedMachine.PublicIp.Ip)
|
||||
|
||||
// Verify both changes persisted.
|
||||
// Verify both changes propagated to the connected machine's store view.
|
||||
require.Eventually(t, func() bool {
|
||||
inspected, err := cli.InspectMachine(ctx, updatedMachine.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newName, inspected.Machine.Name)
|
||||
assert.Equal(t, newPublicIP.Ip, inspected.Machine.PublicIp.Ip)
|
||||
if err != nil || inspected.Machine.PublicIp == nil {
|
||||
return false
|
||||
}
|
||||
return inspected.Machine.Name == newName &&
|
||||
string(inspected.Machine.PublicIp.Ip) == string(newPublicIP.Ip)
|
||||
}, 15*time.Second, 100*time.Millisecond, "name and public IP should be updated")
|
||||
})
|
||||
|
||||
t.Run("update non-existent machine", func(t *testing.T) {
|
||||
// Try to update properties on a machine that doesn't exist.
|
||||
nonExistentName := "should-be-updated"
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: "non-existent-machine-id",
|
||||
Name: &nonExistentName,
|
||||
}
|
||||
_, err := cli.UpdateMachine(ctx, req)
|
||||
assert.Error(t, err)
|
||||
_, err := cli.UpdateMachine(ctx, "non-existent-machine-id", req)
|
||||
assert.ErrorContains(t, err, "machine not found")
|
||||
})
|
||||
|
||||
t.Run("update to duplicate name", func(t *testing.T) {
|
||||
// Get two machines.
|
||||
machines, err := cli.ListMachines(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, machines, 3)
|
||||
|
||||
machine1 := machines[0]
|
||||
machine2 := machines[1]
|
||||
|
||||
// Try to update machine2 with machine1's name.
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: machine2.Machine.Id,
|
||||
Name: &machine1.Machine.Name,
|
||||
// Update the connected machine with another machine's name. The uniqueness check runs on the connected
|
||||
// machine, which already sees the other machine's name, so the collision is detected deterministically
|
||||
// (a remote target's store view may lag behind the connected machine's).
|
||||
connectedID := c.Machines[0].ID
|
||||
var otherName string
|
||||
for _, m := range machines {
|
||||
if m.Machine.Id != connectedID {
|
||||
otherName = m.Machine.Name
|
||||
break
|
||||
}
|
||||
_, err = cli.UpdateMachine(ctx, req)
|
||||
}
|
||||
require.NotEmpty(t, otherName)
|
||||
|
||||
req := &pb.UpdateMachineRequest{
|
||||
Name: &otherName,
|
||||
}
|
||||
_, err = cli.UpdateMachine(ctx, connectedID, req)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
@@ -423,10 +443,8 @@ func TestMachineOperations(t *testing.T) {
|
||||
targetMachine := machines[0]
|
||||
|
||||
// Update with no fields set (should be a no-op).
|
||||
req := &pb.UpdateMachineRequest{
|
||||
MachineId: targetMachine.Machine.Id,
|
||||
}
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, req)
|
||||
req := &pb.UpdateMachineRequest{}
|
||||
updatedMachine, err := cli.UpdateMachine(ctx, targetMachine.Machine.Id, req)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Machine should remain unchanged.
|
||||
|
||||
Reference in New Issue
Block a user