123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- // Copyright 2015 The etcd Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package command
- import (
- "crypto/tls"
- "errors"
- "io"
- "io/ioutil"
- "os"
- "strings"
- "time"
- "github.com/bgentry/speakeasy"
- "github.com/coreos/etcd/clientv3"
- "github.com/coreos/etcd/pkg/flags"
- "github.com/coreos/etcd/pkg/transport"
- "github.com/spf13/cobra"
- "google.golang.org/grpc/grpclog"
- )
- // GlobalFlags are flags that defined globally
- // and are inherited to all sub-commands.
- type GlobalFlags struct {
- Insecure bool
- InsecureSkipVerify bool
- Endpoints []string
- DialTimeout time.Duration
- CommandTimeOut time.Duration
- TLS transport.TLSInfo
- OutputFormat string
- IsHex bool
- User string
- Debug bool
- }
- type secureCfg struct {
- cert string
- key string
- cacert string
- insecureTransport bool
- insecureSkipVerify bool
- }
- type authCfg struct {
- username string
- password string
- }
- var display printer = &simplePrinter{}
- func initDisplayFromCmd(cmd *cobra.Command) {
- isHex, err := cmd.Flags().GetBool("hex")
- if err != nil {
- ExitWithError(ExitError, err)
- }
- outputType, err := cmd.Flags().GetString("write-out")
- if err != nil {
- ExitWithError(ExitError, err)
- }
- if display = NewPrinter(outputType, isHex); display == nil {
- ExitWithError(ExitBadFeature, errors.New("unsupported output format"))
- }
- }
- func mustClientFromCmd(cmd *cobra.Command) *clientv3.Client {
- flags.SetPflagsFromEnv("ETCDCTL", cmd.InheritedFlags())
- debug, derr := cmd.Flags().GetBool("debug")
- if derr != nil {
- ExitWithError(ExitError, derr)
- }
- if debug {
- clientv3.SetLogger(grpclog.NewLoggerV2WithVerbosity(os.Stderr, os.Stderr, os.Stderr, 4))
- } else {
- clientv3.SetLogger(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, ioutil.Discard))
- }
- endpoints, err := cmd.Flags().GetStringSlice("endpoints")
- if err != nil {
- ExitWithError(ExitError, err)
- }
- dialTimeout := dialTimeoutFromCmd(cmd)
- sec := secureCfgFromCmd(cmd)
- auth := authCfgFromCmd(cmd)
- initDisplayFromCmd(cmd)
- return mustClient(endpoints, dialTimeout, sec, auth)
- }
- func mustClient(endpoints []string, dialTimeout time.Duration, scfg *secureCfg, acfg *authCfg) *clientv3.Client {
- cfg, err := newClientCfg(endpoints, dialTimeout, scfg, acfg)
- if err != nil {
- ExitWithError(ExitBadArgs, err)
- }
- client, err := clientv3.New(*cfg)
- if err != nil {
- ExitWithError(ExitBadConnection, err)
- }
- return client
- }
- func newClientCfg(endpoints []string, dialTimeout time.Duration, scfg *secureCfg, acfg *authCfg) (*clientv3.Config, error) {
- // set tls if any one tls option set
- var cfgtls *transport.TLSInfo
- tlsinfo := transport.TLSInfo{}
- if scfg.cert != "" {
- tlsinfo.CertFile = scfg.cert
- cfgtls = &tlsinfo
- }
- if scfg.key != "" {
- tlsinfo.KeyFile = scfg.key
- cfgtls = &tlsinfo
- }
- if scfg.cacert != "" {
- tlsinfo.CAFile = scfg.cacert
- cfgtls = &tlsinfo
- }
- cfg := &clientv3.Config{
- Endpoints: endpoints,
- DialTimeout: dialTimeout,
- }
- if cfgtls != nil {
- clientTLS, err := cfgtls.ClientConfig()
- if err != nil {
- return nil, err
- }
- cfg.TLS = clientTLS
- }
- // if key/cert is not given but user wants secure connection, we
- // should still setup an empty tls configuration for gRPC to setup
- // secure connection.
- if cfg.TLS == nil && !scfg.insecureTransport {
- cfg.TLS = &tls.Config{}
- }
- // If the user wants to skip TLS verification then we should set
- // the InsecureSkipVerify flag in tls configuration.
- if scfg.insecureSkipVerify && cfg.TLS != nil {
- cfg.TLS.InsecureSkipVerify = true
- }
- if acfg != nil {
- cfg.Username = acfg.username
- cfg.Password = acfg.password
- }
- return cfg, nil
- }
- func argOrStdin(args []string, stdin io.Reader, i int) (string, error) {
- if i < len(args) {
- return args[i], nil
- }
- bytes, err := ioutil.ReadAll(stdin)
- if string(bytes) == "" || err != nil {
- return "", errors.New("no available argument and stdin")
- }
- return string(bytes), nil
- }
- func dialTimeoutFromCmd(cmd *cobra.Command) time.Duration {
- dialTimeout, err := cmd.Flags().GetDuration("dial-timeout")
- if err != nil {
- ExitWithError(ExitError, err)
- }
- return dialTimeout
- }
- func secureCfgFromCmd(cmd *cobra.Command) *secureCfg {
- cert, key, cacert := keyAndCertFromCmd(cmd)
- insecureTr := insecureTransportFromCmd(cmd)
- skipVerify := insecureSkipVerifyFromCmd(cmd)
- return &secureCfg{
- cert: cert,
- key: key,
- cacert: cacert,
- insecureTransport: insecureTr,
- insecureSkipVerify: skipVerify,
- }
- }
- func insecureTransportFromCmd(cmd *cobra.Command) bool {
- insecureTr, err := cmd.Flags().GetBool("insecure-transport")
- if err != nil {
- ExitWithError(ExitError, err)
- }
- return insecureTr
- }
- func insecureSkipVerifyFromCmd(cmd *cobra.Command) bool {
- skipVerify, err := cmd.Flags().GetBool("insecure-skip-tls-verify")
- if err != nil {
- ExitWithError(ExitError, err)
- }
- return skipVerify
- }
- func keyAndCertFromCmd(cmd *cobra.Command) (cert, key, cacert string) {
- var err error
- if cert, err = cmd.Flags().GetString("cert"); err != nil {
- ExitWithError(ExitBadArgs, err)
- } else if cert == "" && cmd.Flags().Changed("cert") {
- ExitWithError(ExitBadArgs, errors.New("empty string is passed to --cert option"))
- }
- if key, err = cmd.Flags().GetString("key"); err != nil {
- ExitWithError(ExitBadArgs, err)
- } else if key == "" && cmd.Flags().Changed("key") {
- ExitWithError(ExitBadArgs, errors.New("empty string is passed to --key option"))
- }
- if cacert, err = cmd.Flags().GetString("cacert"); err != nil {
- ExitWithError(ExitBadArgs, err)
- } else if cacert == "" && cmd.Flags().Changed("cacert") {
- ExitWithError(ExitBadArgs, errors.New("empty string is passed to --cacert option"))
- }
- return cert, key, cacert
- }
- func authCfgFromCmd(cmd *cobra.Command) *authCfg {
- userFlag, err := cmd.Flags().GetString("user")
- if err != nil {
- ExitWithError(ExitBadArgs, err)
- }
- if userFlag == "" {
- return nil
- }
- var cfg authCfg
- splitted := strings.SplitN(userFlag, ":", 2)
- if len(splitted) < 2 {
- cfg.username = userFlag
- cfg.password, err = speakeasy.Ask("Password: ")
- if err != nil {
- ExitWithError(ExitError, err)
- }
- } else {
- cfg.username = splitted[0]
- cfg.password = splitted[1]
- }
- return &cfg
- }
|