This is an automated email from the ASF dual-hosted git repository.
elek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hadoop-ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 3328d7d HDDS-2720. Ozone Failure injection Service (#956)
3328d7d is described below
commit 3328d7dc706b3a098a10def34aa367f4a7414b3e
Author: prashantpogde <[email protected]>
AuthorDate: Mon Jun 8 11:26:37 2020 -0700
HDDS-2720. Ozone Failure injection Service (#956)
---
tools/fault-injection-service/CMakeLists.txt | 114 +++
.../FileSystem/cpp_unit/TestFailureInjector.cc | 175 ++++
.../FileSystem/cpp_unit/TestFilePathFailures.cc | 138 ++++
.../FileSystem/failure_injector.cc | 201 +++++
.../FileSystem/failure_injector.h | 145 ++++
.../FileSystem/failure_injector_fs.cc | 912 +++++++++++++++++++++
.../FileSystem/failure_injector_fs.h | 176 ++++
tools/fault-injection-service/README.md | 56 ++
.../Service/cpp/failure_injector_svc_client.cc | 209 +++++
.../Service/cpp/failure_injector_svc_client.h | 51 ++
.../Service/cpp/failure_injector_svc_server.cc | 93 +++
.../Service/cpp/failure_injector_svc_server.h | 63 ++
.../Service/cpp/run_grpc_service.cc | 58 ++
.../Service/cpp/run_grpc_service.h | 36 +
.../Service/protos/failure_injection_service.proto | 68 ++
15 files changed, 2495 insertions(+)
diff --git a/tools/fault-injection-service/CMakeLists.txt
b/tools/fault-injection-service/CMakeLists.txt
new file mode 100644
index 0000000..ebb3cad
--- /dev/null
+++ b/tools/fault-injection-service/CMakeLists.txt
@@ -0,0 +1,114 @@
+#
+# 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
+# <p>
+# http://www.apache.org/licenses/LICENSE-2.0
+# <p>
+# 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.
+#
+# cmake build file for C++ failure_injection_service.
+# Assumes protobuf and gRPC have been installed using cmake.
+
+cmake_minimum_required(VERSION 2.8)
+
+project(FailureInjectionService C CXX)
+
+set(BASE_DIR ".")
+set(FS_DIR "${BASE_DIR}/FileSystem")
+set(SRV_DIR "${BASE_DIR}/Service/cpp")
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -Wall")
+
+# This assumes that gRPC and all its dependencies are already installed
+# on this system, so they can be located by find_package().
+
+# Find Protobuf installation
+# Looks for protobuf-config.cmake file installed by Protobuf's cmake
+# installation.
+set(protobuf_MODULE_COMPATIBLE TRUE)
+find_package(Protobuf CONFIG REQUIRED)
+message(STATUS "Using protobuf ${protobuf_VERSION}")
+
+set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
+set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
+
+# Find gRPC installation
+# Looks for gRPCConfig.cmake file installed by gRPC's cmake installation.
+find_package(gRPC CONFIG REQUIRED)
+message(STATUS "Using gRPC ${gRPC_VERSION}")
+
+set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure)
+set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
+
+# Proto file
+get_filename_component(hw_proto
+ "${BASE_DIR}/Service/protos/failure_injection_service.proto"
+ ABSOLUTE)
+get_filename_component(hw_proto_path "${hw_proto}" PATH)
+
+# Generated sources
+set(hw_proto_srcs
+ "${CMAKE_CURRENT_BINARY_DIR}/failure_injection_service.pb.cc")
+set(hw_proto_hdrs
+ "${CMAKE_CURRENT_BINARY_DIR}/failure_injection_service.pb.h")
+set(hw_grpc_srcs
+ "${CMAKE_CURRENT_BINARY_DIR}/failure_injection_service.grpc.pb.cc")
+set(hw_grpc_hdrs
+ "${CMAKE_CURRENT_BINARY_DIR}/failure_injection_service.grpc.pb.h")
+add_custom_command(
+ OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}"
+ "${hw_grpc_srcs}" "${hw_grpc_hdrs}"
+ COMMAND ${_PROTOBUF_PROTOC}
+ ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
+ --cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
+ -I "${hw_proto_path}"
+ --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
+ "${hw_proto}"
+ DEPENDS "${hw_proto}")
+
+# Include generated *.pb.h files
+include_directories("${CMAKE_CURRENT_BINARY_DIR}"
+ "${FS_DIR}"
+ "${SRV_DIR}")
+
+#add_compile_options("-fpermissive")
+
+# Build server
+add_executable(failure_injector_svc_server
+ ${FS_DIR}/failure_injector_fs.cc ${FS_DIR}/failure_injector.cc
+ ${SRV_DIR}/failure_injector_svc_server.cc ${SRV_DIR}/run_grpc_service.cc
+ ${hw_proto_srcs}
+ ${hw_grpc_srcs})
+target_link_libraries(failure_injector_svc_server
+ ${_GRPC_GRPCPP_UNSECURE}
+ fuse3
+ ${_PROTOBUF_LIBPROTOBUF})
+
+# Build client
+add_executable(failure_injector_svc_client
+ "${SRV_DIR}/failure_injector_svc_client.cc"
+ ${hw_proto_srcs}
+ ${hw_grpc_srcs})
+target_link_libraries(failure_injector_svc_client
+ ${_GRPC_GRPCPP_UNSECURE}
+ ${_PROTOBUF_LIBPROTOBUF})
+
+# Build unit tests
+set(CPP_UNIT_FUSE cpp_unit)
+foreach(_target
+ TestFilePathFailures
+ TestFailureInjector)
+ add_executable(${_target}
+ "${FS_DIR}/${CPP_UNIT_FUSE}/${_target}.cc"
+ ${FS_DIR}/failure_injector.cc)
+ target_link_libraries(${_target}
+ cppunit)
+endforeach()
diff --git
a/tools/fault-injection-service/FileSystem/cpp_unit/TestFailureInjector.cc
b/tools/fault-injection-service/FileSystem/cpp_unit/TestFailureInjector.cc
new file mode 100644
index 0000000..c501d8e
--- /dev/null
+++ b/tools/fault-injection-service/FileSystem/cpp_unit/TestFailureInjector.cc
@@ -0,0 +1,175 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#include <iostream>
+#include <string>
+#include <list>
+#include <cppunit/TestCase.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/ui/text/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TestRunner.h>
+#include <cppunit/BriefTestProgressListener.h>
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/XmlOutputter.h>
+#include <netinet/in.h>
+#include "failure_injector.h"
+
+using namespace CppUnit;
+using namespace std;
+using namespace NoiseInjector;
+
+//-----------------------------------------------------------------------------
+
+class TestFailureInjector : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestFailureInjector);
+ CPPUNIT_TEST(testFailureInjector);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp(void);
+ void tearDown(void);
+
+protected:
+ void testFailureInjector();
+ void testGetOpCode();
+
+private:
+
+ FailureInjector *mTestObj;
+};
+
+//-----------------------------------------------------------------------------
+
+void TestFailureInjector::testGetOpCode()
+{
+ CPPUNIT_ASSERT(mTestObj->getOpCode("NO_OP") == NO_OP);
+ CPPUNIT_ASSERT(mTestObj->getOpCode("GETATTR") == GETATTR);
+ CPPUNIT_ASSERT(mTestObj->getOpCode("READDIR") == READDIR);
+ CPPUNIT_ASSERT(mTestObj->getOpCode("LSEEK") == LSEEK);
+ CPPUNIT_ASSERT(mTestObj->getOpCode("NUM_OP_CODES") == NUM_OP_CODES);
+}
+
+//-----------------------------------------------------------------------------
+
+void TestFailureInjector::testFailureInjector()
+{
+ string path("/opt/test.xyz");
+ string path2("/opt/test2.xyz");
+
+ testGetOpCode();
+ mTestObj->InjectFailure(path, "RENAME",
+ InjectedAction(InjectedAction::ActionCode::DELAY,
+ 1, 0));
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path, "RENAME")->size() == 1);
+ CPPUNIT_ASSERT((*mTestObj->GetFailures(path, "RENAME"))[0].code ==
+ InjectedAction::ActionCode::DELAY);
+
+ // two actions for (path, RENAME)
+ mTestObj->InjectFailure(path, "RENAME",
+ InjectedAction(InjectedAction::ActionCode::FAIL,
+ 1, 0));
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path, "RENAME")->size() == 2);
+ CPPUNIT_ASSERT((*mTestObj->GetFailures(path, "RENAME"))[0].code ==
+ InjectedAction::ActionCode::DELAY);
+ CPPUNIT_ASSERT((*mTestObj->GetFailures(path, "RENAME"))[1].code ==
+ InjectedAction::ActionCode::FAIL);
+
+ // one actions for (path,READ)
+ mTestObj->InjectFailure(path, "READ",
+ InjectedAction(InjectedAction::ActionCode::DELAY,
+ 1, 0));
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path, "READ")->size() == 1);
+ CPPUNIT_ASSERT((*mTestObj->GetFailures(path, "READ"))[0].code ==
+ InjectedAction::ActionCode::DELAY);
+
+ // one actions for (path2,LOCK)
+ mTestObj->InjectFailure(path2, "LOCK",
+ InjectedAction(InjectedAction::ActionCode::DELAY,
+ 1, 0));
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path2, "LOCK")->size() == 1);
+ CPPUNIT_ASSERT((*mTestObj->GetFailures(path2, "LOCK"))[0].code ==
+ InjectedAction::ActionCode::DELAY);
+
+ mTestObj->dumpFailures();
+
+ mTestObj->ResetFailure(path, READ);
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path, "READ") == NULL);
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path, "RENAME")->size() == 2);
+
+ mTestObj->ResetFailure(path);
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path, "RENAME") == NULL);
+
+ mTestObj->ResetFailure();
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path, "RENAME") == NULL);
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path, "READ") == NULL);
+ CPPUNIT_ASSERT(mTestObj->GetFailures(path2, "LOCK") == NULL);
+
+ mTestObj->dumpFailures();
+}
+
+//-----------------------------------------------------------------------------
+
+void TestFailureInjector::setUp(void)
+{
+ mTestObj = new FailureInjector();
+}
+
+void TestFailureInjector::tearDown(void)
+{
+ delete mTestObj;
+}
+
+//-----------------------------------------------------------------------------
+
+CPPUNIT_TEST_SUITE_REGISTRATION( TestFailureInjector );
+
+int main(int argc, char* argv[])
+{
+ // informs test-listener about testresults
+ CPPUNIT_NS::TestResult testresult;
+
+ // register listener for collecting the test-results
+ CPPUNIT_NS::TestResultCollector collectedresults;
+ testresult.addListener (&collectedresults);
+
+ // register listener for per-test progress output
+ CPPUNIT_NS::BriefTestProgressListener progress;
+ testresult.addListener (&progress);
+
+ // insert test-suite at test-runner by registry
+ CPPUNIT_NS::TestRunner testrunner;
+ testrunner.addTest
(CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest ());
+ testrunner.run(testresult);
+
+ // output results in compiler-format
+ CPPUNIT_NS::CompilerOutputter compileroutputter(&collectedresults,
std::cerr);
+ compileroutputter.write ();
+
+ // Output XML for Jenkins CPPunit plugin
+ ofstream xmlFileOut("cppTestFailureInjectorResults.xml");
+ XmlOutputter xmlOut(&collectedresults, xmlFileOut);
+ xmlOut.write();
+
+ // return 0 if tests were successful
+ return collectedresults.wasSuccessful() ? 0 : 1;
+}
+
diff --git
a/tools/fault-injection-service/FileSystem/cpp_unit/TestFilePathFailures.cc
b/tools/fault-injection-service/FileSystem/cpp_unit/TestFilePathFailures.cc
new file mode 100644
index 0000000..9b681bc
--- /dev/null
+++ b/tools/fault-injection-service/FileSystem/cpp_unit/TestFilePathFailures.cc
@@ -0,0 +1,138 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#include <iostream>
+#include <string>
+#include <list>
+#include <cppunit/TestCase.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/ui/text/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TestRunner.h>
+#include <cppunit/BriefTestProgressListener.h>
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/XmlOutputter.h>
+#include <netinet/in.h>
+#include "failure_injector.h"
+
+using namespace CppUnit;
+using namespace std;
+using namespace NoiseInjector;
+
+//-----------------------------------------------------------------------------
+
+class TestFilePathFailures : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestFilePathFailures);
+ CPPUNIT_TEST(testFilePathFailures);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp(void);
+ void tearDown(void);
+
+protected:
+ void testFilePathFailures();
+
+private:
+
+ FilePathFailures *mTestObj;
+};
+
+//-----------------------------------------------------------------------------
+
+void TestFilePathFailures::testFilePathFailures()
+{
+ mTestObj->addFailure(READ,
+ InjectedAction(InjectedAction::ActionCode::DELAY,
+ 1, 0));
+ CPPUNIT_ASSERT(mTestObj->GetFailures(READ)->size() == 1);
+
+ mTestObj->addFailure(READ,
+ InjectedAction(InjectedAction::ActionCode::DELAY,
+ 1, 0));
+ // Redundant actions should not be added
+ CPPUNIT_ASSERT(mTestObj->GetFailures(READ)->size() == 1);
+ CPPUNIT_ASSERT(mTestObj->GetFailures(READ)->size() == 1);
+ CPPUNIT_ASSERT((*mTestObj->GetFailures(READ))[0].code ==
+ InjectedAction::ActionCode::DELAY);
+ mTestObj->addFailure(READ,
+ InjectedAction(InjectedAction::ActionCode::FAIL,
+ 1, 0));
+ mTestObj->addFailure(READ,
+ InjectedAction(InjectedAction::ActionCode::CORRUPT,
+ 1, 0));
+ CPPUNIT_ASSERT(mTestObj->GetFailures(READ)->size() == 3);
+ mTestObj->addFailure(FLOCK,
+ InjectedAction(InjectedAction::ActionCode::DELAY,
+ 1, 0));
+ CPPUNIT_ASSERT(mTestObj->GetFailures(FLOCK)->size() == 1);
+ CPPUNIT_ASSERT((*mTestObj->GetFailures(FLOCK))[0].code ==
+ InjectedAction::ActionCode::DELAY);
+ mTestObj->dumpFailures();
+}
+
+//-----------------------------------------------------------------------------
+
+void TestFilePathFailures::setUp(void)
+{
+ mTestObj = new FilePathFailures();
+}
+
+void TestFilePathFailures::tearDown(void)
+{
+ delete mTestObj;
+}
+
+//-----------------------------------------------------------------------------
+
+CPPUNIT_TEST_SUITE_REGISTRATION( TestFilePathFailures );
+
+int main(int argc, char* argv[])
+{
+ // informs test-listener about testresults
+ CPPUNIT_NS::TestResult testresult;
+
+ // register listener for collecting the test-results
+ CPPUNIT_NS::TestResultCollector collectedresults;
+ testresult.addListener (&collectedresults);
+
+ // register listener for per-test progress output
+ CPPUNIT_NS::BriefTestProgressListener progress;
+ testresult.addListener (&progress);
+
+ // insert test-suite at test-runner by registry
+ CPPUNIT_NS::TestRunner testrunner;
+ testrunner.addTest
(CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest ());
+ testrunner.run(testresult);
+
+ // output results in compiler-format
+ CPPUNIT_NS::CompilerOutputter compileroutputter(&collectedresults,
std::cerr);
+ compileroutputter.write ();
+
+ // Output XML for Jenkins CPPunit plugin
+ ofstream xmlFileOut("cppTestFilePathFailuresResults.xml");
+ XmlOutputter xmlOut(&collectedresults, xmlFileOut);
+ xmlOut.write();
+
+ // return 0 if tests were successful
+ return collectedresults.wasSuccessful() ? 0 : 1;
+}
+
diff --git a/tools/fault-injection-service/FileSystem/failure_injector.cc
b/tools/fault-injection-service/FileSystem/failure_injector.cc
new file mode 100644
index 0000000..2c6928a
--- /dev/null
+++ b/tools/fault-injection-service/FileSystem/failure_injector.cc
@@ -0,0 +1,201 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#include<string>
+#include<map>
+#include<vector>
+#include<iostream>
+#include"failure_injector.h"
+
+using namespace std;
+using namespace NoiseInjector;
+
+#define GEN_CODE_NAMES(x) #x
+
+string InjectedOpNames[] = {"NO_OP", InjectedOperations(GEN_CODE_NAMES)};
+
+vector<InjectedAction> *FilePathFailures::GetFailures(InjectedOpCode op)
+{
+ auto iter = mInjectedOperations.find(op);
+ if (iter == mInjectedOperations.end()) {
+ return NULL;
+ }
+ return (vector<InjectedAction> *)&iter->second;
+}
+
+void FilePathFailures::addFailure(
+ InjectedOpCode op,
+ InjectedAction action)
+{
+ auto iter = mInjectedOperations.find(op);
+ if (iter == mInjectedOperations.end()) {
+ mInjectedOperations[op].push_back(action);
+ } else {
+ vector<InjectedAction> &action_vector = iter->second;
+ for (auto &existing_action : action_vector) {
+ if (action.code == existing_action.code) {
+ return;
+ }
+ }
+ action_vector.push_back(action);
+ }
+}
+
+void FilePathFailures::resetFailure(InjectedOpCode op)
+{
+ auto itr = mInjectedOperations.find(op);
+ if (itr != mInjectedOperations.end()) {
+ mInjectedOperations[op].clear();
+ mInjectedOperations.erase(op);
+ }
+}
+
+void FilePathFailures::resetFailure()
+{
+ for (auto iter:mInjectedOperations) {
+ InjectedOpCode op = iter.first;
+ mInjectedOperations[op].clear();
+ mInjectedOperations.erase(op);
+ }
+}
+
+void FilePathFailures::dumpFailures()
+{
+ for (auto iter:mInjectedOperations) {
+ InjectedOpCode op = iter.first;
+ for (const auto action : mInjectedOperations[op]) {
+ cout << "\t" << InjectedOpNames[op] << ": " << action.code << "\n";
+ }
+ }
+}
+
+InjectedOpCode FailureInjector::getOpCode(std::string op_name)
+{
+ int i = 0;
+ for (auto name : InjectedOpNames) {
+ if (!name.compare(op_name)) {
+ return (InjectedOpCode)i;
+ }
+ ++i;
+ }
+ return NO_OP;
+}
+
+std::vector<InjectedAction>* FailureInjector::GetFailures(
+ std::string path,
+ std::string op_name)
+{
+ auto op =getOpCode(op_name);
+ if (op >= NUM_OP_CODES) {
+ return NULL;
+ }
+
+ auto iter = mAllInjectedFailures_.find(path);
+ if (iter != mAllInjectedFailures_.end()) {
+ FilePathFailures* failure = iter->second;
+ return failure->GetFailures(op);
+ }
+ return NULL;
+}
+
+void FailureInjector::InjectFailure(
+ std::string path,
+ std::string op_name,
+ InjectedAction action)
+{
+ InjectFailure(path, getOpCode(op_name), action);
+}
+
+void FailureInjector::InjectFailure(
+ std::string path,
+ InjectedOpCode op,
+ InjectedAction action)
+{
+ if (op >= NUM_OP_CODES) {
+ return;
+ }
+ auto iter = mAllInjectedFailures_.find(path);
+ if (iter == mAllInjectedFailures_.end()) {
+ FilePathFailures* failure = new FilePathFailures();
+ failure->addFailure(op, action);
+ mAllInjectedFailures_[path] = failure;
+ } else {
+ FilePathFailures* failure = iter->second;
+ failure->addFailure(op, action);
+ }
+
+}
+
+void FailureInjector::ResetFailure(
+ std::string path,
+ std::string op_name)
+{
+ auto op =getOpCode(op_name);
+ if (op >= NUM_OP_CODES) {
+ return NULL;
+ }
+ ResetFailure(path, op);
+}
+
+void FailureInjector::ResetFailure(
+ std::string path,
+ InjectedOpCode op)
+{
+ auto iter = mAllInjectedFailures_.find(path);
+ if (iter != mAllInjectedFailures_.end()) {
+ FilePathFailures* failure = iter->second;
+ failure->resetFailure(op);
+ }
+}
+
+void FailureInjector::ResetFailure(
+ std::string path)
+{
+ auto iter = mAllInjectedFailures_.find(path);
+ if (iter != mAllInjectedFailures_.end()) {
+ FilePathFailures* failure = iter->second;
+ failure->resetFailure();
+ mAllInjectedFailures_.erase(path);
+ }
+}
+
+void FailureInjector::ResetFailure()
+{
+ for (auto iter : mAllInjectedFailures_) {
+ FilePathFailures* failure = iter.second;
+ failure->resetFailure();
+ }
+ mAllInjectedFailures_.clear();
+}
+
+void FailureInjector::dumpFailures(std::string path)
+{
+ auto iter = mAllInjectedFailures_.find(path);
+ if (iter != mAllInjectedFailures_.end()) {
+ FilePathFailures* failure = iter->second;
+ failure->dumpFailures();
+ }
+}
+
+void FailureInjector::dumpFailures()
+{
+ for (auto iter : mAllInjectedFailures_) {
+ FilePathFailures* failure = iter.second;
+ cout << "Path: " << iter.first << "\n";
+ failure->dumpFailures();
+ }
+}
diff --git a/tools/fault-injection-service/FileSystem/failure_injector.h
b/tools/fault-injection-service/FileSystem/failure_injector.h
new file mode 100644
index 0000000..8cce0df
--- /dev/null
+++ b/tools/fault-injection-service/FileSystem/failure_injector.h
@@ -0,0 +1,145 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#ifndef __FAILURE_INJECTOR_H__
+#define __FAILURE_INJECTOR_H__
+
+#include<string>
+#include<map>
+#include<vector>
+
+#define CORRUPT_DATA_ERROR_CODE (99999)
+#define MICROSECONDS_IN_A_SECOND (1000 * 1000)
+
+#define InjectedOperations(GEN_CODE) \
+ GEN_CODE(GETATTR), \
+ GEN_CODE(READLINK), \
+ GEN_CODE(MKNOD), \
+ GEN_CODE(MKDIR), \
+ GEN_CODE(UNLINK), \
+ GEN_CODE(RMDIR), \
+ GEN_CODE(SYMLINK), \
+ GEN_CODE(RENAME), \
+ GEN_CODE(LINK), \
+ GEN_CODE(CHMOD), \
+ GEN_CODE(CHOWN), \
+ GEN_CODE(TRUNCATE), \
+ GEN_CODE(OPEN), \
+ GEN_CODE(READ), \
+ GEN_CODE(WRITE), \
+ GEN_CODE(STATFS), \
+ GEN_CODE(FLUSH), \
+ GEN_CODE(RELEASE), \
+ GEN_CODE(FSYNC), \
+ GEN_CODE(SETXATTR), \
+ GEN_CODE(GETXATTR), \
+ GEN_CODE(LISTXATTR), \
+ GEN_CODE(REMOVEXATTR), \
+ GEN_CODE(OPENDIR), \
+ GEN_CODE(READDIR), \
+ GEN_CODE(RELEASEDIR), \
+ GEN_CODE(FSYNCDIR), \
+ GEN_CODE(INIT), \
+ GEN_CODE(DESTROY), \
+ GEN_CODE(ACCESS), \
+ GEN_CODE(CREATE), \
+ GEN_CODE(LOCK), \
+ GEN_CODE(UTIMENS), \
+ GEN_CODE(BMAP), \
+ GEN_CODE(IOCTL), \
+ GEN_CODE(POLL), \
+ GEN_CODE(WRITE_BUF), \
+ GEN_CODE(READ_BUF), \
+ GEN_CODE(FLOCK), \
+ GEN_CODE(FALLOCATE), \
+ GEN_CODE(COPY_FILE_RANGE), \
+ GEN_CODE(LSEEK), \
+ GEN_CODE(NUM_OP_CODES)
+
+#define GEN_CODE_ENUM(x) x
+
+namespace NoiseInjector {
+
+enum InjectedOpCode {NO_OP = 0, InjectedOperations(GEN_CODE_ENUM)};
+
+struct InjectedAction {
+ enum ActionCode {DELAY = 0, FAIL, CORRUPT} code;
+ int delay; /* In seconds */
+ int error_code;
+
+ InjectedAction(int c, int d, int e) : delay(d), error_code(e) {
+ switch (c) {
+ case DELAY:
+ code = DELAY;
+ break;
+ case FAIL:
+ code = FAIL;
+ break;
+ case CORRUPT:
+ code = CORRUPT;
+ break;
+ }
+ };
+};
+
+class FilePathFailures {
+public:
+ std::vector<InjectedAction>* GetFailures(InjectedOpCode op);
+ void addFailure(InjectedOpCode op, InjectedAction action);
+ void resetFailure(InjectedOpCode op);
+ void resetFailure();
+ void dumpFailures();
+
+private:
+ /*
+ * Same file path could have multiple failures injected for
+ * different operations. For each {path, operation}, it
+ * is possible to have more than on action. For example,
+ * path {/opt/ABC/, read} injected failures could be
+ * 1. Delay the operation for 50 miliseconds, followed by
+ * 2. Fail the operation with EIO
+ * simulating a malfunction disk.
+ */
+
+ std::map<InjectedOpCode, std::vector<InjectedAction> > mInjectedOperations;
+};
+
+class FailureInjector {
+public:
+ std::vector<InjectedAction>* GetFailures(std::string path,
+ std::string op_name);
+ void InjectFailure(std::string path, std::string op_name,
+ InjectedAction action);
+ void InjectFailure(std::string path, InjectedOpCode op,
+ InjectedAction action);
+ void ResetFailure(std::string path, std::string op_name);
+ void ResetFailure(std::string path, InjectedOpCode op);
+ void ResetFailure(std::string path);
+ void ResetFailure();
+ void dumpFailures(std::string path);
+ void dumpFailures();
+ InjectedOpCode getOpCode(std::string op_name);
+
+private:
+ std::map<std::string, FilePathFailures *> mAllInjectedFailures_;
+
+friend class TestFailureInjector;
+};
+
+} /* namespace NoiseInjector */
+
+#endif /* __FAILURE_INJECTOR_H */
diff --git a/tools/fault-injection-service/FileSystem/failure_injector_fs.cc
b/tools/fault-injection-service/FileSystem/failure_injector_fs.cc
new file mode 100644
index 0000000..ad03e74
--- /dev/null
+++ b/tools/fault-injection-service/FileSystem/failure_injector_fs.cc
@@ -0,0 +1,912 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+
+#define FUSE_USE_VERSION 31
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef linux
+/* For pread()/pwrite()/utimensat() */
+#define _XOPEN_SOURCE 700
+#endif
+
+#include <libgen.h>
+#include <stdlib.h>
+
+#include <fuse3/fuse.h>
+#include <stdio.h>
+#include <ctime>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#ifdef __FreeBSD__
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+#include <sys/time.h>
+
+
+#ifdef HAVE_SETXATTR
+#include <sys/xattr.h>
+#endif
+#include "failure_injector_fs.h"
+#include "failure_injector.h"
+#include "run_grpc_service.h"
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <strings.h>
+#include <thread>
+#include <cstdio>
+
+using NoiseInjector::FailureInjector;
+using NoiseInjector::RunGrpcService;
+
+using namespace std;
+using namespace NoiseInjector::FileSystem;
+
+#define LOGFILE "/var/log/noise_injector_log.txt"
+
+struct fuse_operations FailureInjectorFs::mFuseOperationsVec;
+FailureInjector *FailureInjectorFs::mFailureInjector = NULL;
+RunGrpcService *FailureInjectorFs::mGrpcSever = NULL;
+
+FailureInjectorFs::FailureInjectorFs(FailureInjector *injector)
+{
+ mFailureInjector = injector;
+ mGrpcSever = new RunGrpcService(mFailureInjector);
+}
+
+int FailureInjectorFs::mknod_wrapper(
+ int dirfd,
+ const char *path,
+ const char *link,
+ int mode,
+ dev_t rdev)
+{
+ int res;
+
+ if (S_ISREG(mode)) {
+ res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode);
+ if (res >= 0)
+ res = close(res);
+ } else if (S_ISDIR(mode)) {
+ res = mkdirat(dirfd, path, mode);
+ } else if (S_ISLNK(mode) && link != NULL) {
+ res = symlinkat(link, dirfd, path);
+ } else if (S_ISFIFO(mode)) {
+ res = mkfifoat(dirfd, path, mode);
+ } else {
+ res = mknodat(dirfd, path, mode, rdev);
+ }
+
+ return res;
+}
+
+void *FailureInjectorFs::fifs_init(
+ struct fuse_conn_info *conn,
+ struct fuse_config *cfg)
+{
+ extern void RunServer();
+ (void) conn;
+ cfg->use_ino = 1;
+
+ std::freopen(LOGFILE, "w", stdout);
+
+ /*
+ * Pick up changes from lower filesystem right away. This is
+ * also necessary for better hardlink support. When the kernel
+ * calls the unlink() handler, it does not know the inode of
+ * the to-be-removed entry and can therefore not invalidate
+ * the cache of the associated inode - resulting in an
+ * incorrect st_nlink value being reported for any remaining
+ * hardlinks to this inode.
+ */
+ cfg->entry_timeout = 0;
+ cfg->attr_timeout = 0;
+ cfg->negative_timeout = 0;
+
+ /* Create a separete GRPC server thread to accept failure injection. */
+ std::thread th(&RunGrpcService::RunServer, mGrpcSever);
+ th.detach();
+
+ return NULL;
+}
+
+int FailureInjectorFs::fifs_getattr(
+ const char *path,
+ struct stat *stbuf,
+ struct fuse_file_info *fi)
+{
+ (void) fi;
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"GETATTR", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = lstat(path, stbuf);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_access(
+ const char *path,
+ int mask)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"ACCESS", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = access(path, mask);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_readlink(
+ const char *path,
+ char *buf,
+ size_t size)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"READLINK", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = readlink(path, buf, size - 1);
+ if (res == -1)
+ return -errno;
+
+ buf[res] = '\0';
+ return 0;
+}
+
+int FailureInjectorFs::fifs_readdir(
+ const char *path,
+ void *buf,
+ fuse_fill_dir_t filler,
+ off_t offset,
+ struct fuse_file_info *fi,
+ enum fuse_readdir_flags flags)
+{
+ DIR *dp;
+ struct dirent *de;
+ int injected_error = 0;
+
+ (void) offset;
+ (void) fi;
+ (void) flags;
+
+ if (CheckForInjectedError(path,"READDIR", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ dp = opendir(path);
+ if (dp == NULL)
+ return -errno;
+
+ while ((de = readdir(dp)) != NULL) {
+ struct stat st;
+ memset(&st, 0, sizeof(st));
+ st.st_ino = de->d_ino;
+ st.st_mode = de->d_type << 12;
+ if (filler(buf, de->d_name, &st, 0, (fuse_fill_dir_flags)0))
+ break;
+ }
+
+ closedir(dp);
+ return 0;
+}
+
+int FailureInjectorFs::fifs_mknod(
+ const char *path,
+ mode_t mode,
+ dev_t rdev)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"MKNOD", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = mknod_wrapper(AT_FDCWD, path, NULL, mode, rdev);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_mkdir(
+ const char *path,
+ mode_t mode)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"MKDIR", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = mkdir(path, mode);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_unlink(const char *path)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"UNLINK", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = unlink(path);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_rmdir(const char *path)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"RMDIR", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = rmdir(path);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_symlink(
+ const char *from,
+ const char *to)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(from, "SYMLINK", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = symlink(from, to);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_rename(
+ const char *from,
+ const char *to,
+ unsigned int flags)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(from, "RENAME", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ if (flags)
+ return -EINVAL;
+
+ res = rename(from, to);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_link(
+ const char *from,
+ const char *to)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(from,"LINK", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = link(from, to);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_chmod(
+ const char *path,
+ mode_t mode,
+ struct fuse_file_info *fi)
+{
+ (void) fi;
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"CHMOD", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = chmod(path, mode);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_chown(
+ const char *path,
+ uid_t uid,
+ gid_t gid,
+ struct fuse_file_info *fi)
+{
+ (void) fi;
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"CHOWN", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = lchown(path, uid, gid);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_truncate(
+ const char *path,
+ off_t size,
+ struct fuse_file_info *fi)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"TRUNCATE", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ if (fi != NULL)
+ res = ftruncate(fi->fh, size);
+ else
+ res = truncate(path, size);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+#ifdef HAVE_UTIMENSAT
+int FailureInjectorFs::fifs_utimens(
+ const char *path,
+ const struct timespec ts[2],
+ struct fuse_file_info *fi)
+{
+ (void) fi;
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"UTIMENS", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+
+ /* don't use utime/utimes since they follow symlinks */
+ res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+#endif
+
+int FailureInjectorFs::fifs_create(
+ const char *path,
+ mode_t mode,
+ struct fuse_file_info *fi)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"CREATE", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = open(path, fi->flags, mode);
+ if (res == -1)
+ return -errno;
+
+ fi->fh = res;
+ return 0;
+}
+
+int FailureInjectorFs::fifs_open(
+ const char *path,
+ struct fuse_file_info *fi)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"OPEN", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = open(path, fi->flags);
+ if (res == -1)
+ return -errno;
+
+ fi->fh = res;
+ return 0;
+}
+
+bool FailureInjectorFs::CheckForInjectedError(
+ string path,
+ string op,
+ int *injected_error)
+{
+ char *mpath = strdup(path.c_str());
+ if (mFailureInjector == NULL) {
+ return false;
+ }
+
+ auto failures = mFailureInjector->GetFailures(path, op);
+ while (failures == NULL) {
+ // Check if failures are injected in any of the parent directories.
+ char *dir = dirname(mpath);
+ failures = mFailureInjector->GetFailures(string(dir), op);
+ if ((failures == NULL) && (!strcmp(dir, ".") || !strcmp(dir, "/"))) {
+ free(mpath);
+ return false;
+ }
+ mpath = dir;
+ }
+ free(mpath);
+
+ *injected_error = 0;
+ useconds_t delay = 1;
+ for (auto f : *failures) {
+ switch(f.code) {
+ case InjectedAction::DELAY:
+ delay = f.delay * MICROSECONDS_IN_A_SECOND;
+ break;
+ case InjectedAction::FAIL:
+ if (*injected_error != CORRUPT_DATA_ERROR_CODE) {
+ *injected_error = f.error_code;
+ }
+ break;
+ case InjectedAction::CORRUPT:
+ *injected_error = CORRUPT_DATA_ERROR_CODE;
+ break;
+ default:
+ // Ignore for now.
+ break;
+ }
+ }
+ // First create the delay.
+ usleep(delay);
+
+ if (*injected_error) {
+ return true;
+ }
+ return false;
+}
+
+void FailureInjectorFs::FillCorruptData(
+ char *buf,
+ size_t size)
+{
+ // For now just fill with some pattern based on input.
+ // TBD : Fill with random data pattern.
+ for (size_t i = 0; i < size; ++ i) {
+ buf[i] = buf[i] + 2;
+ }
+}
+
+int FailureInjectorFs::fifs_read(
+ const char *path,
+ char *buf,
+ size_t size,
+ off_t offset,
+ struct fuse_file_info *fi)
+{
+ int fd;
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path, "READ", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ if (injected_error != CORRUPT_DATA_ERROR_CODE) {
+ return -injected_error;
+ }
+ }
+
+ if(fi == NULL)
+ fd = open(path, O_RDONLY);
+ else
+ fd = fi->fh;
+
+ if (fd == -1)
+ return -errno;
+
+ res = pread(fd, buf, size, offset);
+ if (res == -1)
+ res = -errno;
+
+ if(fi == NULL)
+ close(fd);
+ if ((res != -1) && (injected_error == CORRUPT_DATA_ERROR_CODE)) {
+ FillCorruptData(buf, size);
+ return res;
+ }
+ return res;
+}
+
+int FailureInjectorFs::fifs_write(
+ const char *path,
+ const char *buf,
+ size_t size,
+ off_t offset,
+ struct fuse_file_info *fi)
+{
+ int fd;
+ int res;
+ int injected_error = 0;
+ (void) fi;
+
+ if (CheckForInjectedError(path, "WRITE", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ if (injected_error != CORRUPT_DATA_ERROR_CODE) {
+ return -injected_error;
+ } else {
+ FillCorruptData(const_cast<char *>(buf), size);
+ }
+ }
+
+ if(fi == NULL)
+ fd = open(path, O_WRONLY);
+ else
+ fd = fi->fh;
+
+ if (fd == -1)
+ return -errno;
+
+ res = pwrite(fd, buf, size, offset);
+ if (res == -1)
+ res = -errno;
+
+ if(fi == NULL)
+ close(fd);
+ return res;
+}
+
+int FailureInjectorFs::fifs_statfs(
+ const char *path,
+ struct statvfs *stbuf)
+{
+ int res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path, "STATFS", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ res = statvfs(path, stbuf);
+ if (res == -1)
+ return -errno;
+
+ return 0;
+}
+
+int FailureInjectorFs::fifs_release(
+ const char *path,
+ struct fuse_file_info *fi)
+{
+ (void) path;
+ close(fi->fh);
+ return 0;
+}
+
+int FailureInjectorFs::fifs_fsync(
+ const char *path,
+ int isdatasync,
+ struct fuse_file_info *fi)
+{
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"FSYNC", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+
+ (void) path;
+ (void) isdatasync;
+ (void) fi;
+ return 0;
+}
+
+#ifdef HAVE_POSIX_FALLOCATE
+int FailureInjectorFs::fifs_fallocate(
+ const char *path,
+ int mode,
+ off_t offset,
+ off_t length,
+ struct fuse_file_info *fi)
+{
+ int fd;
+ int res;
+ int injected_error = 0;
+
+ (void) fi;
+
+ if (CheckForInjectedError(path,"FALLOCATE", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ if (mode)
+ return -EOPNOTSUPP;
+
+ if(fi == NULL)
+ fd = open(path, O_WRONLY);
+ else
+ fd = fi->fh;
+
+ if (fd == -1)
+ return -errno;
+
+ res = -posix_fallocate(fd, offset, length);
+
+ if(fi == NULL)
+ close(fd);
+ return res;
+}
+#endif
+
+#ifdef HAVE_SETXATTR
+/* xattr operations are optional and can safely be left unimplemented */
+int FailureInjectorFs::fifs_setxattr(
+ const char *path,
+ const char *name,
+ const char *value,
+ size_t size,
+ int flags)
+{
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"SETXATTR", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ int res = lsetxattr(path, name, value, size, flags);
+ if (res == -1)
+ return -errno;
+ return 0;
+}
+
+int FailureInjectorFs::fifs_getxattr(
+ const char *path,
+ const char *name,
+ char *value,
+ size_t size)
+{
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"GETXATTR", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ int res = lgetxattr(path, name, value, size);
+ if (res == -1)
+ return -errno;
+ return res;
+}
+
+int FailureInjectorFs::fifs_listxattr(
+ const char *path,
+ char *list,
+ size_t size)
+{
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"LISTXATTR", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ int res = llistxattr(path, list, size);
+ if (res == -1)
+ return -errno;
+ return res;
+}
+
+int FailureInjectorFs::fifs_removexattr(
+ const char *path,
+ const char *name)
+{
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"REMOVEXATTR", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ int res = lremovexattr(path, name);
+ if (res == -1)
+ return -errno;
+ return 0;
+}
+#endif /* HAVE_SETXATTR */
+
+off_t FailureInjectorFs::fifs_lseek(
+ const char *path,
+ off_t off,
+ int whence,
+ struct fuse_file_info *fi)
+{
+ int fd;
+ off_t res;
+ int injected_error = 0;
+
+ if (CheckForInjectedError(path,"LSEEK", &injected_error)) {
+ cout << "Returning Injected error " << injected_error << "\n";
+ return -injected_error;
+ }
+
+ if (fi == NULL)
+ fd = open(path, O_RDONLY);
+ else
+ fd = fi->fh;
+
+ if (fd == -1)
+ return -errno;
+
+ res = lseek(fd, off, whence);
+ if (res == -1)
+ res = -errno;
+
+ if (fi == NULL)
+ close(fd);
+ return res;
+}
+
+void FailureInjectorFs::load_operations() {
+ mFuseOperationsVec.getattr = FailureInjectorFs::fifs_getattr;
+ mFuseOperationsVec.readlink = FailureInjectorFs::fifs_readlink;
+ mFuseOperationsVec.mknod = FailureInjectorFs::fifs_mknod;
+ mFuseOperationsVec.mkdir = FailureInjectorFs::fifs_mkdir;
+ mFuseOperationsVec.unlink = FailureInjectorFs::fifs_unlink;
+ mFuseOperationsVec.rmdir = FailureInjectorFs::fifs_rmdir;
+ mFuseOperationsVec.symlink = FailureInjectorFs::fifs_symlink;
+ mFuseOperationsVec.rename = FailureInjectorFs::fifs_rename;
+ mFuseOperationsVec.link = FailureInjectorFs::fifs_link;
+ mFuseOperationsVec.chmod = FailureInjectorFs::fifs_chmod;
+ mFuseOperationsVec.chown = FailureInjectorFs::fifs_chown;
+ mFuseOperationsVec.truncate = FailureInjectorFs::fifs_truncate;
+ mFuseOperationsVec.open = FailureInjectorFs::fifs_open;
+ mFuseOperationsVec.read = FailureInjectorFs::fifs_read;
+ mFuseOperationsVec.write = FailureInjectorFs::fifs_write;
+ mFuseOperationsVec.statfs = FailureInjectorFs::fifs_statfs;
+ mFuseOperationsVec.flush = NULL;
+ mFuseOperationsVec.release = FailureInjectorFs::fifs_release;
+ mFuseOperationsVec.fsync = FailureInjectorFs::fifs_fsync;
+
+#ifdef HAVE_SETXATTR
+ mFuseOperationsVec.setxattr = FailureInjectorFs::fifs_setxattr;
+ mFuseOperationsVec.getxattr = FailureInjectorFs::fifs_getxattr;
+ mFuseOperationsVec.listxattr = FailureInjectorFs::fifs_listxattr;
+ mFuseOperationsVec.removexattr = FailureInjectorFs::fifs_removexattr;
+#else
+ mFuseOperationsVec.setxattr = NULL;
+ mFuseOperationsVec.getxattr = NULL;
+ mFuseOperationsVec.listxattr = NULL;
+ mFuseOperationsVec.removexattr = NULL;
+#endif
+
+ mFuseOperationsVec.opendir = NULL;
+ mFuseOperationsVec.readdir = FailureInjectorFs::fifs_readdir;
+ mFuseOperationsVec.releasedir = NULL;
+ mFuseOperationsVec.fsyncdir = NULL;
+ mFuseOperationsVec.init = FailureInjectorFs::fifs_init;
+ mFuseOperationsVec.destroy = NULL;
+ mFuseOperationsVec.access = FailureInjectorFs::fifs_access;
+ mFuseOperationsVec.create = FailureInjectorFs::fifs_create;
+ mFuseOperationsVec.lock = NULL;
+
+#ifdef HAVE_UTIMENSAT
+ mFuseOperationsVec.utimens = FailureInjectorFs::fifs_utimens;
+#else
+ mFuseOperationsVec.utimens = NULL;
+#endif
+
+ mFuseOperationsVec.bmap = NULL;
+ mFuseOperationsVec.ioctl = NULL;
+ mFuseOperationsVec.poll = NULL;
+ mFuseOperationsVec.write_buf = NULL;
+ mFuseOperationsVec.read_buf = NULL;
+ mFuseOperationsVec.flock = NULL;
+
+#ifdef HAVE_POSIX_FALLOCATE
+ mFuseOperationsVec.fallocate = FailureInjectorFs::fifs_fallocate;
+#else
+ mFuseOperationsVec.fallocate = NULL;
+#endif
+
+ mFuseOperationsVec.copy_file_range = NULL;
+}
+
+const struct fuse_operations *FailureInjectorFs::getOperations() {
+ return &mFuseOperationsVec;
+}
+
+int main(int argc, char *argv[])
+{
+ FailureInjector *injector = new FailureInjector();
+ FailureInjectorFs noise_fs(injector);
+
+ noise_fs.load_operations();
+ umask(0);
+ fuse_main(argc, argv, noise_fs.getOperations(), NULL);
+}
diff --git a/tools/fault-injection-service/FileSystem/failure_injector_fs.h
b/tools/fault-injection-service/FileSystem/failure_injector_fs.h
new file mode 100644
index 0000000..20237c9
--- /dev/null
+++ b/tools/fault-injection-service/FileSystem/failure_injector_fs.h
@@ -0,0 +1,176 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#ifndef __FAILURE_INJECTOR_FS_H
+#define __FAILURE_INJECTOR_FS_H
+
+#define FUSE_USE_VERSION 31
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef linux
+/* For pread()/pwrite()/utimensat() */
+#define _XOPEN_SOURCE 700
+#endif
+
+#include <fuse3/fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#ifdef __FreeBSD__
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+#include <sys/time.h>
+
+
+#ifdef HAVE_SETXATTR
+#include <sys/xattr.h>
+#endif
+
+#include<string>
+#include"failure_injector.h"
+#include "run_grpc_service.h"
+
+namespace NoiseInjector {
+
+namespace FileSystem {
+
+class FailureInjectorFs {
+private:
+ /* Helper function for mknod operation */
+ static int mknod_wrapper(int dirfd, const char *path,
+ const char *link, int mode, dev_t rdev);
+public:
+ FailureInjectorFs(FailureInjector *);
+ /*
+ * Following operations correspond with their corresponding
+ * Fuse operations vector.
+ */
+
+ static void *fifs_init(struct fuse_conn_info *conn,
+ struct fuse_config *cfg);
+
+ static int fifs_getattr(const char *path, struct stat *stbuf,
+ struct fuse_file_info *fi);
+
+ static int fifs_access(const char *path, int mask);
+
+ static int fifs_readlink(const char *path, char *buf, size_t size);
+
+ static int fifs_readdir(const char *path, void *buf, fuse_fill_dir_t
filler,
+ off_t offset, struct fuse_file_info *fi,
+ enum fuse_readdir_flags flags);
+
+ static int fifs_mknod(const char *path, mode_t mode, dev_t rdev);
+
+ static int fifs_mkdir(const char *path, mode_t mode);
+
+ static int fifs_unlink(const char *path);
+
+ static int fifs_rmdir(const char *path);
+
+ static int fifs_symlink(const char *from, const char *to);
+
+ static int fifs_rename(const char *from, const char *to,
+ unsigned int flags);
+
+ static int fifs_link(const char *from, const char *to);
+
+ static int fifs_chmod(const char *path, mode_t mode,
+ struct fuse_file_info *fi);
+
+ static int fifs_chown(const char *path, uid_t uid, gid_t gid,
+ struct fuse_file_info *fi);
+
+ static int fifs_truncate(const char *path, off_t size,
+ struct fuse_file_info *fi);
+
+#ifdef HAVE_UTIMENSAT
+ static int fifs_utimens(const char *path, const struct timespec ts[2],
+ struct fuse_file_info *fi);
+#endif
+
+ static int fifs_create(const char *path, mode_t mode,
+ struct fuse_file_info *fi);
+
+ static int fifs_open(const char *path, struct fuse_file_info *fi);
+
+ static int fifs_read(const char *path, char *buf, size_t size,
+ off_t offset, struct fuse_file_info *fi);
+
+ static int fifs_write(const char *path, const char *buf, size_t size,
+ off_t offset, struct fuse_file_info *fi);
+
+ static int fifs_statfs(const char *path, struct statvfs *stbuf);
+
+ static int fifs_release(const char *path, struct fuse_file_info *fi);
+
+ static int fifs_fsync(const char *path, int isdatasync,
+ struct fuse_file_info *fi);
+
+#ifdef HAVE_POSIX_FALLOCATE
+ static int fifs_fallocate(const char *path, int mode, off_t offset,
+ off_t length, struct fuse_file_info *fi);
+#endif
+
+#ifdef HAVE_SETXATTR
+ static int fifs_setxattr(const char *path, const char *name,
+ const char *value, size_t size, int flags);
+
+ static int fifs_getxattr(const char *path, const char *name, char *value,
+ size_t size);
+
+ static int fifs_listxattr(const char *path, char *list, size_t size);
+
+ static int fifs_removexattr(const char *path, const char *name);
+#endif /* HAVE_SETXATTR */
+
+ static off_t fifs_lseek(const char *path, off_t off, int whence,
+ struct fuse_file_info *fi);
+
+ /* Helper functions to setup/access Fuse operations vector */
+
+ static bool CheckForInjectedError(std::string path, std::string op,
+ int *injected_error);
+
+ static void FillCorruptData(char *buf, size_t size);
+
+ void load_operations();
+
+ const struct fuse_operations *getOperations();
+
+ FailureInjector& GetFailureInjector();
+
+private:
+ /* Fuse operations vector */
+ static struct fuse_operations mFuseOperationsVec;
+
+ static FailureInjector *mFailureInjector;
+
+ static RunGrpcService *mGrpcSever;
+};
+}
+}
+
+#endif /* __FAILURE_INJECTOR_FS_H */
diff --git a/tools/fault-injection-service/README.md
b/tools/fault-injection-service/README.md
new file mode 100644
index 0000000..d988107
--- /dev/null
+++ b/tools/fault-injection-service/README.md
@@ -0,0 +1,56 @@
+Fault Injection Service
+========================
+
+About
+------
+Fault Injection Service is designed to validate Ozone under heavy stress and
+failed or failing system components. This service runs independently of Ozone
+and offers a client tool to inject errors.
+
+Development Status
+------------------
+Currently this service can inject errors on the IO path. The next step would be
+to add ability to inject similar errors on the network path as well.
+
+Supported Platforms
+-------------------
+Linux
+
+Dependencies
+-------------
+- libfuse3
+ yum install fuse3.x86_64 fuse3-devel.x86_64 fuse3-libs.x86_64
+- protobuf 2.5 or higher
+- grpc
+ built/installed from sources
+- cmake 3.14
+ built/installed from sources
+- cppunit & cppunit-devel
+
+Installation
+------------
+mkdir Build
+cd Build
+do 'cmake ..'
+do 'make'
+
+
+This will build following binaries:
+- failure_injector_svc_server
+ usage : failure_injector_svc_server /mnt
+ It will create a Fuse mountpoint on /mnt and also start a grpc server
+ to listen for failure injections on this mountpoint.
+
+- failure_injector_svc_client
+ This is a grpc client that can be used to inject failures on the /mnt
+ mountpoint above. Currently it supports,
+ - Injecting delays on various filesystem interfaces.
+ - Injecting a specific failure on a specific path for a specific operation.
+ - Simulate temporary or on-disk data corruption on IO path.
+ - Reseting specific or all the failures injected so far.
+
+- some unit test binaries
+
+Security implications
+---------------------
+TBD
diff --git
a/tools/fault-injection-service/Service/cpp/failure_injector_svc_client.cc
b/tools/fault-injection-service/Service/cpp/failure_injector_svc_client.cc
new file mode 100644
index 0000000..bdedbb3
--- /dev/null
+++ b/tools/fault-injection-service/Service/cpp/failure_injector_svc_client.cc
@@ -0,0 +1,209 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <unistd.h>
+
+#include <grpcpp/grpcpp.h>
+
+#include "failure_injection_service.grpc.pb.h"
+#include "failure_injector_svc_client.h"
+#include "failure_injector.h"
+
+using grpc::Channel;
+using grpc::ClientContext;
+using grpc::Status;
+
+using namespace NoiseInjector;
+using namespace std;
+
+FailureInjectorSvcClient::FailureInjectorSvcClient(
+ shared_ptr<Channel> channel)
+ : stub_(FailureInjectorSvc::NewStub(channel)) {}
+
+string FailureInjectorSvcClient::GetStatus(const string& user)
+{
+ GetStatusRequest request;
+ request.set_name(user);
+
+ GetStatusReply reply;
+
+ ClientContext context;
+
+ Status status = stub_->GetStatus(&context, request, &reply);
+
+ if (status.ok()) {
+ return reply.message();
+ } else {
+ cout << status.error_code() << ": " << status.error_message()
+ << endl;
+ return "RPC failed";
+ }
+}
+
+void FailureInjectorSvcClient::InjectFailure(
+ string path,
+ string op,
+ int action,
+ int param)
+
+{
+ InjectFailureRequest request;
+
+ switch (action) {
+ case 0:
+ request.set_action_code(InjectFailureRequest::DELAY);
+ break;
+ case 1:
+ request.set_action_code(InjectFailureRequest::FAIL);
+ break;
+ case 2:
+ request.set_action_code(InjectFailureRequest::CORRUPT);
+ break;
+ }
+
+ request.set_path(path);
+ request.set_op_name(op);
+ request.set_action_param(param);
+
+
+ InjectFailureReply reply;
+
+ ClientContext context;
+
+ Status status = stub_->InjectFailure(&context, request, &reply);
+
+ if (status.ok()) {
+ cout << "RPC Success\n";
+ } else {
+ cout << status.error_code() << ": " << status.error_message()
+ << endl;
+ cout << "RPC failed\n";
+ }
+}
+
+void FailureInjectorSvcClient::ResetFailure(
+ string path,
+ string op)
+{
+ ResetFailureRequest request;
+
+ request.set_path(path);
+ request.set_op_name(op);
+
+ ResetFailureReply reply;
+
+ ClientContext context;
+
+ Status status = stub_->ResetFailure(&context, request, &reply);
+
+ if (status.ok()) {
+ cout << "RPC Success\n";
+ } else {
+ cout << status.error_code() << ": " << status.error_message()
+ << endl;
+ cout << "RPC failed\n";
+ }
+}
+
+void usage(char *prog)
+{
+ cout << prog << ": -irs -o operation -p path -a action -d delay ";
+ cout << "-e error_code\n" ;
+ cout << " -i: Inject failure\n";
+ cout << " -r: Reset failure \n";
+ cout << " -s: status of NoiseInjection service \n";
+ cout << " -p path: path to inject failure \n";
+ cout << " -o operation: operation to inject failure \n";
+ cout << " -a action: injected action (0: DELAY/1: FAIL/2: CORRUPT) \n";
+ cout << " -d delay: delay in seconds\n";
+ cout << " -e error code to return\n";
+
+ exit(1);
+}
+
+int main(int argc, char** argv)
+{
+ // Instantiate the client.
+ FailureInjectorSvcClient injector(grpc::CreateChannel(
+ "localhost:50051", grpc::InsecureChannelCredentials()));
+ string reply;
+ int opt;
+ int flag = 0;
+ string path;
+ string operation;
+ int action = InjectedAction::FAIL;
+#define INVALID_PARAM (-9999)
+ int param = INVALID_PARAM;
+
+ while ((opt = getopt(argc, argv, "irsp:o:a:d:e:")) != -1) {
+ switch(opt) {
+ case 'i':
+ flag = 'i';
+ break;
+ case 'r':
+ flag = 'r';
+ break;
+ case 's':
+ flag = 's';
+ break;
+ case 'p':
+ path = optarg;
+ break;
+ case 'o':
+ operation = optarg;
+ break;
+ case 'a':
+ action =atoi(optarg);
+ break;
+ case 'd':
+ case 'e':
+ if (param == INVALID_PARAM) {
+ param =atoi(optarg);
+ } else {
+ usage(argv[0]);
+ }
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ switch (flag) {
+ case 'i':
+ if (param == INVALID_PARAM || action > InjectedAction::CORRUPT ||
+ path.empty() || operation.empty()) {
+ usage(argv[0]);
+ }
+ injector.InjectFailure(path, operation, action, param);
+ break;
+ case 'r':
+ injector.ResetFailure(path, operation);
+ break;
+ case 's':
+ reply = injector.GetStatus("Some Status");
+ cout << "FailureInjectorSvc received: ";
+ cout << reply << endl;
+ break;
+ default:
+ usage(argv[0]);
+ }
+
+ return 0;
+}
diff --git
a/tools/fault-injection-service/Service/cpp/failure_injector_svc_client.h
b/tools/fault-injection-service/Service/cpp/failure_injector_svc_client.h
new file mode 100644
index 0000000..3fccdbc
--- /dev/null
+++ b/tools/fault-injection-service/Service/cpp/failure_injector_svc_client.h
@@ -0,0 +1,51 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#ifndef __FAILURE_INJECTOR_SVC_CLIENT_H
+#define __FAILURE_INJECTOR_SVC_CLIENT_H
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <grpcpp/grpcpp.h>
+
+#include "failure_injection_service.grpc.pb.h"
+
+using grpc::Channel;
+using grpc::ClientContext;
+using grpc::Status;
+
+namespace NoiseInjector {
+
+class FailureInjectorSvcClient {
+ public:
+ FailureInjectorSvcClient(std::shared_ptr<Channel> channel);
+
+ std::string GetStatus(const std::string& user);
+
+ void InjectFailure(std::string path, std::string op, int action, int param);
+
+ void ResetFailure(std::string path, std::string op);
+
+ private:
+ std::unique_ptr<FailureInjectorSvc::Stub> stub_;
+};
+
+}
+
+#endif /* __FAILURE_INJECTOR_SVC_CLIENT_H */
diff --git
a/tools/fault-injection-service/Service/cpp/failure_injector_svc_server.cc
b/tools/fault-injection-service/Service/cpp/failure_injector_svc_server.cc
new file mode 100644
index 0000000..ac7919c
--- /dev/null
+++ b/tools/fault-injection-service/Service/cpp/failure_injector_svc_server.cc
@@ -0,0 +1,93 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <iostream>
+
+#include <grpcpp/grpcpp.h>
+
+#include "failure_injection_service.grpc.pb.h"
+#include "failure_injector.h"
+#include "failure_injector_svc_server.h"
+#include "run_grpc_service.h"
+
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+using grpc::Status;
+
+using namespace NoiseInjector;
+using namespace std;
+
+Status FailureInjectorSvcServiceImpl::GetStatus(
+ ServerContext* context,
+ const GetStatusRequest* request,
+ GetStatusReply* reply)
+{
+
+ string prefix("GetStatus ");
+ cout << "Recived request " << request->name() << "\n";
+ reply->set_message(prefix + request->name());
+ return Status::OK;
+}
+
+Status FailureInjectorSvcServiceImpl::InjectFailure(
+ ServerContext* context,
+ const InjectFailureRequest* request,
+ InjectFailureReply* reply)
+{
+ cout << "Recived request " << request->path() << ":"
+ << request->op_name() << "\n";
+ mFailureInjector->InjectFailure(request->path(), request->op_name(),
+ InjectedAction((int)request->action_code(),
+ (int)request->action_param(),
+ (int)request->action_param()));
+ return Status::OK;
+}
+
+Status FailureInjectorSvcServiceImpl::ResetFailure(
+ ServerContext* context,
+ const ResetFailureRequest* request,
+ ResetFailureReply* reply)
+{
+ cout << "Recived request ";
+ if (request->has_path()) {
+ cout << request->path() << "\n";
+ if (request->has_op_name()) {
+ cout << request->op_name() << "\n";
+ }
+ }
+
+ if (request->has_path() && !request->path().empty()) {
+ if (request->has_op_name() && !request->op_name().empty()) {
+ mFailureInjector->ResetFailure(request->path(),
request->op_name());
+ } else {
+ mFailureInjector->ResetFailure(request->path());
+ }
+ } else {
+ mFailureInjector->ResetFailure();
+ }
+ return Status::OK;
+}
+
+FailureInjectorSvcServiceImpl::FailureInjectorSvcServiceImpl(
+ FailureInjector* injector)
+{
+ mFailureInjector = injector;
+}
diff --git
a/tools/fault-injection-service/Service/cpp/failure_injector_svc_server.h
b/tools/fault-injection-service/Service/cpp/failure_injector_svc_server.h
new file mode 100644
index 0000000..369a5cb
--- /dev/null
+++ b/tools/fault-injection-service/Service/cpp/failure_injector_svc_server.h
@@ -0,0 +1,63 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#ifndef __FAILURE_INJECTOR_SVC_SERVER_H
+#define __FAILURE_INJECTOR_SVC_SERVER_H
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <iostream>
+
+#include <grpcpp/grpcpp.h>
+
+#include "failure_injection_service.grpc.pb.h"
+#include "failure_injector.h"
+#include "run_grpc_service.h"
+
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+using grpc::Status;
+
+namespace NoiseInjector {
+
+class FailureInjectorSvcServiceImpl final :
+ public FailureInjectorSvc::Service {
+
+public:
+ Status GetStatus(ServerContext* context,
+ const GetStatusRequest* request,
+ GetStatusReply* reply) override;
+
+ Status InjectFailure(ServerContext* context,
+ const InjectFailureRequest* request,
+ InjectFailureReply* reply) override;
+
+ Status ResetFailure(ServerContext* context,
+ const ResetFailureRequest* request,
+ ResetFailureReply* reply);
+
+ FailureInjectorSvcServiceImpl(FailureInjector* injector);
+
+private :
+ FailureInjector *mFailureInjector;
+};
+
+}
+
+#endif /* __FAILURE_INJECTOR_SVC_SERVER_H */
diff --git a/tools/fault-injection-service/Service/cpp/run_grpc_service.cc
b/tools/fault-injection-service/Service/cpp/run_grpc_service.cc
new file mode 100644
index 0000000..b3d88b9
--- /dev/null
+++ b/tools/fault-injection-service/Service/cpp/run_grpc_service.cc
@@ -0,0 +1,58 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <iostream>
+
+#include <grpcpp/grpcpp.h>
+
+#include "failure_injection_service.grpc.pb.h"
+#include "failure_injector_svc_server.h"
+#include "run_grpc_service.h"
+
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+
+using namespace NoiseInjector;
+using namespace std;
+
+void RunGrpcService::RunServer()
+{
+ string server_address("0.0.0.0:50051");
+ FailureInjectorSvcServiceImpl service(mFailureInjector);
+
+ ServerBuilder builder;
+ // Listen on the given address without any authentication mechanism.
+ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ // Register "service" as the instance through which we'll communicate with
+ // clients. In this case it corresponds to an *synchronous* service.
+ builder.RegisterService(&service);
+ // Finally assemble the server.
+ unique_ptr<Server> server(builder.BuildAndStart());
+ cout << "Server listening on " << server_address << endl;
+
+ // Wait for the server to shutdown.
+ server->Wait();
+}
+
+RunGrpcService::RunGrpcService(FailureInjector *injector)
+{
+ mFailureInjector = injector;
+}
diff --git a/tools/fault-injection-service/Service/cpp/run_grpc_service.h
b/tools/fault-injection-service/Service/cpp/run_grpc_service.h
new file mode 100644
index 0000000..73a71d1
--- /dev/null
+++ b/tools/fault-injection-service/Service/cpp/run_grpc_service.h
@@ -0,0 +1,36 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+#ifndef __RUN_GRPC_SERVICE_H__
+#define __RUN_GRPC_SERVICE_H__
+
+#include "failure_injector.h"
+
+namespace NoiseInjector {
+
+class RunGrpcService {
+public:
+ void RunServer();
+ RunGrpcService(FailureInjector *injector);
+
+private :
+ FailureInjector *mFailureInjector;
+};
+
+}
+
+#endif /* __RUN_GRPC_SERVICE_H__ */
diff --git
a/tools/fault-injection-service/Service/protos/failure_injection_service.proto
b/tools/fault-injection-service/Service/protos/failure_injection_service.proto
new file mode 100644
index 0000000..1886621
--- /dev/null
+++
b/tools/fault-injection-service/Service/protos/failure_injection_service.proto
@@ -0,0 +1,68 @@
+//
+// 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
+// <p>
+// http://www.apache.org/licenses/LICENSE-2.0
+// <p>
+// 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.
+//
+
+syntax = "proto2";
+
+package NoiseInjector;
+
+// The failure injection service definition.
+service FailureInjectorSvc {
+ // Get Service Status
+ rpc GetStatus (GetStatusRequest) returns (GetStatusReply) {
+ }
+
+ // Inject Failure
+ rpc InjectFailure (InjectFailureRequest) returns (InjectFailureReply) {
+ }
+
+ // Reset Failure
+ rpc ResetFailure (ResetFailureRequest) returns (ResetFailureReply) {
+ }
+}
+
+// The request message containing the user's name.
+message GetStatusRequest {
+ optional string name = 1;
+}
+
+// The response message containing the greetings
+message GetStatusReply {
+ optional string message = 1;
+}
+
+message InjectFailureRequest {
+ required string path = 1;
+ required string op_name = 2;
+ enum ActionCode {
+ DELAY = 0;
+ FAIL = 1;
+ CORRUPT = 2;
+ };
+ required ActionCode action_code = 3;
+ optional int64 action_param = 4;
+};
+
+message InjectFailureReply {
+}
+
+message ResetFailureRequest {
+ optional string path = 1;
+ optional string op_name = 2;
+};
+
+message ResetFailureReply {
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]