Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Commit

Permalink
feat(warden) : added warden client
Browse files Browse the repository at this point in the history
  • Loading branch information
Sudheer Pal committed Oct 12, 2023
1 parent d1f60e8 commit 9f3e743
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 106 deletions.
6 changes: 5 additions & 1 deletion cli/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/goto/dex/internal/server/gcs"
"github.com/goto/dex/pkg/logger"
"github.com/goto/dex/pkg/telemetry"
"github.com/goto/dex/warden"
)

func Commands() *cobra.Command {
Expand Down Expand Up @@ -104,6 +105,9 @@ func runServer(baseCtx context.Context, nrApp *newrelic.Application, zapLog *zap
if err != nil {
return err
}

wardenClient := warden.NewClient(cfg.Warden.Addr)

return server.Serve(ctx, cfg.Service.Addr(), nrApp, zapLog,
shieldv1beta1.NewShieldServiceClient(shieldConn),
entropyv1beta1.NewResourceServiceClient(entropyConn),
Expand All @@ -113,6 +117,6 @@ func runServer(baseCtx context.Context, nrApp *newrelic.Application, zapLog *zap
&gcs.Client{StorageClient: gcsClient},
cfg.Odin.Addr,
cfg.StencilAddr,
cfg.Warden.Addr,
wardenClient,
)
}
7 changes: 4 additions & 3 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import (
kubernetesv1 "github.com/goto/dex/internal/server/v1/kubernetes"
optimusv1 "github.com/goto/dex/internal/server/v1/optimus"
projectsv1 "github.com/goto/dex/internal/server/v1/project"
warden "github.com/goto/dex/internal/server/v1/warden"
wardenV1 "github.com/goto/dex/internal/server/v1/warden"
"github.com/goto/dex/warden"
)

// Serve initialises all the HTTP API routes, starts listening for requests at addr, and blocks until
Expand All @@ -39,7 +40,7 @@ func Serve(ctx context.Context, addr string,
gcsClient gcs.BlobStorageClient,
odinAddr string,
stencilAddr string,
wardenAddr string,
wardenClient *warden.Client,
) error {
alertSvc := alertsv1.NewService(sirenClient)

Expand Down Expand Up @@ -68,7 +69,7 @@ func Serve(ctx context.Context, addr string,
r.Route("/dlq", dlqv1.Routes(entropyClient, gcsClient))
r.Route("/firehoses", firehosev1.Routes(entropyClient, shieldClient, alertSvc, compassClient, odinAddr, stencilAddr))
r.Route("/kubernetes", kubernetesv1.Routes(entropyClient))
r.Route("/warden", warden.Routes(shieldClient, http.DefaultClient, wardenAddr))
r.Route("/warden", wardenV1.Routes(shieldClient, wardenClient))
})

logger.Info("starting server", zap.String("addr", addr))
Expand Down
16 changes: 8 additions & 8 deletions internal/server/v1/warden/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestHandler_teamList(t *testing.T) {
req.Header.Add("X-Auth-Email", "[email protected]")
router := chi.NewRouter()
router.Use(reqctx.WithRequestCtx())
warden.Routes(nil, doer, "")(router)
warden.Routes(nil, nil)(router)
router.ServeHTTP(resp, req)

assert.Equal(t, http.StatusOK, resp.Code)
Expand Down Expand Up @@ -112,22 +112,22 @@ func TestHandler_teamList(t *testing.T) {
req.Header.Add("X-Auth-Email", "[email protected]")
router := chi.NewRouter()
router.Use(reqctx.WithRequestCtx())
warden.Routes(shieldClient, doer, "")(router)
warden.Routes(shieldClient, nil)(router)
router.ServeHTTP(resp, req)

assert.Equal(t, http.StatusNotFound, resp.Code)
})

t.Run("should return Unauthorized when X-Auth-Email is not present is header", func(t *testing.T) {
shieldClient := shareMocks.NewShieldServiceClient(t)
doer := mocks.NewDoer(t)
// doer := mocks.NewDoer(t)

resp := httptest.NewRecorder()
req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, "/users/me/warden_teams", nil)
require.NoError(t, err)
router := chi.NewRouter()
router.Use(reqctx.WithRequestCtx())
warden.Routes(shieldClient, doer, "")(router)
warden.Routes(shieldClient, nil)(router)
router.ServeHTTP(resp, req)

assert.Equal(t, http.StatusUnauthorized, resp.Code)
Expand Down Expand Up @@ -198,7 +198,7 @@ func TestHandler_updateGroup(t *testing.T) {
require.NoError(t, err)
router := chi.NewRouter()
router.Use(reqctx.WithRequestCtx())
warden.Routes(shieldClient, doer, "")(router)
warden.Routes(shieldClient, nil)(router)
router.ServeHTTP(resp, req)

assert.Equal(t, http.StatusOK, resp.Code)
Expand Down Expand Up @@ -235,22 +235,22 @@ func TestHandler_updateGroup(t *testing.T) {
require.NoError(t, err)
router := chi.NewRouter()
router.Use(reqctx.WithRequestCtx())
warden.Routes(shieldClient, doer, "")(router)
warden.Routes(shieldClient, nil)(router)
router.ServeHTTP(resp, req)

assert.Equal(t, http.StatusInternalServerError, resp.Code)
})

t.Run("should return error when warden_team_id is empty string", func(t *testing.T) {
shieldClient := shareMocks.NewShieldServiceClient(t)
doer := mocks.NewDoer(t)
// doer := mocks.NewDoer(t)

resp := httptest.NewRecorder()
req, err := http.NewRequestWithContext(context.TODO(), http.MethodPatch, "/groups/e38527ee-a8cd-40f9-98a7-1f0bbd20909f/metadata", bytes.NewBufferString(`{"warden_team_id": ""}`))
require.NoError(t, err)
router := chi.NewRouter()
router.Use(reqctx.WithRequestCtx())
warden.Routes(shieldClient, doer, "")(router)
warden.Routes(shieldClient, nil)(router)
router.ServeHTTP(resp, req)

assert.Equal(t, http.StatusBadRequest, resp.Code)
Expand Down
6 changes: 4 additions & 2 deletions internal/server/v1/warden/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package warden
import (
shieldv1beta1rpc "buf.build/gen/go/gotocompany/proton/grpc/go/gotocompany/shield/v1beta1/shieldv1beta1grpc"
chiv5 "github.com/go-chi/chi/v5"

"github.com/goto/dex/warden"
)

func Routes(shieldClient shieldv1beta1rpc.ShieldServiceClient, doer HTTPClient, wardenAddr string) func(r chiv5.Router) {
service := NewService(shieldClient, doer, wardenAddr)
func Routes(shieldClient shieldv1beta1rpc.ShieldServiceClient, wardenClient *warden.Client) func(r chiv5.Router) {
service := NewService(shieldClient, wardenClient)
handler := NewHandler(service)
return func(r chiv5.Router) {
r.Get("/users/me/warden_teams", handler.teamList)
Expand Down
113 changes: 21 additions & 92 deletions internal/server/v1/warden/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,66 +2,28 @@ package warden

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

shieldv1beta1rpc "buf.build/gen/go/gotocompany/proton/grpc/go/gotocompany/shield/v1beta1/shieldv1beta1grpc"
shieldv1beta1 "buf.build/gen/go/gotocompany/proton/protocolbuffers/go/gotocompany/shield/v1beta1"
"google.golang.org/protobuf/types/known/structpb"

"github.com/goto/dex/warden"
)

//go:generate mockery --with-expecter --keeptree --case snake --name Doer

type Service struct {
shieldClient shieldv1beta1rpc.ShieldServiceClient
doer HTTPClient
wardenAddr string
}

type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
wardenClient *warden.Client
}

func NewService(shieldClient shieldv1beta1rpc.ShieldServiceClient, doer HTTPClient, wardenAddr string) *Service {
func NewService(shieldClient shieldv1beta1rpc.ShieldServiceClient, wardenClient *warden.Client) *Service {
return &Service{
shieldClient: shieldClient,
doer: doer,
wardenAddr: wardenAddr,
wardenClient: wardenClient,
}
}

func (c *Service) TeamList(ctx context.Context, userEmail string) (*TeamData, error) {
endpoint := "/api/v1"
userPath := "/users/"
teamsEndpoint := "/teams"

url := c.wardenAddr + endpoint + userPath + userEmail + teamsEndpoint

req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}

resp, err := c.doer.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

var data TeamListResponse
err = json.NewDecoder(resp.Body).Decode(&data)
if err != nil {
return nil, err
}

if data.Success {
return &data.Data, nil
}

return nil, ErrEmailNotOnWarden
}

func (c *Service) UpdateGroupMetadata(ctx context.Context, groupID, wardenTeamID string) (map[string]any, error) {
wardenTeam, err := c.TeamByUUID(ctx, wardenTeamID)
if err != nil {
Expand All @@ -82,8 +44,8 @@ func (c *Service) UpdateGroupMetadata(ctx context.Context, groupID, wardenTeamID
metaData = make(map[string]any)
}

metaData["team-id"] = wardenTeam.Identifier
metaData["product-group-id"] = wardenTeam.ProductGroupID
metaData["team-id"] = wardenTeam.Data.Identifier
metaData["product-group-id"] = wardenTeam.Data.ProductGroupID

updatedMetaData, err := structpb.NewStruct(metaData)
if err != nil {
Expand All @@ -106,60 +68,27 @@ func (c *Service) UpdateGroupMetadata(ctx context.Context, groupID, wardenTeamID
return UpdatedGroupRes.Group.Metadata.AsMap(), nil
}

func (c *Service) TeamByUUID(ctx context.Context, teamByUUID string) (*Team, error) {
endpoint := "/api/v2"
teamPath := "/teams/"

url := c.wardenAddr + endpoint + teamPath + teamByUUID

req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
func (svc *Service) TeamList(ctx context.Context, userEmail string) ([]warden.Team, error) {

Check failure on line 71 in internal/server/v1/warden/service.go

View workflow job for this annotation

GitHub Actions / golangci-lint

receiver-naming: receiver name svc should be consistent with previous receiver name c for Service (revive)
teams, err := svc.wardenClient.ListUserTeams(ctx, warden.TeamListRequest{
Email: userEmail,
})
if err != nil {
return nil, err
}

resp, err := c.doer.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return teams, nil
}

var data TeamResponse
err = json.NewDecoder(resp.Body).Decode(&data)
func (svc *Service) TeamByUUID(ctx context.Context, teamByUUID string) (*warden.TeamResponse, error) {

Check failure on line 82 in internal/server/v1/warden/service.go

View workflow job for this annotation

GitHub Actions / golangci-lint

receiver-naming: receiver name svc should be consistent with previous receiver name c for Service (revive)
team, err := svc.wardenClient.WardenTeamByUUID(ctx, warden.TeamByUUIDRequest{
TeamUUID: teamByUUID,
})
if err != nil {
return nil, err
}

if data.Success {
return &data.Data, nil
}

return nil, ErrEmailNotOnWarden
}

type TeamResponse struct {
Success bool `json:"success"`
Data Team `json:"data"`
Message string `json:"message"`
}

type TeamListResponse struct {
Success bool `json:"success"`
Data TeamData `json:"data"`
}

type TeamData struct {
Teams []Team `json:"teams"`
}

type Team struct {
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
OwnerID int `json:"owner_id"`
ParentTeamIdentifier string `json:"parent_team_identifier"`
Identifier string `json:"identifier"`
ProductGroupName string `json:"product_group_name"`
ProductGroupID string `json:"product_group_id"`
Labels any `json:"labels"`
ShortCode string `json:"short_code"`
return &warden.TeamResponse{
Success: true,
Data: *team,
}, nil
}
83 changes: 83 additions & 0 deletions warden/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package warden

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

type Client struct {
BaseURL string
Client *http.Client
}

func NewClient(baseURL string) *Client {
return &Client{
BaseURL: baseURL,
Client: &http.Client{},
}
}

func (c *Client) ListUserTeams(ctx context.Context, req TeamListRequest) ([]Team, error) {
const (
endpoint = "/api/v1"
userPath = "/users/"
teamsEndpoint = "/teams"
)
url := fmt.Sprintf("%s%s%s%s%s", c.BaseURL, endpoint, userPath, req.Email, teamsEndpoint)
fmt.Println("URL: ", url)
httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}

resp, err := c.Client.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch teams: %v", resp.Status)

Check failure on line 42 in warden/client.go

View workflow job for this annotation

GitHub Actions / golangci-lint

err113: do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"failed to fetch teams: %v\", resp.Status)" (goerr113)
}

var data TeamListResponse
err = json.NewDecoder(resp.Body).Decode(&data)
if err != nil {
return nil, err
}

return data.Data.Teams, nil
}

func (c *Client) WardenTeamByUUID(ctx context.Context, req TeamByUUIDRequest) (*Team, error) {
const (
endpoint = "/api/v2"
teamPath = "/teams/"
)

url := fmt.Sprintf("%s%s%s%s", c.BaseURL, endpoint, teamPath, req.TeamUUID)
httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}

resp, err := c.Client.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch team: %v", resp.Status)

Check failure on line 73 in warden/client.go

View workflow job for this annotation

GitHub Actions / golangci-lint

err113: do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"failed to fetch team: %v\", resp.Status)" (goerr113)
}

var data TeamResponse
err = json.NewDecoder(resp.Body).Decode(&data)
if err != nil {
return nil, err
}

return &data.Data, nil
}
Loading

0 comments on commit 9f3e743

Please sign in to comment.