Skip to content

Commit

Permalink
refactor validation and builder to play nice with net and vol templates
Browse files Browse the repository at this point in the history
Signed-off-by: yaacov <[email protected]>
  • Loading branch information
yaacov committed Feb 2, 2025
1 parent 0d0ad2e commit d768d5a
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 81 deletions.
132 changes: 66 additions & 66 deletions pkg/controller/plan/adapter/vsphere/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,71 +392,6 @@ func (r *Builder) Secret(vmRef ref.Ref, in, object *core.Secret) (err error) {
return
}

// Get the plan VM for the given vsphere VM
func (r *Builder) getPlanVM(vm *model.VM) *plan.VM {
for _, planVM := range r.Plan.Spec.VMs {
if planVM.ID == vm.ID {
return &planVM
}
}

return nil
}

// GetPVCNameTemplate returns the PVC name template
func (r *Builder) getPVCNameTemplate(vm *model.VM) string {
// Get plan VM
planVM := r.getPlanVM(vm)
if planVM == nil {
return ""
}

// if vm.PVCNameTemplate is set, use it
if planVM.PVCNameTemplate != "" {
return planVM.PVCNameTemplate
}

// if planSpec.PVCNameTemplate is set, use it
if r.Plan.Spec.PVCNameTemplate != "" {
return r.Plan.Spec.PVCNameTemplate
}

return ""
}

func (r *Builder) getGeneratePVCName(pvcNameTemplate string, vm *model.VM, diskIndex int) (string, error) {
var buf bytes.Buffer

// Get plan VM
planVM := r.getPlanVM(vm)
if planVM == nil {
return "", errors.New("plan VM not found")
}
rootDisk := planVM.RootDisk

// Create template data
templateData := api.PVCNameTemplateData{
VmName: vm.Name,
PlanName: r.Plan.Name,
DiskIndex: diskIndex,
RootDiskIndex: utils.GetDeviceNumber(rootDisk),
}

// Parse template syntax
tmpl, err := template.New("pvcname").Parse(pvcNameTemplate)
if err != nil {
return "", err
}

// Execute template
err = tmpl.Execute(&buf, templateData)
if err != nil {
return "", err
}

return buf.String(), nil
}

// Create DataVolume specs for the VM.
func (r *Builder) DataVolumes(vmRef ref.Ref, secret *core.Secret, _ *core.ConfigMap, dvTemplate *cdi.DataVolume) (dvs []cdi.DataVolume, err error) {
vm := &model.VM{}
Expand Down Expand Up @@ -555,7 +490,22 @@ func (r *Builder) DataVolumes(vmRef ref.Ref, secret *core.Secret, _ *core.Config
// and update the GenerateName field in the DataVolume object.
pvcNameTemplate := r.getPVCNameTemplate(vm)
if pvcNameTemplate != "" {
generatedName, err := r.getGeneratePVCName(pvcNameTemplate, vm, diskIndex)
// Get the VM root disk index
planVM := r.getPlanVM(vm)
rootDiskIndex := 0
if planVM != nil {
rootDiskIndex = utils.GetDeviceNumber(planVM.RootDisk)
}

// Create template data
templateData := api.PVCNameTemplateData{
VmName: vm.Name,
PlanName: r.Plan.Name,
DiskIndex: diskIndex,
RootDiskIndex: rootDiskIndex,
}

generatedName, err := r.getGeneratePVCName(pvcNameTemplate, &templateData, diskIndex)
if err == nil && generatedName != "" {
dv.ObjectMeta.GenerateName = generatedName
}
Expand Down Expand Up @@ -1059,3 +1009,53 @@ func (r *Builder) GetPopulatorTaskName(pvc *core.PersistentVolumeClaim) (taskNam
err = planbase.VolumePopulatorNotSupportedError
return
}

// Get the plan VM for the given vsphere VM
func (r *Builder) getPlanVM(vm *model.VM) *plan.VM {
for _, planVM := range r.Plan.Spec.VMs {
if planVM.ID == vm.ID {
return &planVM
}
}

return nil
}

// GetPVCNameTemplate returns the PVC name template
func (r *Builder) getPVCNameTemplate(vm *model.VM) string {
// Get plan VM
planVM := r.getPlanVM(vm)
if planVM == nil {
return ""
}

// if vm.PVCNameTemplate is set, use it
if planVM.PVCNameTemplate != "" {
return planVM.PVCNameTemplate
}

// if planSpec.PVCNameTemplate is set, use it
if r.Plan.Spec.PVCNameTemplate != "" {
return r.Plan.Spec.PVCNameTemplate
}

return ""
}

func (r *Builder) getGeneratePVCName(pvcNameTemplate string, templateData *api.PVCNameTemplateData, diskIndex int) (string, error) {
var buf bytes.Buffer

// Parse template syntax
tmpl, err := template.New("pvcname").Parse(pvcNameTemplate)
if err != nil {
return "", err
}

// Execute template
err = tmpl.Execute(&buf, templateData)
if err != nil {
return "", err
}

return buf.String(), nil
}
39 changes: 24 additions & 15 deletions pkg/controller/plan/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -1181,12 +1181,6 @@ func (r *Reconciler) IsValidPVCNameTemplate(pvcNameTemplate string) error {
return nil
}

// Validate golang template syntax
tmpl, err := template.New("pvcname").Parse(pvcNameTemplate)
if err != nil {
return liberr.Wrap(err, "Invalid template syntax")
}

// Test template with sample data
testData := api.PVCNameTemplateData{
VmName: "test-vm",
Expand All @@ -1195,16 +1189,9 @@ func (r *Reconciler) IsValidPVCNameTemplate(pvcNameTemplate string) error {
RootDiskIndex: 0,
}

var buf bytes.Buffer
err = tmpl.Execute(&buf, testData)
result, err := r.IsValidTemplate(pvcNameTemplate, testData)
if err != nil {
return liberr.Wrap(err, "Template execution failed")
}
result := buf.String()

// Empty output is not valid
if result == "" {
return liberr.New("Template output is empty")
return err
}

// Validate that template output is a valid k8s label
Expand All @@ -1215,3 +1202,25 @@ func (r *Reconciler) IsValidPVCNameTemplate(pvcNameTemplate string) error {

return nil
}

func (r *Reconciler) IsValidTemplate(templateStr string, testData interface{}) (string, error) {
// Validate golang template syntax
tmpl, err := template.New("template").Parse(templateStr)
if err != nil {
return "", liberr.Wrap(err, "Invalid template syntax")
}

var buf bytes.Buffer
err = tmpl.Execute(&buf, testData)
if err != nil {
return "", liberr.Wrap(err, "Template execution failed")
}
result := buf.String()

// Empty output is not valid
if result == "" {
return "", liberr.New("Template output is empty")
}

return result, nil
}

0 comments on commit d768d5a

Please sign in to comment.