From 13b434668304a51d30c5d272fc3458e4b435029c Mon Sep 17 00:00:00 2001
From: Michael Davis <michael.davis@cern.ch>
Date: Tue, 9 Aug 2022 10:07:00 +0200
Subject: [PATCH] Resolve "CTA Frontend protobuf changes to support dCache"

---
 frontend-grpc/FrontendGRpcSvc.cpp             | 200 ++++++++++--------
 frontend-grpc/FrontendGRpcSvc.h               |  14 +-
 .../protobuf/cta_grpc_frontend.proto          | 123 +++++------
 xrootd-ssi-protobuf-interface                 |   2 +-
 4 files changed, 178 insertions(+), 161 deletions(-)

diff --git a/frontend-grpc/FrontendGRpcSvc.cpp b/frontend-grpc/FrontendGRpcSvc.cpp
index 2df229e411..7016e38b16 100644
--- a/frontend-grpc/FrontendGRpcSvc.cpp
+++ b/frontend-grpc/FrontendGRpcSvc.cpp
@@ -26,7 +26,32 @@ Status CtaRpcImpl::Version(::grpc::ServerContext *context, const ::google::proto
     return Status::OK;
 }
 
-Status CtaRpcImpl::Archive(::grpc::ServerContext* context, const ::cta::frontend::rpc::ArchiveRequest* request, ::cta::frontend::rpc::ArchiveResponse* response) {
+/*
+ * Validate the storage class and issue the archive ID which should be used for the Archive request
+ */
+Status CtaRpcImpl::Create(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::cta::frontend::rpc::CreateResponse* response) {
+  cta::log::LogContext lc(*m_log);
+  cta::log::ScopedParamContainer sp(lc);
+
+  lc.log(cta::log::INFO, "Create");
+
+  try {
+    auto& instance = request->md().wf().instance().name();
+    auto& storageClass = request->md().file().storage_class();
+    cta::common::dataStructures::RequesterIdentity requester;
+    requester.name = request->md().cli().user().username();
+    requester.group = request->md().cli().user().groupname();
+    uint64_t archiveFileId = m_scheduler->checkAndGetNextArchiveFileId(instance, storageClass, requester, lc);
+    response->set_archive_file_id(archiveFileId);
+  } catch (cta::exception::Exception &ex) {
+    lc.log(cta::log::ERR, ex.getMessageValue());
+    return ::grpc::Status(::grpc::StatusCode::INTERNAL, ex.getMessageValue());
+  }
+
+  return Status::OK;
+}
+
+Status CtaRpcImpl::Archive(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::cta::frontend::rpc::ArchiveResponse* response) {
 
     cta::log::LogContext lc(*m_log);
     cta::log::ScopedParamContainer sp(lc);
@@ -36,7 +61,7 @@ Status CtaRpcImpl::Archive(::grpc::ServerContext* context, const ::cta::frontend
     sp.add("remoteHost", context->peer());
     sp.add("request", "archive");
 
-    const std::string storageClass = request->file().storageclass();
+    const std::string storageClass = request->md().file().storage_class();
     if (storageClass.empty()) {
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Storage class is not set.");
     }
@@ -44,65 +69,65 @@ Status CtaRpcImpl::Archive(::grpc::ServerContext* context, const ::cta::frontend
     lc.log(cta::log::DEBUG, "Archive request for storageClass: " + storageClass);
 
     cta::common::dataStructures::RequesterIdentity requester;
-    requester.name = request->cli().user().username();
-    requester.group = request->cli().user().groupname();
+    requester.name = request->md().cli().user().username();
+    requester.group = request->md().cli().user().groupname();
 
     // check validate request args
-    if (request->instance().name().empty()) {
+    if (request->md().wf().instance().name().empty()) {
         lc.log(cta::log::WARNING, "CTA instance is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA instance is not set.");
     }
 
-    if (request->cli().user().username().empty()) {
+    if (request->md().cli().user().username().empty()) {
         lc.log(cta::log::WARNING, "CTA username is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA username is not set.");
     }
 
-    if (request->cli().user().groupname().empty()) {
+    if (request->md().cli().user().groupname().empty()) {
         lc.log(cta::log::WARNING, "CTA groupname is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA groupname is not set.");
     }
 
-    if (!request->file().uid()) {
+    if (!request->md().file().owner().uid()) {
         lc.log(cta::log::WARNING, "File's owner uid can't be zero");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "File's owner uid can't be zero");
     }
 
-    if (!request->file().gid()) {
+    if (!request->md().file().owner().gid()) {
         lc.log(cta::log::WARNING, "File's owner gid can't be zero");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "File's owner gid can't be zero");
     }
 
-    if (request->file().path().empty()) {
+    if (request->md().file().lpath().empty()) {
         lc.log(cta::log::WARNING, "File's path can't be empty");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "File's path can't be empty");
     }
 
-    auto instance = request->instance().name();
+    auto instance = request->md().wf().instance().name();
     sp.add("instance", instance);
-    sp.add("username", request->cli().user().username());
-    sp.add("groupname", request->cli().user().groupname());
+    sp.add("username", request->md().cli().user().username());
+    sp.add("groupname", request->md().cli().user().groupname());
 
     sp.add("storageClass", storageClass);
-    sp.add("fileID", request->file().fid());
+    sp.add("fileID", request->md().file().disk_file_id());
 
     try {
-        uint64_t archiveFileId = m_scheduler->checkAndGetNextArchiveFileId(instance, storageClass, requester, lc);
+        auto archiveFileId = request->md().file().archive_file_id();
         sp.add("archiveID", archiveFileId);
 
         cta::common::dataStructures::ArchiveRequest archiveRequest;
-        cta::checksum::ProtobufToChecksumBlob(request->file().csb(), archiveRequest.checksumBlob);
-        archiveRequest.diskFileInfo.owner_uid = request->file().uid();
-        archiveRequest.diskFileInfo.gid = request->file().gid();
-        archiveRequest.diskFileInfo.path = request->file().path();
-        archiveRequest.diskFileID = request->file().fid();
-        archiveRequest.fileSize = request->file().size();
-        archiveRequest.requester.name = request->cli().user().username();
-        archiveRequest.requester.group = request->cli().user().groupname();
+        cta::checksum::ProtobufToChecksumBlob(request->md().file().csb(), archiveRequest.checksumBlob);
+        archiveRequest.diskFileInfo.owner_uid = request->md().file().owner().uid();
+        archiveRequest.diskFileInfo.gid = request->md().file().owner().gid();
+        archiveRequest.diskFileInfo.path = request->md().file().lpath();
+        archiveRequest.diskFileID = request->md().file().disk_file_id();
+        archiveRequest.fileSize = request->md().file().size();
+        archiveRequest.requester.name = request->md().cli().user().username();
+        archiveRequest.requester.group = request->md().cli().user().groupname();
         archiveRequest.storageClass = storageClass;
-        archiveRequest.srcURL = request->transport().dst_url();
-        archiveRequest.archiveReportURL = request->transport().report_url() + "?archiveid=" + std::to_string(archiveFileId);
-        archiveRequest.archiveErrorReportURL = request->transport().error_report_url();
+        archiveRequest.srcURL = request->md().transport().dst_url();
+        archiveRequest.archiveReportURL = request->md().transport().report_url() + "?archiveid=" + std::to_string(archiveFileId);
+        archiveRequest.archiveErrorReportURL = request->md().transport().error_report_url();
         archiveRequest.creationLog.host = context->peer();
         archiveRequest.creationLog.username = instance;
         archiveRequest.creationLog.time = time(nullptr);
@@ -114,19 +139,17 @@ Status CtaRpcImpl::Archive(::grpc::ServerContext* context, const ::cta::frontend
             + " archiveFileId: " + std::to_string(archiveFileId)
             + " RequestID: " + reqId);
 
-        response->set_fid(archiveFileId);
-        response->set_reqid(reqId);
+        response->set_objectstore_id(reqId);
 
     } catch (cta::exception::Exception &ex) {
-        lc.log(cta::log::CRIT, ex.getMessageValue());
+        lc.log(cta::log::ERR, ex.getMessageValue());
         return ::grpc::Status(::grpc::StatusCode::INTERNAL, ex.getMessageValue());
     }
 
     return Status::OK;
 }
 
-
-Status CtaRpcImpl::Delete(::grpc::ServerContext* context, const ::cta::frontend::rpc::DeleteRequest* request, ::google::protobuf::Empty* response) {
+Status CtaRpcImpl::Delete(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::google::protobuf::Empty* response) {
 
     cta::log::LogContext lc(*m_log);
     cta::log::ScopedParamContainer sp(lc);
@@ -137,60 +160,60 @@ Status CtaRpcImpl::Delete(::grpc::ServerContext* context, const ::cta::frontend:
     sp.add("request", "delete");
 
     // check validate request args
-    if (request->instance().name().empty()) {
+    if (request->md().wf().instance().name().empty()) {
         lc.log(cta::log::WARNING, "CTA instance is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA instance is not set.");
     }
 
-    if (request->cli().user().username().empty()) {
+    if (request->md().cli().user().username().empty()) {
         lc.log(cta::log::WARNING, "CTA username is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA username is not set.");
     }
 
-    if (request->cli().user().groupname().empty()) {
+    if (request->md().cli().user().groupname().empty()) {
         lc.log(cta::log::WARNING, "CTA groupname is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA groupname is not set.");
     }
 
-    if (request->archiveid() == 0) {
+    if (request->md().file().archive_file_id() == 0) {
         lc.log(cta::log::WARNING, "Invalid archive file id");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid archive file id.");
     }
 
-    if (!request->file().uid()) {
+    if (!request->md().file().owner().uid()) {
         lc.log(cta::log::WARNING, "File's owner uid can't be zero");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "File's owner uid can't be zero");
     }
 
-    if (!request->file().gid()) {
+    if (!request->md().file().owner().gid()) {
         lc.log(cta::log::WARNING, "File's owner gid can't be zero");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "File's owner gid can't be zero");
     }
 
-    if (request->file().path().empty()) {
+    if (request->md().file().lpath().empty()) {
         lc.log(cta::log::WARNING, "File's path can't be empty");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "File's path can't be empty");
     }
 
-    auto instance = request->instance().name();
+    auto instance = request->md().wf().instance().name();
     // Unpack message
     cta::common::dataStructures::DeleteArchiveRequest deleteRequest;
-    deleteRequest.requester.name    = request->cli().user().username();
-    deleteRequest.requester.group   = request->cli().user().groupname();
+    deleteRequest.requester.name    = request->md().cli().user().username();
+    deleteRequest.requester.group   = request->md().cli().user().groupname();
 
     sp.add("instance", instance);
-    sp.add("username", request->cli().user().username());
-    sp.add("groupname", request->cli().user().groupname());
-    sp.add("fileID", request->file().fid());
+    sp.add("username", request->md().cli().user().username());
+    sp.add("groupname", request->md().cli().user().groupname());
+    sp.add("fileID", request->md().file().disk_file_id());
 
-    deleteRequest.diskFilePath = request->file().path();
-    deleteRequest.diskFileId = request->file().fid();
+    deleteRequest.diskFilePath = request->md().file().lpath();
+    deleteRequest.diskFileId = request->md().file().disk_file_id();
     deleteRequest.diskInstance = instance;
 
     // remove pending scheduler entry, if any
-    deleteRequest.archiveFileID = request->archiveid();
-    if (!request->reqid().empty()) {
-        deleteRequest.address = request->reqid();
+    deleteRequest.archiveFileID = request->md().file().archive_file_id();
+    if (!request->objectstore_id().empty()) {
+        deleteRequest.address = request->objectstore_id();
     }
 
     // Delete the file from the catalogue or from the objectstore if archive request is created
@@ -207,8 +230,7 @@ Status CtaRpcImpl::Delete(::grpc::ServerContext* context, const ::cta::frontend:
     return Status::OK;
 }
 
-Status CtaRpcImpl::Retrieve(::grpc::ServerContext* context, const ::cta::frontend::rpc::RetrieveRequest* request, ::cta::frontend::rpc::RetrieveResponse *response) {
-
+Status CtaRpcImpl::Retrieve(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::cta::frontend::rpc::RetrieveResponse* response) {
 
     cta::log::LogContext lc(*m_log);
     cta::log::ScopedParamContainer sp(lc);
@@ -216,7 +238,7 @@ Status CtaRpcImpl::Retrieve(::grpc::ServerContext* context, const ::cta::fronten
     sp.add("remoteHost", context->peer());
     sp.add("request", "retrieve");
 
-    const std::string storageClass = request->file().storageclass();
+    const std::string storageClass = request->md().file().storage_class();
     if (storageClass.empty()) {
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Storage class is not set.");
     }
@@ -224,67 +246,67 @@ Status CtaRpcImpl::Retrieve(::grpc::ServerContext* context, const ::cta::fronten
     lc.log(cta::log::DEBUG, "Retrieve request for storageClass: " + storageClass);
 
     // check validate request args
-    if (request->instance().name().empty()) {
+    if (request->md().wf().instance().name().empty()) {
         lc.log(cta::log::WARNING, "CTA instance is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA instance is not set.");
     }
 
-    if (request->cli().user().username().empty()) {
+    if (request->md().cli().user().username().empty()) {
         lc.log(cta::log::WARNING, "CTA username is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA username is not set.");
     }
 
-    if (request->cli().user().groupname().empty()) {
+    if (request->md().cli().user().groupname().empty()) {
         lc.log(cta::log::WARNING, "CTA groupname is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA groupname is not set.");
     }
 
-    if (request->archiveid() == 0) {
+    if (request->md().file().archive_file_id() == 0) {
         lc.log(cta::log::WARNING, "Invalid archive file id");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid archive file id.");
     }
 
-    if (!request->file().uid()) {
+    if (!request->md().file().owner().uid()) {
         lc.log(cta::log::WARNING, "File's owner uid can't be zero");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "File's owner uid can't be zero");
     }
 
-    if (!request->file().gid()) {
+    if (!request->md().file().owner().gid()) {
         lc.log(cta::log::WARNING, "File's owner gid can't be zero");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "File's owner gid can't be zero");
     }
 
-    if (request->file().path().empty()) {
+    if (request->md().file().lpath().empty()) {
         lc.log(cta::log::WARNING, "File's path can't be empty");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "File's path can't be empty");
     }
 
-    auto instance = request->instance().name();
+    auto instance = request->md().wf().instance().name();
 
     sp.add("instance", instance);
-    sp.add("username", request->cli().user().username());
-    sp.add("groupname", request->cli().user().groupname());
+    sp.add("username", request->md().cli().user().username());
+    sp.add("groupname", request->md().cli().user().groupname());
     sp.add("storageClass", storageClass);
-    sp.add("archiveID", request->archiveid());
-    sp.add("fileID", request->file().fid());
+    sp.add("archiveID", request->md().file().archive_file_id());
+    sp.add("fileID", request->md().file().disk_file_id());
 
     // Unpack message
     cta::common::dataStructures::RetrieveRequest retrieveRequest;
-    retrieveRequest.requester.name         = request->cli().user().username();
-    retrieveRequest.requester.group        = request->cli().user().groupname();
-    retrieveRequest.dstURL                 = request->transport().dst_url();
-    retrieveRequest.errorReportURL         = request->transport().error_report_url();
-    retrieveRequest.diskFileInfo.owner_uid = request->file().uid();
-    retrieveRequest.diskFileInfo.gid       = request->file().gid();
-    retrieveRequest.diskFileInfo.path      = request->file().path();
+    retrieveRequest.requester.name         = request->md().cli().user().username();
+    retrieveRequest.requester.group        = request->md().cli().user().groupname();
+    retrieveRequest.dstURL                 = request->md().transport().dst_url();
+    retrieveRequest.errorReportURL         = request->md().transport().error_report_url();
+    retrieveRequest.diskFileInfo.owner_uid = request->md().file().owner().uid();
+    retrieveRequest.diskFileInfo.gid       = request->md().file().owner().gid();
+    retrieveRequest.diskFileInfo.path      = request->md().file().lpath();
     retrieveRequest.creationLog.host       = context->peer();
     retrieveRequest.creationLog.username   = instance;
     retrieveRequest.creationLog.time       = time(nullptr);
     retrieveRequest.isVerifyOnly           = false;
 
-    retrieveRequest.archiveFileID = request->archiveid();
-    sp.add("archiveID", request->archiveid());
-    sp.add("fileID", request->file().fid());
+    retrieveRequest.archiveFileID = request->md().file().archive_file_id();
+    sp.add("archiveID", request->md().file().archive_file_id());
+    sp.add("fileID", request->md().file().disk_file_id());
 
     cta::utils::Timer t;
 
@@ -296,7 +318,7 @@ Status CtaRpcImpl::Retrieve(::grpc::ServerContext* context, const ::cta::fronten
                                + " archiveFileId: " + std::to_string(retrieveRequest.archiveFileID)
                                + " RequestID: " + reqId);
 
-        response->set_reqid(reqId);
+        response->set_objectstore_id(reqId);
     } catch (cta::exception::Exception &ex){
         lc.log(cta::log::CRIT, ex.getMessageValue());
         return ::grpc::Status(::grpc::StatusCode::INTERNAL, ex.getMessageValue());
@@ -304,7 +326,7 @@ Status CtaRpcImpl::Retrieve(::grpc::ServerContext* context, const ::cta::fronten
     return Status::OK;
 }
 
-Status CtaRpcImpl::CancelRetrieve(::grpc::ServerContext* context, const ::cta::frontend::rpc::CancelRetrieveRequest* request, ::google::protobuf::Empty* response) {
+Status CtaRpcImpl::CancelRetrieve(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::google::protobuf::Empty* response) {
 
     cta::log::LogContext lc(*m_log);
     cta::log::ScopedParamContainer sp(lc);
@@ -315,39 +337,39 @@ Status CtaRpcImpl::CancelRetrieve(::grpc::ServerContext* context, const ::cta::f
     sp.add("request", "cancel");
 
     // check validate request args
-    if (request->instance().name().empty()) {
+    if (request->md().wf().instance().name().empty()) {
         lc.log(cta::log::WARNING, "CTA instance is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA instance is not set.");
     }
 
-    if (request->cli().user().username().empty()) {
+    if (request->md().cli().user().username().empty()) {
         lc.log(cta::log::WARNING, "CTA username is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA username is not set.");
     }
 
-    if (request->cli().user().groupname().empty()) {
+    if (request->md().cli().user().groupname().empty()) {
         lc.log(cta::log::WARNING, "CTA groupname is not set");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "CTA groupname is not set.");
     }
 
-    if (!request->archiveid()) {
+    if (!request->md().file().archive_file_id()) {
         lc.log(cta::log::WARNING, "Invalid archive file id");
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid archive file id.");
     }
 
-    auto instance = request->instance().name();
+    auto instance = request->md().wf().instance().name();
     // Unpack message
     cta::common::dataStructures::CancelRetrieveRequest cancelRequest;
-    cancelRequest.requester.name    = request->cli().user().username();
-    cancelRequest.requester.group   = request->cli().user().groupname();
-    cancelRequest.archiveFileID = request->archiveid();
-    cancelRequest.retrieveRequestId = request->reqid();
+    cancelRequest.requester.name    = request->md().cli().user().username();
+    cancelRequest.requester.group   = request->md().cli().user().groupname();
+    cancelRequest.archiveFileID = request->md().file().archive_file_id();
+    cancelRequest.retrieveRequestId = request->objectstore_id();
 
     sp.add("instance", instance);
-    sp.add("username", request->cli().user().username());
-    sp.add("groupname", request->cli().user().groupname());
-    sp.add("fileID", request->archiveid());
-    sp.add("schedulerJobID", request->reqid());
+    sp.add("username", request->md().cli().user().username());
+    sp.add("groupname", request->md().cli().user().groupname());
+    sp.add("fileID", request->md().file().archive_file_id());
+    sp.add("schedulerJobID", request->objectstore_id());
 
     m_scheduler->abortRetrieve(instance, cancelRequest, lc);
 
diff --git a/frontend-grpc/FrontendGRpcSvc.h b/frontend-grpc/FrontendGRpcSvc.h
index 294f0f40cc..6a0d44ad16 100644
--- a/frontend-grpc/FrontendGRpcSvc.h
+++ b/frontend-grpc/FrontendGRpcSvc.h
@@ -28,11 +28,13 @@ private:
 public:
     CtaRpcImpl(cta::log::Logger *logger, std::unique_ptr<cta::catalogue::Catalogue> &catalogue, std::unique_ptr<cta::Scheduler> &scheduler);
 
+    // Archive/Retrieve interface
+    Status Create(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::cta::frontend::rpc::CreateResponse* response);
+    Status Archive(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::cta::frontend::rpc::ArchiveResponse* response);
+    Status Retrieve(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::cta::frontend::rpc::RetrieveResponse* response);
+    Status CancelRetrieve(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::google::protobuf::Empty* response);
+    Status Delete(::grpc::ServerContext* context, const ::cta::frontend::rpc::SchedulerRequest* request, ::google::protobuf::Empty* response);
+
+    // Admin interface
     Status Version(::grpc::ServerContext *context, const ::google::protobuf::Empty *request, ::cta::admin::Version *response);
-
-    Status Archive(::grpc::ServerContext* context, const ::cta::frontend::rpc::ArchiveRequest* request, ::cta::frontend::rpc::ArchiveResponse* response);
-    Status Retrieve(::grpc::ServerContext* context, const ::cta::frontend::rpc::RetrieveRequest* request, ::cta::frontend::rpc::RetrieveResponse* response);
-    Status Delete(::grpc::ServerContext* context, const ::cta::frontend::rpc::DeleteRequest* request, ::google::protobuf::Empty* response);
-    Status CancelRetrieve(::grpc::ServerContext* context, const ::cta::frontend::rpc::CancelRetrieveRequest* request, ::google::protobuf::Empty* response);
 };
-
diff --git a/frontend-grpc/grpc-proto/protobuf/cta_grpc_frontend.proto b/frontend-grpc/grpc-proto/protobuf/cta_grpc_frontend.proto
index d2ad36748f..9dbbb6a517 100644
--- a/frontend-grpc/grpc-proto/protobuf/cta_grpc_frontend.proto
+++ b/frontend-grpc/grpc-proto/protobuf/cta_grpc_frontend.proto
@@ -1,97 +1,90 @@
+/*
+ * @project      The CERN Tape Archive (CTA)
+ * @copyright    Copyright © 2021-2022 CERN
+ * @license      This program is free software, distributed under the terms of the GNU General Public
+ *               Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can
+ *               redistribute it and/or modify it under the terms of the GPL Version 3, or (at your
+ *               option) any later version.
+ *
+ *               This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ *               WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *               PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ *               In applying this licence, CERN does not waive the privileges and immunities
+ *               granted to it by virtue of its status as an Intergovernmental Organization or
+ *               submit itself to any jurisdiction.
+ */
+
 syntax = "proto3";
 
 option java_multiple_files = true;
 option java_package = "ch.cern.cta.rpc";
 option optimize_for = CODE_SIZE;
+
 package cta.frontend.rpc;
 
 import "google/protobuf/empty.proto";
-
-import "cta_common.proto";
 import "cta_admin.proto";
 import "cta_eos.proto";
-
-//
-// gRPC interface to CTA frontend
-//
+import "cta_frontend.proto";
 
 /*
- * File metadata
+ * Requests sent to the CTA Frontend
  */
-message FileInfo {
-  string fid = 1; // disk system unique file ID
-  uint64 size = 2; // file size
-  string storageClass = 3; // tape system related storage class (file family)
-  cta.common.ChecksumBlob csb = 4; // set of knows checksums for the given file
-  uint32 uid = 5; // files owner user id
-  uint32 gid = 6; // files owner group id
-  string path = 7; // files path at creation time
-}
 
-/*
- * Response to the ARCHIVE request.
- */
-message ArchiveResponse {
-  uint64 fid = 1; // tape system unique file ID
-  string reqId = 2; // tape request scheduler ID, used to cancel the request
+// gRPC Request for Archive/Retrieve/Delete/Cancel events
+message SchedulerRequest {
+  cta.eos.Notification md        = 1;    //< Metadata associated with this request
+  string objectstore_id          = 2;    //< Address of the queued request in the SchedulerDB (objectstore),
+                                         //< used to cancel a previous PREPARE request
+  string client_version          = 3;    //< Client software version
+  string client_protobuf_version = 4;    //< Client protobuf version
 }
 
-/*
- * Response to the RETRIEVE request.
- */
-message RetrieveResponse {
-  string reqId = 1; // tape request scheduler ID, used to cancel the request
+// gRPC Request for Admin commands
+message AdminRequest {
+  cta.admin.AdminCmd admincmd    = 1;    //< CTA Admin Command
+  string client_version          = 2;    //< Version of cta-admin client
+  string client_protobuf_version = 3;    //< Client protobuf version
 }
 
-
 /*
- * ARCHIVE request.
+ * Metadata responses returned by the CTA Frontend
  */
-message ArchiveRequest {
-  cta.common.Service instance = 1;  // client instance ID
-  cta.eos.Client cli = 2;      // requester information
-  cta.eos.Transport transport = 3;      // IO, error and success endpoints
-  FileInfo file = 4;      // files' metadata
+
+message CreateResponse {
+  uint64 archive_file_id = 1;    //< CTA-assigned unique file ID
 }
 
-/*
- * RETRIEVE request.
- */
-message RetrieveRequest {
-  cta.common.Service instance = 1;  // client instance ID
-  cta.eos.Client cli = 2;      // requester information
-  cta.eos.Transport transport = 3;      // IO, error and success endpoints
-  FileInfo file = 4;      // files' metadata
-  uint64 archiveId = 5; // tape system unique file ID
+message ArchiveResponse {
+  string objectstore_id = 1;     //< Address of the queued request in the SchedulerDB (objectstore),
+                                 //< used to cancel the request
 }
 
-/*
- * DELETE request.
- */
-message DeleteRequest {
-  cta.common.Service instance = 1;  // client instance ID
-  cta.eos.Client cli = 2;      // requester information
-  FileInfo file = 3;      // files' metadata
-  uint64 archiveId = 4; // tape system unique file ID
-  string reqId = 5; // pending ARCHIVE request scheduler ID
+message RetrieveResponse {
+  string objectstore_id = 1;     //< Address of the queued request in the SchedulerDB (objectstore),
+                                 //< used to cancel the request
 }
 
 /*
- * CANCEL RETRIEVE request.
+ * gRPC request-response pairs
  */
-message CancelRetrieveRequest {
-  cta.common.Service instance = 1;  // client instance ID
-  cta.eos.Client cli = 2;      // requester information
-  uint64 archiveId = 3; // tape system unique file ID
-  string reqId = 4; // tape request scheduler ID, used to cancel the request
-}
 
 service CtaRpc {
-  rpc Version (google.protobuf.Empty) returns (cta.admin.Version) {}
+  // Generic request to give a migration path from EOS
+  rpc GenericRequest (cta.xrd.Request) returns (cta.xrd.Response) {}
+
+  // Specific request types
+  rpc Create (SchedulerRequest) returns (CreateResponse) {}
+  rpc Archive (SchedulerRequest) returns (ArchiveResponse) {}
+  rpc Retrieve (SchedulerRequest) returns (RetrieveResponse) {}
+  rpc Delete (SchedulerRequest) returns (google.protobuf.Empty) {}
+  rpc CancelRetrieve (SchedulerRequest) returns (google.protobuf.Empty) {}
 
-  rpc Archive (ArchiveRequest) returns (ArchiveResponse) {}
-  rpc Retrieve (RetrieveRequest) returns (RetrieveResponse) {}
-  rpc Delete (DeleteRequest) returns (google.protobuf.Empty) {}
-  rpc CancelRetrieve (CancelRetrieveRequest) returns (google.protobuf.Empty) {}
+  // Admin commands
+  rpc Admin (AdminRequest) returns (cta.xrd.Response) {}
+
+  // Should possibly be replaced by AdminRequest "version" command
+  rpc Version (google.protobuf.Empty) returns (cta.admin.Version) {}
+}
 
-}
\ No newline at end of file
diff --git a/xrootd-ssi-protobuf-interface b/xrootd-ssi-protobuf-interface
index 0d99b9180f..f05ac4849d 160000
--- a/xrootd-ssi-protobuf-interface
+++ b/xrootd-ssi-protobuf-interface
@@ -1 +1 @@
-Subproject commit 0d99b9180f83448e4e2dd9ff82d1cf0469e937e6
+Subproject commit f05ac4849d43590c459fe30bb834ef96eb515d7e
-- 
GitLab