瀏覽代碼

add casing to make sure revisions are up to date when intended

Alexander Belanger 3 年之前
父節點
當前提交
6565aac89c

+ 23 - 0
api/server/handlers/release/upgrade.go

@@ -118,6 +118,29 @@ func (c *UpgradeReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 		conf.Chart = chart
 	}
 
+	// if LatestRevision is set, check that the revision matches the latest revision in the database
+	if request.LatestRevision != 0 {
+		currHelmRelease, err := helmAgent.GetRelease(helmRelease.Name, 0, false)
+
+		if err != nil {
+			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+				fmt.Errorf("could not retrieve latest revision"),
+				http.StatusBadRequest,
+			))
+
+			return
+		}
+
+		if currHelmRelease.Version != int(request.LatestRevision) {
+			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+				fmt.Errorf("The provided revision is not up to date with the current revision. Provided revision is %d, latest revision is %d. If you would like to deploy from this revision, please revert first and update the configuration.", request.LatestRevision, currHelmRelease.Version),
+				http.StatusBadRequest,
+			))
+
+			return
+		}
+	}
+
 	newHelmRelease, upgradeErr := helmAgent.UpgradeRelease(conf, request.Values, c.Config().DOConf)
 
 	if upgradeErr == nil && newHelmRelease != nil {

+ 23 - 0
api/server/handlers/v1/release/upgrade.go

@@ -120,6 +120,29 @@ func (c *UpgradeReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 
 	conf.Values = request.Values
 
+	// if LatestRevision is set, check that the revision matches the latest revision in the database
+	if request.LatestRevision != 0 {
+		currHelmRelease, err := helmAgent.GetRelease(helmRelease.Name, 0, false)
+
+		if err != nil {
+			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+				fmt.Errorf("could not retrieve latest revision"),
+				http.StatusBadRequest,
+			))
+
+			return
+		}
+
+		if currHelmRelease.Version != int(request.LatestRevision) {
+			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+				fmt.Errorf("The provided revision is not up to date with the current revision. Provided revision is %d, latest revision is %d. If you would like to deploy from this revision, please revert first and update the configuration.", request.LatestRevision, currHelmRelease.Version),
+				http.StatusBadRequest,
+			))
+
+			return
+		}
+	}
+
 	newHelmRelease, upgradeErr := helmAgent.UpgradeReleaseByValues(conf, c.Config().DOConf)
 
 	if upgradeErr == nil && newHelmRelease != nil {

+ 8 - 0
api/types/release.go

@@ -110,11 +110,19 @@ type V1UpgradeReleaseRequest struct {
 
 	// The Porter charts version to upgrade the release with
 	ChartVersion string `json:"version"`
+
+	// (optional) if set, the backend will validate that the user was upgrading from the revision specified by
+	// LatestRevision, and there hasn't been an upgrade in the meantime.
+	LatestRevision uint `json:"latest_revision"`
 }
 
 type UpgradeReleaseRequest struct {
 	Values       string `json:"values" form:"required"`
 	ChartVersion string `json:"version"`
+
+	// (optional) if set, the backend will validate that the user was upgrading from the revision specified by
+	// LatestRevision, and there hasn't been an upgrade in the meantime.
+	LatestRevision uint `json:"latest_revision"`
 }
 
 type UpdateImageBatchRequest struct {

+ 4 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -312,6 +312,9 @@ const ExpandedChart: React.FC<Props> = (props) => {
         "<token>",
         {
           values: valuesYaml,
+          // this is triggered from the Porter form, so we set the latest revision to ensure that the release is
+          // up to date
+          latest_revision: currentChart.version,
         },
         {
           id: currentProject.id,
@@ -369,6 +372,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
           {
             values: valuesYaml,
             version: version,
+            latest_revision: currentChart.version,
           },
           {
             id: currentProject.id,

+ 1 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/SettingsSection.tsx

@@ -116,6 +116,7 @@ const SettingsSection: React.FC<PropsType> = ({
         "<token>",
         {
           values: conf,
+          latest_revision: currentChart?.version,
         },
         {
           id: currentProject.id,

+ 1 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/ValuesYaml.tsx

@@ -64,6 +64,7 @@ export default class ValuesYaml extends Component<PropsType, StateType> {
         "<token>",
         {
           values: valuesString,
+          latest_revision: this.props.currentChart.version,
         },
         {
           id: currentProject.id,

+ 1 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/build-settings/BuildSettingsTab.tsx

@@ -122,6 +122,7 @@ const BuildSettingsTab: React.FC<Props> = ({
         "<token>",
         {
           values: valuesYaml,
+          latest_revision: chart.version,
         },
         {
           id: currentProject.id,

+ 1 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/useJobs.ts

@@ -354,6 +354,7 @@ export const useJobs = (chart: ChartType) => {
         "<token>",
         {
           values: yamlValues,
+          latest_revision: chart.version,
         },
         {
           id: currentProject.id,

+ 2 - 0
dashboard/src/shared/hooks/useChart.ts

@@ -67,6 +67,7 @@ export const useChart = (oldChart: ChartType, closeChart: () => void) => {
         {
           values: valuesYaml,
           version: chart.latest_version,
+          latest_revision: chart.version,
         },
         {
           id: currentProject.id,
@@ -237,6 +238,7 @@ export const useChart = (oldChart: ChartType, closeChart: () => void) => {
         "<token>",
         {
           values,
+          latest_revision: chart.version,
         },
         {
           id: currentProject.id,