Skip to content

Commit

Permalink
Infra tab 2.0 (#4274)
Browse files Browse the repository at this point in the history
  • Loading branch information
Feroze Mohideen authored Feb 15, 2024
1 parent 8e3a14b commit d968c18
Show file tree
Hide file tree
Showing 74 changed files with 6,604 additions and 877 deletions.
28 changes: 13 additions & 15 deletions api/server/handlers/cluster/cluster_status.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package cluster

import (
"fmt"
"net/http"

"connectrpc.com/connect"
porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
"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"
Expand Down Expand Up @@ -45,32 +43,32 @@ func (c *ClusterStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
defer span.End()

cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
project, _ := ctx.Value(types.ProjectScope).(*models.Project)
req := connect.NewRequest(&porterv1.ClusterStatusRequest{
ProjectId: int64(cluster.ProjectID),
ClusterId: int64(cluster.ID),
})
resp := ClusterStatusResponse{
ProjectID: int(project.ID),
ClusterID: int(cluster.ID),
}

status, err := c.Config().ClusterControlPlaneClient.ClusterStatus(ctx, req)
if err != nil {
err := fmt.Errorf("unable to retrieve status for cluster: %w", err)
err = telemetry.Error(ctx, span, err, err.Error())
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
_ = telemetry.Error(ctx, span, err, "error getting cluster status")
c.WriteResult(w, r, resp)
return
}
if status.Msg == nil {
err := fmt.Errorf("unable to parse status for cluster: %w", err)
err = telemetry.Error(ctx, span, err, err.Error())
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
_ = telemetry.Error(ctx, span, nil, "error getting cluster status")
c.WriteResult(w, r, resp)
return
}
statusResp := status.Msg

resp := ClusterStatusResponse{
ProjectID: int(statusResp.ProjectId),
ClusterID: int(statusResp.ClusterId),
Phase: statusResp.Phase,
IsInfrastructureReady: statusResp.InfrastructureStatus,
IsControlPlaneReady: statusResp.ControlPlaneStatus,
}
resp.Phase = statusResp.Phase
resp.IsInfrastructureReady = statusResp.InfrastructureStatus
resp.IsControlPlaneReady = statusResp.ControlPlaneStatus

telemetry.WithAttributes(span,
telemetry.AttributeKV{Key: "cluster-phase", Value: statusResp.Phase},
Expand Down
3 changes: 1 addition & 2 deletions api/server/handlers/cluster/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"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/kubernetes"
Expand Down Expand Up @@ -38,7 +37,7 @@ func (c *ClusterGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

agent, err := c.GetAgent(r, cluster, "")
if err != nil {
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
c.WriteResult(w, r, res)
return
}

Expand Down
11 changes: 9 additions & 2 deletions api/server/handlers/cluster/rename.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/porter-dev/porter/api/server/shared/config"
"github.com/porter-dev/porter/api/types"
"github.com/porter-dev/porter/internal/models"
"github.com/porter-dev/porter/internal/telemetry"
)

type RenameClusterHandler struct {
Expand All @@ -29,10 +30,15 @@ func NewRenameClusterHandler(
}

func (c *RenameClusterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
ctx, span := telemetry.NewSpan(r.Context(), "serve-rename-cluster")
defer span.End()

cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)

request := &types.UpdateClusterRequest{}
if ok := c.DecodeAndValidate(w, r, request); !ok {
err := telemetry.Error(ctx, span, nil, "invalid request")
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
return
}

Expand All @@ -42,7 +48,8 @@ func (c *RenameClusterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

cluster, err := c.Repo().Cluster().UpdateCluster(cluster, c.Config().LaunchDarklyClient)
if err != nil {
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
err = telemetry.Error(ctx, span, err, "error updating cluster")
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
return
}

Expand Down
77 changes: 73 additions & 4 deletions api/server/handlers/project_integration/preflight_check.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package project_integration

import (
"fmt"
"net/http"

"connectrpc.com/connect"
Expand Down Expand Up @@ -32,10 +31,42 @@ func NewCreatePreflightCheckHandler(
}
}

// PorterError is the error response for the preflight check endpoint
type PorterError struct {
Code string `json:"code"`
Message string `json:"message"`
Metadata map[string]string `json:"metadata,omitempty"`
}

// PreflightCheckError is the error response for the preflight check endpoint
type PreflightCheckError struct {
Name string `json:"name"`
Error PorterError `json:"error"`
}

// PreflightCheckResponse is the response to the preflight check endpoint
type PreflightCheckResponse struct {
Errors []PreflightCheckError `json:"errors"`
}

var recognizedPreflightCheckKeys = []string{
"eip",
"vcpu",
"vpc",
"natGateway",
"apiEnabled",
"cidrAvailability",
"iamPermissions",
"resourceProviders",
}

func (p *CreatePreflightCheckHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, span := telemetry.NewSpan(r.Context(), "preflight-checks")
defer span.End()
project, _ := ctx.Value(types.ProjectScope).(*models.Project)
betaFeaturesEnabled := project.GetFeatureFlag(models.BetaFeaturesEnabled, p.Config().LaunchDarklyClient)

telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "beta-features-enabled", Value: betaFeaturesEnabled})

cloudValues := &porterv1.PreflightCheckRequest{}
err := helpers.UnmarshalContractObjectFromReader(r.Body, cloudValues)
Expand All @@ -45,6 +76,8 @@ func (p *CreatePreflightCheckHandler) ServeHTTP(w http.ResponseWriter, r *http.R
return
}

var resp PreflightCheckResponse

input := porterv1.PreflightCheckRequest{
ProjectId: int64(project.ID),
CloudProvider: cloudValues.CloudProvider,
Expand All @@ -60,10 +93,46 @@ func (p *CreatePreflightCheckHandler) ServeHTTP(w http.ResponseWriter, r *http.R

checkResp, err := p.Config().ClusterControlPlaneClient.PreflightCheck(ctx, connect.NewRequest(&input))
if err != nil {
e := fmt.Errorf("Pre-provision check failed: %w", err)
p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(e, http.StatusPreconditionFailed, err.Error()))
err = telemetry.Error(ctx, span, err, "error calling preflight checks")
p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
return
}

if checkResp.Msg == nil {
err = telemetry.Error(ctx, span, nil, "no message received from preflight checks")
p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
return
}

if !betaFeaturesEnabled {
p.WriteResult(w, r, checkResp)
return
}

p.WriteResult(w, r, checkResp)
errors := []PreflightCheckError{}
for key, val := range checkResp.Msg.PreflightChecks {
if val.Message == "" || !contains(recognizedPreflightCheckKeys, key) {
continue
}

errors = append(errors, PreflightCheckError{
Name: key,
Error: PorterError{
Code: val.Code,
Message: val.Message,
Metadata: val.Metadata,
},
})
}
resp.Errors = errors
p.WriteResult(w, r, resp)
}

func contains(slice []string, elem string) bool {
for _, item := range slice {
if item == elem {
return true
}
}
return false
}
58 changes: 29 additions & 29 deletions api/server/router/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,35 @@ func getClusterRoutes(
Router: r,
})

// POST /api/projects/{project_id}/clusters/{cluster_id}/rename -> cluster.NewRenameClusterHandler
renameClusterEndpoint := factory.NewAPIEndpoint(
&types.APIRequestMetadata{
Verb: types.APIVerbCreate,
Method: types.HTTPVerbPost,
Path: &types.Path{
Parent: basePath,
RelativePath: relPath + "/rename",
},
Scopes: []types.PermissionScope{
types.UserScope,
types.ProjectScope,
types.ClusterScope,
},
},
)

renameClusterHandler := cluster.NewRenameClusterHandler(
config,
factory.GetDecoderValidator(),
factory.GetResultWriter(),
)

routes = append(routes, &router.Route{
Endpoint: renameClusterEndpoint,
Handler: renameClusterHandler,
Router: r,
})

// GET /api/projects/{project_id}/clusters/{cluster_id}/databases -> database.NewDatabaseListHandler
listDatabaseEndpoint := factory.NewAPIEndpoint(
&types.APIRequestMetadata{
Expand Down Expand Up @@ -770,35 +799,6 @@ func getClusterRoutes(
Router: r,
})

// POST /api/projects/{project_id}/clusters/{cluster_id}/rename -> cluster.NewRenameClusterHandler
renameClusterEndpoint := factory.NewAPIEndpoint(
&types.APIRequestMetadata{
Verb: types.APIVerbCreate,
Method: types.HTTPVerbPost,
Path: &types.Path{
Parent: basePath,
RelativePath: relPath + "/rename",
},
Scopes: []types.PermissionScope{
types.UserScope,
types.ProjectScope,
types.ClusterScope,
},
},
)

renameClusterHandler := cluster.NewRenameClusterHandler(
config,
factory.GetDecoderValidator(),
factory.GetResultWriter(),
)

routes = append(routes, &router.Route{
Endpoint: renameClusterEndpoint,
Handler: renameClusterHandler,
Router: r,
})

// DELETE /api/projects/{project_id}/clusters/{cluster_id}/deployments/{deployment_id} ->
// environment.NewDeleteDeploymentHandler
deleteDeploymentEndpoint := factory.NewAPIEndpoint(
Expand Down
2 changes: 2 additions & 0 deletions api/types/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type ProjectList struct {
FullAddOns bool `json:"full_add_ons"`
EnableReprovision bool `json:"enable_reprovision"`
ValidateApplyV2 bool `json:"validate_apply_v2"`
AdvancedInfraEnabled bool `json:"advanced_infra_enabled"`
}

// Project type for entries in api responses for everything other than `GET /projects`
Expand Down Expand Up @@ -50,6 +51,7 @@ type Project struct {
StacksEnabled bool `json:"stacks_enabled"`
ValidateApplyV2 bool `json:"validate_apply_v2"`
ManagedDeploymentTargetsEnabled bool `json:"managed_deployment_targets_enabled"`
AdvancedInfraEnabled bool `json:"advanced_infra_enabled"`
}

// FeatureFlags is a struct that contains old feature flag representations
Expand Down
9 changes: 9 additions & 0 deletions dashboard/src/assets/bolt.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions dashboard/src/assets/world.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit d968c18

Please sign in to comment.