Skip to content

Commit 0e48caa

Browse files
committed
feat(domain): add fw_cfg_name option
1 parent 7f16e87 commit 0e48caa

File tree

9 files changed

+278
-12
lines changed

9 files changed

+278
-12
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
## Flatcar Linux simple cluster setup
2+
3+
### Requirements
4+
5+
This setup works with the following config:
6+
```shell
7+
$ libvirtd --version
8+
libvirtd (libvirt) 5.5.0
9+
$ terraform version
10+
Terraform v0.12.6
11+
```
12+
13+
### Flatcar Linux
14+
15+
Ths example is strongly inspired by the CoreOS [example](https://github.com/dmacvicar/terraform-provider-libvirt/tree/master/examples/v0.12/coreos).
16+
17+
QEMU-agent is not used, network is configured with static IP to keep things simple.
18+
19+
```shell
20+
$ virsh net-dumpxml --network cluster-net
21+
...
22+
<ip address='192.168.122.1' netmask='255.255.255.0'>
23+
<dhcp>
24+
<range start='192.168.122.100' end='192.168.122.254'/>
25+
<host mac='52:54:00:00:00:a1' name='node-01' ip='192.168.122.101'/>
26+
<host mac='52:54:00:00:00:a2' name='node-02' ip='192.168.122.102'/>
27+
<host mac='52:54:00:00:00:a3' name='node-03' ip='192.168.122.103'/>
28+
</dhcp>
29+
</ip>
30+
...
31+
```
32+
33+
Do not forget to download Flatcar Linux image and to add it the pool of your [choice](https://docs.flatcar-linux.org/os/booting-with-libvirt/#choosing-a-channel).
34+
35+
You can specify the number of hosts by updating:
36+
```hcl
37+
variable "hosts" {
38+
default = 2
39+
}
40+
```
41+
42+
(:warning: you will need to update `units/etcd-member.conf` to add or remove or node to the initial cluster :warning:)
43+
44+
Add you SSH pub key or provide a hashed password.
45+
46+
Finally, `fw_cfg_name` is the "path" where ignition file will be mounted [doc](https://docs.flatcar-linux.org/os/booting-with-libvirt/#creating-the-domain-xml).
47+
48+
```hcl
49+
resource "libvirt_domain" "node" {
50+
...
51+
fw_cfg_name = "opt/org.flatcar-linux/config"
52+
...
53+
}
54+
```
55+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
data "ignition_config" "ignition" {
2+
users = [
3+
data.ignition_user.core.id,
4+
]
5+
6+
files = [
7+
element(data.ignition_file.hostname.*.id, count.index)
8+
]
9+
10+
networkd = [
11+
"${data.ignition_networkd_unit.network-dhcp.id}",
12+
]
13+
14+
systemd = [
15+
"${data.ignition_systemd_unit.etcd-member[count.index].id}",
16+
]
17+
18+
count = var.hosts
19+
}
20+
21+
data "ignition_file" "hostname" {
22+
filesystem = "root"
23+
path = "/etc/hostname"
24+
mode = 420
25+
26+
content {
27+
content = format(var.hostname_format, count.index + 1)
28+
}
29+
30+
count = var.hosts
31+
}
32+
33+
data "ignition_user" "core" {
34+
name = "core"
35+
36+
ssh_authorized_keys = ["ssh-rsa <your-ssh-pub-key>"]
37+
}
38+
39+
data "ignition_networkd_unit" "network-dhcp" {
40+
name = "00-wired.network"
41+
content = "${file("${path.module}/units/00-wired.network")}"
42+
}
43+
44+
data "ignition_systemd_unit" "etcd-member" {
45+
name = "etcd-member.service"
46+
enabled = true
47+
dropin {
48+
content = "${data.template_file.etcd-member[count.index].rendered}"
49+
name = "20-etcd-member.conf"
50+
}
51+
count = var.hosts
52+
}
53+
54+
resource "random_string" "token" {
55+
length = 16
56+
special = false
57+
}
58+
59+
data "template_file" "etcd-member" {
60+
template = "${file("${path.module}/units/20-etcd-member.conf")}"
61+
count = var.hosts
62+
vars = {
63+
node_name = format(var.hostname_format, count.index + 1)
64+
private_ip = format("192.168.122.1%02d", count.index + 1)
65+
cluster_token = random_string.token.result
66+
}
67+
}
68+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
provider "libvirt" {
2+
uri = "qemu:///system"
3+
}
4+
5+
variable "hosts" {
6+
default = 2
7+
}
8+
9+
variable "hostname_format" {
10+
type = string
11+
default = "node-%02d"
12+
}
13+
14+
resource "libvirt_volume" "flatcar-disk" {
15+
name = "flatcar-${format(var.hostname_format, count.index + 1)}.qcow2"
16+
count = var.hosts
17+
base_volume_name = "flatcar_production_qemu_image.img"
18+
pool = "container-linux"
19+
format = "qcow2"
20+
}
21+
22+
resource "libvirt_ignition" "ignition" {
23+
name = "${format(var.hostname_format, count.index + 1)}-ignition"
24+
pool = "container-linux"
25+
count = var.hosts
26+
content = element(data.ignition_config.ignition.*.rendered, count.index)
27+
}
28+
29+
resource "libvirt_domain" "node" {
30+
count = var.hosts
31+
name = format(var.hostname_format, count.index + 1)
32+
vcpu = 1
33+
memory = 2048
34+
35+
disk {
36+
volume_id = element(libvirt_volume.flatcar-disk.*.id, count.index)
37+
}
38+
39+
network_interface {
40+
network_name = "default"
41+
mac = "52:54:00:00:00:a${count.index + 1}"
42+
wait_for_lease = true
43+
}
44+
45+
coreos_ignition = element(libvirt_ignition.ignition.*.id, count.index)
46+
fw_cfg_name = "opt/org.flatcar-linux/config"
47+
}
48+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[Math]
2+
Name=eth0
3+
4+
[Network]
5+
DHCP=ipv4
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[Service]
2+
Environment="ETCD_IMAGE_TAG=v3.2.0"
3+
Environment="ETCD_DATA_DIR=/var/lib/etcd"
4+
Environment="ETCD_OPTS=--name ${node_name} \
5+
--listen-client-urls http://0.0.0.0:2379 \
6+
--advertise-client-urls http://${private_ip}:2379 \
7+
--listen-peer-urls http://0.0.0.0:2380 \
8+
--initial-advertise-peer-urls http://${private_ip}:2380 \
9+
--initial-cluster node-01=http://192.168.122.101:2380,node-02=http://192.168.122.102:2380 \
10+
--initial-cluster-token ${cluster_token} \
11+
--initial-cluster-state new"

libvirt/domain.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -236,16 +236,20 @@ func setCoreOSIgnition(d *schema.ResourceData, domainDef *libvirtxml.Domain) err
236236
if err != nil {
237237
return err
238238
}
239-
240-
domainDef.QEMUCommandline = &libvirtxml.DomainQEMUCommandline{
241-
Args: []libvirtxml.DomainQEMUCommandlineArg{
242-
{
243-
Value: "-fw_cfg",
244-
},
245-
{
246-
Value: fmt.Sprintf("name=opt/com.coreos/config,file=%s", ignitionKey),
239+
// `fw_cfg_name` stands for firmware config is defined by a key and a value
240+
// credits for this cryptic name: https://github.com/qemu/qemu/commit/81b2b81062612ebeac4cd5333a3b15c7d79a5a3d
241+
if fwCfg, ok := d.GetOk("fw_cfg_name"); ok {
242+
243+
domainDef.QEMUCommandline = &libvirtxml.DomainQEMUCommandline{
244+
Args: []libvirtxml.DomainQEMUCommandlineArg{
245+
{
246+
Value: "-fw_cfg",
247+
},
248+
{
249+
Value: fmt.Sprintf("name=%s,file=%s", fwCfg, ignitionKey),
250+
},
247251
},
248-
},
252+
}
249253
}
250254
}
251255

libvirt/resource_libvirt_domain.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ func resourceLibvirtDomain() *schema.Resource {
105105
ForceNew: true,
106106
Default: "",
107107
},
108+
"fw_cfg_name": {
109+
Type: schema.TypeString,
110+
Optional: true,
111+
ForceNew: true,
112+
Default: "opt/com.coreos/config",
113+
},
108114
"filesystem": {
109115
Type: schema.TypeList,
110116
Optional: true,

libvirt/resource_libvirt_domain_test.go

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ func TestAccLibvirtDomain_IgnitionObject(t *testing.T) {
758758
Check: resource.ComposeTestCheckFunc(
759759
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
760760
testAccCheckIgnitionVolumeExists("libvirt_ignition."+randomIgnitionName, &volume),
761-
testAccCheckIgnitionXML(&domain, &volume),
761+
testAccCheckIgnitionXML(&domain, &volume, "opt/com.coreos/config"),
762762
),
763763
},
764764
},
@@ -996,7 +996,7 @@ func testAccCheckLibvirtDomainExists(name string, domain *libvirt.Domain) resour
996996
}
997997
}
998998

999-
func testAccCheckIgnitionXML(domain *libvirt.Domain, volume *libvirt.StorageVol) resource.TestCheckFunc {
999+
func testAccCheckIgnitionXML(domain *libvirt.Domain, volume *libvirt.StorageVol, fwCfg string) resource.TestCheckFunc {
10001000
return func(s *terraform.State) error {
10011001

10021002
domainDef, err := getXMLDomainDefFromLibvirt(domain)
@@ -1008,7 +1008,7 @@ func testAccCheckIgnitionXML(domain *libvirt.Domain, volume *libvirt.StorageVol)
10081008
if err != nil {
10091009
return err
10101010
}
1011-
ignStr := fmt.Sprintf("name=opt/com.coreos/config,file=%s", ignitionKey)
1011+
ignStr := fmt.Sprintf("name=%s,file=%s", fwCfg, ignitionKey)
10121012

10131013
cmdLine := domainDef.QEMUCommandline.Args
10141014
for i, cmd := range cmdLine {
@@ -1767,3 +1767,71 @@ func testAccCheckLibvirtDomainDestroy(s *terraform.State) error {
17671767
}
17681768
return nil
17691769
}
1770+
1771+
func TestAccLibvirtDomain_FwCfgName(t *testing.T) {
1772+
/*
1773+
Ignition file is mounted of domain through `fw_cfg`.
1774+
`fw_cfg` stands for firmware config is defined by a key and a value.
1775+
The key is generally prefixed by `opt/`
1776+
The value can be a file
1777+
1778+
Finally the file will be mounted on /sys/firmware/qemu_fw_cfg/by_name/<key-name>
1779+
1780+
in example: CoreOS will fetch ignition file from /opt/com.coreos/config, but Flatcar Linux will fetch it from /opt/org.flatcar-linux/config
1781+
1782+
We need to test if we can override the key name.
1783+
*/
1784+
var domain libvirt.Domain
1785+
var volume libvirt.StorageVol
1786+
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
1787+
randomFwCfgName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
1788+
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
1789+
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
1790+
randomIgnitionName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
1791+
var config = fmt.Sprintf(`
1792+
data "ignition_systemd_unit" "acceptance-test-systemd" {
1793+
name = "whatever.service"
1794+
content = "[Service]\nType=oneshot\nExecStart=/usr/bin/echo Hello World\n\n[Install]\nWantedBy=multi-user.target"
1795+
}
1796+
1797+
data "ignition_config" "acceptance-test-config-fw-cfg" {
1798+
systemd = [
1799+
"${data.ignition_systemd_unit.acceptance-test-systemd.id}",
1800+
]
1801+
}
1802+
1803+
resource "libvirt_pool" "%s" {
1804+
name = "%s"
1805+
type = "dir"
1806+
path = "%s"
1807+
}
1808+
1809+
resource "libvirt_ignition" "%s" {
1810+
name = "ignition"
1811+
content = "${data.ignition_config.acceptance-test-config-fw-cfg.rendered}"
1812+
pool = "${libvirt_pool.%s.name}"
1813+
}
1814+
1815+
resource "libvirt_domain" "%s" {
1816+
name = "%s"
1817+
coreos_ignition = "${libvirt_ignition.%s.id}"
1818+
fw_cfg_name = "%s"
1819+
}
1820+
`, randomPoolName, randomPoolName, randomPoolPath, randomIgnitionName, randomPoolName, randomDomainName, randomDomainName, randomIgnitionName, randomFwCfgName)
1821+
1822+
resource.Test(t, resource.TestCase{
1823+
PreCheck: func() { testAccPreCheck(t) },
1824+
Providers: testAccProviders,
1825+
CheckDestroy: testAccCheckLibvirtDomainDestroy,
1826+
Steps: []resource.TestStep{
1827+
{
1828+
Config: config,
1829+
Check: resource.ComposeTestCheckFunc(
1830+
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
1831+
testAccCheckIgnitionVolumeExists("libvirt_ignition."+randomIgnitionName, &volume),
1832+
testAccCheckIgnitionXML(&domain, &volume, randomFwCfgName),
1833+
),
1834+
},
1835+
},
1836+
})
1837+
}

website/docs/r/domain.html.markdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ The following arguments are supported:
5050
* `coreos_ignition` - (Optional) The
5151
[libvirt_ignition](/docs/providers/libvirt/r/coreos_ignition.html) resource
5252
that is to be used by the CoreOS domain.
53+
* `fw_cfg_name` - (Optional) The name of the firmware config path where ignition file is stored: default is `opt/com.coreos/config`. If you are using [Flatcar Linux](https://docs.flatcar-linux.org/os/booting-with-libvirt/#creating-the-domain-xml), the value is `opt/org.flatcar-linux/config`.
5354
* `arch` - (Optional) The architecture for the VM (probably x86_64 or i686),
5455
you normally won't need to set this unless you are building a special VM
5556
* `machine` - (Optional) The machine type,

0 commit comments

Comments
 (0)