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  }