diff --git a/lib/bucket_https_config.go b/lib/bucket_https_config.go new file mode 100644 index 00000000..7158f094 --- /dev/null +++ b/lib/bucket_https_config.go @@ -0,0 +1,288 @@ +package lib + +import ( + "encoding/xml" + "fmt" + "io/ioutil" + "os" + "strings" +) + +var specChineseHttpsConfig = SpecText{ + synopsisText: "设置、查询bucket的TLS版本设置", + + paramText: "bucket_url [local_xml_file] [options]", + + syntaxText: ` + ossutil https-config --method put oss://bucket local_xml_file + ossutil https-config --method get oss://bucket [local_xml_file] +`, + detailHelpText: ` + cors命令通过设置method选项值为put、get,可以设置、查询bucket的TLS版本设置 + +用法: + 该命令有两种用法: + + 1) ossutil https-config --method put oss://bucket local_xml_file + 这个命令从配置文件local_xml_file中读取TLS版本设置,然后设置bucket的TLS版本设置 + 配置文件是一个xml格式的文件,举例如下 + + + + + true + TLSv1.2 + TLSv1.3 + + + + 2) ossutil https-config --method get oss://bucket [local_xml_file] + 这个命令查询bucket的TLS版本设置 + 如果输入参数local_xml_file,TLS版本设置将输出到该文件,否则输出到屏幕上 +`, + sampleText: ` + 1) 设置bucket的TLS版本设置 + ossutil https-config --method put oss://bucket local_xml_file + + 2) 查询bucket的TLS版本设置,结果输出到标准输出 + ossutil https-config --method get oss://bucket + + 3) 查询bucket的TLS版本设置,结果输出到本地文件 + ossutil https-config --method get oss://bucket local_xml_file +`, +} + +var specEnglishHttpsConfig = SpecText{ + synopsisText: "Set, get or delete the https configuration of the oss bucket", + + paramText: "bucket_url [local_xml_file] [options]", + + syntaxText: ` + ossutil https-config --method put oss://bucket local_xml_file + ossutil https-config --method get oss://bucket [local_xml_file] +`, + detailHelpText: ` + cors command can set、get the https configuration of the oss bucket by + set method option value to put, get + +Usage: + There are two usages for this command: + + 1) ossutil https-config --method put oss://bucket local_xml_file + + The command sets the https configuration of bucket from local file local_xml_file + the local_xml_file is xml format + The following is an example of the contents of local_xml_file + + + + + true + TLSv1.2 + TLSv1.3 + + + + 2) ossutil https-config --method get oss://bucket [local_xml_file] + The command gets the https 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 https configuration + ossutil https-config --method put oss://bucket local_xml_file + + 2) get https configuration to stdout + ossutil https-config --method get oss://bucket + + 3) get https configuration to local file + ossutil https-config --method get oss://bucket local_xml_file +`, +} + +type httpsConfigOptionType struct { + bucketName string +} + +type HttpsConfigCommand struct { + command Command + hcOption httpsConfigOptionType +} + +var bucketHttpsConfigCommand = HttpsConfigCommand{ + command: Command{ + name: "https-config", + nameAlias: []string{"https-config"}, + minArgc: 1, + maxArgc: 2, + specChinese: specChineseHttpsConfig, + specEnglish: specEnglishHttpsConfig, + group: GroupTypeNormalCommand, + validOptionNames: []string{ + OptionConfigFile, + OptionEndpoint, + OptionAccessKeyID, + OptionAccessKeySecret, + OptionSTSToken, + OptionProxyHost, + OptionProxyUser, + OptionProxyPwd, + OptionMethod, + OptionLogLevel, + OptionPassword, + OptionMode, + OptionECSRoleName, + OptionTokenTimeout, + OptionRamRoleArn, + OptionRoleSessionName, + OptionReadTimeout, + OptionConnectTimeout, + OptionSTSRegion, + OptionSkipVerifyCert, + OptionUserAgent, + OptionSignVersion, + OptionRegion, + OptionCloudBoxID, + OptionForcePathStyle, + }, + }, +} + +// function for FormatHelper interface +func (hcc *HttpsConfigCommand) formatHelpForWhole() string { + return hcc.command.formatHelpForWhole() +} + +func (hcc *HttpsConfigCommand) formatIndependHelp() string { + return hcc.command.formatIndependHelp() +} + +// Init simulate inheritance, and polymorphism +func (hcc *HttpsConfigCommand) Init(args []string, options OptionMapType) error { + return hcc.command.Init(args, options, hcc) +} + +// RunCommand simulate inheritance, and polymorphism +func (hcc *HttpsConfigCommand) RunCommand() error { + strMethod, _ := GetString(OptionMethod, hcc.command.options) + if strMethod == "" { + return fmt.Errorf("--method value is empty") + } + strMethod = strings.ToLower(strMethod) + if strMethod != "put" && strMethod != "get" { + return fmt.Errorf("--method value is not in the optional value:put|get") + } + + bucketUrL, err := StorageURLFromString(hcc.command.args[0], "") + if err != nil { + return err + } + + if !bucketUrL.IsCloudURL() { + return fmt.Errorf("parameter is not a cloud url,url is %s", bucketUrL.ToString()) + } + + cloudUrl := bucketUrL.(CloudURL) + if cloudUrl.bucket == "" { + return fmt.Errorf("bucket name is empty,url is %s", bucketUrL.ToString()) + } + + hcc.hcOption.bucketName = cloudUrl.bucket + + if strMethod == "put" { + err = hcc.PutBucketHttpsConfig() + } else if strMethod == "get" { + err = hcc.GetBucketHttpsConfig() + } + if err != nil { + fmt.Printf("error:%s\n", err.Error()) + } + return err +} + +func (hcc *HttpsConfigCommand) PutBucketHttpsConfig() error { + if len(hcc.command.args) < 2 { + return fmt.Errorf("missing parameters,the local https config file is empty") + } + + httpsFile := hcc.command.args[1] + fileInfo, err := os.Stat(httpsFile) + if err != nil { + return err + } + + if fileInfo.IsDir() { + return fmt.Errorf("%s is dir,not the expected file", httpsFile) + } + + if fileInfo.Size() == 0 { + return fmt.Errorf("%s is empty file", httpsFile) + } + + // parsing the xml file + file, err := os.Open(httpsFile) + if err != nil { + return err + } + defer file.Close() + text, err := ioutil.ReadAll(file) + if err != nil { + return err + } + + // put bucket cors + client, err := hcc.command.ossClient(hcc.hcOption.bucketName) + if err != nil { + return err + } + + return client.PutBucketHttpsConfigXml(hcc.hcOption.bucketName, string(text)) +} + +func (hcc *HttpsConfigCommand) confirm(str string) bool { + var val string + fmt.Printf(getClearStr(fmt.Sprintf("https config: 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 (hcc *HttpsConfigCommand) GetBucketHttpsConfig() error { + client, err := hcc.command.ossClient(hcc.hcOption.bucketName) + if err != nil { + return err + } + + config, err := client.GetBucketHttpsConfig(hcc.hcOption.bucketName) + if err != nil { + return err + } + output, err := xml.MarshalIndent(config, "", " ") + if err != nil { + return err + } + var outFile *os.File + if len(hcc.command.args) >= 2 { + fileName := hcc.command.args[1] + _, err = os.Stat(fileName) + if err == nil { + bConitnue := hcc.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(xml.Header)) + outFile.Write(output) + fmt.Printf("\n\n") + return nil +} diff --git a/lib/bucket_https_config_test.go b/lib/bucket_https_config_test.go new file mode 100644 index 00000000..bdb45e81 --- /dev/null +++ b/lib/bucket_https_config_test.go @@ -0,0 +1,167 @@ +package lib + +import ( + "encoding/xml" + "github.com/aliyun/aliyun-oss-go-sdk/oss" + "os" + + . "gopkg.in/check.v1" +) + +func (s *OssutilCommandSuite) TestHttpsConfigPutSuccess(c *C) { + httpsXml := ` + + + true + TLSv1.2 + TLSv1.3 + +` + + httpsFileName := randLowStr(12) + s.createFile(httpsFileName, httpsXml, c) + + bucketName := bucketNamePrefix + randLowStr(12) + s.putBucket(bucketName, c) + + // https config command test + var str string + strMethod := "put" + options := OptionMapType{ + "endpoint": &str, + "accessKeyID": &str, + "accessKeySecret": &str, + "configFile": &configFile, + "method": &strMethod, + } + + httpsArgs := []string{CloudURLToString(bucketName, ""), httpsFileName} + _, err := cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, IsNil) + + // check,get cors + httpsDownName := httpsFileName + "-down" + strMethod = "get" + + httpsArgs = []string{CloudURLToString(bucketName, ""), httpsDownName} + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, IsNil) + + // check httpsDownName + _, err = os.Stat(httpsDownName) + c.Assert(err, IsNil) + + httpsBody := s.readFile(httpsDownName, c) + + httpsConfigDest := oss.GetBucketHttpsConfigResult{} + err = xml.Unmarshal([]byte(httpsBody), &httpsConfigDest) + c.Assert(err, IsNil) + c.Assert(httpsConfigDest.TLS.Enable, Equals, true) + c.Assert(httpsConfigDest.TLS.TLSVersion[0], Equals, "TLSv1.2") + c.Assert(httpsConfigDest.TLS.TLSVersion[1], Equals, "TLSv1.3") + os.Remove(httpsFileName) + os.Remove(httpsDownName) + s.removeBucket(bucketName, true, c) +} + +func (s *OssutilCommandSuite) TestHttpsConfigPutError(c *C) { + bucketName := bucketNamePrefix + randLowStr(12) + s.putBucket(bucketName, c) + + httpsFileName := "httpsFile-" + randLowStr(12) + + // cors command test + var str string + strMethod := "" + options := OptionMapType{ + "endpoint": &str, + "accessKeyID": &str, + "accessKeySecret": &str, + "configFile": &configFile, + "method": &strMethod, + } + + // method is empty + httpsArgs := []string{CloudURLToString(bucketName, ""), httpsFileName} + _, err := cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + + //method is error + strMethod = "puttt" + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + + // cloudurl is error + strMethod = "put" + httpsArgs = []string{"http://mybucket", httpsFileName} + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + + // local file is emtpy + httpsArgs = []string{CloudURLToString(bucketName, ""), httpsFileName} + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + + //local file is not exist + os.Remove(httpsFileName) + httpsArgs = []string{CloudURLToString(bucketName, ""), httpsFileName} + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + + // localfile is dir + err = os.MkdirAll(httpsFileName, 0755) + c.Assert(err, IsNil) + httpsArgs = []string{CloudURLToString(bucketName, ""), httpsFileName} + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + os.Remove(httpsFileName) + + //local file is emtpy + s.createFile(httpsFileName, "", c) + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + os.Remove(httpsFileName) + + //local file is not xml file + s.createFile(httpsFileName, "aaa", c) + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + os.Remove(httpsFileName) + + // StorageURLFromString error + httpsArgs = []string{"oss:///1.jpg"} + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + + // bucketname is error + httpsArgs = []string{"oss:///"} + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + + //missing parameter + httpsArgs = []string{CloudURLToString(bucketName, "")} + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + + // bucketname not exist + httpsArgs = []string{CloudURLToString("my-bucket", "")} + _, err = cm.RunCommand("https-config", httpsArgs, options) + c.Assert(err, NotNil) + + os.Remove(httpsFileName) + s.removeBucket(bucketName, true, c) +} + +func (s *OssutilCommandSuite) TestHttpsConfigHelpInfo(c *C) { + // mkdir command test + options := OptionMapType{} + + mkArgs := []string{"https-config"} + _, err := cm.RunCommand("help", mkArgs, options) + c.Assert(err, IsNil) + + mkArgs = []string{} + _, err = cm.RunCommand("help", mkArgs, options) + c.Assert(err, IsNil) + +} diff --git a/lib/command.go b/lib/command.go index 7777bb73..c9fe8977 100644 --- a/lib/command.go +++ b/lib/command.go @@ -896,5 +896,6 @@ func GetAllCommands() []interface{} { &lcbCommand, &bucketAccessMonitorCommand, &bucketResourceGroupCommand, + &bucketHttpsConfigCommand, } }