Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cyclops-ctrl/cmd/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func main() {

prometheus.StartCacheMetricsUpdater(&monitor, templatesRepo.ReturnCache(), 10*time.Second, setupLog)

helmReleaseClient := helm.NewReleaseClient(helmWatchNamespace)
helmReleaseClient := helm.NewReleaseClient(helmWatchNamespace, k8sClient)
gitWriteClient := git.NewWriteClient(credsResolver, getCommitMessageTemplate(), setupLog)

handler, err := handler.New(templatesRepo, k8sClient, helmReleaseClient, renderer, gitWriteClient, moduleTargetNamespace, telemetryClient, monitor)
Expand Down
3 changes: 2 additions & 1 deletion cyclops-ctrl/internal/controller/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,10 @@ func (h *Helm) UninstallRelease(ctx *gin.Context) {
func (h *Helm) GetReleaseResources(ctx *gin.Context) {
ctx.Header("Access-Control-Allow-Origin", "*")

namespace := ctx.Param("namespace")
name := ctx.Param("name")

resources, err := h.kubernetesClient.GetResourcesForRelease(name)
resources, err := h.releaseClient.ListResources(namespace, name)
if err != nil {
fmt.Println(err)
ctx.JSON(http.StatusBadRequest, dto.NewError("Error fetching Helm release resources", err.Error()))
Expand Down
2 changes: 1 addition & 1 deletion cyclops-ctrl/internal/controller/sse/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (s *Server) Resources(ctx *gin.Context) {
}

func (s *Server) ReleaseResources(ctx *gin.Context) {
resources, err := s.k8sClient.GetWorkloadsForRelease(ctx.Param("name"))
resources, err := s.releaseClient.ListWorkloadsForRelease(ctx.Param("namespace"), ctx.Param("name"))
if err != nil {
ctx.String(http.StatusInternalServerError, err.Error())
return
Expand Down
9 changes: 6 additions & 3 deletions cyclops-ctrl/internal/controller/sse/server.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package sse

import (
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/integrations/helm"
"github.com/gin-gonic/gin"

"github.com/cyclops-ui/cyclops/cyclops-ctrl/pkg/cluster/k8sclient"
)

type Server struct {
k8sClient k8sclient.IKubernetesClient
k8sClient k8sclient.IKubernetesClient
releaseClient *helm.ReleaseClient
}

// Initialize event and Start procnteessing requests
func NewServer(k8sClient k8sclient.IKubernetesClient) *Server {
func NewServer(k8sClient k8sclient.IKubernetesClient, releaseClient *helm.ReleaseClient) *Server {
server := &Server{
k8sClient: k8sClient,
k8sClient: k8sClient,
releaseClient: releaseClient,
}

return server
Expand Down
4 changes: 2 additions & 2 deletions cyclops-ctrl/internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ func (h *Handler) Start() error {

h.router = gin.New()

server := sse.NewServer(h.k8sClient)
server := sse.NewServer(h.k8sClient, h.releaseClient)

h.router.GET("/stream/resources/:name", sse.HeadersMiddleware(), server.Resources)
h.router.GET("/stream/releases/resources/:name", sse.HeadersMiddleware(), server.ReleaseResources)
h.router.GET("/stream/releases/:namespace/:name/resources", sse.HeadersMiddleware(), server.ReleaseResources)
h.router.POST("/stream/resources", sse.HeadersMiddleware(), server.SingleResource)

h.router.GET("/ping", h.pong())
Expand Down
86 changes: 85 additions & 1 deletion cyclops-ctrl/internal/integrations/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ package helm

import (
"fmt"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/internal/models/dto"
"github.com/cyclops-ui/cyclops/cyclops-ctrl/pkg/cluster/k8sclient"
"io"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"log"
"sort"
"strings"

"github.com/pkg/errors"
Expand All @@ -16,14 +21,18 @@ import (

type ReleaseClient struct {
namespace string
k8sClient k8sclient.IKubernetesClient
}

func NewReleaseClient(namespace string) *ReleaseClient {
func NewReleaseClient(namespace string, k8sClient k8sclient.IKubernetesClient) *ReleaseClient {
return &ReleaseClient{
namespace: strings.TrimSpace(namespace),
k8sClient: k8sClient,
}
}

func noopLogger(format string, v ...interface{}) {}

func (r *ReleaseClient) ListReleases() ([]*release.Release, error) {
settings := cli.New()

Expand Down Expand Up @@ -119,3 +128,78 @@ func (r *ReleaseClient) UpgradeRelease(
_, err = client.Run(name, current.Chart, values)
return err
}

func (r *ReleaseClient) ListResources(namespace string, name string) ([]dto.Resource, error) {
if len(r.namespace) > 0 && namespace != r.namespace {
return nil, errors.New(fmt.Sprintf("invalid namespace provided: %v", namespace))
}

settings := cli.New()
settings.SetNamespace(namespace)

actionConfig := new(action.Configuration)
if err := actionConfig.Init(settings.RESTClientGetter(), namespace, "", noopLogger); err != nil {
return nil, err
}

client := action.NewStatus(actionConfig)
client.ShowResources = true

releaseStatus, err := client.Run(name)
if err != nil {
return nil, err
}

if releaseStatus.Info == nil {
return nil, errors.New("empty release info resources")
}

out := make([]dto.Resource, 0, 0)
for gv, objs := range releaseStatus.Info.Resources {
if strings.HasSuffix(gv, "(related)") {
continue
}

for _, obj := range objs {
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
if err != nil {
return nil, err
}

res, err := r.k8sClient.MapUnstructuredResource(unstructured.Unstructured{Object: u})
if err != nil {
return nil, err
}

out = append(out, res)
}
}

sort.Slice(out, func(i, j int) bool {
if out[i].GetGroupVersionKind() != out[j].GetGroupVersionKind() {
return out[i].GetGroupVersionKind() < out[j].GetGroupVersionKind()
}

return out[i].GetName() < out[j].GetName()
})

return out, nil
}

func (r *ReleaseClient) ListWorkloadsForRelease(namespace, name string) ([]dto.Resource, error) {
resources, err := r.ListResources(namespace, name)
if err != nil {
return nil, err
}

workloads := make([]dto.Resource, 0, 0)
for _, resource := range resources {
if resource.GetGroup() == "apps" &&
resource.GetVersion() == "v1" &&
(resource.GetKind() == "Deployment" || resource.GetKind() == "DaemonSet" || resource.GetKind() == "StatefulSet") {
workloads = append(workloads, resource)
}
}

return workloads, nil
}
1 change: 1 addition & 0 deletions cyclops-ctrl/pkg/cluster/k8sclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type IKubernetesClient interface {
DeleteModule(name string) error
GetModule(name string) (*cyclopsv1alpha1.Module, error)
GetResourcesForModule(name string) ([]dto.Resource, error)
MapUnstructuredResource(u unstructured.Unstructured) (dto.Resource, error)
GetWorkloadsForModule(name string) ([]dto.Resource, error)
GetDeletedResources([]dto.Resource, string, string) ([]dto.Resource, error)
GetModuleResourcesHealth(name string) (string, error)
Expand Down
29 changes: 19 additions & 10 deletions cyclops-ctrl/pkg/cluster/k8sclient/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,12 @@ func (k *KubernetesClient) GetResourcesForModule(name string) ([]dto.Resource, e
}

for _, o := range other {
status, err := k.getResourceStatus(o)
res, err := k.MapUnstructuredResource(o)
if err != nil {
return nil, err
}

out = append(out, &dto.Other{
Group: o.GroupVersionKind().Group,
Version: o.GroupVersionKind().Version,
Kind: o.GroupVersionKind().Kind,
Name: o.GetName(),
Namespace: o.GetNamespace(),
Status: status,
Deleted: false,
})
out = append(out, res)
}

sort.Slice(out, func(i, j int) bool {
Expand All @@ -121,6 +113,23 @@ func (k *KubernetesClient) GetResourcesForModule(name string) ([]dto.Resource, e
return out, nil
}

func (k *KubernetesClient) MapUnstructuredResource(u unstructured.Unstructured) (dto.Resource, error) {
status, err := k.getResourceStatus(u)
if err != nil {
return nil, err
}

return &dto.Other{
Group: u.GroupVersionKind().Group,
Version: u.GroupVersionKind().Version,
Kind: u.GroupVersionKind().Kind,
Name: u.GetName(),
Namespace: u.GetNamespace(),
Status: status,
Deleted: false,
}, nil
}

func (k *KubernetesClient) GetWorkloadsForModule(name string) ([]dto.Resource, error) {
out := make([]dto.Resource, 0, 0)

Expand Down
58 changes: 58 additions & 0 deletions cyclops-ctrl/pkg/mocks/IKubernetesClient.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export const HelmReleaseDetails = ({
useEffect(() => {
if (isStreamingEnabled()) {
resourcesStream(
`/stream/releases/resources/${releaseName}`,
`/stream/releases/${releaseNamespace}/${releaseName}/resources`,
(r: any) => {
let resourceRef: ResourceRef = {
group: r.group,
Expand All @@ -281,7 +281,7 @@ export const HelmReleaseDetails = ({
resourceStreamImplementation,
);
}
}, [releaseName, resourceStreamImplementation]);
}, [releaseNamespace, releaseName, resourceStreamImplementation]);

const resourceLoading = () => {
if (!loadModule) {
Expand Down