// Validate check if all necessary fields from CreateBasicAuthSecretOptions are present. func (o CreateBasicAuthSecretOptions) Validate() error { if len(o.SecretName) == 0 { return errors.New("basic authentication secret name must be present") } if o.PromptForPassword { if len(o.Password) != 0 { return errors.New("must provide either --prompt or --password flag") } if cmdutil.IsTerminal(o.Reader) { o.Password = cmdutil.PromptForPasswordString(o.Reader, o.Out, "Password: "******"password must be provided") } } else { return errors.New("provided reader is not a terminal") } } else { if len(o.Username) == 0 && len(o.Password) == 0 && len(o.CertificatePath) == 0 { return errors.New("must provide basic authentication credentials") } } return nil }
// Complete fills CreateBasicAuthSecretOptions fields with data and checks for mutual exclusivity // between flags from different option groups. func (o *CreateBasicAuthSecretOptions) Complete(f *kcmdutil.Factory, args []string) error { if len(args) != 1 { return errors.New("must have exactly one argument: secret name") } o.SecretName = args[0] if o.PromptForPassword { if len(o.Password) != 0 { return errors.New("must provide either --prompt or --password flag") } if !cmdutil.IsTerminal(o.Reader) { return errors.New("provided reader is not a terminal") } o.Password = cmdutil.PromptForPasswordString(o.Reader, o.Out, "Password: "******"password must be provided") } } if f != nil { client, err := f.Client() if err != nil { return err } namespace, _, err := f.DefaultNamespace() if err != nil { return err } o.SecretsInterface = client.Secrets(namespace) } return nil }
// NewCmdRsh attempts to open a shell session to the server. func NewCmdRsh(fullName string, f *clientcmd.Factory, in io.Reader, out, err io.Writer) *cobra.Command { options := &kubecmd.ExecOptions{ In: in, Out: out, Err: err, TTY: true, Stdin: true, Executor: &kubecmd.DefaultRemoteExecutor{}, } executable := "/bin/bash" forceTTY, disableTTY := false, false cmd := &cobra.Command{ Use: "rsh POD [command]", Short: "Start a shell session in a pod", Long: fmt.Sprintf(rshLong, fullName), Example: fmt.Sprintf(rshExample, fullName), Run: func(cmd *cobra.Command, args []string) { switch { case forceTTY && disableTTY: kcmdutil.CheckErr(kcmdutil.UsageError(cmd, "you may not specify -t and -T together")) case forceTTY: options.TTY = true case disableTTY: options.TTY = false default: options.TTY = cmdutil.IsTerminal(in) } if len(args) < 1 { kcmdutil.CheckErr(kcmdutil.UsageError(cmd, "rsh requires a single Pod to connect to")) } options.PodName = args[0] args = args[1:] if len(args) > 0 { options.Command = args } else { options.Command = []string{executable} } kcmdutil.CheckErr(RunRsh(options, f, cmd, args)) }, } cmd.Flags().BoolVarP(&forceTTY, "tty", "t", false, "Force a pseudo-terminal to be allocated") cmd.Flags().BoolVarP(&disableTTY, "no-tty", "T", false, "Disable pseudo-terminal allocation") cmd.Flags().StringVar(&executable, "shell", executable, "Path to shell command") cmd.Flags().StringVarP(&options.ContainerName, "container", "c", "", "Container name; defaults to first container") cmd.Flags().SetInterspersed(false) return cmd }
// Complete applies the command environment to RshOptions func (o *RshOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string) error { switch { case o.ForceTTY && o.DisableTTY: return kcmdutil.UsageError(cmd, "you may not specify -t and -T together") case o.ForceTTY: o.TTY = true case o.DisableTTY: o.TTY = false default: o.TTY = cmdutil.IsTerminal(o.In) } if len(args) < 1 { return kcmdutil.UsageError(cmd, "rsh requires a single Pod to connect to") } o.PodName = args[0] args = args[1:] if len(args) > 0 { o.Command = args } else { o.Command = []string{o.Executable} } namespace, _, err := f.DefaultNamespace() if err != nil { return err } o.Namespace = namespace config, err := f.ClientConfig() if err != nil { return err } o.Config = config client, err := f.Client() if err != nil { return err } o.Client = client return nil }
func (o LoginOptions) Validate(args []string, serverFlag string) error { if len(args) > 1 { return errors.New("Only the server URL may be specified as an argument") } if (len(serverFlag) > 0) && (len(args) == 1) { return errors.New("--server and passing the server URL as an argument are mutually exclusive") } if (len(o.Server) == 0) && !cmdutil.IsTerminal(o.Reader) { return errors.New("A server URL must be specified") } if len(o.Username) > 0 && len(o.Token) > 0 { return errors.New("--token and --username are mutually exclusive") } if o.StartingKubeConfig == nil { return errors.New("Must have a config file already created") } return nil }
// getClientConfig returns back the current clientConfig as we know it. If there is no clientConfig, it builds one with enough information // to talk to a server. This may involve user prompts. This method is not threadsafe. func (o *LoginOptions) getClientConfig() (*kclient.Config, error) { if o.Config != nil { return o.Config, nil } clientConfig := &kclient.Config{} if len(o.Server) == 0 { // we need to have a server to talk to if cmdutil.IsTerminal(o.Reader) { for !o.serverProvided() { defaultServer := defaultClusterURL promptMsg := fmt.Sprintf("Server [%s]: ", defaultServer) o.Server = cmdutil.PromptForStringWithDefault(o.Reader, defaultServer, promptMsg) } } } // normalize the provided server to a format expected by config serverNormalized, err := config.NormalizeServerURL(o.Server) if err != nil { return nil, err } o.Server = serverNormalized clientConfig.Host = o.Server if len(o.CAFile) > 0 { clientConfig.CAFile = o.CAFile } else { // check all cluster stanzas to see if we already have one with this URL that contains a client cert for _, cluster := range o.StartingKubeConfig.Clusters { if cluster.Server == clientConfig.Host { if len(cluster.CertificateAuthority) > 0 { clientConfig.CAFile = cluster.CertificateAuthority break } if len(cluster.CertificateAuthorityData) > 0 { clientConfig.CAData = cluster.CertificateAuthorityData break } } } } // ping to check if server is reachable osClient, err := client.New(clientConfig) if err != nil { return nil, err } result := osClient.Get().AbsPath("/osapi").Do() if result.Error() != nil { switch { case o.InsecureTLS: clientConfig.Insecure = true // certificate issue, prompt user for insecure connection case clientcmd.IsCertificateAuthorityUnknown(result.Error()): // check to see if we already have a cluster stanza that tells us to use --insecure for this particular server. If we don't, then prompt clientConfigToTest := *clientConfig clientConfigToTest.Insecure = true matchingClusters := getMatchingClusters(clientConfigToTest, *o.StartingKubeConfig) if len(matchingClusters) > 0 { clientConfig.Insecure = true } else if cmdutil.IsTerminal(o.Reader) { fmt.Fprintln(o.Out, "The server uses a certificate signed by an unknown authority.") fmt.Fprintln(o.Out, "You can bypass the certificate check, but any data you send to the server could be intercepted by others.") clientConfig.Insecure = cmdutil.PromptForBool(os.Stdin, "Use insecure connections? (y/n): ") if !clientConfig.Insecure { return nil, fmt.Errorf(clientcmd.GetPrettyMessageFor(result.Error())) } fmt.Fprintln(o.Out) } default: return nil, result.Error() } } // check for matching api version if len(o.APIVersion) > 0 { clientConfig.Version = o.APIVersion } o.Config = clientConfig return o.Config, nil }
// Negotiate a bearer token with the auth server, or try to reuse one based on the // information already present. In case of any missing information, ask for user input // (usually username and password, interactive depending on the Reader). func (o *LoginOptions) gatherAuthInfo() error { directClientConfig, err := o.getClientConfig() if err != nil { return err } // make a copy and use it to avoid mutating the original t := *directClientConfig clientConfig := &t // if a token were explicitly provided, try to use it if o.tokenProvided() { clientConfig.BearerToken = o.Token if osClient, err := client.New(clientConfig); err == nil { me, err := whoAmI(osClient) if err == nil { o.Username = me.Name o.Config = clientConfig fmt.Fprintf(o.Out, "Logged into %q as %q using the token provided.\n\n", o.Config.Host, o.Username) return nil } if !kerrors.IsUnauthorized(err) { return err } fmt.Fprintln(o.Out, "The token provided is invalid (probably expired).\n") } } // if a token was provided try to make use of it // make sure we have a username before continuing if !o.usernameProvided() { if cmdutil.IsTerminal(o.Reader) { for !o.usernameProvided() { o.Username = cmdutil.PromptForString(o.Reader, "Username: "******"Already logged into %q as %q.\n\n", o.Config.Host, o.Username) } return nil } } } } } // if kubeconfig doesn't already have a matching user stanza... clientConfig.BearerToken = "" clientConfig.CertData = []byte{} clientConfig.KeyData = []byte{} clientConfig.CertFile = o.CertFile clientConfig.KeyFile = o.KeyFile token, err := tokencmd.RequestToken(o.Config, o.Reader, o.Username, o.Password) if err != nil { return err } clientConfig.BearerToken = token osClient, err := client.New(clientConfig) if err != nil { return err } me, err := whoAmI(osClient) if err != nil { return err } o.Username = me.Name o.Config = clientConfig fmt.Fprintln(o.Out, "Login successful.\n") return nil }