Skip to content

Commit

Permalink
🌊 save default chart values to Module spec
Browse files Browse the repository at this point in the history
* save default chart values to Module spec

* decouple templates to support .tpl files

* fetch cluster version info for Helm capabilities

* ⚡ pass default values on module edit

* resolve conflicts

* fetch apiversion name from api

* fetch apiversion name from api when deleting

* default to type string for schema array item

* fix imports
  • Loading branch information
petar-cvit authored May 17, 2024
1 parent dfc6daf commit ba0a744
Show file tree
Hide file tree
Showing 14 changed files with 315 additions and 276 deletions.
6 changes: 5 additions & 1 deletion cyclops-ctrl/cmd/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/telemetry"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/template"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/template/cache"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/template/render"

cyclopsv1alpha1 "github.com/cyclops-ui/cyclops/cyclops-ctrl/api/v1alpha1"
)
Expand Down Expand Up @@ -77,7 +78,9 @@ func main() {
setupLog.Error(err, "failed to set up prom monitor")
}

handler, err := handler.New(templatesRepo, k8sClient, telemetryClient, monitor)
renderer := render.NewRenderer(k8sClient)

handler, err := handler.New(templatesRepo, k8sClient, renderer, telemetryClient, monitor)
if err != nil {
panic(err)
}
Expand All @@ -102,6 +105,7 @@ func main() {
mgr.GetScheme(),
templatesRepo,
k8sClient,
renderer,
telemetryClient,
)).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Module")
Expand Down
42 changes: 33 additions & 9 deletions cyclops-ctrl/internal/cluster/k8sclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -77,6 +78,10 @@ func createLocalClient() (*KubernetesClient, error) {
}, nil
}

func (k *KubernetesClient) VersionInfo() (*version.Info, error) {
return k.discovery.ServerVersion()
}

func (k *KubernetesClient) GetDeployment(namespace, name string) (*v12.Deployment, error) {
deploymentClient := k.clientset.AppsV1().Deployments(namespace)
return deploymentClient.Get(context.TODO(), name, metav1.GetOptions{})
Expand Down Expand Up @@ -241,10 +246,15 @@ func (k *KubernetesClient) GetStatefulSetsLogs(namespace, container, name string
}

func (k *KubernetesClient) GetManifest(group, version, kind, name, namespace string) (string, error) {
apiResourceName, err := k.GVKtoAPIResourceName(schema.GroupVersion{Group: group, Version: version}, kind)
if err != nil {
return "", err
}

resource, err := k.Dynamic.Resource(schema.GroupVersionResource{
Group: group,
Version: version,
Resource: strings.ToLower(kind) + "s",
Resource: apiResourceName,
}).Namespace(namespace).Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
return "", err
Expand Down Expand Up @@ -306,10 +316,19 @@ func (k *KubernetesClient) GetDeploymentsYaml(name string, namespace string) (*b
}

func (k *KubernetesClient) Delete(resource dto.Resource) error {
apiResourceName, err := k.GVKtoAPIResourceName(
schema.GroupVersion{
Group: resource.GetGroup(),
Version: resource.GetVersion(),
}, resource.GetKind())
if err != nil {
return err
}

gvr := schema.GroupVersionResource{
Group: resource.GetGroup(),
Version: resource.GetVersion(),
Resource: strings.ToLower(resource.GetKind()) + "s",
Resource: apiResourceName,
}

return k.Dynamic.Resource(gvr).Namespace(resource.GetNamespace()).Delete(
Expand All @@ -320,10 +339,15 @@ func (k *KubernetesClient) Delete(resource dto.Resource) error {
}

func (k *KubernetesClient) CreateDynamic(obj *unstructured.Unstructured) error {
resourceName, err := k.GVKtoAPIResourceName(obj.GroupVersionKind().GroupVersion(), obj.GroupVersionKind().Kind)
if err != nil {
return err
}

gvr := schema.GroupVersionResource{
Group: obj.GroupVersionKind().Group,
Version: obj.GroupVersionKind().Version,
Resource: strings.ToLower(obj.GroupVersionKind().Kind) + "s",
Resource: resourceName,
}

objNamespace := obj.GetNamespace()
Expand Down Expand Up @@ -573,13 +597,13 @@ func (k *KubernetesClient) mapPersistentVolumeClaims(group, version, kind, name,
}

return &dto.PersistentVolumeClaim{
Group: group,
Version: version,
Kind: kind,
Name: name,
Namespace: namespace,
Group: group,
Version: version,
Kind: kind,
Name: name,
Namespace: namespace,
AccessModes: persistentvolumeclaim.Spec.AccessModes,
Size: storage,
Size: storage,
}, nil
}

Expand Down
31 changes: 20 additions & 11 deletions cyclops-ctrl/internal/cluster/k8sclient/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package k8sclient

import (
"context"
"github.com/pkg/errors"
"sort"
"strings"

Expand All @@ -14,9 +15,7 @@ import (
yaml2 "k8s.io/apimachinery/pkg/util/yaml"

cyclopsv1alpha1 "github.com/cyclops-ui/cyclops/cyclops-ctrl/api/v1alpha1"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/models"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/models/dto"
template2 "github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/template"
)

const (
Expand Down Expand Up @@ -65,14 +64,15 @@ func (k *KubernetesClient) GetResourcesForModule(name string) ([]dto.Resource, e
}

for _, apiResource := range resource.APIResources {
if gvk.Group == "discovery.k8s.io" && gvk.Version == "v1" && apiResource.Kind == "EndpointSlice" {
if gvk.Group == "discovery.k8s.io" && gvk.Version == "v1" && apiResource.Kind == "EndpointSlice" ||
gvk.Group == "" && gvk.Version == "v1" && apiResource.Kind == "Endpoints" {
continue
}

rs, err := k.Dynamic.Resource(schema.GroupVersionResource{
Group: gvk.Group,
Version: gvk.Version,
Resource: strings.ToLower(apiResource.Kind) + "s",
Resource: apiResource.Name,
}).List(context.Background(), metav1.ListOptions{
LabelSelector: "cyclops.module=" + name,
})
Expand Down Expand Up @@ -116,14 +116,8 @@ func (k *KubernetesClient) GetResourcesForModule(name string) ([]dto.Resource, e

func (k *KubernetesClient) GetDeletedResources(
resources []dto.Resource,
module cyclopsv1alpha1.Module,
template *models.Template,
manifest string,
) ([]dto.Resource, error) {
manifest, err := template2.HelmTemplate(module, template)
if err != nil {
return nil, err
}

resourcesFromTemplate := make(map[string][]dto.Resource, 0)

for _, s := range strings.Split(manifest, "---") {
Expand Down Expand Up @@ -238,6 +232,21 @@ func (k *KubernetesClient) GetModuleResourcesHealth(name string) (string, error)
return statusHealthy, nil
}

func (k *KubernetesClient) GVKtoAPIResourceName(gv schema.GroupVersion, kind string) (string, error) {
apiResources, err := k.clientset.Discovery().ServerResourcesForGroupVersion(gv.String())
if err != nil {
return "", err
}

for _, resource := range apiResources.APIResources {
if resource.Kind == kind && len(resource.Name) != 0 {
return resource.Name, nil
}
}

return "", errors.Errorf("could not find api-resource for groupVersion: %v and kind: %v", gv.String(), kind)
}

func (k *KubernetesClient) getResourceStatus(o unstructured.Unstructured) (string, error) {
if isPod(o.GroupVersionKind().Group, o.GroupVersionKind().Version, o.GetKind()) {
pod, err := k.clientset.CoreV1().Pods(o.GetNamespace()).Get(context.Background(), o.GetName(), metav1.GetOptions{})
Expand Down
23 changes: 17 additions & 6 deletions cyclops-ctrl/internal/controller/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,28 @@ import (
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/prometheus"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/telemetry"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/template"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/template/render"
)

type Modules struct {
kubernetesClient *k8sclient.KubernetesClient
templatesRepo *template.Repo
renderer *render.Renderer
telemetryClient telemetry.Client
monitor prometheus.Monitor
}

func NewModulesController(
templatesRepo *template.Repo,
kubernetes *k8sclient.KubernetesClient,
renderer *render.Renderer,
telemetryClient telemetry.Client,
monitor prometheus.Monitor,
) *Modules {
return &Modules{
kubernetesClient: kubernetes,
templatesRepo: templatesRepo,
renderer: renderer,
telemetryClient: telemetryClient,
monitor: monitor,
}
Expand Down Expand Up @@ -132,7 +136,7 @@ func (m *Modules) Manifest(ctx *gin.Context) {
return
}

manifest, err := template.HelmTemplate(v1alpha1.Module{Spec: request}, targetTemplate)
manifest, err := m.renderer.HelmTemplate(v1alpha1.Module{Spec: request}, targetTemplate)
if err != nil {
fmt.Println(err)
ctx.Status(http.StatusInternalServerError)
Expand Down Expand Up @@ -166,7 +170,7 @@ func (m *Modules) CurrentManifest(ctx *gin.Context) {
return
}

manifest, err := template.HelmTemplate(*module, targetTemplate)
manifest, err := m.renderer.HelmTemplate(*module, targetTemplate)
if err != nil {
fmt.Println(err)
ctx.Status(http.StatusInternalServerError)
Expand Down Expand Up @@ -308,7 +312,14 @@ func (m *Modules) ResourcesForModule(ctx *gin.Context) {
return
}

resources, err = m.kubernetesClient.GetDeletedResources(resources, *module, t)
manifest, err := m.renderer.HelmTemplate(*module, t)
if err != nil {
fmt.Println(err)
ctx.JSON(http.StatusInternalServerError, dto.NewError("Error rendering Module manifest", err.Error()))
return
}

resources, err = m.kubernetesClient.GetDeletedResources(resources, manifest)
if err != nil {
fmt.Println(err)
ctx.JSON(http.StatusInternalServerError, dto.NewError("Error fetching deleted module resources", err.Error()))
Expand Down Expand Up @@ -339,7 +350,7 @@ func (m *Modules) Template(ctx *gin.Context) {
return
}

currentManifest, err := template.HelmTemplate(*module, currentTemplate)
currentManifest, err := m.renderer.HelmTemplate(*module, currentTemplate)
if err != nil {
fmt.Println(err)
ctx.JSON(http.StatusInternalServerError, dto.NewError("Error templating current", err.Error()))
Expand All @@ -357,7 +368,7 @@ func (m *Modules) Template(ctx *gin.Context) {
return
}

proposedManifest, err := template.HelmTemplate(*module, proposedTemplate)
proposedManifest, err := m.renderer.HelmTemplate(*module, proposedTemplate)
if err != nil {
fmt.Println(err)
ctx.JSON(http.StatusInternalServerError, dto.NewError("Error templating proposed", err.Error()))
Expand Down Expand Up @@ -393,7 +404,7 @@ func (m *Modules) HelmTemplate(ctx *gin.Context) {
return
}

_, err = template.HelmTemplate(*module, currentTemplate)
_, err = m.renderer.HelmTemplate(*module, currentTemplate)
if err != nil {
fmt.Println(err)
ctx.JSON(http.StatusInternalServerError, dto.NewError("Error templating", err.Error()))
Expand Down
7 changes: 6 additions & 1 deletion cyclops-ctrl/internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import (
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/prometheus"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/telemetry"
templaterepo "github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/template"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/template/render"
)

type Handler struct {
router *gin.Engine

templatesRepo *templaterepo.Repo
k8sClient *k8sclient.KubernetesClient
renderer *render.Renderer

telemetryClient telemetry.Client
monitor prometheus.Monitor
Expand All @@ -25,12 +27,14 @@ type Handler struct {
func New(
templatesRepo *templaterepo.Repo,
kubernetesClient *k8sclient.KubernetesClient,
renderer *render.Renderer,
telemetryClient telemetry.Client,
monitor prometheus.Monitor,
) (*Handler, error) {
return &Handler{
templatesRepo: templatesRepo,
k8sClient: kubernetesClient,
renderer: renderer,
telemetryClient: telemetryClient,
monitor: monitor,
router: gin.New(),
Expand All @@ -39,8 +43,9 @@ func New(

func (h *Handler) Start() error {
gin.SetMode(gin.DebugMode)

templatesController := controller.NewTemplatesController(h.templatesRepo, h.k8sClient)
modulesController := controller.NewModulesController(h.templatesRepo, h.k8sClient, h.telemetryClient, h.monitor)
modulesController := controller.NewModulesController(h.templatesRepo, h.k8sClient, h.renderer, h.telemetryClient, h.monitor)
clusterController := controller.NewClusterController(h.k8sClient)

h.router = gin.New()
Expand Down
Loading

0 comments on commit ba0a744

Please sign in to comment.