arttor/helmify

View on GitHub
pkg/processor/storage/pvc.go

Summary

Maintainability
A
2 hrs
Test Coverage
F
58%
package storage

import (
    "fmt"
    "github.com/arttor/helmify/pkg/helmify"
    "github.com/arttor/helmify/pkg/processor"
    yamlformat "github.com/arttor/helmify/pkg/yaml"
    "github.com/iancoleman/strcase"
    "io"
    corev1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/runtime/schema"
    "strings"
    "text/template"
)

var pvcTempl, _ = template.New("pvc").Parse(
    `{{ .Meta }}
{{ .Spec }}`)

var pvcGVC = schema.GroupVersionKind{
    Group:   "",
    Version: "v1",
    Kind:    "PersistentVolumeClaim",
}

// New creates processor for k8s PVC resource.
func New() helmify.Processor {
    return &pvc{}
}

type pvc struct{}

// Process k8s PVC object into template. Returns false if not capable of processing given resource type.
func (p pvc) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
    if obj.GroupVersionKind() != pvcGVC {
        return false, nil, nil
    }
    meta, err := processor.ProcessObjMeta(appMeta, obj)
    if err != nil {
        return true, nil, err
    }

    name := appMeta.TrimName(obj.GetName())
    nameCamelCase := strcase.ToLowerCamel(name)
    values := helmify.Values{}

    claim := corev1.PersistentVolumeClaim{}
    err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &claim)
    if err != nil {
        return true, nil, fmt.Errorf("%w: unable to cast to PVC", err)
    }

    // template storage class name
    if claim.Spec.StorageClassName != nil {
        templatedSC, err := values.Add(*claim.Spec.StorageClassName, "pvc", nameCamelCase, "storageClass")
        if err != nil {
            return true, nil, err
        }
        claim.Spec.StorageClassName = &templatedSC
    }

    // template resources
    specMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&claim.Spec)
    if err != nil {
        return true, nil, err
    }

    storageReq, ok, _ := unstructured.NestedString(specMap, "resources", "requests", "storage")
    if ok {
        templatedStorageReq, err := values.Add(storageReq, "pvc", nameCamelCase, "storageRequest")
        if err != nil {
            return true, nil, err
        }
        err = unstructured.SetNestedField(specMap, templatedStorageReq, "resources", "requests", "storage")
        if err != nil {
            return true, nil, err
        }
    }

    storageLim, ok, _ := unstructured.NestedString(specMap, "resources", "limits", "storage")
    if ok {
        templatedStorageLim, err := values.Add(storageLim, "pvc", nameCamelCase, "storageLimit")
        if err != nil {
            return true, nil, err
        }
        err = unstructured.SetNestedField(specMap, templatedStorageLim, "resources", "limits", "storage")
        if err != nil {
            return true, nil, err
        }
    }

    spec, err := yamlformat.Marshal(map[string]interface{}{"spec": specMap}, 0)
    if err != nil {
        return true, nil, err
    }
    spec = strings.ReplaceAll(spec, "'", "")

    return true, &result{
        name: name + ".yaml",
        data: struct {
            Meta string
            Spec string
        }{Meta: meta, Spec: spec},
        values: values,
    }, nil
}

type result struct {
    name string
    data struct {
        Meta string
        Spec string
    }
    values helmify.Values
}

func (r *result) Filename() string {
    return r.name
}

func (r *result) Values() helmify.Values {
    return r.values
}

func (r *result) Write(writer io.Writer) error {
    return pvcTempl.Execute(writer, r.data)
}