mirror of
https://github.com/siderolabs/omni.git
synced 2026-05-05 06:36:12 +02:00
feat: check on start up if the account has Talos < 1.6 and strict tokens
Some checks failed
default / default (push) Has been cancelled
default / e2e-backups (push) Has been cancelled
default / e2e-cluster-import (push) Has been cancelled
default / e2e-forced-removal (push) Has been cancelled
default / e2e-omni-upgrade (push) Has been cancelled
default / e2e-scaling (push) Has been cancelled
default / e2e-short (push) Has been cancelled
default / e2e-short-secureboot (push) Has been cancelled
default / e2e-templates (push) Has been cancelled
default / e2e-upgrades (push) Has been cancelled
default / e2e-workload-proxy (push) Has been cancelled
default / integration-test (push) Has been cancelled
default / lint (push) Has been cancelled
default / unit-tests (push) Has been cancelled
Some checks failed
default / default (push) Has been cancelled
default / e2e-backups (push) Has been cancelled
default / e2e-cluster-import (push) Has been cancelled
default / e2e-forced-removal (push) Has been cancelled
default / e2e-omni-upgrade (push) Has been cancelled
default / e2e-scaling (push) Has been cancelled
default / e2e-short (push) Has been cancelled
default / e2e-short-secureboot (push) Has been cancelled
default / e2e-templates (push) Has been cancelled
default / e2e-upgrades (push) Has been cancelled
default / e2e-workload-proxy (push) Has been cancelled
default / integration-test (push) Has been cancelled
default / lint (push) Has been cancelled
default / unit-tests (push) Has been cancelled
If both conditions are true, make Omni crash with the error explaining that using Talos 1.6 and `strict` join tokens mode is not possible. Fixes: https://github.com/siderolabs/omni/issues/1588 Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
This commit is contained in:
parent
99f1506f01
commit
dbe39ea1fc
@ -5868,6 +5868,7 @@ type MachineStatusMetricsSpec struct {
|
||||
ConnectedMachinesCount uint32 `protobuf:"varint,2,opt,name=connected_machines_count,json=connectedMachinesCount,proto3" json:"connected_machines_count,omitempty"`
|
||||
AllocatedMachinesCount uint32 `protobuf:"varint,3,opt,name=allocated_machines_count,json=allocatedMachinesCount,proto3" json:"allocated_machines_count,omitempty"`
|
||||
PendingMachinesCount uint32 `protobuf:"varint,4,opt,name=pending_machines_count,json=pendingMachinesCount,proto3" json:"pending_machines_count,omitempty"`
|
||||
VersionsMap map[string]int32 `protobuf:"bytes,5,rep,name=versions_map,json=versionsMap,proto3" json:"versions_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@ -5930,6 +5931,13 @@ func (x *MachineStatusMetricsSpec) GetPendingMachinesCount() uint32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *MachineStatusMetricsSpec) GetVersionsMap() map[string]int32 {
|
||||
if x != nil {
|
||||
return x.VersionsMap
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClusterStatusMetricsSpec provides aggregated state of the number of clusters in not ready phase.
|
||||
// and the number of clusters in each phase.
|
||||
type ClusterStatusMetricsSpec struct {
|
||||
@ -8688,7 +8696,7 @@ type ClusterDiagnosticsSpec_Node struct {
|
||||
|
||||
func (x *ClusterDiagnosticsSpec_Node) Reset() {
|
||||
*x = ClusterDiagnosticsSpec_Node{}
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[118]
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[119]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -8700,7 +8708,7 @@ func (x *ClusterDiagnosticsSpec_Node) String() string {
|
||||
func (*ClusterDiagnosticsSpec_Node) ProtoMessage() {}
|
||||
|
||||
func (x *ClusterDiagnosticsSpec_Node) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[118]
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[119]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -8742,7 +8750,7 @@ type InfraMachineBMCConfigSpec_IPMI struct {
|
||||
|
||||
func (x *InfraMachineBMCConfigSpec_IPMI) Reset() {
|
||||
*x = InfraMachineBMCConfigSpec_IPMI{}
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[119]
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[120]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -8754,7 +8762,7 @@ func (x *InfraMachineBMCConfigSpec_IPMI) String() string {
|
||||
func (*InfraMachineBMCConfigSpec_IPMI) ProtoMessage() {}
|
||||
|
||||
func (x *InfraMachineBMCConfigSpec_IPMI) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[119]
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[120]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -8807,7 +8815,7 @@ type InfraMachineBMCConfigSpec_API struct {
|
||||
|
||||
func (x *InfraMachineBMCConfigSpec_API) Reset() {
|
||||
*x = InfraMachineBMCConfigSpec_API{}
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[120]
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[121]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -8819,7 +8827,7 @@ func (x *InfraMachineBMCConfigSpec_API) String() string {
|
||||
func (*InfraMachineBMCConfigSpec_API) ProtoMessage() {}
|
||||
|
||||
func (x *InfraMachineBMCConfigSpec_API) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[120]
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[121]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -8853,7 +8861,7 @@ type InfraProviderCombinedStatusSpec_Health struct {
|
||||
|
||||
func (x *InfraProviderCombinedStatusSpec_Health) Reset() {
|
||||
*x = InfraProviderCombinedStatusSpec_Health{}
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[121]
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[122]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -8865,7 +8873,7 @@ func (x *InfraProviderCombinedStatusSpec_Health) String() string {
|
||||
func (*InfraProviderCombinedStatusSpec_Health) ProtoMessage() {}
|
||||
|
||||
func (x *InfraProviderCombinedStatusSpec_Health) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[121]
|
||||
mi := &file_omni_specs_omni_proto_msgTypes[122]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -9478,12 +9486,16 @@ const file_omni_specs_omni_proto_rawDesc = "" +
|
||||
"\tInstalled\x10\x00\x12\x0e\n" +
|
||||
"\n" +
|
||||
"Installing\x10\x01\x12\f\n" +
|
||||
"\bRemoving\x10\x02\"\x80\x02\n" +
|
||||
"\bRemoving\x10\x02\"\x95\x03\n" +
|
||||
"\x18MachineStatusMetricsSpec\x12:\n" +
|
||||
"\x19registered_machines_count\x18\x01 \x01(\rR\x17registeredMachinesCount\x128\n" +
|
||||
"\x18connected_machines_count\x18\x02 \x01(\rR\x16connectedMachinesCount\x128\n" +
|
||||
"\x18allocated_machines_count\x18\x03 \x01(\rR\x16allocatedMachinesCount\x124\n" +
|
||||
"\x16pending_machines_count\x18\x04 \x01(\rR\x14pendingMachinesCount\"\xc2\x01\n" +
|
||||
"\x16pending_machines_count\x18\x04 \x01(\rR\x14pendingMachinesCount\x12S\n" +
|
||||
"\fversions_map\x18\x05 \x03(\v20.specs.MachineStatusMetricsSpec.VersionsMapEntryR\vversionsMap\x1a>\n" +
|
||||
"\x10VersionsMapEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\x05R\x05value:\x028\x01\"\xc2\x01\n" +
|
||||
"\x18ClusterStatusMetricsSpec\x12&\n" +
|
||||
"\x0fnot_ready_count\x18\x01 \x01(\rR\rnotReadyCount\x12C\n" +
|
||||
"\x06phases\x18\x02 \x03(\v2+.specs.ClusterStatusMetricsSpec.PhasesEntryR\x06phases\x1a9\n" +
|
||||
@ -9612,7 +9624,7 @@ func file_omni_specs_omni_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_omni_specs_omni_proto_enumTypes = make([]protoimpl.EnumInfo, 22)
|
||||
var file_omni_specs_omni_proto_msgTypes = make([]protoimpl.MessageInfo, 122)
|
||||
var file_omni_specs_omni_proto_msgTypes = make([]protoimpl.MessageInfo, 123)
|
||||
var file_omni_specs_omni_proto_goTypes = []any{
|
||||
(ConfigApplyStatus)(0), // 0: specs.ConfigApplyStatus
|
||||
(MachineSetPhase)(0), // 1: specs.MachineSetPhase
|
||||
@ -9753,14 +9765,15 @@ var file_omni_specs_omni_proto_goTypes = []any{
|
||||
(*ImagePullRequestSpec_NodeImageList)(nil), // 136: specs.ImagePullRequestSpec.NodeImageList
|
||||
(*TalosExtensionsSpec_Info)(nil), // 137: specs.TalosExtensionsSpec.Info
|
||||
(*MachineExtensionsStatusSpec_Item)(nil), // 138: specs.MachineExtensionsStatusSpec.Item
|
||||
nil, // 139: specs.ClusterStatusMetricsSpec.PhasesEntry
|
||||
(*ClusterDiagnosticsSpec_Node)(nil), // 140: specs.ClusterDiagnosticsSpec.Node
|
||||
(*InfraMachineBMCConfigSpec_IPMI)(nil), // 141: specs.InfraMachineBMCConfigSpec.IPMI
|
||||
(*InfraMachineBMCConfigSpec_API)(nil), // 142: specs.InfraMachineBMCConfigSpec.API
|
||||
(*InfraProviderCombinedStatusSpec_Health)(nil), // 143: specs.InfraProviderCombinedStatusSpec.Health
|
||||
(*durationpb.Duration)(nil), // 144: google.protobuf.Duration
|
||||
(*timestamppb.Timestamp)(nil), // 145: google.protobuf.Timestamp
|
||||
(*machine.MachineStatusEvent)(nil), // 146: machine.MachineStatusEvent
|
||||
nil, // 139: specs.MachineStatusMetricsSpec.VersionsMapEntry
|
||||
nil, // 140: specs.ClusterStatusMetricsSpec.PhasesEntry
|
||||
(*ClusterDiagnosticsSpec_Node)(nil), // 141: specs.ClusterDiagnosticsSpec.Node
|
||||
(*InfraMachineBMCConfigSpec_IPMI)(nil), // 142: specs.InfraMachineBMCConfigSpec.IPMI
|
||||
(*InfraMachineBMCConfigSpec_API)(nil), // 143: specs.InfraMachineBMCConfigSpec.API
|
||||
(*InfraProviderCombinedStatusSpec_Health)(nil), // 144: specs.InfraProviderCombinedStatusSpec.Health
|
||||
(*durationpb.Duration)(nil), // 145: google.protobuf.Duration
|
||||
(*timestamppb.Timestamp)(nil), // 146: google.protobuf.Timestamp
|
||||
(*machine.MachineStatusEvent)(nil), // 147: machine.MachineStatusEvent
|
||||
}
|
||||
var file_omni_specs_omni_proto_depIdxs = []int32{
|
||||
111, // 0: specs.MachineStatusSpec.hardware:type_name -> specs.MachineStatusSpec.HardwareStatus
|
||||
@ -9774,13 +9787,13 @@ var file_omni_specs_omni_proto_depIdxs = []int32{
|
||||
23, // 8: specs.MachineStatusSpec.security_state:type_name -> specs.SecurityState
|
||||
121, // 9: specs.ClusterSpec.features:type_name -> specs.ClusterSpec.Features
|
||||
30, // 10: specs.ClusterSpec.backup_configuration:type_name -> specs.EtcdBackupConf
|
||||
144, // 11: specs.EtcdBackupConf.interval:type_name -> google.protobuf.Duration
|
||||
145, // 12: specs.EtcdBackupSpec.created_at:type_name -> google.protobuf.Timestamp
|
||||
144, // 13: specs.BackupDataSpec.interval:type_name -> google.protobuf.Duration
|
||||
145, // 11: specs.EtcdBackupConf.interval:type_name -> google.protobuf.Duration
|
||||
146, // 12: specs.EtcdBackupSpec.created_at:type_name -> google.protobuf.Timestamp
|
||||
145, // 13: specs.BackupDataSpec.interval:type_name -> google.protobuf.Duration
|
||||
6, // 14: specs.EtcdBackupStatusSpec.status:type_name -> specs.EtcdBackupStatusSpec.Status
|
||||
145, // 15: specs.EtcdBackupStatusSpec.last_backup_time:type_name -> google.protobuf.Timestamp
|
||||
145, // 16: specs.EtcdBackupStatusSpec.last_backup_attempt:type_name -> google.protobuf.Timestamp
|
||||
145, // 17: specs.EtcdManualBackupSpec.backup_at:type_name -> google.protobuf.Timestamp
|
||||
146, // 15: specs.EtcdBackupStatusSpec.last_backup_time:type_name -> google.protobuf.Timestamp
|
||||
146, // 16: specs.EtcdBackupStatusSpec.last_backup_attempt:type_name -> google.protobuf.Timestamp
|
||||
146, // 17: specs.EtcdManualBackupSpec.backup_at:type_name -> google.protobuf.Timestamp
|
||||
36, // 18: specs.EtcdBackupOverallStatusSpec.last_backup_status:type_name -> specs.EtcdBackupStatusSpec
|
||||
7, // 19: specs.ClusterMachineStatusSpec.stage:type_name -> specs.ClusterMachineStatusSpec.Stage
|
||||
0, // 20: specs.ClusterMachineStatusSpec.config_apply_status:type_name -> specs.ConfigApplyStatus
|
||||
@ -9798,7 +9811,7 @@ var file_omni_specs_omni_proto_depIdxs = []int32{
|
||||
1, // 32: specs.MachineSetStatusSpec.phase:type_name -> specs.MachineSetPhase
|
||||
48, // 33: specs.MachineSetStatusSpec.machines:type_name -> specs.Machines
|
||||
124, // 34: specs.MachineSetStatusSpec.machine_allocation:type_name -> specs.MachineSetSpec.MachineAllocation
|
||||
146, // 35: specs.MachineStatusSnapshotSpec.machine_status:type_name -> machine.MachineStatusEvent
|
||||
147, // 35: specs.MachineStatusSnapshotSpec.machine_status:type_name -> machine.MachineStatusEvent
|
||||
13, // 36: specs.MachineStatusSnapshotSpec.power_stage:type_name -> specs.MachineStatusSnapshotSpec.PowerStage
|
||||
128, // 37: specs.ControlPlaneStatusSpec.conditions:type_name -> specs.ControlPlaneStatusSpec.Condition
|
||||
129, // 38: specs.KubernetesStatusSpec.nodes:type_name -> specs.KubernetesStatusSpec.NodeStatus
|
||||
@ -9809,9 +9822,9 @@ var file_omni_specs_omni_proto_depIdxs = []int32{
|
||||
73, // 43: specs.OngoingTaskSpec.destroy:type_name -> specs.DestroyStatusSpec
|
||||
80, // 44: specs.FeaturesConfigSpec.etcd_backup_settings:type_name -> specs.EtcdBackupSettings
|
||||
79, // 45: specs.FeaturesConfigSpec.user_pilot_settings:type_name -> specs.UserPilotSettings
|
||||
144, // 46: specs.EtcdBackupSettings.tick_interval:type_name -> google.protobuf.Duration
|
||||
144, // 47: specs.EtcdBackupSettings.min_interval:type_name -> google.protobuf.Duration
|
||||
144, // 48: specs.EtcdBackupSettings.max_interval:type_name -> google.protobuf.Duration
|
||||
145, // 46: specs.EtcdBackupSettings.tick_interval:type_name -> google.protobuf.Duration
|
||||
145, // 47: specs.EtcdBackupSettings.min_interval:type_name -> google.protobuf.Duration
|
||||
145, // 48: specs.EtcdBackupSettings.max_interval:type_name -> google.protobuf.Duration
|
||||
132, // 49: specs.MachineClassSpec.auto_provision:type_name -> specs.MachineClassSpec.Provision
|
||||
133, // 50: specs.MachineConfigGenOptionsSpec.install_image:type_name -> specs.MachineConfigGenOptionsSpec.InstallImage
|
||||
134, // 51: specs.KubernetesUsageSpec.cpu:type_name -> specs.KubernetesUsageSpec.Quantity
|
||||
@ -9822,38 +9835,39 @@ var file_omni_specs_omni_proto_depIdxs = []int32{
|
||||
137, // 56: specs.TalosExtensionsSpec.items:type_name -> specs.TalosExtensionsSpec.Info
|
||||
17, // 57: specs.ExtensionsConfigurationStatusSpec.phase:type_name -> specs.ExtensionsConfigurationStatusSpec.Phase
|
||||
138, // 58: specs.MachineExtensionsStatusSpec.extensions:type_name -> specs.MachineExtensionsStatusSpec.Item
|
||||
139, // 59: specs.ClusterStatusMetricsSpec.phases:type_name -> specs.ClusterStatusMetricsSpec.PhasesEntry
|
||||
25, // 60: specs.MachineRequestSetSpec.meta_values:type_name -> specs.MetaValue
|
||||
3, // 61: specs.MachineRequestSetSpec.grpc_tunnel:type_name -> specs.GrpcTunnelMode
|
||||
140, // 62: specs.ClusterDiagnosticsSpec.nodes:type_name -> specs.ClusterDiagnosticsSpec.Node
|
||||
19, // 63: specs.ClusterMachineRequestStatusSpec.stage:type_name -> specs.ClusterMachineRequestStatusSpec.Stage
|
||||
21, // 64: specs.InfraMachineConfigSpec.power_state:type_name -> specs.InfraMachineConfigSpec.MachinePowerState
|
||||
20, // 65: specs.InfraMachineConfigSpec.acceptance_status:type_name -> specs.InfraMachineConfigSpec.AcceptanceStatus
|
||||
141, // 66: specs.InfraMachineBMCConfigSpec.ipmi:type_name -> specs.InfraMachineBMCConfigSpec.IPMI
|
||||
142, // 67: specs.InfraMachineBMCConfigSpec.api:type_name -> specs.InfraMachineBMCConfigSpec.API
|
||||
143, // 68: specs.InfraProviderCombinedStatusSpec.health:type_name -> specs.InfraProviderCombinedStatusSpec.Health
|
||||
117, // 69: specs.MachineStatusSpec.HardwareStatus.processors:type_name -> specs.MachineStatusSpec.HardwareStatus.Processor
|
||||
118, // 70: specs.MachineStatusSpec.HardwareStatus.memory_modules:type_name -> specs.MachineStatusSpec.HardwareStatus.MemoryModule
|
||||
119, // 71: specs.MachineStatusSpec.HardwareStatus.blockdevices:type_name -> specs.MachineStatusSpec.HardwareStatus.BlockDevice
|
||||
120, // 72: specs.MachineStatusSpec.NetworkStatus.network_links:type_name -> specs.MachineStatusSpec.NetworkStatus.NetworkLinkStatus
|
||||
24, // 73: specs.MachineStatusSpec.Schematic.overlay:type_name -> specs.Overlay
|
||||
25, // 74: specs.MachineStatusSpec.Schematic.meta_values:type_name -> specs.MetaValue
|
||||
10, // 75: specs.MachineSetSpec.MachineClass.allocation_type:type_name -> specs.MachineSetSpec.MachineClass.Type
|
||||
11, // 76: specs.MachineSetSpec.MachineAllocation.allocation_type:type_name -> specs.MachineSetSpec.MachineAllocation.Type
|
||||
126, // 77: specs.MachineSetSpec.UpdateStrategyConfig.rolling:type_name -> specs.MachineSetSpec.RollingUpdateStrategyConfig
|
||||
2, // 78: specs.ControlPlaneStatusSpec.Condition.type:type_name -> specs.ConditionType
|
||||
14, // 79: specs.ControlPlaneStatusSpec.Condition.status:type_name -> specs.ControlPlaneStatusSpec.Condition.Status
|
||||
15, // 80: specs.ControlPlaneStatusSpec.Condition.severity:type_name -> specs.ControlPlaneStatusSpec.Condition.Severity
|
||||
130, // 81: specs.KubernetesStatusSpec.NodeStaticPods.static_pods:type_name -> specs.KubernetesStatusSpec.StaticPodStatus
|
||||
25, // 82: specs.MachineClassSpec.Provision.meta_values:type_name -> specs.MetaValue
|
||||
3, // 83: specs.MachineClassSpec.Provision.grpc_tunnel:type_name -> specs.GrpcTunnelMode
|
||||
23, // 84: specs.MachineConfigGenOptionsSpec.InstallImage.security_state:type_name -> specs.SecurityState
|
||||
18, // 85: specs.MachineExtensionsStatusSpec.Item.phase:type_name -> specs.MachineExtensionsStatusSpec.Item.Phase
|
||||
86, // [86:86] is the sub-list for method output_type
|
||||
86, // [86:86] is the sub-list for method input_type
|
||||
86, // [86:86] is the sub-list for extension type_name
|
||||
86, // [86:86] is the sub-list for extension extendee
|
||||
0, // [0:86] is the sub-list for field type_name
|
||||
139, // 59: specs.MachineStatusMetricsSpec.versions_map:type_name -> specs.MachineStatusMetricsSpec.VersionsMapEntry
|
||||
140, // 60: specs.ClusterStatusMetricsSpec.phases:type_name -> specs.ClusterStatusMetricsSpec.PhasesEntry
|
||||
25, // 61: specs.MachineRequestSetSpec.meta_values:type_name -> specs.MetaValue
|
||||
3, // 62: specs.MachineRequestSetSpec.grpc_tunnel:type_name -> specs.GrpcTunnelMode
|
||||
141, // 63: specs.ClusterDiagnosticsSpec.nodes:type_name -> specs.ClusterDiagnosticsSpec.Node
|
||||
19, // 64: specs.ClusterMachineRequestStatusSpec.stage:type_name -> specs.ClusterMachineRequestStatusSpec.Stage
|
||||
21, // 65: specs.InfraMachineConfigSpec.power_state:type_name -> specs.InfraMachineConfigSpec.MachinePowerState
|
||||
20, // 66: specs.InfraMachineConfigSpec.acceptance_status:type_name -> specs.InfraMachineConfigSpec.AcceptanceStatus
|
||||
142, // 67: specs.InfraMachineBMCConfigSpec.ipmi:type_name -> specs.InfraMachineBMCConfigSpec.IPMI
|
||||
143, // 68: specs.InfraMachineBMCConfigSpec.api:type_name -> specs.InfraMachineBMCConfigSpec.API
|
||||
144, // 69: specs.InfraProviderCombinedStatusSpec.health:type_name -> specs.InfraProviderCombinedStatusSpec.Health
|
||||
117, // 70: specs.MachineStatusSpec.HardwareStatus.processors:type_name -> specs.MachineStatusSpec.HardwareStatus.Processor
|
||||
118, // 71: specs.MachineStatusSpec.HardwareStatus.memory_modules:type_name -> specs.MachineStatusSpec.HardwareStatus.MemoryModule
|
||||
119, // 72: specs.MachineStatusSpec.HardwareStatus.blockdevices:type_name -> specs.MachineStatusSpec.HardwareStatus.BlockDevice
|
||||
120, // 73: specs.MachineStatusSpec.NetworkStatus.network_links:type_name -> specs.MachineStatusSpec.NetworkStatus.NetworkLinkStatus
|
||||
24, // 74: specs.MachineStatusSpec.Schematic.overlay:type_name -> specs.Overlay
|
||||
25, // 75: specs.MachineStatusSpec.Schematic.meta_values:type_name -> specs.MetaValue
|
||||
10, // 76: specs.MachineSetSpec.MachineClass.allocation_type:type_name -> specs.MachineSetSpec.MachineClass.Type
|
||||
11, // 77: specs.MachineSetSpec.MachineAllocation.allocation_type:type_name -> specs.MachineSetSpec.MachineAllocation.Type
|
||||
126, // 78: specs.MachineSetSpec.UpdateStrategyConfig.rolling:type_name -> specs.MachineSetSpec.RollingUpdateStrategyConfig
|
||||
2, // 79: specs.ControlPlaneStatusSpec.Condition.type:type_name -> specs.ConditionType
|
||||
14, // 80: specs.ControlPlaneStatusSpec.Condition.status:type_name -> specs.ControlPlaneStatusSpec.Condition.Status
|
||||
15, // 81: specs.ControlPlaneStatusSpec.Condition.severity:type_name -> specs.ControlPlaneStatusSpec.Condition.Severity
|
||||
130, // 82: specs.KubernetesStatusSpec.NodeStaticPods.static_pods:type_name -> specs.KubernetesStatusSpec.StaticPodStatus
|
||||
25, // 83: specs.MachineClassSpec.Provision.meta_values:type_name -> specs.MetaValue
|
||||
3, // 84: specs.MachineClassSpec.Provision.grpc_tunnel:type_name -> specs.GrpcTunnelMode
|
||||
23, // 85: specs.MachineConfigGenOptionsSpec.InstallImage.security_state:type_name -> specs.SecurityState
|
||||
18, // 86: specs.MachineExtensionsStatusSpec.Item.phase:type_name -> specs.MachineExtensionsStatusSpec.Item.Phase
|
||||
87, // [87:87] is the sub-list for method output_type
|
||||
87, // [87:87] is the sub-list for method input_type
|
||||
87, // [87:87] is the sub-list for extension type_name
|
||||
87, // [87:87] is the sub-list for extension extendee
|
||||
0, // [0:87] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_omni_specs_omni_proto_init() }
|
||||
@ -9872,7 +9886,7 @@ func file_omni_specs_omni_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_omni_specs_omni_proto_rawDesc), len(file_omni_specs_omni_proto_rawDesc)),
|
||||
NumEnums: 22,
|
||||
NumMessages: 122,
|
||||
NumMessages: 123,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@ -1225,6 +1225,8 @@ message MachineStatusMetricsSpec {
|
||||
uint32 connected_machines_count = 2;
|
||||
uint32 allocated_machines_count = 3;
|
||||
uint32 pending_machines_count = 4;
|
||||
|
||||
map<string, int32> versions_map = 5;
|
||||
}
|
||||
|
||||
// ClusterStatusMetricsSpec provides aggregated state of the number of clusters in not ready phase.
|
||||
|
||||
@ -2212,6 +2212,13 @@ func (m *MachineStatusMetricsSpec) CloneVT() *MachineStatusMetricsSpec {
|
||||
r.ConnectedMachinesCount = m.ConnectedMachinesCount
|
||||
r.AllocatedMachinesCount = m.AllocatedMachinesCount
|
||||
r.PendingMachinesCount = m.PendingMachinesCount
|
||||
if rhs := m.VersionsMap; rhs != nil {
|
||||
tmpContainer := make(map[string]int32, len(rhs))
|
||||
for k, v := range rhs {
|
||||
tmpContainer[k] = v
|
||||
}
|
||||
r.VersionsMap = tmpContainer
|
||||
}
|
||||
if len(m.unknownFields) > 0 {
|
||||
r.unknownFields = make([]byte, len(m.unknownFields))
|
||||
copy(r.unknownFields, m.unknownFields)
|
||||
@ -5618,6 +5625,18 @@ func (this *MachineStatusMetricsSpec) EqualVT(that *MachineStatusMetricsSpec) bo
|
||||
if this.PendingMachinesCount != that.PendingMachinesCount {
|
||||
return false
|
||||
}
|
||||
if len(this.VersionsMap) != len(that.VersionsMap) {
|
||||
return false
|
||||
}
|
||||
for i, vx := range this.VersionsMap {
|
||||
vy, ok := that.VersionsMap[i]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if vx != vy {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return string(this.unknownFields) == string(that.unknownFields)
|
||||
}
|
||||
|
||||
@ -12103,6 +12122,23 @@ func (m *MachineStatusMetricsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, err
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.VersionsMap) > 0 {
|
||||
for k := range m.VersionsMap {
|
||||
v := m.VersionsMap[k]
|
||||
baseI := i
|
||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(v))
|
||||
i--
|
||||
dAtA[i] = 0x10
|
||||
i -= len(k)
|
||||
copy(dAtA[i:], k)
|
||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))
|
||||
i--
|
||||
dAtA[i] = 0x2a
|
||||
}
|
||||
}
|
||||
if m.PendingMachinesCount != 0 {
|
||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.PendingMachinesCount))
|
||||
i--
|
||||
@ -15429,6 +15465,14 @@ func (m *MachineStatusMetricsSpec) SizeVT() (n int) {
|
||||
if m.PendingMachinesCount != 0 {
|
||||
n += 1 + protohelpers.SizeOfVarint(uint64(m.PendingMachinesCount))
|
||||
}
|
||||
if len(m.VersionsMap) > 0 {
|
||||
for k, v := range m.VersionsMap {
|
||||
_ = k
|
||||
_ = v
|
||||
mapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + protohelpers.SizeOfVarint(uint64(v))
|
||||
n += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))
|
||||
}
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
@ -30740,6 +30784,119 @@ func (m *MachineStatusMetricsSpec) UnmarshalVT(dAtA []byte) error {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field VersionsMap", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return protohelpers.ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return protohelpers.ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.VersionsMap == nil {
|
||||
m.VersionsMap = make(map[string]int32)
|
||||
}
|
||||
var mapkey string
|
||||
var mapvalue int32
|
||||
for iNdEx < postIndex {
|
||||
entryPreIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
if fieldNum == 1 {
|
||||
var stringLenmapkey uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLenmapkey |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLenmapkey := int(stringLenmapkey)
|
||||
if intStringLenmapkey < 0 {
|
||||
return protohelpers.ErrInvalidLength
|
||||
}
|
||||
postStringIndexmapkey := iNdEx + intStringLenmapkey
|
||||
if postStringIndexmapkey < 0 {
|
||||
return protohelpers.ErrInvalidLength
|
||||
}
|
||||
if postStringIndexmapkey > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
|
||||
iNdEx = postStringIndexmapkey
|
||||
} else if fieldNum == 2 {
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
mapvalue |= int32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iNdEx = entryPreIndex
|
||||
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return protohelpers.ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > postIndex {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
m.VersionsMap[mapkey] = mapvalue
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
|
||||
|
||||
@ -10,7 +10,9 @@ import (
|
||||
"github.com/blang/semver"
|
||||
)
|
||||
|
||||
var minSupportedSecureTokensVersion = semver.MustParse("1.6.0")
|
||||
// MinSupportedSecureTokensVersion is 1.6.0.
|
||||
// Below 1.6.0 Talos doesn't properly report node unique tokens to Omni.
|
||||
var MinSupportedSecureTokensVersion = semver.MustParse("1.6.0")
|
||||
|
||||
// SupportsSecureJoinTokens checks if the Talos version supports secure join tokens.
|
||||
func SupportsSecureJoinTokens(talosVersion string) bool {
|
||||
@ -19,5 +21,5 @@ func SupportsSecureJoinTokens(talosVersion string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
return v.GTE(minSupportedSecureTokensVersion)
|
||||
return v.GTE(MinSupportedSecureTokensVersion)
|
||||
}
|
||||
|
||||
@ -93,6 +93,10 @@ var rootCmd = &cobra.Command{
|
||||
}
|
||||
}()
|
||||
|
||||
if err = config.ValidateState(ctx, state.Default()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if constants.IsDebugBuild {
|
||||
logger.Warn("running debug build")
|
||||
}
|
||||
|
||||
@ -131,14 +131,15 @@ option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
// ) to obtain a formatter capable of generating timestamps in this format.
|
||||
//
|
||||
message Timestamp {
|
||||
// Represents seconds of UTC time since Unix epoch
|
||||
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||
// 9999-12-31T23:59:59Z inclusive.
|
||||
// Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must
|
||||
// be between -315576000000 and 315576000000 inclusive (which corresponds to
|
||||
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z).
|
||||
int64 seconds = 1;
|
||||
|
||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
// second values with fractions must still have non-negative nanos values
|
||||
// that count forward in time. Must be from 0 to 999,999,999
|
||||
// Non-negative fractions of a second at nanosecond resolution. This field is
|
||||
// the nanosecond portion of the duration, not an alternative to seconds.
|
||||
// Negative second values with fractions must still have non-negative nanos
|
||||
// values that count forward in time. Must be between 0 and 999,999,999
|
||||
// inclusive.
|
||||
int32 nanos = 2;
|
||||
}
|
||||
|
||||
@ -807,6 +807,7 @@ export type MachineStatusMetricsSpec = {
|
||||
connected_machines_count?: number
|
||||
allocated_machines_count?: number
|
||||
pending_machines_count?: number
|
||||
versions_map?: {[key: string]: number}
|
||||
}
|
||||
|
||||
export type ClusterStatusMetricsSpec = {
|
||||
|
||||
@ -27,7 +27,7 @@ import (
|
||||
//nolint:govet
|
||||
type MachineStatusMetricsController struct {
|
||||
versionsMu sync.Mutex
|
||||
versionsMap map[string]int
|
||||
versionsMap map[string]int32
|
||||
|
||||
metricsOnce sync.Once
|
||||
metricNumMachines prometheus.Gauge
|
||||
@ -120,7 +120,7 @@ func (ctrl *MachineStatusMetricsController) Run(ctx context.Context, r controlle
|
||||
var machines, connectedMachines, allocatedMachines int
|
||||
|
||||
ctrl.versionsMu.Lock()
|
||||
ctrl.versionsMap = map[string]int{}
|
||||
ctrl.versionsMap = map[string]int32{}
|
||||
|
||||
for ms := range list.All() {
|
||||
machines++
|
||||
@ -149,6 +149,7 @@ func (ctrl *MachineStatusMetricsController) Run(ctx context.Context, r controlle
|
||||
res.TypedSpec().Value.RegisteredMachinesCount = uint32(machines)
|
||||
res.TypedSpec().Value.AllocatedMachinesCount = uint32(allocatedMachines)
|
||||
res.TypedSpec().Value.PendingMachinesCount = uint32(pendingMachines)
|
||||
res.TypedSpec().Value.VersionsMap = ctrl.versionsMap
|
||||
|
||||
return nil
|
||||
},
|
||||
|
||||
@ -8,6 +8,7 @@ package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -16,6 +17,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/state"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/siderolabs/gen/xyaml"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/merge"
|
||||
@ -27,6 +29,7 @@ import (
|
||||
consts "github.com/siderolabs/omni/client/pkg/constants"
|
||||
"github.com/siderolabs/omni/client/pkg/omni/resources/common"
|
||||
"github.com/siderolabs/omni/internal/pkg/auth/role"
|
||||
"github.com/siderolabs/omni/internal/pkg/config/validations"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -271,6 +274,18 @@ type Params struct {
|
||||
Features Features `yaml:"features"`
|
||||
}
|
||||
|
||||
// ValidateState validate Omni params against the current state of Omni instance.
|
||||
// Add any hooks that would need to validate the config against the state here.
|
||||
func (p *Params) ValidateState(ctx context.Context, st state.State) error {
|
||||
if p.Services.Siderolink.JoinTokensMode == JoinTokensModeStrict {
|
||||
if err := validations.EnsureAllMachinesSupportStrictTokens(ctx, st); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate Omni params.
|
||||
func (p *Params) Validate() error {
|
||||
validate := validator.New(validator.WithRequiredStructEnabled())
|
||||
|
||||
@ -7,12 +7,21 @@
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
"github.com/cosi-project/runtime/pkg/state"
|
||||
"github.com/cosi-project/runtime/pkg/state/impl/inmem"
|
||||
"github.com/cosi-project/runtime/pkg/state/impl/namespaced"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap/zaptest"
|
||||
|
||||
"github.com/siderolabs/omni/client/pkg/omni/resources"
|
||||
"github.com/siderolabs/omni/client/pkg/omni/resources/omni"
|
||||
"github.com/siderolabs/omni/internal/pkg/config"
|
||||
)
|
||||
|
||||
@ -61,6 +70,39 @@ func TestMergeConfig(t *testing.T) {
|
||||
require.True(t, cfg.Services.EmbeddedDiscoveryService.Enabled)
|
||||
}
|
||||
|
||||
func TestValidateStateConfig(t *testing.T) {
|
||||
state := state.WrapCore(namespaced.NewState(inmem.Build))
|
||||
|
||||
cfg, err := config.FromBytes(configFull)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx, cancel := context.WithTimeout(t.Context(), time.Second*5)
|
||||
defer cancel()
|
||||
|
||||
// no machines
|
||||
|
||||
assert.NoError(t, cfg.ValidateState(ctx, state))
|
||||
|
||||
// fail with machines below 1.6, pass with above 1.6
|
||||
|
||||
machine := omni.NewMachineStatus(resources.DefaultNamespace, "1")
|
||||
machine.TypedSpec().Value.TalosVersion = "v1.5.5"
|
||||
|
||||
require.NoError(t, state.Create(ctx, machine))
|
||||
|
||||
assert.Error(t, cfg.ValidateState(ctx, state))
|
||||
|
||||
_, err = safe.StateUpdateWithConflicts(ctx, state, machine.Metadata(), func(res *omni.MachineStatus) error {
|
||||
res.TypedSpec().Value.TalosVersion = "v1.6.0"
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NoError(t, cfg.ValidateState(ctx, state))
|
||||
}
|
||||
|
||||
func TestValidateConfig(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
|
||||
73
internal/pkg/config/validations/join_token_strict.go
Normal file
73
internal/pkg/config/validations/join_token_strict.go
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2025 Sidero Labs, Inc.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the LICENSE file.
|
||||
|
||||
package validations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
"github.com/cosi-project/runtime/pkg/state"
|
||||
"github.com/gertd/go-pluralize"
|
||||
|
||||
"github.com/siderolabs/omni/client/pkg/omni/resources/omni"
|
||||
"github.com/siderolabs/omni/client/pkg/siderolink"
|
||||
)
|
||||
|
||||
// EnsureAllMachinesSupportStrictTokens makes sure that Omni state doesn't have any machines running Talos
|
||||
// below 1.6 and strict tokens mode is enabled.
|
||||
func EnsureAllMachinesSupportStrictTokens(ctx context.Context, st state.State) error {
|
||||
count, err := getMachinesBelowTalosVersion(ctx, st, siderolink.MinSupportedSecureTokensVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("detected %s running Talos version below 1.6. 'strict' join token is not supported on the instance\n"+
|
||||
"Please upgrade the machines\n"+
|
||||
"Or change '--join-tokens-mode' flag to 'legacyAllowed'", pluralize.NewClient().Pluralize("machine", int(count), true))
|
||||
}
|
||||
|
||||
func getMachinesBelowTalosVersion(ctx context.Context, st state.State, belowVersion semver.Version) (int32, error) {
|
||||
statuses, err := safe.ReaderListAll[*omni.MachineStatus](ctx, st)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
versions := map[string]int32{}
|
||||
|
||||
for status := range statuses.All() {
|
||||
if status.TypedSpec().Value.TalosVersion == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
versions[status.TypedSpec().Value.TalosVersion]++
|
||||
}
|
||||
|
||||
if len(versions) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var count int32
|
||||
|
||||
for version, c := range versions {
|
||||
v, err := semver.ParseTolerant(strings.TrimLeft(version, "v"))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if v.LT(belowVersion) {
|
||||
count += c
|
||||
}
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
7
internal/pkg/config/validations/validations.go
Normal file
7
internal/pkg/config/validations/validations.go
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright (c) 2025 Sidero Labs, Inc.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the LICENSE file.
|
||||
|
||||
// Package validations contains config validations which run against the existing Omni state.
|
||||
package validations
|
||||
Loading…
x
Reference in New Issue
Block a user