@@ -1151,6 +1151,122 @@ func domainModelToXML(ctx context.Context, client *libvirt.Client, model *Domain
11511151 domain .Devices .TPMs = append (domain .Devices .TPMs , tpm )
11521152 }
11531153 }
1154+
1155+ // Process Inputs
1156+ if ! devices .Inputs .IsNull () && ! devices .Inputs .IsUnknown () {
1157+ var inputs []DomainInputModel
1158+ diags := devices .Inputs .ElementsAs (ctx , & inputs , false )
1159+ if diags .HasError () {
1160+ return nil , fmt .Errorf ("failed to extract inputs: %v" , diags .Errors ())
1161+ }
1162+
1163+ for _ , inputModel := range inputs {
1164+ input := libvirtxml.DomainInput {}
1165+
1166+ // Set type (required)
1167+ if ! inputModel .Type .IsNull () && ! inputModel .Type .IsUnknown () {
1168+ input .Type = inputModel .Type .ValueString ()
1169+ }
1170+
1171+ // Set bus (optional)
1172+ if ! inputModel .Bus .IsNull () && ! inputModel .Bus .IsUnknown () {
1173+ input .Bus = inputModel .Bus .ValueString ()
1174+ }
1175+
1176+ // Set model (optional)
1177+ if ! inputModel .Model .IsNull () && ! inputModel .Model .IsUnknown () {
1178+ input .Model = inputModel .Model .ValueString ()
1179+ }
1180+
1181+ // Set driver (optional nested object)
1182+ if ! inputModel .Driver .IsNull () && ! inputModel .Driver .IsUnknown () {
1183+ var driver DomainInputDriverModel
1184+ diags := inputModel .Driver .As (ctx , & driver , basetypes.ObjectAsOptions {})
1185+ if diags .HasError () {
1186+ return nil , fmt .Errorf ("failed to extract input driver: %v" , diags .Errors ())
1187+ }
1188+
1189+ inputDriver := & libvirtxml.DomainInputDriver {}
1190+
1191+ if ! driver .IOMMU .IsNull () && ! driver .IOMMU .IsUnknown () {
1192+ inputDriver .IOMMU = driver .IOMMU .ValueString ()
1193+ }
1194+
1195+ if ! driver .ATS .IsNull () && ! driver .ATS .IsUnknown () {
1196+ inputDriver .ATS = driver .ATS .ValueString ()
1197+ }
1198+
1199+ if ! driver .Packed .IsNull () && ! driver .Packed .IsUnknown () {
1200+ inputDriver .Packed = driver .Packed .ValueString ()
1201+ }
1202+
1203+ if ! driver .PagePerVQ .IsNull () && ! driver .PagePerVQ .IsUnknown () {
1204+ inputDriver .PagePerVQ = driver .PagePerVQ .ValueString ()
1205+ }
1206+
1207+ input .Driver = inputDriver
1208+ }
1209+
1210+ // Set source (optional nested object)
1211+ if ! inputModel .Source .IsNull () && ! inputModel .Source .IsUnknown () {
1212+ var source DomainInputSourceModel
1213+ diags := inputModel .Source .As (ctx , & source , basetypes.ObjectAsOptions {})
1214+ if diags .HasError () {
1215+ return nil , fmt .Errorf ("failed to extract input source: %v" , diags .Errors ())
1216+ }
1217+
1218+ inputSource := & libvirtxml.DomainInputSource {}
1219+
1220+ // Handle passthrough variant
1221+ if ! source .Passthrough .IsNull () && ! source .Passthrough .IsUnknown () {
1222+ var passthrough DomainInputSourcePassthroughModel
1223+ diags := source .Passthrough .As (ctx , & passthrough , basetypes.ObjectAsOptions {})
1224+ if diags .HasError () {
1225+ return nil , fmt .Errorf ("failed to extract input source passthrough: %v" , diags .Errors ())
1226+ }
1227+
1228+ if ! passthrough .EVDev .IsNull () && ! passthrough .EVDev .IsUnknown () {
1229+ inputSource .Passthrough = & libvirtxml.DomainInputSourcePassthrough {
1230+ EVDev : passthrough .EVDev .ValueString (),
1231+ }
1232+ }
1233+ }
1234+
1235+ // Handle evdev variant
1236+ if ! source .EVDev .IsNull () && ! source .EVDev .IsUnknown () {
1237+ var evdev DomainInputSourceEVDevModel
1238+ diags := source .EVDev .As (ctx , & evdev , basetypes.ObjectAsOptions {})
1239+ if diags .HasError () {
1240+ return nil , fmt .Errorf ("failed to extract input source evdev: %v" , diags .Errors ())
1241+ }
1242+
1243+ inputSourceEVDev := & libvirtxml.DomainInputSourceEVDev {}
1244+
1245+ if ! evdev .Dev .IsNull () && ! evdev .Dev .IsUnknown () {
1246+ inputSourceEVDev .Dev = evdev .Dev .ValueString ()
1247+ }
1248+
1249+ if ! evdev .Grab .IsNull () && ! evdev .Grab .IsUnknown () {
1250+ inputSourceEVDev .Grab = evdev .Grab .ValueString ()
1251+ }
1252+
1253+ if ! evdev .GrabToggle .IsNull () && ! evdev .GrabToggle .IsUnknown () {
1254+ inputSourceEVDev .GrabToggle = evdev .GrabToggle .ValueString ()
1255+ }
1256+
1257+ if ! evdev .Repeat .IsNull () && ! evdev .Repeat .IsUnknown () {
1258+ inputSourceEVDev .Repeat = evdev .Repeat .ValueString ()
1259+ }
1260+
1261+ inputSource .EVDev = inputSourceEVDev
1262+ }
1263+
1264+ input .Source = inputSource
1265+ }
1266+
1267+ domain .Devices .Inputs = append (domain .Devices .Inputs , input )
1268+ }
1269+ }
11541270 }
11551271
11561272 return domain , nil
@@ -2568,6 +2684,216 @@ func xmlToDomainModel(ctx context.Context, domain *libvirtxml.Domain, model *Dom
25682684 }
25692685 }
25702686
2687+ // Process Inputs
2688+ inputsType := types.ListType {
2689+ ElemType : types.ObjectType {
2690+ AttrTypes : map [string ]attr.Type {
2691+ "type" : types .StringType ,
2692+ "bus" : types .StringType ,
2693+ "model" : types .StringType ,
2694+ "driver" : types.ObjectType {
2695+ AttrTypes : map [string ]attr.Type {
2696+ "iommu" : types .StringType ,
2697+ "ats" : types .StringType ,
2698+ "packed" : types .StringType ,
2699+ "page_per_vq" : types .StringType ,
2700+ },
2701+ },
2702+ "source" : types.ObjectType {
2703+ AttrTypes : map [string ]attr.Type {
2704+ "passthrough" : types.ObjectType {
2705+ AttrTypes : map [string ]attr.Type {
2706+ "evdev" : types .StringType ,
2707+ },
2708+ },
2709+ "evdev" : types.ObjectType {
2710+ AttrTypes : map [string ]attr.Type {
2711+ "dev" : types .StringType ,
2712+ "grab" : types .StringType ,
2713+ "grab_toggle" : types .StringType ,
2714+ "repeat" : types .StringType ,
2715+ },
2716+ },
2717+ },
2718+ },
2719+ },
2720+ },
2721+ }
2722+ inputsObjType , ok := inputsType .ElemType .(types.ObjectType )
2723+ if ! ok {
2724+ diags .AddError ("Type Error" , "Expected inputsType.ElemType to be ObjectType" )
2725+ return diags
2726+ }
2727+ inputsList := types .ListNull (inputsObjType )
2728+
2729+ if ! model .Devices .IsNull () && ! model .Devices .IsUnknown () {
2730+ var existingDevices DomainDevicesModel
2731+ diags .Append (model .Devices .As (ctx , & existingDevices , basetypes.ObjectAsOptions {})... )
2732+
2733+ if ! existingDevices .Inputs .IsNull () && ! existingDevices .Inputs .IsUnknown () && len (domain .Devices .Inputs ) > 0 {
2734+ // Get the count of user-configured inputs
2735+ var userInputs []DomainInputModel
2736+ diags .Append (existingDevices .Inputs .ElementsAs (ctx , & userInputs , false )... )
2737+ userInputCount := len (userInputs )
2738+
2739+ // Only read back the number of inputs the user configured (libvirt adds defaults)
2740+ inputsToRead := domain .Devices .Inputs
2741+ if len (inputsToRead ) > userInputCount {
2742+ inputsToRead = inputsToRead [:userInputCount ]
2743+ }
2744+
2745+ inputs := make ([]DomainInputModel , 0 , len (inputsToRead ))
2746+ for _ , input := range inputsToRead {
2747+ inputModel := DomainInputModel {
2748+ Driver : types .ObjectNull (map [string ]attr.Type {
2749+ "iommu" : types .StringType ,
2750+ "ats" : types .StringType ,
2751+ "packed" : types .StringType ,
2752+ "page_per_vq" : types .StringType ,
2753+ }),
2754+ Source : types .ObjectNull (map [string ]attr.Type {
2755+ "passthrough" : types.ObjectType {
2756+ AttrTypes : map [string ]attr.Type {
2757+ "evdev" : types .StringType ,
2758+ },
2759+ },
2760+ "evdev" : types.ObjectType {
2761+ AttrTypes : map [string ]attr.Type {
2762+ "dev" : types .StringType ,
2763+ "grab" : types .StringType ,
2764+ "grab_toggle" : types .StringType ,
2765+ "repeat" : types .StringType ,
2766+ },
2767+ },
2768+ }),
2769+ }
2770+
2771+ if input .Type != "" {
2772+ inputModel .Type = types .StringValue (input .Type )
2773+ }
2774+
2775+ if input .Bus != "" {
2776+ inputModel .Bus = types .StringValue (input .Bus )
2777+ }
2778+
2779+ if input .Model != "" {
2780+ inputModel .Model = types .StringValue (input .Model )
2781+ }
2782+
2783+ // Process driver
2784+ if input .Driver != nil && (input .Driver .IOMMU != "" || input .Driver .ATS != "" || input .Driver .Packed != "" || input .Driver .PagePerVQ != "" ) {
2785+ driverModel := DomainInputDriverModel {}
2786+
2787+ if input .Driver .IOMMU != "" {
2788+ driverModel .IOMMU = types .StringValue (input .Driver .IOMMU )
2789+ }
2790+
2791+ if input .Driver .ATS != "" {
2792+ driverModel .ATS = types .StringValue (input .Driver .ATS )
2793+ }
2794+
2795+ if input .Driver .Packed != "" {
2796+ driverModel .Packed = types .StringValue (input .Driver .Packed )
2797+ }
2798+
2799+ if input .Driver .PagePerVQ != "" {
2800+ driverModel .PagePerVQ = types .StringValue (input .Driver .PagePerVQ )
2801+ }
2802+
2803+ driverObj , d := types .ObjectValueFrom (ctx , map [string ]attr.Type {
2804+ "iommu" : types .StringType ,
2805+ "ats" : types .StringType ,
2806+ "packed" : types .StringType ,
2807+ "page_per_vq" : types .StringType ,
2808+ }, driverModel )
2809+ diags .Append (d ... )
2810+ if ! diags .HasError () {
2811+ inputModel .Driver = driverObj
2812+ }
2813+ }
2814+
2815+ // Process source
2816+ if input .Source != nil && (input .Source .Passthrough != nil || input .Source .EVDev != nil ) {
2817+ sourceModel := DomainInputSourceModel {}
2818+
2819+ if input .Source .Passthrough != nil {
2820+ passthroughModel := DomainInputSourcePassthroughModel {}
2821+ if input .Source .Passthrough .EVDev != "" {
2822+ passthroughModel .EVDev = types .StringValue (input .Source .Passthrough .EVDev )
2823+ }
2824+
2825+ passthroughObj , d := types .ObjectValueFrom (ctx , map [string ]attr.Type {
2826+ "evdev" : types .StringType ,
2827+ }, passthroughModel )
2828+ diags .Append (d ... )
2829+ if ! diags .HasError () {
2830+ sourceModel .Passthrough = passthroughObj
2831+ }
2832+ }
2833+
2834+ if input .Source .EVDev != nil {
2835+ evdevModel := DomainInputSourceEVDevModel {}
2836+
2837+ if input .Source .EVDev .Dev != "" {
2838+ evdevModel .Dev = types .StringValue (input .Source .EVDev .Dev )
2839+ }
2840+
2841+ if input .Source .EVDev .Grab != "" {
2842+ evdevModel .Grab = types .StringValue (input .Source .EVDev .Grab )
2843+ }
2844+
2845+ if input .Source .EVDev .GrabToggle != "" {
2846+ evdevModel .GrabToggle = types .StringValue (input .Source .EVDev .GrabToggle )
2847+ }
2848+
2849+ if input .Source .EVDev .Repeat != "" {
2850+ evdevModel .Repeat = types .StringValue (input .Source .EVDev .Repeat )
2851+ }
2852+
2853+ evdevObj , d := types .ObjectValueFrom (ctx , map [string ]attr.Type {
2854+ "dev" : types .StringType ,
2855+ "grab" : types .StringType ,
2856+ "grab_toggle" : types .StringType ,
2857+ "repeat" : types .StringType ,
2858+ }, evdevModel )
2859+ diags .Append (d ... )
2860+ if ! diags .HasError () {
2861+ sourceModel .EVDev = evdevObj
2862+ }
2863+ }
2864+
2865+ sourceObj , d := types .ObjectValueFrom (ctx , map [string ]attr.Type {
2866+ "passthrough" : types.ObjectType {
2867+ AttrTypes : map [string ]attr.Type {
2868+ "evdev" : types .StringType ,
2869+ },
2870+ },
2871+ "evdev" : types.ObjectType {
2872+ AttrTypes : map [string ]attr.Type {
2873+ "dev" : types .StringType ,
2874+ "grab" : types .StringType ,
2875+ "grab_toggle" : types .StringType ,
2876+ "repeat" : types .StringType ,
2877+ },
2878+ },
2879+ }, sourceModel )
2880+ diags .Append (d ... )
2881+ if ! diags .HasError () {
2882+ inputModel .Source = sourceObj
2883+ }
2884+ }
2885+
2886+ inputs = append (inputs , inputModel )
2887+ }
2888+
2889+ inputsList , d = types .ListValueFrom (ctx , inputsObjType , inputs )
2890+ diags .Append (d ... )
2891+ if diags .HasError () {
2892+ return diags
2893+ }
2894+ }
2895+ }
2896+
25712897 newDevices := DomainDevicesModel {
25722898 Disks : disksList ,
25732899 Interfaces : interfacesList ,
@@ -2579,6 +2905,7 @@ func xmlToDomainModel(ctx context.Context, domain *libvirtxml.Domain, model *Dom
25792905 Serials : serialsList ,
25802906 RNGs : rngsList ,
25812907 TPMs : tpmsList ,
2908+ Inputs : inputsList ,
25822909 }
25832910
25842911 // Create the devices object
@@ -2699,6 +3026,40 @@ func xmlToDomainModel(ctx context.Context, domain *libvirtxml.Domain, model *Dom
26993026 },
27003027 },
27013028 },
3029+ "inputs" : types.ListType {
3030+ ElemType : types.ObjectType {
3031+ AttrTypes : map [string ]attr.Type {
3032+ "type" : types .StringType ,
3033+ "bus" : types .StringType ,
3034+ "model" : types .StringType ,
3035+ "driver" : types.ObjectType {
3036+ AttrTypes : map [string ]attr.Type {
3037+ "iommu" : types .StringType ,
3038+ "ats" : types .StringType ,
3039+ "packed" : types .StringType ,
3040+ "page_per_vq" : types .StringType ,
3041+ },
3042+ },
3043+ "source" : types.ObjectType {
3044+ AttrTypes : map [string ]attr.Type {
3045+ "passthrough" : types.ObjectType {
3046+ AttrTypes : map [string ]attr.Type {
3047+ "evdev" : types .StringType ,
3048+ },
3049+ },
3050+ "evdev" : types.ObjectType {
3051+ AttrTypes : map [string ]attr.Type {
3052+ "dev" : types .StringType ,
3053+ "grab" : types .StringType ,
3054+ "grab_toggle" : types .StringType ,
3055+ "repeat" : types .StringType ,
3056+ },
3057+ },
3058+ },
3059+ },
3060+ },
3061+ },
3062+ },
27023063 }, newDevices )
27033064 diags .Append (d ... )
27043065 if diags .HasError () {
0 commit comments