github.com/yandex-cloud/geesefs@v0.40.9/internal/cfg/flags.go (about) 1 // Copyright 2015 - 2017 Ka-Hing Cheung 2 // Copyright 2015 - 2017 Google Inc. All Rights Reserved. 3 // Copyright 2021 Yandex LLC 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package cfg 18 19 import ( 20 "io" 21 "os" 22 "runtime" 23 "strconv" 24 "strings" 25 "syscall" 26 "text/tabwriter" 27 "text/template" 28 "time" 29 30 "github.com/urfave/cli" 31 ) 32 33 const GEESEFS_VERSION = "0.40.9" 34 35 var flagCategories map[string]string 36 37 // Set up custom help text for goofys; in particular the usage section. 38 func filterCategory(flags []cli.Flag, category string) (ret []cli.Flag) { 39 for _, f := range flags { 40 if flagCategories[f.GetName()] == category { 41 ret = append(ret, f) 42 } 43 } 44 return 45 } 46 47 var VersionHash string 48 var FuseOptions string 49 50 func NewApp() (app *cli.App) { 51 cli.AppHelpTemplate = `NAME: 52 {{.Name}} - {{.Usage}} 53 54 USAGE: 55 {{.Name}} {{if .Flags}}[global options]{{end}} bucket[:prefix] mountpoint 56 {{if .Version}} 57 VERSION: 58 {{.Version}} 59 {{end}}{{if len .Authors}} 60 AUTHOR(S): 61 {{range .Authors}}{{ . }}{{end}} 62 {{end}}{{if .Commands}} 63 COMMANDS: 64 {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} 65 {{end}}{{end}}{{if .Flags}} 66 GLOBAL OPTIONS: 67 {{range category .Flags ""}}{{.}} 68 {{end}} 69 TUNING OPTIONS: 70 {{range category .Flags "tuning"}}{{.}} 71 {{end}} 72 S3 OPTIONS: 73 {{range category .Flags "aws"}}{{.}} 74 {{end}} 75 MISC OPTIONS: 76 {{range category .Flags "misc"}}{{.}} 77 {{end}}{{end}} 78 `+FuseOptions+`{{if .Copyright }}COPYRIGHT: 79 {{.Copyright}} 80 {{end}} 81 ` 82 83 uid, gid := MyUserAndGroup() 84 85 s3Default := (&S3Config{}).Init() 86 87 fsFlags := []cli.Flag{ 88 ///////////////////////// 89 // File system 90 ///////////////////////// 91 92 cli.StringSliceFlag{ 93 Name: "o", 94 Usage: "Additional system-specific mount options. Be careful!", 95 }, 96 97 cli.StringFlag{ 98 Name: "cache", 99 Usage: "Directory to use for data cache. (default: off)", 100 }, 101 102 cli.IntFlag{ 103 Name: "dir-mode", 104 Value: 0755, 105 Usage: "Permission bits for directories. (default: 0755)", 106 }, 107 108 cli.IntFlag{ 109 Name: "file-mode", 110 Value: 0644, 111 Usage: "Permission bits for files. (default: 0644)", 112 }, 113 114 cli.IntFlag{ 115 Name: "cache-file-mode", 116 Value: 0644, 117 Usage: "Permission bits for disk cache files. (default: 0644)", 118 }, 119 120 cli.IntFlag{ 121 Name: "uid", 122 Value: uid, 123 Usage: "UID owner of all inodes.", 124 }, 125 126 cli.IntFlag{ 127 Name: "gid", 128 Value: gid, 129 Usage: "GID owner of all inodes.", 130 }, 131 132 cli.IntFlag{ 133 Name: "setuid", 134 Value: uid, 135 Usage: "Drop root privileges and change to this user ID (defaults to --uid).", 136 }, 137 138 cli.IntFlag{ 139 Name: "setgid", 140 Value: gid, 141 Usage: "Drop root group and change to this group ID (defaults to --gid).", 142 }, 143 } 144 145 s3Flags := []cli.Flag{ 146 ///////////////////////// 147 // S3 148 ///////////////////////// 149 150 cli.StringFlag{ 151 Name: "endpoint", 152 Value: "https://storage.yandexcloud.net", 153 Usage: "The S3 endpoint to connect to." + 154 " Possible values: http://127.0.0.1:8081/, https://s3.amazonaws.com", 155 }, 156 157 cli.StringFlag{ 158 Name: "project-id", 159 Value: "", 160 Usage: "Project ID for Ceph multi-tenancy bucket sharing (bucket syntax project-id:bucket-name)", 161 }, 162 163 cli.BoolFlag{ 164 Name: "iam", 165 Usage: "Try to authenticate automatically using VM metadata service (Yandex Cloud / IMDSv1 / GCP)", 166 }, 167 168 cli.StringFlag{ 169 Name: "iam-header", 170 Value: "X-YaCloud-SubjectToken", 171 Usage: "The header to use for authenticating with IAM token", 172 }, 173 174 cli.StringFlag{ 175 Name: "iam-flavor", 176 Value: "gcp", 177 Usage: "Instance metadata service flavor: gcp or imdsv1", 178 }, 179 180 cli.StringFlag{ 181 Name: "iam-url", 182 Value: "", 183 Usage: "Custom instance metadata service URL", 184 }, 185 186 cli.StringFlag{ 187 Name: "region", 188 Value: s3Default.Region, 189 Usage: "The region to connect to. Usually this is auto-detected." + 190 " Possible values: us-east-1, us-west-1, us-west-2, eu-west-1, " + 191 "eu-central-1, ap-southeast-1, ap-southeast-2, ap-northeast-1, " + 192 "sa-east-1, cn-north-1", 193 }, 194 195 cli.BoolFlag{ 196 Name: "requester-pays", 197 Usage: "Whether to allow access to requester-pays buckets (default: off)", 198 }, 199 200 cli.StringFlag{ 201 Name: "storage-class", 202 Value: s3Default.StorageClass, 203 Usage: "The type of storage to use when writing objects." + 204 " Possible values: REDUCED_REDUNDANCY, STANDARD, STANDARD_IA.", 205 }, 206 207 cli.Uint64Flag{ 208 Name: "cold-min-size", 209 Usage: "Objects smaller than this size will be stored in STANDARD if STANDARD_IA (cold storage) is selected as default.", 210 }, 211 212 cli.StringFlag{ 213 Name: "profile", 214 Usage: "Use a named profile from $HOME/.aws/credentials instead of \"default\"", 215 }, 216 217 cli.StringSliceFlag{ 218 Name: "shared-config", 219 Usage: "Use different shared configuration file(s) instead of $HOME/.aws/credentials and $HOME/.aws/config", 220 }, 221 222 cli.BoolFlag{ 223 Name: "use-content-type", 224 Usage: "Set Content-Type according to file extension and /etc/mime.types (default: off)", 225 }, 226 227 /// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html 228 /// See http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html 229 cli.BoolFlag{ 230 Name: "sse", 231 Usage: "Enable basic server-side encryption at rest (SSE-S3) in S3 for all writes (default: off)", 232 }, 233 234 cli.StringFlag{ 235 Name: "sse-kms", 236 Usage: "Enable KMS encryption (SSE-KMS) for all writes using this particular KMS `key-id`. Leave blank to Use the account's CMK - customer master key (default: off)", 237 Value: "", 238 }, 239 240 cli.StringFlag{ 241 Name: "sse-c", 242 Usage: "Enable server-side encryption using this base64-encoded key (default: off)", 243 Value: "", 244 }, 245 246 cli.BoolFlag{ 247 Name: "no-checksum", 248 Usage: "Disable content MD5 and SHA256 checksums for performance (default: off)", 249 }, 250 251 cli.StringFlag{ 252 Name: "list-type", 253 Usage: "Listing type to use: ext-v1 (yandex only), 2 or 1 (default: ext-v1 for yandex, 1 for others)", 254 Value: "", 255 }, 256 257 cli.StringFlag{ 258 Name: "multipart-age", 259 Usage: "Multipart uploads older than this value will be deleted on start", 260 Value: "48h", 261 }, 262 263 cli.IntFlag{ 264 Name: "multipart-copy-threshold", 265 Usage: "Threshold for switching from single-part to multipart object copy in MB. Maximum for AWS S3 is 5 GB", 266 Value: 128, 267 }, 268 269 /// http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl 270 cli.StringFlag{ 271 Name: "acl", 272 Usage: "The canned ACL to apply to the object. Possible values: private, public-read, public-read-write, authenticated-read, aws-exec-read, bucket-owner-read, bucket-owner-full-control (default: off)", 273 Value: "", 274 }, 275 276 cli.BoolFlag{ 277 Name: "subdomain", 278 Usage: "Enable subdomain mode of S3", 279 }, 280 281 cli.IntFlag{ 282 Name: "sdk-max-retries", 283 Value: 3, 284 Usage: "Maximum number of AWS SDK request retries.", 285 }, 286 287 cli.DurationFlag{ 288 Name: "sdk-min-retry-delay", 289 Value: 30 * time.Millisecond, 290 Usage: "Minimum delay for AWS SDK retries of temporary request failures.", 291 }, 292 293 cli.DurationFlag{ 294 Name: "sdk-max-retry-delay", 295 Value: 300 * time.Second, 296 Usage: "Maximum delay for AWS SDK retries of temporary request failures.", 297 }, 298 299 cli.DurationFlag{ 300 Name: "sdk-min-throttle-delay", 301 Value: 500 * time.Millisecond, 302 Usage: "Minimum delay for AWS SDK retries of throttled requests (429, 502, 503, 504).", 303 }, 304 305 cli.DurationFlag{ 306 Name: "sdk-max-throttle-delay", 307 Value: 300 * time.Second, 308 Usage: "Maximum delay for AWS SDK retries of throttled requests.", 309 }, 310 } 311 312 tuningFlags := []cli.Flag{ 313 ///////////////////////// 314 // Tuning 315 ///////////////////////// 316 317 cli.IntFlag{ 318 Name: "memory-limit", 319 Usage: "Maximum memory in MB to use for data cache", 320 Value: 1000, 321 }, 322 323 cli.IntFlag{ 324 Name: "entry-limit", 325 Usage: "Maximum metadata entries to cache in memory (1 entry uses ~1 KB of memory)", 326 Value: 100000, 327 }, 328 329 cli.IntFlag{ 330 Name: "gc-interval", 331 Usage: "Force garbage collection after this amount of data buffer allocations", 332 Value: 250, 333 }, 334 335 cli.BoolFlag{ 336 Name: "cheap", 337 Usage: "Reduce S3 operation costs at the expense of some performance (default: off)", 338 }, 339 340 cli.BoolFlag{ 341 Name: "no-implicit-dir", 342 Usage: "Assume all directory objects (\"dir/\") exist (default: off)", 343 }, 344 345 cli.BoolFlag{ 346 Name: "no-dir-object", 347 Usage: "Do not create and check directory objects (\"dir/\") (default: off)", 348 }, 349 350 cli.IntFlag{ 351 Name: "max-flushers", 352 Value: 16, 353 Usage: "How much parallel requests should be used for flushing changes to server", 354 }, 355 356 cli.IntFlag{ 357 Name: "max-parallel-parts", 358 Value: 8, 359 Usage: "How much parallel requests out of the total number can be used for large part uploads."+ 360 " Large parts take more bandwidth so they usually require less parallelism", 361 }, 362 363 cli.IntFlag{ 364 Name: "max-parallel-copy", 365 Value: 16, 366 Usage: "How much parallel unmodified part copy requests should be used."+ 367 " This limit is separate from max-flushers", 368 }, 369 370 cli.IntFlag{ 371 Name: "read-ahead", 372 Value: 5*1024, 373 Usage: "How much data in KB should be pre-loaded with every read by default", 374 }, 375 376 cli.IntFlag{ 377 Name: "small-read-count", 378 Value: 4, 379 Usage: "Number of last reads within a single file handle to be checked for being random", 380 }, 381 382 cli.IntFlag{ 383 Name: "small-read-cutoff", 384 Value: 128, 385 Usage: "Maximum average size of last reads in KB to trigger \"small\" readahead", 386 }, 387 388 cli.IntFlag{ 389 Name: "read-ahead-small", 390 Value: 128, 391 Usage: "Smaller readahead size in KB to be used when small random reads are detected", 392 }, 393 394 cli.IntFlag{ 395 Name: "large-read-cutoff", 396 Value: 20*1024, 397 Usage: "Amount of linear read in KB after which the \"large\" readahead should be triggered", 398 }, 399 400 cli.IntFlag{ 401 Name: "read-ahead-large", 402 Value: 100*1024, 403 Usage: "Larger readahead size in KB to be used when long linear reads are detected", 404 }, 405 406 cli.IntFlag{ 407 Name: "read-ahead-parallel", 408 Value: 20*1024, 409 Usage: "Larger readahead will be triggered in parallel chunks of this size in KB", 410 }, 411 412 cli.IntFlag{ 413 Name: "read-merge", 414 Value: 512, 415 Usage: "Two HTTP requests required to satisfy a read will be merged into one" + 416 " if they're at most this number of KB away", 417 }, 418 419 cli.IntFlag{ 420 Name: "single-part", 421 Value: 5, 422 Usage: "Maximum size of an object in MB to upload it as a single part." + 423 " Can't be less than 5 MB", 424 }, 425 426 cli.StringFlag{ 427 Name: "part-sizes", 428 Value: "5:1000,25:1000,125", 429 Usage: "Part sizes in MB. Total part count is always 10000 in S3."+ 430 " Default is 1000 5 MB parts, then 1000 25 MB parts" + 431 " and then 125 MB for the rest of parts", 432 }, 433 434 cli.BoolFlag{ 435 Name: "enable-patch", 436 Usage: "Use PATCH method to upload object data changes to s3. Yandex only. (default: off)", 437 }, 438 439 cli.BoolFlag{ 440 Name: "drop-patch-conflicts", 441 Usage: "Drop local changes in case of conflicting concurrent PATCH updates. (default: off)", 442 }, 443 444 cli.IntFlag{ 445 Name: "max-merge-copy", 446 Value: 0, 447 Usage: "If non-zero, allow to compose larger parts up to this number of megabytes" + 448 " in size from existing unchanged parts when doing server-side part copy."+ 449 " Must be left at 0 for Yandex S3", 450 }, 451 452 cli.BoolFlag{ 453 Name: "ignore-fsync", 454 Usage: "Do not wait until changes are persisted to the server on fsync() call (default: off)", 455 }, 456 457 cli.BoolFlag{ 458 Name: "fsync-on-close", 459 Usage: "Wait until changes are persisted to the server when closing file (default: off)", 460 }, 461 462 cli.BoolFlag{ 463 Name: "enable-perms", 464 Usage: "Enable permissions, user and group ID." + 465 " Only works correctly if your S3 returns UserMetadata in listings (default: off)", 466 }, 467 468 cli.BoolFlag{ 469 Name: "enable-specials", 470 Usage: "Enable special file support (sockets, devices, named pipes)." + 471 " Only works correctly if your S3 returns UserMetadata in listings (default: on for Yandex, off for others)", 472 }, 473 474 cli.BoolFlag{ 475 Name: "no-specials", 476 Usage: "Disable special file support (sockets, devices, named pipes).", 477 }, 478 479 cli.BoolFlag{ 480 Name: "enable-mtime", 481 Usage: "Enable modification time preservation." + 482 " Only works correctly if your S3 returns UserMetadata in listings (default: off)", 483 }, 484 485 cli.BoolFlag{ 486 Name: "disable-xattr", 487 Usage: "Disable extended attributes. Improves performance of very long directory listings", 488 }, 489 490 cli.StringFlag{ 491 Name: "uid-attr", 492 Value: "uid", 493 Usage: "User ID metadata attribute name", 494 }, 495 496 cli.StringFlag{ 497 Name: "gid-attr", 498 Value: "gid", 499 Usage: "Group ID metadata attribute name", 500 }, 501 502 cli.StringFlag{ 503 Name: "mode-attr", 504 Value: "mode", 505 Usage: "File mode (permissions & special file flags) metadata attribute name", 506 }, 507 508 cli.StringFlag{ 509 Name: "rdev-attr", 510 Value: "rdev", 511 Usage: "Block/character device number metadata attribute name", 512 }, 513 514 cli.StringFlag{ 515 Name: "mtime-attr", 516 Value: "mtime", 517 Usage: "File modification time (UNIX time) metadata attribute name", 518 }, 519 520 cli.StringFlag{ 521 Name: "symlink-attr", 522 Value: "--symlink-target", 523 Usage: "Symbolic link target metadata attribute name." + 524 " Only works correctly if your S3 returns UserMetadata in listings", 525 }, 526 527 cli.StringFlag{ 528 Name: "refresh-attr", 529 Value: ".invalidate", 530 Usage: "Setting xattr with this name, without user. prefix, " + 531 " refreshes the cache of the file or directory.", 532 }, 533 534 cli.DurationFlag{ 535 Name: "stat-cache-ttl", 536 Value: time.Minute, 537 Usage: "How long to cache file metadata.", 538 }, 539 540 cli.DurationFlag{ 541 Name: "http-timeout", 542 Value: 30 * time.Second, 543 Usage: "Set the timeout on HTTP requests to S3", 544 }, 545 546 cli.DurationFlag{ 547 Name: "retry-interval", 548 Value: 30 * time.Second, 549 Usage: "Retry unsuccessful writes after this time", 550 }, 551 552 cli.DurationFlag{ 553 Name: "read-retry-interval", 554 Value: 1 * time.Second, 555 Usage: "Initial interval for retrying unsuccessful reads", 556 }, 557 558 cli.Float64Flag{ 559 Name: "read-retry-mul", 560 Value: 2, 561 Usage: "Increase read retry interval this number of times on each unsuccessful attempt", 562 }, 563 564 cli.DurationFlag{ 565 Name: "read-retry-max-interval", 566 Value: 60 * time.Second, 567 Usage: "Maximum interval for retrying unsuccessful reads", 568 }, 569 570 cli.IntFlag{ 571 Name: "read-retry-attempts", 572 Value: 0, 573 Usage: "Maximum read retry attempts (0 means unlimited)", 574 }, 575 576 cli.IntFlag{ 577 Name: "cache-popular-threshold", 578 Value: 3, 579 Usage: "Value of the read counter after which a cached file is started being treated as 'popular'", 580 }, 581 582 cli.IntFlag{ 583 Name: "cache-max-hits", 584 Value: 6, 585 Usage: "Maximum value of the cache read counter for a file", 586 }, 587 588 cli.IntFlag{ 589 Name: "cache-age-interval", 590 Value: 4096, 591 Usage: "Number of reads after which read counters are decremented for all files", 592 }, 593 594 cli.IntFlag{ 595 Name: "cache-age-decrement", 596 Value: 1, 597 Usage: "Decrement amount", 598 }, 599 600 cli.IntFlag{ 601 Name: "cache-to-disk-hits", 602 Value: 2, 603 Usage: "Minimum value of the read counter to cache file on disk", 604 }, 605 606 cli.IntFlag{ 607 Name: "max-disk-cache-fd", 608 Value: 512, 609 Usage: "Simultaneously opened cache file descriptor limit", 610 }, 611 } 612 613 if runtime.GOOS == "windows" { 614 tuningFlags = append(tuningFlags, cli.StringFlag{ 615 Name: "refresh-filename", 616 Value: ".invalidate", 617 Usage: "Trying to open a file with this name refreshes the cache of its directory.", 618 }) 619 tuningFlags = append(tuningFlags, cli.StringFlag{ 620 Name: "flush-filename", 621 Value: ".fsyncdir", 622 Usage: "Trying to open a file with this name flushes the cache of its directory to server.", 623 }) 624 } 625 626 debugFlags := []cli.Flag{ 627 ///////////////////////// 628 // Debugging 629 ///////////////////////// 630 631 cli.BoolFlag{ 632 Name: "debug", 633 Usage: "Enable generic debugging output.", 634 }, 635 636 cli.BoolFlag{ 637 Name: "debug_fuse", 638 Usage: "Enable fuse-related debugging output.", 639 }, 640 641 cli.BoolFlag{ 642 Name: "debug_s3", 643 Usage: "Enable S3-related debugging output.", 644 }, 645 646 cli.StringFlag{ 647 Name: "pprof", 648 Usage: "Specify port or host:port to enable pprof HTTP profiler on that port.", 649 Value: "", 650 }, 651 652 cli.BoolFlag{ 653 Name: "f", 654 Usage: "Run geesefs in foreground.", 655 }, 656 657 cli.StringFlag{ 658 Name: "log-file", 659 Usage: "Redirect logs to file, 'stderr' (default for foreground) or 'syslog' (default for background).", 660 Value: "", 661 }, 662 663 cli.DurationFlag{ 664 Name: "print-stats", 665 Value: 30 * time.Second, 666 Usage: "I/O statistics printing interval. Set to 0 to disable.", 667 }, 668 669 cli.BoolFlag{ 670 Name: "debug_grpc", 671 Usage: "Enable grpc logging in cluster mode.", 672 }, 673 } 674 675 clusterFlags := []cli.Flag{ 676 cli.BoolFlag{ 677 Name: "cluster", 678 Usage: "Enable cluster mode.", 679 }, 680 681 cli.BoolFlag{ 682 Name: "grpc-reflection", 683 Usage: "Enable grpc reflection (--cluster flag required).", 684 }, 685 686 cli.StringFlag{ 687 Name: "cluster-me", 688 Usage: "<node-id>:<address> to communicate with this node (--cluster flag required).", 689 }, 690 691 cli.StringSliceFlag{ 692 Name: "cluster-peer", 693 Usage: "List of all cluster nodes in format <node-id>:<address> (--cluster flag required).", 694 }, 695 } 696 697 app = &cli.App{ 698 Name: "geesefs", 699 Version: GEESEFS_VERSION, 700 Usage: "Mount an S3 bucket locally", 701 HideHelp: true, 702 Writer: os.Stderr, 703 Flags: append(append(append(append(append([]cli.Flag{ 704 cli.BoolFlag{ 705 Name: "help, h", 706 Usage: "Print this help text and exit successfully.", 707 }, 708 }, fsFlags...), s3Flags...), tuningFlags...), debugFlags...), clusterFlags...), 709 } 710 711 var funcMap = template.FuncMap{ 712 "category": filterCategory, 713 "join": strings.Join, 714 } 715 716 flagCategories = map[string]string{} 717 flagCategories["help"] = "misc" 718 flagCategories["h"] = "misc" 719 720 for _, f := range s3Flags { 721 for _, n := range strings.Split(f.GetName(), ",") { 722 flagCategories[strings.Trim(n, " ")] = "aws" 723 } 724 } 725 for _, f := range tuningFlags { 726 for _, n := range strings.Split(f.GetName(), ",") { 727 flagCategories[strings.Trim(n, " ")] = "tuning" 728 } 729 } 730 for _, f := range debugFlags { 731 for _, n := range strings.Split(f.GetName(), ",") { 732 flagCategories[strings.Trim(n, " ")] = "misc" 733 } 734 } 735 736 cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) { 737 w = tabwriter.NewWriter(w, 1, 8, 2, ' ', 0) 738 var tmplGet = template.Must(template.New("help").Funcs(funcMap).Parse(templ)) 739 tmplGet.Execute(w, app) 740 } 741 742 return 743 } 744 745 func parsePartSizes(s string) (result []PartSizeConfig) { 746 partSizes := strings.Split(s, ",") 747 totalCount := uint64(0) 748 for pi, ps := range partSizes { 749 a := strings.Split(ps, ":") 750 size, err := strconv.ParseUint(a[0], 10, 32) 751 if err != nil { 752 panic("Incorrect syntax for --part-sizes") 753 } 754 count := uint64(0) 755 if len(a) > 1 { 756 count, err = strconv.ParseUint(a[1], 10, 32) 757 if err != nil { 758 panic("Incorrect syntax for --part-sizes") 759 } 760 } 761 if count == 0 { 762 if pi < len(partSizes)-1 { 763 panic("Part count may be omitted only for the last interval") 764 } 765 count = 10000-totalCount 766 } 767 totalCount += count 768 if totalCount > 10000 { 769 panic("Total part count must be 10000") 770 } 771 if size < 5 { 772 panic("Minimum part size is 5 MB") 773 } 774 if size > 5*1024 { 775 panic("Maximum part size is 5 GB") 776 } 777 result = append(result, PartSizeConfig{ 778 PartSize: size*1024*1024, 779 PartCount: count, 780 }) 781 } 782 return 783 } 784 785 func parseNode(s string) *NodeConfig { 786 parts := strings.SplitN(s, ":", 2) 787 if len(parts) != 2 { 788 panic("Incorrect syntax for node config, should be: <node-id>:<address>") 789 } 790 nodeId, err := strconv.ParseUint(parts[0], 10, 64) 791 if err != nil { 792 panic("Incorrect syntax for node config, <node-id> shoud be uint64") 793 } 794 return &NodeConfig{ 795 Id: nodeId, 796 Address: parts[1], 797 } 798 } 799 800 // PopulateFlags adds the flags accepted by run to the supplied flag set, returning the 801 // variables into which the flags will parse. 802 func PopulateFlags(c *cli.Context) (ret *FlagStorage) { 803 singlePart := c.Int("single-part") 804 if singlePart < 5 { 805 singlePart = 5 806 } 807 808 flags := &FlagStorage{ 809 // File system 810 MountOptions: c.StringSlice("o"), 811 DirMode: os.FileMode(c.Int("dir-mode")), 812 FileMode: os.FileMode(c.Int("file-mode")), 813 Uid: uint32(c.Int("uid")), 814 Gid: uint32(c.Int("gid")), 815 Setuid: c.Int("setuid"), 816 Setgid: c.Int("setgid"), 817 818 // Tuning, 819 MemoryLimit: uint64(1024*1024*c.Int("memory-limit")), 820 EntryLimit: c.Int("entry-limit"), 821 GCInterval: uint64(1024*1024*c.Int("gc-interval")), 822 Cheap: c.Bool("cheap"), 823 ExplicitDir: c.Bool("no-implicit-dir"), 824 NoDirObject: c.Bool("no-dir-object"), 825 MaxFlushers: int64(c.Int("max-flushers")), 826 MaxParallelParts: c.Int("max-parallel-parts"), 827 MaxParallelCopy: c.Int("max-parallel-copy"), 828 StatCacheTTL: c.Duration("stat-cache-ttl"), 829 HTTPTimeout: c.Duration("http-timeout"), 830 RetryInterval: c.Duration("retry-interval"), 831 ReadRetryInterval: c.Duration("read-retry-interval"), 832 ReadRetryMultiplier: c.Float64("read-retry-mul"), 833 ReadRetryMax: c.Duration("read-retry-max-interval"), 834 ReadRetryAttempts: c.Int("read-retry-attempts"), 835 ReadAheadKB: uint64(c.Int("read-ahead")), 836 SmallReadCount: uint64(c.Int("small-read-count")), 837 SmallReadCutoffKB: uint64(c.Int("small-read-cutoff")), 838 ReadAheadSmallKB: uint64(c.Int("read-ahead-small")), 839 LargeReadCutoffKB: uint64(c.Int("large-read-cutoff")), 840 ReadAheadLargeKB: uint64(c.Int("read-ahead-large")), 841 ReadAheadParallelKB: uint64(c.Int("read-ahead-parallel")), 842 ReadMergeKB: uint64(c.Int("read-merge")), 843 SinglePartMB: uint64(singlePart), 844 MaxMergeCopyMB: uint64(c.Int("max-merge-copy")), 845 IgnoreFsync: c.Bool("ignore-fsync"), 846 FsyncOnClose: c.Bool("fsync-on-close"), 847 EnablePerms: c.Bool("enable-perms"), 848 EnableSpecials: c.Bool("enable-specials"), 849 EnableMtime: c.Bool("enable-mtime"), 850 DisableXattr: c.Bool("disable-xattr"), 851 UidAttr: c.String("uid-attr"), 852 GidAttr: c.String("gid-attr"), 853 FileModeAttr: c.String("mode-attr"), 854 RdevAttr: c.String("rdev-attr"), 855 MtimeAttr: c.String("mtime-attr"), 856 SymlinkAttr: c.String("symlink-attr"), 857 RefreshAttr: c.String("refresh-attr"), 858 CachePath: c.String("cache"), 859 MaxDiskCacheFD: int64(c.Int("max-disk-cache-fd")), 860 CacheFileMode: os.FileMode(c.Int("cache-file-mode")), 861 UsePatch: c.Bool("enable-patch"), 862 DropPatchConflicts: c.Bool("drop-patch-conflicts"), 863 864 // Common Backend Config 865 Endpoint: c.String("endpoint"), 866 UseContentType: c.Bool("use-content-type"), 867 868 // Debugging, 869 DebugMain: c.Bool("debug"), 870 DebugFuse: c.Bool("debug_fuse"), 871 DebugS3: c.Bool("debug_s3"), 872 Foreground: c.Bool("f"), 873 LogFile: c.String("log-file"), 874 StatsInterval: c.Duration("print-stats"), 875 PProf: c.String("pprof"), 876 DebugGrpc: c.Bool("debug_grpc"), 877 878 // Cluster Mode 879 ClusterMode: c.Bool("cluster"), 880 ClusterGrpcReflection: c.Bool("grpc-reflection"), 881 } 882 883 if runtime.GOOS == "windows" { 884 flags.RefreshFilename = c.String("refresh-filename") 885 flags.FlushFilename = c.String("flush-filename") 886 } 887 888 flags.PartSizes = parsePartSizes(c.String("part-sizes")) 889 890 if flags.ClusterMode { 891 flags.ClusterMe = parseNode(c.String("cluster-me")) 892 893 for _, peer := range c.StringSlice("cluster-peer") { 894 flags.ClusterPeers = append(flags.ClusterPeers, parseNode(peer)) 895 } 896 } 897 898 // S3 by default, if not initialized in api/api.go 899 if flags.Backend == nil { 900 flags.Backend = (&S3Config{}).Init() 901 config, _ := flags.Backend.(*S3Config) 902 config.Region = c.String("region") 903 config.RegionSet = c.IsSet("region") 904 config.ProjectId = c.String("project-id") 905 config.RequesterPays = c.Bool("requester-pays") 906 config.StorageClass = c.String("storage-class") 907 config.ColdMinSize = c.Uint64("cold-min-size") 908 config.Profile = c.String("profile") 909 config.SharedConfig = c.StringSlice("shared-config") 910 config.UseSSE = c.Bool("sse") 911 config.UseKMS = c.IsSet("sse-kms") 912 config.KMSKeyID = c.String("sse-kms") 913 config.SseC = c.String("sse-c") 914 config.ACL = c.String("acl") 915 config.Subdomain = c.Bool("subdomain") 916 config.NoChecksum = c.Bool("no-checksum") 917 config.UseIAM = c.Bool("iam") 918 config.IAMHeader = c.String("iam-header") 919 config.IAMFlavor = c.String("iam-flavor") 920 config.IAMUrl = c.String("iam-url") 921 config.MultipartAge = c.Duration("multipart-age") 922 if config.IAMFlavor != "gcp" && config.IAMFlavor != "imdsv1" { 923 panic("Unknown --iam-flavor: "+config.IAMFlavor) 924 } 925 listType := c.String("list-type") 926 isYandex := strings.Contains(flags.Endpoint, "yandex") 927 if isYandex && !c.IsSet("no-specials") { 928 flags.EnableSpecials = true 929 } 930 if listType == "" { 931 if isYandex { 932 listType = "ext-v1" 933 } else { 934 listType = "1" 935 } 936 } 937 config.ListV1Ext = listType == "ext-v1" 938 config.ListV2 = listType == "2" 939 940 config.MultipartCopyThreshold = uint64(c.Int("multipart-copy-threshold")) * 1024 * 1024 941 942 config.SDKMaxRetries = c.Int("sdk-max-retries") 943 config.SDKMinRetryDelay = c.Duration("sdk-min-retry-delay") 944 config.SDKMaxRetryDelay = c.Duration("sdk-max-retry-delay") 945 config.SDKMinThrottleDelay = c.Duration("sdk-min-throttle-delay") 946 config.SDKMaxThrottleDelay = c.Duration("sdk-max-throttle-delay") 947 948 // KMS implies SSE 949 if config.UseKMS { 950 config.UseSSE = true 951 } 952 } 953 954 if c.IsSet("no-specials") { 955 flags.EnableSpecials = false 956 } 957 958 if syscall.Getuid() == 0 && !c.IsSet("setuid") && flags.Uid != 0 { 959 flags.Setuid = int(flags.Uid) 960 } 961 if syscall.Getgid() == 0 && !c.IsSet("setgid") && flags.Gid != 0 { 962 flags.Setgid = int(flags.Gid) 963 } 964 965 flags.MountPointArg = c.Args()[1] 966 flags.MountPoint = flags.MountPointArg 967 var err error 968 969 defer func() { 970 if err != nil { 971 flags.Cleanup() 972 } 973 }() 974 975 if !flags.ClusterMode && flags.ClusterGrpcReflection { 976 return nil 977 } 978 979 if flags.ClusterMode != (flags.ClusterMe != nil) { 980 return nil 981 } 982 983 if flags.ClusterMode != (flags.ClusterPeers != nil) { 984 return nil 985 } 986 987 return flags 988 } 989 990 func MessageMountFlags(args []string) (ret []string) { 991 if len(args) == 5 && args[3] == "-o" { 992 // looks like it's coming from fstab! 993 mountOptions := "" 994 ret = append(ret, args[0]) 995 996 for _, p := range strings.Split(args[4], ",") { 997 if strings.HasPrefix(p, "-") { 998 ret = append(ret, p) 999 } else { 1000 mountOptions += p 1001 mountOptions += "," 1002 } 1003 } 1004 1005 if len(mountOptions) != 0 { 1006 // remove trailing , 1007 mountOptions = mountOptions[:len(mountOptions)-1] 1008 ret = append(ret, "-o") 1009 ret = append(ret, mountOptions) 1010 } 1011 1012 ret = append(ret, args[1]) 1013 ret = append(ret, args[2]) 1014 } else { 1015 return args 1016 } 1017 1018 return 1019 } 1020 1021 func DefaultFlags() *FlagStorage { 1022 uid, gid := MyUserAndGroup() 1023 return &FlagStorage{ 1024 DirMode: 0755, 1025 FileMode: 0644, 1026 CacheFileMode: 0644, 1027 Uid: uint32(uid), 1028 Gid: uint32(gid), 1029 Setuid: uid, 1030 Setgid: gid, 1031 Endpoint: "https://storage.yandexcloud.net", 1032 Backend: (&S3Config{}).Init(), 1033 MemoryLimit: 1000 * 1024 * 1024, 1034 EntryLimit: 100000, 1035 GCInterval: 250 * 1024 * 1024, 1036 MaxFlushers: 16, 1037 MaxParallelParts: 8, 1038 MaxParallelCopy: 16, 1039 ReadAheadKB: 5 * 1024, 1040 SmallReadCount: 4, 1041 SmallReadCutoffKB: 128, 1042 ReadAheadSmallKB: 128, 1043 LargeReadCutoffKB: 20 * 1024, 1044 ReadAheadLargeKB: 100 * 1024, 1045 ReadAheadParallelKB: 20 * 1024, 1046 ReadMergeKB: 512, 1047 SinglePartMB: 5, 1048 MaxMergeCopyMB: 0, 1049 UidAttr: "uid", 1050 GidAttr: "gid", 1051 FileModeAttr: "mode", 1052 RdevAttr: "rdev", 1053 MtimeAttr: "mtime", 1054 SymlinkAttr: "--symlink-target", 1055 RefreshAttr: ".invalidate", 1056 StatCacheTTL: 30 * time.Second, 1057 HTTPTimeout: 30 * time.Second, 1058 RetryInterval: 30 * time.Second, 1059 MaxDiskCacheFD: 512, 1060 RefreshFilename: ".invalidate", 1061 FlushFilename: ".fsyncdir", 1062 PartSizes: []PartSizeConfig{ 1063 {PartSize: 5 * 1024 * 1024, PartCount: 1000}, 1064 {PartSize: 25 * 1024 * 1024, PartCount: 1000}, 1065 {PartSize: 125 * 1024 * 1024, PartCount: 8000}, 1066 }, 1067 } 1068 }