HDFS-16260. Make hdfs_deleteSnapshot tool cross platform (#3532)

This commit is contained in:
Gautham B A 2021-10-12 06:55:28 +05:30 committed by GitHub
parent d7c01d083c
commit a05eb23a85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 453 additions and 89 deletions

View File

@ -18,6 +18,7 @@
add_executable(hdfs_tool_tests
hdfs-allow-snapshot-mock.cc
hdfs-delete-snapshot-mock.cc
hdfs-cat-mock.cc
hdfs-tool-test-fixtures.cc
hdfs-tool-tests.cc
@ -31,5 +32,6 @@ target_include_directories(hdfs_tool_tests PRIVATE
target_link_libraries(hdfs_tool_tests PRIVATE
gmock_main
hdfs_allowSnapshot_lib
hdfs_deleteSnapshot_lib
hdfs_cat_lib)
add_test(hdfs_tool_tests hdfs_tool_tests)

View File

@ -0,0 +1,57 @@
/*
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.
*/
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "hdfs-delete-snapshot-mock.h"
#include "hdfs-tool-tests.h"
namespace hdfs::tools::test {
DeleteSnapshotMock::~DeleteSnapshotMock() = default;
void DeleteSnapshotMock::SetExpectations(
std::function<std::unique_ptr<DeleteSnapshotMock>()> test_case,
const std::vector<std::string> &args) const {
// Get the pointer to the function that defines the test case
const auto test_case_func =
test_case.target<std::unique_ptr<DeleteSnapshotMock> (*)()>();
ASSERT_NE(test_case_func, nullptr);
// Set the expected method calls and their corresponding arguments for each
// test case
if (*test_case_func == &CallHelp<DeleteSnapshotMock>) {
EXPECT_CALL(*this, HandleHelp()).Times(1).WillOnce(testing::Return(true));
return;
}
if (*test_case_func == &Pass2Paths<DeleteSnapshotMock>) {
const auto arg1 = args[0];
const auto arg2 = args[1];
EXPECT_CALL(*this, HandleSnapshot(arg1, arg2))
.Times(1)
.WillOnce(testing::Return(true));
}
}
} // namespace hdfs::tools::test

View File

@ -0,0 +1,70 @@
/**
* 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.
*/
#ifndef LIBHDFSPP_TOOLS_HDFS_DELETE_SNAPSHOT_MOCK
#define LIBHDFSPP_TOOLS_HDFS_DELETE_SNAPSHOT_MOCK
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <gmock/gmock.h>
#include "hdfs-delete-snapshot.h"
namespace hdfs::tools::test {
/**
* {@class DeleteSnapshotMock} is an {@class DeleteSnapshot} whereby it mocks
* the HandleHelp and HandleSnapshot methods for testing their functionality.
*/
class DeleteSnapshotMock : public hdfs::tools::DeleteSnapshot {
public:
/**
* {@inheritdoc}
*/
DeleteSnapshotMock(const int argc, char **argv)
: DeleteSnapshot(argc, argv) {}
// Abiding to the Rule of 5
DeleteSnapshotMock(const DeleteSnapshotMock &) = delete;
DeleteSnapshotMock(DeleteSnapshotMock &&) = delete;
DeleteSnapshotMock &operator=(const DeleteSnapshotMock &) = delete;
DeleteSnapshotMock &operator=(DeleteSnapshotMock &&) = delete;
~DeleteSnapshotMock() override;
/**
* Defines the methods and the corresponding arguments that are expected
* to be called on this instance of {@link HdfsTool} for the given test case.
*
* @param test_case An {@link std::function} object that points to the
* function defining the test case
* @param args The arguments that are passed to this test case
*/
void SetExpectations(
std::function<std::unique_ptr<DeleteSnapshotMock>()> test_case,
const std::vector<std::string> &args = {}) const;
MOCK_METHOD(bool, HandleHelp, (), (const, override));
MOCK_METHOD(bool, HandleSnapshot, (const std::string &, const std::string &),
(const, override));
};
} // namespace hdfs::tools::test
#endif

View File

@ -21,6 +21,7 @@
#include "hdfs-allow-snapshot-mock.h"
#include "hdfs-cat-mock.h"
#include "hdfs-delete-snapshot-mock.h"
#include "hdfs-tool-test-fixtures.h"
#include "hdfs-tool-tests.h"
@ -30,6 +31,12 @@
* hdfs-tool-test.h} to yield the test suite.
*/
/**
* This file combines the test fixtures defined in {@file
* hdfs-tool-test-fixtures.h} and the test cases defined in {@file
* hdfs-tool-test.h} to yield the test structure.
*/
INSTANTIATE_TEST_SUITE_P(
HdfsAllowSnapshot, HdfsToolBasicTest,
testing::Values(PassAPath<hdfs::tools::test::AllowSnapshotMock>,
@ -39,6 +46,11 @@ INSTANTIATE_TEST_SUITE_P(HdfsCat, HdfsToolBasicTest,
testing::Values(PassAPath<hdfs::tools::test::CatMock>,
CallHelp<hdfs::tools::test::CatMock>));
INSTANTIATE_TEST_SUITE_P(
HdfsDeleteSnapshot, HdfsToolBasicTest,
testing::Values(CallHelp<hdfs::tools::test::DeleteSnapshotMock>,
Pass2Paths<hdfs::tools::test::DeleteSnapshotMock>));
INSTANTIATE_TEST_SUITE_P(
HdfsAllowSnapshot, HdfsToolNegativeTestThrows,
testing::Values(Pass2Paths<hdfs::tools::test::AllowSnapshotMock>));
@ -46,3 +58,7 @@ INSTANTIATE_TEST_SUITE_P(
INSTANTIATE_TEST_SUITE_P(
HdfsCat, HdfsToolNegativeTestThrows,
testing::Values(Pass2Paths<hdfs::tools::test::CatMock>));
INSTANTIATE_TEST_SUITE_P(
HdfsDeleteSnapshot, HdfsToolNegativeTestNoThrow,
testing::Values(PassAPath<hdfs::tools::test::DeleteSnapshotMock>));

View File

@ -89,8 +89,7 @@ target_link_libraries(hdfs_createSnapshot tools_common hdfspp_static)
add_executable(hdfs_renameSnapshot hdfs_renameSnapshot.cc)
target_link_libraries(hdfs_renameSnapshot tools_common hdfspp_static)
add_executable(hdfs_deleteSnapshot hdfs_deleteSnapshot.cc)
target_link_libraries(hdfs_deleteSnapshot tools_common hdfspp_static)
add_subdirectory(hdfs-delete-snapshot)
add_executable(hdfs_tail hdfs_tail.cc)
target_link_libraries(hdfs_tail tools_common hdfspp_static)

View File

@ -0,0 +1,27 @@
#
# 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.
#
add_library(hdfs_deleteSnapshot_lib STATIC $<TARGET_OBJECTS:hdfs_tool_obj> hdfs-delete-snapshot.cc)
target_include_directories(hdfs_deleteSnapshot_lib PRIVATE ../../tools ${Boost_INCLUDE_DIRS})
target_link_libraries(hdfs_deleteSnapshot_lib PRIVATE Boost::boost Boost::program_options tools_common hdfspp_static)
add_executable(hdfs_deleteSnapshot main.cc)
target_include_directories(hdfs_deleteSnapshot PRIVATE ../../tools)
target_link_libraries(hdfs_deleteSnapshot PRIVATE hdfs_deleteSnapshot_lib)
install(TARGETS hdfs_deleteSnapshot RUNTIME DESTINATION bin)

View File

@ -0,0 +1,133 @@
/*
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.
*/
#include <iostream>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include "hdfs-delete-snapshot.h"
#include "tools_common.h"
namespace hdfs::tools {
DeleteSnapshot::DeleteSnapshot(const int argc, char **argv)
: HdfsTool(argc, argv) {}
bool DeleteSnapshot::Initialize() {
auto add_options = opt_desc_.add_options();
add_options("help,h", "Show the help for hdfs_deleteSnapshot");
add_options("path", po::value<std::string>(),
"The path to the directory that is snapshot-able");
add_options("name", po::value<std::string>(), "The name of the snapshot");
// Register "path" and "name" as positional arguments.
// We allow only two arguments to be passed to this tool. An exception is
// thrown if more than two arguments are passed.
pos_opt_desc_.add("path", 1);
pos_opt_desc_.add("name", 1);
po::store(po::command_line_parser(argc_, argv_)
.options(opt_desc_)
.positional(pos_opt_desc_)
.run(),
opt_val_);
po::notify(opt_val_);
return true;
}
bool DeleteSnapshot::ValidateConstraints() const {
// Only "help" is allowed as single argument
if (argc_ == 2) {
if (opt_val_.count("help") > 0) {
return true;
}
return false;
}
// Rest of the cases must contain more than 1 argument on the command line
return argc_ > 2;
}
std::string DeleteSnapshot::GetDescription() const {
std::stringstream desc;
desc << "Usage: hdfs_deleteSnapshot [OPTION] PATH NAME" << std::endl
<< std::endl
<< "Delete a snapshot NAME from a snapshot-able directory." << std::endl
<< "This operation requires owner privilege of the snapshot-able "
"directory."
<< std::endl
<< std::endl
<< " -h display this help and exit" << std::endl
<< std::endl
<< "Examples:" << std::endl
<< "hdfs_deleteSnapshot hdfs://localhost.localdomain:8020/dir mySnapshot"
<< std::endl
<< "hdfs_deleteSnapshot /dir1/dir2 mySnapshot" << std::endl;
return desc.str();
}
bool DeleteSnapshot::Do() {
if (!Initialize()) {
std::cerr << "Unable to initialize HDFS delete snapshot tool" << std::endl;
return false;
}
if (!ValidateConstraints()) {
std::cout << GetDescription();
return false;
}
if (opt_val_.count("help") > 0) {
return HandleHelp();
}
if (opt_val_.count("path") > 0 && opt_val_.count("name") > 0) {
const auto path = opt_val_["path"].as<std::string>();
const auto name = opt_val_["name"].as<std::string>();
return HandleSnapshot(path, name);
}
return true;
}
bool DeleteSnapshot::HandleHelp() const {
std::cout << GetDescription();
return true;
}
bool DeleteSnapshot::HandleSnapshot(const std::string &path,
const std::string &name) const {
// Building a URI object from the given path
auto uri = hdfs::parse_path_or_exit(path);
const auto fs = hdfs::doConnect(uri, false);
if (!fs) {
std::cerr << "Could not connect the file system. " << std::endl;
return false;
}
const auto status = fs->DeleteSnapshot(uri.get_path(), name);
if (!status.ok()) {
std::cerr << "Error: " << status.ToString() << std::endl;
return false;
}
return true;
}
} // namespace hdfs::tools

View File

@ -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
*
* 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.
*/
#ifndef LIBHDFSPP_TOOLS_HDFS_DELETE_SNAPSHOT
#define LIBHDFSPP_TOOLS_HDFS_DELETE_SNAPSHOT
#include <string>
#include <boost/program_options.hpp>
#include "hdfs-tool.h"
namespace hdfs::tools {
/**
* {@class DeleteSnapshot} is an {@class HdfsTool} that facilitates the
* snapshots of a directory at PATH to be created, causing the directory to be
* snapshot-able.
*/
class DeleteSnapshot : public HdfsTool {
public:
/**
* {@inheritdoc}
*/
DeleteSnapshot(int argc, char **argv);
// Abiding to the Rule of 5
DeleteSnapshot(const DeleteSnapshot &) = default;
DeleteSnapshot(DeleteSnapshot &&) = default;
DeleteSnapshot &operator=(const DeleteSnapshot &) = delete;
DeleteSnapshot &operator=(DeleteSnapshot &&) = delete;
~DeleteSnapshot() override = default;
/**
* {@inheritdoc}
*/
[[nodiscard]] std::string GetDescription() const override;
/**
* {@inheritdoc}
*/
[[nodiscard]] bool Do() override;
protected:
/**
* {@inheritdoc}
*/
[[nodiscard]] bool Initialize() override;
/**
* {@inheritdoc}
*/
[[nodiscard]] bool ValidateConstraints() const override;
/**
* {@inheritdoc}
*/
[[nodiscard]] bool HandleHelp() const override;
/**
* Handle the arguments that are passed to this tool.
*
* @param path The path to the directory that is snapshot-able.
* @param name The name of the snapshot.
*
* @return A boolean indicating the result of this operation.
*/
[[nodiscard]] virtual bool HandleSnapshot(const std::string &path,
const std::string &name) const;
private:
/**
* A boost data-structure containing the description of positional arguments
* passed to the command-line.
*/
po::positional_options_description pos_opt_desc_;
};
} // namespace hdfs::tools
#endif

View File

@ -0,0 +1,54 @@
/*
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.
*/
#include <cstdlib>
#include <exception>
#include <iostream>
#include <google/protobuf/stubs/common.h>
#include "hdfs-delete-snapshot.h"
int main(int argc, char *argv[]) {
const auto result = std::atexit([]() -> void {
// Clean up static data on exit and prevent valgrind memory leaks
google::protobuf::ShutdownProtobufLibrary();
});
if (result != 0) {
std::cerr << "Error: Unable to schedule clean-up tasks for HDFS delete "
"snapshot tool, exiting"
<< std::endl;
std::exit(EXIT_FAILURE);
}
hdfs::tools::DeleteSnapshot delete_snapshot(argc, argv);
auto success = false;
try {
success = delete_snapshot.Do();
} catch (const std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
success = false;
}
if (!success) {
std::exit(EXIT_FAILURE);
}
return 0;
}

View File

@ -1,87 +0,0 @@
/*
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.
*/
#include <google/protobuf/stubs/common.h>
#include <unistd.h>
#include "tools_common.h"
void usage(){
std::cout << "Usage: hdfs_deleteSnapshot [OPTION] PATH NAME"
<< std::endl
<< std::endl << "Delete a snapshot NAME from a snapshottable directory."
<< std::endl << "This operation requires owner privilege of the snapshottable directory."
<< std::endl
<< std::endl << " -h display this help and exit"
<< std::endl
<< std::endl << "Examples:"
<< std::endl << "hdfs_deleteSnapshot hdfs://localhost.localdomain:8020/dir mySnapshot"
<< std::endl << "hdfs_deleteSnapshot /dir1/dir2 mySnapshot"
<< std::endl;
}
int main(int argc, char *argv[]) {
//We should have at least 2 arguments
if (argc < 2) {
usage();
exit(EXIT_FAILURE);
}
int input;
//Using GetOpt to read in the values
opterr = 0;
while ((input = getopt(argc, argv, "h")) != -1) {
switch (input)
{
case 'h':
usage();
exit(EXIT_SUCCESS);
case '?':
if (isprint(optopt))
std::cerr << "Unknown option `-" << (char) optopt << "'." << std::endl;
else
std::cerr << "Unknown option character `" << (char) optopt << "'." << std::endl;
usage();
exit(EXIT_FAILURE);
default:
exit(EXIT_FAILURE);
}
}
std::string uri_path = argv[optind];
std::string name = argv[optind+1];
//Building a URI object from the given uri_path
hdfs::URI uri = hdfs::parse_path_or_exit(uri_path);
std::shared_ptr<hdfs::FileSystem> fs = hdfs::doConnect(uri, false);
if (!fs) {
std::cerr << "Could not connect the file system. " << std::endl;
exit(EXIT_FAILURE);
}
hdfs::Status status = fs->DeleteSnapshot(uri.get_path(), name);
if (!status.ok()) {
std::cerr << "Error: " << status.ToString() << std::endl;
exit(EXIT_FAILURE);
}
// Clean up static data and prevent valgrind memory leaks
google::protobuf::ShutdownProtobufLibrary();
return 0;
}