ianedwards 2 лет назад
Родитель
Сommit
ca78803ee5

+ 10 - 22
api/client/porter_app.go

@@ -215,40 +215,28 @@ func (c *Client) ValidatePorterApp(
 	return resp, err
 }
 
-// ApplyPorterAppInput is the input struct to ApplyPorterApp
-type ApplyPorterAppInput struct {
-	ProjectID        uint
-	ClusterID        uint
-	Base64AppProto   string
-	DeploymentTarget string
-	AppRevisionID    string
-	ForceBuild       bool
-	Variables        map[string]string
-	Secrets          map[string]string
-	HardEnvUpdate    bool
-}
-
 // ApplyPorterApp takes in a base64 encoded app definition and applies it to the cluster
 func (c *Client) ApplyPorterApp(
 	ctx context.Context,
-	inp ApplyPorterAppInput,
+	projectID, clusterID uint,
+	base64AppProto string,
+	deploymentTarget string,
+	appRevisionID string,
+	forceBuild bool,
 ) (*porter_app.ApplyPorterAppResponse, error) {
 	resp := &porter_app.ApplyPorterAppResponse{}
 
 	req := &porter_app.ApplyPorterAppRequest{
-		Base64AppProto:     inp.Base64AppProto,
-		DeploymentTargetId: inp.DeploymentTarget,
-		AppRevisionID:      inp.AppRevisionID,
-		ForceBuild:         inp.ForceBuild,
-		Variables:          inp.Variables,
-		Secrets:            inp.Secrets,
-		HardEnvUpdate:      inp.HardEnvUpdate,
+		Base64AppProto:     base64AppProto,
+		DeploymentTargetId: deploymentTarget,
+		AppRevisionID:      appRevisionID,
+		ForceBuild:         forceBuild,
 	}
 
 	err := c.postRequest(
 		fmt.Sprintf(
 			"/projects/%d/clusters/%d/apps/apply",
-			inp.ProjectID, inp.ClusterID,
+			projectID, clusterID,
 		),
 		req,
 		resp,

+ 4 - 14
api/server/handlers/porter_app/apply.go

@@ -47,15 +47,10 @@ func NewApplyPorterAppHandler(
 
 // ApplyPorterAppRequest is the request object for the /apps/apply endpoint
 type ApplyPorterAppRequest struct {
-	Base64AppProto     string            `json:"b64_app_proto"`
-	DeploymentTargetId string            `json:"deployment_target_id"`
-	AppRevisionID      string            `json:"app_revision_id"`
-	ForceBuild         bool              `json:"force_build"`
-	Variables          map[string]string `json:"variables"`
-	Secrets            map[string]string `json:"secrets"`
-	// HardEnvUpdate is used to remove any variables that are not specified in the request.  If false, the request will only update the variables specified in the request,
-	// and leave all other variables untouched.
-	HardEnvUpdate bool `json:"hard_env_update"`
+	Base64AppProto     string `json:"b64_app_proto"`
+	DeploymentTargetId string `json:"deployment_target_id"`
+	AppRevisionID      string `json:"app_revision_id"`
+	ForceBuild         bool   `json:"force_build"`
 }
 
 // ApplyPorterAppResponse is the response object for the /apps/apply endpoint
@@ -186,11 +181,6 @@ func (c *ApplyPorterAppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 		App:                 appProto,
 		PorterAppRevisionId: appRevisionID,
 		ForceBuild:          request.ForceBuild,
-		AppEnv: &porterv1.EnvGroupVariables{
-			Normal: request.Variables,
-			Secret: request.Secrets,
-		},
-		IsHardEnvUpdate: request.HardEnvUpdate,
 	})
 	ccpResp, err := c.Config().ClusterControlPlaneClient.ApplyPorterApp(ctx, applyReq)
 	if err != nil {

+ 13 - 31
cli/cmd/v2/apply.go

@@ -78,10 +78,6 @@ func Apply(ctx context.Context, inp ApplyInput) error {
 	// overrides incorporated into the app contract baed on the deployment target
 	var overrides *porter_app.EncodedAppWithEnv
 
-	// env variables and secrets to be passed to the apply endpoint
-	var envVariables map[string]string
-	var envSecrets map[string]string
-
 	appName := inp.AppName
 	if porterYamlExists {
 		porterYaml, err := os.ReadFile(filepath.Clean(inp.PorterYamlPath))
@@ -124,6 +120,16 @@ func Apply(ctx context.Context, inp ApplyInput) error {
 			return fmt.Errorf("unable to create porter app from yaml: %w", err)
 		}
 
+		envGroupResp, err := client.CreateOrUpdateAppEnvironment(ctx, cliConf.Project, cliConf.Cluster, appName, deploymentTargetID, parseResp.EnvVariables, parseResp.EnvSecrets, parseResp.B64AppProto)
+		if err != nil {
+			return fmt.Errorf("error calling create or update app environment group endpoint: %w", err)
+		}
+
+		b64AppProto, err = updateEnvGroupsInProto(ctx, b64AppProto, envGroupResp.EnvGroups)
+		if err != nil {
+			return fmt.Errorf("error updating app env group in proto: %w", err)
+		}
+
 		color.New(color.FgGreen).Printf("Successfully parsed Porter YAML: applying app \"%s\"\n", appName) // nolint:errcheck,gosec
 	}
 
@@ -176,17 +182,7 @@ func Apply(ctx context.Context, inp ApplyInput) error {
 	}
 	base64AppProto := validateResp.ValidatedBase64AppProto
 
-	applyInput := api.ApplyPorterAppInput{
-		ProjectID:        cliConf.Project,
-		ClusterID:        cliConf.Cluster,
-		Base64AppProto:   base64AppProto,
-		DeploymentTarget: deploymentTargetID,
-		ForceBuild:       forceBuild,
-		Variables:        envVariables,
-		Secrets:          envSecrets,
-	}
-
-	applyResp, err := client.ApplyPorterApp(ctx, applyInput)
+	applyResp, err := client.ApplyPorterApp(ctx, cliConf.Project, cliConf.Cluster, base64AppProto, deploymentTargetID, "", forceBuild)
 	if err != nil {
 		return fmt.Errorf("error calling apply endpoint: %w", err)
 	}
@@ -284,14 +280,7 @@ func Apply(ctx context.Context, inp ApplyInput) error {
 		buildMetadata["end_time"] = time.Now().UTC()
 		_ = updateExistingEvent(ctx, client, appName, cliConf.Project, cliConf.Cluster, deploymentTargetID, types.PorterAppEventType_Build, eventID, types.PorterAppEventStatus_Success, buildMetadata)
 
-		applyInput = api.ApplyPorterAppInput{
-			ProjectID:     cliConf.Project,
-			ClusterID:     cliConf.Cluster,
-			AppRevisionID: applyResp.AppRevisionId,
-			ForceBuild:    !forceBuild,
-		}
-
-		applyResp, err = client.ApplyPorterApp(ctx, applyInput)
+		applyResp, err = client.ApplyPorterApp(ctx, cliConf.Project, cliConf.Cluster, "", "", applyResp.AppRevisionId, !forceBuild)
 		if err != nil {
 			return fmt.Errorf("apply error post-build: %w", err)
 		}
@@ -338,14 +327,7 @@ func Apply(ctx context.Context, inp ApplyInput) error {
 		metadata["end_time"] = time.Now().UTC()
 		_ = updateExistingEvent(ctx, client, appName, cliConf.Project, cliConf.Cluster, deploymentTargetID, types.PorterAppEventType_PreDeploy, eventID, eventStatus, metadata)
 
-		applyInput = api.ApplyPorterAppInput{
-			ProjectID:     cliConf.Project,
-			ClusterID:     cliConf.Cluster,
-			AppRevisionID: applyResp.AppRevisionId,
-			ForceBuild:    !forceBuild,
-		}
-
-		applyResp, err = client.ApplyPorterApp(ctx, applyInput)
+		applyResp, err = client.ApplyPorterApp(ctx, cliConf.Project, cliConf.Cluster, "", "", applyResp.AppRevisionId, !forceBuild)
 		if err != nil {
 			return fmt.Errorf("apply error post-predeploy: %w", err)
 		}

+ 41 - 13
dashboard/src/main/home/app-dashboard/app-view/AppDataContainer.tsx

@@ -218,17 +218,50 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
         return;
       }
 
+      // updates the default env group associated with this app to store app specific env vars
+      const res = await api.updateEnvironmentGroupV2(
+        "<token>",
+        {
+          deployment_target_id: deploymentTarget.id,
+          variables,
+          secrets,
+          b64_app_proto: btoa(validatedAppProto.toJsonString()),
+          remove_missing: true,
+        },
+        {
+          id: projectId,
+          cluster_id: clusterId,
+          app_name: porterAppRecord.name,
+        }
+      );
+
+      const updatedEnvGroups = z
+        .object({
+          env_groups: z
+            .object({
+              name: z.string(),
+              latest_version: z.coerce.bigint(),
+            })
+            .array(),
+        })
+        .parse(res.data);
+
+      const protoWithUpdatedEnv = new PorterApp({
+        ...validatedAppProto,
+        envGroups: updatedEnvGroups.env_groups.map((eg) => ({
+          name: eg.name,
+          version: eg.latest_version,
+        })),
+      });
+
       // force_build will create a new 0 revision that will not be deployed
       // but will be used to hydrate values when the workflow is run
       await api.applyApp(
         "<token>",
         {
-          b64_app_proto: btoa(validatedAppProto.toJsonString()),
+          b64_app_proto: btoa(protoWithUpdatedEnv.toJsonString()),
           deployment_target_id: deploymentTarget.id,
           force_build: needsRebuild,
-          variables,
-          secrets,
-          hard_env_update: true,
         },
         {
           project_id: projectId,
@@ -274,10 +307,8 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
       // redirect to the default tab after save
       history.push(`/apps/${porterAppRecord.name}/${DEFAULT_TAB}`);
     } catch (err) {
-      showIntercomWithMessage({
-        message: "I am running into an issue updating my application.",
-      });
-
+      showIntercomWithMessage({ message: "I am running into an issue updating my application." });
+      
       let message =
         "App update failed: please try again or contact support@porter.run if the error persists.";
       let stack = "Unable to get error stack";
@@ -373,15 +404,12 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
             errorMessage = `${errorMessage} - ${serviceErrorMessage}`;
           }
           errorMessage = `${errorMessage}. To undo all changes, refresh the page.`;
-        } else if (appErrors.includes("message")) {
-          // this is the high level error message coming from the apply
+        } else if (appErrors.includes("message")) {  // this is the high level error message coming from the apply
           errorMessage = errors.app?.message ?? errorMessage;
         }
       }
 
-      showIntercomWithMessage({
-        message: "I am running into an issue updating my application.",
-      });
+      showIntercomWithMessage({ message: "I am running into an issue updating my application." });
       updateAppStep({
         step: "porter-app-update-failure",
         errorMessage: `Form validation error (visible to user): ${errorMessage}. Stringified JSON errors (invisible to user): ${stringifiedJson}`,

+ 46 - 25
dashboard/src/main/home/app-dashboard/create-app/CreateApp.tsx

@@ -282,14 +282,45 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
           }
         );
 
-        await api.applyApp(
+        const res = await api.updateEnvironmentGroupV2(
           "<token>",
           {
+            deployment_target_id: deploymentTarget.deployment_target_id,
+            variables: variables,
             b64_app_proto: btoa(app.toJsonString()),
+            secrets: secrets,
+          },
+          {
+            id: currentProject.id,
+            cluster_id: currentCluster.id,
+            app_name: app.name,
+          }
+        );
+
+        const updatedEnvGroups = z
+          .object({
+            env_groups: z
+              .object({
+                name: z.string(),
+                latest_version: z.coerce.bigint(),
+              })
+              .array(),
+          })
+          .parse(res.data);
+
+        const protoWithUpdatedEnv = new PorterApp({
+          ...app,
+          envGroups: updatedEnvGroups.env_groups.map((eg) => ({
+            name: eg.name,
+            version: eg.latest_version,
+          })),
+        });
+
+        await api.applyApp(
+          "<token>",
+          {
+            b64_app_proto: btoa(protoWithUpdatedEnv.toJsonString()),
             deployment_target_id: deploymentTarget.deployment_target_id,
-            variables,
-            secrets,
-            hard_env_update: true
           },
           {
             project_id: currentProject.id,
@@ -306,9 +337,7 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
 
         return true;
       } catch (err) {
-        showIntercomWithMessage({
-          message: "I am running into an issue launching an application.",
-        });
+        showIntercomWithMessage({ message: "I am running into an issue launching an application." });
 
         if (axios.isAxiosError(err) && err.response?.data?.error) {
           updateAppStep({
@@ -404,9 +433,7 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
         }
       }
 
-      showIntercomWithMessage({
-        message: "I am running into an issue launching an application.",
-      });
+      showIntercomWithMessage({ message: "I am running into an issue launching an application." });
 
       updateAppStep({
         step: "stack-launch-failure",
@@ -587,12 +614,12 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
                                       porterYamlPath={value}
                                       projectId={currentProject.id}
                                       repoId={source.git_repo_id}
-                                      repoOwner={
-                                        source.git_repo_name.split("/")[0]
-                                      }
-                                      repoName={
-                                        source.git_repo_name.split("/")[1]
-                                      }
+                                      repoOwner={source.git_repo_name.split(
+                                        "/"
+                                      )[0]}
+                                      repoName={source.git_repo_name.split(
+                                        "/"
+                                      )[1]}
                                       branch={source.git_branch}
                                     />
                                   )}
@@ -645,9 +672,8 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
                             }
                           >
                             {detectedServices.count > 0
-                              ? `Detected ${detectedServices.count} service${
-                                  detectedServices.count > 1 ? "s" : ""
-                                } from porter.yaml.`
+                              ? `Detected ${detectedServices.count} service${detectedServices.count > 1 ? "s" : ""
+                              } from porter.yaml.`
                               : `Could not detect any services from porter.yaml. Make sure it exists in the root of your repo.`}
                           </Text>
                         </AppearingDiv>
@@ -659,9 +685,7 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
                       fieldArrayName={"app.services"}
                       maxCPU={currentClusterResources.maxCPU}
                       maxRAM={currentClusterResources.maxRAM}
-                      clusterContainsGPUNodes={
-                        currentClusterResources.clusterContainsGPUNodes
-                      }
+                      clusterContainsGPUNodes={currentClusterResources.clusterContainsGPUNodes}
                     />
                   </>,
                   <>
@@ -697,9 +721,6 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
                         fieldArrayName={"app.predeploy"}
                         maxCPU={currentClusterResources.maxCPU}
                         maxRAM={currentClusterResources.maxRAM}
-                        clusterContainsGPUNodes={
-                          currentClusterResources.clusterContainsGPUNodes
-                        }
                       />
                     </>
                   ),

+ 0 - 3
dashboard/src/shared/api.tsx

@@ -1004,9 +1004,6 @@ const applyApp = baseApi<
     b64_app_proto?: string;
     app_revision_id?: string;
     force_build?: boolean;
-    variables?: Record<string, string>;
-    secrets?: Record<string, string>;
-    hard_env_update?: boolean;
   },
   {
     project_id: number;

+ 1 - 1
go.mod

@@ -83,7 +83,7 @@ require (
 	github.com/matryer/is v1.4.0
 	github.com/nats-io/nats.go v1.24.0
 	github.com/open-policy-agent/opa v0.44.0
-	github.com/porter-dev/api-contracts v0.2.25
+	github.com/porter-dev/api-contracts v0.2.24
 	github.com/riandyrn/otelchi v0.5.1
 	github.com/santhosh-tekuri/jsonschema/v5 v5.0.1
 	github.com/stefanmcshane/helm v0.0.0-20221213002717-88a4a2c6e77d

+ 2 - 2
go.sum

@@ -1520,8 +1520,8 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw=
-github.com/porter-dev/api-contracts v0.2.25 h1:VQRxdksCPsTV6cd/ZgQ8nKltiOJaROKkK/642qyJKZ4=
-github.com/porter-dev/api-contracts v0.2.25/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
+github.com/porter-dev/api-contracts v0.2.24 h1:0Jas/m7l+FD+1VRGYg8lq6vxTZ77A79X4A1wZcTVrEI=
+github.com/porter-dev/api-contracts v0.2.24/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
 github.com/porter-dev/switchboard v0.0.3 h1:dBuYkiVLa5Ce7059d6qTe9a1C2XEORFEanhbtV92R+M=
 github.com/porter-dev/switchboard v0.0.3/go.mod h1:xSPzqSFMQ6OSbp42fhCi4AbGbQbsm6nRvOkrblFeXU4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=