diff --git a/pkg/controller/bootstrap/bootstrap.go b/pkg/controller/bootstrap/bootstrap.go index c614107248..3e2c34a9c3 100644 --- a/pkg/controller/bootstrap/bootstrap.go +++ b/pkg/controller/bootstrap/bootstrap.go @@ -75,6 +75,7 @@ func (b *Bootstrap) Run(destDir string) error { var cconfig *mcfgv1.ControllerConfig var featureGate *apicfgv1.FeatureGate var nodeConfig *apicfgv1.Node + var infraConfig *apicfgv1.Infrastructure var kconfigs []*mcfgv1.KubeletConfig var pools []*mcfgv1.MachineConfigPool var configs []*mcfgv1.MachineConfig @@ -131,6 +132,10 @@ func (b *Bootstrap) Run(destDir string) error { if obj.GetName() == ctrlcommon.ClusterNodeInstanceName { nodeConfig = obj } + case *apicfgv1.Infrastructure: + if obj.GetName() == ctrlcommon.ClusterInfrastructureInstanceName { + infraConfig = obj + } default: glog.Infof("skipping %q [%d] manifest because of unhandled %T", file.Name(), idx+1, obji) } @@ -183,6 +188,14 @@ func (b *Bootstrap) Run(destDir string) error { configs = append(configs, kconfigs...) } + if infraConfig.Status.CPUPartitioning != apicfgv1.CPUPartitioningNone { + cpuPartMCs, err := kubeletconfig.GenerateCPUPartitioningMC() + if err != nil { + return err + } + configs = append(configs, cpuPartMCs...) + } + fpools, gconfigs, err := render.RunBootstrap(pools, configs, cconfig) if err != nil { return err diff --git a/pkg/controller/common/constants.go b/pkg/controller/common/constants.go index aa1fa75961..85daf7ffc1 100644 --- a/pkg/controller/common/constants.go +++ b/pkg/controller/common/constants.go @@ -34,6 +34,9 @@ const ( // ClusterNodeInstanceName is a singleton name for node configuration ClusterNodeInstanceName = "cluster" + // ClusterInfrastructureInstanceName is a singleton name for infrastructure configuration + ClusterInfrastructureInstanceName = "cluster" + // MachineConfigPoolMaster is the MachineConfigPool name given to the master MachineConfigPoolMaster = "master" // MachineConfigPoolWorker is the MachineConfigPool name given to the worker diff --git a/pkg/controller/kubelet-config/helpers.go b/pkg/controller/kubelet-config/helpers.go index c7952eaf0c..72c1b6eb47 100644 --- a/pkg/controller/kubelet-config/helpers.go +++ b/pkg/controller/kubelet-config/helpers.go @@ -383,3 +383,59 @@ func generateKubeletIgnFiles(kubeletConfig *mcfgv1.KubeletConfig, originalKubeCo return kubeletIgnition, logLevelIgnition, autoSizingReservedIgnition, nil } + +func cpuPartitionMC(role string, ignitionConfig ign3types.Config) (*mcfgv1.MachineConfig, error) { + rawIgnition, err := json.Marshal(ignitionConfig) + if err != nil { + return nil, err + } + + mc := &mcfgv1.MachineConfig{ + TypeMeta: metav1.TypeMeta{ + APIVersion: mcfgv1.GroupVersion.String(), + Kind: "MachineConfig", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("01-%s-cpu-partitioning", role), + Labels: map[string]string{ + "machineconfiguration.openshift.io/role": role, + }, + }, + Spec: mcfgv1.MachineConfigSpec{}, + } + mc.Spec.Config = runtime.RawExtension{Raw: rawIgnition} + return mc, nil +} + +func GenerateCPUPartitioningMC() (mc []*mcfgv1.MachineConfig, err error) { + mode := 420 + source := "data:text/plain;charset=utf-8;base64,ewogICJtYW5hZ2VtZW50IjogewogICAgImNwdXNldCI6ICIiCiAgfQp9Cg==" + ignitionConfig := ign3types.Config{ + Ignition: ign3types.Ignition{ + Version: ign3types.MaxVersion.String(), + }, + Storage: ign3types.Storage{ + Files: []ign3types.File{{ + Node: ign3types.Node{ + Path: "/etc/kubernetes/openshift-workload-pinning", + }, + FileEmbedded1: ign3types.FileEmbedded1{ + Contents: ign3types.Resource{ + Source: &source, + }, + Mode: &mode, + }, + }}, + }, + } + masterMC, err := cpuPartitionMC("master", ignitionConfig) + if err != nil { + return nil, err + } + workerMC, err := cpuPartitionMC("worker", ignitionConfig) + if err != nil { + return nil, err + } + mc = append(mc, masterMC, workerMC) + return +} diff --git a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure.crd.yaml b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure.crd.yaml index 7db041fbab..234d4115e3 100644 --- a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure.crd.yaml +++ b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure.crd.yaml @@ -220,6 +220,13 @@ spec: - HighlyAvailable - SingleReplica - External + cpuPartitioning: + description: cpuPartitioning expresses that CPU partitioning is a currently enabled feature in the cluster. + type: string + default: None + enum: + - None + - AllNodes etcdDiscoveryDomain: description: 'etcdDiscoveryDomain is the domain used to fetch the SRV records for discovering etcd servers and clients. For more info: https://github.com/etcd-io/etcd/blob/329be66e8b3f9e2e6af83c123ff89297e49ebd15/Documentation/op-guide/clustering.md#dns-discovery deprecated: as of 4.7, this field is no longer set or honored. It will be removed in a future release.' type: string diff --git a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go index 5cfa463f04..dfe6a77125 100644 --- a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go +++ b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go @@ -101,6 +101,11 @@ type InfrastructureStatus struct { // +kubebuilder:default=HighlyAvailable // +kubebuilder:validation:Enum=HighlyAvailable;SingleReplica InfrastructureTopology TopologyMode `json:"infrastructureTopology"` + + // cpuPartitioning expresses that CPU partitioning is a currently enabled feature in the cluster. + // +kubebuilder:default=None + // +kubebuilder:validation:Enum=None;AllNodes + CPUPartitioning CPUPartitioningMode `json:"cpuPartitioning"` } // TopologyMode defines the topology mode of the control/infra nodes. @@ -123,6 +128,14 @@ const ( ExternalTopologyMode TopologyMode = "External" ) +// CPUPartitioningMode defines the mode for CPU partitioning +type CPUPartitioningMode string + +const ( + CPUPartitioningNone CPUPartitioningMode = "None" + CPUPartitioningAllNodes CPUPartitioningMode = "AllNodes" +) + // PlatformType is a specific supported infrastructure provider. // +kubebuilder:validation:Enum="";AWS;Azure;BareMetal;GCP;Libvirt;OpenStack;None;VSphere;oVirt;IBMCloud;KubeVirt;EquinixMetal;PowerVS;AlibabaCloud;Nutanix type PlatformType string diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go index c8f59db3a7..ddaadaa6bd 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go @@ -1180,6 +1180,7 @@ var map_InfrastructureStatus = map[string]string{ "apiServerInternalURI": "apiServerInternalURL is a valid URI with scheme 'https', address and optionally a port (defaulting to 443). apiServerInternalURL can be used by components like kubelets, to contact the Kubernetes API server using the infrastructure provider rather than Kubernetes networking.", "controlPlaneTopology": "controlPlaneTopology expresses the expectations for operands that normally run on control nodes. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation The 'External' mode indicates that the control plane is hosted externally to the cluster and that its components are not visible within the cluster.", "infrastructureTopology": "infrastructureTopology expresses the expectations for infrastructure services that do not run on control plane nodes, usually indicated by a node selector for a `role` value other than `master`. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation NOTE: External topology mode is not applicable for this field.", + "cpuPartitioning": "cpuPartitioning expresses that CPU partitioning is a currently enabled feature in the cluster.", } func (InfrastructureStatus) SwaggerDoc() map[string]string {