// 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 !term.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 }
func promptForInsecureTLS(reader io.Reader, out io.Writer) bool { var input bool if term.IsTerminal(reader) { fmt.Fprintln(out, "The server uses a certificate signed by an unknown authority.") fmt.Fprintln(out, "You can bypass the certificate check, but any data you send to the server could be intercepted by others.") input = cmdutil.PromptForBool(os.Stdin, out, "Use insecure connections? (y/n): ") fmt.Fprintln(out) } return input }
// 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 = term.IsTerminal(o.In) } if len(args) < 1 { return kcmdutil.UsageError(cmd, "rsh requires a single Pod to connect to") } resource := 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 // TODO: Consider making the timeout configurable o.PodName, err = f.PodForResource(resource, 10*time.Second) return err }
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) && !term.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 }
func promptForInsecureTLS(reader io.Reader, out io.Writer, reason error) bool { var insecureTLSRequestReason string if reason != nil { switch reason.(type) { case x509.UnknownAuthorityError: insecureTLSRequestReason = "The server uses a certificate signed by an unknown authority." case x509.HostnameError: insecureTLSRequestReason = fmt.Sprintf("The server is using a certificate that does not match its hostname: %s", reason.Error()) case x509.CertificateInvalidError: insecureTLSRequestReason = fmt.Sprintf("The server is using an invalid certificate: %s", reason.Error()) } } var input bool if kterm.IsTerminal(reader) { if len(insecureTLSRequestReason) > 0 { fmt.Fprintln(out, insecureTLSRequestReason) } fmt.Fprintln(out, "You can bypass the certificate check, but any data you send to the server could be intercepted by others.") input = term.PromptForBool(os.Stdin, out, "Use insecure connections? (y/n): ") fmt.Fprintln(out) } return input }
func (o *DebugOptions) Complete(cmd *cobra.Command, f *clientcmd.Factory, args []string, in io.Reader, out, errout io.Writer) error { if i := cmd.ArgsLenAtDash(); i != -1 && i < len(args) { o.Command = args[i:] args = args[:i] } resources, envArgs, ok := cmdutil.SplitEnvironmentFromResources(args) if !ok { return kcmdutil.UsageError(cmd, "all resources must be specified before environment changes: %s", strings.Join(args, " ")) } switch { case o.ForceTTY && o.NoStdin: return kcmdutil.UsageError(cmd, "you may not specify -I and -t together") case o.ForceTTY && o.DisableTTY: return kcmdutil.UsageError(cmd, "you may not specify -t and -T together") case o.ForceTTY: o.Attach.TTY = true case o.DisableTTY: o.Attach.TTY = false // don't default TTY to true if a command is passed case len(o.Command) > 0: o.Attach.TTY = false o.Attach.Stdin = false default: o.Attach.TTY = term.IsTerminal(in) glog.V(4).Infof("Defaulting TTY to %t", o.Attach.TTY) } if o.NoStdin { o.Attach.TTY = false o.Attach.Stdin = false } if o.Annotations == nil { o.Annotations = make(map[string]string) } if len(o.Command) == 0 { o.Command = []string{"/bin/sh"} } cmdNamespace, explicit, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object(false) b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()). NamespaceParam(cmdNamespace).DefaultNamespace(). SingleResourceType(). ResourceNames("pods", resources...). Flatten() if len(o.Filename) > 0 { b.FilenameParam(explicit, false, o.Filename) } o.AddEnv, o.RemoveEnv, err = cmdutil.ParseEnv(envArgs, nil) if err != nil { return err } one := false infos, err := b.Do().IntoSingular(&one).Infos() if err != nil { return err } if !one { return fmt.Errorf("you must identify a resource with a pod template to debug") } template, err := f.ApproximatePodTemplateForObject(infos[0].Object) if err != nil && template == nil { return fmt.Errorf("cannot debug %s: %v", infos[0].Name, err) } if err != nil { glog.V(4).Infof("Unable to get exact template, but continuing with fallback: %v", err) } pod := &kapi.Pod{ ObjectMeta: template.ObjectMeta, Spec: template.Spec, } pod.Name, pod.Namespace = infos[0].Name, infos[0].Namespace o.Attach.Pod = pod o.AsNonRoot = !o.AsRoot && cmd.Flag("as-root").Changed if len(o.Attach.ContainerName) == 0 && len(pod.Spec.Containers) > 0 { glog.V(4).Infof("Defaulting container name to %s", pod.Spec.Containers[0].Name) o.Attach.ContainerName = pod.Spec.Containers[0].Name } o.Annotations[debugPodAnnotationSourceResource] = fmt.Sprintf("%s/%s", infos[0].Mapping.Resource, infos[0].Name) o.Annotations[debugPodAnnotationSourceContainer] = o.Attach.ContainerName output := kcmdutil.GetFlagString(cmd, "output") if len(output) != 0 { o.Print = func(pod *kapi.Pod, out io.Writer) error { return f.PrintObject(cmd, mapper, pod, out) } } config, err := f.ClientConfig() if err != nil { return err } o.Attach.Config = config _, kc, err := f.Clients() if err != nil { return err } o.Attach.Client = kc 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() (*restclient.Config, error) { if o.Config != nil { return o.Config, nil } if len(o.Server) == 0 { // we need to have a server to talk to if kterm.IsTerminal(o.Reader) { for !o.serverProvided() { defaultServer := defaultClusterURL promptMsg := fmt.Sprintf("Server [%s]: ", defaultServer) o.Server = term.PromptForStringWithDefault(o.Reader, o.Out, defaultServer, promptMsg) } } } clientConfig := &restclient.Config{} // 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 // use specified CA or find existing CA if len(o.CAFile) > 0 { clientConfig.CAFile = o.CAFile clientConfig.CAData = nil } else if caFile, caData, ok := findExistingClientCA(clientConfig.Host, *o.StartingKubeConfig); ok { clientConfig.CAFile = caFile clientConfig.CAData = caData } // try to TCP connect to the server to make sure it's reachable, and discover // about the need of certificates or insecure TLS if err := dialToServer(*clientConfig); err != nil { switch err.(type) { // certificate authority unknown, check or prompt if we want an insecure // connection or if we already have a cluster stanza that tells us to // connect to this particular server insecurely case x509.UnknownAuthorityError, x509.HostnameError, x509.CertificateInvalidError: if o.InsecureTLS || hasExistingInsecureCluster(*clientConfig, *o.StartingKubeConfig) || promptForInsecureTLS(o.Reader, o.Out, err) { clientConfig.Insecure = true clientConfig.CAFile = "" clientConfig.CAData = nil } else { return nil, clientcmd.GetPrettyErrorForServer(err, o.Server) } // TLS record header errors, like oversized record which usually means // the server only supports "http" case tls.RecordHeaderError: return nil, clientcmd.GetPrettyErrorForServer(err, o.Server) default: // suggest the port used in the cluster URL by default, in case we're not already using it host, port, parsed, err1 := getHostPort(o.Server) _, defaultClusterPort, _, err2 := getHostPort(defaultClusterURL) if err1 == nil && err2 == nil && port != defaultClusterPort { parsed.Host = net.JoinHostPort(host, defaultClusterPort) return nil, fmt.Errorf("%s\nYou may want to try using the default cluster port: %s", err.Error(), parsed.String()) } return nil, err } } // check for matching api version if !o.APIVersion.Empty() { clientConfig.GroupVersion = &o.APIVersion } o.Config = clientConfig return o.Config, 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() (*restclient.Config, error) { if o.Config != nil { return o.Config, nil } clientConfig := &restclient.Config{} if len(o.Server) == 0 { // we need to have a server to talk to if term.IsTerminal(o.Reader) { for !o.serverProvided() { defaultServer := defaultClusterURL promptMsg := fmt.Sprintf("Server [%s]: ", defaultServer) o.Server = cmdutil.PromptForStringWithDefault(o.Reader, o.Out, 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("/").Do() if result.Error() != nil { switch { case o.InsecureTLS: clientConfig.Insecure = true // insecure, clear CA info clientConfig.CAFile = "" clientConfig.CAData = nil // 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 term.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, o.Out, "Use insecure connections? (y/n): ") if !clientConfig.Insecure { return nil, fmt.Errorf(clientcmd.GetPrettyMessageFor(result.Error())) } // insecure, clear CA info clientConfig.CAFile = "" clientConfig.CAData = nil fmt.Fprintln(o.Out) } default: return nil, result.Error() } } // check for matching api version if !o.APIVersion.IsEmpty() { clientConfig.GroupVersion = &o.APIVersion } o.Config = clientConfig return o.Config, nil }
func readInput(r io.Reader) string { if kterm.IsTerminal(r) { return readInputFromTerminal(r) } return readInputFromReader(r) }