Skip to content

Commit

Permalink
moving node-labeller and cpu plugin from ssp operator into kubevirt
Browse files Browse the repository at this point in the history
This feature labels nodes with host supported cpu models and features.
It runs empty virt-launcher pod which contains info about supported cpus
on the host. Virt-handler then parses all info and labels the node.

Signed-off-by: Karel Simon <[email protected]>
  • Loading branch information
ksimon1 committed Apr 24, 2020
1 parent 07e6e9e commit aaafe7e
Show file tree
Hide file tree
Showing 32 changed files with 1,342 additions and 17 deletions.
9 changes: 9 additions & 0 deletions cmd/virt-handler/virt-handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ func (app *virtHandlerApp) Run() {
cache.Indexers{},
)

nodeLabellerConfigMapSharedInformer := cache.NewSharedIndexInformer(
cache.NewListWatchFromClient(app.virtCli.CoreV1().RESTClient(), "configmaps", app.namespace, fields.OneTermEqualSelector("metadata.name", "kubevirt-cpu-plugin-configmap")),
&k8sv1.ConfigMap{},
(24 * time.Hour),
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
)

// Wire Domain controller
domainSharedInformer, err := virtcache.NewSharedInformer(app.VirtShareDir, int(app.WatchdogTimeoutDuration.Seconds()), recorder, vmSourceSharedInformer.GetStore())
if err != nil {
Expand Down Expand Up @@ -249,6 +256,7 @@ func (app *virtHandlerApp) Run() {
app.VirtPrivateDir,
vmSourceSharedInformer,
vmTargetSharedInformer,
nodeLabellerConfigMapSharedInformer,
domainSharedInformer,
gracefulShutdownInformer,
int(app.WatchdogTimeoutDuration.Seconds()),
Expand All @@ -257,6 +265,7 @@ func (app *virtHandlerApp) Run() {
app.serverTLSConfig,
app.clientTLSConfig,
podIsolationDetector,
app.namespace,
)

consoleHandler := rest.NewConsoleHandler(
Expand Down
1 change: 1 addition & 0 deletions cmd/virt-launcher/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ container_image(
directory = "/usr/bin",
entrypoint = ["/usr/bin/virt-launcher"],
files = [
"node-labeller/node-labeller.sh",
":virt-launcher",
"//cmd/container-disk-v2alpha:container-disk",
],
Expand Down
14 changes: 14 additions & 0 deletions cmd/virt-launcher/node-labeller/node-labeller.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e

if [ ! -e /dev/kvm ]; then
mknod /dev/kvm c 10 $(grep '\\<kvm\\>' /proc/misc | cut -f 1 -d' ')
fi
chmod o+rw /dev/kvm

libvirtd -d

virsh domcapabilities --machine q35 --arch x86_64 --virttype kvm > /var/lib/kubevirt-node-labeller/virsh_domcapabilities.xml

cp -r /usr/share/libvirt/cpu_map /var/lib/kubevirt-node-labeller
15 changes: 15 additions & 0 deletions manifests/generated/operator-csv.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ spec:
- update
- delete
- patch
- apiGroups:
- ""
resources:
- configmaps
verbs:
- patch
- apiGroups:
- batch
resources:
Expand Down Expand Up @@ -506,6 +512,15 @@ spec:
- nodes
verbs:
- patch
- get
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
Expand Down
15 changes: 15 additions & 0 deletions manifests/generated/rbac-operator.authorization.k8s.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ rules:
- update
- delete
- patch
- apiGroups:
- ""
resources:
- configmaps
verbs:
- patch
- apiGroups:
- batch
resources:
Expand Down Expand Up @@ -408,6 +414,15 @@ rules:
- nodes
verbs:
- patch
- get
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
Expand Down
1 change: 1 addition & 0 deletions pkg/virt-handler/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ go_library(
"//pkg/virt-handler/device-manager:go_default_library",
"//pkg/virt-handler/isolation:go_default_library",
"//pkg/virt-handler/migration-proxy:go_default_library",
"//pkg/virt-handler/node-labeller:go_default_library",
"//pkg/virt-launcher/virtwrap/api:go_default_library",
"//pkg/virt-launcher/virtwrap/network:go_default_library",
"//pkg/watchdog:go_default_library",
Expand Down
2 changes: 1 addition & 1 deletion pkg/virt-handler/device-manager/device_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func NewDeviceController(host string, maxDevices int) *DeviceController {
}
}

func (c *DeviceController) nodeHasDevice(devicePath string) bool {
func (c *DeviceController) NodeHasDevice(devicePath string) bool {
_, err := os.Stat(devicePath)
// Since this is a boolean question, any error means "no"
return (err == nil)
Expand Down
8 changes: 4 additions & 4 deletions pkg/virt-handler/device-manager/device_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ var _ = Describe("Device Controller", func() {
It("Should indicate if node has device", func() {
deviceController := NewDeviceController(host, 10)
devicePath := path.Join(workDir, "fake-device")
res := deviceController.nodeHasDevice(devicePath)
res := deviceController.NodeHasDevice(devicePath)
Expect(res).To(BeFalse())

fileObj, err := os.Create(devicePath)
Expect(err).ToNot(HaveOccurred())
fileObj.Close()

res = deviceController.nodeHasDevice(devicePath)
res = deviceController.NodeHasDevice(devicePath)
Expect(res).To(BeTrue())
})
})
Expand Down Expand Up @@ -120,8 +120,8 @@ var _ = Describe("Device Controller", func() {
deviceController.devicePlugins = []GenericDevice{plugin1, plugin2}
go deviceController.Run(stop)

Expect(deviceController.nodeHasDevice(devicePath1)).To(BeFalse())
Expect(deviceController.nodeHasDevice(devicePath2)).To(BeTrue())
Expect(deviceController.NodeHasDevice(devicePath1)).To(BeFalse())
Expect(deviceController.NodeHasDevice(devicePath2)).To(BeTrue())

Eventually(func() int {
return int(atomic.LoadInt32(&plugin1.Starts))
Expand Down
45 changes: 45 additions & 0 deletions pkg/virt-handler/node-labeller/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "go_default_library",
srcs = [
"config.go",
"cpu_plugin.go",
"model.go",
"node_labeller.go",
"test-util.go",
],
importpath = "kubevirt.io/kubevirt/pkg/virt-handler/node-labeller",
visibility = ["//visibility:public"],
deps = [
"//pkg/virt-handler/device-manager:go_default_library",
"//staging/src/kubevirt.io/client-go/kubecli:go_default_library",
"//staging/src/kubevirt.io/client-go/log:go_default_library",
"//vendor/gopkg.in/yaml.v2:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/k8s.io/client-go/util/workqueue:go_default_library",
],
)

go_test(
name = "go_default_test",
srcs = [
"config_test.go",
"cpu_plugin_test.go",
"node_labeller_suite_test.go",
],
embed = [":go_default_library"],
deps = [
"//staging/src/kubevirt.io/client-go/kubecli:go_default_library",
"//vendor/github.com/golang/mock/gomock:go_default_library",
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
],
)
64 changes: 64 additions & 0 deletions pkg/virt-handler/node-labeller/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* This file is part of the KubeVirt project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2020 Red Hat, Inc.
*/

package nodelabeller

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

//Config holds data about obsolete cpus and minimal baseline cpus
type Config struct {
ObsoleteCPUs []string `yaml:"obsoleteCPUs"`
MinCPU string `yaml:"minCPU"`
}

var configPath = "/var/lib/kubevirt-node-labeller/cpu-plugin-configmap.yaml"

//LoadConfig loads config yaml file with obsolete cpus and minimal baseline cpus
func (n *NodeLabeller) loadConfig() (Config, error) {
config := Config{}
cm, err := n.clientset.CoreV1().ConfigMaps(n.namespace).Get("kubevirt-cpu-plugin-configmap", metav1.GetOptions{})
if err != nil {
return config, err
}

if value, ok := cm.Data["cpu-plugin-configmap.yaml"]; ok {
err := writeConfigFile(configPath, value)
if err != nil {
return config, err
}
}
err = getStructureFromYamlFile(configPath, &config)
if err != nil {
return Config{}, err
}

return config, nil
}

//GetObsoleteCPUMap returns map of obsolete cpus
func (c *Config) getObsoleteCPUMap() map[string]bool {
return convertStringSliceToMap(c.ObsoleteCPUs)
}

//GetMinCPU returns minimal baseline cpu. If minimal cpu is not defined,
//it returns for Intel vendor Penryn cpu model, for AMD it returns Opteron_G1.
func (c *Config) getMinCPU() string {
return c.MinCPU
}
82 changes: 82 additions & 0 deletions pkg/virt-handler/node-labeller/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* This file is part of the KubeVirt project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2020 Red Hat, Inc.
*
*/

package nodelabeller

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Node-labeller config", func() {

It("should return obsolete cpus", func() {
var testCases = []struct {
conf Config
result map[string]bool
}{
{
conf: Config{
ObsoleteCPUs: []string{"Conroe", "Haswell", "Penryn"},
},
result: map[string]bool{
"Conroe": true,
"Haswell": true,
"Penryn": true,
},
},
{
conf: Config{
ObsoleteCPUs: []string{},
},
result: map[string]bool{},
},
}
for _, testCase := range testCases {
m := testCase.conf.getObsoleteCPUMap()
Expect(m).To(Equal(testCase.result), "obsolete cpus are not equal")
}
})

It("should return min cpu", func() {
var testCases = []struct {
conf Config
provider string
result string
}{
{
conf: Config{
MinCPU: "Penryn",
},
result: "Penryn",
},
{
conf: Config{
MinCPU: "",
},
result: "",
},
}
for _, testCase := range testCases {
result := testCase.conf.getMinCPU()
Expect(result).To(Equal(testCase.result), "minCPU is not equal")
}
})

})
Loading

0 comments on commit aaafe7e

Please sign in to comment.