564 строки
24 KiB
Go
Executable File
564 строки
24 KiB
Go
Executable File
/*
|
|
_____ _____ _____ ____ ______ _____ ------
|
|
| | | | | | | | | | | | |
|
|
| | | | | | | | | | | | |
|
|
| --- | | | | |-----| |---- | | |-----| |----- ------
|
|
| | | | | | | | | | | | |
|
|
| ____| |_____ | ____| | ____| | |_____| _____| |_____ |_____
|
|
|
|
|
|
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
|
|
|
Copyright © 2020-2024 Microsoft Corporation. All rights reserved.
|
|
Author : <blobfusedev@microsoft.com>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE
|
|
*/
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"log/syslog"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/Azure/azure-storage-fuse/v2/common"
|
|
"github.com/Azure/azure-storage-fuse/v2/common/log"
|
|
"github.com/Azure/azure-storage-fuse/v2/component/attr_cache"
|
|
"github.com/Azure/azure-storage-fuse/v2/component/azstorage"
|
|
"github.com/Azure/azure-storage-fuse/v2/component/file_cache"
|
|
"github.com/Azure/azure-storage-fuse/v2/component/libfuse"
|
|
"github.com/Azure/azure-storage-fuse/v2/component/stream"
|
|
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/pflag"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type blobfuseCliOptions struct {
|
|
configFile string
|
|
logLevel string
|
|
fuseLogging bool
|
|
useAttrCache bool
|
|
useStreaming bool
|
|
// fuseAttrTimeout uint32
|
|
// fuseEntryTimeout uint32
|
|
tmpPath string
|
|
cacheSize float64
|
|
fileCacheTimeout uint32
|
|
maxEviciton uint32
|
|
highDiskThreshold uint32
|
|
lowDiskThreshold uint32
|
|
emptyDirCheck bool
|
|
blockSize uint64
|
|
maxBlocksPerFile int
|
|
streamCacheSize uint64
|
|
noSymlinks bool
|
|
cacheOnList bool
|
|
useAdls bool
|
|
useHttps bool
|
|
containerName string
|
|
maxConcurrency uint16
|
|
cancelListOnMount uint16
|
|
maxRetry int32
|
|
maxRetryInterval int32
|
|
retryDelayFactor int32
|
|
httpProxy string
|
|
httpsProxy string
|
|
ignoreOpenFlags bool
|
|
}
|
|
type ComponentsConfig []string
|
|
type PipelineConfig struct {
|
|
ForegroundOption bool `yaml:"foreground,omitempty"`
|
|
ReadOnlyOption bool `yaml:"read-only,omitempty"`
|
|
AllowOtherOption bool `yaml:"allow-other,omitempty"`
|
|
NonEmptyMountOption bool `yaml:"nonempty,omitempty"`
|
|
LogOptions `yaml:"logging,omitempty"`
|
|
libfuse.LibfuseOptions `yaml:"libfuse,omitempty"`
|
|
stream.StreamOptions `yaml:"stream,omitempty"`
|
|
file_cache.FileCacheOptions `yaml:"file_cache,omitempty"`
|
|
attr_cache.AttrCacheOptions `yaml:"attr_cache,omitempty"`
|
|
azstorage.AzStorageOptions `yaml:"azstorage,omitempty"`
|
|
ComponentsConfig `yaml:"components,omitempty"`
|
|
}
|
|
|
|
var outputFilePath string
|
|
var mountPath string
|
|
var libfuseOptions []string
|
|
var bfConfCliOptions blobfuseCliOptions
|
|
var bfv2StorageConfigOptions azstorage.AzStorageOptions
|
|
var bfv2LoggingConfigOptions LogOptions
|
|
var bfv2FuseConfigOptions libfuse.LibfuseOptions
|
|
var bfv2FileCacheConfigOptions file_cache.FileCacheOptions
|
|
var bfv2AttrCacheConfigOptions attr_cache.AttrCacheOptions
|
|
var bfv2ComponentsConfigOptions ComponentsConfig
|
|
var bfv2StreamConfigOptions stream.StreamOptions
|
|
var bfv2ForegroundOption bool
|
|
var bfv2ReadOnlyOption bool
|
|
var bfv2NonEmptyMountOption bool
|
|
var bfv2AllowOtherOption bool
|
|
var useAttrCache bool
|
|
var useStream bool
|
|
var useFileCache bool = true
|
|
var convertConfigOnly bool
|
|
var enableGen1 bool
|
|
var reqFreeSpaceMB int
|
|
|
|
func resetOptions() {
|
|
bfv2StorageConfigOptions = azstorage.AzStorageOptions{}
|
|
bfv2LoggingConfigOptions = LogOptions{}
|
|
bfv2FuseConfigOptions = libfuse.LibfuseOptions{}
|
|
bfv2FileCacheConfigOptions = file_cache.FileCacheOptions{}
|
|
bfv2AttrCacheConfigOptions = attr_cache.AttrCacheOptions{}
|
|
bfv2ComponentsConfigOptions = ComponentsConfig{}
|
|
bfv2StreamConfigOptions = stream.StreamOptions{}
|
|
bfv2ForegroundOption = false
|
|
bfv2ReadOnlyOption = false
|
|
bfv2NonEmptyMountOption = false
|
|
bfv2AllowOtherOption = false
|
|
useAttrCache = false
|
|
useStream = false
|
|
useFileCache = true
|
|
}
|
|
|
|
var generateConfigCmd = &cobra.Command{
|
|
Use: "mountv1",
|
|
Short: "Generate a configuration file for Blobfuse2 from Blobfuse configuration file/flags",
|
|
Long: "Generate a configuration file for Blobfuse2 from Blobfuse configuration file/flags",
|
|
SuggestFor: []string{"conv config", "convert config"},
|
|
Args: cobra.MaximumNArgs(1),
|
|
FlagErrorHandling: cobra.ExitOnError,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
if !disableVersionCheck {
|
|
err := VersionCheck()
|
|
if err != nil {
|
|
log.Err(err.Error())
|
|
}
|
|
}
|
|
resetOptions()
|
|
// If we are only converting the config without mounting then we do not need the mount path and therefore the args length would be 0
|
|
if len(args) == 1 {
|
|
mountPath = args[0]
|
|
}
|
|
|
|
file, err := os.Open(bfConfCliOptions.configFile)
|
|
if err == nil {
|
|
defer file.Close()
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
// some users may have a commented out config
|
|
linePieces := strings.SplitN(scanner.Text(), "#", 2)
|
|
line := linePieces[0]
|
|
configParam := strings.Fields(line)
|
|
if len(configParam) == 0 {
|
|
continue
|
|
}
|
|
if len(configParam) != 2 {
|
|
return fmt.Errorf("failed to read configuration file. Configuration %s is incorrect. Make sure your configuration file parameters are of the format `key value`", configParam)
|
|
}
|
|
|
|
// get corresponding Blobfuse2 configurations from the config file parameters
|
|
err := convertBfConfigParameter(cmd.Flags(), configParam[0], configParam[1])
|
|
if err != nil {
|
|
return fmt.Errorf("failed to convert configuration parameters [%s]", err.Error())
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
bfv2ComponentsConfigOptions = append(bfv2ComponentsConfigOptions, "libfuse")
|
|
// get corresponding Blobfuse2 configurations from the cli parameters - these supersede the config options
|
|
err = convertBfCliParameters(cmd.Flags())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to convert CLI parameters [%s]", err.Error())
|
|
}
|
|
|
|
// if we have the o being passed then parse it
|
|
if cmd.Flags().Lookup("o").Changed {
|
|
err := parseFuseConfig(libfuseOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if useStream {
|
|
bfv2ComponentsConfigOptions = append(bfv2ComponentsConfigOptions, "stream")
|
|
}
|
|
if useFileCache {
|
|
bfv2ComponentsConfigOptions = append(bfv2ComponentsConfigOptions, "file_cache")
|
|
}
|
|
if useAttrCache {
|
|
bfv2ComponentsConfigOptions = append(bfv2ComponentsConfigOptions, "attr_cache")
|
|
}
|
|
bfv2ComponentsConfigOptions = append(bfv2ComponentsConfigOptions, "azstorage")
|
|
|
|
// Set the endpoint if not explicitly provided
|
|
if bfv2StorageConfigOptions.Endpoint == "" {
|
|
accountName := bfv2StorageConfigOptions.AccountName
|
|
if accountName == "" {
|
|
res, ok := os.LookupEnv(azstorage.EnvAzStorageAccount)
|
|
if !ok {
|
|
return fmt.Errorf("invalid account name")
|
|
} else {
|
|
accountName = res
|
|
}
|
|
}
|
|
http := "https"
|
|
if bfv2StorageConfigOptions.UseHTTP {
|
|
http = "http"
|
|
}
|
|
|
|
accountType := ""
|
|
if bfv2StorageConfigOptions.AccountType == "" || bfv2StorageConfigOptions.AccountType == "blob" {
|
|
accountType = "blob"
|
|
} else if bfv2StorageConfigOptions.AccountType == "adls" {
|
|
accountType = "dfs"
|
|
} else {
|
|
return fmt.Errorf("invalid account type")
|
|
}
|
|
bfv2StorageConfigOptions.Endpoint = fmt.Sprintf("%s://%s.%s.core.windows.net", http, accountName, accountType)
|
|
}
|
|
bfv2StorageConfigOptions.VirtualDirectory = true
|
|
|
|
pConf := PipelineConfig{
|
|
bfv2ForegroundOption,
|
|
bfv2ReadOnlyOption,
|
|
bfv2AllowOtherOption,
|
|
bfv2NonEmptyMountOption,
|
|
bfv2LoggingConfigOptions,
|
|
bfv2FuseConfigOptions,
|
|
bfv2StreamConfigOptions,
|
|
bfv2FileCacheConfigOptions,
|
|
bfv2AttrCacheConfigOptions,
|
|
bfv2StorageConfigOptions,
|
|
bfv2ComponentsConfigOptions}
|
|
|
|
data, _ := yaml.Marshal(&pConf)
|
|
err2 := os.WriteFile(outputFilePath, data, 0700)
|
|
if err2 != nil {
|
|
return fmt.Errorf("failed to write file [%s]", err2.Error())
|
|
}
|
|
|
|
if !convertConfigOnly {
|
|
buf := new(bytes.Buffer)
|
|
rootCmd.SetOut(buf)
|
|
rootCmd.SetErr(buf)
|
|
if enableGen1 {
|
|
rootCmd.SetArgs([]string{"mountgen1", mountPath, fmt.Sprintf("--config-file=%s", outputFilePath), fmt.Sprintf("--required-free-space-mb=%v", reqFreeSpaceMB)})
|
|
} else {
|
|
rootCmd.SetArgs([]string{"mount", mountPath, fmt.Sprintf("--config-file=%s", outputFilePath), "--disable-version-check=true"})
|
|
}
|
|
err := rootCmd.Execute()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to execute command [%s]", err.Error())
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
// `-o negative_timeout`: files that do not exist
|
|
// `-o ro`: read-only mode
|
|
// `-o entry_timeout`: timeout in seconds for which name lookups will be cached
|
|
// `-o attr_timeout`: The timeout in seconds for which file/directory attributes
|
|
// `-o umask`: inverse of default permissions being set, so 0000 is 0777
|
|
// `-d` : enable debug logs and foreground on
|
|
func parseFuseConfig(config []string) error {
|
|
for _, v := range config {
|
|
parameter := strings.Split(v, "=")
|
|
if len(parameter) > 2 || len(parameter) <= 0 {
|
|
return errors.New(common.FuseAllowedFlags)
|
|
}
|
|
|
|
v = strings.TrimSpace(v)
|
|
if ignoreFuseOptions(v) {
|
|
continue
|
|
} else if v == "allow_other" || v == "allow_other=true" {
|
|
bfv2AllowOtherOption = true
|
|
} else if v == "allow_other=false" {
|
|
bfv2AllowOtherOption = false
|
|
} else if v == "nonempty" {
|
|
bfv2NonEmptyMountOption = true
|
|
} else if strings.HasPrefix(v, "attr_timeout=") {
|
|
timeout, err := strconv.ParseUint(parameter[1], 10, 32)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse attr_timeout [%s]", err.Error())
|
|
}
|
|
bfv2FuseConfigOptions.AttributeExpiration = uint32(timeout)
|
|
} else if strings.HasPrefix(v, "entry_timeout=") {
|
|
timeout, err := strconv.ParseUint(parameter[1], 10, 32)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse entry_timeout [%s]", err.Error())
|
|
}
|
|
bfv2FuseConfigOptions.EntryExpiration = uint32(timeout)
|
|
} else if strings.HasPrefix(v, "negative_timeout=") {
|
|
timeout, err := strconv.ParseUint(parameter[1], 10, 32)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse negative_timeout [%s]", err.Error())
|
|
}
|
|
bfv2FuseConfigOptions.NegativeEntryExpiration = uint32(timeout)
|
|
} else if v == "ro" {
|
|
bfv2ReadOnlyOption = true
|
|
} else if v == "allow_root" {
|
|
bfv2FuseConfigOptions.DefaultPermission = 700
|
|
} else if strings.HasPrefix(v, "umask=") {
|
|
permission, err := strconv.ParseUint(parameter[1], 10, 32)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse umask [%s]", err.Error())
|
|
}
|
|
perm := ^uint32(permission) & 777
|
|
bfv2FuseConfigOptions.DefaultPermission = perm
|
|
} else {
|
|
return errors.New(common.FuseAllowedFlags)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// helper method: converts config file options
|
|
func convertBfConfigParameter(flags *pflag.FlagSet, configParameterKey string, configParameterValue string) error {
|
|
switch configParameterKey {
|
|
case "logLevel":
|
|
if !flags.Lookup("log-level").Changed {
|
|
bfv2LoggingConfigOptions.LogLevel = configParameterValue
|
|
}
|
|
case "accountName":
|
|
bfv2StorageConfigOptions.AccountName = configParameterValue
|
|
case "accountKey":
|
|
bfv2StorageConfigOptions.AccountKey = configParameterValue
|
|
case "accountType":
|
|
if !flags.Lookup("use-adls").Changed {
|
|
bfv2StorageConfigOptions.AccountType = configParameterValue
|
|
}
|
|
case "aadEndpoint":
|
|
bfv2StorageConfigOptions.ActiveDirectoryEndpoint = configParameterValue
|
|
case "authType":
|
|
bfv2StorageConfigOptions.AuthMode = strings.ToLower(configParameterValue)
|
|
case "blobEndpoint":
|
|
bfv2StorageConfigOptions.Endpoint = configParameterValue
|
|
case "containerName":
|
|
if !flags.Lookup("container-name").Changed {
|
|
bfv2StorageConfigOptions.Container = configParameterValue
|
|
}
|
|
case "httpProxy":
|
|
if !flags.Lookup("http-proxy").Changed {
|
|
bfv2StorageConfigOptions.HttpProxyAddress = configParameterValue
|
|
}
|
|
case "identityClientId":
|
|
bfv2StorageConfigOptions.ApplicationID = configParameterValue
|
|
case "httpsProxy":
|
|
bfv2StorageConfigOptions.HttpsProxyAddress = configParameterValue
|
|
case "identityObjectId":
|
|
bfv2StorageConfigOptions.ObjectID = configParameterValue
|
|
case "identityResourceId":
|
|
bfv2StorageConfigOptions.ResourceID = configParameterValue
|
|
case "sasToken":
|
|
bfv2StorageConfigOptions.SaSKey = configParameterValue
|
|
case "servicePrincipalClientId":
|
|
bfv2StorageConfigOptions.ClientID = configParameterValue
|
|
case "servicePrincipalClientSecret":
|
|
bfv2StorageConfigOptions.ClientSecret = configParameterValue
|
|
case "servicePrincipalTenantId":
|
|
bfv2StorageConfigOptions.TenantID = configParameterValue
|
|
|
|
case "msiEndpoint":
|
|
// msiEndpoint is not supported config in V2, this needs to be given as MSI_ENDPOINT env variable
|
|
return nil
|
|
|
|
default:
|
|
return fmt.Errorf("failed to parse configuration file. Configuration parameter `%s` is not supported in Blobfuse2", configParameterKey)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// helper method: converts cli options - cli options that overlap with config file take precedence
|
|
func convertBfCliParameters(flags *pflag.FlagSet) error {
|
|
if flags.Lookup("set-content-type").Changed || flags.Lookup("ca-cert-file").Changed || flags.Lookup("basic-remount-check").Changed || flags.Lookup(
|
|
"background-download").Changed || flags.Lookup("cache-poll-timeout-msec").Changed || flags.Lookup("upload-modified-only").Changed || flags.Lookup("debug-libcurl").Changed {
|
|
logWriter, _ := syslog.New(syslog.LOG_WARNING, "")
|
|
_ = logWriter.Warning("one or more unsupported v1 parameters [set-content-type, ca-cert-file, basic-remount-check, background-download, cache-poll-timeout-msec, upload-modified-only, debug-libcurl] have been passed, ignoring and proceeding to mount")
|
|
}
|
|
|
|
bfv2LoggingConfigOptions.Type = "syslog"
|
|
if flags.Lookup("log-level").Changed {
|
|
bfv2LoggingConfigOptions.LogLevel = bfConfCliOptions.logLevel
|
|
}
|
|
|
|
if flags.Lookup("streaming").Changed {
|
|
if bfConfCliOptions.useStreaming {
|
|
useStream = true
|
|
useFileCache = false
|
|
if flags.Lookup("block-size-mb").Changed {
|
|
bfv2StreamConfigOptions.BlockSize = bfConfCliOptions.blockSize
|
|
}
|
|
if flags.Lookup("max-blocks-per-file").Changed {
|
|
bfv2StreamConfigOptions.BufferSize = bfConfCliOptions.blockSize * uint64(bfConfCliOptions.maxBlocksPerFile)
|
|
}
|
|
if flags.Lookup("stream-cache-mb").Changed {
|
|
bfv2StreamConfigOptions.CachedObjLimit = bfConfCliOptions.streamCacheSize / bfv2StreamConfigOptions.BufferSize
|
|
if bfv2StreamConfigOptions.CachedObjLimit == 0 {
|
|
bfv2StreamConfigOptions.CachedObjLimit = 1
|
|
}
|
|
}
|
|
} else {
|
|
useStream = false
|
|
useFileCache = true
|
|
}
|
|
}
|
|
|
|
if flags.Lookup("use-attr-cache").Changed {
|
|
useAttrCache = true
|
|
if bfConfCliOptions.useAttrCache {
|
|
if flags.Lookup("cache-on-list").Changed {
|
|
if bfConfCliOptions.cacheOnList {
|
|
bfv2AttrCacheConfigOptions.NoCacheOnList = !bfConfCliOptions.cacheOnList
|
|
}
|
|
}
|
|
if flags.Lookup("no-symlinks").Changed {
|
|
if bfConfCliOptions.noSymlinks {
|
|
bfv2AttrCacheConfigOptions.NoSymlinks = bfConfCliOptions.noSymlinks
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if flags.Lookup("tmp-path").Changed {
|
|
bfv2FileCacheConfigOptions.TmpPath = bfConfCliOptions.tmpPath
|
|
}
|
|
if flags.Lookup("cache-size-mb").Changed {
|
|
bfv2FileCacheConfigOptions.MaxSizeMB = bfConfCliOptions.cacheSize
|
|
}
|
|
if flags.Lookup("file-cache-timeout-in-seconds").Changed {
|
|
bfv2FileCacheConfigOptions.Timeout = bfConfCliOptions.fileCacheTimeout
|
|
}
|
|
if flags.Lookup("max-eviction").Changed {
|
|
bfv2FileCacheConfigOptions.MaxEviction = bfConfCliOptions.maxEviciton
|
|
}
|
|
if flags.Lookup("high-disk-threshold").Changed {
|
|
bfv2FileCacheConfigOptions.HighThreshold = bfConfCliOptions.highDiskThreshold
|
|
}
|
|
if flags.Lookup("low-disk-threshold").Changed {
|
|
bfv2FileCacheConfigOptions.LowThreshold = bfConfCliOptions.lowDiskThreshold
|
|
}
|
|
if flags.Lookup("empty-dir-check").Changed {
|
|
bfv2FileCacheConfigOptions.AllowNonEmpty = !bfConfCliOptions.emptyDirCheck
|
|
}
|
|
if flags.Lookup("use-adls").Changed {
|
|
if bfConfCliOptions.useAdls {
|
|
bfv2StorageConfigOptions.AccountType = "adls"
|
|
} else {
|
|
bfv2StorageConfigOptions.AccountType = "block"
|
|
}
|
|
}
|
|
if flags.Lookup("use-https").Changed {
|
|
bfv2StorageConfigOptions.UseHTTP = !bfConfCliOptions.useHttps
|
|
}
|
|
if flags.Lookup("container-name").Changed {
|
|
bfv2StorageConfigOptions.Container = bfConfCliOptions.containerName
|
|
}
|
|
if flags.Lookup("max-concurrency").Changed {
|
|
bfv2StorageConfigOptions.MaxConcurrency = bfConfCliOptions.maxConcurrency
|
|
}
|
|
if flags.Lookup("cancel-list-on-mount-seconds").Changed {
|
|
bfv2StorageConfigOptions.CancelListForSeconds = bfConfCliOptions.cancelListOnMount
|
|
}
|
|
if flags.Lookup("max-retry").Changed {
|
|
bfv2StorageConfigOptions.MaxRetries = bfConfCliOptions.maxRetry
|
|
}
|
|
if flags.Lookup("max-retry-interval-in-seconds").Changed {
|
|
bfv2StorageConfigOptions.MaxTimeout = bfConfCliOptions.maxRetryInterval
|
|
}
|
|
if flags.Lookup("retry-delay-factor").Changed {
|
|
bfv2StorageConfigOptions.BackoffTime = bfConfCliOptions.retryDelayFactor
|
|
}
|
|
if flags.Lookup("http-proxy").Changed {
|
|
bfv2StorageConfigOptions.HttpProxyAddress = bfConfCliOptions.httpProxy
|
|
}
|
|
if flags.Lookup("https-proxy").Changed {
|
|
bfv2StorageConfigOptions.HttpsProxyAddress = bfConfCliOptions.httpsProxy
|
|
}
|
|
if flags.Lookup("d").Changed {
|
|
bfv2FuseConfigOptions.EnableFuseTrace = bfConfCliOptions.fuseLogging
|
|
bfv2ForegroundOption = bfConfCliOptions.fuseLogging
|
|
}
|
|
if flags.Lookup("ignore-open-flags").Changed {
|
|
bfv2FuseConfigOptions.IgnoreOpenFlags = bfConfCliOptions.ignoreOpenFlags
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(generateConfigCmd)
|
|
generateConfigCmd.Flags().StringVar(&outputFilePath, "output-file", "config.yaml", "Output Blobfuse configuration file.")
|
|
|
|
generateConfigCmd.Flags().StringVar(&bfConfCliOptions.tmpPath, "tmp-path", "", "Tmp location for the file cache.")
|
|
generateConfigCmd.Flags().StringVar(&bfConfCliOptions.configFile, "config-file", "", "Input Blobfuse configuration file.")
|
|
generateConfigCmd.Flags().BoolVar(&bfConfCliOptions.useHttps, "use-https", false, "Enables HTTPS communication with Blob storage.")
|
|
generateConfigCmd.Flags().Uint32Var(&bfConfCliOptions.fileCacheTimeout, "file-cache-timeout-in-seconds", 0, "During this time, blobfuse will not check whether the file is up to date or not.")
|
|
generateConfigCmd.Flags().StringVar(&bfConfCliOptions.containerName, "container-name", "", "Required if no configuration file is specified.")
|
|
generateConfigCmd.Flags().StringVar(&bfConfCliOptions.logLevel, "log-level", "LOG_WARNING", "Logging level.")
|
|
generateConfigCmd.Flags().BoolVar(&bfConfCliOptions.useAttrCache, "use-attr-cache", false, "Enable attribute cache.")
|
|
generateConfigCmd.Flags().BoolVar(&bfConfCliOptions.useAdls, "use-adls", false, "Enables blobfuse to access Azure DataLake storage account.")
|
|
generateConfigCmd.Flags().BoolVar(&bfConfCliOptions.noSymlinks, "no-symlinks", false, "Disables symlink support.")
|
|
generateConfigCmd.Flags().BoolVar(&bfConfCliOptions.cacheOnList, "cache-on-list", true, "Cache attributes on listing.")
|
|
generateConfigCmd.Flags().Uint16Var(&bfConfCliOptions.maxConcurrency, "max-concurrency", 0, "Option to override default number of concurrent storage connections")
|
|
generateConfigCmd.Flags().Float64Var(&bfConfCliOptions.cacheSize, "cache-size-mb", 0, "File cache size.")
|
|
generateConfigCmd.Flags().BoolVar(&bfConfCliOptions.emptyDirCheck, "empty-dir-check", false, "Disallows remounting using a non-empty tmp-path.")
|
|
generateConfigCmd.Flags().Uint16Var(&bfConfCliOptions.cancelListOnMount, "cancel-list-on-mount-seconds", 0, "A list call to the container is by default issued on mount.")
|
|
generateConfigCmd.Flags().Uint32Var(&bfConfCliOptions.highDiskThreshold, "high-disk-threshold", 0, "High disk threshold percentage.")
|
|
generateConfigCmd.Flags().Uint32Var(&bfConfCliOptions.lowDiskThreshold, "low-disk-threshold", 0, "Low disk threshold percentage.")
|
|
generateConfigCmd.Flags().Uint32Var(&bfConfCliOptions.maxEviciton, "max-eviction", 0, "Number of files to be evicted from cache at once.")
|
|
generateConfigCmd.Flags().StringVar(&bfConfCliOptions.httpsProxy, "https-proxy", "", "HTTPS Proxy address.")
|
|
generateConfigCmd.Flags().StringVar(&bfConfCliOptions.httpProxy, "http-proxy", "", "HTTP Proxy address.")
|
|
generateConfigCmd.Flags().Int32Var(&bfConfCliOptions.maxRetry, "max-retry", 0, "Maximum retry count if the failure codes are retryable.")
|
|
generateConfigCmd.Flags().Int32Var(&bfConfCliOptions.maxRetryInterval, "max-retry-interval-in-seconds", 0, "Maximum number of seconds between 2 retries.")
|
|
generateConfigCmd.Flags().Int32Var(&bfConfCliOptions.retryDelayFactor, "retry-delay-factor", 0, "Retry delay between two tries")
|
|
//invalidate-on-sync is always on - accept it as an arg and just ignore it
|
|
generateConfigCmd.Flags().Bool("invalidate-on-sync", true, "Invalidate file/dir on sync/fsync")
|
|
//pre-mount-validate is always on - accept it as an arg and just ignore it
|
|
generateConfigCmd.Flags().Bool("pre-mount-validate", true, "Validate blobfuse2 is mounted")
|
|
generateConfigCmd.Flags().BoolVar(&bfConfCliOptions.useStreaming, "streaming", false, "Enable Streaming.")
|
|
generateConfigCmd.Flags().Uint64Var(&bfConfCliOptions.streamCacheSize, "stream-cache-mb", 0, "Limit total amount of data being cached in memory to conserve memory footprint of blobfuse.")
|
|
generateConfigCmd.Flags().IntVar(&bfConfCliOptions.maxBlocksPerFile, "max-blocks-per-file", 0, "Maximum number of blocks to be cached in memory for streaming.")
|
|
generateConfigCmd.Flags().Uint64Var(&bfConfCliOptions.blockSize, "block-size-mb", 0, "Size (in MB) of a block to be downloaded during streaming.")
|
|
|
|
generateConfigCmd.Flags().StringSliceVarP(&libfuseOptions, "o", "o", []string{}, "FUSE options.")
|
|
generateConfigCmd.Flags().BoolVarP(&bfConfCliOptions.fuseLogging, "d", "d", false, "Mount with foreground and FUSE logs on.")
|
|
generateConfigCmd.Flags().BoolVar(&convertConfigOnly, "convert-config-only", false, "Don't mount - only convert v1 configuration to v2.")
|
|
generateConfigCmd.Flags().BoolVar(&bfConfCliOptions.ignoreOpenFlags, "ignore-open-flags", false, "Flag to ignore open flags unsupported by blobfuse.")
|
|
|
|
// options that are not available in V2:
|
|
generateConfigCmd.Flags().Bool("set-content-type", false, "Turns on automatic 'content-type' property based on the file extension.")
|
|
generateConfigCmd.Flags().String("ca-cert-file", "", "Specifies the proxy pem certificate path if its not in the default path.")
|
|
generateConfigCmd.Flags().Bool("basic-remount-check", false, "Check for an already mounted status using /etc/mtab.")
|
|
generateConfigCmd.Flags().Bool("background-download", false, "File download to run in the background on open call.")
|
|
generateConfigCmd.Flags().Uint64("cache-poll-timeout-msec", 0, "Time in milliseconds in order to poll for possible expired files awaiting cache eviction.")
|
|
generateConfigCmd.Flags().Bool("upload-modified-only", false, "Flag to turn off unnecessary uploads to storage.")
|
|
generateConfigCmd.Flags().Bool("debug-libcurl", false, "Flag to allow users to debug libcurl calls.")
|
|
|
|
// flags for gen1 mount
|
|
generateConfigCmd.Flags().BoolVar(&enableGen1, "enable-gen1", false, "To enable Gen1 mount")
|
|
generateConfigCmd.Flags().IntVar(&reqFreeSpaceMB, "required-free-space-mb", 0, "Required free space in MB")
|
|
}
|