Skip to content

Commit

Permalink
Add support for CPU model and topology
Browse files Browse the repository at this point in the history
  • Loading branch information
NamelessOne91 committed Nov 19, 2024
1 parent 1cd90b7 commit 687b414
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 13 deletions.
62 changes: 62 additions & 0 deletions libvirt/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ const (
domainStateConfLeaseDone = resourceStateConfDone
)

const (
hostPassthroughCPUMode = "host-passthrough"
customCPUMode = "custom"
noneCPUMode = "none"
)

func domainLeaseStateRefreshFunc(_ context.Context,
virConn *libvirt.Libvirt, domain libvirt.Domain,
waitForLeases []*libvirtxml.DomainInterface, rd *schema.ResourceData) retry.StateRefreshFunc {
Expand Down Expand Up @@ -236,6 +242,62 @@ func newDiskForCloudInit(virConn *libvirt.Libvirt, volumeKey string) (libvirtxml
return disk, nil
}

func setCPU(d *schema.ResourceData, domainDef *libvirtxml.Domain) error {
if cpuMode, ok := d.GetOk("cpu.0.mode"); ok {
mode := cpuMode.(string)
if mode != hostPassthroughCPUMode && mode != customCPUMode && mode != noneCPUMode {
return fmt.Errorf("invalid CPU mode: %s.Must be one of 'host-passthrough', 'custom', 'none'", mode)
}

var model *libvirtxml.DomainCPUModel
if modelConfig, ok := d.GetOk("cpu.0.model"); ok {
if models, ok := modelConfig.([]interface{}); ok && len(models) > 0 {
if mode != customCPUMode {
return fmt.Errorf("CPU model can only be defined when the CPU mode is set to 'custom'")
}
cpuModel := models[0].(map[string]interface{})

model = &libvirtxml.DomainCPUModel{
Fallback: cpuModel["fallback"].(string),
Value: cpuModel["value"].(string),
VendorID: cpuModel["vendor_id"].(string),
}
}
}

var topology *libvirtxml.DomainCPUTopology
if topologyConfig, ok := d.GetOk("cpu.0.topology"); ok {
if topologies, ok := topologyConfig.([]interface{}); ok && len(topologies) > 0 {
cpuTopology := topologies[0].(map[string]interface{})

sockets := cpuTopology["sockets"].(int)
cores := cpuTopology["cores"].(int)
threads := cpuTopology["threads"].(int)

if (sockets * cores * threads) > int(domainDef.VCPU.Value) {
return fmt.Errorf(
"(%d sockets * %d cores * %d threads) is more than the vCPU count (%d)",
sockets, cores, threads, domainDef.VCPU.Value,
)
}

topology = &libvirtxml.DomainCPUTopology{
Sockets: sockets,
Cores: cores,
Threads: threads,
}
}
}

domainDef.CPU = &libvirtxml.DomainCPU{
Mode: mode,
Model: model,
Topology: topology,
}
}
return nil
}

func setCoreOSIgnition(d *schema.ResourceData, domainDef *libvirtxml.Domain, arch string) error {
if ignition, ok := d.GetOk("coreos_ignition"); ok {
ignitionKey, err := getIgnitionVolumeKeyFromTerraformID(ignition.(string))
Expand Down
93 changes: 80 additions & 13 deletions libvirt/resource_libvirt_domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,57 @@ func resourceLibvirtDomain() *schema.Resource {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"model": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"fallback": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"value": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"vendor_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
},
},
"topology": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"sockets": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
},
"cores": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
},
"threads": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
},
},
},
},
},
},
Expand Down Expand Up @@ -494,24 +545,25 @@ func resourceLibvirtDomainCreate(ctx context.Context, d *schema.ResourceData, me
domainDef.Name = name.(string)
}

if cpuMode, ok := d.GetOk("cpu.0.mode"); ok {
domainDef.CPU = &libvirtxml.DomainCPU{
Mode: cpuMode.(string),
}
domainDef.VCPU = &libvirtxml.DomainVCPU{
Value: uint(d.Get("vcpu").(int)),
}

if err := setCPU(d, &domainDef); err != nil {
return diag.FromErr(err)
}

domainDef.Memory = &libvirtxml.DomainMemory{
Value: uint(d.Get("memory").(int)),
Unit: "MiB",
}
domainDef.VCPU = &libvirtxml.DomainVCPU{
Value: uint(d.Get("vcpu").(int)),
}

domainDef.Description = d.Get("description").(string)

domainDef.OS.Kernel = d.Get("kernel").(string)
domainDef.OS.Initrd = d.Get("initrd").(string)
domainDef.OS.Type.Arch = d.Get("arch").(string)
domainDef.OS.Type.Machine = d.Get("machine").(string)

domainDef.Devices.Emulator = d.Get("emulator").(string)

Expand Down Expand Up @@ -837,15 +889,30 @@ func resourceLibvirtDomainRead(ctx context.Context, d *schema.ResourceData, meta
}

if domainDef.CPU != nil {
cpu := make(map[string]interface{})
var cpus []map[string]interface{}
cpu := map[string]interface{}{}

if domainDef.CPU.Mode != "" {
cpu["mode"] = domainDef.CPU.Mode

if domainDef.CPU.Model != nil {
model := map[string]interface{}{}
model["fallback"] = domainDef.CPU.Model.Fallback
model["value"] = domainDef.CPU.Model.Value
model["vendor_id"] = domainDef.CPU.Model.VendorID

cpu["model"] = []map[string]interface{}{model}
}

if domainDef.CPU.Topology != nil {
topology := map[string]interface{}{}
topology["sockets"] = domainDef.CPU.Topology.Sockets
topology["cores"] = domainDef.CPU.Topology.Cores
topology["threads"] = domainDef.CPU.Topology.Threads

cpu["topology"] = []map[string]interface{}{topology}
}
}
if len(cpu) > 0 {
cpus = append(cpus, cpu)
d.Set("cpu", cpus)
}
d.Set("cpu", []map[string]interface{}{cpu})
}

d.Set("arch", domainDef.OS.Type.Arch)
Expand Down

0 comments on commit 687b414

Please sign in to comment.