Skip to content

Commit

Permalink
Migration of root launcher to nonroot
Browse files Browse the repository at this point in the history
Marking VMI as nonroot before migration will cause
correct pod to render and correct handling on handler level.

Signed-off-by: L. Pivarc <[email protected]>
  • Loading branch information
xpivarc committed Mar 3, 2022
1 parent a78d4b9 commit 25fbfc3
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
11 changes: 11 additions & 0 deletions pkg/virt-controller/watch/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"

"kubevirt.io/kubevirt/pkg/util"
"kubevirt.io/kubevirt/pkg/util/pdbs"
"kubevirt.io/kubevirt/pkg/util/status"

Expand Down Expand Up @@ -1011,6 +1012,16 @@ func (c *MigrationController) sync(key string, migration *virtv1.VirtualMachineI
// will be marked as failed too.
return nil
}
if c.clusterConfig.NonRootEnabled() && util.CanBeNonRoot(vmi) == nil {
if vmi.Status.RuntimeUser != 107 {
patch := fmt.Sprintf(`[{ "op": "replace", "path": "/status/runtimeUser", "value": %s }]`, "107")
vmi, err = c.clientset.VirtualMachineInstance(vmi.Namespace).Patch(vmi.Name, types.JSONPatchType, []byte(patch), &v1.PatchOptions{})
if err != nil {
return fmt.Errorf("failed to mark VMI as nonroot: %v", err)
}
}

}
return c.handleTargetPodCreation(key, migration, vmi, sourcePod)
} else if isPodReady(pod) {
if controller.VMIHasHotplugVolumes(vmi) {
Expand Down
96 changes: 96 additions & 0 deletions tests/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,102 @@ var _ = Describe("[rfe_id:393][crit:high][vendor:[email protected]][level:system
})
})

Context("[Serial] migration to nonroot", func() {

var cleanUp func()
ipProtocol := k8sv1.IPv4Protocol
os := string(cd.ContainerDiskAlpine)
size := "256Mi"

BeforeEach(func() {
if !checks.HasFeature(virtconfig.NonRoot) {
Skip("Test specific to NonRoot featureGate that is not enabled")
}
tests.DisableFeatureGate(virtconfig.NonRoot)
})
AfterEach(func() {
tests.EnableFeatureGate(virtconfig.NonRoot)
if cleanUp != nil {
cleanUp()
}
})

createPVC := func() (nfsPod *k8sv1.Pod, pvName string) {
targetImage, nodeName := tests.CopyAlpineWithNonQEMUPermissions()
cleanUp = tests.DeleteAlpineWithNonQEMUPermissions

By("Starting an NFS POD")
nfsPod = storageframework.InitNFS(targetImage, nodeName)
pvName = fmt.Sprintf("test-nfs%s", rand.String(48))

// create a new PV and PVC (PVs can't be reused)
By("create a new NFS PV and PVC")
nfsIP := libnet.GetPodIpByFamily(nfsPod, ipProtocol)
ExpectWithOffset(1, nfsIP).NotTo(BeEmpty())

tests.CreateNFSPvAndPvc(pvName, util.NamespaceTestDefault, size, nfsIP, os)
return
}

table.DescribeTable("should migrate root implementation to nonroot", func(createVMI func() *v1.VirtualMachineInstance) {
By("Create a VMI that will run root(default)")
vmi := createVMI()

By("Starting the VirtualMachineInstance")
// Resizing takes too long and therefor a warning is thrown
vmi = runVMIAndExpectLaunchIgnoreWarnings(vmi, 240)

By("Checking that the VirtualMachineInstance console has expected output")
Expect(console.LoginToAlpine(vmi)).To(Succeed())

By("Checking that the launcher is running as root")
Expect(tests.GetIdOfLauncher(vmi)).To(Equal("0"))

tests.EnableFeatureGate(virtconfig.NonRoot)

By("Starting new migration and waiting for it to succeed")
migration := tests.NewRandomMigration(vmi.Name, vmi.Namespace)
migrationUID := tests.RunMigrationAndExpectCompletion(virtClient, migration, 340)

By("Verifying Second Migration Succeeeds")
tests.ConfirmVMIPostMigration(virtClient, vmi, migrationUID)

By("Checking that the launcher is running as qemu")
Expect(tests.GetIdOfLauncher(vmi)).To(Equal("107"))

By("Deleting the VMI")
Expect(virtClient.VirtualMachineInstance(vmi.Namespace).Delete(vmi.Name, &metav1.DeleteOptions{})).To(Succeed())

By("Waiting for VMI to disappear")
tests.WaitForVirtualMachineToDisappearWithTimeout(vmi, 240)

},
table.Entry("with simple VMI", func() *v1.VirtualMachineInstance {
return libvmi.NewAlpine()
}),

table.Entry("with DataVolume", func() *v1.VirtualMachineInstance {
nfsPod, pvName := createPVC()

// Create fake DV and new PV&PVC of that name. Otherwise VM can't be created
dv := tests.NewRandomDataVolumeWithPVCSource(util.NamespaceTestDefault, pvName, util.NamespaceTestDefault, k8sv1.ReadWriteMany)
dv.Spec.PVC.Resources.Requests["storage"] = resource.MustParse(size)
_, err := virtClient.CdiClient().CdiV1beta1().DataVolumes(dv.Namespace).Create(context.Background(), dv, metav1.CreateOptions{})
Expect(err).To(BeNil())
tests.CreateNFSPvAndPvc(dv.Name, util.NamespaceTestDefault, size, libnet.GetPodIpByFamily(nfsPod, ipProtocol), os)

return tests.NewRandomVMIWithDataVolume(dv.Name)
}),

table.Entry("with PVC", func() *v1.VirtualMachineInstance {
nfsPod, pvName := createPVC()

tests.CreateNFSPvAndPvc(pvName, util.NamespaceTestDefault, size, libnet.GetPodIpByFamily(nfsPod, ipProtocol), os)

return tests.NewRandomVMIWithPVC(pvName)
}),
)
})
Context("migration security", func() {
Context("[Serial] with TLS disabled", func() {
It("[test_id:6976] should be successfully migrated", func() {
Expand Down

0 comments on commit 25fbfc3

Please sign in to comment.