This is an automated email from the ASF dual-hosted git repository.
mssun pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git
The following commit(s) were added to refs/heads/develop by this push:
new b177b47 [management] Handle function in management service (#221)
b177b47 is described below
commit b177b4779cd31bca9ec0f23067ca0c069b46bf8c
Author: TX <[email protected]>
AuthorDate: Tue Feb 11 13:04:51 2020 -0800
[management] Handle function in management service (#221)
---
services/management/enclave/src/function.rs | 79 +++++++
services/management/enclave/src/lib.rs | 2 +
services/management/enclave/src/service.rs | 120 ++++++++++-
.../src/proto/teaclave_frontend_service.proto | 39 ++++
.../src/proto/teaclave_management_service.proto | 2 +
services/proto/src/teaclave_frontend_service.rs | 239 +++++++++++++++++++++
.../enclave/src/teaclave_management_service.rs | 70 +++++-
7 files changed, 549 insertions(+), 2 deletions(-)
diff --git a/services/management/enclave/src/function.rs
b/services/management/enclave/src/function.rs
new file mode 100644
index 0000000..4c7834e
--- /dev/null
+++ b/services/management/enclave/src/function.rs
@@ -0,0 +1,79 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+use anyhow::{anyhow, Result};
+use serde::{Deserialize, Serialize};
+use serde_json;
+use std::prelude::v1::*;
+use teaclave_proto::teaclave_frontend_service::{
+ FunctionInput, FunctionOutput, RegisterFunctionRequest,
+};
+
+use uuid::Uuid;
+const SCRIPT_PREFIX: &str = "function-";
+const NATIVE_PREFIX: &str = "native-";
+#[derive(Debug, Deserialize, Serialize)]
+pub(crate) struct Function {
+ pub(crate) function_id: String,
+ pub(crate) name: String,
+ pub(crate) description: String,
+ pub(crate) payload: Vec<u8>,
+ pub(crate) is_public: bool,
+ pub(crate) arg_list: Vec<String>,
+ pub(crate) input_list: Vec<FunctionInput>,
+ pub(crate) output_list: Vec<FunctionOutput>,
+ pub(crate) owner: String,
+ pub(crate) is_native: bool,
+}
+
+impl Function {
+ pub(crate) fn new_from_register_request(
+ request: RegisterFunctionRequest,
+ owner: String,
+ ) -> Function {
+ let function_id = format!("{}{}", SCRIPT_PREFIX,
Uuid::new_v4().to_string());
+ Function {
+ function_id,
+ name: request.name,
+ description: request.description,
+ payload: request.payload,
+ is_public: request.is_public,
+ arg_list: request.arg_list,
+ input_list: request.input_list,
+ output_list: request.output_list,
+ owner,
+ is_native: false,
+ }
+ }
+
+ pub(crate) fn from_slice(bytes: &[u8]) -> Result<Self> {
+ let ret: Function =
+ serde_json::from_slice(&bytes).map_err(|_| anyhow!("failed to
Deserialize"))?;
+ Ok(ret)
+ }
+
+ pub(crate) fn to_vec(&self) -> Result<Vec<u8>> {
+ serde_json::to_vec(&self).map_err(|_| anyhow!("failed to Serialize"))
+ }
+
+ pub(crate) fn get_key_vec(&self) -> Vec<u8> {
+ self.function_id.as_bytes().to_vec()
+ }
+
+ pub(crate) fn is_function_id(id: &str) -> bool {
+ id.starts_with(NATIVE_PREFIX) || id.starts_with(SCRIPT_PREFIX)
+ }
+}
diff --git a/services/management/enclave/src/lib.rs
b/services/management/enclave/src/lib.rs
index 1d78230..10fb682 100644
--- a/services/management/enclave/src/lib.rs
+++ b/services/management/enclave/src/lib.rs
@@ -40,6 +40,7 @@ use teaclave_rpc::server::SgxTrustedTlsServer;
use teaclave_service_enclave_utils::ServiceEnclave;
use teaclave_types::{EnclaveInfo, TeeServiceError, TeeServiceResult};
mod file;
+mod function;
mod fusion_data;
mod service;
@@ -152,6 +153,7 @@ pub mod tests {
service::tests::handle_input_file,
service::tests::handle_output_file,
service::tests::handle_fusion_data,
+ service::tests::handle_function,
)
}
}
diff --git a/services/management/enclave/src/service.rs
b/services/management/enclave/src/service.rs
index fd5069e..b934b21 100644
--- a/services/management/enclave/src/service.rs
+++ b/services/management/enclave/src/service.rs
@@ -1,10 +1,12 @@
use crate::file::{InputFile, OutputFile};
+use crate::function::Function;
use crate::fusion_data::FusionData;
use anyhow::{anyhow, Result};
use std::prelude::v1::*;
use std::sync::{Arc, SgxMutex as Mutex};
use teaclave_proto::teaclave_frontend_service::{
- GetFusionDataRequest, GetFusionDataResponse, GetOutputFileRequest,
GetOutputFileResponse,
+ GetFunctionRequest, GetFunctionResponse, GetFusionDataRequest,
GetFusionDataResponse,
+ GetOutputFileRequest, GetOutputFileResponse, RegisterFunctionRequest,
RegisterFunctionResponse,
RegisterInputFileRequest, RegisterInputFileResponse,
RegisterOutputFileRequest,
RegisterOutputFileResponse,
};
@@ -151,17 +153,103 @@ impl TeaclaveManagement for TeaclaveManagementService {
};
Ok(response)
}
+
+ fn register_function(
+ &self,
+ request: Request<RegisterFunctionRequest>,
+ ) -> TeaclaveServiceResponseResult<RegisterFunctionResponse> {
+ let user_id = request
+ .metadata
+ .get("id")
+ .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
+ .to_string();
+
+ let request = request.message;
+ let function = Function::new_from_register_request(request, user_id);
+ let key = function.get_key_vec();
+ let value = function
+ .to_vec()
+ .map_err(|_| TeaclaveManagementError::DataError)?;
+
+ self.write_to_storage(&key, &value)
+ .map_err(|_| TeaclaveManagementError::StorageError)?;
+ let response = RegisterFunctionResponse {
+ function_id: function.function_id,
+ };
+ Ok(response)
+ }
+
+ fn get_function(
+ &self,
+ request: Request<GetFunctionRequest>,
+ ) -> TeaclaveServiceResponseResult<GetFunctionResponse> {
+ let user_id = request
+ .metadata
+ .get("id")
+ .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
+ .to_string();
+ let function_id = request.message.function_id;
+ if !Function::is_function_id(&function_id) {
+ return Err(TeaclaveManagementError::PermissionDenied.into());
+ }
+ let key: &[u8] = function_id.as_bytes();
+ let value = self
+ .read_from_storage(key)
+ .map_err(|_| TeaclaveManagementError::StorageError)?;
+ let function =
+ Function::from_slice(&value).map_err(|_|
TeaclaveManagementError::DataError)?;
+ if !(function.is_public || function.owner == user_id) {
+ return Err(TeaclaveManagementError::PermissionDenied.into());
+ }
+ let response = GetFunctionResponse {
+ name: function.name,
+ description: function.description,
+ owner: function.owner,
+ payload: function.payload,
+ is_public: function.is_public,
+ arg_list: function.arg_list,
+ input_list: function.input_list,
+ output_list: function.output_list,
+ };
+ Ok(response)
+ }
}
impl TeaclaveManagementService {
#[cfg(test_mode)]
fn add_mock_data(&self) -> Result<()> {
+ use teaclave_proto::teaclave_frontend_service::{FunctionInput,
FunctionOutput};
let mut fusion_data =
FusionData::new(vec!["mock_user_a".to_string(),
"mock_user_b".to_string()])?;
fusion_data.data_id = "fusion-data-mock-data".to_string();
let key = fusion_data.get_key_vec();
let value = fusion_data.to_vec()?;
self.write_to_storage(&key, &value)?;
+
+ let function_input = FunctionInput {
+ name: "input".to_string(),
+ description: "input_desc".to_string(),
+ };
+ let function_output = FunctionOutput {
+ name: "output".to_string(),
+ description: "output_desc".to_string(),
+ };
+
+ let native_function = Function {
+ function_id: "native-mock-native-func".to_string(),
+ name: "mock-native-func".to_string(),
+ description: "mock-desc".to_string(),
+ payload: b"mock-payload".to_vec(),
+ is_public: true,
+ arg_list: vec!["arg".to_string()],
+ input_list: vec![function_input],
+ output_list: vec![function_output],
+ owner: "teaclave".to_string(),
+ is_native: true,
+ };
+ let key = native_function.get_key_vec();
+ let value = native_function.to_vec()?;
+ self.write_to_storage(&key, &value)?;
Ok(())
}
@@ -202,6 +290,7 @@ impl TeaclaveManagementService {
#[cfg(feature = "enclave_unit_test")]
pub mod tests {
use super::*;
+ use teaclave_proto::teaclave_frontend_service::{FunctionInput,
FunctionOutput};
use teaclave_types::{TeaclaveFileCryptoInfo, TeaclaveFileRootKey128};
use url::Url;
@@ -249,4 +338,33 @@ pub mod tests {
let deserialized_data = FusionData::from_slice(&value).unwrap();
info!("data: {:?}", deserialized_data);
}
+
+ pub fn handle_function() {
+ let function_input = FunctionInput {
+ name: "input".to_string(),
+ description: "input_desc".to_string(),
+ };
+ let function_output = FunctionOutput {
+ name: "output".to_string(),
+ description: "output_desc".to_string(),
+ };
+ let register_request = RegisterFunctionRequest {
+ name: "mock_function".to_string(),
+ description: "mock function".to_string(),
+ payload: b"python script".to_vec(),
+ is_public: true,
+ arg_list: vec!["arg".to_string()],
+ input_list: vec![function_input],
+ output_list: vec![function_output],
+ };
+ let function =
+ Function::new_from_register_request(register_request,
"mock_user".to_string());
+ let key = function.get_key_vec();
+ let key_str = std::str::from_utf8(&key).unwrap();
+ info!("key: {}", key_str);
+ assert!(Function::is_function_id(key_str));
+ let value = function.to_vec().unwrap();
+ let deserialized_data = Function::from_slice(&value).unwrap();
+ info!("data: {:?}", deserialized_data);
+ }
}
diff --git a/services/proto/src/proto/teaclave_frontend_service.proto
b/services/proto/src/proto/teaclave_frontend_service.proto
index a5d85da..c41e585 100644
--- a/services/proto/src/proto/teaclave_frontend_service.proto
+++ b/services/proto/src/proto/teaclave_frontend_service.proto
@@ -40,6 +40,45 @@ message GetFusionDataResponse {
repeated string data_owner_id_list = 2;
}
+message FunctionInput {
+ string name = 1;
+ string description = 2;
+}
+
+message FunctionOutput {
+ string name = 1;
+ string description = 2;
+}
+
+message RegisterFunctionRequest {
+ string name = 1;
+ string description = 2;
+ bytes payload = 3;
+ bool is_public = 4;
+ repeated string arg_list = 5;
+ repeated FunctionInput input_list = 6;
+ repeated FunctionOutput output_list = 7;
+}
+
+message RegisterFunctionResponse {
+ string function_id = 1;
+}
+
+message GetFunctionRequest {
+ string function_id = 1;
+}
+
+message GetFunctionResponse {
+ string name = 1;
+ string description = 2;
+ string owner = 3;
+ bytes payload = 4;
+ bool is_public = 5;
+ repeated string arg_list = 6;
+ repeated FunctionInput input_list = 7;
+ repeated FunctionOutput output_list = 8;
+}
+
service TeaclaveFrontend {
rpc RegisterInputFile (RegisterInputFileRequest) returns
(RegisterInputFileResponse);
rpc RegisterOutputFile (RegisterOutputFileRequest) returns
(RegisterOutputFileResponse);
diff --git a/services/proto/src/proto/teaclave_management_service.proto
b/services/proto/src/proto/teaclave_management_service.proto
index d7a9c85..c0b154f 100644
--- a/services/proto/src/proto/teaclave_management_service.proto
+++ b/services/proto/src/proto/teaclave_management_service.proto
@@ -9,4 +9,6 @@ service TeaclaveManagement {
rpc RegisterOutputFile
(teaclave_frontend_service_proto.RegisterOutputFileRequest) returns
(teaclave_frontend_service_proto.RegisterOutputFileResponse);
rpc GetOutputFile (teaclave_frontend_service_proto.GetOutputFileRequest)
returns (teaclave_frontend_service_proto.GetOutputFileResponse);
rpc GetFusionData (teaclave_frontend_service_proto.GetFusionDataRequest)
returns (teaclave_frontend_service_proto.GetFusionDataResponse);
+ rpc RegisterFunction
(teaclave_frontend_service_proto.RegisterFunctionRequest) returns
(teaclave_frontend_service_proto.RegisterFunctionResponse);
+ rpc GetFunction (teaclave_frontend_service_proto.GetFunctionRequest) returns
(teaclave_frontend_service_proto.GetFunctionResponse);
}
\ No newline at end of file
diff --git a/services/proto/src/teaclave_frontend_service.rs
b/services/proto/src/teaclave_frontend_service.rs
index 801d694..e7f9865 100644
--- a/services/proto/src/teaclave_frontend_service.rs
+++ b/services/proto/src/teaclave_frontend_service.rs
@@ -2,6 +2,7 @@ use crate::teaclave_frontend_service_proto as proto;
use anyhow::anyhow;
use anyhow::{Error, Result};
use core::convert::TryInto;
+use serde::{Deserialize, Serialize};
use teaclave_types::TeaclaveFileCryptoInfo;
use url::Url;
@@ -54,6 +55,51 @@ pub struct GetFusionDataResponse {
pub data_owner_id_list: std::vec::Vec<std::string::String>,
}
+#[derive(Debug, Deserialize, Serialize)]
+pub struct FunctionInput {
+ pub name: std::string::String,
+ pub description: std::string::String,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct FunctionOutput {
+ pub name: std::string::String,
+ pub description: std::string::String,
+}
+
+#[derive(Debug)]
+pub struct RegisterFunctionRequest {
+ pub name: std::string::String,
+ pub description: std::string::String,
+ pub payload: std::vec::Vec<u8>,
+ pub is_public: bool,
+ pub arg_list: std::vec::Vec<std::string::String>,
+ pub input_list: std::vec::Vec<FunctionInput>,
+ pub output_list: std::vec::Vec<FunctionOutput>,
+}
+
+#[derive(Debug)]
+pub struct RegisterFunctionResponse {
+ pub function_id: std::string::String,
+}
+
+#[derive(Debug)]
+pub struct GetFunctionRequest {
+ pub function_id: std::string::String,
+}
+
+#[derive(Debug)]
+pub struct GetFunctionResponse {
+ pub name: std::string::String,
+ pub description: std::string::String,
+ pub owner: std::string::String,
+ pub payload: std::vec::Vec<u8>,
+ pub is_public: bool,
+ pub arg_list: std::vec::Vec<std::string::String>,
+ pub input_list: std::vec::Vec<FunctionInput>,
+ pub output_list: std::vec::Vec<FunctionOutput>,
+}
+
impl std::convert::TryFrom<proto::RegisterInputFileRequest> for
RegisterInputFileRequest {
type Error = Error;
@@ -217,3 +263,196 @@ impl From<GetFusionDataResponse> for
proto::GetFusionDataResponse {
}
}
}
+
+impl std::convert::TryFrom<proto::FunctionInput> for FunctionInput {
+ type Error = Error;
+
+ fn try_from(proto: proto::FunctionInput) -> Result<Self> {
+ let ret = Self {
+ name: proto.name,
+ description: proto.description,
+ };
+
+ Ok(ret)
+ }
+}
+
+impl From<FunctionInput> for proto::FunctionInput {
+ fn from(input: FunctionInput) -> Self {
+ Self {
+ name: input.name,
+ description: input.description,
+ }
+ }
+}
+
+impl std::convert::TryFrom<proto::FunctionOutput> for FunctionOutput {
+ type Error = Error;
+
+ fn try_from(proto: proto::FunctionOutput) -> Result<Self> {
+ let ret = Self {
+ name: proto.name,
+ description: proto.description,
+ };
+
+ Ok(ret)
+ }
+}
+
+impl From<FunctionOutput> for proto::FunctionOutput {
+ fn from(output: FunctionOutput) -> Self {
+ Self {
+ name: output.name,
+ description: output.description,
+ }
+ }
+}
+
+impl std::convert::TryFrom<proto::RegisterFunctionRequest> for
RegisterFunctionRequest {
+ type Error = Error;
+
+ fn try_from(proto: proto::RegisterFunctionRequest) -> Result<Self> {
+ let input_list: Result<std::vec::Vec<FunctionInput>> = proto
+ .input_list
+ .into_iter()
+ .map(FunctionInput::try_from)
+ .collect();
+ let output_list: Result<std::vec::Vec<FunctionOutput>> = proto
+ .output_list
+ .into_iter()
+ .map(FunctionOutput::try_from)
+ .collect();
+
+ let ret = Self {
+ name: proto.name,
+ description: proto.description,
+ payload: proto.payload,
+ is_public: proto.is_public,
+ arg_list: proto.arg_list,
+ input_list: input_list?,
+ output_list: output_list?,
+ };
+ Ok(ret)
+ }
+}
+
+impl From<RegisterFunctionRequest> for proto::RegisterFunctionRequest {
+ fn from(request: RegisterFunctionRequest) -> Self {
+ let input_list: std::vec::Vec<proto::FunctionInput> = request
+ .input_list
+ .into_iter()
+ .map(proto::FunctionInput::from)
+ .collect();
+ let output_list: std::vec::Vec<proto::FunctionOutput> = request
+ .output_list
+ .into_iter()
+ .map(proto::FunctionOutput::from)
+ .collect();
+
+ Self {
+ name: request.name,
+ description: request.description,
+ payload: request.payload,
+ is_public: request.is_public,
+ arg_list: request.arg_list,
+ input_list,
+ output_list,
+ }
+ }
+}
+
+impl std::convert::TryFrom<proto::RegisterFunctionResponse> for
RegisterFunctionResponse {
+ type Error = Error;
+
+ fn try_from(proto: proto::RegisterFunctionResponse) -> Result<Self> {
+ let ret = Self {
+ function_id: proto.function_id,
+ };
+
+ Ok(ret)
+ }
+}
+
+impl From<RegisterFunctionResponse> for proto::RegisterFunctionResponse {
+ fn from(response: RegisterFunctionResponse) -> Self {
+ Self {
+ function_id: response.function_id,
+ }
+ }
+}
+
+impl std::convert::TryFrom<proto::GetFunctionRequest> for GetFunctionRequest {
+ type Error = Error;
+
+ fn try_from(proto: proto::GetFunctionRequest) -> Result<Self> {
+ let ret = Self {
+ function_id: proto.function_id,
+ };
+
+ Ok(ret)
+ }
+}
+
+impl From<GetFunctionRequest> for proto::GetFunctionRequest {
+ fn from(request: GetFunctionRequest) -> Self {
+ Self {
+ function_id: request.function_id,
+ }
+ }
+}
+
+impl std::convert::TryFrom<proto::GetFunctionResponse> for GetFunctionResponse
{
+ type Error = Error;
+
+ fn try_from(proto: proto::GetFunctionResponse) -> Result<Self> {
+ let input_list: Result<std::vec::Vec<FunctionInput>> = proto
+ .input_list
+ .into_iter()
+ .map(FunctionInput::try_from)
+ .collect();
+ let output_list: Result<std::vec::Vec<FunctionOutput>> = proto
+ .output_list
+ .into_iter()
+ .map(FunctionOutput::try_from)
+ .collect();
+
+ let ret = Self {
+ name: proto.name,
+ description: proto.description,
+ owner: proto.owner,
+ payload: proto.payload,
+ is_public: proto.is_public,
+ arg_list: proto.arg_list,
+ input_list: input_list?,
+ output_list: output_list?,
+ };
+
+ Ok(ret)
+ }
+}
+
+impl From<GetFunctionResponse> for proto::GetFunctionResponse {
+ fn from(response: GetFunctionResponse) -> Self {
+ let input_list: std::vec::Vec<proto::FunctionInput> = response
+ .input_list
+ .into_iter()
+ .map(proto::FunctionInput::from)
+ .collect();
+ let output_list: std::vec::Vec<proto::FunctionOutput> = response
+ .output_list
+ .into_iter()
+ .map(proto::FunctionOutput::from)
+ .collect();
+
+ Self {
+ name: response.name,
+ description: response.description,
+ owner: response.owner,
+ payload: response.payload,
+ is_public: response.is_public,
+ arg_list: response.arg_list,
+ input_list,
+ output_list,
+ }
+ }
+}
diff --git a/tests/functional_tests/enclave/src/teaclave_management_service.rs
b/tests/functional_tests/enclave/src/teaclave_management_service.rs
index b83e022..21e25d3 100644
--- a/tests/functional_tests/enclave/src/teaclave_management_service.rs
+++ b/tests/functional_tests/enclave/src/teaclave_management_service.rs
@@ -16,8 +16,10 @@ pub fn run_tests() -> bool {
run_tests!(
test_register_input_file,
test_register_output_file,
+ test_register_function,
test_get_output_file,
- test_get_fusion_data
+ test_get_fusion_data,
+ test_get_function,
)
}
@@ -132,3 +134,69 @@ fn test_get_fusion_data() {
let response = client.get_fusion_data(request);
assert!(response.is_err());
}
+
+fn test_register_function() {
+ let function_input = FunctionInput {
+ name: "input".to_string(),
+ description: "input_desc".to_string(),
+ };
+ let function_output = FunctionOutput {
+ name: "output".to_string(),
+ description: "output_desc".to_string(),
+ };
+ let request = RegisterFunctionRequest {
+ name: "mock_function".to_string(),
+ description: "mock function".to_string(),
+ payload: b"python script".to_vec(),
+ is_public: true,
+ arg_list: vec!["arg".to_string()],
+ input_list: vec![function_input],
+ output_list: vec![function_output],
+ };
+
+ let mut client = get_client("mock_user");
+ let response = client.register_function(request);
+
+ assert!(response.is_ok());
+}
+
+fn test_get_function() {
+ let function_input = FunctionInput {
+ name: "input".to_string(),
+ description: "input_desc".to_string(),
+ };
+ let function_output = FunctionOutput {
+ name: "output".to_string(),
+ description: "output_desc".to_string(),
+ };
+ let request = RegisterFunctionRequest {
+ name: "mock_function".to_string(),
+ description: "mock function".to_string(),
+ payload: b"python script".to_vec(),
+ is_public: false,
+ arg_list: vec!["arg".to_string()],
+ input_list: vec![function_input],
+ output_list: vec![function_output],
+ };
+
+ let mut client = get_client("mock_user");
+ let response = client.register_function(request);
+ let function_id = response.unwrap().function_id;
+
+ let request = GetFunctionRequest {
+ function_id: function_id.clone(),
+ };
+ let response = client.get_function(request);
+ assert!(response.is_ok());
+ info!("{:?}", response.unwrap());
+ let mut client = get_client("mock_unauthorized_user");
+ let request = GetFunctionRequest { function_id };
+ let response = client.get_function(request);
+ assert!(response.is_err());
+ let request = GetFunctionRequest {
+ function_id: "native-mock-native-func".to_string(),
+ };
+ let response = client.get_function(request);
+ assert!(response.is_ok());
+ info!("{:?}", response.unwrap());
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]