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

Merge pull request #1167 from porter-dev/master

improve loading time
sunguroku 4 лет назад
Родитель
Сommit
0502639edc

+ 1 - 4
cli/cmd/deploy/deploy.go

@@ -3,7 +3,6 @@ package deploy
 import (
 	"context"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -328,10 +327,8 @@ func GetEnvFromConfig(config map[string]interface{}) (map[string]string, error)
 	envConfig, err := getNestedMap(config, "container", "env", "normal")
 
 	// if the field is not found, set envConfig to an empty map; this release has no env set
-	if e := (&NestedMapFieldNotFoundError{}); errors.As(err, &e) {
+	if err != nil {
 		envConfig = make(map[string]interface{})
-	} else if err != nil {
-		return nil, fmt.Errorf("could not get environment variables from release: %s", err.Error())
 	}
 
 	mapEnvConfig := make(map[string]string)

+ 42 - 14
dashboard/src/components/porter-form/field-components/ArrayInput.tsx

@@ -8,15 +8,22 @@ import {
 import useFormField from "../hooks/useFormField";
 import { hasSetValue } from "../utils";
 
+// this is used to set validation for the below form component in case
+// input validation needs to get more complicated in the future
+const validateArray = (arr: any[]) => {
+  return arr.some((x) => x);
+};
+
 const ArrayInput: React.FC<ArrayInputField> = (props) => {
-  const { state, variables, setVars } = useFormField<ArrayInputFieldState>(
-    props.id,
-    {
+  const { state, variables, setVars, setValidation } =
+    useFormField<ArrayInputFieldState>(props.id, {
       initVars: {
         [props.variable]: hasSetValue(props) ? props.value[0] : [],
       },
-    }
-  );
+      initValidation: {
+        validated: validateArray(hasSetValue(props) ? props.value[0] : []),
+      },
+    });
 
   if (state == undefined) return <></>;
 
@@ -26,10 +33,17 @@ const ArrayInput: React.FC<ArrayInputField> = (props) => {
         <DeleteButton
           onClick={() => {
             setVars((prev) => {
+              const val = prev[props.variable]
+                .slice(0, i)
+                .concat(prev[props.variable].slice(i + 1));
+              setValidation((prev) => {
+                return {
+                  ...prev,
+                  validated: validateArray(val),
+                };
+              });
               return {
-                [props.variable]: prev[props.variable]
-                  .slice(0, i)
-                  .concat(prev[props.variable].slice(i + 1)),
+                [props.variable]: val,
               };
             });
           }}
@@ -53,12 +67,19 @@ const ArrayInput: React.FC<ArrayInputField> = (props) => {
                 onChange={(e: any) => {
                   e.persist();
                   setVars((prev) => {
+                    const val = prev[props.variable]?.map(
+                      (t: string, j: number) => {
+                        return i == j ? e.target.value : t;
+                      }
+                    );
+                    setValidation((prev) => {
+                      return {
+                        ...prev,
+                        validated: validateArray(val),
+                      };
+                    });
                     return {
-                      [props.variable]: prev[props.variable]?.map(
-                        (t: string, j: number) => {
-                          return i == j ? e.target.value : t;
-                        }
-                      ),
+                      [props.variable]: val,
                     };
                   });
                 }}
@@ -74,7 +95,10 @@ const ArrayInput: React.FC<ArrayInputField> = (props) => {
 
   return (
     <StyledInputArray>
-      <Label>{props.label}</Label>
+      <Label>
+        {props.label}
+        {props.required && <Required>{" *"}</Required>}
+      </Label>
       {variables[props.variable] === 0 ? (
         <></>
       ) : (
@@ -186,3 +210,7 @@ const StyledInputArray = styled.div`
   margin-bottom: 15px;
   margin-top: 22px;
 `;
+
+const Required = styled.span`
+  color: #fc4976;
+`;

+ 2 - 2
dashboard/src/components/porter-form/field-components/Checkbox.tsx

@@ -60,9 +60,9 @@ export const getFinalVariablesForCheckbox: GetFinalVariablesFunction = (
 ) => {
   // Read from revision values if unrendered (and therefore not in form state)
   if (vars[props.variable] === null || vars[props.variable] === undefined) {
-    if (props.value[0] === false) {
+    if (props.value && props.value[0] === false) {
       return { [props.variable]: false };
-    } else if (props.value[0] === true) {
+    } else if (props.value && props.value[0] === true) {
       return { [props.variable]: true };
     }
   }

+ 3 - 1
dashboard/src/main/home/cluster-dashboard/chart/Chart.tsx

@@ -99,7 +99,9 @@ const Chart: React.FunctionComponent<Props> = ({
         let urlParams = new URLSearchParams(location.search);
         let cluster = urlParams.get("cluster");
         let route = `${match.url}/${cluster}/${chart.namespace}/${chart.name}`;
-        pushFiltered({ location, history }, route, ["project_id"]);
+        pushFiltered({ location, history }, route, ["project_id"], {
+          chart_revision: chart.version,
+        });
       }}
     >
       <Title>

+ 10 - 28
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChartWrapper.tsx

@@ -5,7 +5,7 @@ import { RouteComponentProps, withRouter } from "react-router";
 
 import { ChartType, StorageType } from "shared/types";
 import api from "shared/api";
-import { pushFiltered } from "shared/routing";
+import { getQueryParam, pushFiltered } from "shared/routing";
 import ExpandedJobChart from "./ExpandedJobChart";
 import ExpandedChart from "./ExpandedChart";
 import Loading from "components/Loading";
@@ -34,42 +34,24 @@ class ExpandedChartWrapper extends Component<PropsType, StateType> {
     let { currentProject, currentCluster } = this.context;
     if (currentProject && currentCluster) {
       // TODO: add query for retrieving max revision #
+      const lastCheckedRevision = getQueryParam(this.props, "chart_revision");
+
       api
-        .getRevisions(
+        .getChart(
           "<token>",
           {
             namespace: namespace,
             cluster_id: currentCluster.id,
             storage: StorageType.Secret,
           },
-          { id: currentProject.id, name: chartName }
+          {
+            name: chartName,
+            revision: Number(lastCheckedRevision),
+            id: currentProject.id,
+          }
         )
         .then((res) => {
-          res.data.sort((a: ChartType, b: ChartType) => {
-            return -(a.version - b.version);
-          });
-          let maxVersion = res.data[0].version;
-          api
-            .getChart(
-              "<token>",
-              {
-                namespace: namespace,
-                cluster_id: currentCluster.id,
-                storage: StorageType.Secret,
-              },
-              {
-                name: chartName,
-                revision: maxVersion,
-                id: currentProject.id,
-              }
-            )
-            .then((res) => {
-              this.setState({ currentChart: res.data, loading: false });
-            })
-            .catch((err) => {
-              console.log("err", err.response.data);
-              this.setState({ loading: false });
-            });
+          this.setState({ currentChart: res.data, loading: false });
         })
         .catch((err) => {
           console.log("err", err.response.data);

+ 29 - 2
internal/helm/agent.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 
 	"github.com/pkg/errors"
+	"github.com/porter-dev/porter/internal/helm/loader"
 	"github.com/porter-dev/porter/internal/kubernetes"
 	"github.com/porter-dev/porter/internal/models"
 	"github.com/porter-dev/porter/internal/repository"
@@ -36,13 +37,39 @@ func (a *Agent) ListReleases(
 func (a *Agent) GetRelease(
 	name string,
 	version int,
+	getDeps bool,
 ) (*release.Release, error) {
 	// Namespace is already known by the RESTClientGetter.
 	cmd := action.NewGet(a.ActionConfig)
 
 	cmd.Version = version
 
-	return cmd.Run(name)
+	release, err := cmd.Run(name)
+
+	if getDeps {
+		for _, dep := range release.Chart.Metadata.Dependencies {
+			depExists := false
+
+			for _, currDep := range release.Chart.Dependencies() {
+				// we just case on name for now -- there might be edge cases we're missing
+				// but this will cover 99% of cases
+				if dep.Name == currDep.Name() {
+					depExists = true
+					break
+				}
+			}
+
+			if !depExists {
+				depChart, err := loader.LoadChartPublic(dep.Repository, dep.Name, dep.Version)
+
+				if err == nil {
+					release.Chart.AddDependency(depChart)
+				}
+			}
+		}
+	}
+
+	return release, err
 }
 
 // GetReleaseHistory returns a list of charts for a specific release
@@ -88,7 +115,7 @@ func (a *Agent) UpgradeReleaseByValues(
 	doAuth *oauth2.Config,
 ) (*release.Release, error) {
 	// grab the latest release
-	rel, err := a.GetRelease(conf.Name, 0)
+	rel, err := a.GetRelease(conf.Name, 0, true)
 
 	if err != nil {
 		return nil, fmt.Errorf("Could not get release to be upgraded: %v", err)

+ 24 - 1
internal/helm/loader/loader.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"io/ioutil"
 	"net/http"
+	"net/url"
 	"strings"
 
 	"github.com/porter-dev/porter/internal/models"
@@ -140,7 +141,11 @@ func LoadChart(client *BasicAuthClient, repoURL, chartName, chartVersion string)
 	}
 
 	trimmedRepoURL := strings.TrimSuffix(strings.TrimSpace(repoURL), "/")
-	chartURL := trimmedRepoURL + "/" + strings.TrimPrefix(cv.URLs[0], "/")
+	chartURL := cv.URLs[0]
+
+	if !isValidURL(chartURL) {
+		chartURL = trimmedRepoURL + "/" + strings.TrimPrefix(cv.URLs[0], "/")
+	}
 
 	// download tgz
 	req, err := http.NewRequest("GET", chartURL, nil)
@@ -178,3 +183,21 @@ func LoadChart(client *BasicAuthClient, repoURL, chartName, chartVersion string)
 func LoadChartPublic(repoURL, chartName, chartVersion string) (*chart.Chart, error) {
 	return LoadChart(&BasicAuthClient{}, repoURL, chartName, chartVersion)
 }
+
+// Helper method to test if chart repo URL is valid, or is a path. Chartmuseum saves URLs
+// as paths, other Helm repositories do not.
+func isValidURL(testURI string) bool {
+	_, err := url.ParseRequestURI(testURI)
+
+	if err != nil {
+		return false
+	}
+
+	u, err := url.Parse(testURI)
+
+	if err != nil || u.Scheme == "" || u.Host == "" {
+		return false
+	}
+
+	return true
+}

+ 0 - 5
internal/integrations/ci/actions/actions.go

@@ -136,11 +136,6 @@ func (g *GithubActions) Cleanup() error {
 		}
 	}
 
-	// delete the porter token secret
-	if err := g.deleteGithubSecret(client, g.getPorterTokenSecretName()); err != nil {
-		return err
-	}
-
 	return g.deleteGithubFile(client, g.getPorterYMLFileName())
 }
 

+ 10 - 10
server/api/release_handler.go

@@ -121,7 +121,7 @@ func (app *App) HandleGetRelease(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	release, err := agent.GetRelease(form.Name, form.Revision)
+	release, err := agent.GetRelease(form.Name, form.Revision, false)
 
 	if err != nil {
 		app.sendExternalError(err, http.StatusNotFound, HTTPError{
@@ -281,7 +281,7 @@ func (app *App) HandleGetReleaseComponents(w http.ResponseWriter, r *http.Reques
 		return
 	}
 
-	release, err := agent.GetRelease(form.Name, form.Revision)
+	release, err := agent.GetRelease(form.Name, form.Revision, false)
 
 	if err != nil {
 		app.sendExternalError(err, http.StatusNotFound, HTTPError{
@@ -338,7 +338,7 @@ func (app *App) HandleGetReleaseControllers(w http.ResponseWriter, r *http.Reque
 		return
 	}
 
-	release, err := agent.GetRelease(form.Name, form.Revision)
+	release, err := agent.GetRelease(form.Name, form.Revision, false)
 
 	if err != nil {
 		app.sendExternalError(err, http.StatusNotFound, HTTPError{
@@ -478,7 +478,7 @@ func (app *App) HandleGetReleaseAllPods(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	release, err := agent.GetRelease(form.Name, form.Revision)
+	release, err := agent.GetRelease(form.Name, form.Revision, false)
 
 	if err != nil {
 		app.sendExternalError(err, http.StatusNotFound, HTTPError{
@@ -636,7 +636,7 @@ func (app *App) HandleGetJobStatus(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	release, err := agent.GetRelease(form.Name, form.Revision)
+	release, err := agent.GetRelease(form.Name, form.Revision, false)
 
 	if err != nil {
 		app.sendExternalError(err, http.StatusNotFound, HTTPError{
@@ -844,7 +844,7 @@ func (app *App) HandleCreateWebhookToken(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	rel, err := agent.GetRelease(name, 0)
+	rel, err := agent.GetRelease(name, 0, false)
 
 	if err != nil {
 		app.handleErrorDataRead(err, w)
@@ -970,7 +970,7 @@ func (app *App) HandleUpgradeRelease(w http.ResponseWriter, r *http.Request) {
 
 	// if the chart version is set, load a chart from the repo
 	if form.ChartVersion != "" {
-		release, err := agent.GetRelease(form.Name, 0)
+		release, err := agent.GetRelease(form.Name, 0, false)
 
 		if err != nil {
 			app.sendExternalError(err, http.StatusNotFound, HTTPError{
@@ -1220,7 +1220,7 @@ func (app *App) HandleReleaseDeployWebhook(w http.ResponseWriter, r *http.Reques
 		return
 	}
 
-	rel, err := agent.GetRelease(form.Name, 0)
+	rel, err := agent.GetRelease(form.Name, 0, false)
 
 	// repository is set to current repository by default
 	commit := vals["commit"][0]
@@ -1402,7 +1402,7 @@ func (app *App) HandleReleaseUpdateJobImages(w http.ResponseWriter, r *http.Requ
 		go func() {
 			defer wg.Done()
 			// read release via agent
-			rel, err := agent.GetRelease(releases[index].Name, 0)
+			rel, err := agent.GetRelease(releases[index].Name, 0, false)
 
 			if err != nil {
 				mu.Lock()
@@ -1495,7 +1495,7 @@ func (app *App) HandleRollbackRelease(w http.ResponseWriter, r *http.Request) {
 	}
 
 	// get the full release data for GHA updating
-	rel, err := agent.GetRelease(form.Name, form.Revision)
+	rel, err := agent.GetRelease(form.Name, form.Revision, false)
 
 	if err != nil {
 		app.sendExternalError(err, http.StatusNotFound, HTTPError{

+ 10 - 2
server/router/router.go

@@ -915,7 +915,11 @@ func New(a *api.App) *chi.Mux {
 				"POST",
 				"/projects/{project_id}/releases/{name}/notifications",
 				auth.DoesUserHaveProjectAccess(
-					requestlog.NewHandler(a.HandleUpdateNotificationConfig, l),
+					auth.DoesUserHaveClusterAccess(
+						requestlog.NewHandler(a.HandleUpdateNotificationConfig, l),
+						mw.URLParam,
+						mw.BodyParam,
+					),
 					mw.URLParam,
 					mw.WriteAccess,
 				),
@@ -925,7 +929,11 @@ func New(a *api.App) *chi.Mux {
 				"GET",
 				"/projects/{project_id}/releases/{name}/notifications",
 				auth.DoesUserHaveProjectAccess(
-					requestlog.NewHandler(a.HandleGetNotificationConfig, l),
+					auth.DoesUserHaveClusterAccess(
+						requestlog.NewHandler(a.HandleGetNotificationConfig, l),
+						mw.URLParam,
+						mw.QueryParam,
+					),
 					mw.URLParam,
 					mw.WriteAccess,
 				),