From 43a8e18b18d373c87ea50245d200e8b708b8538d Mon Sep 17 00:00:00 2001 From: yangpeng Date: Mon, 25 Dec 2023 12:08:02 +0800 Subject: [PATCH] add bucket archive direct read api --- lib/bucket_archive_direct_read.go | 267 +++++++++++++++++++++++++ lib/bucket_archive_direct_read_test.go | 207 +++++++++++++++++++ lib/command.go | 1 + 3 files changed, 475 insertions(+) create mode 100644 lib/bucket_archive_direct_read.go create mode 100644 lib/bucket_archive_direct_read_test.go diff --git a/lib/bucket_archive_direct_read.go b/lib/bucket_archive_direct_read.go new file mode 100644 index 00000000..ace355f3 --- /dev/null +++ b/lib/bucket_archive_direct_read.go @@ -0,0 +1,267 @@ +package lib + +import ( + "fmt" + "github.com/aliyun/aliyun-oss-go-sdk/oss" + "io/ioutil" + "os" + "strings" +) + +var specChineseBucketArchiveDirectRead = SpecText{ + synopsisText: "设置、查询bucket的archive direct read配置", + paramText: "bucket_url local_xml_file [options]", + + syntaxText: ` + ossutil archive-direct-read --method put oss://bucket local_xml_file [options] + ossutil archive-direct-read --method get oss://bucket [local_xml_file] [options] +`, + detailHelpText: ` + archive-direct-read命令通过设置method选项值为put、get,可以设置、查询bucket的archive direct read配置 + +用法: + 该命令有二种用法: + + 1) ossutil archive-direct-read --method put oss://bucket local_xml_file [options] + 这个命令从配置文件local_xml_file中读取archive direct read配置,然后设置bucket的archive direct read规则 + 配置文件是一个xml格式的文件,下面是一个所有规则的例子 + + + + true + + + 2) ossutil archive-direct-read --method get oss://bucket [local_xml_file] [options] + 这个命令查询bucket的archive direct read配置 + 如果输入参数local_xml_file,archive direct read配置将输出到该文件,否则输出到屏幕上 + +`, + sampleText: ` + 1) 设置bucket的archive direct read配置 + ossutil archive-direct-read --method put oss://bucket local_xml_file + + 2) 查询bucket的archive direct read配置,结果输出到标准输出 + ossutil archive-direct-read --method get oss://bucket + + 3) 查询bucket的archive direct read配置,结果输出到本地文件 + ossutil archive-direct-read --method get oss://bucket local_xml_file +`, +} + +var specEnglishBucketArchiveDirectRead = SpecText{ + synopsisText: "Set, get bucket archive direct read configuration", + paramText: "bucket_url local_xml_file [options]", + + syntaxText: ` + ossutil archive-direct-read --method put oss://bucket local_xml_file [options] + ossutil archive-direct-read --method get oss://bucket [local_xml_file] [options] +`, + + detailHelpText: ` + archive-direct-read command can set, get the archive direct read configuration of the oss bucket by + set method option value to put, get + +Usage: + 1) ossutil archive-direct-read --method put oss://bucket local_xml_file [options] + The command sets the lifecycle configuration of bucket from local file local_xml_file + the local_xml_file is xml format, you can choose to configure only some rules + The following is an example of all rules: + + + + true + + + 2) ossutil archive-direct-read --method get oss://bucket [local_xml_file] [options] + The command gets the archive direct read configuration of bucket + If you input parameter local_xml_file,the configuration will be output to local_xml_file + If you don't input parameter local_xml_file,the configuration will be output to stdout +`, + + sampleText: ` + 1) put bucket archive direct read + ossutil archive-direct-read --method put oss://bucket local_xml_file + + 2) get bucket archive direct read configuration to stdout + ossutil archive-direct-read --method get oss://bucket + + 3) get bucket archive direct read configuration to local file + ossutil archive-direct-read --method get oss://bucket local_xml_file +`, +} + +type bucketArchiveDirectReadOptionType struct { + bucketName string +} + +type BucketArchiveDirectReadCommand struct { + command Command + blOption bucketArchiveDirectReadOptionType +} + +var bucketArchiveDirectReadCommand = BucketArchiveDirectReadCommand{ + command: Command{ + name: "archive-direct-read", + nameAlias: []string{"archive-direct-read"}, + minArgc: 1, + maxArgc: 2, + specChinese: specChineseBucketArchiveDirectRead, + specEnglish: specEnglishBucketArchiveDirectRead, + group: GroupTypeNormalCommand, + validOptionNames: []string{ + OptionConfigFile, + OptionEndpoint, + OptionAccessKeyID, + OptionAccessKeySecret, + OptionSTSToken, + OptionProxyHost, + OptionProxyUser, + OptionProxyPwd, + OptionLogLevel, + OptionMethod, + OptionPassword, + OptionMode, + OptionECSRoleName, + OptionTokenTimeout, + OptionRamRoleArn, + OptionRoleSessionName, + OptionReadTimeout, + OptionConnectTimeout, + OptionSTSRegion, + OptionSkipVerifyCert, + OptionUserAgent, + OptionSignVersion, + OptionRegion, + OptionCloudBoxID, + }, + }, +} + +// function for FormatHelper interface +func (badr *BucketArchiveDirectReadCommand) formatHelpForWhole() string { + return badr.command.formatHelpForWhole() +} + +func (badr *BucketArchiveDirectReadCommand) formatIndependHelp() string { + return badr.command.formatIndependHelp() +} + +// Init simulate inheritance, and polymorphism +func (badr *BucketArchiveDirectReadCommand) Init(args []string, options OptionMapType) error { + return badr.command.Init(args, options, badr) +} + +// RunCommand simulate inheritance, and polymorphism +func (badr *BucketArchiveDirectReadCommand) RunCommand() error { + strMethod, _ := GetString(OptionMethod, badr.command.options) + if strMethod == "" { + return fmt.Errorf("--method value is empty") + } + + strMethod = strings.ToLower(strMethod) + if strMethod != "put" && strMethod != "get" && strMethod != "delete" { + return fmt.Errorf("--method value is not in the optional value:put|get|delete") + } + + srcBucketUrL, err := GetCloudUrl(badr.command.args[0], "") + if err != nil { + return err + } + + badr.blOption.bucketName = srcBucketUrL.bucket + + switch strMethod { + case "put": + err = badr.PutBucketArchiveDirectRead() + case "get": + err = badr.GetBucketArchiveDirectRead() + } + return err +} + +func (badr *BucketArchiveDirectReadCommand) PutBucketArchiveDirectRead() error { + if len(badr.command.args) < 2 { + return fmt.Errorf("put bucket archive direct read need at least 2 parameters,the local xml file is empty") + } + + xmlFile := badr.command.args[1] + fileInfo, err := os.Stat(xmlFile) + if err != nil { + return err + } + + if fileInfo.IsDir() { + return fmt.Errorf("%s is dir,not the expected file", xmlFile) + } + + if fileInfo.Size() == 0 { + return fmt.Errorf("%s is empty file", xmlFile) + } + + // parsing the xml file + file, err := os.Open(xmlFile) + if err != nil { + return err + } + defer file.Close() + xmlBody, err := ioutil.ReadAll(file) + if err != nil { + return err + } + + // put bucket lifecycle + client, err := badr.command.ossClient(badr.blOption.bucketName) + if err != nil { + return err + } + + options := []oss.Option{oss.AllowSameActionOverLap(true)} + return client.PutBucketArchiveDirectReadXml(badr.blOption.bucketName, string(xmlBody), options...) +} + +func (badr *BucketArchiveDirectReadCommand) confirm(str string) bool { + var val string + fmt.Printf(getClearStr(fmt.Sprintf("bucket archive direct read: overwrite \"%s\"(y or N)? ", str))) + if _, err := fmt.Scanln(&val); err != nil || (strings.ToLower(val) != "yes" && strings.ToLower(val) != "y") { + return false + } + return true +} + +func (badr *BucketArchiveDirectReadCommand) GetBucketArchiveDirectRead() error { + client, err := badr.command.ossClient(badr.blOption.bucketName) + if err != nil { + return err + } + + output, err := client.GetBucketArchiveDirectReadXml(badr.blOption.bucketName) + if err != nil { + return err + } + + var outFile *os.File + if len(badr.command.args) >= 2 { + fileName := badr.command.args[1] + _, err = os.Stat(fileName) + if err == nil { + bConitnue := badr.confirm(fileName) + if !bConitnue { + return nil + } + } + + outFile, err = os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0660) + if err != nil { + return err + } + defer outFile.Close() + } else { + outFile = os.Stdout + } + + outFile.Write([]byte(output)) + + fmt.Printf("\n\n") + + return nil +} diff --git a/lib/bucket_archive_direct_read_test.go b/lib/bucket_archive_direct_read_test.go new file mode 100644 index 00000000..b8348660 --- /dev/null +++ b/lib/bucket_archive_direct_read_test.go @@ -0,0 +1,207 @@ +package lib + +import ( + "encoding/xml" + "github.com/aliyun/aliyun-oss-go-sdk/oss" + . "gopkg.in/check.v1" + "os" +) + +func (s *OssutilCommandSuite) TestArchiveDirectReadHelpInfo(c *C) { + // mkdir command test + options := OptionMapType{} + + mkArgs := []string{"archive-direct-read"} + _, err := cm.RunCommand("help", mkArgs, options) + c.Assert(err, IsNil) + + mkArgs = []string{} + _, err = cm.RunCommand("help", mkArgs, options) + c.Assert(err, IsNil) +} + +func (s *OssutilCommandSuite) TestPutBucketArchiveDirectReadError(c *C) { + bucketName := bucketNamePrefix + randLowStr(12) + s.putBucket(bucketName, c) + + archiveFileName := "archive-direct-read" + randLowStr(12) + + strMethod := "" + options := OptionMapType{ + "endpoint": &endpoint, + "accessKeyID": &accessKeyID, + "accessKeySecret": &accessKeySecret, + "method": &strMethod, + } + + // method is empty + archiveArgs := []string{CloudURLToString(bucketName, ""), archiveFileName} + _, err := cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + + //method is error + strMethod = "puttt" + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + + // cloudurl is error + strMethod = "put" + archiveArgs = []string{"http://mybucket", archiveFileName} + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + + // local file is emtpy + archiveArgs = []string{CloudURLToString(bucketName, ""), archiveFileName} + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + + //local file is not exist + os.Remove(archiveFileName) + archiveArgs = []string{CloudURLToString(bucketName, ""), archiveFileName} + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + + // local file is dir + err = os.MkdirAll(archiveFileName, 0755) + c.Assert(err, IsNil) + archiveArgs = []string{CloudURLToString(bucketName, ""), archiveFileName} + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + os.Remove(archiveFileName) + + //local file is empty + s.createFile(archiveFileName, "", c) + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + os.Remove(archiveFileName) + + //local file is not xml file + s.createFile(archiveFileName, "aaa", c) + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + os.Remove(archiveFileName) + + // StorageURLFromString error + archiveArgs = []string{"oss:///1.jpg"} + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + + // bucketname is error + archiveArgs = []string{"oss:///"} + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + + //missing parameter + archiveArgs = []string{CloudURLToString(bucketName, "")} + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + + // bucketname not exist + archiveArgs = []string{CloudURLToString("my-bucket", "")} + _, err = cm.RunCommand("archive-direct-read", archiveArgs, options) + c.Assert(err, NotNil) + + os.Remove(archiveFileName) + s.removeBucket(bucketName, true, c) +} + +func (s *OssutilCommandSuite) TestPutBucketArchiveDirectRead(c *C) { + archiveXml := ` + + true +` + + archiveConfigSrc := oss.PutBucketArchiveDirectRead{} + err := xml.Unmarshal([]byte(archiveXml), &archiveConfigSrc) + c.Assert(err, IsNil) + + archiveFileName := randLowStr(12) + s.createFile(archiveFileName, archiveXml, c) + + bucketName := bucketNamePrefix + randLowStr(12) + s.putBucket(bucketName, c) + + strMethod := "put" + options := OptionMapType{ + "endpoint": &endpoint, + "accessKeyID": &accessKeyID, + "accessKeySecret": &accessKeySecret, + "method": &strMethod, + } + + testLogger.Println(endpoint) + + command := "archive-direct-read" + archiveArgs := []string{CloudURLToString(bucketName, ""), archiveFileName} + _, err = cm.RunCommand(command, archiveArgs, options) + c.Assert(err, IsNil) + + archiveDownName := archiveFileName + "-down" + strMethod = "get" + options[OptionMethod] = &strMethod + + archiveArgs = []string{CloudURLToString(bucketName, ""), archiveDownName} + _, err = cm.RunCommand(command, archiveArgs, options) + c.Assert(err, IsNil) + + _, err = os.Stat(archiveDownName) + c.Assert(err, IsNil) + + accessBody := s.readFile(archiveDownName, c) + + var out oss.GetBucketArchiveDirectReadResult + err = xml.Unmarshal([]byte(accessBody), &out) + c.Assert(err, IsNil) + + c.Assert(archiveConfigSrc.Enabled, Equals, out.Enabled) + + os.Remove(archiveFileName) + os.Remove(archiveDownName) + s.removeBucket(bucketName, true, c) +} + +func (s *OssutilCommandSuite) TestGetBucketArchiveDirectReadConfirm(c *C) { + bucketName := bucketNamePrefix + randLowStr(12) + s.putBucket(bucketName, c) + + archiveXml := ` + + true +` + + archiveFileName := inputFileName + randLowStr(5) + s.createFile(archiveFileName, archiveXml, c) + + strMethod := "put" + options := OptionMapType{ + "endpoint": &endpoint, + "accessKeyID": &accessKeyID, + "accessKeySecret": &accessKeySecret, + "method": &strMethod, + } + + command := "archive-direct-read" + archiveArgs := []string{CloudURLToString(bucketName, ""), archiveFileName} + _, err := cm.RunCommand(command, archiveArgs, options) + c.Assert(err, IsNil) + + archiveDownName := archiveFileName + "-down" + strMethod = "get" + options[OptionMethod] = &strMethod + + archiveArgs = []string{CloudURLToString(bucketName, ""), archiveDownName} + _, err = cm.RunCommand(command, archiveArgs, options) + c.Assert(err, IsNil) + + archiveArgs = []string{CloudURLToString(bucketName, ""), archiveDownName} + _, err = cm.RunCommand(command, archiveArgs, options) + c.Assert(err, IsNil) + + archiveArgs = []string{CloudURLToString(bucketName, "")} + _, err = cm.RunCommand(command, archiveArgs, options) + c.Assert(err, IsNil) + + os.Remove(archiveFileName) + os.Remove(archiveDownName) + s.removeBucket(bucketName, true, c) +} diff --git a/lib/command.go b/lib/command.go index 7777bb73..ae3a78cb 100644 --- a/lib/command.go +++ b/lib/command.go @@ -896,5 +896,6 @@ func GetAllCommands() []interface{} { &lcbCommand, &bucketAccessMonitorCommand, &bucketResourceGroupCommand, + &bucketArchiveDirectReadCommand, } }