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
}