Skip to content

Commit

Permalink
feat: addition of applens client and detector endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
Zach Jones committed Jul 12, 2022
1 parent 7439c4b commit 5807b66
Show file tree
Hide file tree
Showing 26 changed files with 2,030 additions and 38 deletions.
15 changes: 15 additions & 0 deletions pkg/env/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net"
"os"

"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/sirupsen/logrus"

Expand Down Expand Up @@ -98,3 +99,17 @@ func (d *dev) FPAuthorizer(tenantID, resource string) (refreshable.Authorizer, e

return refreshable.NewAuthorizer(sp), nil
}

func (d *dev) FPNewClientCertificateCredential(tenantID string) (*azidentity.ClientCertificateCredential, error) {
fpPrivateKey, fpCertificates := d.fpCertificateRefresher.GetCertificates()

credential, err := azidentity.NewClientCertificateCredential(tenantID, d.fpClientID, fpCertificates, fpPrivateKey, &azidentity.ClientCertificateCredentialOptions{
AuthorityHost: d.Environment().AuthorityHost,
})

if err != nil {
return nil, err
}

return credential, nil
}
2 changes: 2 additions & 0 deletions pkg/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os"
"strings"

"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
mgmtcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
"github.com/sirupsen/logrus"

Expand Down Expand Up @@ -79,6 +80,7 @@ type Interface interface {
Domain() string
FeatureIsSet(Feature) bool
FPAuthorizer(string, string) (refreshable.Authorizer, error)
FPNewClientCertificateCredential(string) (*azidentity.ClientCertificateCredential, error)
FPClientID() string
Listen() (net.Listener, error)
GatewayDomains() []string
Expand Down
15 changes: 15 additions & 0 deletions pkg/env/prod.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
mgmtcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure"
Expand Down Expand Up @@ -358,3 +359,17 @@ func (p *prod) VMSku(vmSize string) (*mgmtcompute.ResourceSku, error) {
}
return vmsku, nil
}

func (p *prod) FPNewClientCertificateCredential(tenantID string) (*azidentity.ClientCertificateCredential, error) {
fpPrivateKey, fpCertificates := p.fpCertificateRefresher.GetCertificates()

credential, err := azidentity.NewClientCertificateCredential(tenantID, p.fpClientID, fpCertificates, fpPrivateKey, &azidentity.ClientCertificateCredentialOptions{
AuthorityHost: p.Environment().AuthorityHost,
})

if err != nil {
return nil, err
}

return credential, nil
}
28 changes: 28 additions & 0 deletions pkg/frontend/adminactions/azureactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package adminactions

import (
"context"
"encoding/json"
"fmt"
"net/http"

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

"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/env"
"github.com/Azure/ARO-RP/pkg/util/azureclient/applens"
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/compute"
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/features"
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/network"
Expand All @@ -30,6 +32,8 @@ type AzureActions interface {
VMSizeList(ctx context.Context) ([]mgmtcompute.ResourceSku, error)
VMResize(ctx context.Context, vmName string, vmSize string) error
VMSerialConsole(ctx context.Context, w http.ResponseWriter, log *logrus.Entry, vmName string) error
AppLensGetDetector(ctx context.Context, detectorId string) ([]byte, error)
AppLensListDetectors(ctx context.Context) ([]byte, error)
}

type azureActions struct {
Expand All @@ -45,6 +49,7 @@ type azureActions struct {
routeTables network.RouteTablesClient
storageAccounts storage.AccountsClient
networkInterfaces network.InterfacesClient
appLens applens.AppLensClient
}

// NewAzureActions returns an azureActions
Expand All @@ -56,6 +61,11 @@ func NewAzureActions(log *logrus.Entry, env env.Interface, oc *api.OpenShiftClus
return nil, err
}

fpClientCertCred, err := env.FPNewClientCertificateCredential(subscriptionDoc.Subscription.Properties.TenantID)
if err != nil {
return nil, err
}

return &azureActions{
log: log,
env: env,
Expand All @@ -69,6 +79,7 @@ func NewAzureActions(log *logrus.Entry, env env.Interface, oc *api.OpenShiftClus
routeTables: network.NewRouteTablesClient(env.Environment(), subscriptionDoc.ID, fpAuth),
storageAccounts: storage.NewAccountsClient(env.Environment(), subscriptionDoc.ID, fpAuth),
networkInterfaces: network.NewInterfacesClient(env.Environment(), subscriptionDoc.ID, fpAuth),
appLens: applens.NewAppLensClient(env.Environment(), fpClientCertCred),
}, nil
}

Expand Down Expand Up @@ -102,3 +113,20 @@ func (a *azureActions) VMResize(ctx context.Context, vmName string, size string)
vm.HardwareProfile.VMSize = mgmtcompute.VirtualMachineSizeTypes(size)
return a.virtualMachines.CreateOrUpdateAndWait(ctx, clusterRGName, vmName, vm)
}

func (a *azureActions) AppLensGetDetector(ctx context.Context, detectorId string) ([]byte, error) {
resp, err := a.appLens.GetDetector(ctx, &applens.GetDetectorOptions{ResourceID: a.oc.Properties.ClusterProfile.ResourceGroupID, DetectorID: detectorId})

if err != nil {
return nil, err
}
return json.Marshal(resp.Body)
}

func (a *azureActions) AppLensListDetectors(ctx context.Context) ([]byte, error) {
resp, err := a.appLens.ListDetectors(ctx, &applens.ListDetectorsOptions{ResourceID: a.oc.Properties.ClusterProfile.ResourceGroupID})
if err != nil {
return nil, err
}
return json.Marshal(resp.Body)
}
12 changes: 12 additions & 0 deletions pkg/frontend/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,18 @@ func (f *frontend) authenticatedRoutes(r *mux.Router) {

s.Methods(http.MethodPost).HandlerFunc(f.postOpenShiftClusterKubeConfigCredentials).Name("postOpenShiftClusterKubeConfigCredentials")

s = r.
Path("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}/detectors").
Subrouter()

s.Methods(http.MethodGet).HandlerFunc(f.listAppLensDetectors).Name("listAppLensDetectors")

s = r.
Path("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}/detectors/{detectorId}").
Subrouter()

s.Methods(http.MethodGet).HandlerFunc(f.getAppLensDetector).Name("getAppLensDetector")

// Admin actions
s = r.
Path("/admin/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}/kubernetesobjects").
Expand Down
83 changes: 83 additions & 0 deletions pkg/frontend/openshiftcluster_applensdetectors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package frontend

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

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

"github.com/gorilla/mux"
"github.com/sirupsen/logrus"

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

func (f *frontend) listAppLensDetectors(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry)
r.URL.Path = filepath.Dir(r.URL.Path)

b, err := f._listAppLensDetectors(ctx, r, log)

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

func (f *frontend) _listAppLensDetectors(ctx context.Context, r *http.Request, log *logrus.Entry) ([]byte, error) {
a, err := f._createAzureActionsFactory(ctx, r, log)
if err != nil {
return nil, err
}

return a.AppLensListDetectors(ctx)
}

func (f *frontend) getAppLensDetector(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry)
r.URL.Path = filepath.Dir(r.URL.Path)

b, err := f._appLensDetectors(ctx, r, log)

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

func (f *frontend) _appLensDetectors(ctx context.Context, r *http.Request, log *logrus.Entry) ([]byte, error) {
a, err := f._createAzureActionsFactory(ctx, r, log)
if err != nil {
return nil, err
}

vars := mux.Vars(r)
return a.AppLensGetDetector(ctx, vars["detectorId"])
}

func (f *frontend) _createAzureActionsFactory(ctx context.Context, r *http.Request, log *logrus.Entry) (adminactions.AzureActions, error) {
vars := mux.Vars(r)

resourceID := strings.TrimSuffix(r.URL.Path, "/detectors")
doc, err := f.dbOpenShiftClusters.Get(ctx, resourceID)
switch {
case cosmosdb.IsErrorStatusCode(err, http.StatusNotFound):
return nil, api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeResourceNotFound, "", "The Resource '%s/%s' under resource group '%s' was not found.", vars["resourceType"], vars["resourceName"], vars["resourceGroupName"])
case err != nil:
return nil, err
}

subscriptionDoc, err := f.getSubscriptionDocument(ctx, doc.Key)
if err != nil {
return nil, err
}

a, err := f.azureActionsFactory(log, f.env, doc.OpenShiftCluster, subscriptionDoc)
if err != nil {
return nil, err
}

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

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

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

"github.com/golang/mock/gomock"
"github.com/sirupsen/logrus"

"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/env"
"github.com/Azure/ARO-RP/pkg/frontend/adminactions"
"github.com/Azure/ARO-RP/pkg/metrics/noop"
mock_adminactions "github.com/Azure/ARO-RP/pkg/util/mocks/adminactions"
)

func TestAppLensDetectors(t *testing.T) {
mockSubID := "00000000-0000-0000-0000-000000000000"
mockTenantID := "00000000-0000-0000-0000-000000000000"
ctx := context.Background()

type test struct {
name string
resourceID string
detectorID string
getDetector bool
mocks func(*test, *mock_adminactions.MockAzureActions)
method string
wantStatusCode int
wantResponse []byte
wantError string
}

for _, tt := range []*test{
{
method: http.MethodGet,
name: "list applens detectors",
resourceID: fmt.Sprintf("/subscriptions/%s/resourcegroups/resourceGroup/providers/Microsoft.RedHatOpenShift/openShiftClusters/resourceName", mockSubID),
detectorID: "",
getDetector: false,
mocks: func(tt *test, a *mock_adminactions.MockAzureActions) {
a.EXPECT().
AppLensListDetectors(gomock.Any()).
Return([]byte(`{"Kind": "test"}`), nil)
},
wantStatusCode: http.StatusOK,
wantResponse: []byte(`{"Kind": "test"}` + "\n"),
},
{
method: http.MethodGet,
name: "get applens detector",
resourceID: fmt.Sprintf("/subscriptions/%s/resourcegroups/resourceGroup/providers/Microsoft.RedHatOpenShift/openShiftClusters/resourceName", mockSubID),
detectorID: "testdetector",
getDetector: true,
mocks: func(tt *test, a *mock_adminactions.MockAzureActions) {
a.EXPECT().
AppLensGetDetector(gomock.Any(), tt.detectorID).
Return([]byte(`{"Kind": "test"}`), nil)
},
wantStatusCode: http.StatusOK,
wantResponse: []byte(`{"Kind": "test"}` + "\n"),
},
{
method: http.MethodGet,
name: "no applens detector specified",
resourceID: fmt.Sprintf("/subscriptions/%s/resourcegroups/resourceGroup/providers/Microsoft.RedHatOpenShift/openShiftClusters/resourceName", mockSubID),
detectorID: "",
getDetector: true,
mocks: func(tt *test, a *mock_adminactions.MockAzureActions) {
},
wantStatusCode: http.StatusNotFound,
wantError: "404: NotFound: : The requested path could not be found.",
},
} {
t.Run(tt.name, func(t *testing.T) {
ti := newTestInfra(t).WithSubscriptions().WithOpenShiftClusters()
defer ti.done()

a := mock_adminactions.NewMockAzureActions(ti.controller)
tt.mocks(tt, a)

ti.fixture.AddOpenShiftClusterDocuments(&api.OpenShiftClusterDocument{
Key: strings.ToLower(tt.resourceID),
OpenShiftCluster: &api.OpenShiftCluster{
ID: tt.resourceID,
Name: "resourceName",
Type: "Microsoft.RedHatOpenShift/openshiftClusters",
},
})
ti.fixture.AddSubscriptionDocuments(&api.SubscriptionDocument{
ID: mockSubID,
Subscription: &api.Subscription{
State: api.SubscriptionStateRegistered,
Properties: &api.SubscriptionProperties{
TenantID: mockTenantID,
},
},
})

err := ti.buildFixtures(nil)
if err != nil {
t.Fatal(err)
}

f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, api.APIs, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
return a, nil
}, nil)

if err != nil {
t.Fatal(err)
}

go f.Run(ctx, nil, nil)

finalURL := fmt.Sprintf("https://server%s/detectors", tt.resourceID)
if tt.getDetector {
finalURL = fmt.Sprintf("%s/%s", finalURL, tt.detectorID)
}

resp, b, err := ti.request(http.MethodGet, finalURL, nil, nil)
if err != nil {
t.Fatal(err)
}

err = validateResponse(resp, b, tt.wantStatusCode, tt.wantError, tt.wantResponse)
if err != nil {
t.Error(err)
}
})
}
}
Loading

0 comments on commit 5807b66

Please sign in to comment.