muhlba91 / pulumi-proxmoxve

A Pulumi provider for creating and managing Proxmox VE resources
Apache License 2.0
130 stars 14 forks source link

Dynamic VM ID generation #428

Open miberecz opened 1 month ago

miberecz commented 1 month ago

Hello Everyone,

Its not a bug report, I'm just reaching out to get some help to solve a problem of mine. If you can suggest better forum for this that already helps.

Right now, we are creating Virtual Machines on Proxmox using this provider with Go. Iterating through a set of input files where different VM details are described, generating VirtualMachineArgs, running NewVirtualMachine on each. Having different parameters defined by us is fine for the most part. Every VM has to have name, resource values, list of disk... etc. Where my problem comes is the ID. If I change the ID of VM, then pulumi recreates the resource. Which is obviously not a desired outcome. Okay, then do not change the ID you could say. And I do not want to. But to dynamically generate the ID, I would have to re-calculate it every time we run 'pulumi up'. The problem is, at the time of 'pulumi up' we cannot differentiate that its a creation of a new resource, or updating an already existing. Or we can, I'm just missing something. There is this feature ignoreChanges, which works for most fields of the stack json, but not for the VMID, since its part of the resource URN. And not a solution, since I do not want to change the Id at the first place, so no point to ignore it anyways.

How could I only run a piece of code only at creation time, store the result somewhere, and later read the same parameter from that storage. Currently we do not use any sort of database apart from the pulumi stack file stored in S3, and we would like to keep this way unless there is no other option.

ghost commented 1 week ago

Hi miberecz,

I have just been playing around this weekend with this provider and just out of curiosity: why manage VM IDs in the first place? If you dont specify a VM ID, doesn't it get auto-assigned?

miberecz commented 1 week ago

Every pulumi resource has an identifier, an URN as it called. Currently we assign the VM ID as URN. It has to be unique obviously. Other option for us would be the VM Name, but then we lose the ability to rename VM-s. We could figure out a 3rd identifier just for URNs but so far it was just convenient to have them same for both in case we are looking for something. But maybe you gave me an idea.

muhlba91 commented 1 week ago

do i get it right that you are having a file which contains properties, e.g., name, cpu, memory, and a field id which people are, theoretically, allowed to change? if so, i'd argue that no one should change the field id. otherwise, you could link, e.g., the file name to the pulumi identifier and let the URN auto-create or would this not work?

maybe you could share an anonymized file and the piece of code which generated the VM for better understanding?

miberecz commented 1 week ago

Well, its not easy, we have quite extensive system to fit Pulumi into our infrastructure.

Basically, we create VMs, on Proxmox based on 2 input file. One describes a whole Pool of VMs in yaml separated by --- as usual. Every yaml section refers to a 'basefile' which contains default values and we only have to specify the differences. The whole thing tries to emulate the kube-virt

---
base:
  fileName: _some_basefile.yaml
metadata:
  name: vmname
  vmId: 164
  ansibleManaged: true
  production: true
  labels:
    - debian11
  description:
    manager: userid
    managerName: name
    department: name
    bunchMore: of custom data
spec:
  nodeSelector:
    nodeName: hostserver
  source:
    name: debian11-template
  domain: 
    cpu:
      cores: 2
    resources:
      requests:
        memory: 32768
    devices:      
      disks:
        - interface: scsi0
          disk:
            capacity: 250    
        - interface: scsi1
          disk:
            capacity: 750
      interfaces:            
          - name: net0
            bridge: vmbr1
            model: virtio
etc...
---

Every yaml field gets unmarshaled into a Go struct. On each of them we do a whole lot of processing (checking if mandatory field is given, with proper values... etc) Eventually we concatenate a 'vm-definition' and feed it to the NewVirtualMachine function something like this:


 ...    
 vmArgs = &vm.VirtualMachineArgs{
        Name:     pulumi.String(vmName),
        VmId:     pulumi.Int(vmId),
        NodeName: buildNodeName(vmDef),
        Agent: vm.VirtualMachineAgentArgs{
            Enabled: pulumi.Bool(true),
        },
        Tags:           tags,
        Description:    pulumi.String(description),
        Clone:          buildClone(vmDef, templateVmId),
        Memory:         buildMemory(vmDef),
...     

 ...
        // Create the VM
        var vmMachine *vm.VirtualMachine
        vmMachine, err = vm.NewVirtualMachine(
            ctx,
            vmIdStr,
            vmArgs,
            pulumi.DeleteBeforeReplace(true),
            pulumi.IgnoreChanges(ignoreString),
        )

        if err != nil {
            lg.LOG.Errorf("Error during creation of VM: %v", vmArgs.Name)
            return vms, err
        }
        vms = append(vms, vmMachine)
...

As you can see, currently we name the pulumi resource vmIdStr based on the ID got from the yaml. We do not want to change ID-s, they should be static. What we want is to dynamically create them. But for that we would need to tell if its a new resource to create or an existing one to update. Currently there is only NewVirtualMachine there are no UpdateVirtualMachine or such. Somehow we have to connect the Yaml entry with the resource in the state-file. So just having a 3rd identifier besides the name and the ID is not the best approach, we just move the problem to somewhere else.

So as you can see I do not have the right direction with this. Any help is appreciated. Maybe I just do not see something obvious.

ghost commented 1 week ago

I could be missing something obvious in your system, but can't you add another key in your yaml file so that you have name and vmName that are used to build the resource name and vm name respectfully?