Skip to content

Commit

Permalink
use new update call and remove cli actions in cli apply (#3924)
Browse files Browse the repository at this point in the history
Co-authored-by: David Townley <[email protected]>
Co-authored-by: d-g-town <[email protected]>
  • Loading branch information
3 people authored Nov 3, 2023
1 parent 87f6d03 commit 8a9ae39
Show file tree
Hide file tree
Showing 16 changed files with 765 additions and 144 deletions.
41 changes: 41 additions & 0 deletions api/client/porter_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,26 @@ func (c *Client) PredeployStatus(
return resp, err
}

// GetRevision returns an app revision
func (c *Client) GetRevision(
ctx context.Context,
projectID uint, clusterID uint,
appName string, appRevisionId string,
) (*porter_app.GetAppRevisionResponse, error) {
resp := &porter_app.GetAppRevisionResponse{}

err := c.getRequest(
fmt.Sprintf(
"/projects/%d/clusters/%d/apps/%s/revisions/%s",
projectID, clusterID, appName, appRevisionId,
),
nil,
resp,
)

return resp, err
}

// UpdateRevisionStatus updates the status of an app revision
func (c *Client) UpdateRevisionStatus(
ctx context.Context,
Expand Down Expand Up @@ -683,3 +703,24 @@ func (c *Client) RollbackRevision(

return resp, err
}

// UseNewApplyLogic checks whether the CLI should use the new apply logic
func (c *Client) UseNewApplyLogic(
ctx context.Context,
projectID, clusterID uint,
) (*porter_app.UseNewApplyLogicResponse, error) {
resp := &porter_app.UseNewApplyLogicResponse{}

req := &porter_app.UseNewApplyLogicRequest{}

err := c.getRequest(
fmt.Sprintf(
"/projects/%d/clusters/%d/apps/use-new-apply-logic",
projectID, clusterID,
),
req,
resp,
)

return resp, err
}
25 changes: 12 additions & 13 deletions api/server/handlers/porter_app/get_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,22 @@ func (c *GetBuildFromRevisionHandler) ServeHTTP(w http.ResponseWriter, r *http.R
return
}

if appProto.Build == nil {
err := telemetry.Error(ctx, span, nil, "app proto does not have build settings")
if appProto.Image == nil {
err := telemetry.Error(ctx, span, nil, "app proto does not have image settings. Tag is unknown")
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
return
}

resp.Image = Image{
Repository: appProto.Image.Repository,
Tag: appProto.Image.Tag,
}

if appProto.Build == nil {
c.WriteResult(w, r, resp)
return
}

resp.Build = BuildSettings{
Method: appProto.Build.Method,
Context: appProto.Build.Context,
Expand All @@ -143,17 +153,6 @@ func (c *GetBuildFromRevisionHandler) ServeHTTP(w http.ResponseWriter, r *http.R
CommitSHA: appProto.Build.CommitSha,
}

if appProto.Image == nil {
err := telemetry.Error(ctx, span, nil, "app proto does not have image settings. Tag is unknown")
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
return
}

resp.Image = Image{
Repository: appProto.Image.Repository,
Tag: appProto.Image.Tag,
}

agent, err := c.GetAgent(r, cluster, "")
if err != nil {
err := telemetry.Error(ctx, span, err, "error getting agent")
Expand Down
54 changes: 8 additions & 46 deletions api/server/handlers/porter_app/update_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,6 @@ func NewUpdateAppHandler(
}
}

// CLIAction is an enum for actions the CLI should take after calling applyWithRevisionID
type CLIAction int

// Actions for the CLI to take after applying the porter yaml
const (
// CLIAction_Missing is the zero value that indicates an action was not assigned. This should never be returned.
CLIAction_Missing CLIAction = iota
// CLIAction_NoAction indicates that no action should be taken by the CLI.
CLIAction_NoAction
// CLIAction_Build indicates that the CLI should build the app.
CLIAction_Build
// CLIAction_TrackPredeploy indicates that the CLI should track the predeploy job.
CLIAction_TrackPredeploy
)

// UpdateAppRequest is the request object for the POST /apps/update endpoint
type UpdateAppRequest struct {
// Name is the name of the app to update. If not specified, the name will be inferred from the porter yaml
Expand Down Expand Up @@ -85,9 +70,8 @@ type UpdateAppRequest struct {

// UpdateAppResponse is the response object for the POST /apps/update endpoint
type UpdateAppResponse struct {
AppName string `json:"app_name"`
AppRevisionId string `json:"app_revision_id"`
CLIAction CLIAction `json:"cli_action"`
AppName string `json:"app_name"`
AppRevisionId string `json:"app_revision_id"`
}

// ServeHTTP translates the request into an UpdateApp request, forwards to the cluster control plane, and returns the response
Expand Down Expand Up @@ -165,9 +149,12 @@ func (c *UpdateAppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}

if appProto.Name == "" {
err := telemetry.Error(ctx, span, nil, "app name is empty")
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
return
if request.Name == "" {
err := telemetry.Error(ctx, span, nil, "app name is empty")
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
return
}
appProto.Name = request.Name
}

sourceType, image := sourceFromAppAndGitSource(appProto, request.GitSource)
Expand Down Expand Up @@ -311,33 +298,8 @@ func (c *UpdateAppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "resp-app-revision-id", Value: ccpResp.Msg.AppRevisionId})

if ccpResp.Msg.CliAction == porterv1.EnumCLIAction_ENUM_CLI_ACTION_UNSPECIFIED {
err := telemetry.Error(ctx, span, err, "ccp resp cli action is nil")
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
return
}

telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "cli-action", Value: ccpResp.Msg.CliAction.String()})

var cliAction CLIAction
switch ccpResp.Msg.CliAction {
case porterv1.EnumCLIAction_ENUM_CLI_ACTION_UNSPECIFIED:
cliAction = CLIAction_Missing
case porterv1.EnumCLIAction_ENUM_CLI_ACTION_NONE:
cliAction = CLIAction_NoAction
case porterv1.EnumCLIAction_ENUM_CLI_ACTION_BUILD:
cliAction = CLIAction_Build
case porterv1.EnumCLIAction_ENUM_CLI_ACTION_TRACK_PREDEPLOY:
cliAction = CLIAction_TrackPredeploy
default:
err := telemetry.Error(ctx, span, err, "ccp resp cli action is invalid")
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
return
}

response := &UpdateAppResponse{
AppRevisionId: ccpResp.Msg.AppRevisionId,
CLIAction: cliAction,
AppName: appProto.Name,
}

Expand Down
2 changes: 2 additions & 0 deletions api/server/handlers/porter_app/update_app_revision_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ func (c *UpdateAppRevisionStatusHandler) ServeHTTP(w http.ResponseWriter, r *htt
statusProto = porterv1.EnumRevisionStatus_ENUM_REVISION_STATUS_DEPLOY_FAILED
case models.AppRevisionStatus_PredeployFailed:
statusProto = porterv1.EnumRevisionStatus_ENUM_REVISION_STATUS_PREDEPLOY_FAILED
case models.AppRevisionStatus_BuildSuccessful:
statusProto = porterv1.EnumRevisionStatus_ENUM_REVISION_STATUS_BUILD_SUCCESSFUL
default:
err := telemetry.Error(ctx, span, nil, "invalid status")
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
Expand Down
63 changes: 63 additions & 0 deletions api/server/handlers/porter_app/use_new_apply_logic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package porter_app

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/config"
"github.com/porter-dev/porter/api/types"
"github.com/porter-dev/porter/internal/models"
"github.com/porter-dev/porter/internal/telemetry"
)

// UseNewApplyLogicHandler returns whether the CLI should use the new apply logic or not
type UseNewApplyLogicHandler struct {
handlers.PorterHandlerReadWriter
authz.KubernetesAgentGetter
}

// NewUseNewApplyLogicHandler returns a new UseNewApplyLogicHandler
func NewUseNewApplyLogicHandler(
config *config.Config,
decoderValidator shared.RequestDecoderValidator,
writer shared.ResultWriter,
) *UseNewApplyLogicHandler {
return &UseNewApplyLogicHandler{
PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
}
}

// UseNewApplyLogicRequest is the request body for the /apps/use-new-apply-logic endpoint
type UseNewApplyLogicRequest struct{}

// UseNewApplyLogicResponse is the response body for the /apps/use-new-apply-logic endpoint
type UseNewApplyLogicResponse struct {
UseNewApplyLogic bool `json:"use_new_apply_logic"`
}

// ServeHTTP handles the request on the /apps/use-new-apply-logic endpoint, allowing the server to tell the CLI whether to use the new apply logic or not
func (c *UseNewApplyLogicHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, span := telemetry.NewSpan(r.Context(), "serve-use-new-apply-logic")
defer span.End()

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

telemetry.WithAttributes(span,
telemetry.AttributeKV{Key: "project_id", Value: project.ID},
telemetry.AttributeKV{Key: "cluster_id", Value: cluster.ID},
)

betaFeaturesEnabled := project.GetFeatureFlag(models.BetaFeaturesEnabled, c.Config().LaunchDarklyClient)

telemetry.WithAttributes(span,
telemetry.AttributeKV{Key: "beta_features_enabled", Value: betaFeaturesEnabled},
)

c.WriteResult(w, r, &UseNewApplyLogicResponse{
UseNewApplyLogic: betaFeaturesEnabled,
})
}
29 changes: 29 additions & 0 deletions api/server/router/porter_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1473,5 +1473,34 @@ func getPorterAppRoutes(
Router: r,
})

// GET /api/projects/{project_id}/clusters/{cluster_id}/apps/use-new-apply-logic -> porter_app.NewUseNewApplyLogicHandler
useNewApplyLogicEndpoint := factory.NewAPIEndpoint(
&types.APIRequestMetadata{
Verb: types.APIVerbGet,
Method: types.HTTPVerbGet,
Path: &types.Path{
Parent: basePath,
RelativePath: fmt.Sprintf("%s/use-new-apply-logic", relPathV2),
},
Scopes: []types.PermissionScope{
types.UserScope,
types.ProjectScope,
types.ClusterScope,
},
},
)

useNewApplyLogicHandler := porter_app.NewUseNewApplyLogicHandler(
config,
factory.GetDecoderValidator(),
factory.GetResultWriter(),
)

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

return routes, newPath
}
1 change: 1 addition & 0 deletions api/types/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Project struct {
EnableReprovision bool `json:"enable_reprovision"`
ValidateApplyV2 bool `json:"validate_apply_v2"`
QuotaIncrease bool `json:"quota_increase"`
BetaFeaturesEnabled bool `json:"beta_features_enabled"`
}

type FeatureFlags struct {
Expand Down
Loading

0 comments on commit 8a9ae39

Please sign in to comment.