Просмотр исходного кода

separate porter and helm version number (#4518)

d-g-town 2 лет назад
Родитель
Сommit
5ba0a8ca2d

+ 74 - 71
api/server/handlers/porter_app/helm_release.go

@@ -4,7 +4,6 @@ import (
 	"context"
 	"fmt"
 	"net/http"
-	"strconv"
 	"strings"
 
 	"github.com/porter-dev/api-contracts/generated/go/porter/v1/porterv1connect"
@@ -72,102 +71,53 @@ func (c *PorterAppHelmReleaseGetHandler) ServeHTTP(w http.ResponseWriter, r *htt
 
 	// TODO (POR-2170): Deprecate this entire endpoint in favor of v2 endpoints
 	if project.GetFeatureFlag(models.ValidateApplyV2, c.Config().LaunchDarklyClient) {
-		appInstance, err := appInstanceFromAppName(ctx, appInstanceFromAppNameInput{
-			ProjectID: project.ID,
-			ClusterID: cluster.ID,
-			AppName:   appName,
-			CCPClient: c.Config().ClusterControlPlaneClient,
-		})
-		if err != nil {
-			err := telemetry.Error(ctx, span, err, "error getting deployment target id from app name")
-			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
-			return
-		}
-
-		// TODO (POR-2170): delete these database calls once endpoint is deprecated
-		var revision *models.AppRevision
-		// treat version 0 as latest like helm
-		if version == 0 {
-			revision, err = c.Repo().AppRevision().LatestNumberedAppRevision(project.ID, appInstance.Id)
-			if err != nil {
-				err := telemetry.Error(ctx, span, err, "error getting latest numbered app revision")
-				c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
-				return
-			}
-		} else {
-			revision, err = c.Repo().AppRevision().AppRevisionByInstanceIDAndRevisionNumber(project.ID, appInstance.Id, version)
-			if err != nil {
-				err := telemetry.Error(ctx, span, err, "error getting app revision by instance id and revision number")
-				c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
-				return
-			}
-		}
 
-		if revision == nil {
-			err := telemetry.Error(ctx, span, err, "app revision is nil")
+		namespace := fmt.Sprintf("app-%s", appName)
+		helmAgent, err := c.GetHelmAgent(ctx, r, cluster, namespace)
+		if err != nil {
+			err = telemetry.Error(ctx, span, err, "error getting helm agent")
 			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
 			return
 		}
 
-		appRevisionRequest := connect.NewRequest(&porterv1.GetAppRevisionRequest{
-			ProjectId:     int64(project.ID),
-			AppRevisionId: revision.ID.String(),
-		})
-
-		getAppRevisionResp, err := c.Config().ClusterControlPlaneClient.GetAppRevision(ctx, appRevisionRequest)
+		rel, err := helmAgent.GetRelease(ctx, appName, int(version), false)
 		if err != nil {
-			err := telemetry.Error(ctx, span, err, "error getting current app revision from cluster control plane client")
+			err = telemetry.Error(ctx, span, err, "error getting helm release")
 			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
 			return
 		}
 
-		if getAppRevisionResp.Msg == nil || getAppRevisionResp.Msg.AppRevision == nil {
-			err := telemetry.Error(ctx, span, err, "app revision is nil")
+		if rel == nil {
+			err = telemetry.Error(ctx, span, nil, "release is nil")
 			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
 			return
 		}
 
-		appRevision := getAppRevisionResp.Msg.AppRevision
+		config := rel.Config
 
-		if appRevision.App == nil || appRevision.App.Image == nil {
-			err := telemetry.Error(ctx, span, err, "app revision app or image is nil")
-			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
-			return
-		}
-
-		namespace := fmt.Sprintf("app-%s", appName)
-		k8sAgent, err := c.GetAgent(r, cluster, namespace)
+		tag, err := imageTagFromConfig(config)
 		if err != nil {
-			err = telemetry.Error(ctx, span, err, "error getting helm agent")
+			err := telemetry.Error(ctx, span, err, "error getting image tag from config")
 			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
 			return
 		}
 
-		deployments, err := k8sAgent.GetDeploymentsBySelector(ctx, namespace, fmt.Sprintf("porter.run/app-revision-id=%s", revision.ID.String()))
+		revisionId, err := appRevisionIdFromConfig(config)
 		if err != nil {
-			err = telemetry.Error(ctx, span, err, "error getting helm release history")
+			err := telemetry.Error(ctx, span, err, "error getting app revision id from config")
 			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
 			return
 		}
 
-		if deployments == nil || len(deployments.Items) == 0 {
-			err = telemetry.Error(ctx, span, nil, "no deployments found for revision")
-			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
-			return
-		}
-
-		firstDeployment := deployments.Items[0]
-
-		if len(firstDeployment.Spec.Template.Annotations) == 0 || firstDeployment.Spec.Template.Annotations["helm.sh/revision"] == "" {
-			err = telemetry.Error(ctx, span, nil, "helm revision annotation not found")
+		revision, err := c.Repo().AppRevision().AppRevisionById(project.ID, revisionId)
+		if err != nil {
+			err := telemetry.Error(ctx, span, err, "error getting app revision by instance id and revision number")
 			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
 			return
 		}
 
-		helmRevisionNumberString := firstDeployment.Spec.Template.Annotations["helm.sh/revision"]
-		helmRevisionNumber, err := strconv.Atoi(helmRevisionNumberString)
-		if err != nil {
-			err = telemetry.Error(ctx, span, err, "error converting helm revision number to int")
+		if revision == nil {
+			err := telemetry.Error(ctx, span, err, "app revision is nil")
 			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
 			return
 		}
@@ -180,17 +130,18 @@ func (c *PorterAppHelmReleaseGetHandler) ServeHTTP(w http.ResponseWriter, r *htt
 				Config: map[string]interface{}{
 					"global": map[string]interface{}{
 						"image": map[string]interface{}{
-							"tag": appRevision.App.Image.Tag,
+							"tag": tag,
 						},
 					},
 				},
 				Manifest:  "",
 				Hooks:     nil,
-				Version:   helmRevisionNumber,
+				Version:   rel.Version,
 				Namespace: "",
 				Labels:    nil,
 			},
-			PorterVersion: uint(appRevision.RevisionNumber),
+			PorterVersion: uint(revision.RevisionNumber),
+			AppRevisionId: revisionId,
 			PorterRelease: nil,
 			Form:          nil,
 		}
@@ -315,3 +266,55 @@ func appInstanceFromAppName(ctx context.Context, input appInstanceFromAppNameInp
 
 	return matchingAppInstances[0], nil
 }
+
+func imageTagFromConfig(config map[string]interface{}) (string, error) {
+	globalConfig, ok := config["global"].(map[string]interface{})
+	if !ok || globalConfig == nil {
+		return "", fmt.Errorf("error converting global config to map")
+	}
+
+	imageConfig, ok := globalConfig["image"].(map[string]interface{})
+	if !ok || imageConfig == nil {
+		return "", fmt.Errorf("error converting image config to map")
+	}
+
+	tag, ok := imageConfig["tag"].(string)
+	if !ok || tag == "" {
+		return "", fmt.Errorf("error converting tag to string")
+	}
+
+	return tag, nil
+}
+
+func appRevisionIdFromConfig(config map[string]interface{}) (string, error) {
+	var appRevisionId string
+	for _, val := range config {
+		if val == nil {
+			continue
+		}
+
+		m, ok := val.(map[string]interface{})
+		if !ok || m == nil {
+			continue
+		}
+
+		labels, ok := m["labels"].(map[string]interface{})
+		if !ok || labels == nil {
+			continue
+		}
+
+		id, ok := labels["porter.run/app-revision-id"].(string)
+		if !ok || id == "" {
+			continue
+		}
+
+		appRevisionId = id
+		break
+	}
+
+	if appRevisionId == "" {
+		return "", fmt.Errorf("app revision id not found in config")
+	}
+
+	return appRevisionId, nil
+}

+ 2 - 1
api/types/release.go

@@ -10,7 +10,8 @@ import (
 type Release struct {
 	*release.Release
 	*PorterRelease
-	PorterVersion uint `json:"porter_version,omitempty"`
+	PorterVersion uint   `json:"porter_version,omitempty"`
+	AppRevisionId string `json:"app_revision_id,omitempty"`
 
 	Form *FormYAML `json:"form,omitempty"`
 }

+ 2 - 4
internal/repository/app_revision.go

@@ -6,8 +6,6 @@ import (
 
 // AppRevisionRepository represents the set of queries on the AppRevision model
 type AppRevisionRepository interface {
-	// AppRevisionByInstanceIDAndRevisionNumber finds an app revision by revision number
-	AppRevisionByInstanceIDAndRevisionNumber(projectID uint, appInstanceId string, revisionNumber uint) (*models.AppRevision, error)
-	// LatestNumberedAppRevision finds the latest numbered app revision
-	LatestNumberedAppRevision(projectID uint, appInstanceId string) (*models.AppRevision, error)
+	// AppRevisionById finds an app revision by id
+	AppRevisionById(projectID uint, appRevisionId string) (*models.AppRevision, error)
 }

+ 3 - 14
internal/repository/gorm/app_revision.go

@@ -17,22 +17,11 @@ func NewAppRevisionRepository(db *gorm.DB) repository.AppRevisionRepository {
 	return &AppRevisionRepository{db}
 }
 
-// AppRevisionByInstanceIDAndRevisionNumber finds an app revision by revision number
-func (repo *AppRevisionRepository) AppRevisionByInstanceIDAndRevisionNumber(projectID uint, instanceId string, revisionNumber uint) (*models.AppRevision, error) {
+// AppRevisionById finds an app revision by id
+func (repo *AppRevisionRepository) AppRevisionById(projectID uint, id string) (*models.AppRevision, error) {
 	AppRevision := &models.AppRevision{}
 
-	if err := repo.db.Where("project_id = ? AND app_instance_id = ? AND revision_number = ?", projectID, instanceId, revisionNumber).Limit(1).Find(&AppRevision).Error; err != nil {
-		return nil, err
-	}
-
-	return AppRevision, nil
-}
-
-// LatestNumberedAppRevision finds the latest numbered app revision
-func (repo *AppRevisionRepository) LatestNumberedAppRevision(projectID uint, appInstanceId string) (*models.AppRevision, error) {
-	AppRevision := &models.AppRevision{}
-
-	if err := repo.db.Where("project_id = ? AND app_instance_id = ?", projectID, appInstanceId).Order("revision_number DESC").Limit(1).Find(&AppRevision).Error; err != nil {
+	if err := repo.db.Where("project_id = ? AND id = ?", projectID, id).Limit(1).Find(&AppRevision).Error; err != nil {
 		return nil, err
 	}
 

+ 2 - 7
internal/repository/test/app_revision.go

@@ -17,12 +17,7 @@ func NewAppRevisionRepository() repository.AppRevisionRepository {
 	return &AppRevisionRepository{canQuery: false}
 }
 
-// AppRevisionByInstanceIDAndRevisionNumber finds an app revision by revision number
-func (repo *AppRevisionRepository) AppRevisionByInstanceIDAndRevisionNumber(projectID uint, appInstanceId string, revisionNumber uint) (*models.AppRevision, error) {
-	return nil, errors.New("cannot read database")
-}
-
-// LatestNumberedAppRevision finds the latest numbered app revision
-func (repo *AppRevisionRepository) LatestNumberedAppRevision(projectID uint, appInstanceId string) (*models.AppRevision, error) {
+// AppRevisionById finds an app revision by revision number
+func (repo *AppRevisionRepository) AppRevisionById(projectID uint, appRevisionId string) (*models.AppRevision, error) {
 	return nil, errors.New("cannot read database")
 }