diff --git a/.gitignore b/.gitignore index 5f8c3feae5ccb8f8500cf0d54ded6da0079cfe02..d7c8d680d0598ba1ac993843cf1d2ee7f45fad02 100644 --- a/.gitignore +++ b/.gitignore @@ -129,7 +129,7 @@ asapo_tools/pkg #version files -common/cpp/include/asapo/common/version.h +common/cpp/include/asapo/common/internal/version.h common/go/src/asapo_common/version/version_lib.go diff --git a/CHANGELOG.md b/CHANGELOG.md index a26180846d0335d7dd3b4f09f651def6b38b25f1..27c7a0824aafd5d923b714998da6b8de03a3146b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,16 @@ -## 21.03.0 (in progress) +## 21.03.0 IMPROVEMENTS -<<<<<<< HEAD * Producer API - queue limits in Python, for C++ return original data in error custom data * Consumer API - add GetCurrentDatasetCount/get_current_dataset_count function with option to include or exclude incomplete datasets * Consumer API - GetStreamList/get_stream_list - can filter finished/unfinished streams now * Producer/Consumer API - StreamInfo structure/Python dictionary include more information (is stream finished or not, ...) * Switch to JWT tokens (token has more symbols, expiration time, can be revoked and there are two type of tokens - with read/write access rights) +* Improved versioning. Producer/Consumer API - introduce GetVersionInfo/get_version_info, compatiblity check between clients and server BREAKING CHANGES * Consumer API (C++ only)- GetStreamList has now extra argument StreamFilter +* Consumer/Producer libraries need to be updated due to protocol changes ## 20.12.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index bdba0ff646a6281f95f0ce701e2744db132003a3..b63879369a8f34781829739606389732150ce49e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,17 @@ cmake_minimum_required(VERSION 3.7) project(ASAPO) + +#protocol version changes if one of the microservice API's change +set (ASAPO_CONSUMER_PROTOCOL "v0.1") +set (ASAPO_PRODUCER_PROTOCOL "v0.1") + +set (ASAPO_DISCOVERY_API_VER "v0.1") +set (ASAPO_AUTHORIZER_API_VER "v0.1") +set (ASAPO_BROKER_API_VER "v0.1") +set (ASAPO_FILE_TRANSFER_SERVICE_API_VER "v0.1") +set (ASAPO_RECEIVER_API_VER "v0.1") +set (ASAPO_RDS_API_VER "v0.1") + set(CMAKE_CXX_STANDARD 11) IF(WIN32) set(CMAKE_CXX_FLAGS_DEBUG "/MTd") diff --git a/CMakeModules/prepare_version.cmake b/CMakeModules/prepare_version.cmake index 02bd80de29d1097719e79e97c87df80b850e7a76..7ef56e9486d3c798234c767aedcca48654cf5821 100644 --- a/CMakeModules/prepare_version.cmake +++ b/CMakeModules/prepare_version.cmake @@ -1,4 +1,4 @@ string(TIMESTAMP TIMESTAMP "%H:%M:%S %d.%m.%Y UTC" UTC) -configure_file(${PROJECT_SOURCE_DIR}/common/cpp/include/asapo/common/version.h.in ${PROJECT_SOURCE_DIR}/common/cpp/include/asapo/common/version.h @ONLY) +configure_file(${PROJECT_SOURCE_DIR}/common/cpp/include/asapo/common/internal/version.h.in ${PROJECT_SOURCE_DIR}/common/cpp/include/asapo/common/internal/version.h @ONLY) configure_file(${PROJECT_SOURCE_DIR}/common/go/src/asapo_common/version/version_lib.go.in ${PROJECT_SOURCE_DIR}/common/go/src/asapo_common/version/version_lib.go @ONLY) diff --git a/CMakeModules/prepare_version_tag.cmake b/CMakeModules/prepare_version_tag.cmake index 308beae3a9cf818823b21b68b568e6dbdf1e0085..35273cb2576e98f211cd4fb36b662070dc417e92 100644 --- a/CMakeModules/prepare_version_tag.cmake +++ b/CMakeModules/prepare_version_tag.cmake @@ -14,7 +14,7 @@ execute_process(COMMAND git rev-parse --abbrev-ref HEAD string(STRIP ${BRANCH} BRANCH) cleanup(BRANCH) -execute_process(COMMAND git rev-parse --short HEAD +execute_process(COMMAND git rev-parse --short=10 HEAD OUTPUT_VARIABLE ASAPO_VERSION_COMMIT WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) string(STRIP ${ASAPO_VERSION_COMMIT} ASAPO_VERSION_COMMIT) diff --git a/PROTOCOL-VERSIONS.md b/PROTOCOL-VERSIONS.md new file mode 100644 index 0000000000000000000000000000000000000000..e47b371f29a04c26cd9b121159f1453bf4a99a17 --- /dev/null +++ b/PROTOCOL-VERSIONS.md @@ -0,0 +1,10 @@ +### Producer Protocol +| Release | Supported by client | Supported by server | Status | +| ------------ | ------------------- | -------------------- | ---------------- | +| v0.1 | 21.03.0 - 21.03.0 | 21.03.0 - 21.03.0 | Current version | + + +### Consumer Protocol +| Release | Supported by client | Supported by server | Status | +| ------------ | ------------------- | -------------------- | ---------------- | +| v0.1 | 21.03.0 - 21.03.0 | 21.03.0 - 21.03.0 | Current version | diff --git a/VERSIONS.md b/VERSIONS.md new file mode 100644 index 0000000000000000000000000000000000000000..67aeaf79892c01d4e1ab4a5b850826d4a5837900 --- /dev/null +++ b/VERSIONS.md @@ -0,0 +1,11 @@ +### Producer API + +| Release | API changed | Breaking changes | Protocol | Supported by server up to | Status | +| ------------ | ----------- |----------------- | -------- | ------------------------- | ------- | +| 21.03.0 | Yes | No | v0.1 | 21.03.0 | Current version | + +### Consumer API + +| Release | API changed | Breaking changes | Protocol | Supported by server up to | Status | +| ------------ | ----------- |----------------- | -------- | ------------------------- | ------- | +| 21.03.0 | Yes | Yes | v0.1 | 21.03.0 | Current version | diff --git a/authorizer/src/asapo_authorizer/server/folder_token.go b/authorizer/src/asapo_authorizer/server/folder_token.go index f29a5b318b87042c040ddbe950927ca778b20a1c..6b80193478187250f1d14df00f754bcd6bde5181 100644 --- a/authorizer/src/asapo_authorizer/server/folder_token.go +++ b/authorizer/src/asapo_authorizer/server/folder_token.go @@ -3,6 +3,7 @@ package server import ( "asapo_common/structs" "asapo_common/utils" + "asapo_common/version" "net/http" "time" log "asapo_common/logger" @@ -11,20 +12,20 @@ import ( ) type folderTokenRequest struct { - Folder string + Folder string BeamtimeId string Token string } type folderToken struct { - Token string + Token string } /*func routeFolderToken(w http.ResponseWriter, r *http.Request) { utils.ProcessJWTAuth(processFolderTokenRequest,settings.secret)(w,r) }*/ -func prepareJWTToken(request folderTokenRequest) (string,error) { +func prepareJWTToken(request folderTokenRequest) (string, error) { var claims utils.CustomClaims var extraClaim structs.FolderTokenTokenExtraClaim @@ -35,40 +36,39 @@ func prepareJWTToken(request folderTokenRequest) (string,error) { } -func folderTokenResponce(token string) []byte{ +func folderTokenResponce(token string) []byte { return []byte(token) } func checkBeamtimeToken(request folderTokenRequest) error { - _,err := checkToken(request.Token,utils.SubjectFromBeamtime(request.BeamtimeId)) + _, err := checkToken(request.Token, utils.SubjectFromBeamtime(request.BeamtimeId)) return err } - -func extractFolderTokenrequest(r *http.Request) (folderTokenRequest,error) { +func extractFolderTokenrequest(r *http.Request) (folderTokenRequest, error) { var request folderTokenRequest - err := utils.ExtractRequest(r,&request) + err := utils.ExtractRequest(r, &request) if err != nil { - return folderTokenRequest{},err + return folderTokenRequest{}, err } - if len(request.Folder)==0 ||len(request.BeamtimeId)==0 || len(request.Token) == 0 { - return folderTokenRequest{},errors.New("some request fields are empty") + if len(request.Folder) == 0 || len(request.BeamtimeId) == 0 || len(request.Token) == 0 { + return folderTokenRequest{}, errors.New("some request fields are empty") } - return request,nil + return request, nil } func checkBeamtimeFolder(request folderTokenRequest) error { - beamtimeMeta, err := findMeta(SourceCredentials{request.BeamtimeId,"auto","","",""}) + beamtimeMeta, err := findMeta(SourceCredentials{request.BeamtimeId, "auto", "", "", ""}) if err != nil { - log.Error("cannot get beamtime meta"+err.Error()) + log.Error("cannot get beamtime meta" + err.Error()) return err } folder := filepath.Clean(request.Folder) - if (folder != filepath.Clean(beamtimeMeta.OnlinePath) && folder != filepath.Clean(beamtimeMeta.OfflinePath)) { - err_string := folder + " does not match beamtime folders "+beamtimeMeta.OnlinePath+" or " +beamtimeMeta.OfflinePath + if folder != filepath.Clean(beamtimeMeta.OnlinePath) && folder != filepath.Clean(beamtimeMeta.OfflinePath) { + err_string := folder + " does not match beamtime folders " + beamtimeMeta.OnlinePath + " or " + beamtimeMeta.OfflinePath log.Error(err_string) return errors.New(err_string) } @@ -76,28 +76,37 @@ func checkBeamtimeFolder(request folderTokenRequest) error { return nil } +func checkAuthorizerApiVersion(w http.ResponseWriter, r *http.Request) bool { + _, ok := utils.PrecheckApiVersion(w, r, version.GetAuthorizerApiVersion()) + return ok +} + func routeFolderToken(w http.ResponseWriter, r *http.Request) { + if ok := checkAuthorizerApiVersion(w, r); !ok { + return + } + request, err := extractFolderTokenrequest(r) if err != nil { - utils.WriteServerError(w,err,http.StatusBadRequest) + utils.WriteServerError(w, err, http.StatusBadRequest) return } err = checkBeamtimeToken(request) if err != nil { - utils.WriteServerError(w,err,http.StatusUnauthorized) + utils.WriteServerError(w, err, http.StatusUnauthorized) return } err = checkBeamtimeFolder(request) if err != nil { - utils.WriteServerError(w,err,http.StatusUnauthorized) + utils.WriteServerError(w, err, http.StatusUnauthorized) return } token, err := prepareJWTToken(request) if err != nil { - utils.WriteServerError(w,err,http.StatusInternalServerError) + utils.WriteServerError(w, err, http.StatusInternalServerError) return } diff --git a/authorizer/src/asapo_authorizer/server/folder_token_test.go b/authorizer/src/asapo_authorizer/server/folder_token_test.go index 5b89f3b39ccf62e353b7feb622e214ad9d3de04c..ee9ab2f5088474e753e811c6440196bfa6f2d0ba 100644 --- a/authorizer/src/asapo_authorizer/server/folder_token_test.go +++ b/authorizer/src/asapo_authorizer/server/folder_token_test.go @@ -50,7 +50,7 @@ func TestFolderToken(t *testing.T) { if test.status == http.StatusBadRequest { request =makeRequest(authorizationRequest{}) } - w := doPostRequest("/folder",request,"") + w := doPostRequest("/v0.1/folder",request,"") if w.Code == http.StatusOK { body, _ := ioutil.ReadAll(w.Body) claims,_ := utils.CheckJWTToken(string(body),"secret_folder") @@ -66,3 +66,11 @@ func TestFolderToken(t *testing.T) { } } +func TestFolderTokenWrongProtocol(t *testing.T) { + request := makeRequest(folderTokenRequest{"abs_path","beamtime_id","token"}) + w := doPostRequest("/v0.2/folder",request,"") + assert.Equal(t, http.StatusUnsupportedMediaType, w.Code, "wrong protocol") +} + + + diff --git a/authorizer/src/asapo_authorizer/server/listroutes.go b/authorizer/src/asapo_authorizer/server/listroutes.go index 370dd9dfa5b9cc40fd8f9db92ca4cd4449e06d21..09b695091ffc4ecf686715a5b7a4f10434280cbb 100644 --- a/authorizer/src/asapo_authorizer/server/listroutes.go +++ b/authorizer/src/asapo_authorizer/server/listroutes.go @@ -26,7 +26,7 @@ var listRoutes = utils.Routes{ utils.Route{ "Folder Token", "POST", - "/folder", + "/{apiver}/folder", routeFolderToken, }, utils.Route{ diff --git a/broker/src/asapo_broker/server/get_commands_test.go b/broker/src/asapo_broker/server/get_commands_test.go index 0fc547da341cf9fdc04312a0480c6f05046929f2..c472ddb4c3948004c412ea6267da70a582a72084 100644 --- a/broker/src/asapo_broker/server/get_commands_test.go +++ b/broker/src/asapo_broker/server/get_commands_test.go @@ -58,7 +58,7 @@ func (suite *GetCommandsTestSuite) TestGetCommandsCallsCorrectRoutine() { for _, test := range testsGetCommand { suite.mock_db.On("ProcessRequest", database.Request{DbName: expectedDBName, DbCollectionName: test.stream, GroupId: test.groupid, Op: test.command, ExtraParam: test.externalParam}).Return([]byte("Hello"), nil) logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request "+test.command))) - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + test.reqString+correctTokenSuffix+test.queryParams) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + test.reqString+correctTokenSuffix+test.queryParams) suite.Equal(http.StatusOK, w.Code, test.command+ " OK") suite.Equal("Hello", string(w.Body.Bytes()), test.command+" sends data") } diff --git a/broker/src/asapo_broker/server/get_health.go b/broker/src/asapo_broker/server/get_health.go index ce5f45ee531005cb5817410052b89b3449761028..c4ff315d16533e967019c3e4bbf60cc8404e775d 100644 --- a/broker/src/asapo_broker/server/get_health.go +++ b/broker/src/asapo_broker/server/get_health.go @@ -9,6 +9,5 @@ func routeGetHealth(w http.ResponseWriter, r *http.Request) { if err != nil { ReconnectDb() } - r.Header.Set("Content-type", "application/json") w.WriteHeader(http.StatusNoContent) } diff --git a/broker/src/asapo_broker/server/get_health_test.go b/broker/src/asapo_broker/server/get_health_test.go index a318c8d953d8ce3abc179f7fbdc20076a17b3785..67ade394949cf19882fa0fb0b1cf8ea5a3132ef3 100644 --- a/broker/src/asapo_broker/server/get_health_test.go +++ b/broker/src/asapo_broker/server/get_health_test.go @@ -34,7 +34,7 @@ func TestGetHealthTestSuite(t *testing.T) { func (suite *GetHealthTestSuite) TestGetHealthOk() { suite.mock_db.On("Ping").Return(nil) - w := doRequest("/health") + w := doRequest("/health","GET","","") suite.Equal(http.StatusNoContent, w.Code) } @@ -44,6 +44,6 @@ func (suite *GetHealthTestSuite) TestGetHealthTriesToReconnectsToDataBase() { ExpectReconnect(suite.mock_db) - w := doRequest("/health") + w := doRequest("/health","GET","","") suite.Equal(http.StatusNoContent, w.Code) } diff --git a/broker/src/asapo_broker/server/get_meta_test.go b/broker/src/asapo_broker/server/get_meta_test.go index 4eb0e16547b60e7abb07a60f8667d7aadf9ef1bd..550efb653178533801ed305926cedd2ae1609cbf 100644 --- a/broker/src/asapo_broker/server/get_meta_test.go +++ b/broker/src/asapo_broker/server/get_meta_test.go @@ -35,7 +35,7 @@ func TestGetMetaTestSuite(t *testing.T) { func (suite *GetMetaTestSuite) TestGetMetaOK() { suite.mock_db.On("ProcessRequest", database.Request{DbName: expectedDBName, DbCollectionName: expectedStream, Op: "meta", ExtraParam: "1"}).Return([]byte(""), nil) logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request meta"))) - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/0/meta" + "/1" + correctTokenSuffix,"GET") + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/0/meta" + "/1" + correctTokenSuffix,"GET") suite.Equal(http.StatusOK, w.Code, "meta OK") } diff --git a/broker/src/asapo_broker/server/listroutes.go b/broker/src/asapo_broker/server/listroutes.go index 8d782f58ec83f4351f898c71d7979be495cdc695..b2d87ccf2d9a1d2f1bad08ba88c567658676c6ef 100644 --- a/broker/src/asapo_broker/server/listroutes.go +++ b/broker/src/asapo_broker/server/listroutes.go @@ -8,73 +8,73 @@ var listRoutes = utils.Routes{ utils.Route{ "GetNext", "Get", - "/database/{dbname}/{datasource}/{stream}/{groupid}/next", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/next", routeGetNext, }, utils.Route{ "GetSize", "Get", - "/database/{dbname}/{datasource}/{stream}/size", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/size", routeGetSize, }, utils.Route{ "GetStreams", "Get", - "/database/{dbname}/{datasource}/{stream}/streams", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/streams", routeGetStreams, }, utils.Route{ "GetLast", "Get", - "/database/{dbname}/{datasource}/{stream}/0/last", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/0/last", routeGetLast, }, utils.Route{ "GetLastAck", "Get", - "/database/{dbname}/{datasource}/{stream}/{groupid}/lastack", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/lastack", routeGetLastAck, }, utils.Route{ "GetNacks", "Get", - "/database/{dbname}/{datasource}/{stream}/{groupid}/nacks", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/nacks", routeGetNacks, }, utils.Route{ "GetID", "Get", - "/database/{dbname}/{datasource}/{stream}/0/{id}", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/0/{id}", routeGetByID, }, utils.Route{ "GetMeta", "Get", - "/database/{dbname}/{datasource}/{stream}/0/meta/{id}", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/0/meta/{id}", routeGetMeta, }, utils.Route{ "CreateGroup", "Post", - "/creategroup", + "/{apiver}/creategroup", routeCreateGroupID, }, utils.Route{ "QueryMessages", "Post", - "/database/{dbname}/{datasource}/{stream}/0/querymessages", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/0/querymessages", routeQueryMessages, }, utils.Route{ "ResetConter", "Post", - "/database/{dbname}/{datasource}/{stream}/{groupid}/resetcounter", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/resetcounter", routeResetCounter, }, utils.Route{ "MessageOp", "Post", - "/database/{dbname}/{datasource}/{stream}/{groupid}/{id}", + "/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/{id}", routeMessageOp, }, utils.Route{ diff --git a/broker/src/asapo_broker/server/post_create_group.go b/broker/src/asapo_broker/server/post_create_group.go index b9cfb51f7d10ef99083ffa9a28ec937efff816da..008e72f14d4bf36022a094c923ab301d7ed2bf36 100644 --- a/broker/src/asapo_broker/server/post_create_group.go +++ b/broker/src/asapo_broker/server/post_create_group.go @@ -7,6 +7,11 @@ import ( ) func routeCreateGroupID(w http.ResponseWriter, r *http.Request) { + if ok := checkBrokerApiVersion(w, r); !ok { + return + } + + guid := xid.New() w.Write([]byte(guid.String())) logger.Debug("generated new group: " + guid.String()) diff --git a/broker/src/asapo_broker/server/post_create_group_test.go b/broker/src/asapo_broker/server/post_create_group_test.go index 5f19da351eedf60bc8992a3b7827982d659be194..46f6fb09edd9241e5f54aad5dc7e89192db03152 100644 --- a/broker/src/asapo_broker/server/post_create_group_test.go +++ b/broker/src/asapo_broker/server/post_create_group_test.go @@ -32,3 +32,8 @@ func TestGetNewGroup(t *testing.T) { logger.UnsetMockLog() } + +func TestGetNewGroupWrongProtocol(t *testing.T) { + w := doRequest("/creategroup", "POST","","/v0.2") + assert.Equal(t, http.StatusUnsupportedMediaType, w.Code, "wrong request") +} diff --git a/broker/src/asapo_broker/server/post_op_image_test.go b/broker/src/asapo_broker/server/post_op_image_test.go index 259787e41bc9fc41140daf8bdfb844c55f3939d2..fc1a2d4e72499983f88da4eab17786ffd95f6871 100644 --- a/broker/src/asapo_broker/server/post_op_image_test.go +++ b/broker/src/asapo_broker/server/post_op_image_test.go @@ -36,19 +36,19 @@ func (suite *MessageOpTestSuite) TestAckMessageOpOK() { query_str := "{\"Id\":1,\"Op\":\"ackmessage\"}" suite.mock_db.On("ProcessRequest", database.Request{DbName: expectedDBName, DbCollectionName: expectedStream, GroupId: expectedGroupID, Op: "ackmessage", ExtraParam: query_str}).Return([]byte(""), nil) logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request ackmessage"))) - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/1" + correctTokenSuffix,"POST",query_str) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/1" + correctTokenSuffix,"POST",query_str) suite.Equal(http.StatusOK, w.Code, "ackmessage OK") } func (suite *MessageOpTestSuite) TestAckMessageOpErrorWrongOp() { query_str := "\"Id\":1,\"Op\":\"ackmessage\"}" - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/1" + correctTokenSuffix,"POST",query_str) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/1" + correctTokenSuffix,"POST",query_str) suite.Equal(http.StatusBadRequest, w.Code, "ackmessage wrong") } func (suite *MessageOpTestSuite) TestAckMessageOpErrorWrongID() { query_str := "{\"Id\":1,\"Op\":\"ackmessage\"}" - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/bla" + correctTokenSuffix,"POST",query_str) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/bla" + correctTokenSuffix,"POST",query_str) suite.Equal(http.StatusBadRequest, w.Code, "ackmessage wrong") } diff --git a/broker/src/asapo_broker/server/post_query_images_test.go b/broker/src/asapo_broker/server/post_query_images_test.go index 0f2b55c1477c4f27747b3b6ce9effccd9c213a2a..16aca9242eebd867c58f90e5860f3bd9c665cca1 100644 --- a/broker/src/asapo_broker/server/post_query_images_test.go +++ b/broker/src/asapo_broker/server/post_query_images_test.go @@ -38,7 +38,7 @@ func (suite *QueryTestSuite) TestQueryOK() { suite.mock_db.On("ProcessRequest", database.Request{DbName: expectedDBName, DbCollectionName: expectedStream,Op: "querymessages", ExtraParam: query_str}).Return([]byte("{}"), nil) logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request querymessages"))) - w := doRequest("/database/"+expectedBeamtimeId+"/"+expectedSource+"/"+expectedStream+"/0/querymessages"+correctTokenSuffix, "POST", query_str) + w := doRequest("/beamtime/"+expectedBeamtimeId+"/"+expectedSource+"/"+expectedStream+"/0/querymessages"+correctTokenSuffix, "POST", query_str) suite.Equal(http.StatusOK, w.Code, "Query OK") } diff --git a/broker/src/asapo_broker/server/post_reset_counter_test.go b/broker/src/asapo_broker/server/post_reset_counter_test.go index 37f70e2725294ac6aee3ae440000cb24374b16a4..10fb4e1b0a360707df952060f633cb99041d1cfc 100644 --- a/broker/src/asapo_broker/server/post_reset_counter_test.go +++ b/broker/src/asapo_broker/server/post_reset_counter_test.go @@ -38,6 +38,6 @@ func (suite *ResetCounterTestSuite) TestResetCounterOK() { logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request resetcounter"))) - w := doRequest("/database/"+expectedBeamtimeId+"/"+expectedSource+"/"+expectedStream+"/"+expectedGroupID+"/resetcounter"+correctTokenSuffix+"&value=10", "POST") + w := doRequest("/beamtime/"+expectedBeamtimeId+"/"+expectedSource+"/"+expectedStream+"/"+expectedGroupID+"/resetcounter"+correctTokenSuffix+"&value=10", "POST") suite.Equal(http.StatusOK, w.Code, "ResetCounter OK") } diff --git a/broker/src/asapo_broker/server/process_request.go b/broker/src/asapo_broker/server/process_request.go index b5b8e7dd602486fc14292c383b77ec52c15fd609..87b6a5075c842d859a9d40b47666f2b81f96cd8f 100644 --- a/broker/src/asapo_broker/server/process_request.go +++ b/broker/src/asapo_broker/server/process_request.go @@ -5,13 +5,14 @@ import ( "asapo_common/logger" log "asapo_common/logger" "asapo_common/utils" + "asapo_common/version" "github.com/gorilla/mux" "net/http" ) func extractRequestParameters(r *http.Request, needGroupID bool) (string, string, string, string, bool) { vars := mux.Vars(r) - db_name, ok1 := vars["dbname"] + db_name, ok1 := vars["beamtime"] datasource, ok3 := vars["datasource"] stream, ok4 := vars["stream"] @@ -49,8 +50,17 @@ func checkGroupID(w http.ResponseWriter, needGroupID bool, group_id string, db_n return false } +func checkBrokerApiVersion(w http.ResponseWriter, r *http.Request) bool { + _, ok := utils.PrecheckApiVersion(w, r, version.GetBrokerApiVersion()) + return ok +} + func processRequest(w http.ResponseWriter, r *http.Request, op string, extra_param string, needGroupID bool) { - r.Header.Set("Content-type", "application/json") + if ok := checkBrokerApiVersion(w, r); !ok { + return + } + + w.Header().Set("Access-Control-Allow-Origin", "*") db_name, datasource, stream, group_id, ok := extractRequestParameters(r, needGroupID) if !ok { diff --git a/broker/src/asapo_broker/server/process_request_test.go b/broker/src/asapo_broker/server/process_request_test.go index f84907035beb7627df65ef55556eec9863ea96cb..5ce3aa70bb26c91c332a0733d11d17c5b64fc1dd 100644 --- a/broker/src/asapo_broker/server/process_request_test.go +++ b/broker/src/asapo_broker/server/process_request_test.go @@ -78,16 +78,20 @@ func doRequest(path string, extra_params ...string) *httptest.ResponseRecorder { if len(extra_params) > 1 { body = strings.NewReader(extra_params[1]) } + ver := "/v0.1" + if len(extra_params) > 2 { + ver = extra_params[2] + } mux := utils.NewRouter(listRoutes) - req, _ := http.NewRequest(m, path, body) + req, _ := http.NewRequest(m, ver+path, body) w := httptest.NewRecorder() mux.ServeHTTP(w, req) return w } func TestProcessRequestWithoutDatabaseName(t *testing.T) { - w := doRequest("/database/next") + w := doRequest("/beamtime/next") assert.Equal(t, http.StatusNotFound, w.Code, "no database name") } @@ -124,7 +128,7 @@ func TestProcessRequestTestSuite(t *testing.T) { func (suite *ProcessRequestTestSuite) TestProcessRequestWithWrongToken() { logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong JWT token"))) - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + suffixWithWrongToken) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + suffixWithWrongToken) suite.Equal(http.StatusUnauthorized, w.Code, "wrong token") } @@ -132,7 +136,7 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestWithWrongToken() { func (suite *ProcessRequestTestSuite) TestProcessRequestWithNoToken() { logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("cannot extract"))) - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + wrongTokenSuffix) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + wrongTokenSuffix) suite.Equal(http.StatusUnauthorized, w.Code, "no token") } @@ -146,7 +150,7 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestWithWrongDatabaseName() logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request next"))) - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix) suite.Equal(http.StatusConflict, w.Code, "wrong database name") } @@ -162,7 +166,7 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestWithConnectionError() { ExpectReconnect(suite.mock_db) logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("reconnected"))) - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix) time.Sleep(time.Second) suite.Equal(http.StatusNotFound, w.Code, "data not found") } @@ -177,7 +181,7 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestWithInternalDBError() { logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("reconnected"))) ExpectReconnect(suite.mock_db) - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix) time.Sleep(time.Second) suite.Equal(http.StatusNotFound, w.Code, "internal error") @@ -191,13 +195,13 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestAddsCounter() { logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request next in "+expectedDBName))) - doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix) + doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix) suite.Equal(1, statistics.GetCounter(), "ProcessRequest increases counter") } func (suite *ProcessRequestTestSuite) TestProcessRequestWrongGroupID() { logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong groupid"))) - w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + wrongGroupID + "/next" + correctTokenSuffix) + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + wrongGroupID + "/next" + correctTokenSuffix) suite.Equal(http.StatusBadRequest, w.Code, "wrong group id") } @@ -208,5 +212,11 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestAddsDataset() { logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request next in "+expectedDBName))) - doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix + "&dataset=true") + doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix + "&dataset=true") +} + + +func (suite *ProcessRequestTestSuite) TestProcessRequestErrorOnWrongProtocol() { + w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix,"GET","","/v0.2") + suite.Equal(http.StatusUnsupportedMediaType, w.Code, "wrong protocol") } diff --git a/broker/src/asapo_broker/server/server.go b/broker/src/asapo_broker/server/server.go index c69d58e578ba85eeee96e31836cb5db26b533aab..1537fa08642c36454b679b54e218d5ad5b6f4007 100644 --- a/broker/src/asapo_broker/server/server.go +++ b/broker/src/asapo_broker/server/server.go @@ -18,6 +18,7 @@ type serverSettings struct { DatabaseServer string PerformanceDbServer string PerformanceDbName string + MonitorPerformance bool AuthorizationServer string Port int LogLevel string diff --git a/broker/src/asapo_broker/server/server_nottested.go b/broker/src/asapo_broker/server/server_nottested.go index 3f7cb0a746949205697741387c8e28e1d1402b61..ae96af4d5a957f7bc5529ad0f78510a648cdabd0 100644 --- a/broker/src/asapo_broker/server/server_nottested.go +++ b/broker/src/asapo_broker/server/server_nottested.go @@ -18,7 +18,9 @@ func StartStatistics() { } func Start() { - StartStatistics() + if settings.MonitorPerformance { + StartStatistics() + } mux := utils.NewRouter(listRoutes) log.Info("Listening on port: " + strconv.Itoa(settings.Port)) log.Fatal(http.ListenAndServe(":"+strconv.Itoa(settings.Port), http.HandlerFunc(mux.ServeHTTP))) diff --git a/broker/src/asapo_broker/server/statistics_nottested.go b/broker/src/asapo_broker/server/statistics_nottested.go index c2728623d93b161305d5f9285cea9af751350466..3b6d3ee4b65a2c55957ed253cc473a36b91648e8 100644 --- a/broker/src/asapo_broker/server/statistics_nottested.go +++ b/broker/src/asapo_broker/server/statistics_nottested.go @@ -9,7 +9,7 @@ import ( func (st *serverStatistics) Monitor() { for { - time.Sleep(1000 * time.Millisecond) + time.Sleep(10000 * time.Millisecond) if err := st.WriteStatistic(); err != nil { logstr := "sending statistics to " + settings.PerformanceDbServer + ", dbname: " + settings.PerformanceDbName log.Error(logstr + " - " + err.Error()) diff --git a/common/cpp/CMakeLists.txt b/common/cpp/CMakeLists.txt index f59ad1bcf8f18acae4dc8da02ccd73eb654cb55d..8f90ff257a0db963ffc133518e2768c020975fc7 100644 --- a/common/cpp/CMakeLists.txt +++ b/common/cpp/CMakeLists.txt @@ -6,6 +6,9 @@ add_subdirectory(src/json_parser) add_subdirectory(src/data_structs) +add_subdirectory(src/version) + + add_subdirectory(src/http_client) add_subdirectory(src/logger) @@ -20,7 +23,8 @@ endif() install(DIRECTORY ${ASAPO_CXX_COMMON_INCLUDE_DIR}/asapo/common DESTINATION include/asapo - PATTERN "*.h.in" EXCLUDE) + PATTERN "*.h.in" EXCLUDE + PATTERN "*/internal" EXCLUDE) install(DIRECTORY ${ASAPO_CXX_COMMON_INCLUDE_DIR}/asapo/logger DESTINATION include/asapo ) diff --git a/common/cpp/include/asapo/common/data_structs.h b/common/cpp/include/asapo/common/data_structs.h index f95aea6a769c64948132d88855735573f79e9ba8..96cdaf8c81ef046c05d7699d6e90004a947d149c 100644 --- a/common/cpp/include/asapo/common/data_structs.h +++ b/common/cpp/include/asapo/common/data_structs.h @@ -14,51 +14,49 @@ namespace asapo { const std::string kFinishStreamKeyword = "asapo_finish_stream"; const std::string kNoNextStreamKeyword = "asapo_no_next"; - class JsonStringParser; uint64_t NanosecsEpochFromTimePoint(std::chrono::system_clock::time_point); -uint64_t EpochNanosecsFromNow(); +uint64_t EpochNanosecsFromNow(); std::chrono::system_clock::time_point TimePointfromNanosec(uint64_t nanoseconds_from_epoch); std::string IsoDateFromEpochNanosecs(uint64_t time_from_epoch_nanosec); uint64_t NanosecsEpochFromISODate(std::string date_time); -bool TimeFromJson(const JsonStringParser& parser, const std::string& name, std::chrono::system_clock::time_point* val); +bool TimeFromJson(const JsonStringParser &parser, const std::string &name, std::chrono::system_clock::time_point* val); class MessageMeta { - public: - std::string name; - std::chrono::system_clock::time_point timestamp; - uint64_t size{0}; - uint64_t id{0}; - std::string source; - std::string metadata; - uint64_t buf_id{0}; - uint64_t dataset_substream{0}; - std::string Json() const; - bool SetFromJson(const std::string& json_string); - std::string FullName(const std::string& base_path) const; + public: + std::string name; + std::chrono::system_clock::time_point timestamp; + uint64_t size{0}; + uint64_t id{0}; + std::string source; + std::string metadata; + uint64_t buf_id{0}; + uint64_t dataset_substream{0}; + std::string Json() const; + bool SetFromJson(const std::string &json_string); + std::string FullName(const std::string &base_path) const; }; - struct StreamInfo { - uint64_t last_id{0}; - std::string name; - bool finished{false}; - std::string next_stream; - std::chrono::system_clock::time_point timestamp_created; - std::chrono::system_clock::time_point timestamp_lastentry; - std::string Json() const; - bool SetFromJson(const std::string &json_string); + uint64_t last_id{0}; + std::string name; + bool finished{false}; + std::string next_stream; + std::chrono::system_clock::time_point timestamp_created; + std::chrono::system_clock::time_point timestamp_lastentry; + std::string Json() const; + bool SetFromJson(const std::string &json_string); }; using StreamInfos = std::vector<StreamInfo>; -inline bool operator==(const MessageMeta& lhs, const MessageMeta& rhs) { - return (lhs.name == rhs.name && - lhs.id == rhs.id && - lhs.timestamp == rhs.timestamp && - lhs.size == rhs.size); +inline bool operator==(const MessageMeta &lhs, const MessageMeta &rhs) { + return (lhs.name == rhs.name && + lhs.id == rhs.id && + lhs.timestamp == rhs.timestamp && + lhs.size == rhs.size); } using MessageData = std::unique_ptr<uint8_t[]>; @@ -69,10 +67,10 @@ using MessageMetas = std::vector<MessageMeta>; using IdList = std::vector<uint64_t>; struct DataSet { - uint64_t id; - uint64_t expected_size; - MessageMetas content; - bool SetFromJson(const std::string& json_string); + uint64_t id; + uint64_t expected_size; + MessageMetas content; + bool SetFromJson(const std::string &json_string); }; using SubDirList = std::vector<std::string>; @@ -82,38 +80,122 @@ enum class SourceType { kRaw }; -Error GetSourceTypeFromString(std::string stype,SourceType *type); +Error GetSourceTypeFromString(std::string stype, SourceType* type); std::string GetStringFromSourceType(SourceType type); struct SourceCredentials { - SourceCredentials(SourceType type, std::string beamtime, std::string beamline, std::string data_source, std::string token): - beamtime_id{std::move(beamtime)}, - beamline{std::move(beamline)}, - data_source{std::move(data_source)}, - user_token{std::move(token)}, - type{type}{}; - SourceCredentials() {}; - static const std::string kDefaultStream; - static const std::string kDefaultBeamline; - static const std::string kDefaultBeamtimeId; - std::string beamtime_id; - std::string beamline; - std::string data_source; - std::string user_token; - SourceType type = SourceType::kProcessed; - std::string GetString() { - return (type==SourceType::kRaw?std::string("raw"):std::string("processed")) + "%"+ beamtime_id + "%" + beamline + "%" + data_source + "%" + user_token; - }; + SourceCredentials(SourceType type, + std::string beamtime, + std::string beamline, + std::string data_source, + std::string token) : + beamtime_id{std::move(beamtime)}, + beamline{std::move(beamline)}, + data_source{std::move(data_source)}, + user_token{std::move(token)}, + type{type} {}; + SourceCredentials() {}; + static const std::string kDefaultStream; + static const std::string kDefaultBeamline; + static const std::string kDefaultBeamtimeId; + std::string beamtime_id; + std::string beamline; + std::string data_source; + std::string user_token; + SourceType type = SourceType::kProcessed; + std::string GetString() { + return (type == SourceType::kRaw ? std::string("raw") : std::string("processed")) + "%" + beamtime_id + "%" + + beamline + "%" + data_source + "%" + user_token; + }; }; enum IngestModeFlags : uint64_t { - kTransferData = 1 << 0, - kTransferMetaDataOnly = 1 << 1, - kStoreInFilesystem = 1 << 2, - kStoreInDatabase = 1 << 3, + kTransferData = 1 << 0, + kTransferMetaDataOnly = 1 << 1, + kStoreInFilesystem = 1 << 2, + kStoreInDatabase = 1 << 3, }; const uint64_t kDefaultIngestMode = kTransferData | kStoreInFilesystem | kStoreInDatabase; +class ClientProtocol { + private: + std::string version_; + std::string discovery_version_; + std::string name_; + public: + ClientProtocol(std::string version, std::string name,std::string discovery_version) : version_{version}, name_{name} { + discovery_version_ = discovery_version; + }; + ClientProtocol() = delete; + virtual std::string GetString() = 0; + const std::string &GetVersion() const { + return version_; + } + const std::string &GetDiscoveryVersion() const { + return discovery_version_; + } + const std::string &GetName() const { + return name_; + } +}; + +class ConsumerProtocol final : public ClientProtocol { + private: + std::string authorizer_version_; + std::string file_transfer_service_version_; + std::string broker_version_; + std::string rds_version_; + public: + ConsumerProtocol(std::string version, + std::string discovery_version, + std::string authorizer_version, + std::string file_transfer_service_version, + std::string broker_version, + std::string rds_version) + : ClientProtocol(version, "consumer protocol",discovery_version) { + authorizer_version_ = authorizer_version; + file_transfer_service_version_ = file_transfer_service_version; + broker_version_ = broker_version; + rds_version_ = rds_version; + } + const std::string &GetAuthorizerVersion() const { + return authorizer_version_; + } + const std::string &GetFileTransferServiceVersion() const { + return file_transfer_service_version_; + } + const std::string &GetRdsVersion() const { + return rds_version_; + } + const std::string &GetBrokerVersion() const { + return broker_version_; + }; + ConsumerProtocol() = delete; + std::string GetString() override { + return std::string(); + } +}; + +class ProducerProtocol final : public ClientProtocol { + private: + std::string receiver_version_; + public: + ProducerProtocol(std::string version, + std::string discovery_version, + std::string receiver_version) + : ClientProtocol(version, "producer protocol",discovery_version) { + receiver_version_ = receiver_version; + }; + const std::string &GetReceiverVersion() const { + return receiver_version_; + } + ProducerProtocol() = delete; + std::string GetString() override { + return std::string(); + } +}; + } + #endif //ASAPO_message_meta_H diff --git a/common/cpp/include/asapo/common/internal/version.h.in b/common/cpp/include/asapo/common/internal/version.h.in new file mode 100644 index 0000000000000000000000000000000000000000..79fcea4136e61555e17ee7fc03f5d14d7f66a54a --- /dev/null +++ b/common/cpp/include/asapo/common/internal/version.h.in @@ -0,0 +1,45 @@ +#ifndef ASAPO_VERSION_H +#define ASAPO_VERSION_H + +#include <iostream> +#include "string.h" + +#include "asapo/common/data_structs.h" +#include "asapo/common/error.h" +#include "asapo/http_client/http_client.h" + +namespace asapo { + + +const char kVersion[] = "@ASAPO_VERSION@@ASAPO_VERSION_COMMIT@"; + +inline void ExitAfterPrintVersionIfNeeded(std::string prefix,int argc, char* argv[]) { + if (argc == 2 && strcmp(argv[1], "-v") == 0) { + std::cout << prefix << ", version " << kVersion << std::endl; + exit(0); + } +} + +const ConsumerProtocol kConsumerProtocol{"@ASAPO_CONSUMER_PROTOCOL@","@ASAPO_DISCOVERY_API_VER@", + "@ASAPO_AUTHORIZER_API_VER@","@ASAPO_FILE_TRANSFER_SERVICE_API_VER@","@ASAPO_BROKER_API_VER@","@ASAPO_RDS_API_VER@"}; +const ProducerProtocol kProducerProtocol{"@ASAPO_PRODUCER_PROTOCOL@","@ASAPO_DISCOVERY_API_VER@", "@ASAPO_RECEIVER_API_VER@"}; + +inline std::string GetReceiverApiVersion() { + return "@ASAPO_RECEIVER_API_VER@"; +} + +inline std::string GetRdsApiVersion() { + return "@ASAPO_RDS_API_VER@"; +} + +inline int VersionToNumber(const std::string& version) { + return int(atof(version.c_str()+2)*1000); +} + +Error ExtractVersionFromResponse(const std::string &response, + const std::string &client, + std::string* server_info, + bool* supported); +} + +#endif //ASAPO_VERSION_H diff --git a/common/cpp/include/asapo/common/networking.h b/common/cpp/include/asapo/common/networking.h index bd7f5379f302f0fbd05e423b270495e699958bb0..79f29abb4cefe2095cb06859f11611d0b229d142 100644 --- a/common/cpp/include/asapo/common/networking.h +++ b/common/cpp/include/asapo/common/networking.h @@ -36,6 +36,7 @@ enum NetworkErrorCode : uint16_t { kNetErrorReauthorize, kNetErrorWarning, kNetErrorWrongRequest, + kNetErrorNotSupported, kNetErrorNoData, kNetAuthorizationError, kNetErrorInternalServerError = 65535, @@ -44,6 +45,7 @@ enum NetworkErrorCode : uint16_t { //TODO need to use an serialization framework to ensure struct consistency on different computers const std::size_t kMaxMessageSize = 1024; +const std::size_t kMaxVersionSize = 10; const std::size_t kNCustomParams = 3; using CustomRequestData = uint64_t[kNCustomParams]; const std::size_t kPosIngestMode = 0; @@ -56,6 +58,7 @@ struct GenericRequestHeader { memcpy(custom_data, header.custom_data, kNCustomParams * sizeof(uint64_t)), memcpy(message, header.message, kMaxMessageSize); strncpy(stream, header.stream, kMaxMessageSize); + strncpy(api_version, header.api_version, kMaxVersionSize); } /* Keep in mind that the message here is just strncpy'ed, you can change the message later */ @@ -65,6 +68,7 @@ struct GenericRequestHeader { op_code{i_op_code}, data_id{i_data_id}, data_size{i_data_size}, meta_size{i_meta_size} { strncpy(message, i_message.c_str(), kMaxMessageSize); strncpy(stream, i_stream.c_str(), kMaxMessageSize); + strncpy(api_version,"v0.0", kMaxVersionSize); } Opcode op_code; @@ -74,6 +78,7 @@ struct GenericRequestHeader { CustomRequestData custom_data; char message[kMaxMessageSize]; /* Can also be a binary message (e.g. MemoryRegionDetails) */ char stream[kMaxMessageSize]; /* Must be a string (strcpy is used) */ + char api_version[kMaxVersionSize]; /* Must be a string (strcpy is used) */ std::string Json() { std::string s = "{\"id\":" + std::to_string(data_id) + "," "\"buffer\":\"" + std::string(message) + "\"" + "," @@ -81,7 +86,6 @@ struct GenericRequestHeader { + "}"; return s; }; - }; diff --git a/common/cpp/include/asapo/common/version.h.in b/common/cpp/include/asapo/common/version.h.in deleted file mode 100644 index cfb735d837ece16c9a92c11dc09900390a1b4e3e..0000000000000000000000000000000000000000 --- a/common/cpp/include/asapo/common/version.h.in +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ASAPO_VERSION_H -#define ASAPO_VERSION_H - -#include <iostream> -#include "string.h" - -namespace asapo { - -const char kVersion[] = "@ASAPO_VERSION@@ASAPO_VERSION_COMMIT@"; - -inline void ExitAfterPrintVersionIfNeeded(std::string prefix,int argc, char* argv[]) { - if (argc == 2 && strcmp(argv[1], "-v") == 0) { - std::cout << prefix << ", version " << kVersion << std::endl; - exit(0); - } -} - -} - - -#endif //ASAPO_VERSION_H diff --git a/common/cpp/src/version/CMakeLists.txt b/common/cpp/src/version/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..71abb5416d246fb255410e132556e4f43f5c5b7b --- /dev/null +++ b/common/cpp/src/version/CMakeLists.txt @@ -0,0 +1,12 @@ +set(TARGET_NAME version) +set(SOURCE_FILES + version.cpp +) + +################################ +# Library +################################ + +add_library(${TARGET_NAME} OBJECT ${SOURCE_FILES}) +target_include_directories(${TARGET_NAME} PUBLIC ${ASAPO_CXX_COMMON_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/3d_party/rapidjson/include) diff --git a/common/cpp/src/version/version.cpp b/common/cpp/src/version/version.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57600be0ceb58b7e3515959b643194018d573310 --- /dev/null +++ b/common/cpp/src/version/version.cpp @@ -0,0 +1,28 @@ +#include "asapo/common/internal/version.h" +#include "asapo/json_parser/json_parser.h" + +namespace asapo { + +Error ExtractVersionFromResponse(const std::string &response, + const std::string &client, + std::string* server_info, + bool* supported) { + JsonStringParser parser(response); + std::string server_version, current_client_protocol, client_supported; + Error err; + if ((err = parser.GetString("softwareVersion", &server_version)) + || (err = parser.GetString("clientSupported", &client_supported)) + || (err = parser.Embedded("clientProtocol").GetString("versionInfo", ¤t_client_protocol))) { + return err; + } + if (server_info) { + *server_info = + "Server version: " + server_version + ", " + client + " protocol on server: " + current_client_protocol; + } + if (supported) { + *supported = client_supported == "yes"; + } + return nullptr; +} + +} \ No newline at end of file diff --git a/common/go/src/asapo_common/utils/http.go b/common/go/src/asapo_common/utils/http.go index 4e6f9736e6ff015ba66a5b56a6b32b9e3a1e4982..4a6ce7daef8084c202bebc439676e4fee071665b 100644 --- a/common/go/src/asapo_common/utils/http.go +++ b/common/go/src/asapo_common/utils/http.go @@ -10,7 +10,8 @@ func ExtractRequest(r *http.Request, request interface{}) error { return decoder.Decode(request) } -func WriteServerError(w http.ResponseWriter, err error,code int) { +func WriteServerError(w http.ResponseWriter, err error, code int) { w.WriteHeader(code) w.Write([]byte(err.Error())) -} \ No newline at end of file +} + diff --git a/common/go/src/asapo_common/utils/version.go b/common/go/src/asapo_common/utils/version.go new file mode 100644 index 0000000000000000000000000000000000000000..5e8e03a9dff6ade41f5df8bf421d03bc2ff91987 --- /dev/null +++ b/common/go/src/asapo_common/utils/version.go @@ -0,0 +1,46 @@ +package utils + +import ( + "errors" + "github.com/gorilla/mux" + "net/http" + "strconv" + "strings" +) + + +func VersionToNumber(ver string) int { + ver = strings.TrimPrefix(ver,"v") + floatNum, err := strconv.ParseFloat(ver, 64) + if err!=nil { + return 0 + } + return int(floatNum*1000) +} + + +func ExtractVersion(r *http.Request) (int, error) { + vars := mux.Vars(r) + ver_str, ok := vars["apiver"] + if !ok { + return 0, errors.New("cannot extract version") + } + ver := VersionToNumber(ver_str) + if ver == 0 { + return 0, errors.New("cannot extract version") + } + return ver, nil +} + +func PrecheckApiVersion(w http.ResponseWriter, r *http.Request, currentVersion string) (apiVer int, ok bool) { + apiVer, err := ExtractVersion(r) + if err != nil { + WriteServerError(w, err, http.StatusBadRequest) + return 0, false + } + if apiVer > VersionToNumber(currentVersion) { + WriteServerError(w, errors.New("version not supported"), http.StatusUnsupportedMediaType) + return 0, false + } + return apiVer, true +} diff --git a/common/go/src/asapo_common/version/version.go b/common/go/src/asapo_common/version/version.go index d4674f37bddf4e84eaaec6cde2686ed6e68f306a..769bb508f97920842e834725840f056ff6342263 100644 --- a/common/go/src/asapo_common/version/version.go +++ b/common/go/src/asapo_common/version/version.go @@ -8,6 +8,35 @@ import ( var version string +var consumerProtocolVersion string +var producerProtocolVersion string +var discoveryApiVersion string +var authorizerApiVersion string +var ftsApiVersion string +var brokerApiVersion string + +func GetDiscoveryApiVersion() string { + return discoveryApiVersion +} +func GetAuthorizerApiVersion() string { + return authorizerApiVersion +} +func GetFtsApiVersion() string { + return ftsApiVersion +} +func GetBrokerApiVersion() string { + return brokerApiVersion +} + +func GetProducerProtocolVersion() string { + return producerProtocolVersion +} + +func GetConsumerProtocolVersion() string { + return consumerProtocolVersion +} + + func GetVersion() string { return version } diff --git a/common/go/src/asapo_common/version/version_lib.go.in b/common/go/src/asapo_common/version/version_lib.go.in index 5fc343fe161f109a008ddad671ee7ba3eabd14d1..a276d7babb1542811c6444c7c49c54de33e14474 100644 --- a/common/go/src/asapo_common/version/version_lib.go.in +++ b/common/go/src/asapo_common/version/version_lib.go.in @@ -4,4 +4,10 @@ package version // This file is overridden on build with build-time informations. func init(){ version = "@ASAPO_VERSION@@ASAPO_VERSION_COMMIT@" + consumerProtocolVersion = "@ASAPO_CONSUMER_PROTOCOL@" + producerProtocolVersion = "@ASAPO_PRODUCER_PROTOCOL@" + discoveryApiVersion = "@ASAPO_DISCOVERY_API_VER@" + authorizerApiVersion = "@ASAPO_AUTHORIZER_API_VER@" + ftsApiVersion = "@ASAPO_FILE_TRANSFER_SERVICE_API_VER@" + brokerApiVersion = "@ASAPO_BROKER_API_VER@" } diff --git a/config/nomad/discovery.nmd.in b/config/nomad/discovery.nmd.in index 760aed3c700405ec289b47de69c0dd37c4ba4730..e3c36befc01f51fcbd7478342fe6fb6006d7b916 100644 --- a/config/nomad/discovery.nmd.in +++ b/config/nomad/discovery.nmd.in @@ -30,7 +30,7 @@ job "discovery" { check { name = "alive" type = "http" - path = "/asapo-receiver" + path = "/health" interval = "10s" timeout = "2s" initial_status = "passing" diff --git a/consumer/api/cpp/CMakeLists.txt b/consumer/api/cpp/CMakeLists.txt index 24661f0da20047c86732a811b657cf9f8d5e24ee..47d30a20f9a39dd6f83f070f39d6ac67e838fa68 100644 --- a/consumer/api/cpp/CMakeLists.txt +++ b/consumer/api/cpp/CMakeLists.txt @@ -12,7 +12,7 @@ set(SOURCE_FILES # Library ################################ add_library(${TARGET_NAME} STATIC ${SOURCE_FILES} $<TARGET_OBJECTS:system_io> - $<TARGET_OBJECTS:json_parser> $<TARGET_OBJECTS:data_structs> $<TARGET_OBJECTS:curl_http_client> ) + $<TARGET_OBJECTS:json_parser> $<TARGET_OBJECTS:data_structs> $<TARGET_OBJECTS:version> $<TARGET_OBJECTS:curl_http_client> ) target_include_directories(${TARGET_NAME} PUBLIC include ${ASAPO_CXX_COMMON_INCLUDE_DIR} ${LIBFABRIC_INCLUDE_DIR} ${CURL_INCLUDE_DIRS}) diff --git a/consumer/api/cpp/include/asapo/asapo_consumer.h b/consumer/api/cpp/include/asapo/asapo_consumer.h index e9dee4e9b5ebe0b003680e268eae48b32e91a32b..176d1d56269f35053b1fe8285a84352f6b72d487 100644 --- a/consumer/api/cpp/include/asapo/asapo_consumer.h +++ b/consumer/api/cpp/include/asapo/asapo_consumer.h @@ -3,7 +3,6 @@ #include "asapo/consumer/consumer.h" #include "asapo/consumer/consumer_error.h" -#include "asapo/common/version.h" #include <ostream> #endif //ASAPO_ASAPO_CONSUMER_H diff --git a/consumer/api/cpp/include/asapo/consumer/consumer.h b/consumer/api/cpp/include/asapo/consumer/consumer.h index 2cd1d71b678dcb22554489f9f9bf4428f970f64e..dba769567f4fec4dbd39de384f50f79205a024bc 100644 --- a/consumer/api/cpp/include/asapo/consumer/consumer.h +++ b/consumer/api/cpp/include/asapo/consumer/consumer.h @@ -27,6 +27,14 @@ class Consumer { \return nullptr of command was successful, otherwise error. */ virtual Error ResetLastReadMarker(std::string group_id, std::string stream) = 0; + //! Return version + /*! + \param client_info - for client version + \param server_info - for server + \param supported - set to true if client is supported by server + \return nullptr of command was successful, otherwise error. + */ + virtual Error GetVersionInfo(std::string* client_info,std::string* server_info, bool* supported) = 0; virtual Error SetLastReadMarker(std::string group_id, uint64_t value, std::string stream) = 0; diff --git a/consumer/api/cpp/include/asapo/consumer/consumer_error.h b/consumer/api/cpp/include/asapo/consumer/consumer_error.h index 7f3990d226fbcc3f663e367992496cc07e0fa3f7..38e5329d8f4aad6fdd98e25a85aae6d609c8cb04 100644 --- a/consumer/api/cpp/include/asapo/consumer/consumer_error.h +++ b/consumer/api/cpp/include/asapo/consumer/consumer_error.h @@ -14,7 +14,8 @@ enum class ConsumerErrorType { kInterruptedTransaction, kLocalIOError, kWrongInput, - kPartialData + kPartialData, + kUnsupportedClient }; using ConsumerErrorTemplate = ServiceErrorTemplate<ConsumerErrorType, ErrorType::kConsumerError>; @@ -63,6 +64,11 @@ auto const kWrongInput = ConsumerErrorTemplate { "wrong input", ConsumerErrorType::kWrongInput }; +auto const kUnsupportedClient = ConsumerErrorTemplate { + "unsupported client version", ConsumerErrorType::kUnsupportedClient +}; + + auto const kInterruptedTransaction = ConsumerErrorTemplate { "server error", ConsumerErrorType::kInterruptedTransaction }; diff --git a/consumer/api/cpp/src/consumer_impl.cpp b/consumer/api/cpp/src/consumer_impl.cpp index 84a8fe6c9627970a204629e683ffdabbe2790e0a..7d3d565e5db6a80a6382e31b6c39adaf7d9f504c 100644 --- a/consumer/api/cpp/src/consumer_impl.cpp +++ b/consumer/api/cpp/src/consumer_impl.cpp @@ -12,6 +12,8 @@ #include "fabric_consumer_client.h" #include "rds_response_error.h" +#include "asapo/common/internal/version.h" + using std::chrono::system_clock; namespace asapo { @@ -32,7 +34,7 @@ Error GetNoDataResponseFromJson(const std::string &json_string, ConsumerErrorDat Error GetPartialDataResponseFromJson(const std::string &json_string, PartialErrorData* data) { Error err; auto parser = JsonStringParser(json_string); - uint64_t id,size; + uint64_t id, size; if ((err = parser.GetUInt64("size", &size)) || (err = parser.GetUInt64("_id", &id))) { return err; @@ -84,6 +86,7 @@ Error ConsumerErrorFromHttpCode(const RequestOutput* response, const HttpCode &c case HttpCode::InternalServerError:return ConsumerErrorTemplates::kInterruptedTransaction.Generate(response->to_string()); case HttpCode::NotFound:return ConsumerErrorTemplates::kUnavailableService.Generate(response->to_string()); case HttpCode::Conflict:return ConsumerErrorFromNoDataResponse(response->to_string()); + case HttpCode::UnsupportedMediaType:return ConsumerErrorTemplates::kUnsupportedClient.Generate(response->to_string()); default:return ConsumerErrorTemplates::kInterruptedTransaction.Generate(response->to_string()); } } @@ -178,19 +181,20 @@ Error ConsumerImpl::ProcessRequest(RequestOutput* response, const RequestInfo &r return ProcessRequestResponce(err, response, code); } -Error ConsumerImpl::DiscoverService(const std::string &service_name, std::string* uri_to_set) { - if (!uri_to_set->empty()) { - return nullptr; - } +RequestInfo ConsumerImpl::GetDiscoveryRequest(const std::string &service_name) const { RequestInfo ri; ri.host = endpoint_; - ri.api = "/asapo-discovery/" + service_name; - RequestOutput output; - Error err; - err = ProcessRequest(&output, ri, nullptr); - *uri_to_set = std::move(output.string_output); + ri.api = "/asapo-discovery/" + kConsumerProtocol.GetDiscoveryVersion() + "/" + service_name; + ri.extra_params = "&protocol=" + kConsumerProtocol.GetVersion(); + return ri; +} + +Error ConsumerImpl::ProcessDiscoverServiceResult(Error err, std::string* uri_to_set) { if (err != nullptr || uri_to_set->empty()) { uri_to_set->clear(); + if (err == ConsumerErrorTemplates::kUnsupportedClient) { + return err; + } return ConsumerErrorTemplates::kUnavailableService.Generate(" on " + endpoint_ + (err != nullptr ? ": " + err->Explain() : "")); @@ -198,6 +202,17 @@ Error ConsumerImpl::DiscoverService(const std::string &service_name, std::string return nullptr; } +Error ConsumerImpl::DiscoverService(const std::string &service_name, std::string* uri_to_set) { + if (!uri_to_set->empty()) { + return nullptr; + } + auto ri = GetDiscoveryRequest(service_name); + RequestOutput output; + auto err = ProcessRequest(&output, ri, nullptr); + *uri_to_set = std::move(output.string_output); + return ProcessDiscoverServiceResult(std::move(err), uri_to_set); +} + bool ConsumerImpl::SwitchToGetByIdIfPartialData(Error* err, const std::string &response, std::string* group_id, @@ -215,7 +230,10 @@ bool ConsumerImpl::SwitchToGetByIdIfPartialData(Error* err, return false; } -bool ConsumerImpl::SwitchToGetByIdIfNoData(Error* err, const std::string &response, std::string* group_id, std::string* redirect_uri) { +bool ConsumerImpl::SwitchToGetByIdIfNoData(Error* err, + const std::string &response, + std::string* group_id, + std::string* redirect_uri) { if (*err == ConsumerErrorTemplates::kNoData) { auto error_data = static_cast<const ConsumerErrorData*>((*err)->GetCustomData()); if (error_data == nullptr) { @@ -235,7 +253,7 @@ RequestInfo ConsumerImpl::PrepareRequestInfo(std::string api_url, bool dataset, ri.api = std::move(api_url); if (dataset) { ri.extra_params = "&dataset=true"; - ri.extra_params += "&minsize="+std::to_string(min_size); + ri.extra_params += "&minsize=" + std::to_string(min_size); } return ri; } @@ -248,10 +266,12 @@ Error ConsumerImpl::GetRecordFromServer(std::string* response, std::string group return ConsumerErrorTemplates::kWrongInput.Generate("empty stream"); } - interrupt_flag_= false; + interrupt_flag_ = false; std::string request_suffix = OpToUriCmd(op); std::string request_group = OpToUriCmd(op); - std::string request_api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + std::string + request_api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + "/" + std::move(stream); uint64_t elapsed_ms = 0; Error no_data_error; @@ -301,20 +321,20 @@ Error ConsumerImpl::GetRecordFromServer(std::string* response, std::string group Error ConsumerImpl::GetNext(std::string group_id, MessageMeta* info, MessageData* data, std::string stream) { return GetMessageFromServer(GetMessageServerOperation::GetNext, - 0, - std::move(group_id), - std::move(stream), - info, - data); + 0, + std::move(group_id), + std::move(stream), + info, + data); } Error ConsumerImpl::GetLast(MessageMeta* info, MessageData* data, std::string stream) { return GetMessageFromServer(GetMessageServerOperation::GetLast, - 0, - "0", - std::move(stream), - info, - data); + 0, + "0", + std::move(stream), + info, + data); } std::string ConsumerImpl::OpToUriCmd(GetMessageServerOperation op) { @@ -326,9 +346,9 @@ std::string ConsumerImpl::OpToUriCmd(GetMessageServerOperation op) { } Error ConsumerImpl::GetMessageFromServer(GetMessageServerOperation op, uint64_t id, std::string group_id, - std::string stream, - MessageMeta* info, - MessageData* data) { + std::string stream, + MessageMeta* info, + MessageData* data) { if (info == nullptr) { return ConsumerErrorTemplates::kWrongInput.Generate(); } @@ -437,7 +457,7 @@ Error ConsumerImpl::TryGetDataFromBuffer(const MessageMeta* info, MessageData* d std::string ConsumerImpl::GenerateNewGroupId(Error* err) { RequestInfo ri; - ri.api = "/creategroup"; + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/creategroup"; ri.post = true; return BrokerRequestWithTimeout(ri, err); } @@ -446,7 +466,7 @@ Error ConsumerImpl::ServiceRequestWithTimeout(const std::string &service_name, std::string* service_uri, RequestInfo request, RequestOutput* response) { - interrupt_flag_= false; + interrupt_flag_ = false; uint64_t elapsed_ms = 0; Error err; while (elapsed_ms <= timeout_ms_) { @@ -498,7 +518,7 @@ Error ConsumerImpl::FtsRequestWithTimeout(MessageMeta* info, MessageData* data) RequestInfo ConsumerImpl::CreateFileTransferRequest(const MessageMeta* info) const { RequestInfo ri; - ri.api = "/transfer"; + ri.api = "/" + kConsumerProtocol.GetFileTransferServiceVersion() + "/transfer"; ri.post = true; ri.body = "{\"Folder\":\"" + source_path_ + "\",\"FileName\":\"" + info->name + "\"}"; ri.cookie = "Authorization=Bearer " + folder_token_; @@ -518,7 +538,8 @@ Error ConsumerImpl::ResetLastReadMarker(std::string group_id, std::string stream Error ConsumerImpl::SetLastReadMarker(std::string group_id, uint64_t value, std::string stream) { RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + "/" + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + "/" + std::move(stream) + "/" + std::move(group_id) + "/resetcounter"; ri.extra_params = "&value=" + std::to_string(value); ri.post = true; @@ -530,7 +551,7 @@ Error ConsumerImpl::SetLastReadMarker(std::string group_id, uint64_t value, std: uint64_t ConsumerImpl::GetCurrentSize(std::string stream, Error* err) { auto ri = GetSizeRequestForSingleMessagesStream(stream); - return GetCurrentCount(stream,ri,err); + return GetCurrentCount(stream, ri, err); } Error ConsumerImpl::GetById(uint64_t id, MessageMeta* info, MessageData* data, std::string stream) { @@ -548,13 +569,14 @@ Error ConsumerImpl::GetRecordFromServerById(uint64_t id, std::string* response, } RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + +"/" + std::move(stream) + "/" + std::move( group_id) + "/" + std::to_string(id); if (dataset) { ri.extra_params += "&dataset=true"; - ri.extra_params += "&minsize="+std::to_string(min_size); + ri.extra_params += "&minsize=" + std::to_string(min_size); } Error err; @@ -564,7 +586,9 @@ Error ConsumerImpl::GetRecordFromServerById(uint64_t id, std::string* response, std::string ConsumerImpl::GetBeamtimeMeta(Error* err) { RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + "/default/0/meta/0"; + ri.api = + "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + "/default/0/meta/0"; return BrokerRequestWithTimeout(ri, err); } @@ -573,7 +597,7 @@ DataSet DecodeDatasetFromResponse(std::string response, Error* err) { DataSet res; if (!res.SetFromJson(std::move(response))) { *err = ConsumerErrorTemplates::kInterruptedTransaction.Generate("malformed response:" + response); - return {0,0,MessageMetas{}}; + return {0, 0, MessageMetas{}}; } else { return res; } @@ -586,7 +610,8 @@ MessageMetas ConsumerImpl::QueryMessages(std::string query, std::string stream, } RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + "/" + std::move(stream) + "/0/querymessages"; ri.post = true; ri.body = std::move(query); @@ -601,11 +626,16 @@ MessageMetas ConsumerImpl::QueryMessages(std::string query, std::string stream, } DataSet ConsumerImpl::GetNextDataset(std::string group_id, uint64_t min_size, std::string stream, Error* err) { - return GetDatasetFromServer(GetMessageServerOperation::GetNext, 0, std::move(group_id), std::move(stream),min_size, err); + return GetDatasetFromServer(GetMessageServerOperation::GetNext, + 0, + std::move(group_id), + std::move(stream), + min_size, + err); } DataSet ConsumerImpl::GetLastDataset(uint64_t min_size, std::string stream, Error* err) { - return GetDatasetFromServer(GetMessageServerOperation::GetLast, 0, "0", std::move(stream),min_size, err); + return GetDatasetFromServer(GetMessageServerOperation::GetLast, 0, "0", std::move(stream), min_size, err); } DataSet ConsumerImpl::GetDatasetFromServer(GetMessageServerOperation op, @@ -620,15 +650,15 @@ DataSet ConsumerImpl::GetDatasetFromServer(GetMessageServerOperation op, } else { *err = GetRecordFromServer(&response, std::move(group_id), std::move(stream), op, true, min_size); } - if (*err != nullptr && *err!=ConsumerErrorTemplates::kPartialData) { - return {0, 0,MessageMetas{}}; + if (*err != nullptr && *err != ConsumerErrorTemplates::kPartialData) { + return {0, 0, MessageMetas{}}; } return DecodeDatasetFromResponse(response, err); } DataSet ConsumerImpl::GetDatasetById(uint64_t id, uint64_t min_size, std::string stream, Error* err) { if (id == 0) { - *err = ConsumerErrorTemplates::kWrongInput.Generate("id should be positive"); + *err = ConsumerErrorTemplates::kWrongInput.Generate("id should be positive"); return {}; } return GetDatasetFromServer(GetMessageServerOperation::GetID, id, "0", std::move(stream), min_size, err); @@ -656,18 +686,14 @@ StreamInfos ParseStreamsFromResponse(std::string response, Error* err) { } std::string filterToString(StreamFilter filter) { - switch(filter) { - case StreamFilter::kAllStreams: - return "all"; - case StreamFilter::kFinishedStreams: - return "finished"; - case StreamFilter::kUnfinishedStreams: - return "unfinished"; + switch (filter) { + case StreamFilter::kAllStreams:return "all"; + case StreamFilter::kFinishedStreams:return "finished"; + case StreamFilter::kUnfinishedStreams:return "unfinished"; } } - -StreamInfos ConsumerImpl::GetStreamList(std::string from,StreamFilter filter, Error* err) { +StreamInfos ConsumerImpl::GetStreamList(std::string from, StreamFilter filter, Error* err) { RequestInfo ri = GetStreamListRequest(from, filter); auto response = BrokerRequestWithTimeout(ri, err); @@ -679,12 +705,13 @@ StreamInfos ConsumerImpl::GetStreamList(std::string from,StreamFilter filter, Er RequestInfo ConsumerImpl::GetStreamListRequest(const std::string &from, const StreamFilter &filter) const { RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + "/0/streams"; + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + "/0/streams"; ri.post = false; if (!from.empty()) { ri.extra_params = "&from=" + from; } - ri.extra_params +="&filter="+filterToString(filter); + ri.extra_params += "&filter=" + filterToString(filter); return ri; } @@ -707,7 +734,7 @@ Error ConsumerImpl::UpdateFolderTokenIfNeeded(bool ignore_existing) { RequestInfo ConsumerImpl::CreateFolderTokenRequest() const { RequestInfo ri; ri.host = endpoint_; - ri.api = "/asapo-authorizer/folder"; + ri.api = "/asapo-authorizer/" + kConsumerProtocol.GetAuthorizerVersion() + "/folder"; ri.post = true; ri.body = "{\"Folder\":\"" + source_path_ + "\",\"BeamtimeId\":\"" + source_credentials_.beamtime_id + "\",\"Token\":\"" @@ -747,7 +774,8 @@ Error ConsumerImpl::Acknowledge(std::string group_id, uint64_t id, std::string s return ConsumerErrorTemplates::kWrongInput.Generate("empty stream"); } RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + +"/" + std::move(stream) + "/" + std::move(group_id) + "/" + std::to_string(id); ri.post = true; @@ -768,7 +796,8 @@ IdList ConsumerImpl::GetUnacknowledgedMessages(std::string group_id, return {}; } RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + +"/" + std::move(stream) + "/" + std::move(group_id) + "/nacks"; ri.extra_params = "&from=" + std::to_string(from_id) + "&to=" + std::to_string(to_id); @@ -793,7 +822,8 @@ uint64_t ConsumerImpl::GetLastAcknowledgedMessage(std::string group_id, std::str return 0; } RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + +"/" + std::move(stream) + "/" + std::move(group_id) + "/lastack"; @@ -828,7 +858,8 @@ Error ConsumerImpl::NegativeAcknowledge(std::string group_id, return ConsumerErrorTemplates::kWrongInput.Generate("empty stream"); } RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + +"/" + std::move(stream) + "/" + std::move(group_id) + "/" + std::to_string(id); ri.post = true; @@ -839,21 +870,21 @@ Error ConsumerImpl::NegativeAcknowledge(std::string group_id, return err; } void ConsumerImpl::InterruptCurrentOperation() { - interrupt_flag_= true; + interrupt_flag_ = true; } uint64_t ConsumerImpl::GetCurrentDatasetCount(std::string stream, bool include_incomplete, Error* err) { RequestInfo ri = GetSizeRequestForDatasetStream(stream, include_incomplete); - return GetCurrentCount(stream,ri,err); + return GetCurrentCount(stream, ri, err); } RequestInfo ConsumerImpl::GetSizeRequestForDatasetStream(std::string &stream, bool include_incomplete) const { RequestInfo ri = GetSizeRequestForSingleMessagesStream(stream); - ri.extra_params = std::string("&incomplete=")+(include_incomplete?"true":"false"); + ri.extra_params = std::string("&incomplete=") + (include_incomplete ? "true" : "false"); return ri; } -uint64_t ConsumerImpl::GetCurrentCount(std::string stream, const RequestInfo& ri, Error* err) { +uint64_t ConsumerImpl::GetCurrentCount(std::string stream, const RequestInfo &ri, Error* err) { auto responce = BrokerRequestWithTimeout(ri, err); if (*err) { return 0; @@ -872,9 +903,44 @@ uint64_t ConsumerImpl::ParseGetCurrentCountResponce(Error* err, const std::strin RequestInfo ConsumerImpl::GetSizeRequestForSingleMessagesStream(std::string &stream) const { RequestInfo ri; - ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + + ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/" + + source_credentials_.data_source + +"/" + std::move(stream) + "/size"; return ri; } +RequestInfo ConsumerImpl::GetVersionRequest() const { + RequestInfo ri; + ri.host = endpoint_; + ri.api = "/asapo-discovery/" + kConsumerProtocol.GetDiscoveryVersion() + "/version"; + ri.extra_params = "&client=consumer&protocol=" + kConsumerProtocol.GetVersion(); + return ri; } + +Error ConsumerImpl::GetServerVersionInfo(std::string* server_info, bool* supported) { + auto ri = GetVersionRequest(); + RequestOutput output; + auto err = ProcessRequest(&output, ri, nullptr); + if (err) { + return err; + } + return ExtractVersionFromResponse(output.string_output,"consumer",server_info,supported); +} + +Error ConsumerImpl::GetVersionInfo(std::string* client_info, std::string* server_info, bool* supported) { + if (client_info == nullptr && server_info == nullptr && supported == nullptr) { + return ConsumerErrorTemplates::kWrongInput.Generate("missing parameters"); + } + if (client_info != nullptr) { + *client_info = + "software version: " + std::string(kVersion) + ", consumer protocol: " + kConsumerProtocol.GetVersion(); + } + + if (server_info != nullptr || supported != nullptr) { + return GetServerVersionInfo(server_info,supported); + } + + return nullptr; +} + +} \ No newline at end of file diff --git a/consumer/api/cpp/src/consumer_impl.h b/consumer/api/cpp/src/consumer_impl.h index 9628c810760c03a364677519473756bed77f3e8f..ef0ee3ac8679b32d415dee65442565e28da66558 100644 --- a/consumer/api/cpp/src/consumer_impl.h +++ b/consumer/api/cpp/src/consumer_impl.h @@ -84,6 +84,7 @@ class ConsumerImpl final : public asapo::Consumer { Error GetById(uint64_t id, MessageMeta* info, MessageData* data, std::string stream) override; + Error GetVersionInfo(std::string* client_info,std::string* server_info, bool* supported) override; void SetTimeout(uint64_t timeout_ms) override; void ForceNoRdma() override; @@ -111,6 +112,7 @@ class ConsumerImpl final : public asapo::Consumer { std::unique_ptr<NetClient> net_client__; std::mutex net_client_mutex__; // Required for the lazy initialization of net_client private: + Error ProcessDiscoverServiceResult(Error err, std::string* uri_to_set); Error GetDataFromFileTransferService(MessageMeta* info, MessageData* data, bool retry_with_new_token); Error GetDataFromFile(MessageMeta* info, MessageData* data); static const std::string kBrokerServiceName; @@ -145,6 +147,7 @@ class ConsumerImpl final : public asapo::Consumer { uint64_t GetCurrentCount(std::string stream, const RequestInfo& ri, Error* err); RequestInfo GetStreamListRequest(const std::string &from, const StreamFilter &filter) const; + Error GetServerVersionInfo(std::string* server_info, bool* supported) ; std::string endpoint_; std::string current_broker_uri_; @@ -167,6 +170,9 @@ class ConsumerImpl final : public asapo::Consumer { RequestInfo GetSizeRequestForSingleMessagesStream(std::string &stream) const; RequestInfo GetSizeRequestForDatasetStream(std::string &stream, bool include_incomplete) const; uint64_t ParseGetCurrentCountResponce(Error* err, const std::string &responce) const; + RequestInfo GetDiscoveryRequest(const std::string &service_name) const; + RequestInfo GetVersionRequest() const; + }; } diff --git a/consumer/api/cpp/src/fabric_consumer_client.cpp b/consumer/api/cpp/src/fabric_consumer_client.cpp index 8c80895cb4a1048fb10cab4128677e58f7dbe6b8..774513e1f4d7dab3abce541dfa3e4b1261d46d5b 100644 --- a/consumer/api/cpp/src/fabric_consumer_client.cpp +++ b/consumer/api/cpp/src/fabric_consumer_client.cpp @@ -3,6 +3,7 @@ #include <iostream> #include "fabric_consumer_client.h" #include "rds_response_error.h" +#include "asapo/common/internal/version.h" using namespace asapo; @@ -33,6 +34,7 @@ Error FabricConsumerClient::GetData(const MessageMeta* info, MessageData* data) } GenericRequestHeader request_header{kOpcodeGetBufferData, info->buf_id, info->size}; + strncpy(request_header.api_version, kConsumerProtocol.GetRdsVersion().c_str(), kMaxVersionSize); memcpy(request_header.message, mr->GetDetails(), sizeof(fabric::MemoryRegionDetails)); GenericNetworkResponse response{}; diff --git a/consumer/api/cpp/src/rds_response_error.h b/consumer/api/cpp/src/rds_response_error.h index dfd5859a66ca8e10c2fcaac54e8d87e74bdc1639..8bc8d64c53d24138e10b17458e8af4311df08391 100644 --- a/consumer/api/cpp/src/rds_response_error.h +++ b/consumer/api/cpp/src/rds_response_error.h @@ -12,6 +12,11 @@ namespace RdsResponseErrorTemplates { auto const kNetErrorReauthorize = RdsResponseErrorTemplate { "RDS response Reauthorize", NetworkErrorCode::kNetErrorReauthorize }; + +auto const kNetErrorNotSupported = RdsResponseErrorTemplate { + "RDS unsupported client", NetworkErrorCode::kNetErrorNotSupported +}; + auto const kNetErrorWarning = RdsResponseErrorTemplate { "RDS response Warning", NetworkErrorCode::kNetErrorWarning }; @@ -33,6 +38,8 @@ inline Error ConvertRdsResponseToError(NetworkErrorCode error_code) { switch (error_code) { case kNetErrorNoError: return nullptr; + case kNetErrorNotSupported: + return RdsResponseErrorTemplates::kNetErrorNotSupported.Generate(); case kNetErrorReauthorize: return RdsResponseErrorTemplates::kNetErrorReauthorize.Generate(); case kNetErrorWarning: diff --git a/consumer/api/cpp/src/tcp_consumer_client.cpp b/consumer/api/cpp/src/tcp_consumer_client.cpp index a2bcc349cb90152409dfc3a68f808cfeed68a5dd..d58f05d6bb3213beeb39ec7e0a539ed181a68345 100644 --- a/consumer/api/cpp/src/tcp_consumer_client.cpp +++ b/consumer/api/cpp/src/tcp_consumer_client.cpp @@ -2,6 +2,7 @@ #include "asapo/io/io_factory.h" #include "asapo/common/networking.h" #include "rds_response_error.h" +#include "asapo/common/internal/version.h" namespace asapo { @@ -13,6 +14,7 @@ TcpConsumerClient::TcpConsumerClient() : io__{GenerateDefaultIO()}, connection_p Error TcpConsumerClient::SendGetDataRequest(SocketDescriptor sd, const MessageMeta* info) const noexcept { Error err; GenericRequestHeader request_header{kOpcodeGetBufferData, info->buf_id, info->size}; + strncpy(request_header.api_version, kConsumerProtocol.GetRdsVersion().c_str(), kMaxVersionSize); io__->Send(sd, &request_header, sizeof(request_header), &err); if (err) { connection_pool__->ReleaseConnection(sd); @@ -43,6 +45,10 @@ Error TcpConsumerClient::ReceiveResponce(SocketDescriptor sd) const noexcept { } if (response.error_code) { switch (response.error_code) { + case kNetErrorNotSupported: + io__->CloseSocket(sd, nullptr); + connection_pool__->ReleaseConnection(sd); + break; case kNetErrorWrongRequest: io__->CloseSocket(sd, nullptr); break; diff --git a/consumer/api/cpp/unittests/test_consumer_impl.cpp b/consumer/api/cpp/unittests/test_consumer_impl.cpp index 813a2d65f4144c5c2dfdcf6e7cf04284f35bc916..6ad5448e5d336702803094aa454d40e4292e9555 100644 --- a/consumer/api/cpp/unittests/test_consumer_impl.cpp +++ b/consumer/api/cpp/unittests/test_consumer_impl.cpp @@ -14,6 +14,7 @@ #include "asapo/http_client/http_error.h" #include "mocking.h" #include "../src/tcp_consumer_client.h" +#include "asapo/common/internal/version.h" using asapo::ConsumerFactory; using asapo::Consumer; @@ -66,6 +67,8 @@ class ConsumerImplTests : public Test { MessageMeta info; std::string expected_server_uri = "test:8400"; std::string expected_broker_uri = "asapo-broker:5005"; + std::string expected_consumer_protocol = "v0.1"; + std::string expected_broker_api = expected_broker_uri + "/" + expected_consumer_protocol; std::string expected_fts_uri = "asapo-file-transfer:5008"; std::string expected_token = "token"; std::string expected_path = "/tmp/beamline/beamtime"; @@ -120,7 +123,7 @@ class ConsumerImplTests : public Test { } void MockGet(const std::string &response, asapo::HttpCode return_code = HttpCode::OK) { - EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_broker_uri), _, _)).WillOnce(DoAll( + EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_broker_api), _, _)).WillOnce(DoAll( SetArgPointee<1>(return_code), SetArgPointee<2>(nullptr), Return(response) @@ -128,14 +131,15 @@ class ConsumerImplTests : public Test { } void MockGetError() { - EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_broker_uri), _, _)).WillOnce(DoAll( + EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_broker_api), _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::NotFound), SetArgPointee<2>(asapo::IOErrorTemplates::kUnknownIOError.Generate().release()), Return("") )); } void MockGetServiceUri(std::string service, std::string result) { - EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/" + service), _, + EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/" + service+"?token=" + + expected_token+"&protocol=v0.1"), _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::OK), SetArgPointee<2>(nullptr), @@ -200,7 +204,7 @@ TEST_F(ConsumerImplTests, DefaultStreamIsDetector) { MockGetBrokerUri(); EXPECT_CALL(mock_http_client, - Get_t(expected_broker_uri + "/database/beamtime_id/detector/stream/" + expected_group_id + Get_t(expected_broker_api + "/beamtime/beamtime_id/detector/stream/" + expected_group_id + "/next?token=" + expected_token, _, @@ -215,7 +219,7 @@ TEST_F(ConsumerImplTests, DefaultStreamIsDetector) { TEST_F(ConsumerImplTests, GetNextUsesCorrectUriWithStream) { MockGetBrokerUri(); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" + expected_stream + "/" + expected_group_id + "/next?token=" + expected_token, _, _)).WillOnce(DoAll( @@ -229,7 +233,7 @@ TEST_F(ConsumerImplTests, GetLastUsesCorrectUri) { MockGetBrokerUri(); EXPECT_CALL(mock_http_client, - Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/"+ expected_stream+"/0/last?token=" + Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/"+ expected_stream+"/0/last?token=" + expected_token, _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::OK), @@ -322,7 +326,7 @@ TEST_F(ConsumerImplTests, GetMessageReturnsWrongResponseFromHttpClient) { } TEST_F(ConsumerImplTests, GetMessageReturnsIfBrokerAddressNotFound) { - EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/asapo-broker"), _, + EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/asapo-broker"), _, _)).Times(AtLeast(2)).WillRepeatedly(DoAll( SetArgPointee<1>(HttpCode::NotFound), SetArgPointee<2>(nullptr), @@ -334,8 +338,22 @@ TEST_F(ConsumerImplTests, GetMessageReturnsIfBrokerAddressNotFound) { ASSERT_THAT(err->Explain(), AllOf(HasSubstr(expected_server_uri), HasSubstr("unavailable"))); } +TEST_F(ConsumerImplTests, GetMessageReturnsUnsupportedClient) { + EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/asapo-broker"), _, + _)).Times(AtLeast(2)).WillRepeatedly(DoAll( + SetArgPointee<1>(HttpCode::UnsupportedMediaType), + SetArgPointee<2>(nullptr), + Return(""))); + + consumer->SetTimeout(100); + auto err = consumer->GetNext(expected_group_id, &info, nullptr, expected_stream); + + ASSERT_THAT(err, Eq(asapo::ConsumerErrorTemplates::kUnsupportedClient)); +} + + TEST_F(ConsumerImplTests, GetMessageReturnsIfBrokerUriEmpty) { - EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/asapo-broker"), _, + EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/asapo-broker"), _, _)).Times(AtLeast(2)).WillRepeatedly(DoAll( SetArgPointee<1>(HttpCode::OK), SetArgPointee<2>(nullptr), @@ -356,7 +374,7 @@ TEST_F(ConsumerImplTests, GetDoNotCallBrokerUriIfAlreadyFound) { Mock::VerifyAndClearExpectations(&mock_http_client); EXPECT_CALL(mock_http_client, - Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/asap-broker"), _, _)).Times(0); + Get_t(_, _, _)).Times(0); MockGet("error_response"); consumer->GetNext(expected_group_id, &info, nullptr, expected_stream); } @@ -398,7 +416,7 @@ TEST_F(ConsumerImplTests, GetMessageReturnsNoDataAfterTimeoutEvenIfOtherErrorOcc Return("{\"op\":\"get_record_by_id\",\"id\":" + std::to_string(expected_dataset_id) + ",\"id_max\":2,\"next_stream\":\"""\"}"))); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/" + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/" + std::to_string(expected_dataset_id) + "?token=" + expected_token, _, _)).Times(AtLeast(1)).WillRepeatedly(DoAll( SetArgPointee<1>(HttpCode::NotFound), @@ -431,7 +449,7 @@ ACTION(AssignArg2) { } TEST_F(ConsumerImplTests, GetNextRetriesIfConnectionHttpClientErrorUntilTimeout) { - EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/asapo-broker"), _, + EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/asapo-broker"), _, _)).Times(AtLeast(2)).WillRepeatedly(DoAll( SetArgPointee<1>(HttpCode::OK), SetArgPointee<2>(nullptr), @@ -564,7 +582,7 @@ TEST_F(ConsumerImplTests, GenerateNewGroupIdReturnsErrorCreateGroup) { TEST_F(ConsumerImplTests, GenerateNewGroupIdReturnsGroupID) { MockGetBrokerUri(); - EXPECT_CALL(mock_http_client, Post_t(expected_broker_uri + "/creategroup?token=" + expected_token, _, "", _, + EXPECT_CALL(mock_http_client, Post_t(expected_broker_api + "/creategroup?token=" + expected_token, _, "", _, _)).WillOnce(DoAll( SetArgPointee<3>(HttpCode::OK), SetArgPointee<4>(nullptr), @@ -582,7 +600,7 @@ TEST_F(ConsumerImplTests, ResetCounterByDefaultUsesCorrectUri) { consumer->SetTimeout(100); EXPECT_CALL(mock_http_client, - Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/" + + Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/" + expected_group_id + "/resetcounter?token=" + expected_token + "&value=0", _, _, _, _)).WillOnce(DoAll( SetArgPointee<3>(HttpCode::OK), @@ -596,7 +614,7 @@ TEST_F(ConsumerImplTests, ResetCounterUsesCorrectUri) { MockGetBrokerUri(); consumer->SetTimeout(100); - EXPECT_CALL(mock_http_client, Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" + + EXPECT_CALL(mock_http_client, Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" + expected_stream + "/" + expected_group_id + "/resetcounter?token=" + expected_token + "&value=10", _, _, _, _)).WillOnce(DoAll( @@ -611,7 +629,7 @@ TEST_F(ConsumerImplTests, GetCurrentSizeUsesCorrectUri) { MockGetBrokerUri(); consumer->SetTimeout(100); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" + expected_stream + "/size?token=" + expected_token, _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::OK), @@ -627,7 +645,7 @@ TEST_F(ConsumerImplTests, GetCurrentSizeErrorOnWrongResponce) { MockGetBrokerUri(); consumer->SetTimeout(100); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/"+expected_stream+"/size?token=" + expected_token, _, _)).WillRepeatedly(DoAll( SetArgPointee<1>(HttpCode::Unauthorized), @@ -643,7 +661,7 @@ TEST_F(ConsumerImplTests, GetNDataErrorOnWrongParse) { MockGetBrokerUri(); consumer->SetTimeout(100); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/size?token=" + expected_token, _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::OK), @@ -661,7 +679,7 @@ TEST_F(ConsumerImplTests, GetByIdUsesCorrectUri) { auto to_send = CreateFI(); auto json = to_send.Json(); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/" + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/" + std::to_string( expected_dataset_id) + "?token=" + expected_token, _, @@ -680,7 +698,7 @@ TEST_F(ConsumerImplTests, GetByIdTimeouts) { MockGetBrokerUri(); consumer->SetTimeout(10); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/" + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/" + std::to_string(expected_dataset_id) + "?token=" + expected_token, _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::Conflict), @@ -696,7 +714,7 @@ TEST_F(ConsumerImplTests, GetByIdReturnsEndOfStream) { MockGetBrokerUri(); consumer->SetTimeout(10); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/" + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/" + std::to_string(expected_dataset_id) + "?token=" + expected_token, _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::Conflict), @@ -712,7 +730,7 @@ TEST_F(ConsumerImplTests, GetByIdReturnsEndOfStreamWhenIdTooLarge) { MockGetBrokerUri(); consumer->SetTimeout(10); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/" + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/" + std::to_string(expected_dataset_id) + "?token=" + expected_token, _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::Conflict), @@ -728,7 +746,7 @@ TEST_F(ConsumerImplTests, GetMetaDataOK) { MockGetBrokerUri(); consumer->SetTimeout(100); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/default/0/meta/0?token=" + expected_token, _, _)).WillOnce(DoAll( @@ -834,7 +852,7 @@ TEST_F(ConsumerImplTests, QueryMessagesReturnRecords) { auto responce_string = "[" + json1 + "," + json2 + "]"; EXPECT_CALL(mock_http_client, - Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0" + + Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0" + "/querymessages?token=" + expected_token, _, expected_query_string, _, _)).WillOnce(DoAll( SetArgPointee<3>(HttpCode::OK), SetArgPointee<4>(nullptr), @@ -854,7 +872,7 @@ TEST_F(ConsumerImplTests, QueryMessagesReturnRecords) { TEST_F(ConsumerImplTests, GetNextDatasetUsesCorrectUri) { MockGetBrokerUri(); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/" + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/" + expected_group_id + "/next?token=" + expected_token + "&dataset=true&minsize=0", _, _)).WillOnce(DoAll( @@ -989,7 +1007,7 @@ TEST_F(ConsumerImplTests, GetDataSetReturnsParseError) { TEST_F(ConsumerImplTests, GetLastDatasetUsesCorrectUri) { MockGetBrokerUri(); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" + expected_stream + "/0/last?token=" + expected_token + "&dataset=true&minsize=1", _, _)).WillOnce(DoAll( @@ -1003,7 +1021,7 @@ TEST_F(ConsumerImplTests, GetLastDatasetUsesCorrectUri) { TEST_F(ConsumerImplTests, GetDatasetByIdUsesCorrectUri) { MockGetBrokerUri(); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/" + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/" + std::to_string(expected_dataset_id) + "?token=" + expected_token + "&dataset=true" + "&minsize=0", _, _)).WillOnce(DoAll( @@ -1020,7 +1038,7 @@ TEST_F(ConsumerImplTests, GetStreamListUsesCorrectUri) { std::string(R"({"streams":[{"lastId":123,"name":"test","timestampCreated":1000000,"timestampLast":1000,"finished":false,"nextStream":""},)")+ R"({"lastId":124,"name":"test1","timestampCreated":2000000,"timestampLast":2000,"finished":true,"nextStream":"next"}]})"; EXPECT_CALL(mock_http_client, - Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/0/streams" + Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/0/streams" + "?token=" + expected_token + "&from=stream_from&filter=all", _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::OK), @@ -1039,7 +1057,7 @@ TEST_F(ConsumerImplTests, GetStreamListUsesCorrectUri) { TEST_F(ConsumerImplTests, GetStreamListUsesCorrectUriWithoutFrom) { MockGetBrokerUri(); EXPECT_CALL(mock_http_client, - Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/0/streams" + Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/0/streams" + "?token=" + expected_token+"&filter=finished", _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::OK), @@ -1064,7 +1082,7 @@ void ConsumerImplTests::ExpectFolderToken() { expected_beamtime_id + "\",\"Token\":\"" + expected_token + "\"}"; - EXPECT_CALL(mock_http_client, Post_t(HasSubstr(expected_server_uri + "/asapo-authorizer/folder"), _, + EXPECT_CALL(mock_http_client, Post_t(HasSubstr(expected_server_uri + "/asapo-authorizer/v0.1/folder"), _, expected_folder_query_string, _, _)).WillOnce(DoAll( SetArgPointee<3>(HttpCode::OK), SetArgPointee<4>(nullptr), @@ -1082,7 +1100,7 @@ ACTION_P(AssignArg3, assign) { } void ConsumerImplTests::ExpectFileTransfer(const asapo::ConsumerErrorTemplate* p_err_template) { - EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/transfer"), + EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/v0.1/transfer"), expected_cookie, expected_fts_query_string, _, @@ -1095,7 +1113,7 @@ void ConsumerImplTests::ExpectFileTransfer(const asapo::ConsumerErrorTemplate* p } void ConsumerImplTests::ExpectRepeatedFileTransfer() { - EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/transfer"), + EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/v0.1/transfer"), expected_cookie, expected_fts_query_string, _, @@ -1140,7 +1158,7 @@ TEST_F(ConsumerImplTests, FileTransferReadsFileSize) { Return("{\"file_size\":5}") )); - EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/transfer"), + EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/v0.1/transfer"), expected_cookie, expected_fts_query_string, _, @@ -1181,7 +1199,7 @@ TEST_F(ConsumerImplTests, GetMessageTriesToGetTokenAgainIfTransferFailed) { TEST_F(ConsumerImplTests, AcknowledgeUsesCorrectUri) { MockGetBrokerUri(); auto expected_acknowledge_command = "{\"Op\":\"ackmessage\"}"; - EXPECT_CALL(mock_http_client, Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" + + EXPECT_CALL(mock_http_client, Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" + expected_stream + "/" + expected_group_id + "/" + std::to_string(expected_dataset_id) + "?token=" @@ -1197,7 +1215,7 @@ TEST_F(ConsumerImplTests, AcknowledgeUsesCorrectUri) { void ConsumerImplTests::ExpectIdList(bool error) { MockGetBrokerUri(); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" + expected_stream + "/" + expected_group_id + "/nacks?token=" + expected_token + "&from=1&to=0", _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::OK), @@ -1215,7 +1233,7 @@ TEST_F(ConsumerImplTests, GetUnAcknowledgedListReturnsIds) { } void ConsumerImplTests::ExpectLastAckId(bool empty_response) { - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" + expected_stream + "/" + expected_group_id + "/lastack?token=" + expected_token, _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::OK), @@ -1253,7 +1271,7 @@ TEST_F(ConsumerImplTests, GetByIdErrorsForId0) { TEST_F(ConsumerImplTests, ResendNacks) { MockGetBrokerUri(); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/" + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/" + expected_group_id + "/next?token=" + expected_token + "&resend_nacks=true&delay_ms=10000&resend_attempts=3", _, _)).WillOnce(DoAll( @@ -1268,7 +1286,7 @@ TEST_F(ConsumerImplTests, ResendNacks) { TEST_F(ConsumerImplTests, NegativeAcknowledgeUsesCorrectUri) { MockGetBrokerUri(); auto expected_neg_acknowledge_command = R"({"Op":"negackmessage","Params":{"DelayMs":10000}})"; - EXPECT_CALL(mock_http_client, Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" + + EXPECT_CALL(mock_http_client, Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" + expected_stream + "/" + expected_group_id + "/" + std::to_string(expected_dataset_id) + "?token=" @@ -1313,7 +1331,7 @@ TEST_F(ConsumerImplTests, GetCurrentDataSetCounteUsesCorrectUri) { MockGetBrokerUri(); consumer->SetTimeout(100); - EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" + + EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" + expected_stream + "/size?token=" + expected_token+"&incomplete=true", _, _)).WillOnce(DoAll( SetArgPointee<1>(HttpCode::OK), @@ -1325,4 +1343,30 @@ TEST_F(ConsumerImplTests, GetCurrentDataSetCounteUsesCorrectUri) { ASSERT_THAT(size, Eq(10)); } + +TEST_F(ConsumerImplTests, GetVersionInfoClientOnly) { + std::string client_info; + auto err = consumer->GetVersionInfo(&client_info,nullptr,nullptr); + ASSERT_THAT(err, Eq(nullptr)); + ASSERT_THAT(client_info, HasSubstr(std::string(asapo::kVersion))); + ASSERT_THAT(client_info, HasSubstr(asapo::kConsumerProtocol.GetVersion())); +} + +TEST_F(ConsumerImplTests, GetVersionInfoWithServer) { + + std::string result = R"({"softwareVersion":"20.03.1, build 7a9294ad","clientSupported":"no", "clientProtocol":{"versionInfo":"v0.2"}})"; + + EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/version?token=token&client=consumer&protocol=v0.1"), _,_)).WillOnce(DoAll( + SetArgPointee<1>(HttpCode::OK), + SetArgPointee<2>(nullptr), + Return(result))); + + std::string client_info,server_info; + auto err = consumer->GetVersionInfo(&client_info,&server_info,nullptr); + ASSERT_THAT(err, Eq(nullptr)); + ASSERT_THAT(server_info, HasSubstr("20.03.1")); + ASSERT_THAT(server_info, HasSubstr("v0.2")); +} + + } diff --git a/consumer/api/cpp/unittests/test_fabric_consumer_client.cpp b/consumer/api/cpp/unittests/test_fabric_consumer_client.cpp index 9e32cd3842cc11d96003b342ade885a0d8d7e8a7..dcbd311e16fef382fa1f1d710eab1041912ddf78 100644 --- a/consumer/api/cpp/unittests/test_fabric_consumer_client.cpp +++ b/consumer/api/cpp/unittests/test_fabric_consumer_client.cpp @@ -33,6 +33,7 @@ MATCHER_P6(M_CheckSendRequest, op_code, buf_id, data_size, mr_addr, mr_length, m && data->data_id == uint64_t(buf_id) && data->data_size == uint64_t(data_size) && mr->addr == uint64_t(mr_addr) + && strcmp(data->api_version, "v0.1") == 0 && mr->length == uint64_t(mr_length) && mr->key == uint64_t(mr_key); } diff --git a/consumer/api/cpp/unittests/test_rds_error_mapper.cpp b/consumer/api/cpp/unittests/test_rds_error_mapper.cpp index f19dc56022525914a17fe0b04fee1340571c4216..c5161d0ee8fc35c46d549a968059e7c7ee64aba1 100644 --- a/consumer/api/cpp/unittests/test_rds_error_mapper.cpp +++ b/consumer/api/cpp/unittests/test_rds_error_mapper.cpp @@ -19,4 +19,6 @@ TEST(ConvertRdsResponseToError, TestAllCases) { Eq(RdsResponseErrorTemplates::kNetAuthorizationError)); ASSERT_THAT(ConvertRdsResponseToError(NetworkErrorCode::kNetErrorInternalServerError), Eq(RdsResponseErrorTemplates::kNetErrorInternalServerError)); + ASSERT_THAT(ConvertRdsResponseToError(NetworkErrorCode::kNetErrorNotSupported), + Eq(RdsResponseErrorTemplates::kNetErrorNotSupported)); } diff --git a/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp b/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp index b1df9c9db1e6bd84ae1c21aba9968e0bc7c82a36..ebf4102b3aa4931b9efd884a83acf134e3168b8e 100644 --- a/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp +++ b/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp @@ -44,6 +44,7 @@ MATCHER_P4(M_CheckSendRequest, op_code, buf_id, data_size, message, return ((asapo::GenericRequestHeader*) arg)->op_code == op_code && ((asapo::GenericRequestHeader*) arg)->data_id == uint64_t(buf_id) && ((asapo::GenericRequestHeader*) arg)->data_size == uint64_t(data_size) + && strcmp(((asapo::GenericRequestHeader*) arg)->api_version, "v0.1") == 0 && strcmp(((asapo::GenericRequestHeader*) arg)->message, message) == 0; } @@ -212,6 +213,19 @@ TEST_F(TcpClientTests, GetResponceReturnsWrongRequest) { ASSERT_THAT(err, Ne(nullptr)); } +TEST_F(TcpClientTests, GetResponceReturnsUnsupported) { + ExpectNewConnection(false, true); + ExpectSendRequest(expected_sd, true); + ExpectGetResponce(expected_sd, true, asapo::kNetErrorNotSupported); + EXPECT_CALL(mock_io, CloseSocket_t(expected_sd, _)); + EXPECT_CALL(mock_connection_pool, ReleaseConnection(expected_sd)); + + auto err = client->GetData(&info, &data); + + ASSERT_THAT(err, Ne(nullptr)); +} + + TEST_F(TcpClientTests, ErrorGettingData) { ExpectNewConnection(false, true); ExpectSendRequest(expected_sd, true); diff --git a/consumer/api/python/asapo_consumer.pxd b/consumer/api/python/asapo_consumer.pxd index f0c9fa99c9dc5885b8bee77d9227d89db15d4724..fa755a375a83d05f4469cb4fad4030ea0130caf2 100644 --- a/consumer/api/python/asapo_consumer.pxd +++ b/consumer/api/python/asapo_consumer.pxd @@ -87,6 +87,7 @@ cdef extern from "asapo/asapo_consumer.h" namespace "asapo" nogil: vector[StreamInfo] GetStreamList(string from_stream, StreamFilter filter, Error* err) void SetResendNacs(bool resend, uint64_t delay_ms, uint64_t resend_attempts) void InterruptCurrentOperation() + Error GetVersionInfo(string* client_info,string* server_info, bool* supported) cdef extern from "asapo/asapo_consumer.h" namespace "asapo" nogil: cdef cppclass ConsumerFactory: @@ -103,6 +104,8 @@ cdef extern from "asapo/asapo_consumer.h" namespace "asapo": ErrorTemplateInterface kLocalIOError "asapo::ConsumerErrorTemplates::kLocalIOError" ErrorTemplateInterface kWrongInput "asapo::ConsumerErrorTemplates::kWrongInput" ErrorTemplateInterface kPartialData "asapo::ConsumerErrorTemplates::kPartialData" + ErrorTemplateInterface kUnsupportedClient "asapo::ConsumerErrorTemplates::kUnsupportedClient" + cdef cppclass ConsumerErrorData: uint64_t id diff --git a/consumer/api/python/asapo_consumer.pyx.in b/consumer/api/python/asapo_consumer.pyx.in index 88d5be838750d5e531875823885e41a3da7369c9..1db15ed4a72531c1bb9403c632a4ea9231f4da58 100644 --- a/consumer/api/python/asapo_consumer.pyx.in +++ b/consumer/api/python/asapo_consumer.pyx.in @@ -46,6 +46,9 @@ class AsapoUnavailableServiceError(AsapoConsumerError): class AsapoLocalIOError(AsapoConsumerError): pass +class AsapoUnsupportedClientError(AsapoConsumerError): + pass + class AsapoStreamFinishedError(AsapoConsumerError): def __init__(self,message,id_max=None,next_stream=None): AsapoConsumerError.__init__(self,message) @@ -99,6 +102,8 @@ cdef throw_exception(Error& err, res = None): raise AsapoUnavailableServiceError(error_string) elif err == kInterruptedTransaction: raise AsapoInterruptedTransactionError(error_string) + elif err == kUnsupportedClient: + raise AsapoUnsupportedClientError(error_string) else: raise AsapoConsumerError(error_string) @@ -211,6 +216,21 @@ cdef class PyConsumer: if err: throw_exception(err) return + def get_version_info(self, from_server = "true"): + cdef string client_info,server_info + cdef bool supported + cdef string* p_server_info = &server_info if from_server else <string*>NULL + cdef bool* p_supported = &supported if from_server else <bool*>NULL + cdef Error err + with nogil: + err = self.c_consumer.get().GetVersionInfo(&client_info,p_server_info,p_supported) + if err: + throw_exception(err) + version = {} + if from_server: + return {'client': _str(client_info), 'server': _str(server_info), 'supported': supported} + else: + return {'client': _str(client_info)} def reset_lastread_marker(self,group_id, stream = "default"): cdef string b_group_id = _bytes(group_id) cdef string b_stream = _bytes(stream) diff --git a/deploy/asapo_helm_chart/asapo/configs/asapo-broker.json b/deploy/asapo_helm_chart/asapo/configs/asapo-broker.json index 00325d3e1b8a514c42ad8a72acc816ea52a6e909..196b79c99019f1fdb86eafdd6573ac7a6ae894bf 100644 --- a/deploy/asapo_helm_chart/asapo/configs/asapo-broker.json +++ b/deploy/asapo_helm_chart/asapo/configs/asapo-broker.json @@ -3,6 +3,7 @@ "DiscoveryServer": "asapo-discovery:{{ .Values.ownServices.discovery.port }}", "AuthorizationServer": "asapo-authorizer:{{ .Values.ownServices.authorization.port }}", "PerformanceDbServer":"{{ .Chart.Name }}-influxdb:{{ .Values.influxdb.influxdb.service.port }}", + "MonitorPerformance": true, "PerformanceDbName": "asapo_brokers", "Port": {{ .Values.ownServices.broker.port }}, "CheckResendInterval":10, diff --git a/deploy/asapo_helm_chart/asapo/configs/asapo-receiver.json b/deploy/asapo_helm_chart/asapo/configs/asapo-receiver.json index c034223fc2a8c0082d924ab5ba5db797f2dfc037..6dde5c8adc0a08182691d7158e067bff336f8815 100644 --- a/deploy/asapo_helm_chart/asapo/configs/asapo-receiver.json +++ b/deploy/asapo_helm_chart/asapo/configs/asapo-receiver.json @@ -1,5 +1,6 @@ { "PerformanceDbServer": "{{ .Chart.Name }}-influxdb:{{ .Values.influxdb.influxdb.service.port }}", + "MonitorPerformance": true, "PerformanceDbName": "asapo_receivers", "DatabaseServer": "asapo-mongodb:{{ .Values.ownServices.mongodb.port }}", "DiscoveryServer": "asapo-discovery:{{ .Values.ownServices.discovery.port }}", diff --git a/deploy/asapo_services/scripts/asapo-brokers.nmd.tpl b/deploy/asapo_services/scripts/asapo-brokers.nmd.tpl index e96dc1a954aacfdc6ecef2a325926544e171b151..14f5eaf5baf9587059c4b644d3dbfea8a29eb137 100644 --- a/deploy/asapo_services/scripts/asapo-brokers.nmd.tpl +++ b/deploy/asapo_services/scripts/asapo-brokers.nmd.tpl @@ -30,7 +30,7 @@ job "asapo-brokers" { security_opt = ["no-new-privileges"] userns_mode = "host" image = "yakser/asapo-broker${image_suffix}" - force_pull = true + force_pull = ${force_pull_images} volumes = ["local/config.json:/var/lib/broker/config.json"] %{ if ! nomad_logs } logging { @@ -67,6 +67,10 @@ job "asapo-brokers" { } } + meta { + perf_monitor = "${perf_monitor}" + } + template { source = "${scripts_dir}/broker.json.tpl" destination = "local/config.json" diff --git a/deploy/asapo_services/scripts/asapo-fts.nmd.tpl b/deploy/asapo_services/scripts/asapo-fts.nmd.tpl index 055d567c0da050d0898ca58f72164b7b30065048..5f4d98278ccb419e54ce9465895e47ea22c92bbb 100644 --- a/deploy/asapo_services/scripts/asapo-fts.nmd.tpl +++ b/deploy/asapo_services/scripts/asapo-fts.nmd.tpl @@ -30,7 +30,7 @@ job "asapo-file-transfer" { security_opt = ["no-new-privileges"] userns_mode = "host" image = "yakser/asapo-file-transfer${image_suffix}" - force_pull = true + force_pull = ${force_pull_images} volumes = ["local/config.json:/var/lib/file_transfer/config.json", "${offline_dir}:${offline_dir}", "${online_dir}:${online_dir}" diff --git a/deploy/asapo_services/scripts/asapo-perfmetrics.nmd.tpl b/deploy/asapo_services/scripts/asapo-perfmetrics.nmd.tpl index 6033581d872d53ae108a892f0754c5bff98b901a..cd717baff86ea82bd6bf5b54719d827caa3aacfa 100644 --- a/deploy/asapo_services/scripts/asapo-perfmetrics.nmd.tpl +++ b/deploy/asapo_services/scripts/asapo-perfmetrics.nmd.tpl @@ -14,7 +14,7 @@ job "asapo-perfmetrics" { # } group "perfmetrics" { - count = 1 + count = "%{ if perf_monitor }1%{ else }0%{ endif }" restart { attempts = 2 interval = "3m" @@ -30,11 +30,13 @@ job "asapo-perfmetrics" { security_opt = ["no-new-privileges"] userns_mode = "host" image = "influxdb:${influxdb_version}" - volumes = ["/${service_dir}/influxdb:/var/lib/influxdb"] + volumes = ["/${service_dir}/influxdb2:/var/lib/influxdb2"] } env { PRE_CREATE_DB="asapo_receivers;asapo_brokers" + INFLUXDB_BIND_ADDRESS="127.0.0.1:$${NOMAD_PORT_influxdb_rpc}" + INFLUXDB_HTTP_BIND_ADDRESS=":$${NOMAD_PORT_influxdb}" } resources { @@ -43,6 +45,9 @@ job "asapo-perfmetrics" { port "influxdb" { static = "${influxdb_port}" } + port "influxdb_rpc" { + static = "${influxdb_rpc_port}" + } } } @@ -72,6 +77,7 @@ job "asapo-perfmetrics" { env { GF_SERVER_DOMAIN = "$${attr.unique.hostname}" GF_SERVER_ROOT_URL = "%(protocol)s://%(domain)s/performance/" + GF_SERVER_HTTP_PORT = "${grafana_port}" } config { diff --git a/deploy/asapo_services/scripts/asapo-receivers.nmd.tpl b/deploy/asapo_services/scripts/asapo-receivers.nmd.tpl index 075100884089b185c4695d7f7c063763fda1776c..2096021f5cc99da4edcfbecafaf5c4a2343855d3 100644 --- a/deploy/asapo_services/scripts/asapo-receivers.nmd.tpl +++ b/deploy/asapo_services/scripts/asapo-receivers.nmd.tpl @@ -35,7 +35,7 @@ job "asapo-receivers" { userns_mode = "host" privileged = true image = "yakser/asapo-receiver${image_suffix}" - force_pull = true + force_pull = ${force_pull_images} volumes = ["local/config.json:/var/lib/receiver/config.json", "${offline_dir}:${offline_dir}", "${online_dir}:${online_dir}"] @@ -84,6 +84,7 @@ job "asapo-receivers" { receiver_dataserver_nthreads = "${receiver_dataserver_nthreads}" receiver_receive_to_disk_threshold = "${receiver_receive_to_disk_threshold}" receiver_network_modes = "${receiver_network_modes}" + perf_monitor = "${perf_monitor}" } template { diff --git a/deploy/asapo_services/scripts/asapo-services.nmd.tpl b/deploy/asapo_services/scripts/asapo-services.nmd.tpl index 6220ae11d82341f7b997f0b11aa872908f5bbfe1..9cb6298aa08ab6edf9b2f3897c21ead5a7dd9514 100644 --- a/deploy/asapo_services/scripts/asapo-services.nmd.tpl +++ b/deploy/asapo_services/scripts/asapo-services.nmd.tpl @@ -19,7 +19,7 @@ job "asapo-services" { security_opt = ["no-new-privileges"] userns_mode = "host" image = "yakser/asapo-authorizer${image_suffix}" - force_pull = true + force_pull = ${force_pull_images} volumes = ["local/config.json:/var/lib/authorizer/config.json", "${offline_dir}:${offline_dir}", "${online_dir}:${online_dir}"] @@ -96,7 +96,7 @@ job "asapo-services" { security_opt = ["no-new-privileges"] userns_mode = "host" image = "yakser/asapo-discovery${image_suffix}" - force_pull = true + force_pull = ${force_pull_images} volumes = ["local/config.json:/var/lib/discovery/config.json"] %{ if ! nomad_logs } logging { @@ -125,7 +125,7 @@ job "asapo-services" { check { name = "alive" type = "http" - path = "/asapo-receiver" + path = "/health" interval = "10s" timeout = "2s" initial_status = "passing" diff --git a/deploy/asapo_services/scripts/asapo.auto.tfvars.in b/deploy/asapo_services/scripts/asapo.auto.tfvars.in index 2212ce1f349579fc874591fbf5884a5db746269b..764b672753af79dcad8aebf46aa1205e6672a9f9 100644 --- a/deploy/asapo_services/scripts/asapo.auto.tfvars.in +++ b/deploy/asapo_services/scripts/asapo.auto.tfvars.in @@ -6,10 +6,12 @@ nginx_version = "1.14" elasticsearch_version = "7.3.2" kibana_version = "7.3.2" mongo_version = "4.0.0" -grafana_version="latest" -influxdb_version = "latest" -elk_logs = true +grafana_version="7.5.0" +influxdb_version = "2.0.4" +elk_logs = false +perf_monitor = false nomad_logs = false +force_pull_images = false job_scripts_dir = "/var/run/asapo" @@ -32,8 +34,9 @@ authorizer_total_memory_size = 256 discovery_total_memory_size = 256 -grafana_port = 3000 +grafana_port = 3301 influxdb_port = 8086 +influxdb_rpc_port = 8088 mongo_port = 27017 fluentd_port = 9880 fluentd_port_stream = 24224 diff --git a/deploy/asapo_services/scripts/broker.json.tpl b/deploy/asapo_services/scripts/broker.json.tpl index bbd97f4218f30116f62aaab2ee94088f65b6a8e8..493c986e427c76ff9c226d931055ad6f5e398563 100644 --- a/deploy/asapo_services/scripts/broker.json.tpl +++ b/deploy/asapo_services/scripts/broker.json.tpl @@ -3,6 +3,7 @@ "DiscoveryServer": "localhost:8400/asapo-discovery", "AuthorizationServer": "localhost:8400/asapo-authorizer", "PerformanceDbServer":"localhost:8400/influxdb", + "MonitorPerformance": {{ env "NOMAD_META_perf_monitor" }}, "CheckResendInterval":10, "PerformanceDbName": "asapo_brokers", "Port":{{ env "NOMAD_PORT_broker" }}, diff --git a/deploy/asapo_services/scripts/receiver.json.tpl b/deploy/asapo_services/scripts/receiver.json.tpl index c4f0d33b20cf255c005650b9d849e9ebd2562f3f..e5214deed638118fac712fe6dced5bf56ebaf790 100644 --- a/deploy/asapo_services/scripts/receiver.json.tpl +++ b/deploy/asapo_services/scripts/receiver.json.tpl @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8400/influxdb", + "MonitorPerformance": {{ env "NOMAD_META_perf_monitor" }}, "PerformanceDbName": "asapo_receivers", "DatabaseServer":"auto", "DiscoveryServer": "localhost:8400/asapo-discovery", diff --git a/deploy/asapo_services/scripts/resources.tf b/deploy/asapo_services/scripts/resources.tf index 1539150f6436c3920ebe58520fb05637882b205a..869b4664f4cde62fbd8495ea5aa42c00ed8b3378 100644 --- a/deploy/asapo_services/scripts/resources.tf +++ b/deploy/asapo_services/scripts/resources.tf @@ -1,37 +1,37 @@ resource "nomad_job" "asapo-nginx" { - jobspec = "${data.template_file.nginx.rendered}" + jobspec = data.template_file.nginx.rendered } resource "nomad_job" "asapo-mongo" { - jobspec = "${data.template_file.asapo_mongo.rendered}" + jobspec = data.template_file.asapo_mongo.rendered } resource "nomad_job" "asapo-perfmetrics" { - jobspec = "${data.template_file.asapo_perfmetrics.rendered}" + jobspec = data.template_file.asapo_perfmetrics.rendered } resource "nomad_job" "asapo-logging" { - jobspec = "${data.template_file.asapo_logging.rendered}" + jobspec = data.template_file.asapo_logging.rendered depends_on = [null_resource.nginx] } resource "nomad_job" "asapo-services" { - jobspec = "${data.template_file.asapo_services.rendered}" + jobspec = data.template_file.asapo_services.rendered depends_on = [null_resource.nginx,null_resource.mongo,null_resource.influxdb,null_resource.fluentd,null_resource.elasticsearch] } resource "nomad_job" "asapo-receivers" { - jobspec = "${data.template_file.asapo_receivers.rendered}" + jobspec = data.template_file.asapo_receivers.rendered depends_on = [nomad_job.asapo-services,null_resource.asapo-authorizer,null_resource.asapo-discovery] } resource "nomad_job" "asapo-brokers" { - jobspec = "${data.template_file.asapo_brokers.rendered}" + jobspec = data.template_file.asapo_brokers.rendered depends_on = [nomad_job.asapo-services,null_resource.asapo-authorizer,null_resource.asapo-discovery] } resource "nomad_job" "asapo-fts" { - jobspec = "${data.template_file.asapo_fts.rendered}" + jobspec = data.template_file.asapo_fts.rendered depends_on = [nomad_job.asapo-services,null_resource.asapo-authorizer,null_resource.asapo-discovery] } diff --git a/deploy/asapo_services/scripts/resources_services.tf b/deploy/asapo_services/scripts/resources_services.tf index fa84a79b18e64e5a4a1431b9c8589f08330d2e02..e3cff85810efb48af3bc90347c5e20010204df6b 100644 --- a/deploy/asapo_services/scripts/resources_services.tf +++ b/deploy/asapo_services/scripts/resources_services.tf @@ -8,7 +8,7 @@ resource "null_resource" "nginx" { resource "null_resource" "influxdb" { provisioner "local-exec" { - command = "asapo-wait-service influxdb" + command = "asapo-wait-service influxdb ${var.perf_monitor}" } depends_on = [nomad_job.asapo-perfmetrics] } diff --git a/deploy/asapo_services/scripts/templates.tf b/deploy/asapo_services/scripts/templates.tf index 90f6b71ec4bc3f5cb5c6e66e376e57783aaa50a3..e5dae73a5b2e39f2550df7de744e1142ed60d962 100644 --- a/deploy/asapo_services/scripts/templates.tf +++ b/deploy/asapo_services/scripts/templates.tf @@ -29,6 +29,7 @@ data "template_file" "asapo_services" { authorizer_port = "${var.authorizer_port}" discovery_port = "${var.discovery_port}" asapo_user = "${var.asapo_user}" + force_pull_images = "${var.force_pull_images}" } } @@ -47,6 +48,8 @@ data "template_file" "asapo_receivers" { receiver_network_modes = "${var.receiver_network_modes}" asapo_user = "${var.asapo_user}" n_receivers = "${var.n_receivers}" + force_pull_images = "${var.force_pull_images}" + perf_monitor = "${var.perf_monitor}" } } @@ -58,6 +61,8 @@ data "template_file" "asapo_brokers" { nomad_logs = "${var.nomad_logs}" asapo_user = "${var.asapo_user}" n_brokers = "${var.n_brokers}" + force_pull_images = "${var.force_pull_images}" + perf_monitor = "${var.perf_monitor}" } } @@ -72,6 +77,7 @@ data "template_file" "asapo_fts" { nomad_logs = "${var.nomad_logs}" asapo_user = "${var.asapo_user}" n_fts = "${var.n_fts}" + force_pull_images = "${var.force_pull_images}" } } @@ -86,6 +92,8 @@ data "template_file" "asapo_perfmetrics" { influxdb_total_memory_size = "${var.influxdb_total_memory_size}" influxdb_port = "${var.influxdb_port}" asapo_user = "${var.asapo_user}" + influxdb_rpc_port = "${var.influxdb_rpc_port}" + perf_monitor = "${var.perf_monitor}" } } diff --git a/deploy/asapo_services/scripts/vars.tf b/deploy/asapo_services/scripts/vars.tf index 5d69d474089cd565a3bb5650c78a18e6a21eaef7..2e95cf15a863cff1d0565cf5f36d9e4cb0c5bcd3 100644 --- a/deploy/asapo_services/scripts/vars.tf +++ b/deploy/asapo_services/scripts/vars.tf @@ -1,4 +1,7 @@ variable "elk_logs" {} +variable "perf_monitor" {} + +variable "force_pull_images" {} variable "asapo_user" {} @@ -60,6 +63,8 @@ variable "grafana_port" {} variable "influxdb_port" {} +variable "influxdb_rpc_port" {} + variable "mongo_port" {} variable "fluentd_port" {} diff --git a/deploy/nomad_consul_docker/nomad.hcl.tpl b/deploy/nomad_consul_docker/nomad.hcl.tpl index 1d67eb3f695986732be629468f657b7c75b58d39..2a5716ee38a99f7c301b25544705a0f8f14cc7d4 100644 --- a/deploy/nomad_consul_docker/nomad.hcl.tpl +++ b/deploy/nomad_consul_docker/nomad.hcl.tpl @@ -27,7 +27,9 @@ client { plugin "docker" { config { endpoint = "$docker_endpoint" - + gc { + image = false + } tls { cert = "/etc/nomad/cert.pem" key = "/etc/nomad/key.pem" diff --git a/deploy/nomad_consul_docker/orchestr_config.py b/deploy/nomad_consul_docker/orchestr_config.py index 5e91651d3bd413a2359790284df9da1b6023b904..52f5da0e6d6fc01be04c96a3d73320170919e1ba 100644 --- a/deploy/nomad_consul_docker/orchestr_config.py +++ b/deploy/nomad_consul_docker/orchestr_config.py @@ -59,8 +59,6 @@ def process_file(file_in,file_out): filein = open(file_in) src = Template(filein.read()) d = set_parameters() - print d - with open(file_out, "w") as out: out.write(src.substitute(d)) diff --git a/deploy/nomad_consul_docker/scripts/provider.tf b/deploy/nomad_consul_docker/scripts/provider.tf index 0df2412ca44f14d2a2f03f3c3b0d41d33a9e6cb3..922c3af25a15d5f0668ef0aef8bb1e64ef9238dd 100644 --- a/deploy/nomad_consul_docker/scripts/provider.tf +++ b/deploy/nomad_consul_docker/scripts/provider.tf @@ -1,5 +1,5 @@ provider "nomad" { address = "http://localhost:4646" - secret_id = "${chomp(file("/var/nomad/token"))}" + secret_id = chomp(file("/var/nomad/token")) } diff --git a/discovery/src/asapo_discovery/common/consts.go b/discovery/src/asapo_discovery/common/consts.go index 9789e656f1b7cadca21b370582f815a6e23453bc..e43ea3b1e52bae972c34cb40e658b3d1cc99a98b 100644 --- a/discovery/src/asapo_discovery/common/consts.go +++ b/discovery/src/asapo_discovery/common/consts.go @@ -6,3 +6,4 @@ const ( NameBrokerService = "asapo-broker" NameReceiverService = "asapo-receiver" ) + diff --git a/discovery/src/asapo_discovery/go.mod b/discovery/src/asapo_discovery/go.mod index 84dadee21b1e443654a1c9aaab81842c20e29eb6..d1fbc93e8aa6557c91054b95b2925088f5a36359 100644 --- a/discovery/src/asapo_discovery/go.mod +++ b/discovery/src/asapo_discovery/go.mod @@ -6,6 +6,7 @@ replace asapo_common v0.0.0 => ../../../common/go/src/asapo_common require ( asapo_common v0.0.0 + github.com/gorilla/mux v1.8.0 github.com/hashicorp/consul/api v1.4.0 github.com/stretchr/testify v1.7.0 k8s.io/apimachinery v0.17.0 diff --git a/discovery/src/asapo_discovery/protocols/hard_coded_consumer.go b/discovery/src/asapo_discovery/protocols/hard_coded_consumer.go new file mode 100644 index 0000000000000000000000000000000000000000..15a8f7b5c89c2f31b4c029279254523aa2d0c3db --- /dev/null +++ b/discovery/src/asapo_discovery/protocols/hard_coded_consumer.go @@ -0,0 +1,14 @@ +package protocols + +func GetSupportedConsumerProtocols() []Protocol { + return []Protocol{ + Protocol{"v0.1", + map[string]string{ + "Discovery": "v0.1", + "Authorizer": "v0.1", + "Broker": "v0.1", + "File Transfer": "v0.1", + "Data cache service": "v0.1", + }, &protocolValidatorCurrent{}}, + } +} diff --git a/discovery/src/asapo_discovery/protocols/hard_coded_producer.go b/discovery/src/asapo_discovery/protocols/hard_coded_producer.go new file mode 100644 index 0000000000000000000000000000000000000000..515e242930e9c55231cb35dbc830cf25eb2180ec --- /dev/null +++ b/discovery/src/asapo_discovery/protocols/hard_coded_producer.go @@ -0,0 +1,14 @@ +package protocols + +func GetSupportedProducerProtocols() []Protocol { + return []Protocol{ + Protocol{"v0.1", + map[string]string{ + "Discovery": "v0.1", + "Receiver": "v0.1", + }, &protocolValidatorCurrent{}}, + } +} + + + diff --git a/discovery/src/asapo_discovery/protocols/protocol_test.go b/discovery/src/asapo_discovery/protocols/protocol_test.go new file mode 100644 index 0000000000000000000000000000000000000000..458ff5589920fdbbe4111689fe7fd29cec50a5fa --- /dev/null +++ b/discovery/src/asapo_discovery/protocols/protocol_test.go @@ -0,0 +1,33 @@ +package protocols + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +type protocolTest struct { + client string + protocol string + result bool + hint string + message string +} + +var protocolTests = []protocolTest{ +// consumer + {"consumer", "v0.1", true, "", "current protocol"}, + {"consumer", "v0.2", false, "unknown", "unknown protocol"}, + + +// producer + {"producer", "v0.1", true, "", "current protocol"}, + {"producer", "v0.2", false, "unknown", "unknown protocol"}, +} + +func TestProtocolTests(t *testing.T) { + for _, ct := range protocolTests { + hint, ok := ValidateProtocol(ct.client, ct.protocol) + assert.Equal(t, ct.result, ok, ct.message) + assert.Contains(t, hint, ct.hint, ct.message) + } +} diff --git a/discovery/src/asapo_discovery/protocols/protocols.go b/discovery/src/asapo_discovery/protocols/protocols.go new file mode 100644 index 0000000000000000000000000000000000000000..ada29e7f0e67348e233e8eb21f40903c0c12080a --- /dev/null +++ b/discovery/src/asapo_discovery/protocols/protocols.go @@ -0,0 +1,84 @@ +package protocols + +import "errors" + +type protocolValidator interface { + IsValid() (hint string, ok bool) +} + +type protocolValidatorCurrent struct { +} + +func (p *protocolValidatorCurrent) IsValid() (hint string, ok bool) { + return "current", true +} + +type Protocol struct { + Version string + MicroserviceAPis map[string]string + validator protocolValidator +} + +type ProtocolInfo struct { + VersionInfo string `json:"versionInfo"` + MicroservicesApi map[string]string `json:"microservicesApi"` +} + +func (p *Protocol) IsValid() (hint string, ok bool) { + return p.validator.IsValid() +} + +func (p *Protocol) GetString() string { + hint, _ := p.validator.IsValid() + if hint != "" { + return p.Version + " (" + hint + ")" + } else { + return p.Version + } +} + +func getSupportedProtocols(client string) ([]Protocol, error) { + switch client { + case "consumer": + return GetSupportedConsumerProtocols(), nil + case "producer": + return GetSupportedProducerProtocols(), nil + } + return nil, errors.New("unknown client") +} + +func FindProtocol(client string, version string) (Protocol, error) { + protocols, err := getSupportedProtocols(client) + if err != nil { + return Protocol{},err + } + for _, protocol := range protocols { + if protocol.Version == version { + return protocol,nil + } + } + return Protocol{},errors.New("unknown protocol") +} + +func ValidateProtocol(client string, version string) (hint string, ok bool) { + protocol, err := FindProtocol(client,version) + if err != nil { + return err.Error(), false + } + return protocol.IsValid() +} + +func GetSupportedProtocolsArray(client string) ([]ProtocolInfo, error) { + protocols,err := getSupportedProtocols(client) + if err!=nil { + return nil,err + } + res:=make([]ProtocolInfo,0) + for _,protocol := range protocols { + var info ProtocolInfo + info.VersionInfo = protocol.GetString() + info.MicroservicesApi = protocol.MicroserviceAPis + res = append(res, info) + } + return res,nil +} \ No newline at end of file diff --git a/discovery/src/asapo_discovery/server/get_health.go b/discovery/src/asapo_discovery/server/get_health.go new file mode 100644 index 0000000000000000000000000000000000000000..fdc697baf435f6bd7077bad2bdd7aa25284789fb --- /dev/null +++ b/discovery/src/asapo_discovery/server/get_health.go @@ -0,0 +1,9 @@ +package server + +import ( + "net/http" +) + +func routeGetHealth(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNoContent) +} diff --git a/discovery/src/asapo_discovery/server/get_health_test.go b/discovery/src/asapo_discovery/server/get_health_test.go new file mode 100644 index 0000000000000000000000000000000000000000..4d455e086fb8e9aede4d1fb6a4c1738ac244f442 --- /dev/null +++ b/discovery/src/asapo_discovery/server/get_health_test.go @@ -0,0 +1,12 @@ +package server + +import ( + "github.com/stretchr/testify/assert" + "net/http" + "testing" +) + +func TestHealth(t *testing.T) { + w := doRequest("/health") + assert.Equal(t, http.StatusNoContent, w.Code, "ok") +} diff --git a/discovery/src/asapo_discovery/server/get_receivers.go b/discovery/src/asapo_discovery/server/get_receivers.go deleted file mode 100644 index 5fed8a36aa8be5856be7bad3f700b37933ea2760..0000000000000000000000000000000000000000 --- a/discovery/src/asapo_discovery/server/get_receivers.go +++ /dev/null @@ -1,53 +0,0 @@ -package server - -import ( - "net/http" - "asapo_common/logger" - "asapo_discovery/common" -) - -func getService(service string) (answer []byte, code int) { - var err error - if (service == "asapo-receiver") { - answer, err = requestHandler.GetReceivers(settings.Receiver.UseIBAddress) - } else { - answer, err = requestHandler.GetSingleService(service) - - } - log_str := "processing get "+service - if err != nil { - logger.Error(log_str + " - " + err.Error()) - return []byte(err.Error()),http.StatusInternalServerError - } - logger.Debug(log_str + " - got " + string(answer)) - return answer, http.StatusOK -} - - -func routeGetReceivers(w http.ResponseWriter, r *http.Request) { - r.Header.Set("Content-type", "application/json") - answer,code := getService(common.NameReceiverService) - w.WriteHeader(code) - w.Write(answer) -} - -func routeGetBroker(w http.ResponseWriter, r *http.Request) { - r.Header.Set("Content-type", "application/json") - answer,code := getService(common.NameBrokerService) - w.WriteHeader(code) - w.Write(answer) -} - -func routeGetMongo(w http.ResponseWriter, r *http.Request) { - r.Header.Set("Content-type", "application/json") - answer,code := getService(common.NameMongoService) - w.WriteHeader(code) - w.Write(answer) -} - -func routeGetFileTransferService(w http.ResponseWriter, r *http.Request) { - r.Header.Set("Content-type", "application/json") - answer,code := getService(common.NameFtsService) - w.WriteHeader(code) - w.Write(answer) -} \ No newline at end of file diff --git a/discovery/src/asapo_discovery/server/get_version.go b/discovery/src/asapo_discovery/server/get_version.go new file mode 100644 index 0000000000000000000000000000000000000000..3e2abebd5afd815adb2bda77982424acff6c5992 --- /dev/null +++ b/discovery/src/asapo_discovery/server/get_version.go @@ -0,0 +1,115 @@ +package server + +import ( + "asapo_common/logger" + "asapo_common/utils" + "asapo_common/version" + "asapo_discovery/protocols" + "encoding/json" + "errors" + "net/http" +) + +type versionInfo struct { + SoftwareVersion string `json:"softwareVersion"` + ClientProtocol protocols.ProtocolInfo `json:"clientProtocol"` + ClientSupported string `json:"clientSupported"` + SupportedProtocols []protocols.ProtocolInfo `json:"supportedProtocols"` +} + +func extractProtocol(r *http.Request) (string, error) { + keys := r.URL.Query() + protocol := keys.Get("protocol") + if protocol == "" { + return "", errors.New("cannot extract protocol from request") + } + return protocol, nil +} + +func routeGetVersion(w http.ResponseWriter, r *http.Request) { + log_str := "processing get version" + logger.Debug(log_str) + + if ok := checkDiscoveryApiVersion(w, r); !ok { + return + } + keys := r.URL.Query() + client := keys.Get("client") + protocol := keys.Get("protocol") + info, err := getVersionInfo(client, protocol) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + logger.Error(log_str + " - " + err.Error()) + return + } + resp, _ := json.Marshal(&info) + w.Write(resp) +} + +func checkDiscoveryApiVersion(w http.ResponseWriter, r *http.Request) bool { + _, ok := utils.PrecheckApiVersion(w, r, version.GetDiscoveryApiVersion()) + return ok +} + +func getVersionInfo(client string, ver string) (versionInfo, error) { + info, err := getCoreInfo(client) + if err != nil { + return versionInfo{}, err + } + if ver=="" { + return info, nil + } + updateClientInfo(client, ver, &info) + return info, nil +} + +func getCoreInfo(client string) (versionInfo, error) { + var info versionInfo + info.SoftwareVersion = version.GetVersion() + if client=="" { + return info, nil + } + var err error + info.SupportedProtocols, err = protocols.GetSupportedProtocolsArray(client) + if err != nil { + return versionInfo{}, err + } + return info, nil +} + +func updateClientInfo(client string, ver string, info *versionInfo) { + if client == "" { + return + } + pInfo,valid := getProtocolInfo(client, ver, info) + setSupported(valid, info) + if client == "consumer" { + info.ClientProtocol = pInfo + } else + if client == "producer" { + info.ClientProtocol = pInfo + } +} + +func setSupported(valid bool, info *versionInfo) { + if valid { + info.ClientSupported = "yes" + } else { + info.ClientSupported = "no" + } +} + +func getProtocolInfo(client string, ver string, info *versionInfo) (pInfo protocols.ProtocolInfo, valid bool) { + protocol, err := protocols.FindProtocol(client, ver) + if err != nil { + pInfo.VersionInfo = ver + " (" + err.Error() + ")" + valid = false + } else { + var hint string + hint, valid = protocol.IsValid() + pInfo.VersionInfo = ver + " (" + hint + ")" + pInfo.MicroservicesApi = protocol.MicroserviceAPis + } + return +} diff --git a/discovery/src/asapo_discovery/server/get_version_test.go b/discovery/src/asapo_discovery/server/get_version_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5a1e99c8a159a36b9c884b51b83a8d97d11c851e --- /dev/null +++ b/discovery/src/asapo_discovery/server/get_version_test.go @@ -0,0 +1,69 @@ +package server + +import ( + "asapo_common/version" + "asapo_discovery/protocols" + "encoding/json" + "fmt" + "github.com/stretchr/testify/assert" + "net/http" + "testing" +) + +var coreVer = version.GetVersion() + +var versionTests = []struct { + request string + result versionInfo + code int + message string +}{ + {"", versionInfo{ + SoftwareVersion: coreVer, + ClientProtocol: protocols.ProtocolInfo{}, + ClientSupported: "", + }, http.StatusOK, "no client"}, + {"?client=consumer", versionInfo{ + SoftwareVersion: coreVer, + ClientProtocol: protocols.ProtocolInfo{"", nil}, + ClientSupported: "no", + }, http.StatusOK, "consumer client, no protocol"}, + + {"?client=consumer&protocol=v0.1", versionInfo{ + SoftwareVersion: coreVer, + ClientProtocol: protocols.ProtocolInfo{"v0.1 (current)", + map[string]string{"Authorizer":"v0.1", "Broker":"v0.1", "Data cache service":"v0.1", "Discovery":"v0.1", "File Transfer":"v0.1"}}, + ClientSupported: "yes", + }, http.StatusOK, "consumer client"}, + {"?client=producer&protocol=v0.1", versionInfo{ + SoftwareVersion: coreVer, + ClientProtocol: protocols.ProtocolInfo{"v0.1 (current)",map[string]string{"Discovery":"v0.1", "Receiver":"v0.1"}}, + ClientSupported: "yes", + }, http.StatusOK, "producer client"}, + {"?client=producer&protocol=v0.2", versionInfo{ + SoftwareVersion: coreVer, + ClientProtocol: protocols.ProtocolInfo{"v0.2 (unknown protocol)",nil}, + ClientSupported: "no", + }, http.StatusOK, "producer client unknown"}, +} + +func TestVersionTests(t *testing.T) { + for _, test := range versionTests { + w := doRequest("/" + version.GetDiscoveryApiVersion() + "/version" + test.request) + assert.Equal(t, test.code, w.Code, test.message) + if test.code == http.StatusOK { + var info versionInfo + json.Unmarshal(w.Body.Bytes(), &info) + fmt.Println(w.Body.String()) + assert.Equal(t, test.result.ClientProtocol,info.ClientProtocol, test.message) + if test.message!="no client" { + assert.Equal(t, true,len(info.SupportedProtocols)>0, test.message) + } + } + } +} + +func TestVersionTestsWrongApi(t *testing.T) { + w := doRequest("/v2.0/version") + assert.Equal(t, http.StatusUnsupportedMediaType, w.Code, "wrong api") +} diff --git a/discovery/src/asapo_discovery/server/listroutes.go b/discovery/src/asapo_discovery/server/listroutes.go index ec6ae17371a6f688925c8a05614855a9d7f248a1..88c566d79e480a08e97a6470cb554ef6a0aa3fdc 100644 --- a/discovery/src/asapo_discovery/server/listroutes.go +++ b/discovery/src/asapo_discovery/server/listroutes.go @@ -9,13 +9,13 @@ var listRoutes = utils.Routes{ utils.Route{ "GetReceivers", "Get", - "/" + common.NameReceiverService, + "/{apiver}/" + common.NameReceiverService, routeGetReceivers, }, utils.Route{ "GetBroker", "Get", - "/asapo-broker", + "/{apiver}/"+common.NameBrokerService, routeGetBroker, }, utils.Route{ @@ -24,10 +24,23 @@ var listRoutes = utils.Routes{ "/" + common.NameMongoService, routeGetMongo, }, + utils.Route{ + "GetVersion", + "Get", + "/{apiver}/version", + routeGetVersion, + }, utils.Route{ "GetFTS", "Get", - "/" + common.NameFtsService, + "/{apiver}/" + common.NameFtsService, routeGetFileTransferService, }, + utils.Route{ + "Health", + "Get", + "/health", + routeGetHealth, + }, + } diff --git a/discovery/src/asapo_discovery/server/routes.go b/discovery/src/asapo_discovery/server/routes.go new file mode 100644 index 0000000000000000000000000000000000000000..d918a8adb6db7208fe001f2bb4df96e94ea7bd06 --- /dev/null +++ b/discovery/src/asapo_discovery/server/routes.go @@ -0,0 +1,90 @@ +package server + +import ( + "asapo_discovery/protocols" + "net/http" + "asapo_common/logger" + "asapo_discovery/common" +) + +func getService(service string) (answer []byte, code int) { + var err error + if service == "asapo-receiver" { + answer, err = requestHandler.GetReceivers(settings.Receiver.UseIBAddress) + } else { + answer, err = requestHandler.GetSingleService(service) + + } + log_str := "processing get " + service + if err != nil { + logger.Error(log_str + " - " + err.Error()) + return []byte(err.Error()), http.StatusInternalServerError + } + logger.Debug(log_str + " - got " + string(answer)) + return answer, http.StatusOK +} + +func validateProtocol(w http.ResponseWriter, r *http.Request, client string) bool { + protocol, err := extractProtocol(r) + log_str := "validating " + client + " protocol" + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + logger.Error(log_str + " - " + err.Error()) + return false + } + if hint, ok := protocols.ValidateProtocol(client, protocol); !ok { + w.WriteHeader(http.StatusUnsupportedMediaType) + w.Write([]byte(hint)) + logger.Error(log_str + " - " + hint) + return false + } + logger.Debug(log_str + " - ok") + return true +} + +func routeGetReceivers(w http.ResponseWriter, r *http.Request) { + if ok := checkDiscoveryApiVersion(w, r); !ok { + return + } + + if !validateProtocol(w, r, "producer") { + return + } + answer, code := getService(common.NameReceiverService) + w.WriteHeader(code) + w.Write(answer) +} + +func routeGetBroker(w http.ResponseWriter, r *http.Request) { + if ok := checkDiscoveryApiVersion(w, r); !ok { + return + } + + if !validateProtocol(w, r, "consumer") { + return + } + + answer, code := getService(common.NameBrokerService) + w.WriteHeader(code) + w.Write(answer) +} + +func routeGetMongo(w http.ResponseWriter, r *http.Request) { + answer, code := getService(common.NameMongoService) + w.WriteHeader(code) + w.Write(answer) +} + +func routeGetFileTransferService(w http.ResponseWriter, r *http.Request) { + if ok := checkDiscoveryApiVersion(w, r); !ok { + return + } + if !validateProtocol(w, r, "consumer") { + return + } + + answer, code := getService(common.NameFtsService) + w.WriteHeader(code) + w.Write(answer) +} diff --git a/discovery/src/asapo_discovery/server/routes_test.go b/discovery/src/asapo_discovery/server/routes_test.go index f15fb60704580489017776c1ef40916eb669c892..e72d0c55abfba927659cf6e56f651046b504e2a0 100644 --- a/discovery/src/asapo_discovery/server/routes_test.go +++ b/discovery/src/asapo_discovery/server/routes_test.go @@ -1,6 +1,7 @@ package server import ( + "asapo_common/version" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" "asapo_common/logger" @@ -31,9 +32,9 @@ type GetServicesTestSuite struct { func (suite *GetServicesTestSuite) SetupTest() { requestHandler = new(request_handler.StaticRequestHandler) - var s common.Settings= common.Settings{Receiver:common.ReceiverInfo{MaxConnections:10,StaticEndpoints:[]string{"ip1","ip2"}}, - Broker:common.BrokerInfo{StaticEndpoint:"ip_broker"},Mongo:common.MongoInfo{StaticEndpoint:"ip_mongo"}, - FileTransferService:common.FtsInfo{StaticEndpoint:"ip_fts"}} + var s common.Settings = common.Settings{Receiver: common.ReceiverInfo{MaxConnections: 10, StaticEndpoints: []string{"ip1", "ip2"}}, + Broker: common.BrokerInfo{StaticEndpoint: "ip_broker"}, Mongo: common.MongoInfo{StaticEndpoint: "ip_mongo"}, + FileTransferService: common.FtsInfo{StaticEndpoint: "ip_fts"}} requestHandler.Init(s) logger.SetMockLog() @@ -58,27 +59,63 @@ func (suite *GetServicesTestSuite) TestWrongPath() { suite.Equal(http.StatusNotFound, w.Code, "wrong path") } -func (suite *GetServicesTestSuite) TestGetReceivers() { - logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameReceiverService))) - - w := doRequest("/asapo-receiver") - - suite.Equal(http.StatusOK, w.Code, "code ok") - suite.Equal(w.Body.String(), "{\"MaxConnections\":10,\"Uris\":[\"ip1\",\"ip2\"]}", "result") - assertExpectations(suite.T()) +type requestTest struct { +request string +code int +message string } +var receiverTests = []requestTest { + {"/" + version.GetDiscoveryApiVersion()+"/asapo-receiver",http.StatusBadRequest,"protocol missing"}, + {"/" + version.GetDiscoveryApiVersion()+"/asapo-receiver?protocol=v0.2",http.StatusUnsupportedMediaType,"wrong protocol"}, + {"/" + version.GetDiscoveryApiVersion()+"/asapo-receiver?protocol=v0.1",http.StatusOK,"ok"}, +} -func (suite *GetServicesTestSuite) TestGetBroker() { - logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameBrokerService))) +func (suite *GetServicesTestSuite) TestGetReceivers() { + for _,test:= range receiverTests { + if test.code == http.StatusOK { + logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("validating producer"))) + logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameReceiverService))) + } else { + logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("validating producer"))) + } + + w := doRequest(test.request) + + suite.Equal(test.code, w.Code, test.message) + if test.code == http.StatusOK { + suite.Equal(w.Body.String(), "{\"MaxConnections\":10,\"Uris\":[\"ip1\",\"ip2\"]}", "result") + } + assertExpectations(suite.T()) + } - w := doRequest("/asapo-broker") +} - suite.Equal(http.StatusOK, w.Code, "code ok") - suite.Equal(w.Body.String(), "ip_broker", "result") - assertExpectations(suite.T()) +var brokerTests = []requestTest { + {"/" + version.GetDiscoveryApiVersion()+"/asapo-broker",http.StatusBadRequest,"protocol missing"}, + {"/" + version.GetDiscoveryApiVersion()+"/asapo-broker?protocol=v0.2",http.StatusUnsupportedMediaType,"wrong protocol"}, + {"/" + version.GetDiscoveryApiVersion()+"/asapo-broker?protocol=v0.1",http.StatusOK,"ok"}, +} +func (suite *GetServicesTestSuite) TestGetBroker() { + for _,test:= range brokerTests { + if test.code == http.StatusOK { + logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("validating consumer"))) + logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameBrokerService))) + } else { + logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("validating consumer"))) + } + + w := doRequest(test.request) + + suite.Equal(test.code, w.Code, test.message) + if test.code == http.StatusOK { + suite.Equal(w.Body.String(), "ip_broker", "result") + } + assertExpectations(suite.T()) + } } + func (suite *GetServicesTestSuite) TestGetMongo() { logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameMongoService))) @@ -91,10 +128,23 @@ func (suite *GetServicesTestSuite) TestGetMongo() { func (suite *GetServicesTestSuite) TestGetFts() { logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameFtsService))) + logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("validating"))) - w := doRequest("/asapo-file-transfer") + w := doRequest("/" + version.GetDiscoveryApiVersion()+"/asapo-file-transfer?protocol=v0.1") suite.Equal(http.StatusOK, w.Code, "code ok") suite.Equal(w.Body.String(), "ip_fts", "result") assertExpectations(suite.T()) } + +func (suite *GetServicesTestSuite) TestGetVersions() { + logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get version"))) + + w := doRequest("/" + version.GetDiscoveryApiVersion() + "/version") + + suite.Equal(http.StatusOK, w.Code, "code ok") + // we dont really check what it returns, just that route is ok + suite.Contains(w.Body.String(), version.GetVersion(), "core version") + suite.Contains(w.Body.String(), "supportedProtocols", "protocols") + assertExpectations(suite.T()) +} diff --git a/examples/consumer/getnext/check_linux.sh b/examples/consumer/getnext/check_linux.sh index a8c0ec75089eeff7ab9ca5049ea4dbbc530abd27..2c853792cf60bc9a171c6664a2a695ca71c0791f 100644 --- a/examples/consumer/getnext/check_linux.sh +++ b/examples/consumer/getnext/check_linux.sh @@ -17,7 +17,7 @@ Cleanup() { nomad stop discovery nomad stop authorizer nomad stop broker - echo "db.dropDatabase()" | mongo ${database_name} + echo "db.dropDatabase()" | mongo ${database_name} } nomad run nginx.nmd diff --git a/examples/consumer/getnext/getnext.cpp b/examples/consumer/getnext/getnext.cpp index 5e90a3885be448262e12bbd099278deb62eb6f8b..d30e87e578210fb3776e34c18c1fd4d332ad321b 100644 --- a/examples/consumer/getnext/getnext.cpp +++ b/examples/consumer/getnext/getnext.cpp @@ -19,6 +19,7 @@ std::mutex lock; uint64_t file_size = 0; + inline std::string ConnectionTypeToString(asapo::NetworkConnectionType type) { switch (type) { case asapo::NetworkConnectionType::kUndefined: @@ -119,6 +120,7 @@ StartThreads(const Args& params, std::vector<int>* nfiles, std::vector<int>* err if (err) { (*errors)[i] += ProcessError(err); lock.unlock(); + exit(EXIT_FAILURE); return; } } @@ -263,7 +265,6 @@ void TryGetStream(Args* args) { } int main(int argc, char* argv[]) { - asapo::ExitAfterPrintVersionIfNeeded("GetNext consumer Example", argc, argv); Args params; params.datasets = false; if (argc != 8 && argc != 9) { diff --git a/examples/pipeline/in_to_out/in_to_out.cpp b/examples/pipeline/in_to_out/in_to_out.cpp index 801d9f32a0653776f4a2093a2a3d545bcad19dc3..e96985a02266e9a7e5fa3bde748e0ba6361e3478 100644 --- a/examples/pipeline/in_to_out/in_to_out.cpp +++ b/examples/pipeline/in_to_out/in_to_out.cpp @@ -206,7 +206,6 @@ std::unique_ptr<asapo::Producer> CreateProducer(const Args &args) { } int main(int argc, char* argv[]) { - asapo::ExitAfterPrintVersionIfNeeded("GetNext consumer Example", argc, argv); Args args; if (argc != 11) { std::cout << "Usage: " + std::string{argv[0]} diff --git a/examples/producer/dummy-data-producer/dummy_data_producer.cpp b/examples/producer/dummy-data-producer/dummy_data_producer.cpp index d983f01e2d419a5b5ca0356e746d4a64d16b54be..560cd20ba6b9f89aa52d40deae4cab08319f2666 100644 --- a/examples/producer/dummy-data-producer/dummy_data_producer.cpp +++ b/examples/producer/dummy-data-producer/dummy_data_producer.cpp @@ -69,7 +69,6 @@ void TryGetDataSourceAndToken(Args* args) { void ProcessCommandArguments(int argc, char* argv[], Args* args) { - asapo::ExitAfterPrintVersionIfNeeded("Dummy Data Producer", argc, argv); if (argc != 8 && argc != 9) { std::cout << "Usage: " << argv[0] << diff --git a/file_transfer/src/asapo_file_transfer/server/listroutes.go b/file_transfer/src/asapo_file_transfer/server/listroutes.go index 03fba92d86e41b3418eba91878c4253cb5ffb2f0..54188582ae387e1c61118539ad835eebba1ed36d 100644 --- a/file_transfer/src/asapo_file_transfer/server/listroutes.go +++ b/file_transfer/src/asapo_file_transfer/server/listroutes.go @@ -8,7 +8,7 @@ var listRoutes = utils.Routes{ utils.Route{ "Transfer File", "POST", - "/transfer", + "/{apiver}/transfer", routeFileTransfer, }, utils.Route{ diff --git a/file_transfer/src/asapo_file_transfer/server/transfer.go b/file_transfer/src/asapo_file_transfer/server/transfer.go index 18b172a8e232472bfb55495f0d88886b2e43d733..8e6817007b75dc25ab7b589814c13a0788ea42f6 100644 --- a/file_transfer/src/asapo_file_transfer/server/transfer.go +++ b/file_transfer/src/asapo_file_transfer/server/transfer.go @@ -4,6 +4,7 @@ import ( log "asapo_common/logger" "asapo_common/structs" "asapo_common/utils" + "asapo_common/version" "encoding/json" "errors" "net/http" @@ -88,7 +89,17 @@ func serveFileSize(w http.ResponseWriter, r *http.Request, fullName string) { w.Write(b) } + +func checkFtsApiVersion(w http.ResponseWriter, r *http.Request) bool { + _, ok := utils.PrecheckApiVersion(w, r, version.GetFtsApiVersion()) + return ok +} + func routeFileTransfer(w http.ResponseWriter, r *http.Request) { + if ok := checkFtsApiVersion(w, r); !ok { + return + } + fullName, status,err := checkRequest(r); if err != nil { utils.WriteServerError(w,err,status) diff --git a/file_transfer/src/asapo_file_transfer/server/transfer_test.go b/file_transfer/src/asapo_file_transfer/server/transfer_test.go index 815d4b48a0b7408f43c45c39e777b835f8bd95ee..378426407d26265af17b2ee6e522d023a540b207 100644 --- a/file_transfer/src/asapo_file_transfer/server/transfer_test.go +++ b/file_transfer/src/asapo_file_transfer/server/transfer_test.go @@ -72,7 +72,7 @@ func TestTransferFile(t *testing.T) { for _, test := range transferFileTests { request := makeRequest(fileTransferRequest{test.folder,test.fname}) - w := doPostRequest("/transfer",request,test.token) + w := doPostRequest("/v0.1/transfer",request,test.token) if test.status==http.StatusOK { body, _ := ioutil.ReadAll(w.Body) body_str:=string(body) @@ -92,7 +92,7 @@ func TestTransferFileSize(t *testing.T) { test:=transferFileTests[0] request := makeRequest(fileTransferRequest{test.folder,test.fname}) - w := doPostRequest("/transfer?sizeonly=true",request,test.token) + w := doPostRequest("/v0.1/transfer?sizeonly=true",request,test.token) if test.status==http.StatusOK { body, _ := ioutil.ReadAll(w.Body) body_str:=string(body) @@ -101,3 +101,11 @@ func TestTransferFileSize(t *testing.T) { } assert.Equal(t, test.status, w.Code, test.message) } + + +func TestTransferWrongApiVersion(t *testing.T) { + request := makeRequest(fileTransferRequest{"folder","fname"}) + token := prepareToken("folder") + w := doPostRequest("/v0.2/transfer?sizeonly=true",request,token) + assert.Equal(t, http.StatusUnsupportedMediaType, w.Code, "wrong api version") +} diff --git a/producer/api/cpp/CMakeLists.txt b/producer/api/cpp/CMakeLists.txt index 896c05265d55a5b9c9cea5fbfc75fc877d8716d0..24b5722350e4392b898e3d4b350055184c8b8c4b 100644 --- a/producer/api/cpp/CMakeLists.txt +++ b/producer/api/cpp/CMakeLists.txt @@ -14,7 +14,7 @@ set(SOURCE_FILES # Library ################################ add_library(${TARGET_NAME} STATIC ${SOURCE_FILES} $<TARGET_OBJECTS:system_io> $<TARGET_OBJECTS:logger> $<TARGET_OBJECTS:json_parser> - $<TARGET_OBJECTS:curl_http_client> $<TARGET_OBJECTS:request_pool> $<TARGET_OBJECTS:data_structs>) + $<TARGET_OBJECTS:curl_http_client> $<TARGET_OBJECTS:request_pool> $<TARGET_OBJECTS:data_structs> $<TARGET_OBJECTS:version>) target_include_directories(${TARGET_NAME} PUBLIC include ${ASAPO_CXX_COMMON_INCLUDE_DIR}) target_link_libraries(${TARGET_NAME} ${CURL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) diff --git a/producer/api/cpp/include/asapo/asapo_producer.h b/producer/api/cpp/include/asapo/asapo_producer.h index 1e5ea176cd474cfb25e98e0523ea16ee0ac0418b..152abe230de7e0fe2f7604c55d0f7f3885fccb76 100644 --- a/producer/api/cpp/include/asapo/asapo_producer.h +++ b/producer/api/cpp/include/asapo/asapo_producer.h @@ -2,7 +2,6 @@ #define ASAPO_ASAPO_PRODUCER_H #include "asapo/common/io_error.h" -#include "asapo/common/version.h" #include "asapo/producer/producer.h" #include "asapo/producer/producer_error.h" diff --git a/producer/api/cpp/include/asapo/producer/producer.h b/producer/api/cpp/include/asapo/producer/producer.h index c8de7d637ff86f09f2f976e52f792e23a54cc816..a2fde18ebeeb2f3ae0a02784bf6f5ccf39382bc3 100644 --- a/producer/api/cpp/include/asapo/producer/producer.h +++ b/producer/api/cpp/include/asapo/producer/producer.h @@ -23,6 +23,15 @@ class Producer { virtual ~Producer() = default; + //! Return version + /*! + \param client_info - for client version + \param server_info - for server + \param supported - set to true if client is supported by server + \return nullptr of command was successful, otherwise error. + */ + virtual Error GetVersionInfo(std::string* client_info,std::string* server_info, bool* supported) const = 0; + //! Get stream information from receiver /*! \param stream - stream to send messages to diff --git a/producer/api/cpp/include/asapo/producer/producer_error.h b/producer/api/cpp/include/asapo/producer/producer_error.h index 1d1e0904f91f7be183e8dd55545a0cbca8281ba1..6f8e66ea926a60bbba909809893e350171c2637e 100644 --- a/producer/api/cpp/include/asapo/producer/producer_error.h +++ b/producer/api/cpp/include/asapo/producer/producer_error.h @@ -13,6 +13,7 @@ enum class ProducerErrorType { kWrongInput, kServerWarning, kReAuthorizationNeeded, + kUnsupportedClient, kTimeout }; @@ -54,6 +55,12 @@ auto const kReAuthorizationNeeded = ProducerErrorTemplate { "reauthorization needed", ProducerErrorType::kReAuthorizationNeeded }; +auto const kUnsupportedClient = ProducerErrorTemplate { + "cannot connect to asapo", ProducerErrorType::kUnsupportedClient +}; + + + }; diff --git a/producer/api/cpp/src/producer_impl.cpp b/producer/api/cpp/src/producer_impl.cpp index cba069bb723f350b3713166b27c00208af13671b..2a4d38a5b11699300300d77e93db4992ae84ce23 100644 --- a/producer/api/cpp/src/producer_impl.cpp +++ b/producer/api/cpp/src/producer_impl.cpp @@ -1,16 +1,16 @@ #include <iostream> -#include <iostream> #include <cstring> #include <future> #include "producer_impl.h" #include "producer_logger.h" -#include "asapo/io/io_factory.h" #include "asapo/producer/producer_error.h" #include "producer_request_handler_factory.h" #include "producer_request.h" #include "asapo/common/data_structs.h" #include "asapo/request/request_pool_error.h" +#include "asapo/http_client/http_client.h" +#include "asapo/common/internal/version.h" namespace asapo { @@ -18,7 +18,7 @@ const size_t ProducerImpl::kDiscoveryServiceUpdateFrequencyMs = 10000; // 10s ProducerImpl::ProducerImpl(std::string endpoint, uint8_t n_processing_threads, uint64_t timeout_ms, asapo::RequestHandlerType type): - log__{GetDefaultProducerLogger()}, timeout_ms_{timeout_ms} { + log__{GetDefaultProducerLogger()},httpclient__{DefaultHttpClient()}, timeout_ms_{timeout_ms},endpoint_{endpoint} { switch (type) { case RequestHandlerType::kTcp: discovery_service_.reset(new ReceiverDiscoveryService{endpoint, ProducerImpl::kDiscoveryServiceUpdateFrequencyMs}); @@ -392,5 +392,32 @@ void ProducerImpl::SetRequestsQueueLimits(uint64_t size, uint64_t volume) { request_pool__->SetLimits(RequestPoolLimits{size,volume}); } +Error ProducerImpl::GetVersionInfo(std::string* client_info, std::string* server_info, bool* supported) const { + if (client_info == nullptr && server_info == nullptr && supported == nullptr) { + return ProducerErrorTemplates::kWrongInput.Generate("missing parameters"); + } + if (client_info != nullptr) { + *client_info = + "software version: " + std::string(kVersion) + ", producer protocol: " + kProducerProtocol.GetVersion(); + } + + if (server_info != nullptr || supported != nullptr) { + return GetServerVersionInfo(server_info, supported); + } + return nullptr; +} + +Error ProducerImpl::GetServerVersionInfo(std::string* server_info, + bool* supported) const { + auto endpoint = endpoint_ +"/asapo-discovery/"+kProducerProtocol.GetDiscoveryVersion()+ + "/version?client=producer&protocol="+kProducerProtocol.GetVersion(); + HttpCode code; + Error err; + auto response = httpclient__->Get(endpoint, &code, &err); + if (err) { + return err; + } + return ExtractVersionFromResponse(response,"producer",server_info,supported); +} } \ No newline at end of file diff --git a/producer/api/cpp/src/producer_impl.h b/producer/api/cpp/src/producer_impl.h index a60b59c7dfd0a49b43f2757c782917ab3262a1e2..53fda3df0a07508efce6dc7f7ef891af2601bf4a 100644 --- a/producer/api/cpp/src/producer_impl.h +++ b/producer/api/cpp/src/producer_impl.h @@ -30,6 +30,9 @@ class ProducerImpl : public Producer { ProducerImpl(const ProducerImpl &) = delete; ProducerImpl &operator=(const ProducerImpl &) = delete; + + Error GetVersionInfo(std::string* client_info,std::string* server_info, bool* supported) const override; + StreamInfo GetStreamInfo(std::string stream, uint64_t timeout_ms, Error* err) const override; StreamInfo GetLastStream(uint64_t timeout_ms, Error* err) const override; @@ -56,6 +59,7 @@ class ProducerImpl : public Producer { RequestCallback callback) override; AbstractLogger* log__; + std::unique_ptr<HttpClient> httpclient__; std::unique_ptr<RequestPool> request_pool__; Error SetCredentials(SourceCredentials source_cred) override; @@ -74,6 +78,9 @@ class ProducerImpl : public Producer { uint64_t ingest_mode); std::string source_cred_string_; uint64_t timeout_ms_; + std::string endpoint_; + Error GetServerVersionInfo(std::string* server_info, + bool* supported) const; }; struct StreamInfoResult { diff --git a/producer/api/cpp/src/producer_request.cpp b/producer/api/cpp/src/producer_request.cpp index 73a64c2a61052aae9d9cc68f4c717b77591e99ef..7d41d0d44c1311674214c1d72bf72e0955d5f044 100644 --- a/producer/api/cpp/src/producer_request.cpp +++ b/producer/api/cpp/src/producer_request.cpp @@ -1,5 +1,6 @@ #include <asapo/asapo_producer.h> #include "producer_request.h" +#include "asapo/common/internal/version.h" namespace asapo { @@ -24,6 +25,13 @@ ProducerRequest::ProducerRequest(std::string source_credentials, original_filepath{std::move(original_filepath)}, callback{callback}, manage_data_memory{manage_data_memory} { + + if (kProducerProtocol.GetReceiverVersion().size()<kMaxVersionSize) { + strcpy(header.api_version, kProducerProtocol.GetReceiverVersion().c_str()); + } else { + strcpy(header.api_version, "v0.0"); + } + } bool ProducerRequest::NeedSend() const { diff --git a/producer/api/cpp/src/receiver_discovery_service.cpp b/producer/api/cpp/src/receiver_discovery_service.cpp index 69b6ace5338ae8ec7d07114c85feb9b99a1c060a..b1130b7ec6043a9635c2336c57de719967e48eda 100644 --- a/producer/api/cpp/src/receiver_discovery_service.cpp +++ b/producer/api/cpp/src/receiver_discovery_service.cpp @@ -1,15 +1,17 @@ #include "receiver_discovery_service.h" -#include "producer_logger.h" -#include "asapo/json_parser/json_parser.h" - #include <iostream> #include <algorithm> #include <numeric> +#include "producer_logger.h" +#include "asapo/json_parser/json_parser.h" +#include "asapo/common/internal/version.h" + namespace asapo { -const std::string ReceiverDiscoveryService::kServiceEndpointSuffix = "/asapo-discovery/asapo-receiver"; +const std::string ReceiverDiscoveryService::kServiceEndpointSuffix = "/asapo-discovery/"+kProducerProtocol.GetDiscoveryVersion() + +"/asapo-receiver?protocol="+kConsumerProtocol.GetVersion(); ReceiverDiscoveryService::ReceiverDiscoveryService(std::string endpoint, uint64_t update_frequency_ms): httpclient__{DefaultHttpClient()}, log__{GetDefaultProducerLogger()}, diff --git a/producer/api/cpp/src/request_handler_tcp.cpp b/producer/api/cpp/src/request_handler_tcp.cpp index e6f105d0150499ad74f665b16610710c97153df0..85895cfd06c37dcd4257ad88c2c6bbf1d5be75e4 100644 --- a/producer/api/cpp/src/request_handler_tcp.cpp +++ b/producer/api/cpp/src/request_handler_tcp.cpp @@ -7,16 +7,19 @@ namespace asapo { RequestHandlerTcp::RequestHandlerTcp(ReceiverDiscoveryService* discovery_service, uint64_t thread_id, - uint64_t* shared_counter): - io__{GenerateDefaultIO()}, log__{GetDefaultProducerLogger()}, discovery_service__{discovery_service}, thread_id_{thread_id}, + uint64_t* shared_counter) : + io__{GenerateDefaultIO()}, + log__{GetDefaultProducerLogger()}, + discovery_service__{discovery_service}, + thread_id_{thread_id}, ncurrent_connections_{shared_counter} { } -Error RequestHandlerTcp::Authorize(const std::string& source_credentials) { +Error RequestHandlerTcp::Authorize(const std::string &source_credentials) { GenericRequestHeader header{kOpcodeAuthorize, 0, 0, source_credentials.size(), ""}; Error err; io__->Send(sd_, &header, sizeof(header), &err); - if(err) { + if (err) { return err; } @@ -28,12 +31,11 @@ Error RequestHandlerTcp::Authorize(const std::string& source_credentials) { return ReceiveResponse(header, nullptr); } - -Error RequestHandlerTcp::ConnectToReceiver(const std::string& source_credentials, const std::string& receiver_address) { +Error RequestHandlerTcp::ConnectToReceiver(const std::string &source_credentials, const std::string &receiver_address) { Error err; sd_ = io__->CreateAndConnectIPTCPSocket(receiver_address, &err); - if(err != nullptr) { + if (err != nullptr) { log__->Debug("cannot connect to receiver at " + receiver_address + " - " + err->Explain()); return err; } @@ -55,11 +57,10 @@ Error RequestHandlerTcp::ConnectToReceiver(const std::string& source_credentials Error RequestHandlerTcp::SendRequestContent(const ProducerRequest* request) { Error io_error; io__->Send(sd_, &(request->header), sizeof(request->header), &io_error); - if(io_error) { + if (io_error) { return io_error; } - if (request->NeedSendMetaData()) { io__->Send(sd_, (void*) request->metadata.c_str(), (size_t) request->header.meta_size, &io_error); if (io_error) { @@ -69,9 +70,9 @@ Error RequestHandlerTcp::SendRequestContent(const ProducerRequest* request) { if (request->NeedSend()) { if (request->DataFromFile()) { - io_error = io__->SendFile(sd_, request->original_filepath, (size_t)request->header.data_size); + io_error = io__->SendFile(sd_, request->original_filepath, (size_t) request->header.data_size); } else { - io__->Send(sd_, (void*) request->data.get(), (size_t)request->header.data_size, &io_error); + io__->Send(sd_, (void*) request->data.get(), (size_t) request->header.data_size, &io_error); } if (io_error) { return io_error; @@ -81,65 +82,69 @@ Error RequestHandlerTcp::SendRequestContent(const ProducerRequest* request) { return nullptr; } -Error RequestHandlerTcp::ReceiveResponse(const GenericRequestHeader& request_header, std::string* response) { +Error RequestHandlerTcp::ReceiveResponse(const GenericRequestHeader &request_header, std::string* response) { Error err; SendResponse sendDataResponse; io__->Receive(sd_, &sendDataResponse, sizeof(sendDataResponse), &err); - if(err != nullptr) { + if (err != nullptr) { return err; } switch (sendDataResponse.error_code) { - case kNetAuthorizationError : { - auto res_err = ProducerErrorTemplates::kWrongInput.Generate(); - res_err->Append(sendDataResponse.message); - return res_err; - } - case kNetErrorWrongRequest : { - auto res_err = ProducerErrorTemplates::kWrongInput.Generate(); - res_err->Append(sendDataResponse.message); - return res_err; - } - case kNetErrorWarning: { - auto res_err = ProducerErrorTemplates::kServerWarning.Generate(); - res_err->Append(sendDataResponse.message); - return res_err; - } - case kNetErrorReauthorize: { - auto res_err = ProducerErrorTemplates::kReAuthorizationNeeded.Generate(); - return res_err; - } - case kNetErrorNoError : - if (response) { - *response = sendDataResponse.message; + case kNetAuthorizationError : { + auto res_err = ProducerErrorTemplates::kWrongInput.Generate(); + res_err->Append(sendDataResponse.message); + return res_err; + } + case kNetErrorNotSupported : { + auto res_err = ProducerErrorTemplates::kUnsupportedClient.Generate(); + res_err->Append(sendDataResponse.message); + return res_err; + } + case kNetErrorWrongRequest : { + auto res_err = ProducerErrorTemplates::kWrongInput.Generate(); + res_err->Append(sendDataResponse.message); + return res_err; } - return nullptr; - default: - auto res_err = ProducerErrorTemplates::kInternalServerError.Generate(); - res_err->Append(sendDataResponse.message); - return res_err; + case kNetErrorWarning: { + auto res_err = ProducerErrorTemplates::kServerWarning.Generate(); + res_err->Append(sendDataResponse.message); + return res_err; + } + case kNetErrorReauthorize: { + auto res_err = ProducerErrorTemplates::kReAuthorizationNeeded.Generate(); + return res_err; + } + case kNetErrorNoError : + if (response) { + *response = sendDataResponse.message; + } + return nullptr; + default:auto res_err = ProducerErrorTemplates::kInternalServerError.Generate(); + res_err->Append(sendDataResponse.message); + return res_err; } } Error RequestHandlerTcp::TrySendToReceiver(const ProducerRequest* request, std::string* response) { auto err = SendRequestContent(request); - if (err) { + if (err) { return err; } err = ReceiveResponse(request->header, response); - if (err == nullptr || err == ProducerErrorTemplates::kServerWarning) { + if (err == nullptr || err == ProducerErrorTemplates::kServerWarning) { log__->Debug("successfully sent data, opcode: " + std::to_string(request->header.op_code) + - ", id: " + std::to_string(request->header.data_id) + " to " + connected_receiver_uri_); - if (err == ProducerErrorTemplates::kServerWarning ) { - log__->Warning("warning from server for id " + std::to_string(request->header.data_id) + ": " + err->Explain()); + ", id: " + std::to_string(request->header.data_id) + " to " + connected_receiver_uri_); + if (err == ProducerErrorTemplates::kServerWarning) { + log__->Warning( + "warning from server for id " + std::to_string(request->header.data_id) + ": " + err->Explain()); } } return err; } - void RequestHandlerTcp::UpdateIfNewConnection() { if (Connected()) return; @@ -158,17 +163,15 @@ bool RequestHandlerTcp::UpdateReceiversList() { } bool RequestHandlerTcp::TimeToUpdateReceiverList() { - uint64_t elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>( system_clock::now() - - last_receivers_uri_update_).count(); + uint64_t elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(system_clock::now() - + last_receivers_uri_update_).count(); return elapsed_ms > discovery_service__->UpdateFrequency(); } - bool RequestHandlerTcp::Disconnected() { return !Connected(); } - bool RequestHandlerTcp::NeedRebalance() { if (Disconnected()) return false; @@ -192,23 +195,24 @@ void RequestHandlerTcp::Disconnect() { connected_receiver_uri_.clear(); } -bool RequestHandlerTcp::ServerError(const Error& err) { +bool RequestHandlerTcp::ServerError(const Error &err) { return err != nullptr && (err != ProducerErrorTemplates::kWrongInput && - err != ProducerErrorTemplates::kLocalIOError && - err != ProducerErrorTemplates::kServerWarning - ); + err != ProducerErrorTemplates::kLocalIOError && + err != ProducerErrorTemplates::kUnsupportedClient && + err != ProducerErrorTemplates::kServerWarning + ); } -bool RequestHandlerTcp::ProcessErrorFromReceiver(const Error& error, +bool RequestHandlerTcp::ProcessErrorFromReceiver(const Error &error, const ProducerRequest* request, - const std::string& receiver_uri) { + const std::string &receiver_uri) { bool is_server_error = ServerError(error); if (error && error != ProducerErrorTemplates::kServerWarning) { Disconnect(); std::string log_str = "cannot send data, opcode: " + std::to_string(request->header.op_code) + - ", id: " + std::to_string(request->header.data_id) + " to " + receiver_uri + ": " + - error->Explain(); + ", id: " + std::to_string(request->header.data_id) + " to " + receiver_uri + ": " + + error->Explain(); if (is_server_error) { log__->Warning(log_str + ", will try again"); } else { @@ -219,24 +223,27 @@ bool RequestHandlerTcp::ProcessErrorFromReceiver(const Error& error, return is_server_error; } - void RequestHandlerTcp::ProcessRequestCallback(Error err, ProducerRequest* request, std::string response, bool* retry) { if (request->callback) { - request->callback(RequestCallbackPayload{request->header, std::move(request->data),std::move(response)}, std::move(err)); + request->callback(RequestCallbackPayload{request->header, std::move(request->data), std::move(response)}, + std::move(err)); } *retry = false; } +bool ImmediateCallbackAfterError(const Error& err) { + return err == ProducerErrorTemplates::kWrongInput || err == ProducerErrorTemplates::kUnsupportedClient; +} bool RequestHandlerTcp::SendToOneOfTheReceivers(ProducerRequest* request, bool* retry) { for (auto receiver_uri : receivers_list_) { if (Disconnected()) { auto err = ConnectToReceiver(request->source_credentials, receiver_uri); - if (err == ProducerErrorTemplates::kWrongInput) { + if (ImmediateCallbackAfterError(err)) { ProcessRequestCallback(std::move(err), request, "", retry); return false; } else { - if (err != nullptr ) { + if (err != nullptr) { continue; } } @@ -245,7 +252,7 @@ bool RequestHandlerTcp::SendToOneOfTheReceivers(ProducerRequest* request, bool* std::string response; auto err = TrySendToReceiver(request, &response); bool server_error_can_retry = ProcessErrorFromReceiver(err, request, receiver_uri); - if (server_error_can_retry) { + if (server_error_can_retry) { continue; } @@ -253,13 +260,13 @@ bool RequestHandlerTcp::SendToOneOfTheReceivers(ProducerRequest* request, bool* ProcessRequestCallback(std::move(err), request, response, retry); return success; } - log__->Warning((receivers_list_.empty()?std::string("receiver list empty, "):"")+"put back to the queue, request opcode: " + std::to_string(request->header.op_code) + - ", id: " + std::to_string(request->header.data_id)); + log__->Warning((receivers_list_.empty() ? std::string("receiver list empty, ") : "") + + "put back to the queue, request opcode: " + std::to_string(request->header.op_code) + + ", id: " + std::to_string(request->header.data_id)); *retry = true; return false; } - bool RequestHandlerTcp::ProcessRequestUnlocked(GenericRequest* request, bool* retry) { auto producer_request = static_cast<ProducerRequest*>(request); @@ -303,13 +310,14 @@ void RequestHandlerTcp::TearDownProcessingRequestLocked(bool request_processed_s void RequestHandlerTcp::ProcessRequestTimeout(GenericRequest* request) { auto producer_request = static_cast<ProducerRequest*>(request); auto err_string = "request id:" + std::to_string(request->header.data_id) + ", opcode: " + std::to_string( - request->header.op_code) + " for " + request->header.stream + - " stream"; + request->header.op_code) + " for " + request->header.stream + + " stream"; log__->Error("timeout " + err_string); auto err = ProducerErrorTemplates::kTimeout.Generate(err_string); if (producer_request->callback) { - producer_request->callback(RequestCallbackPayload{request->header, std::move(producer_request->data),""}, std::move(err)); + producer_request->callback(RequestCallbackPayload{request->header, std::move(producer_request->data), ""}, + std::move(err)); } } diff --git a/producer/api/cpp/unittests/test_producer_impl.cpp b/producer/api/cpp/unittests/test_producer_impl.cpp index bdea491aceec053a3b03579c6e38e01be7c9c3dc..5219352f164def64bf0b0d1c819af0feba464c3d 100644 --- a/producer/api/cpp/unittests/test_producer_impl.cpp +++ b/producer/api/cpp/unittests/test_producer_impl.cpp @@ -1,5 +1,3 @@ -#pragma clang diagnostic push -#pragma ide diagnostic ignored "InfiniteRecursion" #include <gtest/gtest.h> #include <gmock/gmock.h> @@ -11,6 +9,7 @@ #include "../src/request_handler_tcp.h" #include "asapo/request/request_pool_error.h" +#include "asapo/unittests/MockHttpClient.h" #include "mocking.h" @@ -26,10 +25,13 @@ using ::testing::Ne; using ::testing::Mock; using ::testing::InSequence; using ::testing::HasSubstr; +using testing::SetArgPointee; using asapo::RequestPool; using asapo::ProducerRequest; +using asapo::MockHttpClient; + MATCHER_P10(M_CheckSendRequest, op_code, source_credentials, metadata, file_id, file_size, message, stream, ingest_mode, @@ -56,6 +58,8 @@ TEST(ProducerImpl, Constructor) { asapo::ProducerImpl producer{"", 4, 3600000, asapo::RequestHandlerType::kTcp}; ASSERT_THAT(dynamic_cast<asapo::AbstractLogger*>(producer.log__), Ne(nullptr)); ASSERT_THAT(dynamic_cast<asapo::RequestPool*>(producer.request_pool__.get()), Ne(nullptr)); + ASSERT_THAT(dynamic_cast<const asapo::HttpClient*>(producer.httpclient__.get()), Ne(nullptr)); + } class ProducerImplTests : public testing::Test { @@ -64,7 +68,8 @@ class ProducerImplTests : public testing::Test { asapo::ProducerRequestHandlerFactory factory{&service}; testing::NiceMock<asapo::MockLogger> mock_logger; testing::NiceMock<MockRequestPull> mock_pull{&factory, &mock_logger}; - asapo::ProducerImpl producer{"", 1, 3600000, asapo::RequestHandlerType::kTcp}; + std::string expected_server_uri = "test:8400"; + asapo::ProducerImpl producer{expected_server_uri, 1, 3600000, asapo::RequestHandlerType::kTcp}; uint64_t expected_size = 100; uint64_t expected_id = 10; uint64_t expected_dataset_id = 100; @@ -88,9 +93,15 @@ class ProducerImplTests : public testing::Test { std::string expected_fullpath = "filename"; bool expected_managed_memory = true; bool expected_unmanaged_memory = false; + + MockHttpClient* mock_http_client; + void SetUp() override { producer.log__ = &mock_logger; producer.request_pool__ = std::unique_ptr<RequestPool>{&mock_pull}; + mock_http_client = new MockHttpClient; + producer.httpclient__.reset(mock_http_client); + } void TearDown() override { producer.request_pool__.release(); @@ -510,8 +521,20 @@ TEST_F(ProducerImplTests, ReturnDataIfCanotAddToQueue) { } +TEST_F(ProducerImplTests, GetVersionInfoWithServer) { + + std::string result = R"({"softwareVersion":"20.03.1, build 7a9294ad","clientSupported":"no", "clientProtocol":{"versionInfo":"v0.2"}})"; + EXPECT_CALL(*mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/version?client=producer&protocol=v0.1"), _,_)).WillOnce(DoAll( + SetArgPointee<1>(asapo::HttpCode::OK), + SetArgPointee<2>(nullptr), + Return(result))); + std::string client_info,server_info; + auto err = producer.GetVersionInfo(&client_info,&server_info,nullptr); + ASSERT_THAT(err, Eq(nullptr)); + ASSERT_THAT(server_info, HasSubstr("20.03.1")); + ASSERT_THAT(server_info, HasSubstr("v0.2")); } -#pragma clang diagnostic pop \ No newline at end of file +} diff --git a/producer/api/cpp/unittests/test_producer_request.cpp b/producer/api/cpp/unittests/test_producer_request.cpp index eb087cfa3b3a4dec67b92d1626c7b0bb58d47ce8..b879fb32833c7dd8bdb911adddd7db9f007a9fc5 100644 --- a/producer/api/cpp/unittests/test_producer_request.cpp +++ b/producer/api/cpp/unittests/test_producer_request.cpp @@ -40,6 +40,7 @@ TEST(ProducerRequest, Constructor) { uint64_t expected_file_size = 1337; uint64_t expected_meta_size = 137; std::string expected_meta = "meta"; + std::string expected_api_version = "v0.1"; asapo::Opcode expected_op_code = asapo::kOpcodeTransferData; asapo::GenericRequestHeader header{expected_op_code, expected_file_id, expected_file_size, @@ -53,7 +54,7 @@ TEST(ProducerRequest, Constructor) { ASSERT_THAT(request.header.data_id, Eq(expected_file_id)); ASSERT_THAT(request.header.op_code, Eq(expected_op_code)); ASSERT_THAT(request.header.meta_size, Eq(expected_meta_size)); - + ASSERT_THAT(request.header.api_version, testing::StrEq(expected_api_version)); } diff --git a/producer/api/cpp/unittests/test_receiver_discovery_service.cpp b/producer/api/cpp/unittests/test_receiver_discovery_service.cpp index 7000da7d4c01930c3906a9460405e7623140d766..014be20c89dd3d247a2e3d7134c9c43fb5131792 100644 --- a/producer/api/cpp/unittests/test_receiver_discovery_service.cpp +++ b/producer/api/cpp/unittests/test_receiver_discovery_service.cpp @@ -48,7 +48,7 @@ class ReceiversStatusTests : public Test { NiceMock<asapo::MockLogger> mock_logger; NiceMock<MockHttpClient>* mock_http_client; - std::string expected_endpoint{"endpoint/asapo-discovery/asapo-receiver"}; + std::string expected_endpoint{"endpoint/asapo-discovery/v0.1/asapo-receiver?protocol=v0.1"}; ReceiverDiscoveryService status{"endpoint", 20}; void SetUp() override { diff --git a/producer/api/cpp/unittests/test_request_handler_tcp.cpp b/producer/api/cpp/unittests/test_request_handler_tcp.cpp index 536aee478111030daf6181ddf82d475b5b8a877e..1d7b812cd1e88df4915b65a83639774ef8ececb8 100644 --- a/producer/api/cpp/unittests/test_request_handler_tcp.cpp +++ b/producer/api/cpp/unittests/test_request_handler_tcp.cpp @@ -120,7 +120,7 @@ class RequestHandlerTcpTests : public testing::Test { bool retry; Sequence seq_receive[2]; void ExpectFailConnect(bool only_once = false); - void ExpectFailAuthorize(bool only_once = false); + void ExpectFailAuthorize(asapo::NetworkErrorCode error_code); void ExpectOKAuthorize(bool only_once = false); void ExpectFailSendHeader(bool only_once = false); void ExpectFailSend(uint64_t expected_size, bool only_once); @@ -191,60 +191,55 @@ void RequestHandlerTcpTests::ExpectFailConnect(bool only_once) { } -void RequestHandlerTcpTests::ExpectFailAuthorize(bool only_once) { - int i = 0; - for (auto expected_sd : expected_sds) { - EXPECT_CALL(mock_io, - Send_t(expected_sd, M_CheckSendRequest(asapo::kOpcodeAuthorize, 0, 0, "", - ""), - sizeof(asapo::GenericRequestHeader), _)) - .WillOnce( - DoAll( - testing::SetArgPointee<3>(nullptr), - Return(sizeof(asapo::GenericRequestHeader)) - )); - EXPECT_CALL(mock_io, - Send_t(expected_sd, _,strlen(expected_beamtime_id), _)) - .WillOnce( - DoAll( - testing::SetArgPointee<3>(nullptr), - Return(strlen(expected_beamtime_id)) - )); - - EXPECT_CALL(mock_io, Receive_t(expected_sd, _, sizeof(asapo::SendResponse), _)) - .InSequence(seq_receive[i]) - .WillOnce( - DoAll( - testing::SetArgPointee<3>(nullptr), - A_WriteSendResponse(asapo::kNetAuthorizationError, expected_auth_message), - testing::ReturnArg<2>() - )); - EXPECT_CALL(mock_io, CloseSocket_t(expected_sd, _)); - if (only_once) { - EXPECT_CALL(mock_logger, Debug(AllOf( - HasSubstr("disconnected"), - HasSubstr(receivers_list[i]) - ) +void RequestHandlerTcpTests::ExpectFailAuthorize(asapo::NetworkErrorCode error_code) { + auto expected_sd = expected_sds[0]; + EXPECT_CALL(mock_io, + Send_t(expected_sd, M_CheckSendRequest(asapo::kOpcodeAuthorize, 0, 0, "", + ""), + sizeof(asapo::GenericRequestHeader), _)) + .WillOnce( + DoAll( + testing::SetArgPointee<3>(nullptr), + Return(sizeof(asapo::GenericRequestHeader)) + )); + EXPECT_CALL(mock_io, + Send_t(expected_sd, _, strlen(expected_beamtime_id), _)) + .WillOnce( + DoAll( + testing::SetArgPointee<3>(nullptr), + Return(strlen(expected_beamtime_id)) )); - EXPECT_CALL(mock_logger, Error(AllOf( - HasSubstr("authorization"), - HasSubstr(expected_auth_message), - HasSubstr(receivers_list[i]) - ) + EXPECT_CALL(mock_io, Receive_t(expected_sd, _, sizeof(asapo::SendResponse), _)) + .InSequence(seq_receive[0]) + .WillOnce( + DoAll( + testing::SetArgPointee<3>(nullptr), + A_WriteSendResponse(error_code, expected_auth_message), + testing::ReturnArg<2>() )); - } - if (only_once) break; - i++; - } + EXPECT_CALL(mock_io, CloseSocket_t(expected_sd, _)); + EXPECT_CALL(mock_logger, Debug(AllOf( + HasSubstr("disconnected"), + HasSubstr(receivers_list[0]) + ) + )); + + EXPECT_CALL(mock_logger, Error(AllOf( + HasSubstr("authorization"), + HasSubstr(expected_auth_message), + HasSubstr(receivers_list[0]) + ) + )); } + void RequestHandlerTcpTests::ExpectOKAuthorize(bool only_once) { int i = 0; for (auto expected_sd : expected_sds) { EXPECT_CALL(mock_io, Send_t(expected_sd, M_CheckSendRequest(asapo::kOpcodeAuthorize, 0, 0, "", - ""), + ""), sizeof(asapo::GenericRequestHeader), _)) .WillOnce( DoAll( @@ -252,7 +247,7 @@ void RequestHandlerTcpTests::ExpectOKAuthorize(bool only_once) { Return(sizeof(asapo::GenericRequestHeader)) )); EXPECT_CALL(mock_io, - Send_t(expected_sd, _,strlen(expected_beamtime_id), _)) + Send_t(expected_sd, _, strlen(expected_beamtime_id), _)) .WillOnce( DoAll( testing::SetArgPointee<3>(nullptr), @@ -284,10 +279,10 @@ void RequestHandlerTcpTests::ExpectFailSendHeader(bool only_once) { int i = 0; for (auto expected_sd : expected_sds) { EXPECT_CALL(mock_io, Send_t(expected_sd, M_CheckSendRequest(expected_op_code, - expected_file_id, - expected_file_size, - expected_file_name, - expected_stream), + expected_file_id, + expected_file_size, + expected_file_name, + expected_stream), sizeof(asapo::GenericRequestHeader), _)) .WillOnce( DoAll( @@ -456,10 +451,10 @@ void RequestHandlerTcpTests::ExpectOKSendFile(bool only_once) { void RequestHandlerTcpTests::ExpectOKSendHeader(bool only_once, asapo::Opcode opcode) { for (auto expected_sd : expected_sds) { EXPECT_CALL(mock_io, Send_t(expected_sd, M_CheckSendRequest(opcode, - expected_file_id, - expected_file_size, - expected_file_name, - expected_stream), + expected_file_id, + expected_file_size, + expected_file_name, + expected_stream), sizeof(asapo::GenericRequestHeader), _)) .WillOnce( DoAll( @@ -595,7 +590,7 @@ TEST_F(RequestHandlerTcpTests, TriesConnectWhenNotConnected) { TEST_F(RequestHandlerTcpTests, FailsWhenCannotAuthorize) { ExpectOKConnect(true); - ExpectFailAuthorize(true); + ExpectFailAuthorize(asapo::kNetAuthorizationError); request_handler.PrepareProcessingRequestLocked(); auto success = request_handler.ProcessRequestUnlocked(&request, &retry); @@ -609,6 +604,21 @@ TEST_F(RequestHandlerTcpTests, FailsWhenCannotAuthorize) { } +TEST_F(RequestHandlerTcpTests, FailsWhenUnsupportedClient) { + ExpectOKConnect(true); + ExpectFailAuthorize(asapo::kNetErrorNotSupported); + + request_handler.PrepareProcessingRequestLocked(); + auto success = request_handler.ProcessRequestUnlocked(&request, &retry); + request_handler.TearDownProcessingRequestLocked(success); + + ASSERT_THAT(n_connections, Eq(0)); + ASSERT_THAT(callback_err, Eq(asapo::ProducerErrorTemplates::kUnsupportedClient)); + ASSERT_THAT(callback_called, Eq(true)); + ASSERT_THAT(success, Eq(false)); + ASSERT_THAT(retry, Eq(false)); +} + TEST_F(RequestHandlerTcpTests, DoesNotTryConnectWhenConnected) { DoSingleSend(); @@ -768,6 +778,12 @@ TEST_F(RequestHandlerTcpTests, ImmediatelyCallBackErrorIfAuthorizationFailure) { AssertImmediatelyCallBack(asapo::kNetAuthorizationError, asapo::ProducerErrorTemplates::kWrongInput); } + +TEST_F(RequestHandlerTcpTests, ImmediatelyCallBackErrorIfNotSupportedfailure) { + AssertImmediatelyCallBack(asapo::kNetErrorNotSupported, asapo::ProducerErrorTemplates::kUnsupportedClient); +} + + TEST_F(RequestHandlerTcpTests, ImmediatelyCallBackErrorIfWrongMetadata) { AssertImmediatelyCallBack(asapo::kNetErrorWrongRequest, asapo::ProducerErrorTemplates::kWrongInput); } diff --git a/producer/api/python/asapo_producer.pxd b/producer/api/python/asapo_producer.pxd index f35a341c933c0dd447ea318ef8b0bae1936c3e94..cd627b6203aa0e9322625f893d7203dfd392c6a1 100644 --- a/producer/api/python/asapo_producer.pxd +++ b/producer/api/python/asapo_producer.pxd @@ -22,6 +22,7 @@ cdef extern from "asapo/asapo_producer.h" namespace "asapo": ErrorTemplateInterface kLocalIOError "asapo::ProducerErrorTemplates::kLocalIOError" ErrorTemplateInterface kServerWarning "asapo::ProducerErrorTemplates::kServerWarning" ErrorTemplateInterface kRequestPoolIsFull "asapo::ProducerErrorTemplates::kRequestPoolIsFull" + ErrorTemplateInterface kUnsupportedClient "asapo::ProducerErrorTemplates::kUnsupportedClient" cdef extern from "asapo/asapo_producer.h" namespace "asapo": cppclass MessageData: @@ -104,6 +105,7 @@ cdef extern from "asapo/asapo_producer.h" namespace "asapo" nogil: Error SendStreamFinishedFlag(string stream, uint64_t last_id, string next_stream, RequestCallback callback) StreamInfo GetStreamInfo(string stream, uint64_t timeout_ms, Error* err) StreamInfo GetLastStream(uint64_t timeout_ms, Error* err) + Error GetVersionInfo(string* client_info,string* server_info, bool* supported) cdef extern from "asapo/asapo_producer.h" namespace "asapo": diff --git a/producer/api/python/asapo_producer.pyx.in b/producer/api/python/asapo_producer.pyx.in index e40d7a5c9e233f7fab8e14802e2cf828ea0f2e23..5391c8ce8ea41e3eada8ad182b8e4cc755d3feb1 100644 --- a/producer/api/python/asapo_producer.pyx.in +++ b/producer/api/python/asapo_producer.pyx.in @@ -54,6 +54,9 @@ class AsapoServerWarning(AsapoProducerError): class AsapoRequestsPoolIsFull(AsapoProducerError): pass +class AsapoUnsupportedClientError(AsapoProducerError): + pass + cdef python_exception_from_error(Error& err): error_string = _str(err.get().Explain()) if err == kTimeout: @@ -66,6 +69,8 @@ cdef python_exception_from_error(Error& err): return AsapoServerWarning(error_string) elif err == kRequestPoolIsFull: return AsapoRequestsPoolIsFull(error_string) + elif err == kUnsupportedClient: + raise AsapoUnsupportedClientError(error_string) else: return AsapoProducerError(error_string) @@ -110,7 +115,21 @@ cdef class PyProducer: print("wrong loglevel mode: "+ level) return self.c_producer.get().SetLogLevel(log_level) - + def get_version_info(self, from_server = "true"): + cdef string client_info,server_info + cdef bool supported + cdef string* p_server_info = &server_info if from_server else <string*>NULL + cdef bool* p_supported = &supported if from_server else <bool*>NULL + cdef Error err + with nogil: + err = self.c_producer.get().GetVersionInfo(&client_info,p_server_info,p_supported) + if err: + throw_exception(err) + version = {} + if from_server: + return {'client': _str(client_info), 'server': _str(server_info), 'supported': supported} + else: + return {'client': _str(client_info)} def __send_np_array(self, id, exposed_path,data, user_meta=None,dataset=None,stream="default",ingest_mode = DEFAULT_INGEST_MODE,callback=None): cdef MessageHeader message_header = self.create_message_header(id,exposed_path,user_meta,dataset,ingest_mode) if data is None: diff --git a/producer/event_monitor_producer/src/main_eventmon.cpp b/producer/event_monitor_producer/src/main_eventmon.cpp index d30e479a8bf6e8af518b818ee0aa4cc8accaf040..72446fa522c48bbdd9724fedc639985874afe1ae 100644 --- a/producer/event_monitor_producer/src/main_eventmon.cpp +++ b/producer/event_monitor_producer/src/main_eventmon.cpp @@ -15,7 +15,7 @@ #include "asapo/preprocessor/definitions.h" #include "asapo/io/io_factory.h" -#include "asapo/common/version.h" +#include "asapo/common/internal/version.h" using asapo::Producer; using asapo::EventMonConfigFactory; diff --git a/receiver/src/main.cpp b/receiver/src/main.cpp index 2f119b2005f4e68a7983b4be247874df7217e735..e00c94fbd97b8e9047bb34d52c49c18cf9b92546 100644 --- a/receiver/src/main.cpp +++ b/receiver/src/main.cpp @@ -6,7 +6,7 @@ #include "receiver_config.h" #include "receiver_data_server/receiver_data_server_logger.h" -#include "asapo/common/version.h" +#include "asapo/common/internal/version.h" #include "receiver_data_server/receiver_data_server.h" #include "receiver_data_server/net_server/rds_tcp_server.h" diff --git a/receiver/src/receiver_config.cpp b/receiver/src/receiver_config.cpp index 82383d3d2b32461fe8c418e71c31438e87ef7495..78052168bdddcce8578809b13d266fb6f4cd9818 100644 --- a/receiver/src/receiver_config.cpp +++ b/receiver/src/receiver_config.cpp @@ -19,6 +19,7 @@ Error ReceiverConfigFactory::SetConfig(std::string file_name) { Error err; (err = parser.GetString("PerformanceDbServer", &config.performance_db_uri)) || + (err = parser.GetBool("MonitorPerformance", &config.monitor_performance)) || (err = parser.GetUInt64("ListenPort", &config.listen_port)) || (err = parser.GetUInt64("ReceiveToDiskThresholdMB", &config.receive_to_disk_threshold_mb)) || (err = parser.Embedded("DataServer").GetUInt64("ListenPort", &config.dataserver.listen_port)) || diff --git a/receiver/src/receiver_config.h b/receiver/src/receiver_config.h index 74316f7e6449af6fc9dface08d59876329065774..c8128362a7e1d51075f54d327aab620dc35f6fb5 100644 --- a/receiver/src/receiver_config.h +++ b/receiver/src/receiver_config.h @@ -11,6 +11,7 @@ namespace asapo { struct ReceiverConfig { std::string performance_db_uri; std::string performance_db_name; + bool monitor_performance = false; std::string database_uri; uint64_t listen_port = 0; std::string authorization_server; diff --git a/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.cpp b/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.cpp index 82165357d48d7fdb3985b28eed9cdb9ca00d7d1e..0f8f387faf1d2bd20490a4e6b409612b1c81e81d 100644 --- a/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.cpp +++ b/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.cpp @@ -1,7 +1,7 @@ #include "receiver_data_server_request_handler.h" #include "../receiver_data_server_error.h" - +#include "asapo/common/internal/version.h" namespace asapo { ReceiverDataServerRequestHandler::ReceiverDataServerRequestHandler(RdsNetServer* server, @@ -11,8 +11,19 @@ ReceiverDataServerRequestHandler::ReceiverDataServerRequestHandler(RdsNetServer* } -bool ReceiverDataServerRequestHandler::CheckRequest(const ReceiverDataServerRequest* request) { - return request->header.op_code == kOpcodeGetBufferData; +bool ReceiverDataServerRequestHandler::CheckRequest(const ReceiverDataServerRequest* request,NetworkErrorCode* code) { + if (request->header.op_code != kOpcodeGetBufferData) { + *code = kNetErrorWrongRequest; + return false; + } + int verClient = VersionToNumber(request->header.api_version); + int verService = VersionToNumber(GetRdsApiVersion()); + if (verClient > verService) { + *code = kNetErrorNotSupported; + return false; + } + + return true; } Error ReceiverDataServerRequestHandler::SendResponse(const ReceiverDataServerRequest* request, NetworkErrorCode code) { @@ -45,8 +56,9 @@ CacheMeta* ReceiverDataServerRequestHandler::GetSlotAndLock(const ReceiverDataSe bool ReceiverDataServerRequestHandler::ProcessRequestUnlocked(GenericRequest* request, bool* retry) { *retry = false; auto receiver_request = dynamic_cast<ReceiverDataServerRequest*>(request); - if (!CheckRequest(receiver_request)) { - HandleInvalidRequest(receiver_request); + NetworkErrorCode code; + if (!CheckRequest(receiver_request,&code)) { + HandleInvalidRequest(receiver_request,code); return true; } @@ -78,10 +90,18 @@ void ReceiverDataServerRequestHandler::ProcessRequestTimeout(GenericRequest* /*r // do nothing } -void ReceiverDataServerRequestHandler::HandleInvalidRequest(const ReceiverDataServerRequest* receiver_request) { - SendResponse(receiver_request, kNetErrorWrongRequest); +void ReceiverDataServerRequestHandler::HandleInvalidRequest(const ReceiverDataServerRequest* receiver_request,NetworkErrorCode code) { + SendResponse(receiver_request, code); server_->HandleAfterError(receiver_request->source_id); - log__->Error("wrong request, code:" + std::to_string(receiver_request->header.op_code)); + switch (code) { + case NetworkErrorCode::kNetErrorWrongRequest: + log__->Error("wrong request, code:" + std::to_string(receiver_request->header.op_code)); + break; + case NetworkErrorCode::kNetErrorNotSupported: + log__->Error("unsupported client, version: " + std::string(receiver_request->header.api_version)); + break; + }; + } void ReceiverDataServerRequestHandler::HandleValidRequest(const ReceiverDataServerRequest* receiver_request, diff --git a/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.h b/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.h index 10c6633bd6963a18413bba8698a240bf89dcd7d0..18fc5937a793c9358376d24ec0480496ce93e88a 100644 --- a/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.h +++ b/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.h @@ -24,12 +24,12 @@ class ReceiverDataServerRequestHandler: public RequestHandler { private: RdsNetServer* server_; DataCache* data_cache_; - bool CheckRequest(const ReceiverDataServerRequest* request); + bool CheckRequest(const ReceiverDataServerRequest* request,NetworkErrorCode* code); Error SendResponse(const ReceiverDataServerRequest* request, NetworkErrorCode code); Error SendResponseAndSlotData(const ReceiverDataServerRequest* request, const CacheMeta* meta); CacheMeta* GetSlotAndLock(const ReceiverDataServerRequest* request); - void HandleInvalidRequest(const ReceiverDataServerRequest* receiver_request); + void HandleInvalidRequest(const ReceiverDataServerRequest* receiver_request,NetworkErrorCode code); void HandleValidRequest(const ReceiverDataServerRequest* receiver_request, const CacheMeta* meta); }; diff --git a/receiver/src/receiver_error.h b/receiver/src/receiver_error.h index 3e30c4fd28a08c7a4fd8768cfae7ee89c20c3dd0..210c116cadfa8d9b1f64f2894cc014ec7355bbd2 100644 --- a/receiver/src/receiver_error.h +++ b/receiver/src/receiver_error.h @@ -11,7 +11,8 @@ enum class ReceiverErrorType { kAuthorizationFailure, kInternalServerError, kReAuthorizationFailure, - kWarningDuplicatedRequest + kWarningDuplicatedRequest, + kUnsupportedClient }; using ReceiverErrorTemplate = ServiceErrorTemplate<ReceiverErrorType, ErrorType::kReceiverError>; @@ -41,6 +42,13 @@ auto const kAuthorizationFailure = ReceiverErrorTemplate { "authorization failure", ReceiverErrorType::kAuthorizationFailure }; +auto const kUnsupportedClient = ReceiverErrorTemplate { + "client version not supported", ReceiverErrorType::kUnsupportedClient +}; + + + + auto const kReAuthorizationFailure = ReceiverErrorTemplate { "reauthorization for auto beamtime failed", ReceiverErrorType::kReAuthorizationFailure }; diff --git a/receiver/src/request.cpp b/receiver/src/request.cpp index 5bf9c1ab2cbdd38f9c0dd8339e0a86912bc163b6..7db51dfd02f8aa91f097ecab8bfdb8747f9e3add 100644 --- a/receiver/src/request.cpp +++ b/receiver/src/request.cpp @@ -89,6 +89,11 @@ std::string Request::GetStream() const { return request_header_.stream; } +std::string Request::GetApiVersion() const { + return request_header_.api_version; +} + + const std::string& Request::GetOriginUri() const { return origin_uri_; } diff --git a/receiver/src/request.h b/receiver/src/request.h index f24ad10fcc1927e69e80a2edf91a64efbc73cc26..141430e7748b09ee46c1c596d3efa2c992e59759 100644 --- a/receiver/src/request.h +++ b/receiver/src/request.h @@ -44,6 +44,7 @@ class Request { VIRTUAL uint64_t GetDataID() const; VIRTUAL std::string GetFileName() const; VIRTUAL std::string GetStream() const; + VIRTUAL std::string GetApiVersion() const; VIRTUAL void* GetData() const; VIRTUAL Opcode GetOpCode() const; VIRTUAL const char* GetMessage() const; diff --git a/receiver/src/request_handler/request_handler_authorize.cpp b/receiver/src/request_handler/request_handler_authorize.cpp index ca67af48f9d62783e61e3abeb915da7eea09e1a8..314b351a46acf31fc5ef08312a4ee989523fc2a8 100644 --- a/receiver/src/request_handler/request_handler_authorize.cpp +++ b/receiver/src/request_handler/request_handler_authorize.cpp @@ -4,6 +4,7 @@ #include "../request.h" #include "asapo/json_parser/json_parser.h" +#include "asapo/common/internal/version.h" using std::chrono::system_clock; @@ -83,6 +84,17 @@ Error RequestHandlerAuthorize::Authorize(Request* request, const char* source_cr return nullptr; } +Error RequestHandlerAuthorize::CheckVersion(const std::string& version_from_client) const { + int verClient = VersionToNumber(version_from_client); + int verService = VersionToNumber(GetReceiverApiVersion()); + if (verClient > verService) { + auto err_string = "client version: "+version_from_client + ", server version: "+GetReceiverApiVersion(); + return asapo::ReceiverErrorTemplates::kUnsupportedClient.Generate(err_string); + log__->Error("failure serving client - unsupported version, " + err_string); + } + return nullptr; +} + Error RequestHandlerAuthorize::ProcessAuthorizationRequest(Request* request) const { if (!cached_source_credentials_.empty()) { Error auth_error = asapo::ReceiverErrorTemplates::kAuthorizationFailure.Generate(); @@ -92,6 +104,12 @@ Error RequestHandlerAuthorize::ProcessAuthorizationRequest(Request* request) con return auth_error; } + auto err = CheckVersion(request->GetApiVersion()); + if (err) { + log__->Error("failure authorizing at client: " + err->Explain()); + return err; + } + return Authorize(request, request->GetMetaData().c_str()); } diff --git a/receiver/src/request_handler/request_handler_authorize.h b/receiver/src/request_handler/request_handler_authorize.h index 1798ea8fb31de1e8d0e99459bcf447b2763085ea..3e5e44c31fb985c58aceeb5c50c65a88ad01b89d 100644 --- a/receiver/src/request_handler/request_handler_authorize.h +++ b/receiver/src/request_handler/request_handler_authorize.h @@ -35,6 +35,8 @@ class RequestHandlerAuthorize final: public ReceiverRequestHandler { Error ProcessReAuthorization(Request* request) const; bool NeedReauthorize() const; std::string GetRequestString(const Request* request, const char* source_credentials) const; + Error CheckVersion(const std::string& version_from_client) const; + }; } diff --git a/receiver/src/request_handler/requests_dispatcher.cpp b/receiver/src/request_handler/requests_dispatcher.cpp index 7debacf5013ee5c1fdc16dba815f52ad6a7f864e..2487f2d70ce0d86c4a325e7a7ae0236277a14152 100644 --- a/receiver/src/request_handler/requests_dispatcher.cpp +++ b/receiver/src/request_handler/requests_dispatcher.cpp @@ -18,6 +18,8 @@ NetworkErrorCode GetNetworkCodeFromError(const Error& err) { if (err) { if (err == ReceiverErrorTemplates::kAuthorizationFailure) { return NetworkErrorCode::kNetAuthorizationError; + } else if (err == ReceiverErrorTemplates::kUnsupportedClient) { + return NetworkErrorCode::kNetErrorNotSupported; } else if (err == ReceiverErrorTemplates::kReAuthorizationFailure) { return NetworkErrorCode::kNetErrorReauthorize; } else if (err == DBErrorTemplates::kJsonParseError || err == ReceiverErrorTemplates::kBadRequest) { diff --git a/receiver/src/statistics/statistics.cpp b/receiver/src/statistics/statistics.cpp index b35da64b1c6007ee9fda78bc1b55339a81db4bba..4549f1bc43f8d45376f55220f86efb2bed5532b2 100644 --- a/receiver/src/statistics/statistics.cpp +++ b/receiver/src/statistics/statistics.cpp @@ -1,7 +1,7 @@ #include "statistics.h" #include "statistics_sender_influx_db.h" #include "statistics_sender_fluentd.h" - +#include "../receiver_config.h" #include <algorithm> using std::chrono::system_clock; @@ -9,6 +9,9 @@ using std::chrono::system_clock; namespace asapo { void Statistics::SendIfNeeded(bool send_always) noexcept { + if (!GetReceiverConfig()->monitor_performance) { + return; + } if (send_always || GetTotalElapsedMs() > write_interval_) { std::lock_guard<std::mutex> lock{mutex_}; Send(); diff --git a/receiver/unittests/mock_receiver_config.cpp b/receiver/unittests/mock_receiver_config.cpp index 916f026baa7d64b274d65ee810ca8fe2f230c25b..17e236cbdd665969a80682f1e62e50e49e987430 100644 --- a/receiver/unittests/mock_receiver_config.cpp +++ b/receiver/unittests/mock_receiver_config.cpp @@ -44,6 +44,7 @@ Error SetReceiverConfig (const ReceiverConfig& config, std::string error_field) auto config_string = std::string("{") + Key("PerformanceDbServer", error_field) + "\"" + config.performance_db_uri + "\""; config_string += "," + Key("PerformanceDbName", error_field) + "\"" + config.performance_db_name + "\""; + config_string += "," + Key("MonitorPerformance", error_field) + (config.monitor_performance?"true":"false"); config_string += "," + Key("DatabaseServer", error_field) + "\"" + config.database_uri + "\""; config_string += "," + Key("DiscoveryServer", error_field) + "\"" + config.discovery_server + "\""; config_string += "," + Key("ListenPort", error_field) + std::to_string(config.listen_port); diff --git a/receiver/unittests/receiver_data_server/request_handler/test_request_handler.cpp b/receiver/unittests/receiver_data_server/request_handler/test_request_handler.cpp index eedc2f99fd39f534183c4b9256eb16782c6d3791..e5c495b00a1d7b9c8663f7fd48be97487c95aadc 100644 --- a/receiver/unittests/receiver_data_server/request_handler/test_request_handler.cpp +++ b/receiver/unittests/receiver_data_server/request_handler/test_request_handler.cpp @@ -122,6 +122,18 @@ TEST_F(RequestHandlerTests, ProcessRequest_WrongOpCode) { ASSERT_THAT(success, Eq(true)); } +TEST_F(RequestHandlerTests, ProcessRequest_WrongClientVersion) { + strcpy(request.header.api_version,"v0.2"); + MockSendResponse(asapo::kNetErrorNotSupported, false); + EXPECT_CALL(mock_net, HandleAfterError_t(expected_source_id)); + + EXPECT_CALL(mock_logger, Error(HasSubstr("unsupported client"))); + + auto success = handler.ProcessRequestUnlocked(&request, &retry); + + ASSERT_THAT(success, Eq(true)); +} + TEST_F(RequestHandlerTests, ProcessRequest_ReturnsNoDataWhenCacheNotUsed) { MockSendResponse(asapo::kNetErrorNoData, true); diff --git a/receiver/unittests/receiver_mocking.h b/receiver/unittests/receiver_mocking.h index 200aeed190a32fbf9b8b958b87723928e11be734..8711a6e70ce6a0bcc26173113891188d3313e197 100644 --- a/receiver/unittests/receiver_mocking.h +++ b/receiver/unittests/receiver_mocking.h @@ -66,6 +66,7 @@ class MockRequest: public Request { MOCK_CONST_METHOD0(GetFileName, std::string()); MOCK_CONST_METHOD0(GetStream, std::string()); + MOCK_CONST_METHOD0(GetApiVersion, std::string()); MOCK_CONST_METHOD0(GetDataSize, uint64_t()); MOCK_CONST_METHOD0(GetDataID, uint64_t()); MOCK_CONST_METHOD0(GetSlotId, uint64_t()); diff --git a/receiver/unittests/request_handler/test_request_handler_authorizer.cpp b/receiver/unittests/request_handler/test_request_handler_authorizer.cpp index c79ec92c965b441454fe60d8cc7bf66a18976c04..e34fa8423a744a1a93a38e8152fac7fa1cd6dae7 100644 --- a/receiver/unittests/request_handler/test_request_handler_authorizer.cpp +++ b/receiver/unittests/request_handler/test_request_handler_authorizer.cpp @@ -72,6 +72,8 @@ class AuthorizerHandlerTests : public Test { std::string expected_authorization_server = "authorizer_host"; std::string expect_request_string; std::string expected_source_credentials; + std::string expected_api_version = "v0.1"; + asapo::SourceType expected_source_type = asapo::SourceType::kProcessed; std::string expected_source_type_str = "processed"; std::string expected_access_type_str = "[\"write\"]"; @@ -150,6 +152,11 @@ class AuthorizerHandlerTests : public Test { .WillOnce(ReturnRef(expected_source_credentials)) ; + EXPECT_CALL(*mock_request, GetApiVersion()) + .WillOnce(Return(expected_api_version)) + ; + + MockAuthRequest(error, code); return handler.ProcessRequest(mock_request.get()); } @@ -267,6 +274,20 @@ TEST_F(AuthorizerHandlerTests, RequestAuthorizeReturnsDifferentBeamtimeId) { } +TEST_F(AuthorizerHandlerTests, RequestFromUnsupportedClient) { + EXPECT_CALL(*mock_request, GetOpCode()) + .WillOnce(Return(asapo::kOpcodeAuthorize)) + ; + EXPECT_CALL(*mock_request, GetApiVersion()) + .WillOnce(Return("v0.2")) + ; + + auto err = handler.ProcessRequest(mock_request.get()); + ASSERT_THAT(err, Eq(asapo::ReceiverErrorTemplates::kUnsupportedClient)); +} + + + TEST_F(AuthorizerHandlerTests, DataTransferRequestAuthorizeUsesCachedValue) { config.authorization_interval_ms = 10000; diff --git a/receiver/unittests/request_handler/test_requests_dispatcher.cpp b/receiver/unittests/request_handler/test_requests_dispatcher.cpp index e5d6daaf0354bcd3a9a40f0cd5de60674bf06152..b03fc381186651da8185d8722c8f77c233547b08 100644 --- a/receiver/unittests/request_handler/test_requests_dispatcher.cpp +++ b/receiver/unittests/request_handler/test_requests_dispatcher.cpp @@ -294,6 +294,17 @@ TEST_F(RequestsDispatcherTests, ProcessRequestReturnsAuthorizationFailure) { ASSERT_THAT(std::string(response.message), HasSubstr("authorization")); } +TEST_F(RequestsDispatcherTests, ProcessRequestReturnsUnsupportedClientFailure) { + MockHandleRequest(1, asapo::ReceiverErrorTemplates::kUnsupportedClient.Generate()); + MockSendResponse(&response, false); + + auto err = dispatcher->ProcessRequest(request); + + ASSERT_THAT(err, Eq(asapo::ReceiverErrorTemplates::kUnsupportedClient)); + ASSERT_THAT(response.error_code, Eq(asapo::kNetErrorNotSupported)); + ASSERT_THAT(std::string(response.message), HasSubstr("supported")); +} + TEST_F(RequestsDispatcherTests, ProcessRequestReturnsReAuthorizationFailure) { MockHandleRequest(2, asapo::ReceiverErrorTemplates::kReAuthorizationFailure.Generate()); MockSendResponse(&response, false); diff --git a/receiver/unittests/statistics/test_statistics.cpp b/receiver/unittests/statistics/test_statistics.cpp index 4f871e4118a19888ce2acb345e7e5edf7860966d..d31c2282f79c87b6c5d5ce4800888a0495443f69 100644 --- a/receiver/unittests/statistics/test_statistics.cpp +++ b/receiver/unittests/statistics/test_statistics.cpp @@ -7,6 +7,9 @@ #include "../../src/statistics/statistics_sender_influx_db.h" #include "../../src/statistics/statistics_sender_fluentd.h" #include "../receiver_mocking.h" +#include "../../src/receiver_config.h" +#include "../../src/receiver_config_factory.h" +#include "../mock_receiver_config.h" using ::testing::Test; using ::testing::Gt; @@ -41,6 +44,9 @@ class StatisticTests : public Test { Statistics statistics{0}; MockStatisticsSender mock_statistics_sender; void SetUp() override { + asapo::ReceiverConfig test_config; + test_config.monitor_performance = true; + asapo::SetReceiverConfig(test_config, "none"); statistics.statistics_sender_list__.clear(); statistics.statistics_sender_list__.emplace_back(&mock_statistics_sender); } @@ -156,6 +162,16 @@ TEST_F(StatisticTests, SendStaticsDoesCallsSender) { } +TEST_F(StatisticTests, DoNotSendStatistics) { + asapo::ReceiverConfig test_config; + test_config.monitor_performance = false; + asapo::SetReceiverConfig(test_config, "none"); + + EXPECT_CALL(mock_statistics_sender, SendStatistics_t(_)).Times(0); + + statistics.SendIfNeeded(true); +} + TEST_F(StatisticTests, StatisticsSend) { statistics.IncreaseRequestCounter(); diff --git a/receiver/unittests/test_config.cpp b/receiver/unittests/test_config.cpp index e654b439b2a44e231fd8405f034cd467830958d5..06c7c2ddf1f26860b168618ce6f48c4bfdb3d7c1 100644 --- a/receiver/unittests/test_config.cpp +++ b/receiver/unittests/test_config.cpp @@ -48,6 +48,7 @@ class ConfigTests : public Test { test_config.tag = "receiver1"; test_config.performance_db_name = "db_test"; test_config.performance_db_uri = "localhost:8086"; + test_config.monitor_performance = true; test_config.database_uri = "localhost:27017"; test_config.log_level = asapo::LogLevel::Error; test_config.authorization_interval_ms = 10000; @@ -84,6 +85,7 @@ TEST_F(ConfigTests, ReadSettings) { ASSERT_THAT(config->log_level, Eq(asapo::LogLevel::Error)); ASSERT_THAT(config->tag, Eq("receiver1")); ASSERT_THAT(config->use_datacache, Eq(false)); + ASSERT_THAT(config->monitor_performance, Eq(true)); ASSERT_THAT(config->datacache_reserved_share, Eq(10)); ASSERT_THAT(config->datacache_size_gb, Eq(2)); ASSERT_THAT(config->discovery_server, Eq("discovery")); @@ -104,7 +106,7 @@ TEST_F(ConfigTests, ErrorReadSettings) { std::vector<std::string>fields {"PerformanceDbServer", "ListenPort", "DataServer", "ListenPort", "DataCache", "Use", "SizeGB", "ReservedShare", "DatabaseServer", "Tag", "AuthorizationServer", "AuthorizationInterval", "PerformanceDbName", "LogLevel", - "NThreads", "DiscoveryServer", "AdvertiseURI", "NetworkMode", + "NThreads", "DiscoveryServer", "AdvertiseURI", "NetworkMode","MonitorPerformance", "ReceiveToDiskThresholdMB"}; for (const auto& field : fields) { auto err = asapo::SetReceiverConfig(test_config, field); diff --git a/receiver/unittests/test_request.cpp b/receiver/unittests/test_request.cpp index cea29e89dc78ee98dc004c9452cb33ac1ca40e96..00d724c03d6b1522b7fecb9133f19a363f95c565 100644 --- a/receiver/unittests/test_request.cpp +++ b/receiver/unittests/test_request.cpp @@ -83,6 +83,7 @@ class RequestTests : public Test { uint64_t expected_metadata_size = expected_metadata.size(); asapo::Opcode expected_op_code = asapo::kOpcodeTransferData; char expected_request_message[asapo::kMaxMessageSize] = "test_message"; + std::string expected_api_version = "v0.1"; std::unique_ptr<Request> request; NiceMock<MockIO> mock_io; NiceMock<MockStatistics> mock_statistics; @@ -96,6 +97,7 @@ class RequestTests : public Test { generic_request_header.op_code = expected_op_code; generic_request_header.custom_data[asapo::kPosIngestMode] = asapo::kDefaultIngestMode; strcpy(generic_request_header.message, expected_request_message); + strcpy(generic_request_header.api_version, expected_api_version.c_str()); request.reset(new Request{generic_request_header, expected_socket_id, expected_origin_uri, nullptr, nullptr}); request->io__ = std::unique_ptr<asapo::IO> {&mock_io}; ON_CALL(mock_io, Receive_t(expected_socket_id, _, data_size_, _)).WillByDefault( @@ -157,6 +159,11 @@ TEST_F(RequestTests, GetRequestMessage) { ASSERT_THAT(message, testing::StrEq(expected_request_message)); } +TEST_F(RequestTests, GetApiVersion) { + auto ver = request->GetApiVersion(); + ASSERT_THAT(ver, testing::Eq(expected_api_version)); +} + TEST_F(RequestTests, GetOriginUri) { auto uri = request->GetOriginUri(); diff --git a/tests/automatic/broker/check_monitoring/check_linux.sh b/tests/automatic/broker/check_monitoring/check_linux.sh index a9c64328bb00c0de187b3ffed01009a7bf3f0c1b..35ab4eb7cfe57f6c7243b3fb2a9a99aee36e3191 100644 --- a/tests/automatic/broker/check_monitoring/check_linux.sh +++ b/tests/automatic/broker/check_monitoring/check_linux.sh @@ -33,16 +33,16 @@ sleep 0.3 brokerid=`echo $!` -groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup` +groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup` for i in `seq 1 50`; do - curl --silent 127.0.0.1:5005/database/data/source/stream/${groupid}/next?token=$token >/dev/null 2>&1 & + curl --silent 127.0.0.1:5005/v0.1/beamtime/data/source/stream/${groupid}/next?token=$token >/dev/null 2>&1 & done -sleep 3 +sleep 12 influx -execute "select sum(rate) from RequestsRate" -database=${database_name} -format=json | jq .results[0].series[0].values[0][1] | tee /dev/stderr | grep 51 diff --git a/tests/automatic/broker/get_last/check_linux.sh b/tests/automatic/broker/get_last/check_linux.sh index b40aad08881ca2b7ee0c34b53716deec9e30f06b..842fc91a96ccef7259992f2a555800da5742e8cb 100644 --- a/tests/automatic/broker/get_last/check_linux.sh +++ b/tests/automatic/broker/get_last/check_linux.sh @@ -31,23 +31,23 @@ sleep 0.3 brokerid=`echo $!` -groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup` +groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup` -curl -v --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - -curl -v --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":2' -curl -v --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":2' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":2' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":2' echo "db.data_${stream}.insert({"_id":3})" | mongo ${database_name} -curl -v --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":3' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":3' echo "db.data_${stream}.insert({"_id":4})" | mongo ${database_name} -curl -v --silent 127.0.0.1:5005/database/data/detector/${stream}/${groupid}/next?token=$token --stderr - | grep '"_id":1' -curl -v --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":4' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/${groupid}/next?token=$token --stderr - | grep '"_id":1' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":4' #with a new group -groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup` -curl -v --silent 127.0.0.1:5005/database/data/detector/${stream}/${groupid}/next?token=$token --stderr - | grep '"_id":1' -curl -v --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":4' \ No newline at end of file +groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup` +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/${groupid}/next?token=$token --stderr - | grep '"_id":1' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":4' \ No newline at end of file diff --git a/tests/automatic/broker/get_last/check_windows.bat b/tests/automatic/broker/get_last/check_windows.bat index 580140b410aec1549d06fe16bd19a499a706a980..497384df3d5af7eb9fac5d7419042187ec850066 100644 --- a/tests/automatic/broker/get_last/check_windows.bat +++ b/tests/automatic/broker/get_last/check_windows.bat @@ -9,34 +9,34 @@ set short_name="%~nx1" c:\opt\consul\nomad run authorizer.nmd c:\opt\consul\nomad run nginx.nmd -ping 192.0.2.1 -n 1 -w 3000 > nul +start /B "" "%full_name%" -config settings.json + +ping 192.0.2.1 -n 1 -w 5000 > nul set token=%BT_DATA_TOKEN% -start /B "" "%full_name%" -config settings.json -ping 192.0.2.1 -n 1 -w 1000 > nul -C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/creategroup > groupid +C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/v0.1/creategroup > groupid set /P groupid=< groupid -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":2 || goto :error -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":2 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":2 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":2 || goto :error echo db.data_default.insert({"_id":3}) | %mongo_exe% %database_name% || goto :error -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":3 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":3 || goto :error echo db.data_default.insert({"_id":4}) | %mongo_exe% %database_name% || goto :error -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/detector/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1 || goto :error -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":4 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":4 || goto :error -C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/creategroup > groupid +C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/v0.1/creategroup > groupid set /P groupid=< groupid -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/detector/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1 || goto :error -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":4 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":4 || goto :error goto :clean diff --git a/tests/automatic/broker/get_meta/check_linux.sh b/tests/automatic/broker/get_meta/check_linux.sh index 2130592555500717d6b207f57817636455a0bd8a..ba084cc02db68612ef667a54c4859060c512f17e 100644 --- a/tests/automatic/broker/get_meta/check_linux.sh +++ b/tests/automatic/broker/get_meta/check_linux.sh @@ -29,6 +29,6 @@ $1 -config settings.json & sleep 0.3 brokerid=`echo $!` -curl -v --silent 127.0.0.1:5005/database/test/detector/default/0/meta/0?token=$token --stderr - | tee /dev/stderr | grep '"data":"test"' -curl -v --silent 127.0.0.1:5005/database/test/detector/default/0/meta/1?token=$token --stderr - | tee /dev/stderr | grep 'no documents' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/test/detector/default/0/meta/0?token=$token --stderr - | tee /dev/stderr | grep '"data":"test"' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/test/detector/default/0/meta/1?token=$token --stderr - | tee /dev/stderr | grep 'no documents' diff --git a/tests/automatic/broker/get_meta/check_windows.bat b/tests/automatic/broker/get_meta/check_windows.bat index cf16f3d18a6100657038480b92667f63c932c5ea..ee02ec0a23cff2fd68a12b8e45fb171693c460a6 100644 --- a/tests/automatic/broker/get_meta/check_windows.bat +++ b/tests/automatic/broker/get_meta/check_windows.bat @@ -8,17 +8,15 @@ set short_name="%~nx1" c:\opt\consul\nomad run authorizer.nmd c:\opt\consul\nomad run nginx.nmd -ping 192.0.2.1 -n 1 -w 3000 > nul +start /B "" "%full_name%" -config settings.json +ping 192.0.2.1 -n 1 -w 5000 > nul set token=%BT_DATA_TOKEN% -start /B "" "%full_name%" -config settings.json - -ping 192.0.2.1 -n 1 -w 1000 > nul -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/detector/default/0/meta/0?token=%token% --stderr - | findstr /c:\"_id\":0 || goto :error -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/detector/default/0/meta/1?token=%token% --stderr - | findstr /c:"no documents" || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/meta/0?token=%token% --stderr - | findstr /c:\"_id\":0 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/meta/1?token=%token% --stderr - | findstr /c:"no documents" || goto :error goto :clean diff --git a/tests/automatic/broker/get_next/check_linux.sh b/tests/automatic/broker/get_next/check_linux.sh index cd204d7248a21956e8dec317e7dfd7435823b4d8..80bb2312f4fcd83c0bb4d0b4c582709785ec2ef5 100644 --- a/tests/automatic/broker/get_next/check_linux.sh +++ b/tests/automatic/broker/get_next/check_linux.sh @@ -31,11 +31,11 @@ $1 -config settings.json & sleep 0.3 brokerid=`echo $!` -groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup` -curl -v --silent 127.0.0.1:5005/database/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"_id":1' -curl -v --silent 127.0.0.1:5005/database/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"_id":2' -curl -v --silent 127.0.0.1:5005/database/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"id_max":2' +groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup` +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"_id":1' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"_id":2' +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"id_max":2' # with a new group -groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup` -curl -v --silent 127.0.0.1:5005/database/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"_id":1' \ No newline at end of file +groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup` +curl -v --silent 127.0.0.1:5005/v0.1/beamtime/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"_id":1' \ No newline at end of file diff --git a/tests/automatic/broker/get_next/check_windows.bat b/tests/automatic/broker/get_next/check_windows.bat index 4d5ed42b65ed9ff318e72739621176c975b50832..89ba33faa721e4c8267d6ae026b5142f1691d140 100644 --- a/tests/automatic/broker/get_next/check_windows.bat +++ b/tests/automatic/broker/get_next/check_windows.bat @@ -11,22 +11,19 @@ set token=%BT_DATA_TOKEN% c:\opt\consul\nomad run authorizer.nmd c:\opt\consul\nomad run nginx.nmd -ping 192.0.2.1 -n 1 -w 3000 > nul - - start /B "" "%full_name%" -config settings.json -ping 192.0.2.1 -n 1 -w 1000 > nul +ping 192.0.2.1 -n 1 -w 5000 > nul -C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/creategroup > groupid +C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/v0.1/creategroup > groupid set /P groupid=< groupid -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1 || goto :error -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":2 || goto :error -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"id_max\":2 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":2 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"id_max\":2 || goto :error -C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/creategroup > groupid +C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/v0.1/creategroup > groupid set /P groupid=< groupid -C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/v0.1/beamtime/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1 || goto :error goto :clean diff --git a/tests/automatic/common_scripts/start_services.bat b/tests/automatic/common_scripts/start_services.bat index e27bc8ccff35a4b9c29c4ea6fbd7acdeae89870a..cbe15b437378469b298ce4355f6bd4ffa592ef4b 100644 --- a/tests/automatic/common_scripts/start_services.bat +++ b/tests/automatic/common_scripts/start_services.bat @@ -16,7 +16,7 @@ if %i% EQU 20 ( goto :error ) ping 192.0.2.1 -n 1 -w 1000 >nul -curl --silent --fail 127.0.0.1:8400/asapo-discovery/asapo-receiver --stderr - | findstr 127.0.0.1 || goto :repeat -curl --silent --fail 127.0.0.1:8400/asapo-discovery/asapo-broker --stderr - | findstr 127.0.0.1 || goto :repeat -curl --silent --fail 127.0.0.1:8400/asapo-discovery/asapo-file-transfer --stderr - | findstr 127.0.0.1 || goto :repeat +curl --silent --fail 127.0.0.1:8400/asapo-discovery/v0.1/asapo-receiver?protocol=v0.1 --stderr - | findstr 127.0.0.1 || goto :repeat +curl --silent --fail 127.0.0.1:8400/asapo-discovery/v0.1/asapo-broker?protocol=v0.1 --stderr - | findstr 127.0.0.1 || goto :repeat +curl --silent --fail 127.0.0.1:8400/asapo-discovery/v0.1/asapo-file-transfer?protocol=v0.1 --stderr - | findstr 127.0.0.1 || goto :repeat echo discovery ready diff --git a/tests/automatic/consumer/consumer_api/consumer_api.cpp b/tests/automatic/consumer/consumer_api/consumer_api.cpp index 91d802d18e75632333eaac2a0fa657047faa8eee..a6f889c2abb8d5943c6c68bb8153a7db9e8e16ea 100644 --- a/tests/automatic/consumer/consumer_api/consumer_api.cpp +++ b/tests/automatic/consumer/consumer_api/consumer_api.cpp @@ -31,6 +31,14 @@ void TestSingle(const std::unique_ptr<asapo::Consumer>& consumer, const std::str asapo::MessageMeta fi; asapo::Error err; + std::string client,server; + bool supported; + err = consumer->GetVersionInfo(&client,&server,&supported); + M_AssertTrue(err == nullptr, "Version OK"); + M_AssertTrue(supported, "client supported by server"); + M_AssertTrue(!client.empty(), "client version"); + M_AssertTrue(!server.empty(), "server version"); + err = consumer->GetNext(group_id, &fi, nullptr, "default"); if (err) { std::cout << err->Explain() << std::endl; diff --git a/tests/automatic/consumer/consumer_api_python/consumer_api.py b/tests/automatic/consumer/consumer_api_python/consumer_api.py index b150e5fb57b5fb14c76e78d1662d6525d43e014b..1b5bf5a153d00bfbd4336529a2ee9a9b9823799f 100644 --- a/tests/automatic/consumer/consumer_api_python/consumer_api.py +++ b/tests/automatic/consumer/consumer_api_python/consumer_api.py @@ -29,6 +29,13 @@ def assert_usermetadata(meta, name): print('meta: ', json.dumps(meta, indent=4, sort_keys=True)) sys.exit(1) +def assert_version(version): + print("asserting version ",version) + ok = version['supported'] and version['client'] and version['server'] + if not ok: + sys.exit(1) + + def assert_eq(val, expected, name): print("asserting eq for " + name) @@ -48,6 +55,10 @@ def check_file_transfer_service(consumer, group_id): def check_single(consumer, group_id): global thread_res + + version = consumer.get_version_info() + assert_version(version) + _, meta = consumer.get_next(group_id, meta_only=True) assert_metaname(meta, "1", "get next1") assert_usermetadata(meta, "get next1") diff --git a/tests/automatic/curl_http_client/curl_http_client_command/curl_httpclient_command.cpp b/tests/automatic/curl_http_client/curl_http_client_command/curl_httpclient_command.cpp index 5d03140816ab9dc7651daf7173f31b2bbc7243c8..c3391d9ab9f63c634420893f615484eacdd7762e 100644 --- a/tests/automatic/curl_http_client/curl_http_client_command/curl_httpclient_command.cpp +++ b/tests/automatic/curl_http_client/curl_http_client_command/curl_httpclient_command.cpp @@ -44,7 +44,7 @@ int main(int argc, char* argv[]) { asapo::HttpCode code; std::string response; std::string input_data; - auto folder_token = consumer_impl->httpclient__->Post(args.uri_authorizer + "/folder", "", authorize_request, &code, + auto folder_token = consumer_impl->httpclient__->Post(args.uri_authorizer + "/v0.1/folder", "", authorize_request, &code, &err); if (err) { std::cout << err->Explain(); @@ -52,7 +52,7 @@ int main(int argc, char* argv[]) { M_AssertTrue(err == nullptr); M_AssertTrue(code == asapo::HttpCode::OK); - consumer_impl->httpclient__->Post(args.uri_authorizer + "/folder", "", "", &code, &err); + consumer_impl->httpclient__->Post(args.uri_authorizer + "/v0.1/folder", "", "", &code, &err); M_AssertTrue(code == asapo::HttpCode::BadRequest); consumer_impl->httpclient__->Post(args.uri_authorizer + "/bla", "", "", &code, &err); @@ -61,12 +61,12 @@ int main(int argc, char* argv[]) { // check post with data std::string transfer = "{\"Folder\":\"" + args.folder + "\",\"FileName\":\"aaa\"}"; std::string cookie = "Authorization=Bearer " + folder_token + ";"; - auto content = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, &code, &err); + auto content = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, &code, &err); M_AssertEq("hello", content); M_AssertTrue(code == asapo::HttpCode::OK); // with array asapo::MessageData data; - err = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, &data, 5, &code); + err = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, &data, 5, &code); M_AssertEq( "hello", reinterpret_cast<char const*>(data.get())); M_AssertTrue(code == asapo::HttpCode::OK); @@ -76,7 +76,7 @@ int main(int argc, char* argv[]) { uint64_t size = 0; auto expected_data = io->GetDataFromFile(fname, &size, &err); M_AssertEq(nullptr, err); - err = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, &data, size, &code); + err = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, &data, size, &code); M_AssertTrue(code == asapo::HttpCode::OK); for (uint64_t i = 0; i < size; i++) { if (expected_data[i] != data[i]) { @@ -86,11 +86,11 @@ int main(int argc, char* argv[]) { // with file transfer = "{\"Folder\":\"" + args.folder + "\",\"FileName\":\"aaa\"}"; - err = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, "bbb", &code); + err = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, "bbb", &code); M_AssertTrue(code == asapo::HttpCode::OK); transfer = "{\"Folder\":\"" + args.folder + "\",\"FileName\":\"random\"}"; - err = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, "random", &code); + err = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, "random", &code); M_AssertTrue(code == asapo::HttpCode::OK); return 0; diff --git a/tests/automatic/file_transfer_service/rest_api/check_linux.sh b/tests/automatic/file_transfer_service/rest_api/check_linux.sh index 2822d4c15ea4edff502d3816006b7c1994b0f6d0..e7350241666f62bd20a802c6ea921af2f5e3f725 100644 --- a/tests/automatic/file_transfer_service/rest_api/check_linux.sh +++ b/tests/automatic/file_transfer_service/rest_api/check_linux.sh @@ -23,22 +23,22 @@ mkdir -p $file_transfer_folder token=$BT_AAA_TOKEN -folder_token=`curl --silent --data "{\"Folder\":\"$file_transfer_folder\",\"BeamtimeId\":\"aaa\",\"Token\":\"$token\"}" 127.0.0.1:5007/folder` +folder_token=`curl --silent --data "{\"Folder\":\"$file_transfer_folder\",\"BeamtimeId\":\"aaa\",\"Token\":\"$token\"}" 127.0.0.1:5007/v0.1/folder` echo $folder_token dd if=/dev/urandom of=$file_transfer_folder/aaa bs=1 count=100000 -curl -o aaa --silent -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"aaa\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/transfer --stderr - | tee /dev/stderr +curl -o aaa --silent -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"aaa\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/v0.1/transfer --stderr - | tee /dev/stderr -curl -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"aaa\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/transfer?sizeonly=true --stderr - | tee /dev/stderr | grep 100000 +curl -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"aaa\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/v0.1/transfer?sizeonly=true --stderr - | tee /dev/stderr | grep 100000 diff -q aaa $file_transfer_folder/aaa dd if=/dev/zero of=$file_transfer_folder/big_file bs=1 count=0 seek=5368709120 -curl -vvv -o big_file -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"big_file\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/transfer --stderr - | tee /dev/stderr +curl -vvv -o big_file -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"big_file\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/v0.1/transfer --stderr - | tee /dev/stderr ls -ln big_file | awk '{ print $5 }' | tee /dev/stderr | grep 5368709120 diff --git a/tests/automatic/file_transfer_service/rest_api/check_windows.bat b/tests/automatic/file_transfer_service/rest_api/check_windows.bat index 2a49fecc6206a9d5cdf2eae712f2e42907673eee..9f869e0d9973a630e45ea532b1fbe35a10179325 100644 --- a/tests/automatic/file_transfer_service/rest_api/check_windows.bat +++ b/tests/automatic/file_transfer_service/rest_api/check_windows.bat @@ -13,12 +13,12 @@ set token=%BT_AAA_TOKEN% mkdir %file_transfer_folder% -C:\Curl\curl.exe --silent --data "{\"Folder\":\"%file_transfer_folder%\",\"BeamtimeId\":\"aaa\",\"Token\":\"%token%\"}" 127.0.0.1:5007/folder > token +C:\Curl\curl.exe --silent --data "{\"Folder\":\"%file_transfer_folder%\",\"BeamtimeId\":\"aaa\",\"Token\":\"%token%\"}" 127.0.0.1:5007/v0.1/folder > token set /P folder_token=< token echo hello > %file_transfer_folder%\aaa -C:\Curl\curl.exe --silent -H "Authorization: Bearer %folder_token%" --data "{\"Folder\":\"%file_transfer_folder%\",\"FileName\":\"aaa\",\"Token\":\"%folder_token%\"}" 127.0.0.1:5008/transfer --stderr - | findstr hello || goto :error +C:\Curl\curl.exe --silent -H "Authorization: Bearer %folder_token%" --data "{\"Folder\":\"%file_transfer_folder%\",\"FileName\":\"aaa\",\"Token\":\"%folder_token%\"}" 127.0.0.1:5008/v0.1/transfer --stderr - | findstr hello || goto :error goto :clean diff --git a/tests/automatic/full_chain/send_recv_streams/send_recv_streams.cpp b/tests/automatic/full_chain/send_recv_streams/send_recv_streams.cpp index 9e18200837e755a3c9e2fbeca72d7064b1ab4cc3..7858801dcd1ea3b0ef8a4e53225c42fde5be4f16 100644 --- a/tests/automatic/full_chain/send_recv_streams/send_recv_streams.cpp +++ b/tests/automatic/full_chain/send_recv_streams/send_recv_streams.cpp @@ -73,7 +73,6 @@ ProducerPtr CreateProducer(const Args& args) { } int main(int argc, char* argv[]) { - asapo::ExitAfterPrintVersionIfNeeded("GetNext consumer Example", argc, argv); Args args; if (argc != 4) { std::cout << "Usage: " + std::string{argv[0]} diff --git a/tests/automatic/full_chain/simple_chain_filegen/check_windows.bat b/tests/automatic/full_chain/simple_chain_filegen/check_windows.bat index dbbfd65225dc280002466170429ddffa097fa187..9d783bd6ad254ac7674fa9262a2a33617febd228 100644 --- a/tests/automatic/full_chain/simple_chain_filegen/check_windows.bat +++ b/tests/automatic/full_chain/simple_chain_filegen/check_windows.bat @@ -23,7 +23,7 @@ mkdir %receiver_folder% mkdir c:\tmp\asapo\test_in\processed start /B "" "%1" test.json -ping 192.0.2.1 -n 1 -w 1000 > nul +ping 192.0.2.1 -n 1 -w 5000 > nul mkdir c:\tmp\asapo\test_in\processed\test1 mkdir c:\tmp\asapo\test_in\processed\test2 diff --git a/tests/automatic/producer/beamtime_metadata/beamtime_metadata.cpp b/tests/automatic/producer/beamtime_metadata/beamtime_metadata.cpp index 5d91a1fd83076ae400f20452e146cbd31629e058..dc1c1f1eff961eb3d87f7edbba81922fc1a2b074 100644 --- a/tests/automatic/producer/beamtime_metadata/beamtime_metadata.cpp +++ b/tests/automatic/producer/beamtime_metadata/beamtime_metadata.cpp @@ -21,7 +21,6 @@ void PrintCommandArguments(const Args& args) { } void ProcessCommandArguments(int argc, char* argv[], Args* args) { - asapo::ExitAfterPrintVersionIfNeeded("dummy beamtime metadata", argc, argv); if (argc != 4) { std::cout << "Usage: " << argv[0] << diff --git a/tests/automatic/producer/python_api/producer_api.py b/tests/automatic/producer/python_api/producer_api.py index 11859cc789bf989e00d866f9d45a06f741106a54..2b419865037cb5cc806da97d3bff01743045c5df 100644 --- a/tests/automatic/producer/python_api/producer_api.py +++ b/tests/automatic/producer/python_api/producer_api.py @@ -36,11 +36,21 @@ def callback(payload, err): print("successfuly sent: ", payload) lock.release() +def assert_version(version): + print("asserting version ",version) + ok = version['supported'] and version['client'] and version['server'] + if not ok: + sys.exit(1) producer = asapo_producer.create_producer(endpoint,'processed', beamtime, 'auto', data_source, token, nthreads, 60000) producer.set_log_level("debug") + +version = producer.get_version_info() +assert_version(version) + + # send single file producer.send_file(1, local_path="./file1", exposed_path="processed/" + data_source + "/" + "file1", user_meta='{"test_key":"test_val"}', callback=callback) diff --git a/tests/automatic/settings/broker_settings.json b/tests/automatic/settings/broker_settings.json index 415622ce7c1ba6fe38424c139f13eb38a3acaf42..a6fb5a48041ae1550dd1f5ffe797929ebac2b0bd 100644 --- a/tests/automatic/settings/broker_settings.json +++ b/tests/automatic/settings/broker_settings.json @@ -1,6 +1,7 @@ { "DatabaseServer":"127.0.0.1:27017", "PerformanceDbServer": "localhost:8086", + "MonitorPerformance": true, "AuthorizationServer": "localhost:8400/asapo-authorizer", "PerformanceDbName": "db_test", "Port":5005, diff --git a/tests/automatic/settings/broker_settings.json.tpl b/tests/automatic/settings/broker_settings.json.tpl index 64411c9d4e1e0dc3dc5cc18820243a9901061c65..b79228a7a658f1e465a60a21f4692fb633a5df66 100644 --- a/tests/automatic/settings/broker_settings.json.tpl +++ b/tests/automatic/settings/broker_settings.json.tpl @@ -3,6 +3,7 @@ "DiscoveryServer": "localhost:8400/asapo-discovery", "AuthorizationServer": "localhost:8400/asapo-authorizer", "PerformanceDbServer": "localhost:8086", + "MonitorPerformance": true, "CheckResendInterval":0, "PerformanceDbName": "db_test", "Port":{{ env "NOMAD_PORT_broker" }}, diff --git a/tests/automatic/settings/receiver_fabric.json.tpl.lin.in b/tests/automatic/settings/receiver_fabric.json.tpl.lin.in index 2138a3296e52ba3c6dd355938c021eb05edbbbf6..6cf20b1cde759790e4373b650413524c0eb10d86 100644 --- a/tests/automatic/settings/receiver_fabric.json.tpl.lin.in +++ b/tests/automatic/settings/receiver_fabric.json.tpl.lin.in @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"auto", "DiscoveryServer": "localhost:8400/asapo-discovery", diff --git a/tests/automatic/settings/receiver_tcp.json.tpl.lin.in b/tests/automatic/settings/receiver_tcp.json.tpl.lin.in index 6061a8a9fd8b7438790b209e8d77c756147a629c..a6f98fe37d8b198a61170a5578f0f212c38b5480 100644 --- a/tests/automatic/settings/receiver_tcp.json.tpl.lin.in +++ b/tests/automatic/settings/receiver_tcp.json.tpl.lin.in @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"auto", "DiscoveryServer": "localhost:8400/asapo-discovery", diff --git a/tests/automatic/settings/receiver_tcp.json.tpl.win.in b/tests/automatic/settings/receiver_tcp.json.tpl.win.in index f96debf98172ac42fd4ce2854d3d7a5c265b3873..c0989d12e5dc83a5f0293976f68493f1eb8fc2b4 100644 --- a/tests/automatic/settings/receiver_tcp.json.tpl.win.in +++ b/tests/automatic/settings/receiver_tcp.json.tpl.win.in @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"auto", "DiscoveryServer": "localhost:8400/asapo-discovery", diff --git a/tests/manual/broker_debug_local/broker.json b/tests/manual/broker_debug_local/broker.json index 55c5f57b1e24f5d0c56b6fd4218b419f04541aa0..cb0155b9ccc950acfb202e8f403c3dda0f229609 100644 --- a/tests/manual/broker_debug_local/broker.json +++ b/tests/manual/broker_debug_local/broker.json @@ -3,6 +3,7 @@ "DiscoveryServer": "localhost:8400/discovery", "AuthorizationServer": "localhost:8400/asapo-authorizer", "PerformanceDbServer": "localhost:8086", + "MonitorPerformance": true, "CheckResendInterval":10, "PerformanceDbName": "db_test", "Port": 5005, diff --git a/tests/manual/broker_debug_local/receiver.json b/tests/manual/broker_debug_local/receiver.json index 8a358c98cbb01faf364b65eb56942638c3c57133..3dfd35396ecf0c78607e5a9983ac33b28a64428c 100644 --- a/tests/manual/broker_debug_local/receiver.json +++ b/tests/manual/broker_debug_local/receiver.json @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"localhost:27017", "DiscoveryServer": "localhost:8400/discovery", diff --git a/tests/manual/broker_debug_local/receiver.json.tpl b/tests/manual/broker_debug_local/receiver.json.tpl index 02e0441d517806b27fbd6ed906cf97519188cdba..4de57e97bac84e89d88767697ef160ec04e85b39 100644 --- a/tests/manual/broker_debug_local/receiver.json.tpl +++ b/tests/manual/broker_debug_local/receiver.json.tpl @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"auto", "DiscoveryServer": "localhost:8400/discovery", diff --git a/tests/manual/performance_broker/settings.json b/tests/manual/performance_broker/settings.json index ddeaeb916d9dacefaa70d5c2ac5b37828087b2c2..b67ac89cdefb2b90aca59811a3675a8351eec59a 100644 --- a/tests/manual/performance_broker/settings.json +++ b/tests/manual/performance_broker/settings.json @@ -1,6 +1,7 @@ { "DatabaseServer":"localhost:27017", "PerformanceDbServer": "localhost:8086", + "MonitorPerformance": true, "AuthorizationServer": "localhost:5007", "PerformanceDbName": "db_test", "Port":5005, diff --git a/tests/manual/performance_broker_receiver/getlast_broker.cpp b/tests/manual/performance_broker_receiver/getlast_broker.cpp index 59011a35aeee20a613a19c85b37a8d264715e4fc..f6a3c1a9270c5ec2de4e63a8ecd8345a0e02fa42 100644 --- a/tests/manual/performance_broker_receiver/getlast_broker.cpp +++ b/tests/manual/performance_broker_receiver/getlast_broker.cpp @@ -169,7 +169,6 @@ int ReadAllData(const Args& params, uint64_t* duration_ms, int* nerrors, int* nb } int main(int argc, char* argv[]) { - asapo::ExitAfterPrintVersionIfNeeded("GetLast consumer Example", argc, argv); Args params; params.datasets = false; if (argc != 9 && argc != 10) { diff --git a/tests/manual/performance_full_chain_simple/broker.json b/tests/manual/performance_full_chain_simple/broker.json index ddeaeb916d9dacefaa70d5c2ac5b37828087b2c2..b67ac89cdefb2b90aca59811a3675a8351eec59a 100644 --- a/tests/manual/performance_full_chain_simple/broker.json +++ b/tests/manual/performance_full_chain_simple/broker.json @@ -1,6 +1,7 @@ { "DatabaseServer":"localhost:27017", "PerformanceDbServer": "localhost:8086", + "MonitorPerformance": true, "AuthorizationServer": "localhost:5007", "PerformanceDbName": "db_test", "Port":5005, diff --git a/tests/manual/performance_full_chain_simple/receiver.json b/tests/manual/performance_full_chain_simple/receiver.json index 3b4bfd1a0223e5040fe36d04d4c07f3378b24899..3c36dadd38dfa8d90994b45019396eefc119d44f 100644 --- a/tests/manual/performance_full_chain_simple/receiver.json +++ b/tests/manual/performance_full_chain_simple/receiver.json @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"localhost:27017", "AuthorizationServer": "localhost:5007", diff --git a/tests/manual/performance_producer_receiver/receiver.json b/tests/manual/performance_producer_receiver/receiver.json index 485e80876e9e42b618d8ff4387bcc9899ba6cfb4..743e5035b20f458bb8183a475fb43d0427581a61 100644 --- a/tests/manual/performance_producer_receiver/receiver.json +++ b/tests/manual/performance_producer_receiver/receiver.json @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"localhost:27017", "DiscoveryServer": "localhost:8400/discovery", diff --git a/tests/manual/producer_cpp/producer.cpp b/tests/manual/producer_cpp/producer.cpp index c198a7506144518a54c0f81f5c15aea2935c2a49..03607b93839e1599617ad19286a76e593734c748 100644 --- a/tests/manual/producer_cpp/producer.cpp +++ b/tests/manual/producer_cpp/producer.cpp @@ -1,7 +1,7 @@ #include <thread> #include <chrono> #include "asapo/asapo_producer.h" - +#include <iostream> void ProcessAfterSend(asapo::RequestCallbackPayload payload, asapo::Error err) { if (err) { diff --git a/tests/manual/python_tests/producer/receiver.json.tpl b/tests/manual/python_tests/producer/receiver.json.tpl index 93539e5f794765ab6e40d2a589c3cd0d402a4569..14a4032cde80ba693285b7f03f1100dc49fbcba3 100644 --- a/tests/manual/python_tests/producer/receiver.json.tpl +++ b/tests/manual/python_tests/producer/receiver.json.tpl @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"localhost:27017", "DiscoveryServer": "localhost:8400/discovery", diff --git a/tests/manual/python_tests/producer_wait_bug_mongo/receiver.json.tpl b/tests/manual/python_tests/producer_wait_bug_mongo/receiver.json.tpl index 93539e5f794765ab6e40d2a589c3cd0d402a4569..14a4032cde80ba693285b7f03f1100dc49fbcba3 100644 --- a/tests/manual/python_tests/producer_wait_bug_mongo/receiver.json.tpl +++ b/tests/manual/python_tests/producer_wait_bug_mongo/receiver.json.tpl @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"localhost:27017", "DiscoveryServer": "localhost:8400/discovery", diff --git a/tests/manual/receiver_debug_local/broker.json.tpl b/tests/manual/receiver_debug_local/broker.json.tpl index 7b55f51c9a8f9cf13cea1042afb80dac1b8739db..968227cab95b7ca440592a2e1c3c0c2c9556d48b 100644 --- a/tests/manual/receiver_debug_local/broker.json.tpl +++ b/tests/manual/receiver_debug_local/broker.json.tpl @@ -2,6 +2,7 @@ "DatabaseServer":"auto", "DiscoveryServer": "localhost:8400/discovery", "PerformanceDbServer": "localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "Port":{{ env "NOMAD_PORT_broker" }}, "LogLevel":"info", diff --git a/tests/manual/receiver_debug_local/receiver.json b/tests/manual/receiver_debug_local/receiver.json index 8a358c98cbb01faf364b65eb56942638c3c57133..3dfd35396ecf0c78607e5a9983ac33b28a64428c 100644 --- a/tests/manual/receiver_debug_local/receiver.json +++ b/tests/manual/receiver_debug_local/receiver.json @@ -1,5 +1,6 @@ { "PerformanceDbServer":"localhost:8086", + "MonitorPerformance": true, "PerformanceDbName": "db_test", "DatabaseServer":"localhost:27017", "DiscoveryServer": "localhost:8400/discovery",