Skip to content

Commit

Permalink
Installer images use sha256 (Azure#2967)
Browse files Browse the repository at this point in the history
* Fix equality logic on version

* Leverage image digests when using the aro-installer image

* frontend: Discontinue adding default to enabled OCP versions

The CosmosDB "OpenShiftVersions" container in all environments is
now primed with supported OCP versions. RP no longer needs to hard
code a default in enabledOcpVersions.

* Insert the default version into cosmosdb on cluster creation in localdevmode

---------

Co-authored-by: Matthew Barnes <[email protected]>
  • Loading branch information
bennerv and mbarnes authored Jul 3, 2023
1 parent 3d758d2 commit 0378d0e
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 87 deletions.
9 changes: 8 additions & 1 deletion cmd/aro/update_ocp_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,18 @@ func getLatestOCPVersions(ctx context.Context, log *logrus.Entry) ([]api.OpenShi
ocpVersions := []api.OpenShiftVersion{}

for _, vers := range version.HiveInstallStreams {
installerPullSpec := fmt.Sprintf("%s/aro-installer:%s", dstRepo, vers.Version.MinorVersion())
digest, ok := version.InstallerImageDigest[vers.Version.MinorVersion()]
if !ok {
return nil, fmt.Errorf("no digest found for version %s", vers.Version.String())
}

installerPullSpec = fmt.Sprintf("%s@sha256:%s", installerPullSpec, digest)
ocpVersions = append(ocpVersions, api.OpenShiftVersion{
Properties: api.OpenShiftVersionProperties{
Version: vers.Version.String(),
OpenShiftPullspec: vers.PullSpec,
InstallerPullspec: fmt.Sprintf("%s/aro-installer:release-%s", dstRepo, vers.Version.MinorVersion()),
InstallerPullspec: installerPullSpec,
Enabled: true,
},
})
Expand Down
28 changes: 0 additions & 28 deletions pkg/cluster/install_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package cluster

import (
"context"
"fmt"
"strings"
"testing"

Expand All @@ -14,7 +13,6 @@ import (

"github.com/Azure/ARO-RP/pkg/api"
mock_env "github.com/Azure/ARO-RP/pkg/util/mocks/env"
"github.com/Azure/ARO-RP/pkg/util/version"
testdatabase "github.com/Azure/ARO-RP/test/database"
"github.com/Azure/ARO-RP/test/util/deterministicuuid"
"github.com/Azure/ARO-RP/test/util/testliveconfig"
Expand All @@ -32,32 +30,6 @@ func TestGetOpenShiftVersionFromVersion(t *testing.T) {
wantErrString string
want *api.OpenShiftVersion
}{
{
name: "no versions gets default version",
f: func(f *testdatabase.Fixture) {},
m: manager{
doc: &api.OpenShiftClusterDocument{
Key: strings.ToLower(key),
OpenShiftCluster: &api.OpenShiftCluster{
ID: key,
Properties: api.OpenShiftClusterProperties{
ClusterProfile: api.ClusterProfile{
Version: version.DefaultInstallStream.Version.String(),
},
},
},
},
openShiftClusterDocumentVersioner: new(openShiftClusterDocumentVersionerService),
},
wantErrString: "",
want: &api.OpenShiftVersion{
Properties: api.OpenShiftVersionProperties{
Version: version.DefaultInstallStream.Version.String(),
OpenShiftPullspec: version.DefaultInstallStream.PullSpec,
InstallerPullspec: fmt.Sprintf("%s/aro-installer:release-%d.%d", testACRDomain, version.DefaultInstallStream.Version.V[0], version.DefaultInstallStream.Version.V[1]),
},
},
},
{
name: "select nonexistent version",
f: func(f *testdatabase.Fixture) {
Expand Down
50 changes: 6 additions & 44 deletions pkg/cluster/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ package cluster

import (
"context"
"fmt"
"net/http"
"strings"

"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/database"
"github.com/Azure/ARO-RP/pkg/env"
"github.com/Azure/ARO-RP/pkg/util/version"
)

// openShiftClusterDocumentVersioner is the interface that validates and obtains the version from an OpenShiftClusterDocument.
Expand All @@ -28,28 +26,6 @@ type openShiftClusterDocumentVersionerService struct{}
func (service *openShiftClusterDocumentVersionerService) Get(ctx context.Context, doc *api.OpenShiftClusterDocument, dbOpenShiftVersions database.OpenShiftVersions, env env.Interface, installViaHive bool) (*api.OpenShiftVersion, error) {
requestedInstallVersion := doc.OpenShiftCluster.Properties.ClusterProfile.Version

// Honor any installer pull spec override
installerPullSpec := env.LiveConfig().DefaultInstallerPullSpecOverride(ctx)
if installerPullSpec == "" {
installerPullSpec = fmt.Sprintf("%s/aro-installer:release-%s", env.ACRDomain(), version.DefaultInstallStream.Version.MinorVersion())
}

// add the default OCP version as we require it as an install target
// if this is removed, we need to also update the logic in
// pkg/frontend/frontend.go, pkg/frontend/validate.go
defaultVersion := &api.OpenShiftVersion{
Properties: api.OpenShiftVersionProperties{
Version: version.DefaultInstallStream.Version.String(),
OpenShiftPullspec: version.DefaultInstallStream.PullSpec,
InstallerPullspec: installerPullSpec,
Enabled: true,
},
}

if requestedInstallVersion == defaultVersion.Properties.Version {
return defaultVersion, nil
}

// TODO: Refactor to use changefeeds rather than querying the database every time
// should also leverage shared changefeed or shared logic
docs, err := dbOpenShiftVersions.ListAll(ctx)
Expand All @@ -66,31 +42,17 @@ func (service *openShiftClusterDocumentVersionerService) Get(ctx context.Context

errUnsupportedVersion := api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, "properties.clusterProfile.version", "The requested OpenShift version '%s' is not supported.", requestedInstallVersion)

// when we have no OpenShiftVersion entries in CosmoDB, default to building one using the DefaultInstallStream
if len(activeOpenShiftVersions) == 0 {
if requestedInstallVersion != version.DefaultInstallStream.Version.String() {
return nil, errUnsupportedVersion
}

openshiftPullSpec := version.DefaultInstallStream.PullSpec
if installViaHive {
openshiftPullSpec = strings.Replace(openshiftPullSpec, "quay.io", env.ACRDomain(), 1)
}

return &api.OpenShiftVersion{
Properties: api.OpenShiftVersionProperties{
Version: version.DefaultInstallStream.Version.String(),
OpenShiftPullspec: openshiftPullSpec,
InstallerPullspec: installerPullSpec,
Enabled: true,
}}, nil
}

for _, active := range activeOpenShiftVersions {
if requestedInstallVersion == active.Properties.Version {
if installViaHive {
active.Properties.OpenShiftPullspec = strings.Replace(active.Properties.OpenShiftPullspec, "quay.io", env.ACRDomain(), 1)
}

// Honor any pull spec override set
installerPullSpecOverride := env.LiveConfig().DefaultInstallerPullSpecOverride(ctx)
if installerPullSpecOverride != "" {
active.Properties.InstallerPullspec = installerPullSpecOverride
}
return active, nil
}
}
Expand Down
11 changes: 1 addition & 10 deletions pkg/frontend/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (
"github.com/Azure/ARO-RP/pkg/util/heartbeat"
utillog "github.com/Azure/ARO-RP/pkg/util/log"
"github.com/Azure/ARO-RP/pkg/util/recover"
"github.com/Azure/ARO-RP/pkg/util/version"
)

type statusCodeError int
Expand Down Expand Up @@ -164,15 +163,7 @@ func NewFrontend(ctx context.Context,

clusterEnricher: enricher,

// add default installation version so it's always supported
enabledOcpVersions: map[string]*api.OpenShiftVersion{
version.DefaultInstallStream.Version.String(): {
Properties: api.OpenShiftVersionProperties{
Version: version.DefaultInstallStream.Version.String(),
Enabled: true,
},
},
},
enabledOcpVersions: map[string]*api.OpenShiftVersion{},

bucketAllocator: &bucket.Random{},

Expand Down
12 changes: 11 additions & 1 deletion pkg/frontend/openshiftcluster_preflightvalidation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/metrics/noop"
"github.com/Azure/ARO-RP/pkg/util/version"
testdatabase "github.com/Azure/ARO-RP/test/database"
)

Expand Down Expand Up @@ -112,13 +113,22 @@ func TestPreflightValidation(t *testing.T) {
t.Fatal(err)
}

f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, ti.openShiftVersionsDatabase, api.APIs, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
oc := tt.preflightRequest()

go f.Run(ctx, nil, nil)
f.mu.Lock()
f.enabledOcpVersions = map[string]*api.OpenShiftVersion{
version.DefaultInstallStream.Version.String(): {
Properties: api.OpenShiftVersionProperties{
Version: version.DefaultInstallStream.Version.String(),
},
},
}
f.mu.Unlock()

headers := http.Header{
"Content-Type": []string{"application/json"},
Expand Down
24 changes: 24 additions & 0 deletions pkg/frontend/openshiftcluster_putorpatch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,15 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
}

defaultVersionChangeFeed := map[string]*api.OpenShiftVersion{
version.DefaultInstallStream.Version.String(): {
Properties: api.OpenShiftVersionProperties{
Version: version.DefaultInstallStream.Version.String(),
Enabled: true,
},
},
}

mockSubID := "00000000-0000-0000-0000-000000000000"
mockCurrentTime := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)

Expand All @@ -657,6 +666,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
request func(*v20200430.OpenShiftCluster)
isPatch bool
fixture func(*testdatabase.Fixture)
changeFeed map[string]*api.OpenShiftVersion
quotaValidatorError error
skuValidatorError error
providersValidatorError error
Expand Down Expand Up @@ -686,6 +696,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
wantSystemDataEnriched: true,
wantDocuments: func(c *testdatabase.Checker) {
c.AddAsyncOperationDocuments(&api.AsyncOperationDocument{
Expand Down Expand Up @@ -758,6 +769,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
quotaValidatorError: api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, "", "The provided VM SKU %s is not supported.", "something"),
wantEnriched: []string{},
wantStatusCode: http.StatusBadRequest,
Expand All @@ -779,6 +791,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
quotaValidatorError: api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeQuotaExceeded, "", "Resource quota of vm exceeded. Maximum allowed: 0, Current in use: 0, Additional requested: 1."),
wantEnriched: []string{},
wantStatusCode: http.StatusBadRequest,
Expand All @@ -800,6 +813,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
skuValidatorError: api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, "", "The selected SKU '%v' is unavailable in region '%v'", "Standard_Sku", "somewhere"),
wantEnriched: []string{},
wantStatusCode: http.StatusBadRequest,
Expand All @@ -821,6 +835,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
skuValidatorError: api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, "", "The selected SKU '%v' is restricted in region '%v' for selected subscription", "Standard_Sku", "somewhere"),
wantEnriched: []string{},
wantStatusCode: http.StatusBadRequest,
Expand All @@ -843,6 +858,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
providersValidatorError: api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeResourceProviderNotRegistered, "", "The resource provider '%s' is not registered.", "Microsoft.Authorization"),
wantEnriched: []string{},
wantStatusCode: http.StatusBadRequest,
Expand All @@ -864,6 +880,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
providersValidatorError: api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeResourceProviderNotRegistered, "", "The resource provider '%s' is not registered.", "Microsoft.Compute"),
wantEnriched: []string{},
wantStatusCode: http.StatusBadRequest,
Expand All @@ -885,6 +902,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
providersValidatorError: api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeResourceProviderNotRegistered, "", "The resource provider '%s' is not registered.", "Microsoft.Network"),
wantEnriched: []string{},
wantStatusCode: http.StatusBadRequest,
Expand All @@ -906,6 +924,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
providersValidatorError: api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeResourceProviderNotRegistered, "", "The resource provider '%s' is not registered.", "Microsoft.Storage"),
wantEnriched: []string{},
wantStatusCode: http.StatusBadRequest,
Expand Down Expand Up @@ -1515,6 +1534,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
wantSystemDataEnriched: true,
wantAsync: true,
wantStatusCode: http.StatusBadRequest,
Expand Down Expand Up @@ -1560,6 +1580,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
},
})
},
changeFeed: defaultVersionChangeFeed,
wantSystemDataEnriched: true,
wantAsync: true,
wantStatusCode: http.StatusBadRequest,
Expand Down Expand Up @@ -1608,6 +1629,9 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
}

go f.Run(ctx, nil, nil)
f.mu.Lock()
f.enabledOcpVersions = tt.changeFeed
f.mu.Unlock()

oc := &v20200430.OpenShiftCluster{}
if tt.request != nil {
Expand Down
3 changes: 1 addition & 2 deletions pkg/frontend/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,12 @@ func validateAdminMasterVMSize(vmSize string) error {
func (f *frontend) validateInstallVersion(ctx context.Context, doc *api.OpenShiftCluster) error {
// If this request is from an older API or the user never specified
// the version to install we default to the DefaultInstallStream.Version
// TODO: We should set default version in cosmosdb instead of hardcoding it in golang code
if doc.Properties.ClusterProfile.Version == "" {
doc.Properties.ClusterProfile.Version = version.DefaultInstallStream.Version.String()
return nil
}

f.mu.RLock()
// we add the default installation version to the enabled ocp versions so no special case
_, ok := f.enabledOcpVersions[doc.Properties.ClusterProfile.Version]
f.mu.RUnlock()

Expand Down
Loading

0 comments on commit 0378d0e

Please sign in to comment.