Skip to content

Commit d860ddf

Browse files
author
Daniel Hiltgen
committed
Templatize the vm config, and misc hardening
1 parent 6a6844c commit d860ddf

File tree

1 file changed

+90
-54
lines changed

1 file changed

+90
-54
lines changed

kvm.go

Lines changed: 90 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import (
1313
"os"
1414
"path/filepath"
1515
"strings"
16+
"text/template"
1617
"time"
1718

18-
// "github.com/codegangsta/cli"
1919
"github.com/docker/machine/libmachine/drivers"
2020
"github.com/docker/machine/libmachine/log"
2121
"github.com/docker/machine/libmachine/mcnflag"
@@ -32,10 +32,9 @@ const (
3232
dnsmasqLeases = "/var/lib/libvirt/dnsmasq/%s.leases"
3333
dnsmasqStatus = "/var/lib/libvirt/dnsmasq/%s.status"
3434

35-
// TODO - Switch to template based instead of sprintf substitution
36-
domainXML = `<domain type='kvm'>
37-
<name>%s</name> <memory unit='M'>%d</memory>
38-
<vcpu>%d</vcpu>
35+
domainXMLTemplate = `<domain type='kvm'>
36+
<name>{{.MachineName}}</name> <memory unit='M'>{{.Memory}}</memory>
37+
<vcpu>{{.CPU}}</vcpu>
3938
<features><acpi/><apic/><pae/></features>
4039
<os>
4140
<type>hvm</type>
@@ -45,22 +44,22 @@ const (
4544
</os>
4645
<devices>
4746
<disk type='file' device='cdrom'>
48-
<source file='%s'/>
47+
<source file='{{.ISO}}'/>
4948
<target dev='hdc' bus='ide'/>
5049
<readonly/>
5150
</disk>
5251
<disk type='file' device='disk'>
53-
<source file='%s'/>
52+
<source file='{{.DiskPath}}'/>
5453
<target dev='hda' bus='ide'/>
5554
</disk>
5655
<graphics type='vnc' autoport='yes' listen='127.0.0.1'>
5756
<listen type='address' address='127.0.0.1'/>
5857
</graphics>
5958
<interface type='network'>
60-
<source network='%s'/>
59+
<source network='{{.Network}}'/>
6160
</interface>
6261
<interface type='network'>
63-
<source network='%s'/>
62+
<source network='{{.PrivateNetwork}}'/>
6463
</interface>
6564
</devices>
6665
</domain>`
@@ -81,10 +80,12 @@ type Driver struct {
8180
DiskSize int
8281
CPU int
8382
Network string
83+
PrivateNetwork string
8484
ISO string
8585
Boot2DockerURL string
8686
CaCertPath string
8787
PrivateKeyPath string
88+
DiskPath string
8889
connectionString string
8990
conn *libvirt.VirConnection
9091
VM *libvirt.VirDomain
@@ -93,19 +94,6 @@ type Driver struct {
9394

9495
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
9596
return []mcnflag.Flag{
96-
/*
97-
* Can't support this at present due to filesystem assumptions
98-
* If we can figure out how to copy the disk image up
99-
* to the remote system, then we could support remote libvirt
100-
* instances
101-
*/
102-
/*
103-
mcnflag.Flag{
104-
Name: "kvm-connection",
105-
Usage: "The libvirt connection string",
106-
Value: "qemu:///system",
107-
},
108-
*/
10997
mcnflag.Flag{
11098
Name: "kvm-memory",
11199
Usage: "Size of memory for host in MB",
@@ -133,6 +121,12 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
133121
Usage: "The URL of the boot2docker image. Defaults to the latest available version",
134122
Value: "",
135123
},
124+
/* Not yet implemented
125+
mcnflag.Flag{
126+
Name: "kvm-no-share",
127+
Usage: "Disable the mount of your home directory",
128+
},
129+
*/
136130
}
137131
}
138132

@@ -179,10 +173,10 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
179173
d.SwarmMaster = flags.Bool("swarm-master")
180174
d.SwarmHost = flags.String("swarm-host")
181175
d.SwarmDiscovery = flags.String("swarm-discovery")
176+
d.ISO = filepath.Join(d.LocalArtifactPath("."), isoFilename)
182177
d.SSHUser = "docker"
183178
d.SSHPort = 22
184-
d.ISO = filepath.Join(d.LocalArtifactPath("."), isoFilename)
185-
179+
d.DiskPath = filepath.Join(d.LocalArtifactPath("."), fmt.Sprintf("%s.img", d.MachineName))
186180
return nil
187181
}
188182

@@ -196,25 +190,62 @@ func (d *Driver) GetURL() (string, error) {
196190
if ip == "" {
197191
return "", nil
198192
}
199-
return fmt.Sprintf("tcp://%s:2376", ip), nil
193+
return fmt.Sprintf("tcp://%s:2376", ip), nil // TODO - don't hardcode the port!
200194
}
201195

202196
// Create, or verify the private network is properly configured
203197
func (d *Driver) validatePrivateNetwork() error {
204198
log.Debug("Validating private network")
205-
_, err := d.conn.LookupNetworkByName(privateNetworkName)
199+
network, err := d.conn.LookupNetworkByName(d.PrivateNetwork)
206200
if err == nil {
207-
// TODO - validate the proper configuration
201+
xmldoc, err := network.GetXMLDesc(0)
202+
if err != nil {
203+
return err
204+
}
205+
/* XML structure:
206+
<network>
207+
...
208+
<ip address='a.b.c.d' netmask='255.255.255.0'>
209+
<dhcp>
210+
<range start='a.b.c.d' end='w.x.y.z'/>
211+
</dhcp>
212+
*/
213+
type Ip struct {
214+
Address string `xml:"address,attr"`
215+
Netmask string `xml:"netmask,attr"`
216+
}
217+
type Network struct {
218+
Ip Ip `xml:"ip"`
219+
}
220+
221+
var nw Network
222+
err = xml.Unmarshal([]byte(xmldoc), &nw)
223+
if err != nil {
224+
return err
225+
}
226+
227+
if nw.Ip.Address == "" {
228+
return fmt.Errorf("%s network doesn't have DHCP configured properly", d.PrivateNetwork)
229+
}
230+
// Corner case, but might happen...
231+
if active, err := network.IsActive(); !active {
232+
log.Debugf("Reactivating private network: %s", err)
233+
err = network.Create()
234+
if err != nil {
235+
log.Warnf("Failed to Start network: %s", err)
236+
return err
237+
}
238+
}
208239
return nil
209240
}
210241
// TODO - try a couple pre-defined networks and look for conflicts before
211242
// settling on one
212-
xml := fmt.Sprintf(networkXML, privateNetworkName,
243+
xml := fmt.Sprintf(networkXML, d.PrivateNetwork,
213244
"192.168.42.1",
214245
"255.255.255.0",
215246
"192.168.42.2",
216247
"192.168.42.254")
217-
network, err := d.conn.NetworkDefineXML(xml)
248+
network, err = d.conn.NetworkDefineXML(xml)
218249
if err != nil {
219250
log.Errorf("Failed to create private network: %s", err)
220251
return nil
@@ -242,8 +273,8 @@ func (d *Driver) validateNetwork(name string) error {
242273
}
243274

244275
func (d *Driver) PreCreateCheck() error {
245-
// We could look at d.conn.GetCapabilities()
246-
// parse the XML, and look for hypervisors we care about
276+
// TODO We could look at d.conn.GetCapabilities()
277+
// parse the XML, and look for kvm
247278

248279
log.Debug("About to check libvirt version")
249280

@@ -302,10 +333,17 @@ func (d *Driver) Create() error {
302333
}
303334

304335
log.Debugf("Defining VM...")
305-
// TODO Needs love for other tunables users might want to tweak
306-
xml := fmt.Sprintf(domainXML, d.MachineName, d.Memory, d.CPU,
307-
d.ISO, d.diskPath(), d.Network, privateNetworkName)
308-
vm, err := d.conn.DomainDefineXML(xml)
336+
tmpl, err := template.New("domain").Parse(domainXMLTemplate)
337+
if err != nil {
338+
return err
339+
}
340+
var xml bytes.Buffer
341+
err = tmpl.Execute(&xml, d)
342+
if err != nil {
343+
return err
344+
}
345+
346+
vm, err := d.conn.DomainDefineXML(xml.String())
309347
if err != nil {
310348
log.Warnf("Failed to create the VM: %s", err)
311349
return err
@@ -443,17 +481,18 @@ func (d *Driver) getMAC() (string, error) {
443481
if err != nil {
444482
return "", err
445483
}
446-
// XML structure:
447-
// <domain>
448-
// ...
449-
// <devices>
450-
// ...
451-
// <interface type='network'>
452-
// ...
453-
// <mac address='52:54:00:d2:3f:ba'/>
454-
// ...
455-
// </interface>
456-
// ...
484+
/* XML structure:
485+
<domain>
486+
...
487+
<devices>
488+
...
489+
<interface type='network'>
490+
...
491+
<mac address='52:54:00:d2:3f:ba'/>
492+
...
493+
</interface>
494+
...
495+
*/
457496
type Mac struct {
458497
Address string `xml:"address,attr"`
459498
}
@@ -483,7 +522,7 @@ func (d *Driver) getMAC() (string, error) {
483522
}
484523

485524
func (d *Driver) getIPByMACFromLeaseFile(mac string) (string, error) {
486-
leaseFile := fmt.Sprintf(dnsmasqLeases, privateNetworkName)
525+
leaseFile := fmt.Sprintf(dnsmasqLeases, d.PrivateNetwork)
487526
data, err := ioutil.ReadFile(leaseFile)
488527
if err != nil {
489528
log.Debugf("Failed to retrieve dnsmasq leases from %s", leaseFile)
@@ -507,7 +546,7 @@ func (d *Driver) getIPByMACFromLeaseFile(mac string) (string, error) {
507546
}
508547

509548
func (d *Driver) getIPByMacFromSettings(mac string) (string, error) {
510-
network, err := d.conn.LookupNetworkByName(privateNetworkName)
549+
network, err := d.conn.LookupNetworkByName(d.PrivateNetwork)
511550
if err != nil {
512551
log.Warnf("Failed to find network: %s", err)
513552
return "", err
@@ -522,7 +561,7 @@ func (d *Driver) getIPByMacFromSettings(mac string) (string, error) {
522561
type Lease struct {
523562
Ip_address string `json:"ip-address"`
524563
Mac_address string `json:"mac-address"`
525-
/* Other unused fields omitted */
564+
// Other unused fields omitted
526565
}
527566
var s []Lease
528567

@@ -561,10 +600,6 @@ func (d *Driver) publicSSHKeyPath() string {
561600
return d.GetSSHKeyPath() + ".pub"
562601
}
563602

564-
func (d *Driver) diskPath() string {
565-
return filepath.Join(d.LocalArtifactPath("."), fmt.Sprintf("%s.img", d.MachineName))
566-
}
567-
568603
// Make a boot2docker VM disk image.
569604
func (d *Driver) generateDiskImage(size int) error {
570605
log.Debugf("Creating %d MB hard disk image...", size)
@@ -609,7 +644,7 @@ func (d *Driver) generateDiskImage(size int) error {
609644
return err
610645
}
611646
raw := bytes.NewReader(buf.Bytes())
612-
return createDiskImage(d.diskPath(), size, raw)
647+
return createDiskImage(d.DiskPath, size, raw)
613648
}
614649

615650
// createDiskImage makes a disk image at dest with the given size in MB. If r is
@@ -639,5 +674,6 @@ func NewDriver() *Driver {
639674
log.Fatalf("Failed to connect to libvirt: %s", err)
640675
}
641676
d.conn = &conn
677+
d.PrivateNetwork = privateNetworkName
642678
return d
643679
}

0 commit comments

Comments
 (0)