Jelajahi Sumber

add kube events endpoints

Alexander Belanger 4 tahun lalu
induk
melakukan
13a239b71d

+ 218 - 0
api/server/handlers/kube_events/create.go

@@ -0,0 +1,218 @@
+package kube_events
+
+import (
+	"net/http"
+	"strings"
+
+	"github.com/porter-dev/porter/api/server/authz"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type CreateKubeEventHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewCreateKubeEventHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *CreateKubeEventHandler {
+	return &CreateKubeEventHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *CreateKubeEventHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+
+	request := &types.CreateKubeEventRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	// handle write to the database
+	_, err := c.Repo().KubeEvent().CreateEvent(&models.KubeEvent{
+		ProjectID:    proj.ID,
+		ClusterID:    cluster.ID,
+		ResourceType: request.ResourceType,
+		Name:         request.Name,
+		OwnerType:    request.OwnerType,
+		OwnerName:    request.OwnerName,
+		EventType:    request.EventType,
+		Namespace:    request.Namespace,
+		Message:      request.Message,
+		Reason:       request.Reason,
+		Timestamp:    request.Timestamp,
+		Data:         []byte(strings.Join(request.Data, "\n")),
+	})
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	w.WriteHeader(http.StatusCreated)
+}
+
+// func (app *App) HandleCreateEvent(w http.ResponseWriter, r *http.Request) {
+// 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
+
+// 	if err != nil || projID == 0 {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	clusterID, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
+
+// 	if err != nil {
+// 		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
+// 			Code:   ErrReleaseReadData,
+// 			Errors: []string{"cluster not found"},
+// 		}, w)
+// 	}
+
+// 	form := &forms.CreateEventForm{}
+
+// 	// decode from JSON to form value
+// 	if err := json.NewDecoder(r.Body).Decode(form); err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	// validate the form
+// 	if err := app.validator.Struct(form); err != nil {
+// 		app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
+// 		return
+// 	}
+
+// 	// convert the form to an invite
+// 	event := form.ToEvent(uint(projID), uint(clusterID))
+
+// 	if err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	// handle write to the database
+// 	event, err = app.Repo.Event.CreateEvent(event)
+
+// 	if err != nil {
+// 		app.handleErrorDataWrite(err, w)
+// 		return
+// 	}
+
+// 	w.WriteHeader(http.StatusCreated)
+// }
+
+// // HandleListEvents lists the events that match certain conditions in a project
+// func (app *App) HandleListEvents(w http.ResponseWriter, r *http.Request) {
+// 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
+
+// 	if err != nil || projID == 0 {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	clusterID, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
+
+// 	if err != nil {
+// 		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
+// 			Code:   ErrReleaseReadData,
+// 			Errors: []string{"cluster not found"},
+// 		}, w)
+// 	}
+
+// 	vals, err := url.ParseQuery(r.URL.RawQuery)
+
+// 	opts := &repository.ListEventOpts{
+// 		ClusterID: uint(clusterID),
+// 	}
+
+// 	decoder := schema.NewDecoder()
+
+// 	decoder.IgnoreUnknownKeys(true)
+
+// 	if err := decoder.Decode(opts, vals); err != nil {
+// 		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
+// 			Code:   ErrReleaseReadData,
+// 			Errors: []string{"bad request"},
+// 		}, w)
+// 	}
+
+// 	// handle write to the database
+// 	events, err := app.Repo.Event.ListEventsByProjectID(uint(projID), opts)
+
+// 	if err != nil {
+// 		app.handleErrorDataWrite(err, w)
+// 		return
+// 	}
+
+// 	eventExts := make([]*models.EventExternalSimple, 0)
+
+// 	for _, event := range events {
+// 		eventExts = append(eventExts, event.ExternalizeSimple())
+// 	}
+
+// 	w.WriteHeader(http.StatusOK)
+
+// 	if err := json.NewEncoder(w).Encode(eventExts); err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+// }
+
+// // HandleListEvents lists the events that match certain conditions in a project
+// func (app *App) HandleGetEvent(w http.ResponseWriter, r *http.Request) {
+// 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
+
+// 	if err != nil || projID == 0 {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	clusterID, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
+
+// 	if err != nil {
+// 		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
+// 			Code:   ErrReleaseReadData,
+// 			Errors: []string{"cluster not found"},
+// 		}, w)
+// 	}
+
+// 	eventID, err := strconv.ParseUint(chi.URLParam(r, "event_id"), 0, 64)
+
+// 	if err != nil || projID == 0 {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	event, err := app.Repo.Event.ReadEvent(uint(eventID), uint(projID), uint(clusterID))
+
+// 	if err != nil {
+// 		if err == gorm.ErrRecordNotFound {
+// 			http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
+// 			return
+// 		}
+
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	eventExt := event.Externalize()
+
+// 	w.WriteHeader(http.StatusOK)
+
+// 	if err := json.NewEncoder(w).Encode(eventExt); err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+// }

+ 46 - 0
api/server/handlers/kube_events/get.go

@@ -0,0 +1,46 @@
+package kube_events
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/authz"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/server/shared/requestutils"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type GetKubeEventHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewGetKubeEventHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *GetKubeEventHandler {
+	return &GetKubeEventHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *GetKubeEventHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+	kubeEventID, _ := requestutils.GetURLParamUint(r, types.URLParamKubeEventID)
+
+	// handle write to the database
+	kubeEvent, err := c.Repo().KubeEvent().ReadEvent(kubeEventID, proj.ID, cluster.ID)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	c.WriteResult(w, r, kubeEvent.ToKubeEventType())
+}

+ 56 - 0
api/server/handlers/kube_events/list.go

@@ -0,0 +1,56 @@
+package kube_events
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/authz"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type ListKubeEventsHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewListKubeEventsHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *ListKubeEventsHandler {
+	return &ListKubeEventsHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *ListKubeEventsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+
+	request := &types.ListKubeEventRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	// handle write to the database
+	kubeEvents, err := c.Repo().KubeEvent().ListEventsByProjectID(proj.ID, cluster.ID, request, false)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	resp := make([]*types.KubeEventBasic, 0)
+
+	for _, kubeEvent := range kubeEvents {
+		resp = append(resp, kubeEvent.ToKubeEventBasicType())
+	}
+
+	c.WriteResult(w, r, resp)
+}

+ 88 - 0
api/server/router/cluster.go

@@ -5,6 +5,7 @@ import (
 
 	"github.com/go-chi/chi"
 	"github.com/porter-dev/porter/api/server/handlers/cluster"
+	"github.com/porter-dev/porter/api/server/handlers/kube_events"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/api/types"
@@ -505,6 +506,93 @@ func getClusterRoutes(
 		Router:   r,
 	})
 
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/kube_events -> kube_events.NewGetKubeEventHandler
+	listKubeEventsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/kube_events",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+			},
+		},
+	)
+
+	listKubeEventsHandler := kube_events.NewListKubeEventsHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: listKubeEventsEndpoint,
+		Handler:  listKubeEventsHandler,
+		Router:   r,
+	})
+
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/kube_events -> kube_events.NewGetKubeEventHandler
+	getKubeEventEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: fmt.Sprintf("%s/kube_events/%s", relPath, types.URLParamKubeEventID),
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+			},
+		},
+	)
+
+	getKubeEventHandler := kube_events.NewGetKubeEventHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: getKubeEventEndpoint,
+		Handler:  getKubeEventHandler,
+		Router:   r,
+	})
+
+	// POST /api/projects/{project_id}/clusters/{cluster_id}/kube_events -> kube_events.NewCreateKubeEventHandler
+	createKubeEventsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbCreate,
+			Method: types.HTTPVerbPost,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/kube_events",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+			},
+		},
+	)
+
+	createKubeEventsHandler := kube_events.NewCreateKubeEventHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: createKubeEventsEndpoint,
+		Handler:  createKubeEventsHandler,
+		Router:   r,
+	})
+
 	// GET /api/projects/{project_id}/clusters/{cluster_id}/prometheus/ingresses -> cluster.NewListNGINXIngressesHandler
 	listNGINXIngressesEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{

+ 4 - 0
api/types/kube_events.go

@@ -2,6 +2,10 @@ package types
 
 import "time"
 
+const (
+	URLParamKubeEventID = "kube_event_id"
+)
+
 // CreateKubeEventRequest is the type for creating a new kube event
 type CreateKubeEventRequest struct {
 	ResourceType string    `json:"resource_type"`