Forráskód Böngészése

add get ingress endpoint

Alexander Belanger 4 éve
szülő
commit
189e881541

+ 50 - 0
api/server/handlers/namespace/get_ingress.go

@@ -0,0 +1,50 @@
+package namespace
+
+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 GetIngressHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewGetIngressHandler(
+	config *config.Config,
+	resultWriter shared.ResultWriter,
+) *GetIngressHandler {
+	return &GetIngressHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, nil, resultWriter),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *GetIngressHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+	agent, err := c.GetAgent(r, cluster)
+	name, _ := requestutils.GetURLParamString(r, types.URLParamIngressName)
+	namespace, _ := requestutils.GetURLParamString(r, types.URLParamNamespace)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	ingress, err := agent.GetIngress(namespace, name)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	c.WriteResult(w, r, ingress)
+}

+ 78 - 0
api/server/handlers/release/create_subdomain.go

@@ -0,0 +1,78 @@
+package release
+
+import (
+	"fmt"
+	"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/kubernetes/domain"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type CreateSubdomainHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewCreateSubdomainHandler(
+	config *config.Config,
+	writer shared.ResultWriter,
+) *CreateSubdomainHandler {
+	return &CreateSubdomainHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *CreateSubdomainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	name, _ := requestutils.GetURLParamString(r, types.URLParamReleaseName)
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+
+	agent, err := c.GetAgent(r, cluster)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	endpoint, found, err := domain.GetNGINXIngressServiceIP(agent.Clientset)
+
+	if !found {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(
+			fmt.Errorf("target cluster does not have nginx ingress"),
+		))
+		return
+	}
+
+	createDomain := domain.CreateDNSRecordConfig{
+		ReleaseName: name,
+		RootDomain:  c.Config().ServerConf.AppRootDomain,
+		Endpoint:    endpoint,
+	}
+
+	record := createDomain.NewDNSRecordForEndpoint()
+
+	record, err = c.Repo().DNSRecord().CreateDNSRecord(record)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	_record := domain.DNSRecord(*record)
+
+	err = _record.CreateDomain(c.Config().IngressAgent.Clientset)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	c.WriteResult(w, r, record.Externalize())
+}

+ 30 - 0
api/server/router/namespace.go

@@ -460,5 +460,35 @@ func getNamespaceRoutes(
 		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
 }

+ 30 - 1
api/server/router/release.go

@@ -297,7 +297,7 @@ func getReleaseRoutes(
 			Method: types.HTTPVerbPost,
 			Path: &types.Path{
 				Parent:       basePath,
-				RelativePath: "/releases/{name}/webhook",
+				RelativePath: relPath + "/webhook",
 			},
 			Scopes: []types.PermissionScope{
 				types.UserScope,
@@ -537,5 +537,34 @@ func getReleaseRoutes(
 		Router:   r,
 	})
 
+	// POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/releases/{name}/subdomain -> release.NewCreateSubdomainHandler
+	createSubdomainEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbCreate,
+			Method: types.HTTPVerbPost,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: "/releases/{name}/subdomain",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+				types.NamespaceScope,
+			},
+		},
+	)
+
+	createSubdomainHandler := release.NewCreateSubdomainHandler(
+		config,
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: createSubdomainEndpoint,
+		Handler:  createSubdomainHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 9 - 0
api/server/shared/config/config.go

@@ -8,6 +8,7 @@ import (
 	"github.com/porter-dev/porter/api/server/shared/apierrors/alerter"
 	"github.com/porter-dev/porter/internal/auth/token"
 	"github.com/porter-dev/porter/internal/helm/urlcache"
+	"github.com/porter-dev/porter/internal/kubernetes"
 	"github.com/porter-dev/porter/internal/logger"
 	"github.com/porter-dev/porter/internal/notifier"
 	"github.com/porter-dev/porter/internal/oauth"
@@ -57,6 +58,14 @@ type Config struct {
 
 	// URLCache contains a cache of chart names to chart repos
 	URLCache *urlcache.ChartURLCache
+
+	// ProvisionerAgent is the kubernetes client responsible for creating new provisioner
+	// jobs
+	ProvisionerAgent *kubernetes.Agent
+
+	// IngressAgent is the kubernetes client responsible for creating new ingress
+	// resources
+	IngressAgent *kubernetes.Agent
 }
 
 type ConfigLoader interface {

+ 55 - 0
api/server/shared/config/loader/loader.go

@@ -1,6 +1,7 @@
 package loader
 
 import (
+	"fmt"
 	"net/http"
 	"strconv"
 
@@ -11,6 +12,8 @@ import (
 	"github.com/porter-dev/porter/internal/auth/sessionstore"
 	"github.com/porter-dev/porter/internal/auth/token"
 	"github.com/porter-dev/porter/internal/helm/urlcache"
+	"github.com/porter-dev/porter/internal/kubernetes"
+	"github.com/porter-dev/porter/internal/kubernetes/local"
 	"github.com/porter-dev/porter/internal/notifier"
 	"github.com/porter-dev/porter/internal/notifier/sendgrid"
 	"github.com/porter-dev/porter/internal/oauth"
@@ -141,5 +144,57 @@ func (e *EnvConfigLoader) LoadConfig() (res *config.Config, err error) {
 
 	res.URLCache = urlcache.Init(sc.DefaultApplicationHelmRepoURL, sc.DefaultAddonHelmRepoURL)
 
+	provAgent, err := getProvisionerAgent(sc)
+
+	if err != nil {
+		return nil, err
+	}
+
+	res.ProvisionerAgent = provAgent
+
+	ingressAgent, err := getIngressAgent(sc)
+
+	if err != nil {
+		return nil, err
+	}
+
+	res.IngressAgent = ingressAgent
+
 	return res, nil
 }
+
+func getProvisionerAgent(sc *config.ServerConf) (*kubernetes.Agent, error) {
+	if sc.ProvisionerCluster == "kubeconfig" && sc.SelfKubeconfig != "" {
+		agent, err := local.GetSelfAgentFromFileConfig(sc.SelfKubeconfig)
+
+		if err != nil {
+			return nil, fmt.Errorf("could not get in-cluster agent: %v", err)
+		}
+
+		return agent, nil
+	} else if sc.ProvisionerCluster == "kubeconfig" {
+		return nil, fmt.Errorf(`"kubeconfig" cluster option requires path to kubeconfig`)
+	}
+
+	agent, _ := kubernetes.GetAgentInClusterConfig()
+
+	return agent, nil
+}
+
+func getIngressAgent(sc *config.ServerConf) (*kubernetes.Agent, error) {
+	if sc.IngressCluster == "kubeconfig" && sc.SelfKubeconfig != "" {
+		agent, err := local.GetSelfAgentFromFileConfig(sc.SelfKubeconfig)
+
+		if err != nil {
+			return nil, fmt.Errorf("could not get in-cluster agent: %v", err)
+		}
+
+		return agent, nil
+	} else if sc.ProvisionerCluster == "kubeconfig" {
+		return nil, fmt.Errorf(`"kubeconfig" cluster option requires path to kubeconfig`)
+	}
+
+	agent, _ := kubernetes.GetAgentInClusterConfig()
+
+	return agent, nil
+}

+ 2 - 1
api/types/namespace.go

@@ -7,7 +7,8 @@ import (
 )
 
 const (
-	URLParamPodName URLParam = "name"
+	URLParamPodName     URLParam = "name"
+	URLParamIngressName URLParam = "name"
 )
 
 // ReleaseListFilter is a struct that represents the various filter options used for

+ 1 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -250,7 +250,6 @@ const ExpandedChart: React.FC<Props> = (props) => {
       await api.upgradeChartValues(
         "<token>",
         {
-          storage: StorageType.Secret,
           values: valuesYaml,
         },
         {
@@ -627,11 +626,11 @@ const ExpandedChart: React.FC<Props> = (props) => {
       .getIngress(
         "<token>",
         {
-          cluster_id: currentCluster.id,
         },
         {
           id: currentProject.id,
           name: ingressName,
+          cluster_id: currentCluster.id,
           namespace: `${currentChart.namespace}`,
         }
       )

+ 2 - 1
dashboard/src/main/home/launch/launch-flow/LaunchFlow.tsx

@@ -214,11 +214,12 @@ const LaunchFlow: React.FC<PropsType> = (props) => {
             .createSubdomain(
               "<token>",
               {
-                release_name: templateName,
               },
               {
                 id: currentProject.id,
                 cluster_id: currentCluster.id,
+                release_name: templateName,
+                namespace: selectedNamespace,
               }
             )
             .then((res) => {

+ 9 - 7
dashboard/src/shared/api.tsx

@@ -175,16 +175,17 @@ const createProject = baseApi<{ name: string }, {}>("POST", (pathParams) => {
 
 const createSubdomain = baseApi<
   {
-    release_name: string;
   },
   {
     id: number;
+    release_name: string;
+    namespace: string;
     cluster_id: number;
   }
 >("POST", (pathParams) => {
-  let { cluster_id, id } = pathParams;
+  let { cluster_id, id, namespace, release_name } = pathParams;
 
-  return `/api/projects/${id}/k8s/subdomain?cluster_id=${cluster_id}`;
+  return `/api/projects/${id}/clusters/${cluster_id}/namespaces/${namespace}/releases/${release_name}/subdomain`;
 });
 
 const deleteCluster = baseApi<
@@ -538,11 +539,12 @@ const getInfra = baseApi<
 
 const getIngress = baseApi<
   {
-    cluster_id: number;
   },
-  { name: string; namespace: string; id: number }
+  { namespace: string; cluster_id: number; name: string; id: number }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.id}/k8s/${pathParams.namespace}/ingress/${pathParams.name}`;
+  let { id, name, cluster_id, namespace } = pathParams
+
+  return `/api/projects/${id}/clusters/${cluster_id}/namespaces/${namespace}/ingresses/${name}`;
 });
 
 const getInvites = baseApi<{}, { id: number }>("GET", (pathParams) => {
@@ -1037,7 +1039,7 @@ const createWebhookToken = baseApi<
 >(
   "POST",
   ({ project_id, chart_name, namespace, cluster_id }) =>
-    `/api/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/releases/${chart_name}/webhook`
+    `/api/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/releases/${chart_name}/0/webhook`
 );
 
 // Bundle export to allow default api import (api.<method> is more readable)

+ 2 - 2
docs/developing/backend-refactor-status.md

@@ -97,8 +97,8 @@
 | <li>- [X] `GET /api/projects/{project_id}/k8s/pods/{namespace}/{name}/events/list`                                          | AB          |                 |             |                  |
 | <li>- [x] `GET /api/projects/{project_id}/k8s/prometheus/detect`                                                            | AS          | yes             |             | yes              |
 | <li>- [x] `GET /api/projects/{project_id}/k8s/prometheus/ingresses`                                                         | AS          | yes             |             | yes              |
-| <li>- [ ] `POST /api/projects/{project_id}/k8s/subdomain`                                                                   |             |                 |             |                  |
-| <li>- [ ] `GET /api/projects/{project_id}/k8s/{namespace}/ingress/{name}`                                                   |             |                 |             |                  |
+| <li>- [X] `POST /api/projects/{project_id}/k8s/subdomain`                                                                   | AB          |                 |             |                  |
+| <li>- [X] `GET /api/projects/{project_id}/k8s/{namespace}/ingress/{name}`                                                   | AB          |                 |             |                  |
 | <li>- [X] `GET /api/projects/{project_id}/k8s/{namespace}/pod/{name}/logs`                                                  | AB          |                 |             |                  |
 | <li>- [X] `GET /api/projects/{project_id}/k8s/{kind}/status`                                                                | AB          | yes             |             |                  |
 | <li>- [X] `GET /api/projects/{project_id}/k8s/{namespace}/{name}/jobs/status`                                               | AB          |                 |             |                  |