diff --git a/Makefile b/Makefile index 974b8d02..a42a9555 100644 --- a/Makefile +++ b/Makefile @@ -220,7 +220,6 @@ mocks: ## Generate testify mocks with Mockery mockery --dir ./internal/thelma/state/api/terra --name ClusterRelease --output=./internal/thelma/state/api/terra/mocks --outpkg mocks --filename cluster_release.go mockery --dir ./internal/thelma/state/api/terra --name Clusters --output=./internal/thelma/state/api/terra/mocks --outpkg mocks --filename clusters.go mockery --dir ./internal/thelma/state/api/terra --name Destination --output=./internal/thelma/state/api/terra/mocks --outpkg mocks --filename destination.go - mockery --dir ./internal/thelma/state/api/terra --name Destinations --output=./internal/thelma/state/api/terra/mocks --outpkg mocks --filename destinations.go mockery --dir ./internal/thelma/state/api/terra --name Environment --output=./internal/thelma/state/api/terra/mocks --outpkg mocks --filename environment.go mockery --dir ./internal/thelma/state/api/terra --name Environments --output=./internal/thelma/state/api/terra/mocks --outpkg mocks --filename environments.go mockery --dir ./internal/thelma/state/api/terra --name Release --output=./internal/thelma/state/api/terra/mocks --outpkg mocks --filename release.go diff --git a/internal/thelma/cli/selector/enum_flags.go b/internal/thelma/cli/selector/enum_flags.go index e83f6272..b742fc83 100644 --- a/internal/thelma/cli/selector/enum_flags.go +++ b/internal/thelma/cli/selector/enum_flags.go @@ -151,15 +151,23 @@ func newDestinationBasesFlag() *enumFlag { usageMessage: `Run for a specific environment or cluster base (eg. \"live\", \"bee\")`, validValues: func(state terra.State) (set.StringSet, error) { - destinations, err := state.Destinations().All() + envs, err := state.Environments().All() + if err != nil { + return nil, err + } + clusters, err := state.Clusters().All() if err != nil { return nil, err } s := set.NewStringSet() - for _, d := range destinations { + for _, d := range envs { s.Add(d.Base()) } + for _, d := range clusters { + s.Add(d.Base()) + } + return s, nil }, diff --git a/internal/thelma/state/api/terra/destinations.go b/internal/thelma/state/api/terra/destinations.go deleted file mode 100644 index e0bb062a..00000000 --- a/internal/thelma/state/api/terra/destinations.go +++ /dev/null @@ -1,9 +0,0 @@ -package terra - -// Destinations is an interface for querying release destinations -type Destinations interface { - // All returns a list of all destinations - All() ([]Destination, error) - // Get returns the destination with the given name, or an error if no such destination exists - Get(name string) (Destination, error) -} diff --git a/internal/thelma/state/api/terra/mocks/state.go b/internal/thelma/state/api/terra/mocks/state.go index e6b35181..b708905e 100644 --- a/internal/thelma/state/api/terra/mocks/state.go +++ b/internal/thelma/state/api/terra/mocks/state.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.32.4. DO NOT EDIT. +// Code generated by mockery v2.40.1. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ func (_m *State) EXPECT() *State_Expecter { func (_m *State) Clusters() terra.Clusters { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Clusters") + } + var r0 terra.Clusters if rf, ok := ret.Get(0).(func() terra.Clusters); ok { r0 = rf() @@ -63,53 +67,14 @@ func (_c *State_Clusters_Call) RunAndReturn(run func() terra.Clusters) *State_Cl return _c } -// Destinations provides a mock function with given fields: -func (_m *State) Destinations() terra.Destinations { - ret := _m.Called() - - var r0 terra.Destinations - if rf, ok := ret.Get(0).(func() terra.Destinations); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(terra.Destinations) - } - } - - return r0 -} - -// State_Destinations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Destinations' -type State_Destinations_Call struct { - *mock.Call -} - -// Destinations is a helper method to define mock.On call -func (_e *State_Expecter) Destinations() *State_Destinations_Call { - return &State_Destinations_Call{Call: _e.mock.On("Destinations")} -} - -func (_c *State_Destinations_Call) Run(run func()) *State_Destinations_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *State_Destinations_Call) Return(_a0 terra.Destinations) *State_Destinations_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *State_Destinations_Call) RunAndReturn(run func() terra.Destinations) *State_Destinations_Call { - _c.Call.Return(run) - return _c -} - // Environments provides a mock function with given fields: func (_m *State) Environments() terra.Environments { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Environments") + } + var r0 terra.Environments if rf, ok := ret.Get(0).(func() terra.Environments); ok { r0 = rf() @@ -153,6 +118,10 @@ func (_c *State_Environments_Call) RunAndReturn(run func() terra.Environments) * func (_m *State) Releases() terra.Releases { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Releases") + } + var r0 terra.Releases if rf, ok := ret.Get(0).(func() terra.Releases); ok { r0 = rf() diff --git a/internal/thelma/state/api/terra/state.go b/internal/thelma/state/api/terra/state.go index 3a1ac04d..2d2352c2 100644 --- a/internal/thelma/state/api/terra/state.go +++ b/internal/thelma/state/api/terra/state.go @@ -4,8 +4,6 @@ package terra // State is an interface for querying the state of Terra infrastructure. type State interface { - // Destinations is an interface for querying terra.Destination instances - Destinations() Destinations // Environments is an interface for querying terra.Environment instances Environments() Environments // Clusters is an interface for querying terra.Cluster instances diff --git a/internal/thelma/state/providers/sherlock/destinations.go b/internal/thelma/state/providers/sherlock/destinations.go deleted file mode 100644 index 60f4d013..00000000 --- a/internal/thelma/state/providers/sherlock/destinations.go +++ /dev/null @@ -1,48 +0,0 @@ -package sherlock - -import ( - "sort" - - "github.com/broadinstitute/thelma/internal/thelma/state/api/terra" - "github.com/broadinstitute/thelma/internal/thelma/state/api/terra/compare" -) - -type destinations struct { - state *state -} - -func newDestinationsView(s *state) terra.Destinations { - return &destinations{ - state: s, - } -} - -func (d *destinations) All() ([]terra.Destination, error) { - var result []terra.Destination - - for _, env := range d.state.environments { - result = append(result, env) - } - - for _, cluster := range d.state.clusters { - result = append(result, cluster) - } - - sort.Slice(result, func(i, j int) bool { - return compare.Destinations(result[i], result[j]) < 0 - }) - - return result, nil -} - -func (d *destinations) Get(name string) (terra.Destination, error) { - if destination, exists := d.state.clusters[name]; exists { - return destination, nil - } - - if destination, exists := d.state.environments[name]; exists { - return destination, nil - } - - return nil, nil -} diff --git a/internal/thelma/state/providers/sherlock/releases.go b/internal/thelma/state/providers/sherlock/releases.go index 20f003de..b28c7738 100644 --- a/internal/thelma/state/providers/sherlock/releases.go +++ b/internal/thelma/state/providers/sherlock/releases.go @@ -15,13 +15,8 @@ func newReleasesView(s *state) terra.Releases { func (r *releases) All() ([]terra.Release, error) { var result []terra.Release - allDestinations, err := r.state.Destinations().All() - if err != nil { - return nil, err - } - - for _, destination := range allDestinations { - result = append(result, destination.Releases()...) + for _, r := range r.state.releases { + result = append(result, r) } return result, nil diff --git a/internal/thelma/state/providers/sherlock/state.go b/internal/thelma/state/providers/sherlock/state.go index 98eb744f..ad79d257 100644 --- a/internal/thelma/state/providers/sherlock/state.go +++ b/internal/thelma/state/providers/sherlock/state.go @@ -10,10 +10,7 @@ type state struct { sherlock sherlock.Client environments map[string]*environment clusters map[string]*cluster -} - -func (s *state) Destinations() terra.Destinations { - return newDestinationsView(s) + releases map[string]*release } func (s *state) Environments() terra.Environments { diff --git a/internal/thelma/state/providers/sherlock/state_loader.go b/internal/thelma/state/providers/sherlock/state_loader.go index 78e9d45b..b31705ab 100644 --- a/internal/thelma/state/providers/sherlock/state_loader.go +++ b/internal/thelma/state/providers/sherlock/state_loader.go @@ -120,6 +120,7 @@ retry: } } + _releases := make(map[string]*release) for _, stateRelease := range stateReleases { if _, knownCluster := _clusters[stateRelease.Cluster]; stateRelease.Cluster != "" && !knownCluster { log.Warn().Msgf("chart release '%s' has cluster '%s' that we do not have: race condition detected, retrying...", @@ -131,52 +132,50 @@ retry: stateRelease.Name, stateRelease.Environment) continue retry } + + _release := &release{ + name: stateRelease.Name, + enabled: true, + chartVersion: stateRelease.ChartVersionExact, + chartName: stateRelease.Chart, + repo: *stateRelease.ChartInfo.ChartRepo, + namespace: stateRelease.Namespace, + cluster: _clusters[stateRelease.Cluster], + helmfileRef: *stateRelease.HelmfileRef, + appVersion: stateRelease.AppVersionExact, + subdomain: stateRelease.Subdomain, + protocol: stateRelease.Protocol, + port: int(stateRelease.Port), + } + switch stateRelease.DestinationType { case "cluster": - _clusters[stateRelease.Cluster].releases[stateRelease.Name] = &release{ - name: stateRelease.Name, - enabled: true, - releaseType: terra.ClusterReleaseType, - chartVersion: stateRelease.ChartVersionExact, - chartName: stateRelease.Chart, - repo: *stateRelease.ChartInfo.ChartRepo, - namespace: stateRelease.Namespace, - cluster: _clusters[stateRelease.Cluster], - destination: _clusters[stateRelease.Cluster], - helmfileRef: *stateRelease.HelmfileRef, - appVersion: stateRelease.AppVersionExact, - } + _release.releaseType = terra.ClusterReleaseType + _release.destination = _clusters[stateRelease.Cluster] + _clusters[stateRelease.Cluster].releases[stateRelease.Name] = _release + case "environment": var helmfileOverlays []string if e, present := _environments[stateRelease.Environment]; present && e.offline { helmfileOverlays = []string{"offline"} } - _environments[stateRelease.Environment].releases[stateRelease.Name] = &release{ - name: stateRelease.Name, - enabled: true, - releaseType: terra.AppReleaseType, - chartVersion: stateRelease.ChartVersionExact, - chartName: stateRelease.Chart, - repo: *stateRelease.ChartInfo.ChartRepo, - namespace: stateRelease.Namespace, - cluster: _clusters[stateRelease.Cluster], - destination: _environments[stateRelease.Environment], - helmfileRef: *stateRelease.HelmfileRef, - helmfileOverlays: helmfileOverlays, - appVersion: stateRelease.AppVersionExact, - subdomain: stateRelease.Subdomain, - protocol: stateRelease.Protocol, - port: int(stateRelease.Port), - } + _release.releaseType = terra.AppReleaseType + _release.destination = _environments[stateRelease.Environment] + _release.helmfileOverlays = helmfileOverlays + _environments[stateRelease.Environment].releases[stateRelease.Name] = _release + default: return nil, errors.Errorf("unexpected destination type '%s' for release '%s'", stateRelease.DestinationType, stateRelease.Name) } + + _releases[stateRelease.Name] = _release } _state := &state{ sherlock: s.sherlock, environments: _environments, clusters: _clusters, + releases: _releases, } s.cached = _state return _state, nil diff --git a/internal/thelma/state/testing/statefixtures/builder.go b/internal/thelma/state/testing/statefixtures/builder.go index a0c739db..4e8cdff3 100644 --- a/internal/thelma/state/testing/statefixtures/builder.go +++ b/internal/thelma/state/testing/statefixtures/builder.go @@ -16,7 +16,6 @@ type builder struct { clusterReleaseSet map[string]*statemocks.ClusterRelease clusters *statemocks.Clusters environments *StubEnvironments - destinations *StubDestinations releases *StubReleases state *statemocks.State stateLoader *statemocks.StateLoader @@ -31,7 +30,6 @@ func newBuilder(data *FixtureData) *builder { clusterReleaseSet: make(map[string]*statemocks.ClusterRelease), clusters: new(statemocks.Clusters), environments: &StubEnvironments{Environments: new(statemocks.Environments)}, - destinations: &StubDestinations{Destinations: new(statemocks.Destinations)}, releases: &StubReleases{Releases: new(statemocks.Releases)}, state: new(statemocks.State), stateLoader: new(statemocks.StateLoader), @@ -50,7 +48,6 @@ func (b *builder) buildMocks() *Mocks { b.setClustersMocks() b.setEnvironmentsMocks() b.setReleasesMocks() - b.setDestinationsMocks() // set up root objects b.setStateMocks() @@ -58,7 +55,6 @@ func (b *builder) buildMocks() *Mocks { return &Mocks{ Clusters: b.clusters, - Destinations: b.destinations, Environments: b.environments, Releases: b.releases, State: b.state, @@ -261,23 +257,9 @@ func (b *builder) setReleasesMocks() { b.releases.EXPECT().All().Return(allReleases, nil) } -func (b *builder) setDestinationsMocks() { - var allDestinations []terra.Destination - - for _, cluster := range b.clusterSet { - allDestinations = append(allDestinations, cluster) - } - for _, env := range b.environmentSet { - allDestinations = append(allDestinations, env) - } - - b.destinations.EXPECT().All().Return(allDestinations, nil) -} - func (b *builder) setStateMocks() { b.state.EXPECT().Environments().Return(b.environments) b.state.EXPECT().Clusters().Return(b.clusters) - b.state.EXPECT().Destinations().Return(b.destinations) b.state.EXPECT().Releases().Return(b.releases) } diff --git a/internal/thelma/state/testing/statefixtures/mocks.go b/internal/thelma/state/testing/statefixtures/mocks.go index a08930e4..e4d96dbb 100644 --- a/internal/thelma/state/testing/statefixtures/mocks.go +++ b/internal/thelma/state/testing/statefixtures/mocks.go @@ -8,7 +8,6 @@ import ( type Mocks struct { Clusters *statemocks.Clusters - Destinations *StubDestinations Environments *StubEnvironments Releases *StubReleases State *statemocks.State @@ -45,15 +44,3 @@ func (m *StubEnvironments) Filter(filter terra.EnvironmentFilter) ([]terra.Envir } return filter.Filter(all), nil } - -type StubDestinations struct { - *statemocks.Destinations -} - -func (m *StubDestinations) Filter(filter terra.DestinationFilter) ([]terra.Destination, error) { - all, err := m.Destinations.All() - if err != nil { - return nil, err - } - return filter.Filter(all), nil -}