kvm: Unbreak minikube on Fedora/RHEL

Since #20852 minikube is broken on Fedora/RHEL. We add console.log
(~/.minikube/machines/NAME/console.log) for dumping the console logs
during startup. Libvirt is blocked by selinux policy:

    $ sudo ausearch -m AVC --start today
    ...
    ----
    time->Sat Sep 13 22:14:10 2025
    type=AVC msg=audit(1757790850.921:4801): avc:  denied  { open } for  pid=215452 comm="virtlogd" path="/home/nsoffer/.minikube/machines/minikube/console.log" dev="vda3" ino=197349579 scontext=system_u:system_r:virtlogd_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=1
    ----

Having better logs in the kvm driver can be helpful but it cannot break
basic functionality. Remove the code to create the log file and dump the
logs.

This is a manual revert of commit
2b81ce24e3. We cannot do a clean revert
since all commits in #20852 were squashed during merge.

Tested using:

    $ make out/docker-machine-driver-kvm2

    $ cp out/docker-machine-driver-kvm2 ~/.minikube/bin/

    $ out/minikube start --driver kvm
    😄  minikube v1.37.0 on Fedora 42 (kvm/amd64)
      Using the kvm2 driver based on user configuration
    👍  Starting "minikube" primary control-plane node in "minikube" cluster
    🔥  Creating kvm2 VM (CPUs=2, Memory=6144MB, Disk=20000MB) ...
    🐳  Preparing Kubernetes v1.34.0 on Docker 28.4.0 ...
    🔗  Configuring bridge CNI (Container Networking Interface) ...
    🔎  Verifying Kubernetes components...
	▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
    🌟  Enabled addons: storage-provisioner, default-storageclass

      /usr/local/bin/kubectl is version 1.32.1, which may have incompatibilities with Kubernetes 1.34.0.
	▪ Want kubectl v1.34.0? Try 'minikube kubectl -- get pods -A'
    🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
pull/21550/head
Nir Soffer 2025-09-14 14:40:53 +03:00
parent 574f958887
commit 0aba0a8e31
3 changed files with 1 additions and 54 deletions

View File

@ -70,14 +70,7 @@ func closeDomain(dom *libvirt.Domain, conn *libvirt.Connect) error {
func (d *Driver) defineDomain() (*libvirt.Domain, error) {
tmpl := template.Must(template.New("domain").Parse(domainTmpl))
var domainXML bytes.Buffer
dlog := struct {
Driver
ConsoleLogPath string
}{
Driver: *d,
ConsoleLogPath: consoleLogPath(*d),
}
if err := tmpl.Execute(&domainXML, dlog); err != nil {
if err := tmpl.Execute(&domainXML, d); err != nil {
return nil, errors.Wrap(err, "executing domain xml")
}
conn, err := getConnection(d.ConnectionURI)

View File

@ -55,7 +55,6 @@ const domainTmpl = `
<source file='{{.DiskPath}}'/>
<target dev='hda' bus='virtio'/>
</disk>
<controller type='virtio-serial'/>
<interface type='network'>
<source network='{{.PrivateNetwork}}'/>
<model type='virtio'/>
@ -66,14 +65,10 @@ const domainTmpl = `
</interface>
<serial type='pty'>
<target port='0'/>
<log file='{{.ConsoleLogPath}}' append='on'/>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<console type='pty'>
<target type="virtio" port="1"/>
</console>
<rng model='virtio'>
<backend model='random'>/dev/random</backend>
</rng>

View File

@ -314,24 +314,6 @@ func (d *Driver) Start() error {
log.Debugf("starting domain XML:\n%s", domXML)
}
// libvirt/qemu creates a console log file owned by root:root and permissions 0600,
// so we pre-create it (and close it immediately), just to be able to read it later
logPath := consoleLogPath(*d)
f, err := os.Create(logPath)
if err != nil {
log.Debugf("failed to create console log file %q: %v", logPath, err)
} else {
f.Close()
}
// ensure console log file is cleaned up
defer func() {
if _, err := os.Stat(logPath); err == nil {
if err := os.Remove(logPath); err != nil {
log.Debugf("failed removing console log file %q: %v", logPath, err)
}
}
}()
if err := dom.Create(); err != nil {
return errors.Wrap(err, "creating domain")
}
@ -355,12 +337,6 @@ func (d *Driver) Start() error {
return nil
}
// consoleLogPath returns the path to the console log file for the given machine name.
func consoleLogPath(d Driver) string {
// return fmt.Sprintf("%s-console.log", machineName)
return d.ResolveStorePath("console.log")
}
// waitForDomainState waits maxTime for the domain to reach a target state.
func (d *Driver) waitForDomainState(targetState state.State, maxTime time.Duration) error {
query := func() error {
@ -377,27 +353,11 @@ func (d *Driver) waitForDomainState(targetState state.State, maxTime time.Durati
return fmt.Errorf("last domain state: %q", currentState.String())
}
if err := retry.Local(query, maxTime); err != nil {
dumpConsoleLogs(consoleLogPath(*d))
return fmt.Errorf("timed out waiting %v for domain to reach %q state: %w", maxTime, targetState.String(), err)
}
return nil
}
// dumpConsoleLogs prints out the console log.
func dumpConsoleLogs(logPath string) {
if _, err := os.Stat(logPath); err != nil {
log.Debugf("failed checking console log file %q: %v", logPath, err)
return
}
data, err := os.ReadFile(logPath)
if err != nil {
log.Debugf("failed dumping console log file %q: %v", logPath, err)
return
}
log.Debugf("console log:\n%s", data)
}
// waitForStaticIP waits for IP address of domain that has been created & starting and then makes that IP static.
func (d *Driver) waitForStaticIP(conn *libvirt.Connect, maxTime time.Duration) error {
query := func() error {
@ -416,7 +376,6 @@ func (d *Driver) waitForStaticIP(conn *libvirt.Connect, maxTime time.Duration) e
return nil
}
if err := retry.Local(query, maxTime); err != nil {
dumpConsoleLogs(consoleLogPath(*d))
return fmt.Errorf("domain %s didn't return IP after %v", d.MachineName, maxTime)
}