package main import ( "errors" "net/url" "path/filepath" "github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2/cmd/influx/config" "github.com/spf13/cobra" ) func cmdConfig(f *globalFlags, opt genericCLIOpts) *cobra.Command { builder := cmdConfigBuilder{ genericCLIOpts: opt, globalFlags: f, svcFn: newConfigService, } return builder.cmd() } type cmdConfigBuilder struct { genericCLIOpts *globalFlags name string url string token string active bool org string json bool hideHeaders bool svcFn func(path string) config.Service } func (b *cmdConfigBuilder) cmd() *cobra.Command { cmd := b.newCmd("config [config name]", b.cmdSwitchActiveRunEFn, false) cmd.Args = cobra.ArbitraryArgs cmd.Short = "Config management commands" cmd.Long = ` Providing no argument to the config command will print the active configuration. When an argument is provided, the active config will be switched to the config with a name matching that of the argument provided. Examples: # show active config influx config # set active config to previously active config influx config - # set active config influx config $CONFIG_NAME The influx config command displays the active InfluxDB connection configuration and manages multiple connection configurations stored, by default, in ~/.influxdbv2/configs. Each connection includes a URL, token, associated organization, and active setting. InfluxDB reads the token from the active connection configuration, so you don't have to manually enter a token to log into InfluxDB. For information about the config command, see https://v2.docs.influxdata.com/v2.0/reference/cli/influx/config ` b.registerFilepath(cmd) cmd.AddCommand( b.cmdCreate(), b.cmdDelete(), b.cmdUpdate(), b.cmdList(), ) return cmd } func (b *cmdConfigBuilder) cmdSwitchActiveRunEFn(cmd *cobra.Command, args []string) error { svc := b.newConfigSVC() if len(args) > 0 { cfg, err := svc.SwitchActive(args[0]) if err != nil { return err } return b.printConfigs(configPrintOpts{ config: cfg, }) } configs, err := svc.ListConfigs() if err != nil { return err } var active config.Config for _, cfg := range configs { if cfg.Active { active = cfg break } } if !active.Active { return nil } return b.printConfigs(configPrintOpts{ config: active, }) } func (b *cmdConfigBuilder) cmdCreate() *cobra.Command { cmd := b.newCmd("create", b.cmdCreateRunEFn, false) cmd.Short = "Create config" cmd.Long = ` The influx config create command creates a new InfluxDB connection configuration and stores it in the configs file (by default, stored at ~/.influxdbv2/configs). Examples: # create a config and set it active influx config create -a -n $CFG_NAME -u $HOST_URL -t $TOKEN -o $ORG_NAME # create a config and without setting it active influx config create -n $CFG_NAME -u $HOST_URL -t $TOKEN -o $ORG_NAME For information about the config command, see https://v2.docs.influxdata.com/v2.0/reference/cli/influx/config and https://v2.docs.influxdata.com/v2.0/reference/cli/influx/config/create` b.registerFilepath(cmd) b.registerPrintFlags(cmd) b.registerConfigSettingFlags(cmd) cmd.MarkFlagRequired("token") cmd.MarkFlagRequired("host-url") return cmd } func (b *cmdConfigBuilder) cmdCreateRunEFn(*cobra.Command, []string) error { svc := b.newConfigSVC() host, err := b.getValidHostURL() if err != nil { return err } cfg, err := svc.CreateConfig(config.Config{ Name: b.name, Host: host, Token: b.token, Org: b.org, Active: b.active, }) if err != nil { return err } return b.printConfigs(configPrintOpts{ config: cfg, }) } func (b *cmdConfigBuilder) cmdDelete() *cobra.Command { cmd := b.newCmd("rm [cfg_name]", b.cmdDeleteRunEFn, false) cmd.Aliases = []string{"delete", "remove"} cmd.Args = cobra.ArbitraryArgs cmd.Short = "Delete config" cmd.Long = ` The influx config delete command deletes an InfluxDB connection configuration from the configs file (by default, stored at ~/.influxdbv2/configs). Examples: # delete a config influx config rm $CFG_NAME # delete multiple configs influx config rm $CFG_NAME_1 $CFG_NAME_2 For information about the config command, see https://v2.docs.influxdata.com/v2.0/reference/cli/influx/config and https://v2.docs.influxdata.com/v2.0/reference/cli/influx/config/remove` b.registerPrintFlags(cmd) cmd.Flags().StringVarP(&b.name, "name", "n", "", "The config name (required)") cmd.Flags().MarkDeprecated("name", "provide the name as an arg; example: influx config rm $CFG_NAME") return cmd } func (b *cmdConfigBuilder) cmdDeleteRunEFn(cmd *cobra.Command, args []string) error { svc := b.newConfigSVC() deletedConfigs := make(config.Configs) for _, name := range append(args, b.name) { if name == "" { continue } cfg, err := svc.DeleteConfig(name) if influxdb.ErrorCode(err) == influxdb.ENotFound { continue } if err != nil { return err } deletedConfigs[name] = cfg } return b.printConfigs(configPrintOpts{ delete: true, configs: deletedConfigs, }) } func (b *cmdConfigBuilder) cmdUpdate() *cobra.Command { cmd := b.newCmd("set", b.cmdUpdateRunEFn, false) cmd.Aliases = []string{"update"} cmd.Short = "Update config" cmd.Long = ` The influx config set command updates information in an InfluxDB connection configuration in the configs file (by default, stored at ~/.influxdbv2/configs). Examples: # update a config and set active influx config set -a -n $CFG_NAME -u $HOST_URL -t $TOKEN -o $ORG_NAME # update a config and do not set to active influx config set -n $CFG_NAME -u $HOST_URL -t $TOKEN -o $ORG_NAME For information about the config command, see https://v2.docs.influxdata.com/v2.0/reference/cli/influx/config and https://v2.docs.influxdata.com/v2.0/reference/cli/influx/config/set` b.registerPrintFlags(cmd) b.registerConfigSettingFlags(cmd) return cmd } func (b *cmdConfigBuilder) cmdUpdateRunEFn(*cobra.Command, []string) error { var host string if b.url != "" { h, err := b.getValidHostURL() if err != nil { return err } host = h } cfg, err := b.newConfigSVC().UpdateConfig(config.Config{ Name: b.name, Host: host, Token: b.token, Org: b.org, Active: b.active, }) if err != nil { return err } return b.printConfigs(configPrintOpts{ config: cfg, }) } func (b *cmdConfigBuilder) cmdList() *cobra.Command { cmd := b.newCmd("ls", b.cmdListRunEFn, false) cmd.Aliases = []string{"list"} cmd.Short = "List configs" cmd.Long = ` The influx config ls command lists all InfluxDB connection configurations in the configs file (by default, stored at ~/.influxdbv2/configs). Each connection configuration includes a URL, authentication token, and active setting. An asterisk (*) indicates the active configuration. Examples: # list configs influx config ls # list configs with long alias influx config list For information about the config command, see https://v2.docs.influxdata.com/v2.0/reference/cli/influx/config and https://v2.docs.influxdata.com/v2.0/reference/cli/influx/config/list` b.registerPrintFlags(cmd) return cmd } func (b *cmdConfigBuilder) cmdListRunEFn(*cobra.Command, []string) error { cfgs, err := b.newConfigSVC().ListConfigs() if err != nil { return err } return b.printConfigs(configPrintOpts{configs: cfgs}) } func (b *cmdConfigBuilder) registerConfigSettingFlags(cmd *cobra.Command) { cmd.Flags().StringVarP(&b.name, "config-name", "n", "", "The config name (required)") // name is required everywhere cmd.MarkFlagRequired("config-name") cmd.Flags().BoolVarP(&b.active, "active", "a", false, "Set as active config") cmd.Flags().StringVarP(&b.url, "host-url", "u", "", "The host url (required)") cmd.Flags().StringVarP(&b.org, "org", "o", "", "The optional organization name") cmd.Flags().StringVarP(&b.token, "token", "t", "", "The token for host (required)") // deprecated moving forward, not explicit enough based on feedback // the short flags will still be respected but their long form is different. cmd.Flags().StringVar(&b.name, "name", "", "The config name (required)") cmd.Flags().MarkDeprecated("name", "use the --config-name flag") cmd.Flags().StringVar(&b.url, "url", "", "The host url (required)") cmd.Flags().MarkDeprecated("url", "use the --host-url flag") } func (b *cmdConfigBuilder) registerFilepath(cmd *cobra.Command) { b.globalFlags.registerFlags(cmd, "host", "token", "skip-verify", "trace-debug-id") } func (b *cmdConfigBuilder) registerPrintFlags(cmd *cobra.Command) { registerPrintOptions(cmd, &b.hideHeaders, &b.json) } func (b *cmdConfigBuilder) printConfigs(opts configPrintOpts) error { if b.json { var v interface{} = opts.configs if opts.configs == nil { v = opts.config } return b.writeJSON(v) } w := b.newTabWriter() defer w.Flush() w.HideHeaders(b.hideHeaders) headers := []string{"Active", "Name", "URL", "Org"} if opts.delete { headers = append(headers, "Deleted") } w.WriteHeaders(headers...) if opts.configs == nil { opts.configs = config.Configs{ opts.config.Name: opts.config, } } for _, c := range opts.configs { var active string if c.Active { active = "*" } m := map[string]interface{}{ "Active": active, "Name": c.Name, "URL": c.Host, "Org": c.Org, } if opts.delete { m["Deleted"] = true } w.Write(m) } return nil } func (b *cmdConfigBuilder) getValidHostURL() (string, error) { u, err := url.Parse(b.url) if err != nil { return "", err } if u.Scheme != "http" && u.Scheme != "https" { return "", errors.New("a scheme of HTTP(S) must be provided for host url") } return u.String(), nil } func (b *cmdConfigBuilder) newConfigSVC() config.Service { return b.svcFn(b.globalFlags.filepath) } func newConfigService(path string) config.Service { return config.NewLocalConfigSVC(path, filepath.Dir(path)) } type configPrintOpts struct { delete bool config config.Config configs config.Configs }