kvm2 driver: be more robust with creating of the network, don't delete the network if it is in use

pull/3148/head
Marcus Heese 2018-08-10 17:40:27 -07:00
parent b35e908dec
commit 34ee59192b
No known key found for this signature in database
GPG Key ID: D4FDE2903B680FF9
2 changed files with 124 additions and 10 deletions

View File

@ -215,8 +215,17 @@ func (d *Driver) Restart() error {
}
func (d *Driver) Start() error {
// if somebody/something deleted the network in the meantime,
// we might need to recreate it. It's (nearly) a noop if the network exists.
log.Info("Creating network...")
err := d.createNetwork()
if err != nil {
return errors.Wrap(err, "creating network")
}
// this call ensures that all networks are active
log.Info("Ensuring networks are active...")
err := d.ensureNetwork()
err = d.ensureNetwork()
if err != nil {
return errors.Wrap(err, "ensuring active networks")
}
@ -358,18 +367,16 @@ func (d *Driver) Remove() error {
}
defer conn.Close()
//Tear down network and disk if they exist
log.Debug("Checking if the network needs to be deleted")
network, err := conn.LookupNetworkByName(d.PrivateNetwork)
// Tear down network if it exists and is not in use by another minikube instance
log.Debug("Trying to delete the networks (if possible)")
err = d.deleteNetwork()
if err != nil {
log.Warn("Network %s does not exist, nothing to clean up...", d.PrivateNetwork)
}
if network != nil {
log.Infof("Network %s exists, removing...", d.PrivateNetwork)
network.Destroy()
network.Undefine()
log.Warnf("Deleting of networks failed: %s", err.Error())
} else {
log.Info("Successfully deleted networks")
}
// Tear down the domain now
log.Debug("Checking if the domain needs to be deleted")
dom, err := conn.LookupDomainByName(d.MachineName)
if err != nil {

View File

@ -19,6 +19,7 @@ package kvm
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io/ioutil"
"strings"
@ -141,6 +142,111 @@ func (d *Driver) createNetwork() error {
return nil
}
func (d *Driver) deleteNetwork() error {
type source struct {
//XMLName xml.Name `xml:"source"`
Network string `xml:"network,attr"`
}
type iface struct {
//XMLName xml.Name `xml:"interface"`
Source source `xml:"source"`
}
type result struct {
//XMLName xml.Name `xml:"domain"`
Name string `xml:"name"`
Interfaces []iface `xml:"devices>interface"`
}
conn, err := getConnection()
if err != nil {
return errors.Wrap(err, "getting libvirt connection")
}
defer conn.Close()
// network: default
// It is assumed that the OS manages this network
// network: private
log.Debugf("Checking if network %s exists...", d.PrivateNetwork)
network, err := conn.LookupNetworkByName(d.PrivateNetwork)
if err != nil {
// TODO: decide if we really wanna throw an error?
return errors.Wrap(err, "network %s does not exist")
}
log.Debugf("Network %s exists", d.PrivateNetwork)
// iterate over every (also turned off) domains, and check if it
// is using the private network. Do *not* delete the network if
// that is the case
log.Debug("Trying to list all domains...")
doms, err := conn.ListAllDomains(0)
if err != nil {
return errors.Wrap(err, "list all domains")
}
log.Debugf("Listed all domains: total of %d domains", len(doms))
// fail if there are 0 domains
if len(doms) == 0 {
return fmt.Errorf("list of domains is 0 lenght")
}
for _, dom := range doms {
// get the name of the domain we iterate over
log.Debug("Trying to get name of domain...")
name, err := dom.GetName()
if err != nil {
return errors.Wrap(err, "failed to get name of a domain")
}
log.Debugf("Got domain name: %s", name)
// skip the domain if it is our own machine
if name == d.MachineName {
log.Debug("Skipping domain as it is us...")
continue
}
// unfortunately, there is no better way to retrieve a list of all defined interfaces
// in domains than getting it from the defined XML of all domains
// NOTE: conn.ListAllInterfaces does not help in this case
log.Debugf("Getting XML for domain %s...", name)
xmlString, err := dom.GetXMLDesc(libvirt.DOMAIN_XML_INACTIVE)
if err != nil {
return errors.Wrapf(err, "failed to get XML of domain '%s'", name)
}
log.Debugf("Got XML for domain %s", name)
v := result{}
err = xml.Unmarshal([]byte(xmlString), &v)
if err != nil {
return errors.Wrapf(err, "failed to unmarshal XML of domain '%s", name)
}
log.Debugf("Unmarshaled XML for domain %s: %#v", name, v)
// iterate over the found interfaces
for _, i := range v.Interfaces {
if i.Source.Network == d.PrivateNetwork {
log.Debugf("domain %s DOES use network %s, aborting...", name, d.PrivateNetwork)
return fmt.Errorf("network still in use at least by domain '%s',", name)
}
log.Debugf("domain %s does not use network %s", name, d.PrivateNetwork)
}
}
// when we reach this point, it means it is safe to delete the network
log.Debugf("Trying to destroy network %s...", d.PrivateNetwork)
err = network.Destroy()
if err != nil {
return errors.Wrap(err, "network destroy")
}
log.Debugf("Trying to undefine network %s...", d.PrivateNetwork)
err = network.Undefine()
if err != nil {
return errors.Wrap(err, "network undefine")
}
return nil
}
func (d *Driver) lookupIP() (string, error) {
conn, err := getConnection()
if err != nil {
@ -159,6 +265,7 @@ func (d *Driver) lookupIP() (string, error) {
return d.lookupIPFromLeasesFile()
}
// TODO: for everything > 1002006, there is direct support in the libvirt-go for handling this
return d.lookupIPFromStatusFile(conn)
}