diff --git a/App/Backend/cmd/kubernetes/Setup.go b/App/Backend/cmd/kubernetes/Setup.go index 38a9e39..24ecea2 100644 --- a/App/Backend/cmd/kubernetes/Setup.go +++ b/App/Backend/cmd/kubernetes/Setup.go @@ -49,6 +49,24 @@ func TestFakeClient() IClient { }, }, }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "node-3", + Labels: map[string]string{ + "kubernetes.io/role": "master", + "version": "v1.25.0", + }, + CreationTimestamp: metav1.NewTime(time.Now().Add(-48 * time.Hour)), + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + {Type: corev1.NodeReady, Status: corev1.ConditionTrue}, + }, + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeInternalIP, Address: "192.168.1.3"}, + }, + }, + }, } for _, node := range nodes { clientset.GetNodes().Create(context.TODO(), node, metav1.CreateOptions{}) @@ -85,9 +103,25 @@ func TestFakeClient() IClient { }, Spec: corev1.PodSpec{NodeName: "node-2"}, }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "pod-3", + Namespace: "test", + Labels: map[string]string{"app": "test-app"}, + }, + Status: corev1.PodStatus{ + Phase: corev1.PodPending, + PodIP: "10.0.0.3", + ContainerStatuses: []corev1.ContainerStatus{ + {RestartCount: 1}, + }, + }, + Spec: corev1.PodSpec{NodeName: "node-3"}, + }, } for _, pod := range pods { - clientset.GetPods("default").Create(context.TODO(), pod, metav1.CreateOptions{}) + namespace := pod.GetNamespace() + clientset.GetPods(namespace).Create(context.TODO(), pod, metav1.CreateOptions{}) } services := []*corev1.Service{ @@ -99,9 +133,18 @@ func TestFakeClient() IClient { Selector: map[string]string{"app": "test-app"}, }, }, + { + ObjectMeta: metav1.ObjectMeta{Name: "service-2", Namespace: "test"}, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + ClusterIP: "10.100.1.2", + Selector: map[string]string{"app": "test-app"}, + }, + }, } for _, service := range services { - clientset.GetServices("default").Create(context.TODO(), service, metav1.CreateOptions{}) + namespace := service.GetNamespace() + clientset.GetServices(namespace).Create(context.TODO(), service, metav1.CreateOptions{}) } var replicas int32 = 3 @@ -120,9 +163,23 @@ func TestFakeClient() IClient { AvailableReplicas: 2, }, }, + { + ObjectMeta: metav1.ObjectMeta{Name: "deployment-2", Namespace: "test"}, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "test-app"}}, + }, + Status: appsv1.DeploymentStatus{ + Replicas: 3, + ReadyReplicas: 2, + UpdatedReplicas: 3, + AvailableReplicas: 2, + }, + }, } for _, deployment := range deployments { - clientset.GetDeployments("default").Create(context.TODO(), deployment, metav1.CreateOptions{}) + namespace := deployment.GetNamespace() + clientset.GetDeployments(namespace).Create(context.TODO(), deployment, metav1.CreateOptions{}) } secrets := []*corev1.Secret{ @@ -131,9 +188,15 @@ func TestFakeClient() IClient { Type: corev1.SecretTypeOpaque, Data: map[string][]byte{"password": []byte("supersecret")}, }, + { + ObjectMeta: metav1.ObjectMeta{Name: "secret-2", Namespace: "test"}, + Type: corev1.SecretTypeOpaque, + Data: map[string][]byte{"password": []byte("supersecret")}, + }, } for _, secret := range secrets { - clientset.GetSecrets("default").Create(context.TODO(), secret, metav1.CreateOptions{}) + namespace := secret.GetNamespace() + clientset.GetSecrets(namespace).Create(context.TODO(), secret, metav1.CreateOptions{}) } configMaps := []*corev1.ConfigMap{ @@ -141,9 +204,14 @@ func TestFakeClient() IClient { ObjectMeta: metav1.ObjectMeta{Name: "configmap-1", Namespace: "default"}, Data: map[string]string{"config": "value"}, }, + { + ObjectMeta: metav1.ObjectMeta{Name: "configmap-2", Namespace: "test"}, + Data: map[string]string{"config": "value"}, + }, } for _, configMap := range configMaps { - clientset.GetConfigMaps("default").Create(context.TODO(), configMap, metav1.CreateOptions{}) + namespace := configMap.GetNamespace() + clientset.GetConfigMaps(namespace).Create(context.TODO(), configMap, metav1.CreateOptions{}) } return clientset diff --git a/App/Backend/cmd/kubernetes/handlers/GetConfigMaps.go b/App/Backend/cmd/kubernetes/handlers/GetConfigMaps.go index 7cedbf5..d6edb35 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetConfigMaps.go +++ b/App/Backend/cmd/kubernetes/handlers/GetConfigMaps.go @@ -10,7 +10,17 @@ import ( ) func GetConfigMapsHandler(ctx *gin.Context) { - configMapList, err := GetConfigMaps(c) + namespace, ok := ctx.GetQuery("namespace") + + var configMapList *[]kubernetes.ConfigMap + var err error + + if ok { + configMapList, err = GetConfigMaps(c, namespace) + } else { + configMapList, err = GetConfigMaps(c, "") + } + if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "An error has occurred or the request has been timed out."}) return @@ -18,11 +28,11 @@ func GetConfigMapsHandler(ctx *gin.Context) { ctx.JSON(http.StatusOK, configMapList) } -func GetConfigMaps(c kubernetes.IClient) (*[]kubernetes.ConfigMap, error) { +func GetConfigMaps(c kubernetes.IClient, namespace string) (*[]kubernetes.ConfigMap, error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := c.GetConfigMaps("").List(ct, metav1.ListOptions{}) + list, err := c.GetConfigMaps(namespace).List(ct, metav1.ListOptions{}) if err != nil { return nil, err } diff --git a/App/Backend/cmd/kubernetes/handlers/GetDeployments.go b/App/Backend/cmd/kubernetes/handlers/GetDeployments.go index ce38c12..e1fe783 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetDeployments.go +++ b/App/Backend/cmd/kubernetes/handlers/GetDeployments.go @@ -10,7 +10,18 @@ import ( ) func GetDeploymentsHandler(ctx *gin.Context) { - deploymentList, err := GetDeployments(c) + + namespace, ok := ctx.GetQuery("namespace") + + var deploymentList *[]kubernetes.Deployment + var err error + + if ok { + deploymentList, err = GetDeployments(c, namespace) + } else { + deploymentList, err = GetDeployments(c, "") + } + if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "An error has occurred or the request has been timed out."}) return @@ -18,11 +29,11 @@ func GetDeploymentsHandler(ctx *gin.Context) { ctx.JSON(http.StatusOK, deploymentList) } -func GetDeployments(c kubernetes.IClient) (*[]kubernetes.Deployment, error) { +func GetDeployments(c kubernetes.IClient, namespace string) (*[]kubernetes.Deployment, error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := c.GetDeployments("").List(ct, metav1.ListOptions{}) + list, err := c.GetDeployments(namespace).List(ct, metav1.ListOptions{}) if err != nil { return nil, err } diff --git a/App/Backend/cmd/kubernetes/handlers/GetPods.go b/App/Backend/cmd/kubernetes/handlers/GetPods.go index da432e3..a566c88 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetPods.go +++ b/App/Backend/cmd/kubernetes/handlers/GetPods.go @@ -10,7 +10,17 @@ import ( ) func GetPodsHandler(ctx *gin.Context) { - podList, err := GetPods(c) + namespace, ok := ctx.GetQuery("namespace") + + var podList *[]kubernetes.Pod + var err error + + if ok { + podList, err = GetPods(c, namespace) + } else { + podList, err = GetPods(c, "") + } + if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "An error has occurred or the request has been timed out."}) return @@ -18,11 +28,11 @@ func GetPodsHandler(ctx *gin.Context) { ctx.JSON(http.StatusOK, podList) } -func GetPods(c kubernetes.IClient) (*[]kubernetes.Pod, error) { +func GetPods(c kubernetes.IClient, namespace string) (*[]kubernetes.Pod, error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := c.GetPods("").List(ct, metav1.ListOptions{}) + list, err := c.GetPods(namespace).List(ct, metav1.ListOptions{}) if err != nil { return nil, err } diff --git a/App/Backend/cmd/kubernetes/handlers/GetSecrets.go b/App/Backend/cmd/kubernetes/handlers/GetSecrets.go index e94aa26..099b926 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetSecrets.go +++ b/App/Backend/cmd/kubernetes/handlers/GetSecrets.go @@ -10,19 +10,28 @@ import ( ) func GetSecretsHandler(ctx *gin.Context) { - nodeList, err := GetSecrets(c) + namespace, ok := ctx.GetQuery("namespace") + + var secretList *[]kubernetes.Secret + var err error + + if ok { + secretList, err = GetSecrets(c, namespace) + } else { + secretList, err = GetSecrets(c, "") + } if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "An error has occurred or the request has been timed out."}) return } - ctx.JSON(http.StatusOK, nodeList) + ctx.JSON(http.StatusOK, secretList) } -func GetSecrets(c kubernetes.IClient) (*[]kubernetes.Secret, error) { +func GetSecrets(c kubernetes.IClient, namespace string) (*[]kubernetes.Secret, error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := c.GetSecrets("").List(ct, metav1.ListOptions{}) + list, err := c.GetSecrets(namespace).List(ct, metav1.ListOptions{}) if err != nil { return nil, err } diff --git a/App/Backend/cmd/kubernetes/handlers/GetServices.go b/App/Backend/cmd/kubernetes/handlers/GetServices.go index af03459..0e99c49 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetServices.go +++ b/App/Backend/cmd/kubernetes/handlers/GetServices.go @@ -10,19 +10,29 @@ import ( ) func GetServicesHandler(ctx *gin.Context) { - podList, err := GetServices(c) + namespace, ok := ctx.GetQuery("namespace") + + var serviceList *[]kubernetes.Service + var err error + + if ok { + serviceList, err = GetServices(c, namespace) + } else { + serviceList, err = GetServices(c, "") + } + if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "An error has occurred or the request has been timed out."}) return } - ctx.JSON(http.StatusOK, podList) + ctx.JSON(http.StatusOK, serviceList) } -func GetServices(c kubernetes.IClient) (*[]kubernetes.Service, error) { +func GetServices(c kubernetes.IClient, namespace string) (*[]kubernetes.Service, error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := c.GetServices("").List(ct, metav1.ListOptions{}) + list, err := c.GetServices(namespace).List(ct, metav1.ListOptions{}) if err != nil { return nil, err } diff --git a/App/Backend/cmd/kubernetes/handlers/GetTableHandler.go b/App/Backend/cmd/kubernetes/handlers/GetTableHandler.go new file mode 100644 index 0000000..18c7c30 --- /dev/null +++ b/App/Backend/cmd/kubernetes/handlers/GetTableHandler.go @@ -0,0 +1,59 @@ +package handlers + +import ( + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +type Element string + +const ( + Nodes Element = "nodes" + Pods Element = "pods" + Services Element = "services" + Deployments Element = "deployments" + ConfigMaps Element = "configmaps" + Secrets Element = "secrets" +) + +func isValidElement(e Element) bool { + switch e { + case Nodes, Pods, Services, Deployments, ConfigMaps, Secrets: + return true + default: + return false + } +} + +func GetTableHandler(ctx *gin.Context) { + + elementType, elementOk := ctx.GetQuery("element") + + if !elementOk { + ctx.JSON(http.StatusBadRequest, gin.H{"Error": "Missing query parameter 'element'"}) + return + } + + element := Element(strings.ToLower(elementType)) + if !isValidElement(element) { + ctx.JSON(http.StatusBadRequest, gin.H{"Error": "Invalid query parameter 'element'"}) + return + } + + switch element { + case Nodes: + GetNodesHandler(ctx) + case Pods: + GetPodsHandler(ctx) + case Services: + GetServicesHandler(ctx) + case Deployments: + GetDeploymentsHandler(ctx) + case ConfigMaps: + GetConfigMapsHandler(ctx) + case Secrets: + GetSecretsHandler(ctx) + } + +} diff --git a/App/Backend/cmd/main.go b/App/Backend/cmd/main.go index a757933..48c5f78 100644 --- a/App/Backend/cmd/main.go +++ b/App/Backend/cmd/main.go @@ -20,6 +20,7 @@ func main() { secured := r.Group("/secured") secured.Use(auth.AuthMiddleware()) + secured.GET("/table", handlers.GetTableHandler) secured.GET("/nodes", handlers.GetNodesHandler) secured.GET("/pods", handlers.GetPodsHandler) secured.GET("/services", handlers.GetServicesHandler) diff --git a/App/Backend/test.http b/App/Backend/test.http index e18baee..60ba131 100644 --- a/App/Backend/test.http +++ b/App/Backend/test.http @@ -25,4 +25,10 @@ GET {{base}}/secured/configMaps GET {{base}}/secured/secrets ### GET DEPLOYMENTS -GET {{base}}/secured/deployments \ No newline at end of file +GET {{base}}/secured/deployments + +### GET TABLE (Nodes) +GET {{base}}/secured/table?element=nodes + +### GET TABLE (Pods) +GET {{base}}/secured/table?element=pODs&namespace=test \ No newline at end of file diff --git a/App/Backend/testing/get_handler_test.go b/App/Backend/testing/get_handler_test.go index 51b6dc1..7a7acf2 100644 --- a/App/Backend/testing/get_handler_test.go +++ b/App/Backend/testing/get_handler_test.go @@ -19,7 +19,7 @@ func TestGetNodes(t *testing.T) { } func TestGetPods(t *testing.T) { - pods, err := handlers.GetPods(client) + pods, err := handlers.GetPods(client, "") assert.NoError(t, err) assert.NotEmpty(t, pods) @@ -27,34 +27,74 @@ func TestGetPods(t *testing.T) { assert.Equal(t, "pod-2", (*pods)[1].Name) } +func TestGetPodsWithNamespace(t *testing.T) { + pods, err := handlers.GetPods(client, "test") + + assert.NoError(t, err) + assert.NotEmpty(t, pods) + assert.Equal(t, "pod-3", (*pods)[0].Name) +} + func TestGetServices(t *testing.T) { - services, err := handlers.GetServices(client) + services, err := handlers.GetServices(client, "") assert.NoError(t, err) assert.NotEmpty(t, services) assert.Equal(t, "service-1", (*services)[0].Name) } +func TestGetServicesWithNamespace(t *testing.T) { + services, err := handlers.GetServices(client, "test") + + assert.NoError(t, err) + assert.NotEmpty(t, services) + assert.Equal(t, "service-2", (*services)[0].Name) +} + func TestGetDeployments(t *testing.T) { - deployments, err := handlers.GetDeployments(client) + deployments, err := handlers.GetDeployments(client, "") assert.NoError(t, err) assert.NotEmpty(t, deployments) assert.Equal(t, "deployment-1", (*deployments)[0].Name) } +func TestGetDeploymentsWithNamespace(t *testing.T) { + deployments, err := handlers.GetDeployments(client, "test") + + assert.NoError(t, err) + assert.NotEmpty(t, deployments) + assert.Equal(t, "deployment-2", (*deployments)[0].Name) +} + func TestGetConfigMaps(t *testing.T) { - maps, err := handlers.GetConfigMaps(client) + maps, err := handlers.GetConfigMaps(client, "") assert.NoError(t, err) assert.NotEmpty(t, maps) assert.Equal(t, "configmap-1", (*maps)[0].Name) } +func TestGetConfigMapsWithNamespace(t *testing.T) { + maps, err := handlers.GetConfigMaps(client, "test") + + assert.NoError(t, err) + assert.NotEmpty(t, maps) + assert.Equal(t, "configmap-2", (*maps)[0].Name) +} + func TestGetSecrets(t *testing.T) { - secrets, err := handlers.GetSecrets(client) + secrets, err := handlers.GetSecrets(client, "") assert.NoError(t, err) assert.NotEmpty(t, secrets) assert.Equal(t, "secret-1", (*secrets)[0].Name) } + +func TestGetSecretsWithNamespace(t *testing.T) { + secrets, err := handlers.GetSecrets(client, "test") + + assert.NoError(t, err) + assert.NotEmpty(t, secrets) + assert.Equal(t, "secret-2", (*secrets)[0].Name) +}