Skip to content

Commit

Permalink
Merge branch 'main' into improve-s3-credential-error-handling
Browse files Browse the repository at this point in the history
  • Loading branch information
jfantinhardesty committed Jun 14, 2024
2 parents d53c9c4 + eef70c8 commit fa86e57
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 123 deletions.
1 change: 1 addition & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ jobs:
run: |
find ./samples/cloudfuse_plugin/ -iname '*.h' -o -iname '*.cpp' | xargs clang-format -i --dry-run --Werror
find ./samples/unit_tests/ -iname '*.h' -o -iname '*.cpp' | xargs clang-format -i --dry-run --Werror
find ./src/cloudfuse/ -iname '*.h' -o -iname '*.cpp' | xargs clang-format -i --dry-run --Werror
6 changes: 4 additions & 2 deletions src/cloudfuse/child_process.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include "child_process.h"

std::string CloudfuseMngr::getMountDir() {
std::string CloudfuseMngr::getMountDir()
{
return mountDir;
}

std::string CloudfuseMngr::getFileCacheDir() {
std::string CloudfuseMngr::getFileCacheDir()
{
return fileCacheDir;
}
30 changes: 17 additions & 13 deletions src/cloudfuse/child_process.h
Original file line number Diff line number Diff line change
@@ -1,38 +1,42 @@
#include <string>

struct processReturn {
int errCode; // 0 if successful, failed otherwise
struct processReturn
{
int errCode; // 0 if successful, failed otherwise
std::string output; // std err and std out from cloudfuse command
};

class CloudfuseMngr {
public:
class CloudfuseMngr
{
public:
CloudfuseMngr();
#ifdef _WIN32
#ifdef _WIN32
CloudfuseMngr(std::string mountDir, std::string configFile, std::string fileCachePath);
processReturn dryRun(std::string passphrase);
processReturn mount(std::string passphrase);
processReturn genS3Config(std::string accessKeyId, std::string secretAccessKey, std::string region, std::string endpoint, std::string bucketName, std::string passphrase);
#elif defined(__linux__) || defined(__APPLE__)
processReturn genS3Config(std::string accessKeyId, std::string secretAccessKey, std::string region,
std::string endpoint, std::string bucketName, std::string passphrase);
#elif defined(__linux__) || defined(__APPLE__)
CloudfuseMngr(std::string mountDir, std::string fileCacheDir, std::string configFile, std::string templateFile);
processReturn dryRun(std::string accessKeyId, std::string secretAccessKey, std::string passphrase);
processReturn mount(std::string accessKeyId, std::string secretAccessKey, std::string passphrase);
processReturn genS3Config(std::string region, std::string endpoint, std::string bucketName, std::string passphrase);
#endif
#endif
std::string getMountDir();
std::string getFileCacheDir();
processReturn unmount();
bool isInstalled();
bool isMounted();
private:

private:
std::string mountDir;
std::string configFile;
std::string fileCacheDir;
std::string templateFile;
#ifdef _WIN32
processReturn spawnProcess(wchar_t* argv, std::wstring envp);
#ifdef _WIN32
processReturn spawnProcess(wchar_t *argv, std::wstring envp);
processReturn encryptConfig(std::string passphrase);
#elif defined(__linux__) || defined(__APPLE__)
#elif defined(__linux__) || defined(__APPLE__)
processReturn spawnProcess(char *const argv[], char *const envp[]);
#endif
#endif
};
142 changes: 94 additions & 48 deletions src/cloudfuse/child_process_linux.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#if defined(__linux__)
#include "child_process.h"
#include <fstream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

std::string config_template = R"(
allow-other: true
Expand Down Expand Up @@ -39,12 +39,16 @@ allow-other: true
region: { AWS_REGION }
)";

CloudfuseMngr::CloudfuseMngr() {
CloudfuseMngr::CloudfuseMngr()
{
std::string homeEnv;
const char *home = std::getenv("HOME");
if (home == nullptr) {
if (home == nullptr)
{
homeEnv = "";
} else {
}
else
{
homeEnv = home;
}
mountDir = homeEnv + "/cloudfuse";
Expand All @@ -53,161 +57,203 @@ CloudfuseMngr::CloudfuseMngr() {
templateFile = homeEnv + "/nx_plugin_config.yaml";

std::ifstream in(templateFile);
if (!in.good()) {
if (!in.good())
{
std::ofstream out(templateFile);
out << config_template;
out.close();
}
}

CloudfuseMngr::CloudfuseMngr(std::string mountDir, std::string fileCacheDir, std::string configFile, std::string templateFile) {
CloudfuseMngr::CloudfuseMngr(std::string mountDir, std::string fileCacheDir, std::string configFile,
std::string templateFile)
{
this->mountDir = mountDir;
this->configFile = configFile;
this->fileCacheDir = fileCacheDir;
this->templateFile = templateFile;
}

processReturn CloudfuseMngr::spawnProcess(char *const argv[], char *const envp[]) {
processReturn CloudfuseMngr::spawnProcess(char *const argv[], char *const envp[])
{
processReturn ret;

int pipefd[2];
if (pipe(pipefd) == -1) {
if (pipe(pipefd) == -1)
{
throw std::runtime_error("Failed to create pipe.");
}

pid_t pid = fork();
if (pid == -1) {
if (pid == -1)
{
// Fork failed
throw std::runtime_error("Failed to fork process.");
} else if (pid != 0) {
}
else if (pid != 0)
{
// Parent process
close(pipefd[1]); // Close write end of pipe

char buffer[4096];
int bytesRead;
while ((bytesRead = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
while ((bytesRead = read(pipefd[0], buffer, sizeof(buffer))) > 0)
{
ret.output.append(buffer, bytesRead);
}

close(pipefd[0]); // Close read end of pipe

// Wait for cloudfuse command to stop
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
if (WIFEXITED(status))
{
ret.errCode = WEXITSTATUS(status);
return ret;
} else if (WIFSIGNALED(status)) {
}
else if (WIFSIGNALED(status))
{
ret.errCode = WTERMSIG(status);
return ret;
}

ret.errCode = WTERMSIG(status);
return ret;
} else {
}
else
{
// Child process
close(pipefd[0]); // Close read end of pipe

if (dup2(pipefd[1], STDOUT_FILENO) == -1 || dup2(pipefd[1], STDERR_FILENO) == -1) {
if (dup2(pipefd[1], STDOUT_FILENO) == -1 || dup2(pipefd[1], STDERR_FILENO) == -1)
{
exit(EXIT_FAILURE);
}

close(pipefd[1]); // Close write end of pipe

if (execve(argv[0], argv, envp) == -1) {
if (execve(argv[0], argv, envp) == -1)
{
exit(EXIT_FAILURE);
}

exit(EXIT_SUCCESS);
}
}

processReturn CloudfuseMngr::genS3Config(std::string region, std::string endpoint, std::string bucketName, std::string passphrase) {
processReturn CloudfuseMngr::genS3Config(std::string region, std::string endpoint, std::string bucketName,
std::string passphrase)
{
std::string configArg = "--config-file=" + templateFile;
std::string outputArg = "--output-file=" + configFile;
std::string fileCachePathArg = "--temp-path=" + fileCacheDir;
std::string passphraseArg = "--passphrase=" + passphrase;
char *const argv[] = {const_cast<char*>("/bin/cloudfuse"), const_cast<char*>("gen-config"), const_cast<char*>(configArg.c_str()),
const_cast<char*>(outputArg.c_str()), const_cast<char*>(fileCachePathArg.c_str()), const_cast<char*>(passphraseArg.c_str()), NULL};

char *const argv[] = {const_cast<char *>("/bin/cloudfuse"),
const_cast<char *>("gen-config"),
const_cast<char *>(configArg.c_str()),
const_cast<char *>(outputArg.c_str()),
const_cast<char *>(fileCachePathArg.c_str()),
const_cast<char *>(passphraseArg.c_str()),
NULL};

std::string bucketNameEnv = "BUCKET_NAME=" + bucketName;
std::string endpointEnv = "ENDPOINT=" + endpoint;
std::string regionEnv = "AWS_REGION=" + region;
char *const envp[] = {const_cast<char*>(bucketNameEnv.c_str()), const_cast<char*>(endpointEnv.c_str()), const_cast<char*>(regionEnv.c_str()), NULL};
char *const envp[] = {const_cast<char *>(bucketNameEnv.c_str()), const_cast<char *>(endpointEnv.c_str()),
const_cast<char *>(regionEnv.c_str()), NULL};

return spawnProcess(argv, envp);
}

processReturn CloudfuseMngr::dryRun(std::string accessKeyId, std::string secretAccessKey, std::string passphrase) {
processReturn CloudfuseMngr::dryRun(std::string accessKeyId, std::string secretAccessKey, std::string passphrase)
{
std::string configArg = "--config-file=" + configFile;
std::string passphraseArg = "--passphrase=" + passphrase;
char *const argv[] = {const_cast<char*>("/bin/cloudfuse"), const_cast<char*>("mount"), const_cast<char*>(mountDir.c_str()), const_cast<char*>(configArg.c_str()),
const_cast<char*>(passphraseArg.c_str()), const_cast<char*>("--dry-run"), NULL};
char *const argv[] = {const_cast<char *>("/bin/cloudfuse"),
const_cast<char *>("mount"),
const_cast<char *>(mountDir.c_str()),
const_cast<char *>(configArg.c_str()),
const_cast<char *>(passphraseArg.c_str()),
const_cast<char *>("--dry-run"),
NULL};

std::string awsAccessKeyIdEnv = "AWS_ACCESS_KEY_ID=" + accessKeyId;
std::string awsSecretAccessKeyEnv = "AWS_SECRET_ACCESS_KEY=" + secretAccessKey;
char *const envp[] = {const_cast<char*>(awsAccessKeyIdEnv.c_str()), const_cast<char*>(awsSecretAccessKeyEnv.c_str()), NULL};

char *const envp[] = {const_cast<char *>(awsAccessKeyIdEnv.c_str()),
const_cast<char *>(awsSecretAccessKeyEnv.c_str()), NULL};

return spawnProcess(argv, envp);
}

processReturn CloudfuseMngr::mount(std::string accessKeyId, std::string secretAccessKey, std::string passphrase) {
processReturn CloudfuseMngr::mount(std::string accessKeyId, std::string secretAccessKey, std::string passphrase)
{
std::string configArg = "--config-file=" + configFile;
std::string passphraseArg = "--passphrase=" + passphrase;
char *const argv[] = {const_cast<char*>("/bin/cloudfuse"), const_cast<char*>("mount"), const_cast<char*>(mountDir.c_str()), const_cast<char*>(configArg.c_str()),
const_cast<char*>(passphraseArg.c_str()), NULL};

char *const argv[] = {const_cast<char *>("/bin/cloudfuse"), const_cast<char *>("mount"),
const_cast<char *>(mountDir.c_str()), const_cast<char *>(configArg.c_str()),
const_cast<char *>(passphraseArg.c_str()), NULL};

std::string awsAccessKeyIdEnv = "AWS_ACCESS_KEY_ID=" + accessKeyId;
std::string awsSecretAccessKeyEnv = "AWS_SECRET_ACCESS_KEY=" + secretAccessKey;
char *const envp[] = {const_cast<char*>(awsAccessKeyIdEnv.c_str()), const_cast<char*>(awsSecretAccessKeyEnv.c_str()), NULL};
char *const envp[] = {const_cast<char *>(awsAccessKeyIdEnv.c_str()),
const_cast<char *>(awsSecretAccessKeyEnv.c_str()), NULL};

return spawnProcess(argv, envp);
}

processReturn CloudfuseMngr::unmount() {
char *const argv[] = {const_cast<char*>("/bin/cloudfuse"), const_cast<char*>("unmount"), const_cast<char*>(mountDir.c_str()), const_cast<char*>("-z"), NULL};
char *const envp[] = {const_cast<char*>("PATH=/bin"), NULL};
processReturn CloudfuseMngr::unmount()
{
char *const argv[] = {const_cast<char *>("/bin/cloudfuse"), const_cast<char *>("unmount"),
const_cast<char *>(mountDir.c_str()), const_cast<char *>("-z"), NULL};
char *const envp[] = {const_cast<char *>("PATH=/bin"), NULL};

return spawnProcess(argv, envp);
}

bool CloudfuseMngr::isInstalled() {
char *const argv[] = {const_cast<char*>("/bin/cloudfuse"), const_cast<char*>("version"), NULL};

bool CloudfuseMngr::isInstalled()
{
char *const argv[] = {const_cast<char *>("/bin/cloudfuse"), const_cast<char *>("version"), NULL};

return spawnProcess(argv, NULL).errCode == 0;
}

bool CloudfuseMngr::isMounted() {
bool CloudfuseMngr::isMounted()
{
// Logic based on os.ismount implementation in Python.

struct stat buf1, buf2;

if (lstat(mountDir.c_str(), &buf1) != 0) {
if (lstat(mountDir.c_str(), &buf1) != 0)
{
// Folder doesn't exist, so not mounted
return false;
}

if S_ISLNK(buf1.st_mode) {
if S_ISLNK (buf1.st_mode)
{
// Mount can't be a symbolic link
return false;
}

std::string parent = mountDir + "/..";
if (lstat(parent.c_str(), &buf2) != 0) {
if (lstat(parent.c_str(), &buf2) != 0)
{
return false;
}

if (buf1.st_dev != buf2.st_dev) {
if (buf1.st_dev != buf2.st_dev)
{
// Directory on a different path from parent, so this is mounted
return true;
}

if (buf1.st_ino == buf2.st_ino) {
if (buf1.st_ino == buf2.st_ino)
{
// These point to the same inode, so this is mounted
return true;
}


return false;
}

Expand Down
Loading

0 comments on commit fa86e57

Please sign in to comment.