diff --git a/internal/bminventory/inventory.go b/internal/bminventory/inventory.go index be1574f15001..8b5b89c5879c 100644 --- a/internal/bminventory/inventory.go +++ b/internal/bminventory/inventory.go @@ -3462,10 +3462,14 @@ func (b *bareMetalInventory) GetCredentialsInternal(ctx context.Context, params log.WithError(err).Errorf("failed to find cluster %s", params.ClusterID) return nil, err } - if !b.clusterApi.IsOperatorAvailable(&cluster, operators.OperatorConsole.Name) { - err := errors.New("console-url isn't available yet, it will be once console operator is ready as part of cluster finalizing stage") - log.WithError(err) - return nil, common.NewApiError(http.StatusConflict, err) + var consoleURL string + if b.clusterApi.IsOperatorMonitored(&cluster, operators.OperatorConsole.Name) { + if !b.clusterApi.IsOperatorAvailable(&cluster, operators.OperatorConsole.Name) { + err := errors.New("console-url isn't available yet, it will be once console operator is ready as part of cluster finalizing stage") + log.WithError(err) + return nil, common.NewApiError(http.StatusConflict, err) + } + consoleURL = common.GetConsoleUrl(cluster.Name, cluster.BaseDNSDomain) } objectName := fmt.Sprintf("%s/%s", params.ClusterID, "kubeadmin-password") r, _, err := b.objectHandler.Download(ctx, objectName) @@ -3482,7 +3486,7 @@ func (b *bareMetalInventory) GetCredentialsInternal(ctx context.Context, params return &models.Credentials{ Username: DefaultUser, Password: string(password), - ConsoleURL: common.GetConsoleUrl(cluster.Name, cluster.BaseDNSDomain), + ConsoleURL: consoleURL, }, nil } diff --git a/internal/bminventory/inventory_test.go b/internal/bminventory/inventory_test.go index 58d02877e5a3..b806d6468f71 100644 --- a/internal/bminventory/inventory_test.go +++ b/internal/bminventory/inventory_test.go @@ -10,6 +10,7 @@ import ( "io/ioutil" "mime/multipart" "net/http" + "net/http/httptest" "net/url" "os" "reflect" @@ -22,6 +23,7 @@ import ( "github.com/cavaliercoder/go-cpio" ign_3_1 "github.com/coreos/ignition/v2/config/v3_1" + "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" @@ -13889,7 +13891,9 @@ var _ = Describe("GetCredentials", func() { clusterID := strfmt.UUID(uuid.New().String()) c = common.Cluster{ Cluster: models.Cluster{ - ID: &clusterID, + ID: &clusterID, + Name: "my-cluster", + BaseDNSDomain: "my-domain", }, } Expect(db.Create(&c).Error).ShouldNot(HaveOccurred()) @@ -13901,7 +13905,7 @@ var _ = Describe("GetCredentials", func() { }) It("Console operator available", func() { - + mockClusterApi.EXPECT().IsOperatorMonitored(gomock.Any(), operators.OperatorConsole.Name).Return(true) mockClusterApi.EXPECT().IsOperatorAvailable(gomock.Any(), operators.OperatorConsole.Name).Return(true) objectName := fmt.Sprintf("%s/%s", *c.ID, "kubeadmin-password") mockS3Client.EXPECT().Download(ctx, objectName).Return(ioutil.NopCloser(strings.NewReader("my_password")), int64(0), nil) @@ -13911,12 +13915,44 @@ var _ = Describe("GetCredentials", func() { }) It("Console operator not available", func() { - + mockClusterApi.EXPECT().IsOperatorMonitored(gomock.Any(), operators.OperatorConsole.Name).Return(true) mockClusterApi.EXPECT().IsOperatorAvailable(gomock.Any(), operators.OperatorConsole.Name).Return(false) reply := bm.V2GetCredentials(ctx, installer.V2GetCredentialsParams{ClusterID: *c.ID}) verifyApiError(reply, http.StatusConflict) }) + + It("Returns credentials and no console URL if the console capability is disabled", func() { + mockClusterApi.EXPECT().IsOperatorMonitored(gomock.Any(), operators.OperatorConsole.Name).Return(false) + objectName := fmt.Sprintf("%s/%s", *c.ID, "kubeadmin-password") + mockS3Client.EXPECT().Download(ctx, objectName).Return(io.NopCloser(strings.NewReader("my_password")), int64(0), nil) + + reply := bm.V2GetCredentials(ctx, installer.V2GetCredentialsParams{ClusterID: *c.ID}) + recorder := httptest.NewRecorder() + reply.WriteResponse(recorder, runtime.JSONProducer()) + Expect(recorder.Code).To(Equal(http.StatusOK)) + Expect(recorder.Body).To(MatchJSON(`{ + "password": "my_password", + "username": "kubeadmin" + }`)) + }) + + It("Returns credentials and console URL if the console capability is enabled", func() { + mockClusterApi.EXPECT().IsOperatorMonitored(gomock.Any(), operators.OperatorConsole.Name).Return(true) + mockClusterApi.EXPECT().IsOperatorAvailable(gomock.Any(), operators.OperatorConsole.Name).Return(true) + objectName := fmt.Sprintf("%s/%s", *c.ID, "kubeadmin-password") + mockS3Client.EXPECT().Download(ctx, objectName).Return(io.NopCloser(strings.NewReader("my_password")), int64(0), nil) + + reply := bm.V2GetCredentials(ctx, installer.V2GetCredentialsParams{ClusterID: *c.ID}) + recorder := httptest.NewRecorder() + reply.WriteResponse(recorder, runtime.JSONProducer()) + Expect(recorder.Code).To(Equal(http.StatusOK)) + Expect(recorder.Body).To(MatchJSON(`{ + "password": "my_password", + "username": "kubeadmin", + "console_url": "https://console-openshift-console.apps.my-cluster.my-domain" + }`)) + }) }) var _ = Describe("AddReleaseImage", func() { diff --git a/internal/cluster/cluster.go b/internal/cluster/cluster.go index c1da7472f6e8..ef052d3ab431 100644 --- a/internal/cluster/cluster.go +++ b/internal/cluster/cluster.go @@ -97,6 +97,7 @@ type API interface { // Refresh state in case of hosts update RefreshStatus(ctx context.Context, c *common.Cluster, db *gorm.DB) (*common.Cluster, error) ClusterMonitoring() + IsOperatorMonitored(c *common.Cluster, operatorName string) bool IsOperatorAvailable(c *common.Cluster, operatorName string) bool UploadIngressCert(c *common.Cluster) (err error) VerifyClusterUpdatability(c *common.Cluster) (err error) @@ -626,6 +627,15 @@ func CanDownloadKubeconfig(c *common.Cluster) (err error) { return err } +func (m *Manager) IsOperatorMonitored(c *common.Cluster, operatorName string) bool { + for _, o := range c.MonitoredOperators { + if o.Name == operatorName { + return true + } + } + return false +} + func (m *Manager) IsOperatorAvailable(c *common.Cluster, operatorName string) bool { // TODO: MGMT-4458 // Backward-compatible solution for clusters that don't have monitored operators data diff --git a/internal/cluster/mock_cluster_api.go b/internal/cluster/mock_cluster_api.go index 4c948c425967..67ea0368568b 100644 --- a/internal/cluster/mock_cluster_api.go +++ b/internal/cluster/mock_cluster_api.go @@ -400,6 +400,20 @@ func (mr *MockAPIMockRecorder) IsOperatorAvailable(c, operatorName interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsOperatorAvailable", reflect.TypeOf((*MockAPI)(nil).IsOperatorAvailable), c, operatorName) } +// IsOperatorMonitored mocks base method. +func (m *MockAPI) IsOperatorMonitored(c *common.Cluster, operatorName string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsOperatorMonitored", c, operatorName) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsOperatorMonitored indicates an expected call of IsOperatorMonitored. +func (mr *MockAPIMockRecorder) IsOperatorMonitored(c, operatorName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsOperatorMonitored", reflect.TypeOf((*MockAPI)(nil).IsOperatorMonitored), c, operatorName) +} + // IsReadyForInstallation mocks base method. func (m *MockAPI) IsReadyForInstallation(c *common.Cluster) (bool, string) { m.ctrl.T.Helper()