Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClusterSync list resources #3762

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions pkg/frontend/admin_hive_syncset_resources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package frontend

// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.

import (
"context"
"net/http"
"path/filepath"
"strings"

"github.com/sirupsen/logrus"
"github.com/ugorji/go/codec"

"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/frontend/middleware"
)

func (f *frontend) getAdminHiveSyncsetResources(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry)
clusterdeployment := strings.TrimPrefix(filepath.Dir(r.URL.Path), "/admin")
b, err := f._getAdminHiveSyncsetResources(ctx, clusterdeployment)

if cloudErr, ok := err.(*api.CloudError); ok {
api.WriteCloudError(w, cloudErr)
return
}

adminReply(log, w, nil, b, err)
}

func (f *frontend) _getAdminHiveSyncsetResources(ctx context.Context, namespace string) ([]byte, error) {
// we have to check if the frontend has a valid clustermanager since hive is not everywhere.
if f.hiveClusterManager == nil {
return nil, api.NewCloudError(http.StatusInternalServerError, api.CloudErrorCodeInternalServerError, "", "hive is not enabled")
}

dbOpenShiftClusters, err := f.dbGroup.OpenShiftClusters()
if err != nil {
return nil, api.NewCloudError(http.StatusInternalServerError, api.CloudErrorCodeInternalServerError, "", err.Error())
}

doc, err := dbOpenShiftClusters.Get(ctx, namespace)
if err != nil {
return nil, api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeNotFound, "", "cluster not found")
}

if doc.OpenShiftCluster.Properties.HiveProfile.Namespace == "" {
return nil, api.NewCloudError(http.StatusNoContent, api.CloudErrorCodeResourceNotFound, "", "cluster is not managed by hive")
}

cd, err := f.hiveClusterManager.GetSyncSetResources(ctx, doc)
if err != nil {
return nil, api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeNotFound, "", "cluster deployment not found")
}

var b []byte
err = codec.NewEncoderBytes(&b, &codec.JsonHandle{}).Encode(cd)
if err != nil {
return nil, api.NewCloudError(http.StatusInternalServerError, api.CloudErrorCodeInternalServerError, "", "unable to marshal response")
}

return b, nil
}
105 changes: 105 additions & 0 deletions pkg/frontend/admin_hive_syncset_resources_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package frontend

// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.

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

"github.com/golang/mock/gomock"
"github.com/openshift/hive/apis/hiveinternal/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/metrics/noop"
mock_env "github.com/Azure/ARO-RP/pkg/util/mocks/env"
mock_hive "github.com/Azure/ARO-RP/pkg/util/mocks/hive"
)

func TestGetAdminHiveSyncsetResources(t *testing.T) {
fakeNamespace := "aro-00000000-0000-0000-0000-000000000000"
ctx := context.Background()
clusterSyncsetTest := &v1alpha1.ClusterSync{
ObjectMeta: metav1.ObjectMeta{
Name: "clustersync1",
Namespace: fakeNamespace,
},
}

type test struct {
name string
namespace string
hiveEnabled bool
mocks func(*test, *mock_hive.MockClusterManager)
wantStatusCode int
wantResponse []byte
wantError string
}

for _, tt := range []*test{
{
name: "Cluster SyncSets must be namespaced",
namespace: "",
hiveEnabled: true,
mocks: func(tt *test, s *mock_hive.MockClusterManager) {},
wantStatusCode: http.StatusNotFound,
wantError: "404: NotFound: : cluster not found",
},
{
name: "List ClusterSync resources successfully",
namespace: "hive",
wantError: "",
mocks: func(tt *test, s *mock_hive.MockClusterManager) {
s.EXPECT().
GetSyncSetResources(gomock.Any(), gomock.Any()).
Return(&clusterSyncsetTest, nil).Times(1)
},
wantStatusCode: http.StatusOK,
},
{
name: "Hive is not enabled",
namespace: fakeNamespace,
mocks: nil,
hiveEnabled: false,
wantStatusCode: http.StatusInternalServerError,
wantError: "500: InternalServerError: : hive is not enabled",
},
} {
t.Run(tt.name, func(t *testing.T) {
ti := newTestInfra(t).WithOpenShiftClusters().WithSubscriptions()
defer ti.done()

_env := ti.env.(*mock_env.MockInterface)
var f *frontend
var err error
if tt.hiveEnabled {
s := mock_hive.NewMockClusterManager(ti.controller) //NewMockSyncSetResourceManager(ti.controller)
tt.mocks(tt, s)
f, err = NewFrontend(ctx, ti.audit, ti.log, _env, ti.dbGroup, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil, nil)
} else {
f, err = NewFrontend(ctx, ti.audit, ti.log, _env, ti.dbGroup, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil, nil)
}
if err != nil {
t.Fatal(err)
}

clusterSyncSet, err := f._getAdminHiveSyncsetResources(ctx, tt.namespace)
cloudErr, isCloudErr := err.(*api.CloudError)
if tt.wantError != "" && isCloudErr && cloudErr != nil {
if tt.wantError != cloudErr.Error() {
t.Fatalf("got %q but wanted %q", cloudErr.Error(), tt.wantError)
}
if tt.wantStatusCode != 0 && tt.wantStatusCode != cloudErr.StatusCode {
t.Fatalf("got %q but wanted %q", cloudErr.Error(), tt.wantError)
}
}

if !strings.EqualFold(string(clusterSyncSet), string(tt.wantResponse)) {
t.Fatalf("got %q and expected %q", clusterSyncSet, tt.wantResponse)
}
})
}
}
1 change: 1 addition & 0 deletions pkg/frontend/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ func (f *frontend) chiAuthenticatedRoutes(router chi.Router) {
r.Get("/serialconsole", f.getAdminOpenShiftClusterSerialConsole)

r.Get("/clusterdeployment", f.getAdminHiveClusterDeployment)
r.Get("/clustersyncresources", f.getAdminHiveSyncsetResources)

r.With(f.maintenanceMiddleware.UnplannedMaintenanceSignal).Post("/redeployvm", f.postAdminOpenShiftClusterRedeployVM)

Expand Down
2 changes: 1 addition & 1 deletion pkg/frontend/security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@

log := logrus.NewEntry(logrus.StandardLogger())
auditHook, auditEntry := testlog.NewAudit()
f, err := NewFrontend(ctx, auditEntry, log, _env, database.NewDBGroup(), api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, auditEntry, log, _env, database.NewDBGroup(), api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil, nil, nil)

Check failure on line 81 in pkg/frontend/security_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

too many arguments in call to NewFrontend
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/frontend/subscriptions_put_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@
t.Fatal(err)
}

f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.dbGroup, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.dbGroup, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil, nil, nil)

Check failure on line 247 in pkg/frontend/subscriptions_put_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

too many arguments in call to NewFrontend
if err != nil {
t.Fatal(err)
}
Expand Down
69 changes: 69 additions & 0 deletions pkg/hive/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
"context"
"errors"
"fmt"
"log"
"sort"

hivev1 "github.com/openshift/hive/apis/hive/v1"
"github.com/openshift/hive/apis/hiveinternal/v1alpha1"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -42,6 +44,7 @@
IsClusterInstallationComplete(ctx context.Context, doc *api.OpenShiftClusterDocument) (bool, error)
GetClusterDeployment(ctx context.Context, doc *api.OpenShiftClusterDocument) (*hivev1.ClusterDeployment, error)
ResetCorrelationData(ctx context.Context, doc *api.OpenShiftClusterDocument) error
GetSyncSetResources(ctx context.Context, doc *api.OpenShiftClusterDocument) (*v1alpha1.ClusterSync, error)
}

type clusterManager struct {
Expand All @@ -54,6 +57,72 @@
dh dynamichelper.Interface
}

// Define the interface for SyncSetResourceManager

// Implement the syncSetResourceManager struct
/*type syncSetResourceManager struct {
log *logrus.Entry
env env.Core
hiveClientset client.Client
}
*/
// GetSyncSetResources lists ClusterSync resources in the specified namespace
func (hr *clusterManager) GetSyncSetResources(ctx context.Context, doc *api.OpenShiftClusterDocument) (*v1alpha1.ClusterSync, error) {

Check failure on line 70 in pkg/hive/manager.go

View workflow job for this annotation

GitHub Actions / golangci-lint

unnecessary leading newline (whitespace)

clusterSync := &v1alpha1.ClusterSync{}

key := client.ObjectKey{
Name: ClusterDeploymentName, // "cluster",
Namespace: doc.OpenShiftCluster.Properties.HiveProfile.Namespace,
}

err := hr.hiveClientset.Get(ctx, key, clusterSync)
if err != nil {
log.Fatalf("Error getting ClusterSync resources: %s", err.Error())
}

return clusterSync, nil
}

/*
func NewClusterSyncFromEnv(ctx context.Context, log *logrus.Entry, env env.Interface) (SyncSetResourceManager, error) {
adoptByHive, err := env.LiveConfig().AdoptByHive(ctx)
if err != nil {
return nil, err
}
installViaHive, err := env.LiveConfig().InstallViaHive(ctx)
if err != nil {
return nil, err
}
if !adoptByHive && !installViaHive {
log.Infof("hive is disabled, skipping creation of syncSetResourceManager")
return nil, nil
}
hiveShard := 1
hiveRestConfig, err := env.LiveConfig().HiveRestConfig(ctx, hiveShard)
if err != nil {
return nil, fmt.Errorf("failed getting RESTConfig for Hive shard %d: %w", hiveShard, err)
}
return NewClusterSyncFromConfig(log, env, hiveRestConfig)
}

// NewFromConfig creates a ClusterManager.
// It MUST NOT take cluster or subscription document as values
// in these structs can be change during the lifetime of the cluster manager.
func NewClusterSyncFromConfig(log *logrus.Entry, _env env.Core, restConfig *rest.Config) (SyncSetResourceManager, error) {
hiveClientset, err := client.New(restConfig, client.Options{})
if err != nil {
return nil, err
}

return &syncSetResourceManager{
log: log,
env: _env,

hiveClientset: hiveClientset,
}, nil
}
*/
// NewFromEnv can return a nil ClusterManager when hive features are disabled. This exists to support regions where we don't have hive,
// and we do not want to restrict the frontend from starting up successfully.
// It has the caveat of requiring a nil check on any operations performed with the returned ClusterManager
Expand Down
50 changes: 50 additions & 0 deletions pkg/hive/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"

hivev1 "github.com/openshift/hive/apis/hive/v1"
"github.com/openshift/hive/apis/hiveinternal/v1alpha1"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -548,3 +549,52 @@ func TestGetClusterDeployment(t *testing.T) {
})
}
}

func TestGetSyncSetResources(t *testing.T) {
fakeNamespace := "aro-00000000-0000-0000-0000-000000000000"
doc := &api.OpenShiftClusterDocument{
OpenShiftCluster: &api.OpenShiftCluster{
Properties: api.OpenShiftClusterProperties{
HiveProfile: api.HiveProfile{
Namespace: fakeNamespace,
},
},
},
}

clusterSyncTest := &v1alpha1.ClusterSync{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
Namespace: fakeNamespace,
},
}

for _, tt := range []struct {
name string
wantErr string
}{
{name: "clustersync exists and are returned"},
{name: "clustersync does not exist err returned"},
} {
t.Run(tt.name, func(t *testing.T) {
fakeClientBuilder := fake.NewClientBuilder()
if tt.wantErr == "" {
fakeClientBuilder = fakeClientBuilder.WithRuntimeObjects(clusterSyncTest)
}
c := clusterManager{
hiveClientset: fakeClientBuilder.Build(),
log: logrus.NewEntry(logrus.StandardLogger()),
}

result, err := c.GetSyncSetResources(context.Background(), doc)
if err != nil && err.Error() != tt.wantErr ||
err == nil && tt.wantErr != "" {
t.Fatal(err)
}

if result != nil && reflect.DeepEqual(result, clusterSyncTest) {
t.Fatal("Unexpected clustersync list returned", result)
}
})
}
}
5 changes: 3 additions & 2 deletions pkg/util/mocks/env/core.go
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flagging this as potentially needing a rebase on master to pick up the .bingo changes. Dismiss if untrue (but it probably doesn't hurt to do it anyways).

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions pkg/util/mocks/hive/hive.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading