github.com/influxdata/telegraf@v1.30.3/cmd/telegraf/cmd_config.go (about) 1 // Command handling for configuration "config" command 2 package main 3 4 import ( 5 "errors" 6 "fmt" 7 "io" 8 "log" 9 "net/url" 10 "os" 11 "path/filepath" 12 13 "github.com/influxdata/telegraf" 14 "github.com/influxdata/telegraf/config" 15 "github.com/influxdata/telegraf/logger" 16 "github.com/influxdata/telegraf/migrations" 17 "github.com/urfave/cli/v2" 18 ) 19 20 func getConfigCommands(pluginFilterFlags []cli.Flag, outputBuffer io.Writer) []*cli.Command { 21 return []*cli.Command{ 22 { 23 Name: "config", 24 Usage: "commands for generating and migrating configurations", 25 Flags: pluginFilterFlags, 26 Action: func(cCtx *cli.Context) error { 27 // The sub_Filters are populated when the filter flags are set after the subcommand config 28 // e.g. telegraf config --section-filter inputs 29 filters := processFilterFlags(cCtx) 30 31 printSampleConfig(outputBuffer, filters) 32 return nil 33 }, 34 Subcommands: []*cli.Command{ 35 { 36 Name: "create", 37 Usage: "create a full sample configuration and show it", 38 Description: ` 39 The 'create' produces a full configuration containing all plugins as an example 40 and shows it on the console. You may apply 'section' or 'plugin' filtering 41 to reduce the output to the plugins you need 42 43 Create the full configuration 44 45 > telegraf config create 46 47 To produce a configuration only containing a Modbus input plugin and an 48 InfluxDB v2 output plugin use 49 50 > telegraf config create --section-filter "inputs:outputs" --input-filter "modbus" --output-filter "influxdb_v2" 51 `, 52 Flags: pluginFilterFlags, 53 Action: func(cCtx *cli.Context) error { 54 filters := processFilterFlags(cCtx) 55 56 printSampleConfig(outputBuffer, filters) 57 return nil 58 }, 59 }, 60 { 61 Name: "migrate", 62 Usage: "migrate deprecated plugins and options of the configuration(s)", 63 Description: ` 64 The 'migrate' command reads the configuration files specified via '--config' or 65 '--config-directory' and tries to migrate plugins or options that are currently 66 deprecated using the recommended replacements. If no configuration file is 67 explicitly specified the command reads the default locations and uses those 68 configuration files. Migrated files are stored with a '.migrated' suffix at the 69 location of the inputs. If you are migrating remote configurations the migrated 70 configurations is stored in the current directory using the filename of the URL 71 with a '.migrated' suffix. 72 It is highly recommended to test those migrated configurations before using 73 those files unattended! 74 75 To migrate the file 'mysettings.conf' use 76 77 > telegraf --config mysettings.conf config migrate 78 `, 79 Flags: []cli.Flag{ 80 &cli.BoolFlag{ 81 Name: "force", 82 Usage: "forces overwriting of an existing migration file", 83 }, 84 }, 85 Action: func(cCtx *cli.Context) error { 86 // Setup logging 87 telegraf.Debug = cCtx.Bool("debug") 88 logConfig := logger.LogConfig{Debug: telegraf.Debug} 89 if err := logger.SetupLogging(logConfig); err != nil { 90 return err 91 } 92 93 // Check if we have migrations at all. There might be 94 // none if you run a custom build without migrations 95 // enabled. 96 if len(migrations.PluginMigrations) == 0 { 97 return errors.New("no migrations available") 98 } 99 log.Printf("%d plugin migration(s) available", len(migrations.PluginMigrations)) 100 101 // Collect the given configuration files 102 configFiles := cCtx.StringSlice("config") 103 configDir := cCtx.StringSlice("config-directory") 104 for _, fConfigDirectory := range configDir { 105 files, err := config.WalkDirectory(fConfigDirectory) 106 if err != nil { 107 return err 108 } 109 configFiles = append(configFiles, files...) 110 } 111 112 // If no "config" or "config-directory" flag(s) was 113 // provided we should load default configuration files 114 if len(configFiles) == 0 { 115 paths, err := config.GetDefaultConfigPath() 116 if err != nil { 117 return err 118 } 119 configFiles = paths 120 } 121 122 for _, fn := range configFiles { 123 log.Printf("D! Trying to migrate %q...", fn) 124 125 // Read and parse the config file 126 data, remote, err := config.LoadConfigFile(fn) 127 if err != nil { 128 return fmt.Errorf("opening input %q failed: %w", fn, err) 129 } 130 131 out, applied, err := config.ApplyMigrations(data) 132 if err != nil { 133 return err 134 } 135 136 // Do not write a migration file if nothing was done 137 if applied == 0 { 138 log.Printf("I! No migration applied for %q", fn) 139 continue 140 } 141 142 // Construct the output filename 143 // For remote locations we just save the filename 144 // with the migrated suffix. 145 outfn := fn + ".migrated" 146 if remote { 147 u, err := url.Parse(fn) 148 if err != nil { 149 return fmt.Errorf("parsing remote config URL %q failed: %w", fn, err) 150 } 151 outfn = filepath.Base(u.Path) + ".migrated" 152 } 153 154 log.Printf("I! %d migration applied for %q, writing result as %q", applied, fn, outfn) 155 156 // Make sure the file does not exist yet if we should not overwrite 157 if !cCtx.Bool("force") { 158 if _, err := os.Stat(outfn); !errors.Is(err, os.ErrNotExist) { 159 return fmt.Errorf("output file %q already exists", outfn) 160 } 161 } 162 163 // Write the output file 164 if err := os.WriteFile(outfn, out, 0640); err != nil { 165 return fmt.Errorf("writing output %q failed: %w", outfn, err) 166 } 167 } 168 return nil 169 }, 170 }, 171 }, 172 }, 173 } 174 }