Skip to content

Commit

Permalink
f
Browse files Browse the repository at this point in the history
  • Loading branch information
emosbaugh committed Oct 29, 2024
1 parent 7fe1ec5 commit cdc7539
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 26 deletions.
38 changes: 22 additions & 16 deletions pkg/store/kotsstore/downstream_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/replicatedhq/kots/pkg/kotsutil"
"github.com/replicatedhq/kots/pkg/logger"
"github.com/replicatedhq/kots/pkg/persistence"
"github.com/replicatedhq/kots/pkg/store"
"github.com/replicatedhq/kots/pkg/store/types"
"github.com/replicatedhq/kots/pkg/tasks"
"github.com/replicatedhq/kots/pkg/util"
Expand Down Expand Up @@ -426,7 +427,7 @@ func (s *KOTSStore) GetDownstreamVersions(appID string, clusterID string, downlo
if err := s.AddDownstreamVersionDetails(appID, clusterID, v, false); err != nil {
return nil, errors.Wrap(err, "failed to add details to latest downloaded version")
}
v.IsDeployable, v.NonDeployableCause, err = s.isAppVersionDeployable(appID, v, result, license.Spec.IsSemverRequired)
v.IsDeployable, v.NonDeployableCause, err = isAppVersionDeployable(s, appID, v, result, license.Spec.IsSemverRequired)
if err != nil {
return nil, errors.Wrapf(err, "failed to check if version %s is deployable", v.VersionLabel)
}
Expand Down Expand Up @@ -681,7 +682,7 @@ func (s *KOTSStore) AddDownstreamVersionsDetails(appID string, clusterID string,
}

for _, v := range versions {
v.IsDeployable, v.NonDeployableCause, err = s.isAppVersionDeployable(appID, v, allVersions, license.Spec.IsSemverRequired)
v.IsDeployable, v.NonDeployableCause, err = isAppVersionDeployable(s, appID, v, allVersions, license.Spec.IsSemverRequired)
if err != nil {
return errors.Wrapf(err, "failed to check if version %s is deployable", v.VersionLabel)
}
Expand Down Expand Up @@ -874,7 +875,7 @@ func isSameUpstreamRelease(v1 *downstreamtypes.DownstreamVersion, v2 *downstream
return v1.Semver.EQ(*v2.Semver)
}

func (s *KOTSStore) isAppVersionDeployable(appID string, version *downstreamtypes.DownstreamVersion, appVersions *downstreamtypes.DownstreamVersions, isSemverRequired bool) (bool, string, error) {
func isAppVersionDeployable(s store.Store, appID string, version *downstreamtypes.DownstreamVersion, appVersions *downstreamtypes.DownstreamVersions, isSemverRequired bool) (bool, string, error) {
if version.HasFailingStrictPreflights {
return false, "Deployment is disabled as a strict analyzer in this version's preflight checks has failed or has not been run.", nil
}
Expand Down Expand Up @@ -916,16 +917,6 @@ func (s *KOTSStore) isAppVersionDeployable(appID string, version *downstreamtype
}

if versionIndex > deployedVersionIndex {
if util.IsEmbeddedCluster() {
changed, err := s.didECClusterConfigChange(appID, version, appVersions.CurrentVersion)
if err != nil {
return false, "", errors.Wrapf(err, "failed to check if embedded cluster config changed for version %s", version.Sequence)
}
if changed {
return false, "Rollback is not supported, cluster configuration has changed.", nil
}
}

// this is a past version
// rollback support is based off of the latest downloaded version
for _, v := range appVersions.AllVersions {
Expand All @@ -937,6 +928,19 @@ func (s *KOTSStore) isAppVersionDeployable(appID string, version *downstreamtype
}
break
}

if util.IsEmbeddedCluster() {
// Compare the embedded cluster config of the version specified to the currently
// deployed version to check if it has changed. If it has, then we do not allow
// rollbacks.
changed, err := didECClusterConfigChange(s, appID, version, appVersions.CurrentVersion)
if err != nil {
return false, "", errors.Wrapf(err, "failed to check if embedded cluster config changed for version %d", version.Sequence)
}
if changed {
return false, "Rollback is not supported, cluster configuration has changed.", nil
}
}
}

// if semantic versioning is not enabled, only require versions from the same channel AND with a lower cursor/channel sequence
Expand Down Expand Up @@ -1024,14 +1028,16 @@ ALL_VERSIONS_LOOP:
return true, "", nil
}

func (s *KOTSStore) didECClusterConfigChange(appID string, version *downstreamtypes.DownstreamVersion, currentVersion *downstreamtypes.DownstreamVersion) (bool, error) {
// didECClusterConfigChange compares the embedded cluster config of the version specified to the
// currently deployed version to check if it has changed.
func didECClusterConfigChange(s store.Store, appID string, version *downstreamtypes.DownstreamVersion, currentVersion *downstreamtypes.DownstreamVersion) (bool, error) {
currentConf, err := s.GetEmbeddedClusterConfigForVersion(appID, currentVersion.Sequence)
if err != nil {
return false, errors.Wrapf(err, "failed to get embedded cluster config for current version %s", currentVersion.Sequence)
return false, errors.Wrapf(err, "failed to get embedded cluster config for current version %d", currentVersion.Sequence)
}
currentECConfigBytes, err := json.Marshal(currentConf)
if err != nil {
return false, errors.Wrapf(err, "failed to marshal embedded cluster config for current version %s", currentVersion.Sequence)
return false, errors.Wrapf(err, "failed to marshal embedded cluster config for current version %d", currentVersion.Sequence)
}
thisConf, err := s.GetEmbeddedClusterConfigForVersion(appID, version.Sequence)
if err != nil {
Expand Down
156 changes: 155 additions & 1 deletion pkg/store/kotsstore/downstream_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import (
"testing"

"github.com/blang/semver"
"github.com/golang/mock/gomock"
embeddedclusterv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
downstreamtypes "github.com/replicatedhq/kots/pkg/api/downstream/types"
"github.com/replicatedhq/kots/pkg/cursor"
"github.com/replicatedhq/kots/pkg/kotsutil"
mock_store "github.com/replicatedhq/kots/pkg/store/mock"
"github.com/replicatedhq/kots/pkg/store/types"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -251,6 +254,7 @@ func Test_isAppVersionDeployable(t *testing.T) {
version *downstreamtypes.DownstreamVersion
appVersions *downstreamtypes.DownstreamVersions
isSemverRequired bool
setup func(t *testing.T, mockStore *mock_store.MockStore)
expectedIsDeployable bool
expectedCause string
wantErr bool
Expand Down Expand Up @@ -3623,6 +3627,149 @@ func Test_isAppVersionDeployable(t *testing.T) {
},
/* ---- Semver rollback tests end here ---- */
/* ---- Semver tests end here ---- */
/* ---- Embedded cluster config tests start here ---- */
{
name: "embedded cluster config change should not allow rollbacks",
setup: func(t *testing.T, mockStore *mock_store.MockStore) {
t.Setenv("EMBEDDED_CLUSTER_ID", "1234")

mockStore.EXPECT().GetEmbeddedClusterConfigForVersion("APPID", int64(0)).Return(&embeddedclusterv1beta1.Config{
Spec: embeddedclusterv1beta1.ConfigSpec{
Version: "1.0.0-ec.0",
},
}, nil)
mockStore.EXPECT().GetEmbeddedClusterConfigForVersion("APPID", int64(1)).Return(&embeddedclusterv1beta1.Config{
Spec: embeddedclusterv1beta1.ConfigSpec{
Version: "1.0.0-ec.1",
},
}, nil)
},
version: &downstreamtypes.DownstreamVersion{
VersionLabel: "1.0.0",
Sequence: 0,
},
appVersions: &downstreamtypes.DownstreamVersions{
CurrentVersion: &downstreamtypes.DownstreamVersion{
VersionLabel: "2.0.0",
Sequence: 1,
},
AllVersions: []*downstreamtypes.DownstreamVersion{
{
VersionLabel: "3.0.0",
Sequence: 2,
KOTSKinds: &kotsutil.KotsKinds{
KotsApplication: kotsv1beta1.Application{
Spec: kotsv1beta1.ApplicationSpec{
AllowRollback: true,
},
},
},
},
{
VersionLabel: "2.0.0",
Sequence: 1,
},
{
VersionLabel: "1.0.0",
Sequence: 0,
},
},
},
expectedIsDeployable: false,
expectedCause: "Rollback is not supported, cluster configuration has changed.",
wantErr: false,
},
{
name: "embedded cluster config no change should allow rollbacks",
setup: func(t *testing.T, mockStore *mock_store.MockStore) {
t.Setenv("EMBEDDED_CLUSTER_ID", "1234")

mockStore.EXPECT().GetEmbeddedClusterConfigForVersion("APPID", int64(0)).Return(&embeddedclusterv1beta1.Config{
Spec: embeddedclusterv1beta1.ConfigSpec{
Version: "1.0.0-ec.0",
},
}, nil)
mockStore.EXPECT().GetEmbeddedClusterConfigForVersion("APPID", int64(1)).Return(&embeddedclusterv1beta1.Config{
Spec: embeddedclusterv1beta1.ConfigSpec{
Version: "1.0.0-ec.0",
},
}, nil)
},
version: &downstreamtypes.DownstreamVersion{
VersionLabel: "1.0.0",
Sequence: 0,
},
appVersions: &downstreamtypes.DownstreamVersions{
CurrentVersion: &downstreamtypes.DownstreamVersion{
VersionLabel: "2.0.0",
Sequence: 1,
},
AllVersions: []*downstreamtypes.DownstreamVersion{
{
VersionLabel: "3.0.0",
Sequence: 2,
KOTSKinds: &kotsutil.KotsKinds{
KotsApplication: kotsv1beta1.Application{
Spec: kotsv1beta1.ApplicationSpec{
AllowRollback: true,
},
},
},
},
{
VersionLabel: "2.0.0",
Sequence: 1,
},
{
VersionLabel: "1.0.0",
Sequence: 0,
},
},
},
expectedIsDeployable: true,
expectedCause: "",
wantErr: false,
},
{
name: "embedded cluster, allowRollback = false should not allow rollbacks",
setup: func(t *testing.T, mockStore *mock_store.MockStore) {
t.Setenv("EMBEDDED_CLUSTER_ID", "1234")
},
version: &downstreamtypes.DownstreamVersion{
VersionLabel: "1.0.0",
Sequence: 0,
},
appVersions: &downstreamtypes.DownstreamVersions{
CurrentVersion: &downstreamtypes.DownstreamVersion{
VersionLabel: "2.0.0",
Sequence: 1,
},
AllVersions: []*downstreamtypes.DownstreamVersion{
{
VersionLabel: "3.0.0",
Sequence: 2,
KOTSKinds: &kotsutil.KotsKinds{
KotsApplication: kotsv1beta1.Application{
Spec: kotsv1beta1.ApplicationSpec{
AllowRollback: false,
},
},
},
},
{
VersionLabel: "2.0.0",
Sequence: 1,
},
{
VersionLabel: "1.0.0",
Sequence: 0,
},
},
},
expectedIsDeployable: false,
expectedCause: "Rollback is not supported.",
wantErr: false,
},
}

for _, test := range tests {
Expand Down Expand Up @@ -3658,7 +3805,14 @@ func Test_isAppVersionDeployable(t *testing.T) {
}
}

isDeployable, cause, err := isAppVersionDeployable(test.version, test.appVersions, test.isSemverRequired)
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockStore := mock_store.NewMockStore(ctrl)
if test.setup != nil {
test.setup(t, mockStore)
}
isDeployable, cause, err := isAppVersionDeployable(mockStore, "APPID", test.version, test.appVersions, test.isSemverRequired)
if test.wantErr {
require.Error(t, err)
} else {
Expand Down
3 changes: 3 additions & 0 deletions pkg/store/kotsstore/kots_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
kotsadmtypes "github.com/replicatedhq/kots/pkg/kotsadm/types"
"github.com/replicatedhq/kots/pkg/logger"
"github.com/replicatedhq/kots/pkg/persistence"
"github.com/replicatedhq/kots/pkg/store"
"github.com/replicatedhq/kots/pkg/util"
kotsscheme "github.com/replicatedhq/kotskinds/client/kotsclientset/scheme"
troubleshootscheme "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme"
Expand All @@ -34,6 +35,8 @@ type KOTSStore struct {
}

func init() {
store.SetStore(StoreFromEnv())

kotsscheme.AddToScheme(scheme.Scheme)
veleroscheme.AddToScheme(scheme.Scheme)
troubleshootscheme.AddToScheme(scheme.Scheme)
Expand Down
10 changes: 1 addition & 9 deletions pkg/store/store.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package store

import (
"github.com/replicatedhq/kots/pkg/store/kotsstore"
"github.com/replicatedhq/kots/pkg/util"
)

Expand All @@ -10,23 +9,16 @@ var (
globalStore Store
)

var _ Store = (*kotsstore.KOTSStore)(nil)

func GetStore() Store {
if util.IsUpgradeService() {
panic("store cannot not be used in the upgrade service")
}
if !hasStore {
globalStore = storeFromEnv()
hasStore = true
panic("store not initialized")
}
return globalStore
}

func storeFromEnv() Store {
return kotsstore.StoreFromEnv()
}

func SetStore(s Store) {
if s == nil {
hasStore = false
Expand Down

0 comments on commit cdc7539

Please sign in to comment.