diff --git a/internal/bminventory/inventory.go b/internal/bminventory/inventory.go index bfa1fb43b1e9..aebcc89fbddc 100644 --- a/internal/bminventory/inventory.go +++ b/internal/bminventory/inventory.go @@ -3734,10 +3734,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) @@ -3754,7 +3758,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 c8795c962427..5ece17ba6aac 100644 --- a/internal/bminventory/inventory_test.go +++ b/internal/bminventory/inventory_test.go @@ -11,6 +11,7 @@ import ( "io" "mime/multipart" "net/http" + "net/http/httptest" "net/url" "os" "reflect" @@ -23,6 +24,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" @@ -15588,7 +15590,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()) @@ -15600,7 +15604,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(io.NopCloser(strings.NewReader("my_password")), int64(0), nil) @@ -15610,12 +15614,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("Platform tests", func() { diff --git a/internal/cluster/cluster.go b/internal/cluster/cluster.go index 1c8761561762..741dfa342fc4 100644 --- a/internal/cluster/cluster.go +++ b/internal/cluster/cluster.go @@ -98,6 +98,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) @@ -677,6 +678,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 7e1bd726f3b9..3e7a69ad5a0f 100644 --- a/internal/cluster/mock_cluster_api.go +++ b/internal/cluster/mock_cluster_api.go @@ -429,6 +429,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()