CentOS Linux release 7.5.1804 (Core)
Terraform v0.11.8
3.9.0
f104fad4
provider "libvirt" {
uri = "qemu:///system"
}
resource "libvirt_network" "public"{
name = "public"
mode = "route"
bridge = "br-public"
addresses = ["{{ ipv6_network }}"]
dhcp {
enabled = "false"
}
autostart = "true"
}
resource "libvirt_domain" "tf_test" {
# init
name = "tf_test"
metadata = "tf_test"
vcpu = 2
memory = 512
running = false
autostart = false
# network
network_interface {
network_id = "${libvirt_network.public.id}"
addresses = ["{{ ipv6_address }}"]
# wait_for_lease = true
}
}
terraform apply
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
+ libvirt_domain.tf_test
id: <computed>
arch: <computed>
autostart: "false"
emulator: <computed>
machine: <computed>
memory: "512"
metadata: "tf_test"
name: "tf_test"
network_interface.#: "1"
network_interface.0.addresses.#: "1"
network_interface.0.addresses.0: "{{ ipv6_address }}"
network_interface.0.hostname: <computed>
network_interface.0.mac: <computed>
network_interface.0.network_id: "${libvirt_network.public.id}"
network_interface.0.network_name: <computed>
qemu_agent: "false"
running: "false"
vcpu: "2"
+ libvirt_network.public
id: <computed>
addresses.#: "1"
addresses.0: "{{ ipv6_network }}"
autostart: "true"
bridge: "br-public"
dhcp.#: "1"
dhcp.0.enabled: "false"
mode: "route"
name: "public"
Plan: 2 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
libvirt_network.public: Creating...
addresses.#: "" => "1"
addresses.0: "" => "{{ ipv6_network }}"
autostart: "" => "true"
bridge: "" => "br-public"
dhcp.#: "" => "1"
dhcp.0.enabled: "" => "false"
mode: "" => "route"
name: "" => "public"
libvirt_network.public: Creation complete after 5s (ID: 3cc28126-de07-4cbc-b4ff-cd62c234cc38)
libvirt_domain.tf_test: Creating...
arch: "" => "<computed>"
autostart: "" => "false"
emulator: "" => "<computed>"
machine: "" => "<computed>"
memory: "" => "512"
metadata: "" => "tf_test"
name: "" => "tf_test"
network_interface.#: "" => "1"
network_interface.0.addresses.#: "" => "1"
network_interface.0.addresses.0: "" => "{{ ipv6_address }}"
network_interface.0.hostname: "" => "<computed>"
network_interface.0.mac: "" => "<computed>"
network_interface.0.network_id: "" => "3cc28126-de07-4cbc-b4ff-cd62c234cc38"
network_interface.0.network_name: "" => "<computed>"
qemu_agent: "" => "false"
running: "" => "false"
vcpu: "" => "2"
Error: Error applying plan:
1 error(s) occurred:
* libvirt_domain.tf_test: 1 error(s) occurred:
* libvirt_domain.tf_test: virError(Code=27, Domain=19, Message='XML error: Invalid to specify MAC address '76:92:e8:5a:a4:9b' in network 'public' IPv6 static host definition')
If I try to uncomment wait_for_lease = true the domain is correctly created, terraform doesn't end because dchp enabled is false, so no lease will be assigned to the domain
If I choose a custom (not computed) MAC address I get the same error. Maybe I'm missing some obvious.
I attach a trace level terraform log:
tf_test_static_ipv6_routed.log
Feel free to ask any additional information and keep up the good work on this nice project.
Ciao,
before to post logs and stdout I replaced my ipv6 network and ipv6 address with placeholders using jinja2 syntax to hide them. I wasn't clear about that in the first post, sorry, my fault.
I experience the problem with some real word ipv6 network and address. I didn't try an ipv4 routed domain like in your example, I'll try and let you know but I suspect it's a ipv6 only problem.
Ok, like you recreate, using an ipv4 addressing there is no problem:
provider "libvirt" {
uri = "qemu:///system"
}
resource "libvirt_network" "public4"{
name = "public4"
mode = "route"
bridge = "br-public4"
addresses = ["10.0.1.0/24"]
dhcp {
enabled = "false"
}
autostart = "true"
}
resource "libvirt_domain" "tf_test4" {
# init
name = "tf_test"
metadata = "tf_test"
vcpu = 2
memory = 512
running = false
autostart = false
network_interface {
network_id = "${libvirt_network.public4.id}"
addresses = ["10.0.1.3"]
# wait_for_lease = true
}
}
but using ipv6 addressing:
resource "libvirt_network" "public6"{
name = "public6"
mode = "route"
bridge = "br-public6"
addresses = ["2a01:4f8:212:2122::/64"]
dhcp {
enabled = "false"
}
autostart = "true"
}
resource "libvirt_domain" "tf_test6" {
# init
name = "tf_test"
metadata = "tf_test"
vcpu = 2
memory = 512
running = false
autostart = false
network_interface {
network_id = "${libvirt_network.public6.id}"
addresses = ["2a01:4f8:212:2122::3"]
# wait_for_lease = true
}
}
the error appears:
libvirt_domain.tf_test6: virError(Code=27, Domain=19, Message='XML error: Invalid to specify MAC address 'ae:3c:38:4d:88:c6' in network 'public6' IPv6 static host definition')
@lgaggini ok thx! i will have a look then
@lgaggini update sofar:
i checked the code in thi repo and everything is ok.
To me look more a libvirt issue/missing feature upstream.
i could look at libvirt upstream : https://github.com/libvirt/libvirt/blob/7564daca8a71dfec4a22c55b6f11f266f7044e05/src/conf/network_conf.c#L411
Would maybe interesting if you can reproduce the same issue with virsh ( i think the provider codebase here is fine)
Thank you.
I'll do some investigation on libvirt too,I'll try to reproduce the same issue on virsh and I'll let you know.
Ok, I think i've figured out what the problem is.
If an ipv6 network / addressing scheme is used, libvirt checks if in the input xml for network manipulation there is the field mac and if it's present gives the error:
Invalid to specify MAC address 'XX:XX:XX:XX:XX:XX' in network 'public' IPv6 static host definition'
This because for the ipv6 the use of mac address (in a dchp context, like used by libvirt) is deprecated and replaced by DHCP Unique Identifier (DUID).
The provider doesn't seem to make difference between ipv4 and ipv6 and it always generates a mac address.
Then the generated mac address in the libvirt/utils_libvirt_go is used to create the xml which is passed to libvirt-go, processed by libvirt-go
and at the end arrives at libvirt where the error pops up.
@lgaggini yop make perfect sense, i just tried out your suggestion, i just gave the xml definition an empty mac and network was up.
Thank for sharing the infos about the DUID and DHCP:+1: This was really awesome :cupid:
now i am asking myself and reading if we should for all network types not generate an IPV6 mac, and more generally if we should generate MACs,
From https://avdv.github.io/libvirt/formatnetwork.html i read
Generally it is best to not specify a MAC address when creating a network - in this case, if a defined MAC address is needed for proper operation, libvirt will automatically generate a random MAC address and save it in the config. Allowing libvirt to generate the MAC address will assure that it is compatible with the idiosyncrasies of the platform where libvirt is running. Since 0.8.8
dns
So i am thinking that we should not generate them (on ipv4 and ipv6) . I will try out some tests and if ok i will remove the mac generation.
@lgaggini can you do some tests from the upstream branch linked and give me some feedback? this would be awesome.
I already did some tests are ok, but just to be on safer side.
for doing the test
you need to build from source and then move the binary to /usr/bin
https://github.com/dmacvicar/terraform-provider-libvirt#building-from-source
otherwise is ok, i plan to merge this tomorrow afternoon more or less
Sure, I'll do some tests on my use case and I'll let you know.
@lgaggini thx! atm i am fixing wait_for_lease =true this will not work. If you find other issue let me know.. :love_hotel:
Ok, using your feature branch nomac I'm correctly able to create ipv6 routed domain.
This:
resource "libvirt_network" "public6"{
name = "public6"
mode = "route"
bridge = "br-public6"
addresses = ["2a01:4f8:212:2122::/64"]
dhcp {
enabled = "false"
}
autostart = "true"
}
resource "libvirt_domain" "tf_test6" {
# init
name = "tf_test"
metadata = "tf_test"
vcpu = 2
memory = 512
running = false
autostart = false
network_interface {
network_id = "${libvirt_network.public6.id}"
addresses = ["2a01:4f8:212:2122::3"]
}
}
now works withour error.
yop this works nice, atm the wait_for_lease to true we don"t get the IP. feel free to experiment other corner cases.. thank you much for all efforts and idea sharing :+1:
@lgaggini atm i am little stuck on this bug because removing the MAC in networkdefinition we get other regression .. :circus_tent: :smile: .. especially when using wait_for_lease.
I have asked to @dmacvicar for some infos, maybe he has more insights. Otherwise i need to move more in deep in that feature, the networking part of the provider is kind of complex, so it will take me more time to analyze the whole picture
Thx for you patience :+1: and insights! if you feel that you can fix it, take inspiration from my PR ! this would be also awesome :smiley:
@MalloZup This one seems to be waiting on you to finish your PR. :) BTW, please add some more info to your git commit messages themselves. One doesn't always have internet (think flights) access and details in git history are your only hope then to figure how why some change was introduced. :)
I've stumbled with this bug too :-(
<network ipv6='yes'>
<name>babe.network</name>
<forward dev='enp5s0' mode='route'>
<interface dev='enp5s0'/>
</forward>
<bridge name='virbr1' stp='on' delay='0'/>
<mac address='52:54:00:ba:be:00'/>
<domain name='babe.example.com'/>
<ip family='ipv6' address='2001:470:cafe:cafe::1' prefix='64'/>
</network>
network_interface {
network_name = "babe.network"
hostname = "master-node-0
}
configuration.tf file DOES NOT return any IP addresses. You don't need that, since you know beforehand which IP addresses you are going to configure. But, if you find convenient that Terraform returns IP addresses to the shell, devise a way to hardcode the return values or populate an array somehow with the addresses you know beforehand should be there. I have commented out the output block, since I don't need it:# You don't need this block below
# output "ipv6" {
# value = [
# libvirt_domain.masters.*.network_interface.0.addresses,
# libvirt_domain.workers.*.network_interface.0.addresses
# ]
# }
{
"ignition": {
"version": "3.2.0"
},
"storage": {
"files": [
{
"filesystem": "root",
"path": "/etc/hostname",
"mode": 420,
"overwrite": true,
"contents": {
"source": "data:,${hostname}"
}
},
{
"filesystem": "root",
"path": "/etc/sysconfig/network/ifcfg-eth0",
"mode": 420,
"overwrite": true,
"contents": {
"source": "data:,BOOTPROTO%3Dstatic%0ASTARTMODE%3Dauto%0AIPADDR_0%3D${network_prefix}::${cluster}:${node}%0ADNS1%3D${network_dns1}%0ADNS2%3D${network_dns2}%0A"
}
},
{
"filesystem": "root",
"path": "/etc/sysconfig/network/routes",
"mode": 420,
"overwrite": true,
"contents": {
"source": "data:,default%20${network_gateway}%20-%20-%0A"
}
}
]
}
}
These are the files created in the virtual machine, which runs OpenSUSE MicroOS:
/etc/hostname
master-node-0
/etc/sysconfig/network/ifcfg-eth0
BOOTPROTO=static
STARTMODE=auto
IPADDR_0=2001:470:cafe:cafe::babe:32
DNS1=2606:4700:4700::1111
DNS2=2606:4700:4700::1001
/etc/sysconfig/network/routes
default 2001:470:cafe:cafe::1 - -
Most helpful comment
Ok, I think i've figured out what the problem is.
If an ipv6 network / addressing scheme is used, libvirt checks if in the input xml for network manipulation there is the field
macand if it's present gives the error:Invalid to specify MAC address 'XX:XX:XX:XX:XX:XX' in network 'public' IPv6 static host definition'This because for the ipv6 the use of mac address (in a dchp context, like used by libvirt) is deprecated and replaced by DHCP Unique Identifier (DUID).
The provider doesn't seem to make difference between ipv4 and ipv6 and it always generates a mac address.
Then the generated mac address in the
libvirt/utils_libvirt_gois used to create the xml which is passed to libvirt-go, processed by libvirt-goand at the end arrives at libvirt where the error pops up.