pkg/processor/statefulset/statefulset.go
package statefulset
import (
"fmt"
"github.com/arttor/helmify/pkg/processor/pod"
"io"
"strings"
"text/template"
"github.com/arttor/helmify/pkg/helmify"
"github.com/arttor/helmify/pkg/processor"
yamlformat "github.com/arttor/helmify/pkg/yaml"
"github.com/iancoleman/strcase"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
var statefulsetGVC = schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "StatefulSet",
}
var statefulsetTempl, _ = template.New("statefulset").Parse(
`{{- .Meta }}
spec:
{{ .Spec }}`)
// New creates processor for k8s StatefulSet resource.
func New() helmify.Processor {
return &statefulset{}
}
type statefulset struct{}
// Process k8s StatefulSet object into template. Returns false if not capable of processing given resource type.
func (d statefulset) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
if obj.GroupVersionKind() != statefulsetGVC {
return false, nil, nil
}
ss := appsv1.StatefulSet{}
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &ss)
if err != nil {
return true, nil, fmt.Errorf("%w: unable to cast to StatefulSet", err)
}
meta, err := processor.ProcessObjMeta(appMeta, obj)
if err != nil {
return true, nil, err
}
ssSpec := ss.Spec
ssSpecMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&ssSpec)
if err != nil {
return true, nil, err
}
delete((ssSpecMap["template"].(map[string]interface{}))["metadata"].(map[string]interface{}), "creationTimestamp")
values := helmify.Values{}
name := appMeta.TrimName(obj.GetName())
nameCamel := strcase.ToLowerCamel(name)
if ssSpec.ServiceName != "" {
servName := appMeta.TemplatedName(ssSpec.ServiceName)
ssSpecMap["serviceName"] = servName
}
if ssSpec.Replicas != nil {
repl, err := values.Add(*ssSpec.Replicas, nameCamel, "replicas")
if err != nil {
return true, nil, err
}
ssSpecMap["replicas"] = repl
}
for i, claim := range ssSpec.VolumeClaimTemplates {
volName := claim.ObjectMeta.Name
delete(((ssSpecMap["volumeClaimTemplates"].([]interface{}))[i]).(map[string]interface{}), "status")
if claim.Spec.StorageClassName != nil {
scName := appMeta.TemplatedName(*claim.Spec.StorageClassName)
err = unstructured.SetNestedField(((ssSpecMap["volumeClaimTemplates"].([]interface{}))[i]).(map[string]interface{}), scName, "spec", "storageClassName")
if err != nil {
return true, nil, err
}
}
if claim.Spec.VolumeName != "" {
vName := appMeta.TemplatedName(claim.Spec.VolumeName)
err = unstructured.SetNestedField(((ssSpecMap["volumeClaimTemplates"].([]interface{}))[i]).(map[string]interface{}), vName, "spec", "volumeName")
if err != nil {
return true, nil, err
}
}
resMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&claim.Spec.Resources)
if err != nil {
return true, nil, err
}
resName, err := values.AddYaml(resMap, 8, true, nameCamel, "volumeClaims", volName)
if err != nil {
return true, nil, err
}
err = unstructured.SetNestedField(((ssSpecMap["volumeClaimTemplates"].([]interface{}))[i]).(map[string]interface{}), resName, "spec", "resources")
if err != nil {
return true, nil, err
}
}
// process pod spec:
podSpecMap, podValues, err := pod.ProcessSpec(nameCamel, appMeta, ssSpec.Template.Spec)
if err != nil {
return true, nil, err
}
err = values.Merge(podValues)
if err != nil {
return true, nil, err
}
err = unstructured.SetNestedMap(ssSpecMap, podSpecMap, "template", "spec")
if err != nil {
return true, nil, err
}
spec, err := yamlformat.Marshal(ssSpecMap, 2)
if err != nil {
return true, nil, err
}
spec = strings.ReplaceAll(spec, "'", "")
return true, &result{
values: values,
data: struct {
Meta string
Spec string
}{
Meta: meta,
Spec: spec,
},
}, nil
}
type result struct {
data struct {
Meta string
Spec string
}
values helmify.Values
}
func (r *result) Filename() string {
return "statefulset.yaml"
}
func (r *result) Values() helmify.Values {
return r.values
}
func (r *result) Write(writer io.Writer) error {
return statefulsetTempl.Execute(writer, r.data)
}