Skip to content

Commit

Permalink
Feat(Multi-tenancy): Add namespaces field to state (#7808)
Browse files Browse the repository at this point in the history
* Add namespaces to state

* Add tests

* Fix golint errors

* Address Naman's comments

(cherry picked from commit d2bd832)
  • Loading branch information
vmrajas authored and OmarAyo committed Jun 30, 2021
1 parent 88edcd9 commit e869d66
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 19 deletions.
5 changes: 5 additions & 0 deletions graphql/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ const (
removed: [Member]
cid: String
license: License
"""
Contains list of namespaces. Note that this is not stored in proto's MembershipState and
computed at the time of query.
"""
namespaces: [UInt64]
}
type ClusterGroup {
Expand Down
35 changes: 24 additions & 11 deletions graphql/admin/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ import (
)

type membershipState struct {
Counter uint64 `json:"counter,omitempty"`
Groups []clusterGroup `json:"groups,omitempty"`
Zeros []*pb.Member `json:"zeros,omitempty"`
MaxUID uint64 `json:"maxUID,omitempty"`
MaxNsID uint64 `json:"maxNsID,omitempty"`
MaxTxnTs uint64 `json:"maxTxnTs,omitempty"`
MaxRaftId uint64 `json:"maxRaftId,omitempty"`
Removed []*pb.Member `json:"removed,omitempty"`
Cid string `json:"cid,omitempty"`
License *pb.License `json:"license,omitempty"`
Counter uint64 `json:"counter,omitempty"`
Groups []clusterGroup `json:"groups,omitempty"`
Zeros []*pb.Member `json:"zeros,omitempty"`
MaxUID uint64 `json:"maxUID,omitempty"`
MaxNsID uint64 `json:"maxNsID,omitempty"`
MaxTxnTs uint64 `json:"maxTxnTs,omitempty"`
MaxRaftId uint64 `json:"maxRaftId,omitempty"`
Removed []*pb.Member `json:"removed,omitempty"`
Cid string `json:"cid,omitempty"`
License *pb.License `json:"license,omitempty"`
Namespaces []uint64 `json:"namespaces,omitempty"`
}

type clusterGroup struct {
Expand Down Expand Up @@ -78,15 +79,22 @@ func resolveState(ctx context.Context, q schema.Query) *resolve.Resolved {
func convertToGraphQLResp(ms pb.MembershipState) membershipState {
var state membershipState

// namespaces stores set of namespaces
namespaces := make(map[uint64]struct{})

state.Counter = ms.Counter
for k, v := range ms.Groups {
var members = make([]*pb.Member, 0, len(v.Members))
for _, v1 := range v.Members {
members = append(members, v1)
}
var tablets = make([]*pb.Tablet, 0, len(v.Tablets))
for _, v1 := range v.Tablets {
for name, v1 := range v.Tablets {
tablets = append(tablets, v1)
val, err := x.ExtractNamespaceFromPredicate(name)
if err == nil {
namespaces[val] = struct{}{}
}
}
state.Groups = append(state.Groups, clusterGroup{
Id: k,
Expand All @@ -108,5 +116,10 @@ func convertToGraphQLResp(ms pb.MembershipState) membershipState {
state.Cid = ms.Cid
state.License = ms.License

state.Namespaces = []uint64{}
for ns := range namespaces {
state.Namespaces = append(state.Namespaces, ns)
}

return state
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
* limitations under the License.
*/

package schema
package multi_tenancy

import (
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -211,7 +212,7 @@ func TestGraphQLResponse(t *testing.T) {
require.Equal(t, schema, common.AssertGetGQLSchema(t, common.Alpha1HTTP, header).Schema)
require.Equal(t, schema, common.AssertGetGQLSchema(t, common.Alpha1HTTP, header1).Schema)

graphqlHelper(t, `
queryHelper(t, groupOneGraphQLServer, `
mutation {
addAuthor(input:{name: "Alice"}) {
author{
Expand All @@ -227,7 +228,7 @@ func TestGraphQLResponse(t *testing.T) {
}
}`)

graphqlHelper(t, query, header,
queryHelper(t, groupOneGraphQLServer, query, header,
`{
"queryAuthor": [
{
Expand All @@ -236,7 +237,7 @@ func TestGraphQLResponse(t *testing.T) {
]
}`)

graphqlHelper(t, query, header1,
queryHelper(t, groupOneGraphQLServer, query, header1,
`{
"queryAuthor": []
}`)
Expand Down Expand Up @@ -309,7 +310,7 @@ func TestAuth(t *testing.T) {
Header: "Authorization",
})
header.Set(accessJwtHeader, testutil.GrootHttpLogin(groupOneAdminServer).AccessJwt)
graphqlHelper(t, addUserMutation, header, `{
queryHelper(t, groupOneGraphQLServer, addUserMutation, header, `{
"addUser": {
"user":[{
"username":"Alice"
Expand All @@ -326,7 +327,7 @@ func TestAuth(t *testing.T) {
})
header1.Set(accessJwtHeader, testutil.GrootHttpLoginNamespace(groupOneAdminServer,
ns).AccessJwt)
graphqlHelper(t, addUserMutation, header1, `{
queryHelper(t, groupOneGraphQLServer, addUserMutation, header1, `{
"addUser": {
"user":[{
"username":"Bob"
Expand Down Expand Up @@ -385,13 +386,13 @@ func TestCORS(t *testing.T) {
common.DeleteNamespace(t, ns, header)
}

func graphqlHelper(t *testing.T, query string, headers http.Header,
func queryHelper(t *testing.T, server, query string, headers http.Header,
expectedResult string) {
params := &common.GraphQLParams{
Query: query,
Headers: headers,
}
queryResult := params.ExecuteAsPost(t, groupOneGraphQLServer)
queryResult := params.ExecuteAsPost(t, server)
common.RequireNoGQLErrors(t, queryResult)
testutil.CompareJSON(t, expectedResult, string(queryResult.Data))
}
Expand Down Expand Up @@ -430,3 +431,53 @@ func testCORS(t *testing.T, namespace uint64, reqOrigin, expectedAllowedOrigin,
common.RequireNoGQLErrors(t, gqlRes)
testutil.CompareJSON(t, `{"queryTestCORS":[]}`, string(gqlRes.Data))
}

// TestNamespacesQueryField checks that namespaces field in state query of /admin endpoint is
// properly working.
func TestNamespacesQueryField(t *testing.T) {
header := http.Header{}
header.Set(accessJwtHeader, testutil.GrootHttpLogin(groupOneAdminServer).AccessJwt)

namespaceQuery :=
`query {
state {
namespaces
}
}`

// Test namespaces query shows 0 as the only namespace.
queryHelper(t, groupOneAdminServer, namespaceQuery, header,
`{
"state": {
"namespaces":[0]
}
}`)

ns1 := common.CreateNamespace(t, header)
ns2 := common.CreateNamespace(t, header)
header1 := http.Header{}
header1.Set(accessJwtHeader, testutil.GrootHttpLoginNamespace(groupOneAdminServer,
ns1).AccessJwt)

// Test namespaces query shows no namespace in case user is not guardian of galaxy.
queryHelper(t, groupOneAdminServer, namespaceQuery, header1,
`{
"state": {
"namespaces":[]
}
}`)

// Test namespaces query shows all 3 namespaces, 0,ns1,ns2 in case user is guardian of galaxy.
queryHelper(t, groupOneAdminServer, namespaceQuery, header,
`{
"state": {
"namespaces":[0,`+
strconv.FormatUint(ns1, 10)+`,`+
strconv.FormatUint(ns2, 10)+`]
}
}`)

// cleanup
common.DeleteNamespace(t, ns1, header)
common.DeleteNamespace(t, ns2, header)
}
13 changes: 13 additions & 0 deletions x/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@ func FormatNsAttr(attr string) string {
return strconv.FormatUint(ns, 10) + "-" + attr
}

func ExtractNamespaceFromPredicate(predicate string) (uint64, error) {
splitString := strings.Split(predicate, "-")
if len(splitString) <= 1 {
return 0, errors.Errorf("predicate does not contain namespace name")
}
uintVal, err := strconv.ParseUint(splitString[0], 0, 64)
if err != nil {
return 0, errors.Wrapf(err, "while parsing %s as uint64", splitString[0])
}
return uintVal, nil

}

func writeAttr(buf []byte, attr string) []byte {
AssertTrue(len(attr) < math.MaxUint16)
binary.BigEndian.PutUint16(buf[:2], uint16(len(attr)))
Expand Down

0 comments on commit e869d66

Please sign in to comment.