diff --git a/client/api/omni/specs/omni.pb.go b/client/api/omni/specs/omni.pb.go index be0e8ee6..7d6a1b6b 100644 --- a/client/api/omni/specs/omni.pb.go +++ b/client/api/omni/specs/omni.pb.go @@ -4669,8 +4669,6 @@ type SchematicSpec struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - - Extensions []string `protobuf:"bytes,1,rep,name=extensions,proto3" json:"extensions,omitempty"` } func (x *SchematicSpec) Reset() { @@ -4705,13 +4703,6 @@ func (*SchematicSpec) Descriptor() ([]byte, []int) { return file_omni_specs_omni_proto_rawDescGZIP(), []int{59} } -func (x *SchematicSpec) GetExtensions() []string { - if x != nil { - return x.Extensions - } - return nil -} - // TalosExtensionsSpec represents all available extensions for a particular Talos version. type TalosExtensionsSpec struct { state protoimpl.MessageState @@ -5095,11 +5086,15 @@ type MachineStatusSpec_Schematic struct { unknownFields protoimpl.UnknownFields // Id is the image factory schematic id used for the image generation. + // + // This must be be plain id computed solely from the system extensions, not including the kernel command line arguments, META content etc. Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // Invalid marks the machine as having extensions installed bypassing image factory. // Which makes it impossible to detect schematic id and manage the image generation // using image factory. Invalid bool `protobuf:"varint,2,opt,name=invalid,proto3" json:"invalid,omitempty"` + // Extensions is the list of extensions installed on the machine. + Extensions []string `protobuf:"bytes,3,rep,name=extensions,proto3" json:"extensions,omitempty"` } func (x *MachineStatusSpec_Schematic) Reset() { @@ -5148,6 +5143,13 @@ func (x *MachineStatusSpec_Schematic) GetInvalid() bool { return false } +func (x *MachineStatusSpec_Schematic) GetExtensions() []string { + if x != nil { + return x.Extensions + } + return nil +} + type MachineStatusSpec_MaintenanceConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -6367,7 +6369,7 @@ var file_omni_specs_omni_proto_rawDesc = []byte{ 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, - 0x08, 0x04, 0x10, 0x05, 0x22, 0x8e, 0x13, 0x0a, 0x11, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, + 0x08, 0x04, 0x10, 0x05, 0x22, 0xae, 0x13, 0x0a, 0x11, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, @@ -6506,10 +6508,12 @@ var file_omni_specs_omni_proto_rawDesc = []byte{ 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x70, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, - 0x73, 0x70, 0x6f, 0x74, 0x1a, 0x35, 0x0a, 0x09, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, + 0x73, 0x70, 0x6f, 0x74, 0x1a, 0x55, 0x0a, 0x09, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x1a, 0x2b, 0x0a, 0x11, 0x4d, + 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x2b, 0x0a, 0x11, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x3e, 0x0a, 0x10, 0x49, 0x6d, 0x61, 0x67, @@ -7164,58 +7168,56 @@ var file_omni_specs_omni_proto_rawDesc = []byte{ 0x0d, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x2f, 0x0a, 0x0d, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x74, 0x69, 0x63, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, - 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe7, 0x01, 0x0a, 0x13, 0x54, 0x61, 0x6c, 0x6f, - 0x73, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, - 0x35, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, - 0x2e, 0x73, 0x70, 0x65, 0x63, 0x73, 0x2e, 0x54, 0x61, 0x6c, 0x6f, 0x73, 0x45, 0x78, 0x74, 0x65, - 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x98, 0x01, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, - 0x74, 0x22, 0xc9, 0x01, 0x0a, 0x1a, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, - 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, - 0x63, 0x49, 0x64, 0x12, 0x40, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x73, 0x70, 0x65, 0x63, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x15, 0x0a, 0x0d, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x74, 0x69, 0x63, 0x53, 0x70, 0x65, 0x63, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xe7, 0x01, + 0x0a, 0x13, 0x54, 0x61, 0x6c, 0x6f, 0x73, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x35, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x70, 0x65, 0x63, 0x73, 0x2e, 0x54, 0x61, 0x6c, + 0x6f, 0x73, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x70, 0x65, 0x63, + 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x98, 0x01, 0x0a, + 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, + 0x03, 0x72, 0x65, 0x66, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, + 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0xc9, 0x01, 0x0a, 0x1a, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, - 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x10, 0x01, - 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x65, 0x74, 0x10, 0x02, - 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x10, 0x03, 0x2a, 0x46, 0x0a, - 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, - 0x41, 0x50, 0x50, 0x4c, 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, - 0x4c, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x7a, 0x0a, 0x0f, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, - 0x53, 0x65, 0x74, 0x50, 0x68, 0x61, 0x73, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, - 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, - 0x55, 0x70, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x44, - 0x6f, 0x77, 0x6e, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, - 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x69, 0x6e, 0x67, - 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x10, 0x05, 0x12, 0x11, - 0x0a, 0x0d, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x10, - 0x06, 0x2a, 0x48, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x43, 0x6f, 0x6e, - 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x45, 0x74, 0x63, 0x64, - 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x57, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x02, 0x42, 0x32, 0x5a, 0x30, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, - 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6f, 0x6d, 0x6e, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6f, 0x6d, 0x6e, 0x69, 0x2f, 0x73, 0x70, 0x65, 0x63, 0x73, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x74, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x49, 0x64, 0x12, 0x40, 0x0a, 0x06, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x73, 0x70, 0x65, 0x63, + 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x06, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, + 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, + 0x68, 0x69, 0x6e, 0x65, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, + 0x65, 0x53, 0x65, 0x74, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x10, 0x03, 0x2a, 0x46, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x70, 0x70, + 0x6c, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, + 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x50, 0x50, 0x4c, 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, + 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x7a, 0x0a, 0x0f, 0x4d, + 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x65, 0x74, 0x50, 0x68, 0x61, 0x73, 0x65, 0x12, 0x0b, + 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, + 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x63, + 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x44, 0x6f, 0x77, 0x6e, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x52, + 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x65, 0x73, 0x74, + 0x72, 0x6f, 0x79, 0x69, 0x6e, 0x67, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x61, 0x69, 0x6c, + 0x65, 0x64, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x69, 0x6e, 0x67, 0x10, 0x06, 0x2a, 0x48, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x6e, 0x6b, 0x6e, + 0x6f, 0x77, 0x6e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x00, 0x12, 0x08, + 0x0a, 0x04, 0x45, 0x74, 0x63, 0x64, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x57, 0x69, 0x72, 0x65, + 0x67, 0x75, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, + 0x02, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6f, 0x6d, 0x6e, 0x69, 0x2f, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6f, 0x6d, 0x6e, 0x69, 0x2f, + 0x73, 0x70, 0x65, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/client/api/omni/specs/omni.proto b/client/api/omni/specs/omni.proto index 69a1364f..5dcdadd0 100644 --- a/client/api/omni/specs/omni.proto +++ b/client/api/omni/specs/omni.proto @@ -127,12 +127,17 @@ message MachineStatusSpec { message Schematic { // Id is the image factory schematic id used for the image generation. + // + // This must be be plain id computed solely from the system extensions, not including the kernel command line arguments, META content etc. string id = 1; // Invalid marks the machine as having extensions installed bypassing image factory. // Which makes it impossible to detect schematic id and manage the image generation // using image factory. bool invalid = 2; + + // Extensions is the list of extensions installed on the machine. + repeated string extensions = 3; } message MaintenanceConfig { @@ -907,7 +912,7 @@ message ImagePullStatusSpec { // SchematicSpec keeps all schematics generated by Omni. // For each schematic it keeps information about the list of extensions. message SchematicSpec { - repeated string extensions = 1; + reserved 1; } // TalosExtensionsSpec represents all available extensions for a particular Talos version. @@ -937,4 +942,4 @@ message SchematicConfigurationSpec { string schematic_id = 1; Target target = 2; -} \ No newline at end of file +} diff --git a/client/api/omni/specs/omni_vtproto.pb.go b/client/api/omni/specs/omni_vtproto.pb.go index 2265b439..1026278c 100644 --- a/client/api/omni/specs/omni_vtproto.pb.go +++ b/client/api/omni/specs/omni_vtproto.pb.go @@ -235,6 +235,11 @@ func (m *MachineStatusSpec_Schematic) CloneVT() *MachineStatusSpec_Schematic { r := new(MachineStatusSpec_Schematic) r.Id = m.Id r.Invalid = m.Invalid + if rhs := m.Extensions; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Extensions = tmpContainer + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -1725,11 +1730,6 @@ func (m *SchematicSpec) CloneVT() *SchematicSpec { return (*SchematicSpec)(nil) } r := new(SchematicSpec) - if rhs := m.Extensions; rhs != nil { - tmpContainer := make([]string, len(rhs)) - copy(tmpContainer, rhs) - r.Extensions = tmpContainer - } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -2135,6 +2135,15 @@ func (this *MachineStatusSpec_Schematic) EqualVT(that *MachineStatusSpec_Schemat if this.Invalid != that.Invalid { return false } + if len(this.Extensions) != len(that.Extensions) { + return false + } + for i, vx := range this.Extensions { + vy := that.Extensions[i] + if vx != vy { + return false + } + } return string(this.unknownFields) == string(that.unknownFields) } @@ -4113,15 +4122,6 @@ func (this *SchematicSpec) EqualVT(that *SchematicSpec) bool { } else if this == nil || that == nil { return false } - if len(this.Extensions) != len(that.Extensions) { - return false - } - for i, vx := range this.Extensions { - vy := that.Extensions[i] - if vx != vy { - return false - } - } return string(this.unknownFields) == string(that.unknownFields) } @@ -4826,6 +4826,15 @@ func (m *MachineStatusSpec_Schematic) MarshalToSizedBufferVT(dAtA []byte) (int, i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.Extensions) > 0 { + for iNdEx := len(m.Extensions) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Extensions[iNdEx]) + copy(dAtA[i:], m.Extensions[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Extensions[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } if m.Invalid { i-- if m.Invalid { @@ -8846,15 +8855,6 @@ func (m *SchematicSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if len(m.Extensions) > 0 { - for iNdEx := len(m.Extensions) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Extensions[iNdEx]) - copy(dAtA[i:], m.Extensions[iNdEx]) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Extensions[iNdEx]))) - i-- - dAtA[i] = 0xa - } - } return len(dAtA) - i, nil } @@ -9282,6 +9282,12 @@ func (m *MachineStatusSpec_Schematic) SizeVT() (n int) { if m.Invalid { n += 2 } + if len(m.Extensions) > 0 { + for _, s := range m.Extensions { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } n += len(m.unknownFields) return n } @@ -10821,12 +10827,6 @@ func (m *SchematicSpec) SizeVT() (n int) { } var l int _ = l - if len(m.Extensions) > 0 { - for _, s := range m.Extensions { - l = len(s) - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - } n += len(m.unknownFields) return n } @@ -12581,6 +12581,38 @@ func (m *MachineStatusSpec_Schematic) UnmarshalVT(dAtA []byte) error { } } m.Invalid = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Extensions", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Extensions = append(m.Extensions, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -22313,38 +22345,6 @@ func (m *SchematicSpec) UnmarshalVT(dAtA []byte) error { return fmt.Errorf("proto: SchematicSpec: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Extensions", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Extensions = append(m.Extensions, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/client/pkg/omni/resources/omni/schematic.go b/client/pkg/omni/resources/omni/schematic.go index ba329e5f..b46e6328 100644 --- a/client/pkg/omni/resources/omni/schematic.go +++ b/client/pkg/omni/resources/omni/schematic.go @@ -28,7 +28,11 @@ const ( SchematicType = resource.Type("Schematics.omni.sidero.dev") ) -// Schematic describes previosly generated image factory schematic. +// Schematic describes an image factory schematic. +// +// This resource is used as a cache for the schematics known by Omni: +// - Schematics generated through Omni UI/APIs. +// - Schematics generated/detected from the discovered Talos machines. type Schematic = typed.Resource[SchematicSpec, SchematicExtension] // SchematicSpec wraps specs.SchematicSpec. diff --git a/cmd/integration-test/pkg/tests/talos.go b/cmd/integration-test/pkg/tests/talos.go index 93e47cf5..ea3916b0 100644 --- a/cmd/integration-test/pkg/tests/talos.go +++ b/cmd/integration-test/pkg/tests/talos.go @@ -585,6 +585,11 @@ func AssertTalosUpgradeIsCancelable(testCtx context.Context, st state.State, clu } } + // wait until the upgraded machine reports the new version + rtestutils.AssertResources(ctx, t, st, ids, func(r *omni.MachineStatus, assert *assert.Assertions) { + assert.Equal(newTalosVersion, strings.TrimLeft(r.TypedSpec().Value.TalosVersion, "v"), resourceDetails(r)) + }) + // revert the update _, err = safe.StateUpdateWithConflicts(ctx, st, omni.NewCluster(resources.DefaultNamespace, clusterName).Metadata(), func(cluster *omni.Cluster) error { cluster.TypedSpec().Value.TalosVersion = currentTalosVersion @@ -593,11 +598,6 @@ func AssertTalosUpgradeIsCancelable(testCtx context.Context, st state.State, clu }) require.NoError(t, err) - // wait until the upgraded machine reports the new version - rtestutils.AssertResources(ctx, t, st, ids, func(r *omni.MachineStatus, assert *assert.Assertions) { - assert.Equal(newTalosVersion, strings.TrimLeft(r.TypedSpec().Value.TalosVersion, "v"), resourceDetails(r)) - }) - rtestutils.AssertResources(ctx, t, st, ids, func(r *omni.ClusterMachineStatus, assert *assert.Assertions) { assert.Equal(specs.ClusterMachineStatusSpec_RUNNING, r.TypedSpec().Value.Stage, resourceDetails(r)) }) @@ -606,6 +606,11 @@ func AssertTalosUpgradeIsCancelable(testCtx context.Context, st state.State, clu rtestutils.AssertResources(ctx, t, st, ids, func(r *omni.MachineStatus, assert *assert.Assertions) { assert.Equal(currentTalosVersion, strings.TrimLeft(r.TypedSpec().Value.TalosVersion, "v"), resourceDetails(r)) }) + + // the upgrade should be not running + rtestutils.AssertResources(ctx, t, st, []resource.ID{clusterName}, func(r *omni.TalosUpgradeStatus, assert *assert.Assertions) { + assert.Equal(specs.TalosUpgradeStatusSpec_Done, r.TypedSpec().Value.Phase, resourceDetails(r)) + }) } } diff --git a/cmd/omni/main.go b/cmd/omni/main.go index 1075d34e..993a0c92 100644 --- a/cmd/omni/main.go +++ b/cmd/omni/main.go @@ -30,6 +30,7 @@ import ( authres "github.com/siderolabs/omni/client/pkg/omni/resources/auth" "github.com/siderolabs/omni/internal/backend" "github.com/siderolabs/omni/internal/backend/dns" + "github.com/siderolabs/omni/internal/backend/imagefactory" "github.com/siderolabs/omni/internal/backend/logging" "github.com/siderolabs/omni/internal/backend/resourcelogger" "github.com/siderolabs/omni/internal/backend/runtime/omni" @@ -163,10 +164,16 @@ func runWithState(logger *zap.Logger) func(context.Context, state.State, *virtua } } + imageFactoryClient, err := imagefactory.NewClient(resourceState, config.Config.ImageFactoryBaseURL) + if err != nil { + return fmt.Errorf("failed to set up image factory client: %w", err) + } + linkCounterDeltaCh := make(chan siderolink.LinkCounterDeltas) omniRuntime, err := omni.New(talosClientFactory, dnsService, workloadProxyServiceRegistry, resourceLogger, - linkCounterDeltaCh, resourceState, virtualState, prometheus.DefaultRegisterer, logger.With(logging.Component("omni_runtime"))) + imageFactoryClient, linkCounterDeltaCh, resourceState, virtualState, + prometheus.DefaultRegisterer, logger.With(logging.Component("omni_runtime"))) if err != nil { return fmt.Errorf("failed to set up the controller runtime: %w", err) } @@ -209,6 +216,7 @@ func runWithState(logger *zap.Logger) func(context.Context, state.State, *virtua rootCmdArgs.pprofBindAddress, dnsService, workloadProxyServiceRegistry, + imageFactoryClient, linkCounterDeltaCh, omniRuntime, talosRuntime, diff --git a/frontend/src/api/omni/specs/omni.pb.ts b/frontend/src/api/omni/specs/omni.pb.ts index 5850ea3e..67f7b7b1 100644 --- a/frontend/src/api/omni/specs/omni.pb.ts +++ b/frontend/src/api/omni/specs/omni.pb.ts @@ -187,6 +187,7 @@ export type MachineStatusSpecPlatformMetadata = { export type MachineStatusSpecSchematic = { id?: string invalid?: boolean + extensions?: string[] } export type MachineStatusSpecMaintenanceConfig = { @@ -605,7 +606,6 @@ export type ImagePullStatusSpec = { } export type SchematicSpec = { - extensions?: string[] } export type TalosExtensionsSpecInfo = { diff --git a/frontend/src/api/resources.ts b/frontend/src/api/resources.ts index 3e21a69b..64892d3a 100644 --- a/frontend/src/api/resources.ts +++ b/frontend/src/api/resources.ts @@ -150,7 +150,7 @@ export const KubernetesUsageType = "KubernetesUsages.omni.sidero.dev"; export const PermissionsID = "permissions"; export const PermissionsType = "Permissions.omni.sidero.dev"; export const SecureBoot = "secureboot"; -export const DefaultTalosVersion = "1.6.4"; +export const DefaultTalosVersion = "1.6.6"; export const PatchWeightInstallDisk = 0; export const PatchBaseWeightCluster = 200; export const PatchBaseWeightMachineSet = 400; diff --git a/frontend/src/views/omni/Modals/DownloadInstallationMedia.vue b/frontend/src/views/omni/Modals/DownloadInstallationMedia.vue index 96116ba0..c51d10f0 100644 --- a/frontend/src/views/omni/Modals/DownloadInstallationMedia.vue +++ b/frontend/src/views/omni/Modals/DownloadInstallationMedia.vue @@ -311,7 +311,7 @@ const createSchematic = async () => { meta_values: {}, }; - if (labels.value) { + if (labels.value && Object.keys(labels.value).length > 0) { const l: Record = {}; for (const k in labels.value) { l[k] = labels.value[k].value; diff --git a/internal/backend/grpc/export_test.go b/internal/backend/grpc/export_test.go index 787d8fa8..2171caca 100644 --- a/internal/backend/grpc/export_test.go +++ b/internal/backend/grpc/export_test.go @@ -7,14 +7,17 @@ package grpc import ( "github.com/cosi-project/runtime/pkg/state" + + "github.com/siderolabs/omni/internal/backend/imagefactory" ) type ManagementServer = managementServer //nolint:revive -func NewManagementServer(st state.State) *ManagementServer { +func NewManagementServer(st state.State, imageFactoryClient *imagefactory.Client) *ManagementServer { return &ManagementServer{ - omniState: st, + omniState: st, + imageFactoryClient: imageFactoryClient, } } diff --git a/internal/backend/grpc/grpc.go b/internal/backend/grpc/grpc.go index b58c4bfc..75e8a718 100644 --- a/internal/backend/grpc/grpc.go +++ b/internal/backend/grpc/grpc.go @@ -24,6 +24,7 @@ import ( "github.com/siderolabs/omni/client/api/talos/machine" "github.com/siderolabs/omni/internal/backend/dns" + "github.com/siderolabs/omni/internal/backend/imagefactory" "github.com/siderolabs/omni/internal/backend/logging" "github.com/siderolabs/omni/internal/backend/monitoring" "github.com/siderolabs/omni/internal/memconn" @@ -45,6 +46,7 @@ func MakeServiceServers( oidcProvider OIDCProvider, jwtSigningKeyProvider JWTSigningKeyProvider, dnsService *dns.Service, + imageFactoryClient *imagefactory.Client, logger *zap.Logger, ) ([]ServiceServer, error) { dest, err := generateDest(config.Config.APIURL) @@ -63,6 +65,7 @@ func MakeServiceServers( omniState: state, dnsService: dnsService, jwtSigningKeyProvider: jwtSigningKeyProvider, + imageFactoryClient: imageFactoryClient, logger: logger.With(logging.Component("management_server")), }, &authServer{ diff --git a/internal/backend/grpc/grpc_test.go b/internal/backend/grpc/grpc_test.go index a68c5658..d9743505 100644 --- a/internal/backend/grpc/grpc_test.go +++ b/internal/backend/grpc/grpc_test.go @@ -41,6 +41,7 @@ import ( "github.com/siderolabs/omni/client/pkg/omni/resources/omni" "github.com/siderolabs/omni/internal/backend/dns" grpcomni "github.com/siderolabs/omni/internal/backend/grpc" + "github.com/siderolabs/omni/internal/backend/imagefactory" "github.com/siderolabs/omni/internal/backend/logging" "github.com/siderolabs/omni/internal/backend/runtime" omniruntime "github.com/siderolabs/omni/internal/backend/runtime/omni" @@ -52,11 +53,12 @@ import ( type GrpcSuite struct { suite.Suite - runtime *omniruntime.Runtime - server *grpc.Server - conn *grpc.ClientConn - state state.State - eg errgroup.Group + runtime *omniruntime.Runtime + server *grpc.Server + conn *grpc.ClientConn + imageFactory *imageFactoryMock + state state.State + eg errgroup.Group ctx context.Context //nolint:containedctx ctxCancel context.CancelFunc @@ -76,11 +78,23 @@ func (suite *GrpcSuite) SetupTest() { dnsService := dns.NewService(suite.state, logger) + suite.imageFactory = &imageFactoryMock{} + + suite.Require().NoError(suite.imageFactory.run()) + suite.imageFactory.serve(suite.ctx) + + suite.T().Cleanup(func() { + suite.Require().NoError(suite.imageFactory.eg.Wait()) + }) + + imageFactoryClient, err := imagefactory.NewClient(suite.state, suite.imageFactory.address) + suite.Require().NoError(err) + workloadProxyServiceRegistry, err := workloadproxy.NewServiceRegistry(suite.state, logger) suite.Require().NoError(err) suite.runtime, err = omniruntime.New(clientFactory, dnsService, workloadProxyServiceRegistry, nil, - nil, suite.state, nil, prometheus.NewRegistry(), logger) + imageFactoryClient, nil, suite.state, nil, prometheus.NewRegistry(), logger) suite.Require().NoError(err) runtime.Install(omniruntime.Name, suite.runtime) @@ -91,6 +105,7 @@ func (suite *GrpcSuite) SetupTest() { authConfigInterceptor := interceptor.NewAuthConfig(false, logger.With(logging.Component("interceptor"))) err = suite.newServer( + imageFactoryClient, grpc.ChainUnaryInterceptor(authConfigInterceptor.Unary()), grpc.ChainStreamInterceptor(authConfigInterceptor.Stream()), ) @@ -262,7 +277,7 @@ func (suite *GrpcSuite) TestConfigValidation() { suite.Require().Equalf(codes.InvalidArgument, status.Code(err), err.Error()) } -func (suite *GrpcSuite) newServer(opts ...grpc.ServerOption) error { +func (suite *GrpcSuite) newServer(imageFactoryClient *imagefactory.Client, opts ...grpc.ServerOption) error { var err error suite.socketPath = filepath.Join(suite.T().TempDir(), "socket") @@ -279,6 +294,7 @@ func (suite *GrpcSuite) newServer(opts ...grpc.ServerOption) error { resapi.RegisterResourceServiceServer(suite.server, &grpcomni.ResourceServer{}) management.RegisterManagementServiceServer(suite.server, grpcomni.NewManagementServer( suite.state, + imageFactoryClient, )) go func() { diff --git a/internal/backend/grpc/management.go b/internal/backend/grpc/management.go index 8a5a4b22..3b770b88 100644 --- a/internal/backend/grpc/management.go +++ b/internal/backend/grpc/management.go @@ -48,6 +48,7 @@ import ( ctlcfg "github.com/siderolabs/omni/client/pkg/omnictl/config" "github.com/siderolabs/omni/internal/backend/dns" "github.com/siderolabs/omni/internal/backend/grpc/router" + "github.com/siderolabs/omni/internal/backend/imagefactory" "github.com/siderolabs/omni/internal/backend/runtime" "github.com/siderolabs/omni/internal/backend/runtime/kubernetes" "github.com/siderolabs/omni/internal/backend/runtime/omni" @@ -72,10 +73,11 @@ type managementServer struct { omniState state.State jwtSigningKeyProvider JWTSigningKeyProvider - logHandler *siderolink.LogHandler - logger *zap.Logger - dnsService *dns.Service - omniconfigDest string + logHandler *siderolink.LogHandler + logger *zap.Logger + dnsService *dns.Service + imageFactoryClient *imagefactory.Client + omniconfigDest string } func (s *managementServer) register(server grpc.ServiceRegistrar) { diff --git a/internal/backend/grpc/schematics.go b/internal/backend/grpc/schematics.go index 43fc9ad6..1df6b3da 100644 --- a/internal/backend/grpc/schematics.go +++ b/internal/backend/grpc/schematics.go @@ -12,8 +12,6 @@ import ( "strings" "github.com/cosi-project/runtime/pkg/safe" - "github.com/cosi-project/runtime/pkg/state" - "github.com/siderolabs/image-factory/pkg/client" "github.com/siderolabs/image-factory/pkg/schematic" "github.com/siderolabs/talos/pkg/machinery/resources/runtime" "google.golang.org/grpc/codes" @@ -22,10 +20,8 @@ import ( "github.com/siderolabs/omni/client/api/omni/management" "github.com/siderolabs/omni/client/pkg/meta" "github.com/siderolabs/omni/client/pkg/omni/resources" - "github.com/siderolabs/omni/client/pkg/omni/resources/omni" "github.com/siderolabs/omni/client/pkg/omni/resources/siderolink" "github.com/siderolabs/omni/internal/pkg/auth" - "github.com/siderolabs/omni/internal/pkg/auth/actor" "github.com/siderolabs/omni/internal/pkg/auth/role" "github.com/siderolabs/omni/internal/pkg/config" ) @@ -78,18 +74,9 @@ func (s *managementServer) CreateSchematic(ctx context.Context, request *managem Customization: customization, } - schematicID, err := schematic.ID() + schematicInfo, err := s.imageFactoryClient.EnsureSchematic(ctx, schematic) if err != nil { - return nil, fmt.Errorf("failed to generate schematic ID: %w", err) - } - - schematicResource := omni.NewSchematic( - resources.DefaultNamespace, schematicID, - ) - - res, err := safe.StateGet[*omni.Schematic](ctx, s.omniState, schematicResource.Metadata()) - if err != nil && !state.IsNotFoundError(err) { - return nil, err + return nil, fmt.Errorf("failed to ensure schematic: %w", err) } pxeURL, err := config.Config.GetImageFactoryPXEBaseURL() @@ -97,30 +84,8 @@ func (s *managementServer) CreateSchematic(ctx context.Context, request *managem return nil, err } - response := &management.CreateSchematicResponse{ - SchematicId: schematicID, - PxeUrl: pxeURL.JoinPath("pxe", schematicID).String(), - } - - if res != nil { - return response, nil - } - - client, err := client.New(config.Config.ImageFactoryBaseURL) - if err != nil { - return nil, err - } - - response.SchematicId, err = client.SchematicCreate(ctx, schematic) - if err != nil { - return nil, err - } - - schematicResource.TypedSpec().Value.Extensions = request.Extensions - - if err = s.omniState.Create(actor.MarkContextAsInternalActor(ctx), schematicResource); err != nil && !state.IsConflictError(err) { - return nil, err - } - - return response, nil + return &management.CreateSchematicResponse{ + SchematicId: schematicInfo.FullID, + PxeUrl: pxeURL.JoinPath("pxe", schematicInfo.FullID).String(), + }, nil } diff --git a/internal/backend/grpc/schematics_test.go b/internal/backend/grpc/schematics_test.go index 350dcd84..de8939d1 100644 --- a/internal/backend/grpc/schematics_test.go +++ b/internal/backend/grpc/schematics_test.go @@ -33,7 +33,6 @@ import ( "github.com/siderolabs/omni/client/pkg/omni/resources" "github.com/siderolabs/omni/client/pkg/omni/resources/omni" "github.com/siderolabs/omni/client/pkg/omni/resources/siderolink" - "github.com/siderolabs/omni/internal/pkg/config" ) type imageFactoryMock struct { @@ -153,19 +152,6 @@ func (suite *GrpcSuite) TestSchematicCreate() { suite.Require().NoError(suite.state.Create(ctx, params)) - factory := imageFactoryMock{} - suite.Require().NoError(factory.run()) - - factory.serve(ctx) - - defer func() { - cancel() - - suite.Require().NoError(factory.eg.Wait()) - }() - - config.Config.ImageFactoryBaseURL = factory.address - client := management.NewManagementServiceClient(suite.conn) for _, tt := range []struct { @@ -240,14 +226,12 @@ func (suite *GrpcSuite) TestSchematicCreate() { require.NoError(t, err) require.NotEmpty(t, resp.SchematicId) - rtestutils.AssertResource(ctx, t, suite.state, resp.SchematicId, func(res *omni.Schematic, assert *assert.Assertions) { - assert.EqualValues(req.Extensions, res.TypedSpec().Value.Extensions) - }) + rtestutils.AssertResource(ctx, t, suite.state, resp.SchematicId, func(*omni.Schematic, *assert.Assertions) {}) - factory.schematicMu.Lock() - defer factory.schematicMu.Unlock() + suite.imageFactory.schematicMu.Lock() + defer suite.imageFactory.schematicMu.Unlock() - config, ok := factory.schematics[resp.SchematicId] + config, ok := suite.imageFactory.schematics[resp.SchematicId] require.Truef(t, ok, "the schematic id %q doesn't exist in the image factory", resp.SchematicId) meta := xslices.ToMap(config.Customization.Meta, func(k schematic.MetaValue) (uint32, string) { diff --git a/internal/backend/imagefactory/client.go b/internal/backend/imagefactory/client.go new file mode 100644 index 00000000..b5dcbe07 --- /dev/null +++ b/internal/backend/imagefactory/client.go @@ -0,0 +1,122 @@ +// Copyright (c) 2024 Sidero Labs, Inc. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. + +// Package imagefactory implements image factory operations, enriching them with the Omni state. +package imagefactory + +import ( + "context" + "fmt" + "time" + + "github.com/cosi-project/runtime/pkg/safe" + "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/image-factory/pkg/client" + "github.com/siderolabs/image-factory/pkg/schematic" + + "github.com/siderolabs/omni/client/pkg/omni/resources" + "github.com/siderolabs/omni/client/pkg/omni/resources/omni" + "github.com/siderolabs/omni/internal/pkg/auth/actor" +) + +// Client is the image factory client. +type Client struct { + state state.State + *client.Client +} + +// NewClient creates a new image factory client. +func NewClient(omniState state.State, imageFactoryBaseURL string) (*Client, error) { + factoryClient, err := client.New(imageFactoryBaseURL) + if err != nil { + return nil, err + } + + return &Client{ + state: omniState, + Client: factoryClient, + }, nil +} + +// EnsuredSchematic contains information on the ensured schematics. +type EnsuredSchematic struct { + // FullID is the ID of the full schematic - with the whole content of the schematic.Schematic, i.e., the extra kernel arguments, META values, and system extensions. + FullID string + + // PlainID is the ID of the plain schematic - with only the system extensions. + PlainID string +} + +// EnsureSchematic ensures that the given schematic exists in the image factory. +// +// It ensures two schematics: one with the full content of the schematic.Schematic, and another with only the system extensions. +// +// We do not call the image factory for the schematics that are already known to (cached by) Omni. +func (cli *Client) EnsureSchematic(ctx context.Context, inputSchematic schematic.Schematic) (EnsuredSchematic, error) { + fullSchematicID, err := cli.ensureSingleSchematic(ctx, inputSchematic) + if err != nil { + return EnsuredSchematic{}, fmt.Errorf("failed to ensure single schematic: %w", err) + } + + plainSchematic := schematic.Schematic{ + Customization: schematic.Customization{ + SystemExtensions: schematic.SystemExtensions{ + OfficialExtensions: inputSchematic.Customization.SystemExtensions.OfficialExtensions, + }, + }, + } + + plainSchematicID, err := plainSchematic.ID() + if err != nil { + return EnsuredSchematic{}, fmt.Errorf("failed to generate plain schematic ID: %w", err) + } + + if plainSchematicID != fullSchematicID { + plainSchematicID, err = cli.ensureSingleSchematic(ctx, plainSchematic) + if err != nil { + return EnsuredSchematic{}, fmt.Errorf("failed to ensure plain schematic: %w", err) + } + } + + return EnsuredSchematic{ + FullID: fullSchematicID, + PlainID: plainSchematicID, + }, nil +} + +func (cli *Client) ensureSingleSchematic(ctx context.Context, schematic schematic.Schematic) (string, error) { + schematicID, err := schematic.ID() + if err != nil { + return "", fmt.Errorf("failed to generate schematic ID: %w", err) + } + + schematicResource := omni.NewSchematic( + resources.DefaultNamespace, schematicID, + ) + + res, err := safe.StateGetByID[*omni.Schematic](ctx, cli.state, schematicID) + if err != nil && !state.IsNotFoundError(err) { + return "", err + } + + if res != nil { + return schematicID, nil + } + + callCtx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + if _, err = cli.SchematicCreate(callCtx, schematic); err != nil { + return "", fmt.Errorf("failed to create schematic: %w", err) + } + + ctx = actor.MarkContextAsInternalActor(ctx) + + if err = cli.state.Create(ctx, schematicResource); err != nil && !state.IsConflictError(err) { + return "", err + } + + return schematicID, nil +} diff --git a/internal/backend/imagefactory/imagefactory.go b/internal/backend/imagefactory/imagefactory.go new file mode 100644 index 00000000..44d02a8f --- /dev/null +++ b/internal/backend/imagefactory/imagefactory.go @@ -0,0 +1,7 @@ +// Copyright (c) 2024 Sidero Labs, Inc. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. + +// Package imagefactory implements image factory operations the use cases of Omni. +package imagefactory diff --git a/internal/backend/runtime/omni/controllers/omni/cluster_machine_config_status.go b/internal/backend/runtime/omni/controllers/omni/cluster_machine_config_status.go index cce68882..6b291cf0 100644 --- a/internal/backend/runtime/omni/controllers/omni/cluster_machine_config_status.go +++ b/internal/backend/runtime/omni/controllers/omni/cluster_machine_config_status.go @@ -336,7 +336,7 @@ func (h *clusterMachineConfigStatusControllerHandler) syncTalosVersionAndSchemat return false, err } - actualSchematic, err := getSchematic(ctx, c) + schematicInfo, err := talosutils.GetSchematicInfo(ctx, c) if err != nil { if !errors.Is(err, talosutils.ErrInvalidSchematic) { return false, err @@ -345,12 +345,11 @@ func (h *clusterMachineConfigStatusControllerHandler) syncTalosVersionAndSchemat // compatibility code for the machines running extensions installed bypassing image factory // make schematic play no role in the checks expectedSchematic = "" - actualSchematic = "" } - if actualVersion == expectedVersion && actualSchematic == expectedSchematic { + if actualVersion == expectedVersion && schematicInfo.Equal(expectedSchematic) { configStatus.TypedSpec().Value.TalosVersion = actualVersion - configStatus.TypedSpec().Value.SchematicId = actualSchematic + configStatus.TypedSpec().Value.SchematicId = expectedSchematic return true, nil } @@ -363,7 +362,7 @@ func (h *clusterMachineConfigStatusControllerHandler) syncTalosVersionAndSchemat h.logger.Info("upgrading the machine", zap.String("from_version", actualVersion), zap.String("to_version", expectedVersion), - zap.String("from_schematic", actualSchematic), + zap.String("from_schematic", schematicInfo.ID), zap.String("to_schematic", expectedSchematic), zap.String("image", image), zap.String("machine", machineConfig.Metadata().ID())) @@ -726,7 +725,3 @@ func getVersion(ctx context.Context, c *client.Client) (string, error) { return "", errors.New("failed to get Talos version on the machine") } - -func getSchematic(ctx context.Context, c *client.Client) (string, error) { - return talosutils.GetSchematicID(ctx, c) -} diff --git a/internal/backend/runtime/omni/controllers/omni/internal/talos/schematic.go b/internal/backend/runtime/omni/controllers/omni/internal/talos/schematic.go index d73f9a9c..0019f5b8 100644 --- a/internal/backend/runtime/omni/controllers/omni/internal/talos/schematic.go +++ b/internal/backend/runtime/omni/controllers/omni/internal/talos/schematic.go @@ -8,8 +8,8 @@ package talos import ( "context" "fmt" + "strings" - "github.com/cosi-project/runtime/pkg/resource" "github.com/cosi-project/runtime/pkg/safe" "github.com/siderolabs/image-factory/pkg/constants" "github.com/siderolabs/image-factory/pkg/schematic" @@ -20,30 +20,68 @@ import ( // ErrInvalidSchematic means that the machine has extensions installed bypassing the image factory. var ErrInvalidSchematic = fmt.Errorf("invalid schematic") -// GetSchematicID calculates schematic using Talos client: reads extensions list and looks up schematic meta -// extension, or calculates vanilla schematic ID if there's none. -func GetSchematicID(ctx context.Context, c *client.Client) (string, error) { - extensions := map[resource.ID]*runtime.ExtensionStatus{} +// SchematicInfo contains the information about the schematic - the plain schematic ID and the extensions. +type SchematicInfo struct { + ID string + FullID string + Extensions []string +} + +// Equal compares schematic id with both extensions ID and Full ID. +func (si SchematicInfo) Equal(id string) bool { + return si.ID == id || si.FullID == id +} + +// GetSchematicInfo uses Talos API to list all the schematics, and computes the plain schematic ID, +// taking only the extensions into account - ignoring everything else, e.g., the kernel command line args or meta values. +func GetSchematicInfo(ctx context.Context, c *client.Client) (SchematicInfo, error) { + const officialExtensionPrefix = "siderolabs/" items, err := safe.StateListAll[*runtime.ExtensionStatus](ctx, c.COSI) if err != nil { - return "", err + return SchematicInfo{}, fmt.Errorf("failed to list extensions: %w", err) } + var ( + extensions []string + schematicID string + ) + items.ForEach(func(status *runtime.ExtensionStatus) { - extensions[status.TypedSpec().Metadata.Name] = status + name := status.TypedSpec().Metadata.Name + if name == constants.SchematicIDExtensionName { // skip the meta extension + schematicID = status.TypedSpec().Metadata.Version + + return + } + + if !strings.HasPrefix(name, officialExtensionPrefix) { + name = officialExtensionPrefix + name + } + + extensions = append(extensions, name) }) - schematicExtension, ok := extensions[constants.SchematicIDExtensionName] + if schematicID == "" && len(extensions) > 0 { + return SchematicInfo{}, ErrInvalidSchematic + } - if !ok && len(extensions) > 0 { - return "", ErrInvalidSchematic + extensionsSchematic := schematic.Schematic{ + Customization: schematic.Customization{ + SystemExtensions: schematic.SystemExtensions{ + OfficialExtensions: extensions, + }, + }, } - // default schematic - if !ok { - return (&schematic.Schematic{}).ID() + id, err := extensionsSchematic.ID() + if err != nil { + return SchematicInfo{}, fmt.Errorf("failed to calculate extensions schematic ID: %w", err) } - return schematicExtension.TypedSpec().Metadata.Version, nil + return SchematicInfo{ + ID: id, + FullID: schematicID, + Extensions: extensions, + }, nil } diff --git a/internal/backend/runtime/omni/controllers/omni/internal/task/machine/poll.go b/internal/backend/runtime/omni/controllers/omni/internal/task/machine/poll.go index f9dd5045..9da860d9 100644 --- a/internal/backend/runtime/omni/controllers/omni/internal/task/machine/poll.go +++ b/internal/backend/runtime/omni/controllers/omni/internal/task/machine/poll.go @@ -333,7 +333,7 @@ func pollExtensions(ctx context.Context, c *client.Client, info *Info) error { var err error - machineSchematic.Id, err = talos.GetSchematicID(ctx, c) + schematicInfo, err := talos.GetSchematicInfo(ctx, c) if err != nil { if errors.Is(err, talos.ErrInvalidSchematic) { machineSchematic.Invalid = true @@ -344,6 +344,9 @@ func pollExtensions(ctx context.Context, c *client.Client, info *Info) error { return err } + machineSchematic.Id = schematicInfo.ID + machineSchematic.Extensions = schematicInfo.Extensions + return nil } diff --git a/internal/backend/runtime/omni/controllers/omni/machine_status.go b/internal/backend/runtime/omni/controllers/omni/machine_status.go index 0c1ad56b..efd91af5 100644 --- a/internal/backend/runtime/omni/controllers/omni/machine_status.go +++ b/internal/backend/runtime/omni/controllers/omni/machine_status.go @@ -14,20 +14,28 @@ import ( "github.com/cosi-project/runtime/pkg/resource/kvutils" "github.com/cosi-project/runtime/pkg/safe" cosistate "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/image-factory/pkg/schematic" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "go.uber.org/zap" "github.com/siderolabs/omni/client/api/omni/specs" "github.com/siderolabs/omni/client/pkg/omni/resources" "github.com/siderolabs/omni/client/pkg/omni/resources/omni" + "github.com/siderolabs/omni/internal/backend/imagefactory" "github.com/siderolabs/omni/internal/backend/runtime/omni/controllers/helpers" "github.com/siderolabs/omni/internal/backend/runtime/omni/controllers/omni/internal/task" "github.com/siderolabs/omni/internal/backend/runtime/omni/controllers/omni/internal/task/machine" ) +// SchematicEnsurer ensures that the given schematic exists in the image factory. +type SchematicEnsurer interface { + EnsureSchematic(ctx context.Context, inputSchematic schematic.Schematic) (imagefactory.EnsuredSchematic, error) +} + // MachineStatusController manages omni.MachineStatuses based on information from Talos API. type MachineStatusController struct { - runner *task.Runner[machine.InfoChan, machine.CollectTaskSpec] + runner *task.Runner[machine.InfoChan, machine.CollectTaskSpec] + ImageFactoryClient SchematicEnsurer } // Name implements controller.Controller interface. @@ -412,5 +420,19 @@ func (ctrl *MachineStatusController) handleNotification(ctx context.Context, r c return fmt.Errorf("error modifying resource: %w", err) } + if event.Schematic != nil && event.Schematic.Id != "" { + machineSchematic := schematic.Schematic{ + Customization: schematic.Customization{ + SystemExtensions: schematic.SystemExtensions{ + OfficialExtensions: event.Schematic.Extensions, + }, + }, + } + + if _, err := ctrl.ImageFactoryClient.EnsureSchematic(ctx, machineSchematic); err != nil { + return fmt.Errorf("error ensuring schematic: %w", err) + } + } + return nil } diff --git a/internal/backend/runtime/omni/controllers/omni/machine_status_link_test.go b/internal/backend/runtime/omni/controllers/omni/machine_status_link_test.go index ad855505..1b678f30 100644 --- a/internal/backend/runtime/omni/controllers/omni/machine_status_link_test.go +++ b/internal/backend/runtime/omni/controllers/omni/machine_status_link_test.go @@ -34,7 +34,9 @@ func (suite *MachineStatusLinkSuite) SetupTest() { suite.deltaCh = make(chan siderolinkmanager.LinkCounterDeltas) - suite.Require().NoError(suite.runtime.RegisterController(&omnictrl.MachineStatusController{})) + suite.Require().NoError(suite.runtime.RegisterController(&omnictrl.MachineStatusController{ + ImageFactoryClient: &imageFactoryClientMock{}, + })) suite.Require().NoError(suite.runtime.RegisterController(omnictrl.NewMachineStatusLinkController(suite.deltaCh))) } diff --git a/internal/backend/runtime/omni/controllers/omni/machine_status_test.go b/internal/backend/runtime/omni/controllers/omni/machine_status_test.go index 18b6941f..fc5170e9 100644 --- a/internal/backend/runtime/omni/controllers/omni/machine_status_test.go +++ b/internal/backend/runtime/omni/controllers/omni/machine_status_test.go @@ -25,9 +25,37 @@ import ( "github.com/siderolabs/omni/client/pkg/meta" "github.com/siderolabs/omni/client/pkg/omni/resources" "github.com/siderolabs/omni/client/pkg/omni/resources/omni" + "github.com/siderolabs/omni/internal/backend/imagefactory" omnictrl "github.com/siderolabs/omni/internal/backend/runtime/omni/controllers/omni" ) +type imageFactoryClientMock struct{} + +func (i *imageFactoryClientMock) EnsureSchematic(_ context.Context, sch schematic.Schematic) (imagefactory.EnsuredSchematic, error) { + fullID, err := sch.ID() + if err != nil { + return imagefactory.EnsuredSchematic{}, err + } + + plainSchematic := schematic.Schematic{ + Customization: schematic.Customization{ + SystemExtensions: schematic.SystemExtensions{ + OfficialExtensions: sch.Customization.SystemExtensions.OfficialExtensions, + }, + }, + } + + plainID, err := plainSchematic.ID() + if err != nil { + return imagefactory.EnsuredSchematic{}, err + } + + return imagefactory.EnsuredSchematic{ + FullID: fullID, + PlainID: plainID, + }, nil +} + type MachineStatusSuite struct { OmniSuite } @@ -35,7 +63,9 @@ type MachineStatusSuite struct { func (suite *MachineStatusSuite) setup() { suite.startRuntime() - suite.Require().NoError(suite.runtime.RegisterController(&omnictrl.MachineStatusController{})) + suite.Require().NoError(suite.runtime.RegisterController(&omnictrl.MachineStatusController{ + ImageFactoryClient: &imageFactoryClientMock{}, + })) } const testID = "testID" @@ -247,18 +277,41 @@ func (suite *MachineStatusSuite) TestMachineSchematic() { extensions []*runtime.ExtensionStatusSpec }{ { - name: "just schematic id", + name: "extensions", extensions: []*runtime.ExtensionStatusSpec{ { Metadata: extensions.Metadata{ - Name: "schematic", - Version: "1234", - Description: constants.SchematicIDExtensionName, + Name: "gvisor", + Description: "0", + }, + }, + { + Metadata: extensions.Metadata{ + Name: "hello-world-service", + Description: "1", + }, + }, + { + Metadata: extensions.Metadata{ + Name: "mdadm", + Description: "2", + }, + }, + { + Metadata: extensions.Metadata{ + Name: constants.SchematicIDExtensionName, + Description: "3", + Version: "1", }, }, }, expected: &specs.MachineStatusSpec_Schematic{ - Id: "1234", + Id: "7d79f1ce28d7e6c099bc89ccf02238fb574165eb4834c2abf2a61eab998d4dc6", + Extensions: []string{ + "siderolabs/gvisor", + "siderolabs/hello-world-service", + "siderolabs/mdadm", + }, }, }, { diff --git a/internal/backend/runtime/omni/controllers/omni/talos_extensions.go b/internal/backend/runtime/omni/controllers/omni/talos_extensions.go index d3d74337..cbd211f7 100644 --- a/internal/backend/runtime/omni/controllers/omni/talos_extensions.go +++ b/internal/backend/runtime/omni/controllers/omni/talos_extensions.go @@ -15,13 +15,12 @@ import ( "github.com/cosi-project/runtime/pkg/controller" "github.com/cosi-project/runtime/pkg/controller/generic/qtransform" "github.com/siderolabs/gen/xerrors" - "github.com/siderolabs/image-factory/pkg/client" "go.uber.org/zap" "github.com/siderolabs/omni/client/api/omni/specs" "github.com/siderolabs/omni/client/pkg/omni/resources" "github.com/siderolabs/omni/client/pkg/omni/resources/omni" - "github.com/siderolabs/omni/internal/pkg/config" + "github.com/siderolabs/omni/internal/backend/imagefactory" ) // TalosExtensionsController creates omni.TalosExtensions for each omni.TalosVersion. @@ -30,7 +29,7 @@ import ( type TalosExtensionsController = qtransform.QController[*omni.TalosVersion, *omni.TalosExtensions] // NewTalosExtensionsController instantiates the TalosExtensions controller. -func NewTalosExtensionsController() *TalosExtensionsController { +func NewTalosExtensionsController(imageFactoryClient *imagefactory.Client) *TalosExtensionsController { return qtransform.NewQController( qtransform.Settings[*omni.TalosVersion, *omni.TalosExtensions]{ Name: "TalosExtensionsController", @@ -41,12 +40,10 @@ func NewTalosExtensionsController() *TalosExtensionsController { return omni.NewTalosVersion(resources.DefaultNamespace, r.Metadata().ID()) }, TransformFunc: func(ctx context.Context, _ controller.Reader, _ *zap.Logger, version *omni.TalosVersion, extensionsResource *omni.TalosExtensions) error { - factoryClient, err := client.New(config.Config.ImageFactoryBaseURL) - if err != nil { - return fmt.Errorf("failed to get image factory client %w", err) - } + ctx, cancel := context.WithTimeout(ctx, time.Second*10) + defer cancel() - versions, err := factoryClient.Versions(ctx) + versions, err := imageFactoryClient.Versions(ctx) if err != nil { return fmt.Errorf("failed to get existing image factory Talos versions %w", err) } @@ -58,7 +55,7 @@ func NewTalosExtensionsController() *TalosExtensionsController { return xerrors.NewTaggedf[qtransform.SkipReconcileTag]("version %q is not registered in the image factory", version.Metadata().ID()) } - extensionsVersions, err := factoryClient.ExtensionsVersions(ctx, version.TypedSpec().Value.Version) + extensionsVersions, err := imageFactoryClient.ExtensionsVersions(ctx, version.TypedSpec().Value.Version) if err != nil { return controller.NewRequeueErrorf(time.Minute*5, "failed to get extension versions from the image factory %w", err) } diff --git a/internal/backend/runtime/omni/controllers/omni/talos_extensions_test.go b/internal/backend/runtime/omni/controllers/omni/talos_extensions_test.go index 06792dba..f378dc7d 100644 --- a/internal/backend/runtime/omni/controllers/omni/talos_extensions_test.go +++ b/internal/backend/runtime/omni/controllers/omni/talos_extensions_test.go @@ -25,8 +25,8 @@ import ( "github.com/siderolabs/omni/client/pkg/omni/resources" "github.com/siderolabs/omni/client/pkg/omni/resources/omni" + "github.com/siderolabs/omni/internal/backend/imagefactory" omnictrl "github.com/siderolabs/omni/internal/backend/runtime/omni/controllers/omni" - "github.com/siderolabs/omni/internal/pkg/config" ) //nolint:govet @@ -155,11 +155,12 @@ func (suite *TalosExtensionsSuite) TestReconcile() { factory.eg.Wait() //nolint:errcheck }() - config.Config.ImageFactoryBaseURL = factory.address + imageFactoryClient, err := imagefactory.NewClient(suite.state, factory.address) + suite.Require().NoError(err) suite.startRuntime() - suite.Require().NoError(suite.runtime.RegisterQController(omnictrl.NewTalosExtensionsController())) + suite.Require().NoError(suite.runtime.RegisterQController(omnictrl.NewTalosExtensionsController(imageFactoryClient))) versions := []string{ "0.14.0", "1.6.0", "200.0.0", diff --git a/internal/backend/runtime/omni/controllers/omni/talos_upgrade_status.go b/internal/backend/runtime/omni/controllers/omni/talos_upgrade_status.go index 0fb47993..0aeed724 100644 --- a/internal/backend/runtime/omni/controllers/omni/talos_upgrade_status.go +++ b/internal/backend/runtime/omni/controllers/omni/talos_upgrade_status.go @@ -303,6 +303,7 @@ func reconcileTalosUpdateStatus(ctx context.Context, r controller.ReaderWriter, var clusterMachineTalosVersion *omni.ClusterMachineTalosVersion + // if we end up creating the ClusterMachineTalosVersion here, schematic won't be outdated, as we are setting it to the desired schematic ID clusterMachineTalosVersion, err = getOrCreateResource(ctx, r, machine, talosVersion, schematicID) if err != nil { return err diff --git a/internal/backend/runtime/omni/omni.go b/internal/backend/runtime/omni/omni.go index 5e5d2474..f73ed6c0 100644 --- a/internal/backend/runtime/omni/omni.go +++ b/internal/backend/runtime/omni/omni.go @@ -32,6 +32,7 @@ import ( virtualres "github.com/siderolabs/omni/client/pkg/omni/resources/virtual" pkgruntime "github.com/siderolabs/omni/client/pkg/runtime" "github.com/siderolabs/omni/internal/backend/dns" + "github.com/siderolabs/omni/internal/backend/imagefactory" "github.com/siderolabs/omni/internal/backend/resourcelogger" "github.com/siderolabs/omni/internal/backend/runtime" "github.com/siderolabs/omni/internal/backend/runtime/cosi" @@ -73,7 +74,7 @@ type Runtime struct { // //nolint:maintidx func New(talosClientFactory *talos.ClientFactory, dnsService *dns.Service, workloadProxyServiceRegistry *workloadproxy.ServiceRegistry, - resourceLogger *resourcelogger.Logger, linkCounterDeltaCh <-chan siderolink.LinkCounterDeltas, resourceState state.State, + resourceLogger *resourcelogger.Logger, imageFactoryClient *imagefactory.Client, linkCounterDeltaCh <-chan siderolink.LinkCounterDeltas, resourceState state.State, virtualState *virtual.State, metricsRegistry prometheus.Registerer, logger *zap.Logger, ) (*Runtime, error) { var opts []options.Option @@ -168,7 +169,9 @@ func New(talosClientFactory *talos.ClientFactory, dnsService *dns.Service, workl &omnictrl.LoadBalancerController{}, &omnictrl.MachineSetNodeController{}, &omnictrl.MachineSetDestroyStatusController{}, - &omnictrl.MachineStatusController{}, + &omnictrl.MachineStatusController{ + ImageFactoryClient: imageFactoryClient, + }, omnictrl.NewMachineCleanupController(), omnictrl.NewMachineStatusLinkController(linkCounterDeltaCh), &omnictrl.MachineStatusMetricsController{}, @@ -211,7 +214,7 @@ func New(talosClientFactory *talos.ClientFactory, dnsService *dns.Service, workl omnictrl.NewRedactedClusterMachineConfigController(), omnictrl.NewSecretsController(storeFactory), omnictrl.NewTalosConfigController(constants.CertificateValidityTime), - omnictrl.NewTalosExtensionsController(), + omnictrl.NewTalosExtensionsController(imageFactoryClient), omnictrl.NewTalosUpgradeStatusController(), } diff --git a/internal/backend/runtime/omni/omni_test.go b/internal/backend/runtime/omni/omni_test.go index 222c4232..9f1acb81 100644 --- a/internal/backend/runtime/omni/omni_test.go +++ b/internal/backend/runtime/omni/omni_test.go @@ -86,7 +86,7 @@ func (suite *OmniRuntimeSuite) SetupTest() { workloadProxyServiceRegistry, err := workloadproxy.NewServiceRegistry(resourceState, logger) suite.Require().NoError(err) - suite.runtime, err = omniruntime.New(clientFactory, dnsService, workloadProxyServiceRegistry, nil, nil, + suite.runtime, err = omniruntime.New(clientFactory, dnsService, workloadProxyServiceRegistry, nil, nil, nil, resourceState, nil, prometheus.NewRegistry(), logger) suite.Require().NoError(err) diff --git a/internal/backend/server.go b/internal/backend/server.go index ffb8636b..8d7c1636 100644 --- a/internal/backend/server.go +++ b/internal/backend/server.go @@ -59,6 +59,7 @@ import ( grpcomni "github.com/siderolabs/omni/internal/backend/grpc" "github.com/siderolabs/omni/internal/backend/grpc/router" "github.com/siderolabs/omni/internal/backend/health" + "github.com/siderolabs/omni/internal/backend/imagefactory" "github.com/siderolabs/omni/internal/backend/k8sproxy" "github.com/siderolabs/omni/internal/backend/logging" "github.com/siderolabs/omni/internal/backend/monitoring" @@ -94,6 +95,7 @@ type Server struct { authConfig *authres.Config dnsService *dns.Service workloadProxyServiceRegistry *workloadproxy.ServiceRegistry + imageFactoryClient *imagefactory.Client linkCounterDeltaCh chan<- siderolink.LinkCounterDeltas @@ -111,6 +113,7 @@ func NewServer( bindAddress, metricsBindAddress, k8sProxyBindAddress, pprofBindAddress string, dnsService *dns.Service, workloadProxyServiceRegistry *workloadproxy.ServiceRegistry, + imageFactoryClient *imagefactory.Client, linkCounterDeltaCh chan<- siderolink.LinkCounterDeltas, omniRuntime *omni.Runtime, talosRuntime *talos.Runtime, @@ -127,6 +130,7 @@ func NewServer( authConfig: authConfig, dnsService: dnsService, workloadProxyServiceRegistry: workloadProxyServiceRegistry, + imageFactoryClient: imageFactoryClient, linkCounterDeltaCh: linkCounterDeltaCh, proxyServer: proxyServer, bindAddress: bindAddress, @@ -202,7 +206,7 @@ func (s *Server) Run(ctx context.Context) error { return err } - serviceServers, err := grpcomni.MakeServiceServers(runtimeState, s.logHandler, oidcProvider, oidcStorage, s.dnsService, s.logger) + serviceServers, err := grpcomni.MakeServiceServers(runtimeState, s.logHandler, oidcProvider, oidcStorage, s.dnsService, s.imageFactoryClient, s.logger) if err != nil { return err }