package router import ( "fmt" "github.com/go-chi/chi" "github.com/porter-dev/porter/api/server/handlers/job" "github.com/porter-dev/porter/api/server/handlers/namespace" "github.com/porter-dev/porter/api/server/shared" "github.com/porter-dev/porter/api/server/shared/config" "github.com/porter-dev/porter/api/types" ) func NewNamespaceScopedRegisterer(children ...*Registerer) *Registerer { return &Registerer{ GetRoutes: GetNamespaceScopedRoutes, Children: children, } } func GetNamespaceScopedRoutes( r chi.Router, config *config.Config, basePath *types.Path, factory shared.APIEndpointFactory, children ...*Registerer, ) []*Route { routes, projPath := getNamespaceRoutes(r, config, basePath, factory) if len(children) > 0 { r.Route(projPath.RelativePath, func(r chi.Router) { for _, child := range children { childRoutes := child.GetRoutes(r, config, basePath, factory, child.Children...) routes = append(routes, childRoutes...) } }) } return routes } func getNamespaceRoutes( r chi.Router, config *config.Config, basePath *types.Path, factory shared.APIEndpointFactory, ) ([]*Route, *types.Path) { relPath := "/namespaces/{namespace}" newPath := &types.Path{ Parent: basePath, RelativePath: relPath, } routes := make([]*Route, 0) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/configmap/list -> namespace.NewListConfigMapsHandler listConfigMapsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/configmap/list", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) listConfigMapsHandler := namespace.NewListConfigMapsHandler( config, factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: listConfigMapsEndpoint, Handler: listConfigMapsHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/configmap -> namespace.NewGetConfigMapHandler getConfigMapEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/configmap", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) getConfigMapHandler := namespace.NewGetConfigMapHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: getConfigMapEndpoint, Handler: getConfigMapHandler, Router: r, }) // POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/configmap/create -> namespace.NewCreateConfigMapHandler createConfigMapEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbCreate, Method: types.HTTPVerbPost, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/configmap/create", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) createConfigMapHandler := namespace.NewCreateConfigMapHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: createConfigMapEndpoint, Handler: createConfigMapHandler, Router: r, }) // POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/configmap/update -> namespace.NewUpdateConfigMapHandler updateConfigMapEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbUpdate, Method: types.HTTPVerbPost, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/configmap/update", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) updateConfigMapHandler := namespace.NewUpdateConfigMapHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: updateConfigMapEndpoint, Handler: updateConfigMapHandler, Router: r, }) // POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/configmap/rename -> namespace.NewRenameConfigMapHandler renameConfigMapEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbUpdate, Method: types.HTTPVerbPost, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/configmap/rename", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) renameConfigMapHandler := namespace.NewRenameConfigMapHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: renameConfigMapEndpoint, Handler: renameConfigMapHandler, Router: r, }) // DELETE /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/configmap/delete -> namespace.NewDeleteConfigMapHandler deleteConfigMapEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbDelete, Method: types.HTTPVerbDelete, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/configmap/delete", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) deleteConfigMapHandler := namespace.NewDeleteConfigMapHandler( config, factory.GetDecoderValidator(), ) routes = append(routes, &Route{ Endpoint: deleteConfigMapEndpoint, Handler: deleteConfigMapHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/releases -> namespace.NewListReleasesHandler listReleasesEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/releases", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) listReleasesHandler := namespace.NewListReleasesHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: listReleasesEndpoint, Handler: listReleasesHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/pod/{name}/logs -> namespace.NewStreamPodLogsHandler streamPodLogsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: fmt.Sprintf( "%s/pod/{%s}/logs", relPath, types.URLParamPodName, ), }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, IsWebsocket: true, }, ) streamPodLogsHandler := namespace.NewStreamPodLogsHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: streamPodLogsEndpoint, Handler: streamPodLogsHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/jobs/{name}/pods -> jobs.NewGetPodsHandler getJobPodsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbList, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: fmt.Sprintf( "%s/jobs/{%s}/pods", relPath, types.URLParamJobName, ), }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) getJobPodsHandler := job.NewGetPodsHandler( config, factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: getJobPodsEndpoint, Handler: getJobPodsHandler, Router: r, }) // DELETE /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/jobs/{name} -> jobs.NewDeleteHandler deleteJobEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbDelete, Method: types.HTTPVerbDelete, Path: &types.Path{ Parent: basePath, RelativePath: fmt.Sprintf( "%s/jobs/{%s}", relPath, types.URLParamJobName, ), }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) deleteJobHandler := job.NewDeleteHandler( config, ) routes = append(routes, &Route{ Endpoint: deleteJobEndpoint, Handler: deleteJobHandler, Router: r, }) // POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/jobs/{name}/stop -> jobs.NewStopHandler stopJobEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbUpdate, Method: types.HTTPVerbPost, Path: &types.Path{ Parent: basePath, RelativePath: fmt.Sprintf( "%s/jobs/{%s}/stop", relPath, types.URLParamJobName, ), }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) stopJobHandler := job.NewStopHandler( config, ) routes = append(routes, &Route{ Endpoint: stopJobEndpoint, Handler: stopJobHandler, Router: r, }) // DELETE /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/pods/{name} -> namespace.NewDeletePodHandler deletePodEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbDelete, Method: types.HTTPVerbDelete, Path: &types.Path{ Parent: basePath, RelativePath: fmt.Sprintf( "%s/pods/{%s}", relPath, types.URLParamPodName, ), }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) deletePodHandler := namespace.NewDeletePodHandler( config, ) routes = append(routes, &Route{ Endpoint: deletePodEndpoint, Handler: deletePodHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/pods/{name}/events -> namespace.NewGetPodEventsHandler getPodEventsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbList, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: fmt.Sprintf( "%s/pods/{%s}/events", relPath, types.URLParamPodName, ), }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) getPodEventsHandler := namespace.NewGetPodEventsHandler( config, factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: getPodEventsEndpoint, Handler: getPodEventsHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/ingresses/{name} -> // release.NewGetJobsHandler getIngressEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/ingresses/{name}", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) getIngressHandler := namespace.NewGetIngressHandler( config, factory.GetResultWriter(), ) routes = append(routes, &Route{ Endpoint: getIngressEndpoint, Handler: getIngressHandler, Router: r, }) return routes, newPath }