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

read endpoint #18268

Merged
merged 38 commits into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
183298e
init commit
wangxinyi7 Jul 17, 2023
eaf297d
pass x-consul-token to the grpc server
wangxinyi7 Jul 20, 2023
97dacbc
query params and add logger
wangxinyi7 Jul 20, 2023
7062429
log message
wangxinyi7 Jul 20, 2023
e69aa2d
change log message
wangxinyi7 Jul 20, 2023
4975291
fix unit test
wangxinyi7 Jul 20, 2023
f5e9707
remove read
wangxinyi7 Jul 21, 2023
f1bfb5d
add detailed error handling message
wangxinyi7 Jul 21, 2023
7c19794
Merge branch 'main' into NET-2678/xw-http-api-write
wangxinyi7 Jul 21, 2023
42d6ccf
fix unit tests
wangxinyi7 Jul 21, 2023
595ac3e
fix unit tests
wangxinyi7 Jul 21, 2023
4ccddf3
read endpoint
wangxinyi7 Jul 24, 2023
eb96780
general refactor
wangxinyi7 Jul 25, 2023
1c2efc2
add more tests
wangxinyi7 Jul 25, 2023
884b79d
Merge branch 'main' into NET-2678/xw-http-api-write
wangxinyi7 Jul 25, 2023
dacbda0
refactor test
wangxinyi7 Jul 27, 2023
b5edf4a
add add owner and remove extra check
wangxinyi7 Jul 27, 2023
8db104c
add more tests
wangxinyi7 Aug 2, 2023
30938f1
Merge branch 'main' into NET-2678/xw-http-api-write
wangxinyi7 Aug 2, 2023
0079424
merge write branch
wangxinyi7 Aug 3, 2023
f326d53
refactor checkUrl function
wangxinyi7 Aug 3, 2023
388a465
write the error msg back
wangxinyi7 Aug 3, 2023
c3775a7
add owner test
wangxinyi7 Aug 3, 2023
f769295
merge write
wangxinyi7 Aug 3, 2023
7e2c9fa
could use the consistent mode
wangxinyi7 Aug 3, 2023
adfab07
add new test
wangxinyi7 Aug 3, 2023
996f9e8
add tests regarding the version query parameter
wangxinyi7 Aug 3, 2023
52bbf65
Merge branch 'NET-2678/xw-http-api-write' into NET-2705/xw-http-api-read
wangxinyi7 Aug 3, 2023
071d612
remove duplicate test case
wangxinyi7 Aug 3, 2023
00bab51
add test case
wangxinyi7 Aug 3, 2023
c043f45
code refactor
wangxinyi7 Aug 3, 2023
b1682ef
Merge branch 'NET-2678/xw-http-api-write' into NET-2705/xw-http-api-read
wangxinyi7 Aug 3, 2023
0c13388
merge main
wangxinyi7 Aug 4, 2023
4ae4941
merge main
wangxinyi7 Aug 11, 2023
0a189db
compare whole body in test
wangxinyi7 Aug 11, 2023
e04c8df
refactor
wangxinyi7 Aug 11, 2023
76a0a9f
linter
wangxinyi7 Aug 11, 2023
129bd83
refactor tests
wangxinyi7 Aug 11, 2023
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
56 changes: 46 additions & 10 deletions internal/resource/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ func (h *resourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPut:
h.handleWrite(w, r, ctx)
case http.MethodGet:
h.handleRead(w, r, ctx)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
return
Expand Down Expand Up @@ -83,17 +85,17 @@ func (h *resourceHandler) handleWrite(w http.ResponseWriter, r *http.Request, ct
return
}

tenancyInfo, resourceName, version := checkURL(r)
tenancyInfo, params := checkURL(r)

rsp, err := h.client.Write(ctx, &pbresource.WriteRequest{
Resource: &pbresource.Resource{
Id: &pbresource.ID{
Type: h.reg.Type,
Tenancy: tenancyInfo,
Name: resourceName,
Name: params["resourceName"],
},
Owner: req.Owner,
Version: version,
Version: params["version"],
Metadata: req.Metadata,
Data: anyProtoMsg,
},
Expand All @@ -112,18 +114,52 @@ func (h *resourceHandler) handleWrite(w http.ResponseWriter, r *http.Request, ct
w.Write(output)
}

func checkURL(r *http.Request) (tenancy *pbresource.Tenancy, resourceName string, version string) {
params := r.URL.Query()
func (h *resourceHandler) handleRead(w http.ResponseWriter, r *http.Request, ctx context.Context) {
tenancyInfo, params := checkURL(r)
if params["consistent"] != "" {
ctx = metadata.AppendToOutgoingContext(ctx, "x-consul-consistency-mode", "consistent")
}

rsp, err := h.client.Read(ctx, &pbresource.ReadRequest{
Id: &pbresource.ID{
Type: h.reg.Type,
Tenancy: tenancyInfo,
Name: params["resourceName"],
},
})
if err != nil {
handleResponseError(err, w, h)
return
}

output, err := jsonMarshal(rsp.Resource)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
h.logger.Error("Failed to unmarshal GRPC resource response", "error", err)
return
}
w.Write(output)
}

func checkURL(r *http.Request) (tenancy *pbresource.Tenancy, params map[string]string) {
query := r.URL.Query()
tenancy = &pbresource.Tenancy{
Partition: params.Get("partition"),
PeerName: params.Get("peer_name"),
Namespace: params.Get("namespace"),
Partition: query.Get("partition"),
PeerName: query.Get("peer_name"),
Namespace: query.Get("namespace"),
}
resourceName = path.Base(r.URL.Path)

resourceName := path.Base(r.URL.Path)
if resourceName == "." || resourceName == "/" {
resourceName = ""
}
version = params.Get("version")

params = make(map[string]string)
params["resourceName"] = resourceName
params["version"] = query.Get("version")
if _, ok := query["consistent"]; ok {
params["consistent"] = "true"
}

return
}
Expand Down
76 changes: 76 additions & 0 deletions internal/resource/http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

const testACLTokenArtistReadPolicy = "00000000-0000-0000-0000-000000000001"
const testACLTokenArtistWritePolicy = "00000000-0000-0000-0000-000000000002"
const fakeToken = "fake-token"

func parseToken(req *http.Request, token *string) {
*token = req.Header.Get("X-Consul-Token")
Expand Down Expand Up @@ -297,3 +298,78 @@ func TestResourceWriteHandler(t *testing.T) {
require.Equal(t, "Keith Urban V1", artist.Name)
})
}

func TestResourceReadHandler(t *testing.T) {
aclResolver := &resourceSvc.MockACLResolver{}
aclResolver.On("ResolveTokenAndDefaultMeta", testACLTokenArtistReadPolicy, mock.Anything, mock.Anything).
Return(svctest.AuthorizerFrom(t, demo.ArtistV1ReadPolicy, demo.ArtistV2ReadPolicy), nil)
aclResolver.On("ResolveTokenAndDefaultMeta", testACLTokenArtistWritePolicy, mock.Anything, mock.Anything).
Return(svctest.AuthorizerFrom(t, demo.ArtistV1WritePolicy, demo.ArtistV2WritePolicy), nil)
aclResolver.On("ResolveTokenAndDefaultMeta", fakeToken, mock.Anything, mock.Anything).
Return(svctest.AuthorizerFrom(t, ""), nil)

client := svctest.RunResourceServiceWithACL(t, aclResolver, demo.RegisterTypes)

v2ArtistHandler := resourceHandler{
resource.Registration{
Type: demo.TypeV2Artist,
Proto: &pbdemov2.Artist{},
},
client,
parseToken,
hclog.NewNullLogger(),
}
JadhavPoonam marked this conversation as resolved.
Show resolved Hide resolved

rsp := httptest.NewRecorder()
req := httptest.NewRequest("PUT", "/demo/v2/artist/keith-urban?partition=default&peer_name=local&namespace=default", strings.NewReader(`
{
"metadata": {
"foo": "bar"
},
"data": {
"name": "Keith Urban",
"genre": "GENRE_COUNTRY"
}
}
`))
req.Header.Add("x-consul-token", testACLTokenArtistWritePolicy)
v2ArtistHandler.ServeHTTP(rsp, req)
require.Equal(t, http.StatusOK, rsp.Result().StatusCode)

t.Run("Read resource", func(t *testing.T) {
rsp := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/demo/v2/artist/keith-urban?partition=default&peer_name=local&namespace=default&consistent", nil)

req.Header.Add("x-consul-token", testACLTokenArtistReadPolicy)

v2ArtistHandler.ServeHTTP(rsp, req)

require.Equal(t, http.StatusOK, rsp.Result().StatusCode)

var result map[string]any
require.NoError(t, json.NewDecoder(rsp.Body).Decode(&result))
require.Equal(t, "Keith Urban", result["data"].(map[string]any)["name"])
JadhavPoonam marked this conversation as resolved.
Show resolved Hide resolved
})

t.Run("should not be found if resource not exist", func(t *testing.T) {
rsp := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/demo/v2/artist/keith-not-exist?partition=default&peer_name=local&namespace=default&consistent", nil)

req.Header.Add("x-consul-token", testACLTokenArtistReadPolicy)

v2ArtistHandler.ServeHTTP(rsp, req)

require.Equal(t, http.StatusNotFound, rsp.Result().StatusCode)
})

t.Run("should be blocked if the token is not authorized", func(t *testing.T) {
rsp := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/demo/v2/artist/keith-urban?partition=default&peer_name=local&namespace=default&consistent", nil)

req.Header.Add("x-consul-token", fakeToken)

v2ArtistHandler.ServeHTTP(rsp, req)

require.Equal(t, http.StatusForbidden, rsp.Result().StatusCode)
})
}
Loading