summary history files

backend/services/persistent_volume_claims_service.go
package services

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"kd/backend/config"
	"kd/backend/logwrap"
	"kd/backend/types"
	"sync"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/kubectl/pkg/describe"
	describecmd "k8s.io/kubectl/pkg/describe"
	"k8s.io/kubectl/pkg/scheme"
)

type persistentVolumeClaimsService struct {
	ctx    context.Context
	conf   config.Config
	logger *logwrap.LogWrap
}

var persistentVolumeClaims *persistentVolumeClaimsService
var oncePersistentVolumeClaims sync.Once

func PersistentVolumeClaims() *persistentVolumeClaimsService {
	if persistentVolumeClaims == nil {
		oncePersistentVolumeClaims.Do(func() {
			persistentVolumeClaims = &persistentVolumeClaimsService{}
		})
	}
	return persistentVolumeClaims
}

func (p *persistentVolumeClaimsService) Start(ctx context.Context, conf config.Config, logger *logwrap.LogWrap) {
	p.ctx = ctx
	p.conf = conf
	p.logger = logger
}

func (p *persistentVolumeClaimsService) getPersistentVolumeClaimFromDefinition(definition any) (*corev1.PersistentVolumeClaim, error) {
	var data []byte
	var err error

	switch v := definition.(type) {
	case string:
		data = []byte(v)
	case []byte:
		data = v
	default:
		data, err = json.Marshal(definition)
		if err != nil {
			return nil, fmt.Errorf("failed to marshal definition: %w", err)
		}
	}

	decode := serializer.NewCodecFactory(scheme.Scheme).UniversalDeserializer().Decode
	obj, gvk, err := decode(data, nil, nil)
	if err != nil {
		return nil, err
	}
	if gvk.Kind != "PersistentVolumeClaim" {
		return nil, errors.New("definition does not define a PersistentVolumeClaim resource")
	}

	persistentVolumeClaim, ok := obj.(*corev1.PersistentVolumeClaim)
	if !ok {
		return nil, errors.New("failed to convert object to PersistentVolumeClaim")
	}

	return persistentVolumeClaim, nil
}

func (p *persistentVolumeClaimsService) Create(context string, definition any) types.PersistentVolumeClaimResponse {
	r := types.NewPersistentVolumeClaimResponse()

	cs, err := p.conf.GetClientSet(context)
	if err != nil {
		r.Msg = fmt.Sprintf("Failed to find context name: %s", err.Error())
		return r
	}

	persistentVolumeClaim, err := p.getPersistentVolumeClaimFromDefinition(definition)
	if err != nil {
		r.Msg = fmt.Sprintf("Failed to get persistent volume claim from definition: %s", err.Error())
		return r
	}

	if _, err := cs.CoreV1().PersistentVolumeClaims(persistentVolumeClaim.ObjectMeta.GetNamespace()).Create(p.ctx, persistentVolumeClaim, metav1.CreateOptions{}); err != nil {
		r.Msg = fmt.Sprintf("Failed to create resource: %s", err.Error())
		return r
	}

	r.Msg = fmt.Sprintf("Persistent Volume Claim created: %s", persistentVolumeClaim.GetName())
	r.Success = true

	return r
}

func (p *persistentVolumeClaimsService) Delete(context, namespace, name string) types.Response {
	r := types.NewResponse()

	cs, err := p.conf.GetClientSet(context)
	if err != nil {
		r.Msg = fmt.Sprintf("Failed to find context name: %s", err.Error())
		return r
	}

	if err := cs.CoreV1().PersistentVolumeClaims(namespace).Delete(p.ctx, name, kubernetesDeleteOptions); err != nil {
		r.Msg = fmt.Sprintf("Failed to delete Persistent Volume Claim: %s", err.Error())
		return r
	}

	r.Msg = fmt.Sprintf("Persistent Volume Claim deleted: %s", name)
	r.Success = true
	return r
}

func (p *persistentVolumeClaimsService) List(context, namespace string) types.PersistentVolumeClaimsResponse {
	r := types.NewPersistentVolumeClaimsResponse()

	cs, err := p.conf.GetClientSet(context)
	if err != nil {
		r.Msg = "Failed to find context name"
		return r
	}

	persistentVolumeClaimsList, err := cs.CoreV1().PersistentVolumeClaims(namespace).List(p.ctx, metav1.ListOptions{})
	if err != nil {
		r.Msg = "Failed to list Persistent Volume Claims"
		return r
	}

	r.Data = persistentVolumeClaimsList.Items
	r.Success = true
	return r
}

func (p *persistentVolumeClaimsService) Describe(context, namespace, name string) types.DescribeResponse {
	r := types.NewDescribeResponse()

	rc, err := p.conf.GetRestConfig(context)
	if err != nil {
		r.Msg = fmt.Sprintf("Failed to find rest config name: %s", err.Error())
		return r
	}

	gk := schema.GroupKind{Group: "", Kind: "PersistentVolumeClaim"}
	d, ok := describecmd.DescriberFor(gk, rc)
	if !ok {
		r.Msg = fmt.Sprintf("Failed to find describer: %s", err.Error())
		return r
	}

	out, err := d.Describe(namespace, name, describe.DescriberSettings{})
	if err != nil {
		r.Msg = fmt.Sprintf("Failed to describe resource: %s", err.Error())
		return r
	}

	r.Data = out
	r.Success = true
	return r
}