Skip to content

Commit 7218c9e

Browse files
committed
kvm2 driver: add static ip
1 parent fcc6283 commit 7218c9e

File tree

12 files changed

+318
-268
lines changed

12 files changed

+318
-268
lines changed

Diff for: cmd/minikube/cmd/start_flags.go

+4-19
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ const (
6262
hypervUseExternalSwitch = "hyperv-use-external-switch"
6363
hypervExternalAdapter = "hyperv-external-adapter"
6464
kvmNetwork = "kvm-network"
65-
kvmPrivateNetwork = "kvm-private-network"
6665
kvmQemuURI = "kvm-qemu-uri"
6766
kvmGPU = "kvm-gpu"
6867
kvmHidden = "kvm-hidden"
@@ -162,7 +161,7 @@ func initMinikubeFlags() {
162161
startCmd.Flags().Bool(preload, true, "If set, download tarball of preloaded images if available to improve start time. Defaults to true.")
163162
startCmd.Flags().Bool(deleteOnFailure, false, "If set, delete the current cluster if start fails and try again. Defaults to false.")
164163
startCmd.Flags().Bool(forceSystemd, false, "If set, force the container runtime to use sytemd as cgroup manager. Defaults to false.")
165-
startCmd.Flags().StringP(network, "", "", "network to run minikube with. Only available with the docker/podman drivers. If left empty, minikube will create a new network.")
164+
startCmd.Flags().StringP(network, "", "", "network to run minikube with. Now it is used by docker/podman and KVM drivers. If left empty, minikube will create a new network.")
166165
startCmd.Flags().StringVarP(&outputFormat, "output", "o", "text", "Format to print stdout in. Options include: [text,json]")
167166
startCmd.Flags().StringP(trace, "", "", "Send trace events. Options include: [gcp]")
168167
}
@@ -193,7 +192,6 @@ func initDriverFlags() {
193192

194193
// kvm2
195194
startCmd.Flags().String(kvmNetwork, "default", "The KVM default network name. (kvm2 driver only)")
196-
startCmd.Flags().String(kvmPrivateNetwork, "", "The KVM private network name. (kvm2 driver only) (default: 'mk-<cluster_name>')")
197195
startCmd.Flags().String(kvmQemuURI, "qemu:///system", "The KVM QEMU connection URI. (kvm2 driver only)")
198196
startCmd.Flags().Bool(kvmGPU, false, "Enable experimental NVIDIA GPU support in minikube")
199197
startCmd.Flags().Bool(kvmHidden, false, "Hide the hypervisor signature from the guest in minikube (kvm2 driver only)")
@@ -313,8 +311,8 @@ func generateClusterConfig(cmd *cobra.Command, existing *config.ClusterConfig, k
313311
out.WarningT("With --network-plugin=cni, you will need to provide your own CNI. See --cni flag as a user-friendly alternative")
314312
}
315313

316-
if !driver.IsKIC(drvName) && viper.GetString(network) != "" {
317-
out.WarningT("--network flag is only valid with the docker/podman drivers, it will be ignored")
314+
if !(driver.IsKIC(drvName) || driver.IsKVM(drvName)) && viper.GetString(network) != "" {
315+
out.WarningT("--network flag is only valid with the docker/podman and KVM drivers, it will be ignored")
318316
}
319317

320318
checkNumaCount(k8sVersion)
@@ -344,7 +342,6 @@ func generateClusterConfig(cmd *cobra.Command, existing *config.ClusterConfig, k
344342
HypervUseExternalSwitch: viper.GetBool(hypervUseExternalSwitch),
345343
HypervExternalAdapter: viper.GetString(hypervExternalAdapter),
346344
KVMNetwork: viper.GetString(kvmNetwork),
347-
KVMPrivateNetwork: viper.GetString(kvmPrivateNetwork),
348345
KVMQemuURI: viper.GetString(kvmQemuURI),
349346
KVMGPU: viper.GetBool(kvmGPU),
350347
KVMHidden: viper.GetBool(kvmHidden),
@@ -383,10 +380,6 @@ func generateClusterConfig(cmd *cobra.Command, existing *config.ClusterConfig, k
383380
},
384381
MultiNodeRequested: viper.GetInt(nodes) > 1,
385382
}
386-
// if KVMPrivateNetwork is not user-defined, defaults to "mk-<cluster_name>"
387-
if cc.KVMPrivateNetwork == "" {
388-
cc.KVMPrivateNetwork = fmt.Sprintf("mk-%s", cc.KubernetesConfig.ClusterName)
389-
}
390383
cc.VerifyComponents = interpretWaitFlag(*cmd)
391384
if viper.GetBool(createMount) && driver.IsKIC(drvName) {
392385
cc.ContainerVolumeMounts = []string{viper.GetString(mountString)}
@@ -561,15 +554,7 @@ func updateExistingConfigFromFlags(cmd *cobra.Command, existing *config.ClusterC
561554
}
562555

563556
if cmd.Flags().Changed(kvmNetwork) {
564-
if cc.KVMNetwork != viper.GetString(kvmNetwork) {
565-
out.WarningT("You cannot change the KVM Default Network name for an exiting minikube cluster. Please first delete the cluster.")
566-
}
567-
}
568-
569-
if cmd.Flags().Changed(kvmPrivateNetwork) {
570-
if cc.KVMPrivateNetwork != viper.GetString(kvmPrivateNetwork) {
571-
out.WarningT("You cannot change the KVM Private Network name for an exiting minikube cluster. Please first delete the cluster.")
572-
}
557+
cc.KVMNetwork = viper.GetString(kvmNetwork)
573558
}
574559

575560
if cmd.Flags().Changed(kvmQemuURI) {

Diff for: pkg/drivers/kvm/domain.go

+12-39
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ package kvm
2020

2121
import (
2222
"bytes"
23-
"crypto/rand"
2423
"fmt"
25-
"net"
2624
"text/template"
2725

2826
libvirt "github.com/libvirt/libvirt-go"
@@ -68,12 +66,10 @@ const domainTmpl = `
6866
</disk>
6967
<interface type='network'>
7068
<source network='{{.Network}}'/>
71-
<mac address='{{.MAC}}'/>
7269
<model type='virtio'/>
7370
</interface>
7471
<interface type='network'>
7572
<source network='{{.PrivateNetwork}}'/>
76-
<mac address='{{.PrivateMAC}}'/>
7773
<model type='virtio'/>
7874
</interface>
7975
<serial type='pty'>
@@ -92,25 +88,6 @@ const domainTmpl = `
9288
</domain>
9389
`
9490

95-
func randomMAC() (net.HardwareAddr, error) {
96-
buf := make([]byte, 6)
97-
_, err := rand.Read(buf)
98-
if err != nil {
99-
return nil, err
100-
}
101-
// We unset the first and second least significant bits (LSB) of the MAC
102-
//
103-
// The LSB of the first octet
104-
// 0 for unicast
105-
// 1 for multicast
106-
//
107-
// The second LSB of the first octet
108-
// 0 for universally administered addresses
109-
// 1 for locally administered addresses
110-
buf[0] &= 0xfc
111-
return buf, nil
112-
}
113-
11491
func (d *Driver) getDomain() (*libvirt.Domain, *libvirt.Connect, error) {
11592
conn, err := getConnection(d.ConnectionURI)
11693
if err != nil {
@@ -146,22 +123,6 @@ func closeDomain(dom *libvirt.Domain, conn *libvirt.Connect) error {
146123
}
147124

148125
func (d *Driver) createDomain() (*libvirt.Domain, error) {
149-
// create random MAC addresses first for our NICs
150-
if d.MAC == "" {
151-
mac, err := randomMAC()
152-
if err != nil {
153-
return nil, errors.Wrap(err, "generating mac address")
154-
}
155-
d.MAC = mac.String()
156-
}
157-
158-
if d.PrivateMAC == "" {
159-
mac, err := randomMAC()
160-
if err != nil {
161-
return nil, errors.Wrap(err, "generating mac address")
162-
}
163-
d.PrivateMAC = mac.String()
164-
}
165126
// create the XML for the domain using our domainTmpl template
166127
tmpl := template.Must(template.New("domain").Parse(domainTmpl))
167128
var domainXML bytes.Buffer
@@ -180,5 +141,17 @@ func (d *Driver) createDomain() (*libvirt.Domain, error) {
180141
return nil, errors.Wrapf(err, "error defining domain xml: %s", domainXML.String())
181142
}
182143

144+
// save MAC address
145+
dmac, err := macFromXML(conn, d.MachineName, d.Network)
146+
if err != nil {
147+
return nil, fmt.Errorf("failed saving MAC address: %w", err)
148+
}
149+
d.MAC = dmac
150+
pmac, err := macFromXML(conn, d.MachineName, d.PrivateNetwork)
151+
if err != nil {
152+
return nil, fmt.Errorf("failed saving MAC address: %w", err)
153+
}
154+
d.PrivateMAC = pmac
155+
183156
return dom, nil
184157
}

Diff for: pkg/drivers/kvm/kvm.go

+43-23
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
libvirt "github.com/libvirt/libvirt-go"
3232
"github.com/pkg/errors"
3333
pkgdrivers "k8s.io/minikube/pkg/drivers"
34+
"k8s.io/minikube/pkg/util/retry"
3435
)
3536

3637
// Driver is the machine driver for KVM
@@ -209,12 +210,14 @@ func (d *Driver) GetIP() (string, error) {
209210
if s != state.Running {
210211
return "", errors.New("host is not running")
211212
}
212-
ip, err := d.lookupIP()
213+
214+
conn, err := getConnection(d.ConnectionURI)
213215
if err != nil {
214-
return "", errors.Wrap(err, "getting IP")
216+
return "", errors.Wrap(err, "getting libvirt connection")
215217
}
218+
defer conn.Close()
216219

217-
return ip, nil
220+
return ipFromXML(conn, d.MachineName, d.PrivateNetwork)
218221
}
219222

220223
// GetSSHHostname returns hostname for use with ssh
@@ -272,32 +275,43 @@ func (d *Driver) Start() (err error) {
272275
}
273276

274277
log.Info("Waiting to get IP...")
275-
for i := 0; i <= 40; i++ {
276-
ip, err := d.GetIP()
278+
if err := d.waitForStaticIP(conn); err != nil {
279+
return errors.Wrap(err, "IP not available after waiting")
280+
}
281+
282+
log.Info("Waiting for SSH to be available...")
283+
if err := drivers.WaitForSSH(d); err != nil {
284+
return errors.Wrap(err, "SSH not available after waiting")
285+
}
286+
287+
return nil
288+
}
289+
290+
// waitForStaticIP waits for IP address of domain that has been created & starting and then makes that IP static.
291+
func (d *Driver) waitForStaticIP(conn *libvirt.Connect) error {
292+
query := func() error {
293+
sip, err := ipFromAPI(conn, d.MachineName, d.PrivateNetwork)
277294
if err != nil {
278-
return errors.Wrap(err, "getting ip during machine start")
295+
return fmt.Errorf("failed getting IP during machine start, will retry: %w", err)
279296
}
280-
if ip == "" {
281-
log.Debugf("Waiting for machine to come up %d/%d", i, 40)
282-
time.Sleep(3 * time.Second)
283-
continue
297+
if sip == "" {
298+
return fmt.Errorf("waiting for machine to come up")
284299
}
285300

286-
if ip != "" {
287-
log.Infof("Found IP for machine: %s", ip)
288-
d.IPAddress = ip
289-
break
290-
}
291-
}
301+
log.Infof("Found IP for machine: %s", sip)
302+
d.IPAddress = sip
292303

293-
if d.IPAddress == "" {
294-
return errors.New("machine didn't return an IP after 120 seconds")
304+
return nil
305+
}
306+
if err := retry.Local(query, 1*time.Minute); err != nil {
307+
return fmt.Errorf("machine %s didn't return IP after 1 minute", d.MachineName)
295308
}
296309

297-
log.Info("Waiting for SSH to be available...")
298-
if err := drivers.WaitForSSH(d); err != nil {
299-
d.IPAddress = ""
300-
return errors.Wrap(err, "SSH not available after waiting")
310+
log.Info("Reserving static IP address...")
311+
if err := addStaticIP(conn, d.PrivateNetwork, d.MachineName, d.PrivateMAC, d.IPAddress); err != nil {
312+
log.Warnf("Failed reserving static IP %s for host %s, will continue anyway: %v", d.IPAddress, d.MachineName, err)
313+
} else {
314+
log.Infof("Reserved static IP address: %s", d.IPAddress)
301315
}
302316

303317
return nil
@@ -385,7 +399,6 @@ func ensureDirPermissions(store string) error {
385399

386400
// Stop a host gracefully
387401
func (d *Driver) Stop() (err error) {
388-
d.IPAddress = ""
389402
s, err := d.GetState()
390403
if err != nil {
391404
return errors.Wrap(err, "getting state of VM")
@@ -458,6 +471,13 @@ func (d *Driver) Remove() error {
458471
return errors.Wrap(err, "undefine domain")
459472
}
460473

474+
log.Info("Removing static IP address...")
475+
if err := delStaticIP(conn, d.PrivateNetwork, "", "", d.IPAddress); err != nil {
476+
log.Warnf("failed removing static IP %s for host %s, will continue anyway: %v", d.IPAddress, d.MachineName, err)
477+
} else {
478+
log.Info("Removed static IP address")
479+
}
480+
461481
return nil
462482
}
463483

0 commit comments

Comments
 (0)