diff --git a/curvefs/proto/mds.proto b/curvefs/proto/mds.proto index 9e4022dfde..37bfdfddc5 100644 --- a/curvefs/proto/mds.proto +++ b/curvefs/proto/mds.proto @@ -77,7 +77,7 @@ enum FsStatus { message FsDetail { optional common.Volume volume = 1; - optional common.S3Info s3Info = 2; + optional common.S3Info s3info = 2; } message Mountpoint { @@ -115,7 +115,8 @@ message GetFsInfoResponse { } message UpdateS3InfoRequest { - required common.S3Info s3Info = 1; + required string fsName = 1; + required common.S3Info s3Info = 2; } message UpdateS3InfoResponse { diff --git a/curvefs/src/client/BUILD b/curvefs/src/client/BUILD index 33a3b45089..f6eefffbc6 100644 --- a/curvefs/src/client/BUILD +++ b/curvefs/src/client/BUILD @@ -92,6 +92,7 @@ cc_library( "//external:brpc", "//external:gflags", "//external:glog", + "//external:json", "//src/client:curve_client", "//src/common:curve_common", "//src/common:curve_s3_adapter", diff --git a/curvefs/src/client/curve_fuse_op.cpp b/curvefs/src/client/curve_fuse_op.cpp index ad3c543a8f..c673c775a6 100644 --- a/curvefs/src/client/curve_fuse_op.cpp +++ b/curvefs/src/client/curve_fuse_op.cpp @@ -428,41 +428,66 @@ FuseClient* Client() { void UpdateS3Config(fuse_req_t req, fuse_ino_t ino, const char* name, - const char* value, - size_t size) { + const char* value) { + + auto fs = g_ClientInstance->GetFileSystem(); if (g_ClientInstance->GetFsInfo()->fstype() != FSType::TYPE_S3) { LOG(ERROR) << "updating s3 config only works for s3"; - return EOPNOTSUPP; + return fs->ReplyError(req, CURVEFS_ERROR::NOT_SUPPORT); } const std::string fsName = g_ClientInstance->GetFsInfo()->fsname(); - const curvefs::common::S3Info oldS3Info = g_ClientInstance->GetFsInfo()->detail()->s3Info(); - const curvefs::common::S3Info newS3Info(oldS3Info); + const curvefs::common::S3Info oldS3Info = g_ClientInstance->GetFsInfo()->detail().s3info(); + curvefs::common::S3Info newS3Info(oldS3Info); Json::CharReaderBuilder builder; Json::CharReaderBuilder::strictMode(&builder.settings_); std::unique_ptr reader(builder.newCharReader()); Json::Value rootNode; JSONCPP_STRING errormsg; - if (reader->parse(value, value + strlen(value), &rootNode, &errormsg)) { - newS3Info.ak = rootNode["ak"].asString(); - newS3Info.sk = rootNode["sk"].asString(); - newS3Info.bucket = rootNode["bucket"].asString(); - newS3Info.endpoint = rootNode["endpoint"].asString(); - - FsInfo fsInfo; - FSStatusCode statusCode = g_ClientInstance->mdsClient_->UpdateS3Info(fsName, newS3Info, &fsInfo); - if (statusCode == FSStatusCode::OK) { - g_ClientInstance->SetFsInfo(fsInfo); - } - } else { + if (!reader->parse(value, value + strlen(value), &rootNode, &errormsg)) { LOG(ERROR) << "Error parsing the input value ' " << value << " ': " << errormsg; + return fs->ReplyError(req, CURVEFS_ERROR::IO_ERROR); } - fuse_reply_err(req, statusCode); + FuseS3Client* g_S3ClientInstance = dynamic_cast(g_ClientInstance); + if (!g_S3ClientInstance) { + LOG(ERROR) << "Dynamic cast from FuseClient to FuseS3Client failed"; + return fs->ReplyError(req, CURVEFS_ERROR::INTERNAL); + } + + if (rootNode.isMember("ak") && rootNode["ak"].asString() != oldS3Info.ak()) { + newS3Info.set_ak(rootNode["ak"].asString()); + } + + if (rootNode.isMember("sk") && rootNode["sk"].asString() != oldS3Info.sk()) { + newS3Info.set_sk(rootNode["sk"].asString()); + } + + if (rootNode.isMember("bucketname") && rootNode["bucketname"].asString() != oldS3Info.bucketname()) { + newS3Info.set_bucketname(rootNode["bucketname"].asString()); + } + + if (rootNode.isMember("endpoint") && rootNode["endpoint"].asString() != oldS3Info.endpoint()) { + newS3Info.set_endpoint(rootNode["endpoint"].asString()); + } + + if (oldS3Info.SerializeAsString() == newS3Info.SerializeAsString()) { + return fs->ReplyError(req, CURVEFS_ERROR::NODATA); + } + + FsInfo fsInfo; + CURVEFS_ERROR updateStatusCode = g_S3ClientInstance->UpdateS3Info(fsName, newS3Info, fsInfo); + if (updateStatusCode != CURVEFS_ERROR::OK) { + return fs->ReplyError(req, updateStatusCode); + } + + g_ClientInstance->SetFsInfo(std::make_shared(fsInfo)); + + return fs->ReplyError(req, CURVEFS_ERROR::OK); } void TriggerWarmup(fuse_req_t req, diff --git a/curvefs/src/client/filesystem/error.h b/curvefs/src/client/filesystem/error.h index 75efe38283..d0ebfb2532 100644 --- a/curvefs/src/client/filesystem/error.h +++ b/curvefs/src/client/filesystem/error.h @@ -59,6 +59,7 @@ enum class CURVEFS_ERROR { NOSYS = -20, END_OF_FILE = -21, NOT_A_DIRECTORY = -22, + UPDATE_S3_INFO_FAILED = -23, }; std::string StrErr(CURVEFS_ERROR code); diff --git a/curvefs/src/client/filesystem/xattr.h b/curvefs/src/client/filesystem/xattr.h index 4059f93d34..8cde3e1127 100644 --- a/curvefs/src/client/filesystem/xattr.h +++ b/curvefs/src/client/filesystem/xattr.h @@ -45,7 +45,7 @@ const char XATTR_DIR_RFBYTES[] = "curve.dir.rfbytes"; const char XATTR_DIR_PREFIX[] = "curve.dir"; const char XATTR_WARMUP_OP[] = "curvefs.warmup.op"; const char XATTR_WARMUP_OP_LIST[] = "curvefs.warmup.op.list"; -const char XATTR_S3_CONFIG[] = "curvefs.s3.config"; +const char XATTR_S3_CONFIG[] = "curvefs.s3.update.config"; inline bool IsSpecialXAttr(const std::string& key) { static std::map xattrs { diff --git a/curvefs/src/client/fuse_s3_client.cpp b/curvefs/src/client/fuse_s3_client.cpp index ab2524f76a..8b7561f9dc 100644 --- a/curvefs/src/client/fuse_s3_client.cpp +++ b/curvefs/src/client/fuse_s3_client.cpp @@ -389,6 +389,28 @@ CURVEFS_ERROR FuseS3Client::Truncate(InodeWrapper *inode, uint64_t length) { return s3Adaptor_->Truncate(inode, length); } +CURVEFS_ERROR FuseS3Client::UpdateS3Info(const std::string& fsName, + const curvefs::common::S3Info& s3Info, + FsInfo& fsInfo) { + ::curve::common::S3InfoOption s3InfoOption; + ::curvefs::client::common::S3Info2FsS3Option(s3Info, &s3InfoOption); + FSStatusCode updateStatusCode = mdsClient_->UpdateS3Info(fsName, s3Info, &fsInfo); + if (updateStatusCode != FSStatusCode::OK) { + LOG(ERROR) << "Update s3 info error code: (FSStatusCode)" + << updateStatusCode; + return CURVEFS_ERROR::UPDATE_S3_INFO_FAILED; + } + + if (option_.s3Opt.s3AdaptrOpt.ak != s3Info.ak() || + option_.s3Opt.s3AdaptrOpt.sk != s3Info.sk() || + option_.s3Opt.s3AdaptrOpt.s3Address != s3Info.endpoint() || + option_.s3Opt.s3AdaptrOpt.bucketName != s3Info.bucketname()) { + s3Adaptor_->GetS3Client()->Reinit(option_.s3Opt.s3AdaptrOpt); + } + + return CURVEFS_ERROR::OK; +} + CURVEFS_ERROR FuseS3Client::FuseOpFlush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { (void)req; diff --git a/curvefs/src/client/fuse_s3_client.h b/curvefs/src/client/fuse_s3_client.h index 1b4b4a70b4..c807f7c482 100644 --- a/curvefs/src/client/fuse_s3_client.h +++ b/curvefs/src/client/fuse_s3_client.h @@ -125,6 +125,10 @@ class FuseS3Client : public FuseClient { CURVEFS_ERROR Truncate(InodeWrapper *inode, uint64_t length) override; + CURVEFS_ERROR UpdateS3Info(const std::string& fsName, + const curvefs::common::S3Info& s3Info, + FsInfo& fsInfo); + private: bool InitKVCache(const KVClientManagerOpt &opt); diff --git a/curvefs/src/client/metric/client_metric.h b/curvefs/src/client/metric/client_metric.h index f5140b896d..b38cfd0b68 100644 --- a/curvefs/src/client/metric/client_metric.h +++ b/curvefs/src/client/metric/client_metric.h @@ -43,6 +43,7 @@ namespace metric { struct MDSClientMetric { static const std::string prefix; + InterfaceMetric updateS3Info; InterfaceMetric mountFs; InterfaceMetric umountFs; InterfaceMetric getFsInfo; @@ -61,6 +62,7 @@ struct MDSClientMetric { MDSClientMetric() : mountFs(prefix, "mountFs"), umountFs(prefix, "umountFs"), + updateS3Info(prefix, "updateS3Info"), getFsInfo(prefix, "getFsInfo"), getMetaServerInfo(prefix, "getMetaServerInfo"), getMetaServerListInCopysets(prefix, "getMetaServerListInCopysets"), diff --git a/curvefs/src/client/rpcclient/base_client.cpp b/curvefs/src/client/rpcclient/base_client.cpp index b479cf1fe8..19b1a2d49a 100644 --- a/curvefs/src/client/rpcclient/base_client.cpp +++ b/curvefs/src/client/rpcclient/base_client.cpp @@ -36,7 +36,7 @@ void MDSBaseClient::UpdateS3Info(const std::string& fsName, brpc::Channel* channel) { UpdateS3InfoRequest request; request.set_fsname(fsName); - request.set_s3Info(s3Info); + request.mutable_s3info()->CopyFrom(s3Info); curvefs::mds::MdsService_Stub stub(channel); stub.UpdateS3Info(cntl, &request, response, nullptr); } diff --git a/curvefs/src/client/rpcclient/base_client.h b/curvefs/src/client/rpcclient/base_client.h index 27d2e15620..f37e9f7d57 100644 --- a/curvefs/src/client/rpcclient/base_client.h +++ b/curvefs/src/client/rpcclient/base_client.h @@ -76,6 +76,8 @@ using curvefs::mds::FsInfo; using curvefs::mds::FsStatus; using curvefs::mds::GetFsInfoRequest; using curvefs::mds::GetFsInfoResponse; +using curvefs::mds::UpdateS3InfoRequest; +using curvefs::mds::UpdateS3InfoResponse; using curvefs::mds::MountFsRequest; using curvefs::mds::MountFsResponse; using curvefs::mds::GetLatestTxIdRequest; diff --git a/curvefs/src/client/rpcclient/mds_client.cpp b/curvefs/src/client/rpcclient/mds_client.cpp index d28b09c79f..596c4af3fd 100644 --- a/curvefs/src/client/rpcclient/mds_client.cpp +++ b/curvefs/src/client/rpcclient/mds_client.cpp @@ -65,13 +65,13 @@ FSStatusCode MdsClientImpl::UpdateS3Info(const std::string& fsName, auto task = RPCTask { (void)addrindex; (void)rpctimeoutMS; - mdsClientMetric_.mountFs.qps.count << 1; - LatencyUpdater updater(&mdsClientMetric_.mountFs.latency); + mdsClientMetric_.updateS3Info.qps.count << 1; + LatencyUpdater updater(&mdsClientMetric_.updateS3Info.latency); UpdateS3InfoResponse response; mdsbasecli_->UpdateS3Info(fsName, s3Info, &response, cntl, channel); if (cntl->Failed()) { - mdsClientMetric_.mountFs.eps.count << 1; - LOG(WARNING) << "MountFs Failed, errorcode = " << cntl->ErrorCode() + mdsClientMetric_.updateS3Info.eps.count << 1; + LOG(WARNING) << "UpdateS3Info Failed, errorcode = " << cntl->ErrorCode() << ", error content:" << cntl->ErrorText() << ", log id = " << cntl->log_id(); return -cntl->ErrorCode(); @@ -80,7 +80,7 @@ FSStatusCode MdsClientImpl::UpdateS3Info(const std::string& fsName, FSStatusCode ret = response.statuscode(); if (ret != FSStatusCode::OK) { LOG(WARNING) << "UpdateS3Info: fsname = " << fsName - << ", mountPt = " << mountPt.ShortDebugString() + << ", s3Info = " << s3Info.ShortDebugString() << ", errcode = " << ret << ", errmsg = " << FSStatusCode_Name(ret); } else if (response.has_fsinfo()) { diff --git a/curvefs/src/client/rpcclient/mds_client.h b/curvefs/src/client/rpcclient/mds_client.h index 1d19644f46..e7503d6c30 100644 --- a/curvefs/src/client/rpcclient/mds_client.h +++ b/curvefs/src/client/rpcclient/mds_client.h @@ -60,6 +60,7 @@ namespace curvefs { namespace client { namespace rpcclient { +using curvefs::common::S3Info; using curvefs::mds::GetLatestTxIdRequest; using curvefs::mds::GetLatestTxIdResponse; using curvefs::mds::CommitTxRequest; @@ -76,7 +77,7 @@ class MdsClient { MDSBaseClient *baseclient) = 0; virtual FSStatusCode UpdateS3Info(const std::string& fsName, - const curvefs::common::S3Info& s3Info, FsInfo* fsInfo) = 0; + const S3Info& s3Info, FsInfo* fsInfo) = 0; virtual FSStatusCode MountFs(const std::string& fsName, const Mountpoint& mountPt, FsInfo* fsInfo) = 0; @@ -174,7 +175,7 @@ class MdsClientImpl : public MdsClient { FSStatusCode Init(const ::curve::client::MetaServerOption &mdsOpt, MDSBaseClient *baseclient) override; - FSStatusCode UpdateS3Info(const std::string& fsName, const curvefs::common::S3Info& s3Info, + FSStatusCode UpdateS3Info(const std::string& fsName, const S3Info& s3Info, FsInfo* fsInfo) override; FSStatusCode MountFs(const std::string& fsName, const Mountpoint& mountPt, diff --git a/curvefs/src/client/s3/client_s3.cpp b/curvefs/src/client/s3/client_s3.cpp index 9b329aefa1..9bceb25b8c 100644 --- a/curvefs/src/client/s3/client_s3.cpp +++ b/curvefs/src/client/s3/client_s3.cpp @@ -28,6 +28,10 @@ void S3ClientImpl::Init(const curve::common::S3AdapterOption &option) { s3Adapter_->Init(option); } +void S3ClientImpl::Reinit(const curve::common::S3AdapterOption &option) { + s3Adapter_->Reinit(option); +} + void S3ClientImpl::Deinit() { s3Adapter_->Deinit(); } diff --git a/curvefs/src/client/s3/client_s3.h b/curvefs/src/client/s3/client_s3.h index 301670a2fa..3fb626c683 100644 --- a/curvefs/src/client/s3/client_s3.h +++ b/curvefs/src/client/s3/client_s3.h @@ -41,6 +41,7 @@ class S3Client { S3Client() {} virtual ~S3Client() {} virtual void Init(const curve::common::S3AdapterOption& option) = 0; + virtual void Reinit(const curve::common::S3AdapterOption& option) = 0; virtual void Deinit() = 0; virtual int Upload(const std::string& name, const char* buf, uint64_t length) = 0; @@ -65,6 +66,7 @@ class S3ClientImpl : public S3Client { } virtual ~S3ClientImpl() {} void Init(const curve::common::S3AdapterOption& option); + void Reinit(const curve::common::S3AdapterOption& option); void Deinit(); int Upload(const std::string& name, const char* buf, uint64_t length); void UploadAsync(std::shared_ptr context); diff --git a/curvefs/src/mds/fs_info_wrapper.h b/curvefs/src/mds/fs_info_wrapper.h index 7de3263460..a4db99c7f7 100644 --- a/curvefs/src/mds/fs_info_wrapper.h +++ b/curvefs/src/mds/fs_info_wrapper.h @@ -35,6 +35,7 @@ namespace curvefs { namespace mds { using ::curvefs::common::FSType; +using ::curvefs::common::S3Info; // A wrapper for proto FsInfo class FsInfoWrapper { @@ -67,8 +68,8 @@ class FsInfoWrapper { } void SetS3Info(S3Info s3info) { - const FsDetail fsdetail_ = GetFsDetail(); - fsdetail_._set_s3info(s3info) + FsDetail* fsdetail_ = fsInfo_.mutable_detail(); + fsdetail_->mutable_s3info()->CopyFrom(s3info); } void SetFsName(const std::string& name) { diff --git a/curvefs/src/mds/fs_manager.cpp b/curvefs/src/mds/fs_manager.cpp index 913ac29644..060bef10fd 100644 --- a/curvefs/src/mds/fs_manager.cpp +++ b/curvefs/src/mds/fs_manager.cpp @@ -599,7 +599,7 @@ FSStatusCode FsManager::DeleteFs(const std::string& fsName) { } FSStatusCode FsManager::UpdateS3Info(const std::string& fsName, - const curvefs::common::S3Info& s3Info, FsInfo* fsInfo) { + const S3Info& s3Info, FsInfo* fsInfo) { NameLockGuard lock(nameLock_, fsName); // query fs @@ -611,21 +611,18 @@ FSStatusCode FsManager::UpdateS3Info(const std::string& fsName, return ret; } - // insert mountpoint + // update s3Info wrapper.SetS3Info(s3Info); // for persistence consider ret = fsStorage_->Update(wrapper); if (ret != FSStatusCode::OK) { LOG(WARNING) << "UpdateS3Info fail, update fs fail, fsName = " << fsName - << ", mountpoint = " << mountpoint.ShortDebugString() + << ", s3Info = " << s3Info.ShortDebugString() << ", errCode = " << FSStatusCode_Name(ret); return ret; } - // update client alive time - UpdateClientAliveTime(mountpoint, fsName, false); // convert fs info - FsMetric::GetInstance().OnMount(wrapper.GetFsName(), mountpoint); *fsInfo = std::move(wrapper).ProtoFsInfo(); return FSStatusCode::OK; diff --git a/curvefs/src/mds/fs_manager.h b/curvefs/src/mds/fs_manager.h index dc6b21ef31..9d25a25fe8 100644 --- a/curvefs/src/mds/fs_manager.h +++ b/curvefs/src/mds/fs_manager.h @@ -62,10 +62,11 @@ using ::curve::common::Atomic; using ::curve::common::InterruptibleSleeper; using ::curve::common::S3Adapter; using ::curve::common::Thread; + +using ::curvefs::common::S3Info; using ::curvefs::mds::topology::PartitionTxId; using ::curvefs::mds::topology::Topology; using ::curvefs::mds::topology::TopologyManager; - using ::curvefs::mds::dlock::DLock; using ::curvefs::mds::Mountpoint; @@ -130,7 +131,7 @@ class FsManager { * */ FSStatusCode UpdateS3Info(const std::string& fsName, - const Mountpoint& mountpoint, FsInfo* fsInfo); + const S3Info& mountpoint, FsInfo* fsInfo); /** * @brief Mount fs, mount point can not repeat. It will increate diff --git a/curvefs/src/mds/mds_service.cpp b/curvefs/src/mds/mds_service.cpp index 82faa44bc7..2f3bda28c5 100644 --- a/curvefs/src/mds/mds_service.cpp +++ b/curvefs/src/mds/mds_service.cpp @@ -149,8 +149,8 @@ void MdsServiceImpl::UpdateS3Info(::google::protobuf::RpcController* controller, const std::string &fsName = request->fsname(); const curvefs::common::S3Info &s3Info = request->s3info(); - LOG(INFO) << "MountFs request, fsName = " << fsName - << ", mountPoint = " << mount.ShortDebugString(); + LOG(INFO) << "UpdateS3Info request, fsName = " << fsName + << ", s3Info = " << s3Info.ShortDebugString(); FSStatusCode status = fsManager_->UpdateS3Info(fsName, s3Info, response->mutable_fsinfo()); @@ -159,15 +159,15 @@ void MdsServiceImpl::UpdateS3Info(::google::protobuf::RpcController* controller, response->clear_fsinfo(); response->set_statuscode(status); LOG(ERROR) << "UpdateS3Info fail, fsName = " << fsName - << ", mountPoint = " << mount.ShortDebugString() + << ", s3Info = " << s3Info.ShortDebugString() << ", errCode = " << FSStatusCode_Name(status); return; } response->set_statuscode(FSStatusCode::OK); LOG(INFO) << "UpdateS3Info success, fsName = " << fsName - << ", mountPoint = " << mount.ShortDebugString() - << ", mps: " << response->mutable_fsinfo()->mountpoints_size(); + << ", s3Info in response = " << response->fsinfo().detail().s3info().ShortDebugString() + << ", mps = " << response->mutable_fsinfo()->mountpoints_size(); } void MdsServiceImpl::MountFs(::google::protobuf::RpcController* controller, diff --git a/curvefs/src/mds/mds_service.h b/curvefs/src/mds/mds_service.h index dbcfaaf6f4..7d01de2a0d 100644 --- a/curvefs/src/mds/mds_service.h +++ b/curvefs/src/mds/mds_service.h @@ -50,6 +50,11 @@ class MdsServiceImpl : public MdsService { CreateFsResponse* response, ::google::protobuf::Closure* done); + void UpdateS3Info(::google::protobuf::RpcController* controller, + const UpdateS3InfoRequest* request, + UpdateS3InfoResponse* response, + ::google::protobuf::Closure* done); + void MountFs(::google::protobuf::RpcController* controller, const MountFsRequest* request, MountFsResponse* response, diff --git a/curvefs/test/client/mock_client_s3.h b/curvefs/test/client/mock_client_s3.h index 5588fd73c5..938049cc73 100644 --- a/curvefs/test/client/mock_client_s3.h +++ b/curvefs/test/client/mock_client_s3.h @@ -41,6 +41,7 @@ class MockS3Client : public S3Client { ~MockS3Client() {} MOCK_METHOD1(Init, void(const curve::common::S3AdapterOption &options)); + MOCK_METHOD1(Reinit, void(const curve::common::S3AdapterOption &options)); MOCK_METHOD0(Deinit, void()); MOCK_METHOD3(Upload, int(const std::string &name, const char *buf, uint64_t length)); diff --git a/curvefs/test/client/rpcclient/mock_mds_client.h b/curvefs/test/client/rpcclient/mock_mds_client.h index c77a2296cc..72443afb9a 100644 --- a/curvefs/test/client/rpcclient/mock_mds_client.h +++ b/curvefs/test/client/rpcclient/mock_mds_client.h @@ -50,6 +50,10 @@ class MockMdsClient : public MdsClient { FSStatusCode(const ::curve::client::MetaServerOption& mdsOpt, MDSBaseClient* baseclient)); + MOCK_METHOD3(UpdateS3Info, + FSStatusCode(const std::string& fsName, + const S3Info& s3Info, FsInfo* fsInfo)); + MOCK_METHOD3(MountFs, FSStatusCode(const std::string& fsName, const Mountpoint& mountPt, FsInfo* fsInfo)); diff --git a/tools-v2/pkg/cli/command/curvefs/update/s3info/s3info.go b/tools-v2/pkg/cli/command/curvefs/update/s3info/s3info.go new file mode 100644 index 0000000000..c1b8308654 --- /dev/null +++ b/tools-v2/pkg/cli/command/curvefs/update/s3info/s3info.go @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2022 NetEase Inc. + * + * Licensed 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. + */ + +/* + * Project: CurveCli + * Created Date: 2024-01-24 + * Author: ken90242 (Ken Han) + */ + + package s3info + + import ( + "errors" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + + basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" + cmderror "github.com/opencurve/curve/tools-v2/internal/error" + cobrautil "github.com/opencurve/curve/tools-v2/internal/utils" + mountinfo "github.com/cilium/cilium/pkg/mountinfo" + + "github.com/opencurve/curve/tools-v2/pkg/config" + "github.com/opencurve/curve/tools-v2/pkg/output" + "github.com/spf13/cobra" + "golang.org/x/sys/unix" + ) + + const ( + updateS3InfoExample = `$ curve fs update s3info /mnt/test --s3.ak=ak` + ) + + const ( + CURVEFS_S3_UPDATE_CONFIG_XATTR = "curvefs.s3.update.config" + ) + + type S3InfoObj struct { + AK string `json:"ak"` + SK string `json:"sk"` + Endpoint string `json:"endpoint"` + Bucketname string `json:"bucketname"` +} + + type UpdateS3InfoCommand struct { + basecmd.FinalCurveCmd + CtrlFilePath string // path in user system + MountpointInfo *mountinfo.MountInfo + S3InfoByte []byte + } + + var _ basecmd.FinalCurveCmdFunc = (*UpdateS3InfoCommand)(nil) + + func fileNotExists(filePath string) bool { + _, err := os.Stat(filePath) + return os.IsNotExist(err) +} + + func NewUpdateS3InfoCommand() *UpdateS3InfoCommand { + uCmd := &UpdateS3InfoCommand{ + FinalCurveCmd: basecmd.FinalCurveCmd{ + Use: "s3info", + Short: "update s3 info for both MDS and Fuse client", + Example: updateS3InfoExample, + }, + } + basecmd.NewFinalCurveCli(&uCmd.FinalCurveCmd, uCmd) + return uCmd + } + + func NewUpdateCommand() *cobra.Command { + return NewUpdateS3InfoCommand().Cmd + } + + func (uCmd *UpdateS3InfoCommand) AddFlags() { + config.AddS3AkOptionFlag(uCmd.Cmd) + config.AddS3SkOptionFlag(uCmd.Cmd) + config.AddS3EndpointOptionFlag(uCmd.Cmd) + config.AddS3BucknameOptionFlag(uCmd.Cmd) + } + + func (uCmd *UpdateS3InfoCommand) Init(cmd *cobra.Command, args []string) error { + // check args + ak := config.GetS3AkOptionFlag(uCmd.Cmd) + sk := config.GetS3SkOptionFlag(uCmd.Cmd) + endpoint := config.GetS3EndpointOptionFlag(uCmd.Cmd) + bucketName := config.GetS3BucknameOptionFlag(uCmd.Cmd) + + if len(args) == 0 { + return fmt.Errorf("no mountpath has been specified") + } + + // check has curvefs mountpoint + mountpoints, err := cobrautil.GetCurveFSMountPoints() + if err.TypeCode() != cmderror.CODE_SUCCESS { + return err.ToError() + } else if len(mountpoints) == 0 { + return errors.New("no curvefs mountpoint has been found") + } + + absPath, _ := filepath.Abs(args[0]) + uCmd.CtrlFilePath = "" + for _, mountpointInfo := range mountpoints { + rel, err := filepath.Rel(mountpointInfo.MountPoint, absPath) + if err == nil && !strings.HasPrefix(rel, "..") { + // found the mountpoint + if uCmd.MountpointInfo == nil || + len(uCmd.MountpointInfo.MountPoint) < len(mountpointInfo.MountPoint) { + // Prevent the curvefs directory from being mounted under the curvefs directory + // /a/b/c: + // test-1 mount in /a + // test-1 mount in /a/b + // warmup /a/b/c. + uCmd.CtrlFilePath = fmt.Sprintf("%s/%s", absPath, config.CURVEFS_CTRL_FILE) + } + } + } + + s3Info := S3InfoObj{ + AK: ak, + SK: sk, + Endpoint: endpoint, + Bucketname: bucketName, + } + + jsonData, errStr := json.Marshal(s3Info) + // Serialize the S3InfoObj struct to JSON bytes + if errStr != nil { + convertErr := cmderror.ErrSetxattr() + convertErr.Format(CURVEFS_S3_UPDATE_CONFIG_XATTR, err) + return convertErr.ToError() + } + + uCmd.S3InfoByte = make([]byte, len(jsonData)) + copy(uCmd.S3InfoByte, jsonData) + + return nil + } + + func (uCmd *UpdateS3InfoCommand) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutput(&uCmd.FinalCurveCmd, uCmd) + } + + func (uCmd *UpdateS3InfoCommand) RunCommand(cmd *cobra.Command, args []string) error { + var createFileErr error + var file *os.File + createFileErr = nil + if fileNotExists(uCmd.CtrlFilePath) { + file, createFileErr = os.Create(uCmd.CtrlFilePath) + } + + if createFileErr != nil { + return fmt.Errorf("there was an error creating temporary control file: %s", createFileErr) + } + + defer file.Close() + + err := unix.Setxattr(uCmd.CtrlFilePath, CURVEFS_S3_UPDATE_CONFIG_XATTR, uCmd.S3InfoByte, 0) + if err == unix.ENOTSUP || err == unix.EOPNOTSUPP { + return fmt.Errorf("filesystem does not support extended attributes") + } else if err != nil { + setErr := cmderror.ErrSetxattr() + setErr.Format(CURVEFS_S3_UPDATE_CONFIG_XATTR, err.Error()) + return setErr.ToError() + } + + fmt.Println("s3 info is updated.") + + return nil + } + + func (uCmd *UpdateS3InfoCommand) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&uCmd.FinalCurveCmd) + } + \ No newline at end of file diff --git a/tools-v2/pkg/cli/command/curvefs/update/update.go b/tools-v2/pkg/cli/command/curvefs/update/update.go index 5882a195b4..b968b0e665 100644 --- a/tools-v2/pkg/cli/command/curvefs/update/update.go +++ b/tools-v2/pkg/cli/command/curvefs/update/update.go @@ -20,6 +20,7 @@ import ( basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvefs/update/fs" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvefs/update/mds" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvefs/update/s3info" "github.com/spf13/cobra" ) @@ -33,6 +34,7 @@ func (updateCmd *UpdateCommand) AddSubCommands() { updateCmd.Cmd.AddCommand( fs.NewFsCommand(), mds.NewMdsCommand(), + s3info.NewUpdateCommand(), ) } diff --git a/tools-v2/pkg/config/fs.go b/tools-v2/pkg/config/fs.go index 15af464ade..5b0a1ff7bb 100644 --- a/tools-v2/pkg/config/fs.go +++ b/tools-v2/pkg/config/fs.go @@ -33,6 +33,7 @@ import ( const ( // curvefs + CURVEFS_CTRL_FILE = "__ctrl_file__.tmp" CURVEFS_MDSADDR = "mdsaddr" VIPER_CURVEFS_MDSADDR = "curvefs.mdsAddr" CURVEFS_MDSDUMMYADDR = "mdsdummyaddr" @@ -658,21 +659,37 @@ func AddS3AkOptionFlag(cmd *cobra.Command) { AddStringOptionFlag(cmd, CURVEFS_S3_AK, "s3 ak") } +func GetS3AkOptionFlag(cmd *cobra.Command) string { + return GetFlagString(cmd, CURVEFS_S3_AK) +} + // S3.Sk [option] func AddS3SkOptionFlag(cmd *cobra.Command) { AddStringOptionFlag(cmd, CURVEFS_S3_SK, "s3 sk") } +func GetS3SkOptionFlag(cmd *cobra.Command) string { + return GetFlagString(cmd, CURVEFS_S3_SK) +} + // S3.Endpoint [option] func AddS3EndpointOptionFlag(cmd *cobra.Command) { AddStringOptionFlag(cmd, CURVEFS_S3_ENDPOINT, "s3 endpoint") } +func GetS3EndpointOptionFlag(cmd *cobra.Command) string { + return GetFlagString(cmd, CURVEFS_S3_ENDPOINT) +} + // S3.Buckname [option] func AddS3BucknameOptionFlag(cmd *cobra.Command) { AddStringOptionFlag(cmd, CURVEFS_S3_BUCKETNAME, "s3 buckname") } +func GetS3BucknameOptionFlag(cmd *cobra.Command) string { + return GetFlagString(cmd, CURVEFS_S3_BUCKETNAME) +} + // S3.Blocksize [option] func AddS3BlocksizeOptionFlag(cmd *cobra.Command) { AddStringOptionFlag(cmd, CURVEFS_S3_BLOCKSIZE, "s3 blocksize")