Skip to content

Commit

Permalink
enforce required releases in api
Browse files Browse the repository at this point in the history
  • Loading branch information
sgalsaleh committed Jun 14, 2024
1 parent 604ccc3 commit 28b553e
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 22 deletions.
1 change: 0 additions & 1 deletion pkg/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,6 @@ func RegisterSessionAuthRoutes(r *mux.Router, kotsStore store.Store, handler KOT
r.Name("ChangePassword").Path("/api/v1/password/change").Methods("PUT").
HandlerFunc(middleware.EnforceAccess(policy.PasswordChange, handler.ChangePassword))

// TODO NOW: when to stop this upgrade service?
// Start upgrade service
r.Name("StartUpgradeService").Path("/api/v1/app/{appSlug}/start-upgrade-service").Methods("POST").
HandlerFunc(middleware.EnforceAccess(policy.AppUpdate, handler.StartUpgradeService))
Expand Down
33 changes: 31 additions & 2 deletions pkg/handlers/upgrade_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (

"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/replicatedhq/kots/pkg/kotsutil"
"github.com/replicatedhq/kots/pkg/logger"
"github.com/replicatedhq/kots/pkg/reporting"
"github.com/replicatedhq/kots/pkg/store"
"github.com/replicatedhq/kots/pkg/updatechecker"
"github.com/replicatedhq/kots/pkg/upgradeservice"
upgradeservicetypes "github.com/replicatedhq/kots/pkg/upgradeservice/types"
)
Expand All @@ -29,8 +31,6 @@ func (h *Handler) StartUpgradeService(w http.ResponseWriter, r *http.Request) {
Success: false,
}

// TODO NOW: required releases

request := StartUpgradeServiceRequest{}
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
response.Error = "failed to decode request body"
Expand All @@ -49,6 +49,35 @@ func (h *Handler) StartUpgradeService(w http.ResponseWriter, r *http.Request) {
return
}

license, err := kotsutil.LoadLicenseFromBytes([]byte(foundApp.License))
if err != nil {
response.Error = "failed to parse app license"
logger.Error(errors.Wrap(err, response.Error))
JSON(w, http.StatusInternalServerError, response)
return
}

updates, err := updatechecker.GetAvailableUpdates(store.GetStore(), foundApp, license)
if err != nil {
response.Error = "failed to get available updates"
logger.Error(errors.Wrap(err, response.Error))
JSON(w, http.StatusInternalServerError, response)
return
}

isDeployable, nonDeployableCause := false, "update not found"
for _, u := range updates {
if u.UpdateCursor == request.UpdateCursor {
isDeployable, nonDeployableCause = u.IsDeployable, u.NonDeployableCause
break
}
}
if !isDeployable {
response.Error = nonDeployableCause
JSON(w, http.StatusBadRequest, response)
return
}

registrySettings, err := store.GetStore().GetRegistryDetailsForApp(foundApp.ID)
if err != nil {
response.Error = "failed to get registry details for app"
Expand Down
6 changes: 3 additions & 3 deletions pkg/updatechecker/updatechecker.go
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ func GetAvailableUpdates(kotsStore storepkg.Store, app *apptypes.App, license *k

availableUpdates := []types.AvailableUpdate{}
for _, u := range updates.Updates {
deployable, cause := isUpdateDeployable(updates.Updates, u)
deployable, cause := isUpdateDeployable(u.Cursor, updates.Updates)
availableUpdates = append(availableUpdates, types.AvailableUpdate{
VersionLabel: u.VersionLabel,
UpdateCursor: u.Cursor,
Expand All @@ -750,11 +750,11 @@ func GetAvailableUpdates(kotsStore storepkg.Store, app *apptypes.App, license *k
return availableUpdates, nil
}

func isUpdateDeployable(updates []upstreamtypes.Update, u upstreamtypes.Update) (bool, string) {
func isUpdateDeployable(updateCursor string, updates []upstreamtypes.Update) (bool, string) {
// iterate over updates in reverse since they are sorted in descending order
requiredUpdates := []upstreamtypes.Update{}
for i := len(updates) - 1; i >= 0; i-- {
if updates[i].Cursor == u.Cursor {
if updates[i].Cursor == updateCursor {
break
}
if updates[i].IsRequired {
Expand Down
32 changes: 16 additions & 16 deletions pkg/updatechecker/updatechecker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1095,74 +1095,74 @@ func newMockServerWithReleases(channelReleases []upstream.ChannelRelease, wantEr
}
func TestIsUpdateDeployable(t *testing.T) {
tests := []struct {
name string
updates []upstreamtypes.Update
u upstreamtypes.Update
want bool
wantCause string
name string
updateCursor string
updates []upstreamtypes.Update
want bool
wantCause string
}{
{
name: "one update",
name: "one update",
updateCursor: "3",
updates: []upstreamtypes.Update{
{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
},
u: upstreamtypes.Update{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
want: true,
wantCause: "",
},
{
name: "no required updates",
name: "no required updates",
updateCursor: "3",
updates: []upstreamtypes.Update{
{VersionLabel: "1.0.4", Cursor: "4", IsRequired: false},
{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
{VersionLabel: "1.0.2", Cursor: "2", IsRequired: false},
{VersionLabel: "1.0.1", Cursor: "1", IsRequired: false},
},
u: upstreamtypes.Update{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
want: true,
wantCause: "",
},
{
name: "no required releases before it",
name: "no required releases before it",
updateCursor: "3",
updates: []upstreamtypes.Update{
{VersionLabel: "1.0.4", Cursor: "4", IsRequired: true},
{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
{VersionLabel: "1.0.2", Cursor: "2", IsRequired: false},
{VersionLabel: "1.0.1", Cursor: "1", IsRequired: false},
},
u: upstreamtypes.Update{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
want: true,
wantCause: "",
},
{
name: "one required release before it",
name: "one required release before it",
updateCursor: "3",
updates: []upstreamtypes.Update{
{VersionLabel: "1.0.4", Cursor: "4", IsRequired: false},
{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
{VersionLabel: "1.0.2", Cursor: "2", IsRequired: true},
{VersionLabel: "1.0.1", Cursor: "1", IsRequired: false},
},
u: upstreamtypes.Update{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
want: false,
wantCause: "This version cannot be deployed because version 1.0.2 is required and must be deployed first.",
},
{
name: "two required releases before it",
name: "two required releases before it",
updateCursor: "3",
updates: []upstreamtypes.Update{
{VersionLabel: "1.0.4", Cursor: "4", IsRequired: false},
{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
{VersionLabel: "1.0.2", Cursor: "2", IsRequired: true},
{VersionLabel: "1.0.1", Cursor: "1", IsRequired: true},
},
u: upstreamtypes.Update{VersionLabel: "1.0.3", Cursor: "3", IsRequired: false},
want: false,
wantCause: "This version cannot be deployed because versions 1.0.2, 1.0.1 are required and must be deployed first.",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, msg := isUpdateDeployable(tt.updates, tt.u)
result, msg := isUpdateDeployable(tt.updateCursor, tt.updates)
assert.Equal(t, tt.want, result)
assert.Equal(t, tt.wantCause, msg)
})
Expand Down

0 comments on commit 28b553e

Please sign in to comment.