2020-11-16 10:09:35 +08:00
package shell
import (
"bytes"
"flag"
2020-11-16 12:15:47 +08:00
"fmt"
2020-11-16 10:09:35 +08:00
"io"
2023-04-05 13:07:17 +08:00
"regexp"
2020-11-17 11:57:08 +08:00
"strings"
2020-11-16 10:09:35 +08:00
2022-07-29 15:17:28 +08:00
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"github.com/seaweedfs/seaweedfs/weed/storage/super_block"
2020-11-16 10:09:35 +08:00
)
func init ( ) {
Commands = append ( Commands , & commandFsConfigure { } )
}
type commandFsConfigure struct {
}
func ( c * commandFsConfigure ) Name ( ) string {
return "fs.configure"
}
func ( c * commandFsConfigure ) Help ( ) string {
return ` configure and apply storage options for each location
2020-11-17 01:54:26 +08:00
# see the current configuration file content
2020-11-16 13:31:14 +08:00
fs . configure
# trying the changes and see the possible configuration file content
2021-07-12 13:51:21 +08:00
fs . configure - locationPrefix = / my / folder - collection = abc
fs . configure - locationPrefix = / my / folder - collection = abc - ttl = 7 d
2020-11-16 13:31:14 +08:00
2020-11-17 17:00:02 +08:00
# example : configure adding only 1 physical volume for each bucket collection
2021-07-12 13:51:21 +08:00
fs . configure - locationPrefix = / buckets / - volumeGrowthCount = 1
2020-11-17 17:00:02 +08:00
2020-11-16 13:31:14 +08:00
# apply the changes
2021-07-12 13:51:21 +08:00
fs . configure - locationPrefix = / my / folder - collection = abc - apply
2020-11-16 13:31:14 +08:00
# delete the changes
2021-07-12 13:51:21 +08:00
fs . configure - locationPrefix = / my / folder - delete - apply
2020-11-16 10:09:35 +08:00
`
}
func ( c * commandFsConfigure ) Do ( args [ ] string , commandEnv * CommandEnv , writer io . Writer ) ( err error ) {
fsConfigureCommand := flag . NewFlagSet ( c . Name ( ) , flag . ContinueOnError )
2020-11-16 12:15:47 +08:00
locationPrefix := fsConfigureCommand . String ( "locationPrefix" , "" , "path prefix, required to update the path-specific configuration" )
2020-11-16 13:16:28 +08:00
collection := fsConfigureCommand . String ( "collection" , "" , "assign writes to this collection" )
2020-11-16 10:09:35 +08:00
replication := fsConfigureCommand . String ( "replication" , "" , "assign writes with this replication" )
2023-04-05 13:07:17 +08:00
ttl := fsConfigureCommand . String ( "ttl" , "" , "assign writes with this ttl (e.g., 1m, 1h, 1d, 1w, 1y)" )
2021-02-22 18:03:12 +08:00
diskType := fsConfigureCommand . String ( "disk" , "" , "[hdd|ssd|<tag>] hard drive or solid state drive or any tag" )
2020-11-16 10:09:35 +08:00
fsync := fsConfigureCommand . Bool ( "fsync" , false , "fsync for the writes" )
2021-06-04 16:03:41 +08:00
isReadOnly := fsConfigureCommand . Bool ( "readOnly" , false , "disable writes" )
2024-09-17 12:02:21 +08:00
worm := fsConfigureCommand . Bool ( "worm" , false , "worm mode, If true, a file can only be changed once, after which it becomes readonly and undeletable, see https://en.wikipedia.org/wiki/Write_once_read_many" )
2023-10-13 05:29:55 +08:00
maxFileNameLength := fsConfigureCommand . Uint ( "maxFileNameLength" , 0 , "file name length limits in bytes for compatibility with Unix-based systems" )
2021-12-23 23:24:10 +08:00
dataCenter := fsConfigureCommand . String ( "dataCenter" , "" , "assign writes to this dataCenter" )
rack := fsConfigureCommand . String ( "rack" , "" , "assign writes to this rack" )
dataNode := fsConfigureCommand . String ( "dataNode" , "" , "assign writes to this dataNode" )
2020-11-17 17:00:02 +08:00
volumeGrowthCount := fsConfigureCommand . Int ( "volumeGrowthCount" , 0 , "the number of physical volumes to add if no writable volumes" )
2020-11-16 12:15:47 +08:00
isDelete := fsConfigureCommand . Bool ( "delete" , false , "delete the configuration by locationPrefix" )
2020-11-16 10:09:35 +08:00
apply := fsConfigureCommand . Bool ( "apply" , false , "update and apply filer configuration" )
if err = fsConfigureCommand . Parse ( args ) ; err != nil {
2022-04-29 11:19:36 +08:00
return nil
2020-11-16 10:09:35 +08:00
}
2021-10-11 18:03:56 +08:00
fc , err := filer . ReadFilerConf ( commandEnv . option . FilerAddress , commandEnv . option . GrpcDialOption , commandEnv . MasterClient )
2021-07-25 18:37:37 +08:00
if err != nil {
2020-11-16 10:09:35 +08:00
return err
}
if * locationPrefix != "" {
2022-06-01 05:48:46 +08:00
infoAboutSimulationMode ( writer , * apply , "-apply" )
2020-11-16 10:09:35 +08:00
locConf := & filer_pb . FilerConf_PathConf {
2020-11-17 17:00:02 +08:00
LocationPrefix : * locationPrefix ,
Collection : * collection ,
Replication : * replication ,
Ttl : * ttl ,
Fsync : * fsync ,
2023-10-13 05:29:55 +08:00
MaxFileNameLength : uint32 ( * maxFileNameLength ) ,
2020-12-14 03:59:32 +08:00
DiskType : * diskType ,
2020-11-17 17:00:02 +08:00
VolumeGrowthCount : uint32 ( * volumeGrowthCount ) ,
2021-06-04 16:03:41 +08:00
ReadOnly : * isReadOnly ,
2021-12-23 23:24:10 +08:00
DataCenter : * dataCenter ,
Rack : * rack ,
DataNode : * dataNode ,
2024-09-17 12:02:21 +08:00
Worm : * worm ,
2020-11-16 10:09:35 +08:00
}
2020-11-17 17:00:02 +08:00
// check collection
2020-11-17 11:57:08 +08:00
if * collection != "" && strings . HasPrefix ( * locationPrefix , "/buckets/" ) {
2020-12-23 09:43:13 +08:00
return fmt . Errorf ( "one s3 bucket goes to one collection and not customizable" )
2020-11-17 11:57:08 +08:00
}
2020-11-17 17:00:02 +08:00
// check replication
if * replication != "" {
rp , err := super_block . NewReplicaPlacementFromString ( * replication )
if err != nil {
return fmt . Errorf ( "parse replication %s: %v" , * replication , err )
}
2020-11-27 03:22:30 +08:00
if * volumeGrowthCount % rp . GetCopyCount ( ) != 0 {
2022-09-16 17:43:49 +08:00
return fmt . Errorf ( "volumeGrowthCount %d should be divided by replication copy count %d" , * volumeGrowthCount , rp . GetCopyCount ( ) )
2020-11-17 17:00:02 +08:00
}
}
2023-04-05 13:07:17 +08:00
// check ttl
if * ttl != "" {
2023-04-11 03:24:38 +08:00
regex := "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[mhdwMy]$"
2023-04-05 13:07:17 +08:00
match , _ := regexp . MatchString ( regex , * ttl )
if ! match {
2023-04-11 03:24:38 +08:00
return fmt . Errorf ( "ttl should be of the following format [1 to 255][unit] (e.g., 5m, 2h, 180d, 1w, 2y)" )
2023-04-05 13:07:17 +08:00
}
}
2020-11-17 17:00:02 +08:00
// save it
2020-11-16 12:15:47 +08:00
if * isDelete {
fc . DeleteLocationConf ( * locationPrefix )
} else {
fc . AddLocationConf ( locConf )
}
2020-11-16 10:09:35 +08:00
}
2021-07-25 18:37:37 +08:00
var buf2 bytes . Buffer
fc . ToText ( & buf2 )
2020-11-16 12:15:47 +08:00
2021-07-25 18:37:37 +08:00
fmt . Fprintf ( writer , string ( buf2 . Bytes ( ) ) )
2020-11-16 13:48:17 +08:00
fmt . Fprintln ( writer )
2020-11-16 10:09:35 +08:00
if * apply {
2021-12-26 16:15:03 +08:00
if err = commandEnv . WithFilerClient ( false , func ( client filer_pb . SeaweedFilerClient ) error {
2021-07-25 18:37:37 +08:00
return filer . SaveInsideFiler ( client , filer . DirectoryEtcSeaweedFS , filer . FilerConfName , buf2 . Bytes ( ) )
2021-07-09 17:33:14 +08:00
} ) ; err != nil && err != filer_pb . ErrNotFound {
2020-11-16 12:15:47 +08:00
return err
}
2020-11-16 10:09:35 +08:00
}
return nil
}
2022-06-01 05:48:46 +08:00
func infoAboutSimulationMode ( writer io . Writer , forceMode bool , forceModeOption string ) {
if forceMode {
return
}
fmt . Fprintf ( writer , "Running in simulation mode. Use \"%s\" option to apply the changes.\n" , forceModeOption )
}