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/server/shared/router" "github.com/porter-dev/porter/api/types" ) func NewNamespaceScopedRegisterer(children ...*router.Registerer) *router.Registerer { return &router.Registerer{ GetRoutes: GetNamespaceScopedRoutes, Children: children, } } func GetNamespaceScopedRoutes( r chi.Router, config *config.Config, basePath *types.Path, factory shared.APIEndpointFactory, children ...*router.Registerer, ) []*router.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, ) ([]*router.Route, *types.Path) { relPath := "/namespaces/{namespace}" newPath := &types.Path{ Parent: basePath, RelativePath: relPath, } routes := make([]*router.Route, 0) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/envgroups/list -> namespace.NewListEnvGroupsHandler listEnvGroupsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/envgroup/list", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) listEnvGroupsHandler := namespace.NewListEnvGroupsHandler( config, factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: listEnvGroupsEndpoint, Handler: listEnvGroupsHandler, Router: r, }) // POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/envgroup/clone -> namespace.NewCloneEnvGroupHandler cloneEnvGroupEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbCreate, Method: types.HTTPVerbPost, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/envgroup/clone", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) cloneEnvGroupHandler := namespace.NewCloneEnvGroupHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: cloneEnvGroupEndpoint, Handler: cloneEnvGroupHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/envgroup -> namespace.NewGetEnvGroupHandler getEnvGroupEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/envgroup", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) getEnvGroupHandler := namespace.NewGetEnvGroupHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: getEnvGroupEndpoint, Handler: getEnvGroupHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/envgroup/all_versions -> namespace.NewGetEnvGroupAllVersionsHandler getEnvGroupAllVersionsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/envgroup/all_versions", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) getEnvGroupAllVersionsHandler := namespace.NewGetEnvGroupAllVersionsHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: getEnvGroupAllVersionsEndpoint, Handler: getEnvGroupAllVersionsHandler, Router: r, }) // POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/envgroup/create -> namespace.NewCreateEnvGroupHandler createEnvGroupEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbCreate, Method: types.HTTPVerbPost, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/envgroup/create", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) createEnvGroupHandler := namespace.NewCreateEnvGroupHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: createEnvGroupEndpoint, Handler: createEnvGroupHandler, Router: r, }) // POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/envgroup/add_application -> namespace.NewAddEnvGroupAppHandler updateEnvGroupAppsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbUpdate, Method: types.HTTPVerbPost, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/envgroup/add_application", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) updateEnvGroupAppsHandler := namespace.NewAddEnvGroupAppHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: updateEnvGroupAppsEndpoint, Handler: updateEnvGroupAppsHandler, Router: r, }) // POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/envgroup/remove_application -> namespace.NewRemoveEnvGroupAppHandler removeEnvGroupAppEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbUpdate, Method: types.HTTPVerbPost, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/envgroup/remove_application", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) removeEnvGroupAppHandler := namespace.NewRemoveEnvGroupAppHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: removeEnvGroupAppEndpoint, Handler: removeEnvGroupAppHandler, Router: r, }) // DELETE /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/envgroup -> namespace.NewDeleteEnvGroupHandler deleteEnvGroupEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbDelete, Method: types.HTTPVerbDelete, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/envgroup", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) deleteEnvGroupHandler := namespace.NewDeleteEnvGroupHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: deleteEnvGroupEndpoint, Handler: deleteEnvGroupHandler, 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, &router.Route{ Endpoint: updateConfigMapEndpoint, Handler: updateConfigMapHandler, Router: r, }) // DELETE /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/crd -> namespace.NewCRDDeleteHandler deleteCRDEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbDelete, Method: types.HTTPVerbDelete, Path: &types.Path{ Parent: basePath, RelativePath: relPath + "/crd", }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, }, }, ) deleteCRDHandler := namespace.NewCRDDeleteHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: deleteCRDEndpoint, Handler: deleteCRDHandler, 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, &router.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, &router.Route{ Endpoint: streamPodLogsEndpoint, Handler: streamPodLogsHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/jobs/stream -> namespace.NewStreamJobRunsHandler streamJobRunsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: fmt.Sprintf( "%s/jobs/stream", relPath, ), }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, IsWebsocket: true, }, ) streamJobRunsHandler := namespace.NewStreamJobRunsHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: streamJobRunsEndpoint, Handler: streamJobRunsHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/pod/{name}/previous_logs getPreviousLogsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, Path: &types.Path{ Parent: basePath, RelativePath: fmt.Sprintf( "%s/pod/{%s}/previous_logs", relPath, types.URLParamPodName, ), }, Scopes: []types.PermissionScope{ types.UserScope, types.ProjectScope, types.ClusterScope, types.NamespaceScope, }, }, ) getPreviousLogsHandler := namespace.NewGetPreviousLogsHandler( config, factory.GetDecoderValidator(), factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: getPreviousLogsEndpoint, Handler: getPreviousLogsHandler, 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, &router.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, &router.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, &router.Route{ Endpoint: stopJobEndpoint, Handler: stopJobHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/pods/{name} -> namespace.NewGetPodHandler getPodEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, Method: types.HTTPVerbGet, 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, }, }, ) getPodHandler := namespace.NewGetPodHandler( config, factory.GetResultWriter(), ) routes = append(routes, &router.Route{ Endpoint: getPodEndpoint, Handler: getPodHandler, 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, &router.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, &router.Route{ Endpoint: getPodEventsEndpoint, Handler: getPodEventsHandler, Router: r, }) // GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/ingresses/{name} -> // namespace.NewGetIngressHandler 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, &router.Route{ Endpoint: getIngressEndpoint, Handler: getIngressHandler, Router: r, }) return routes, newPath }