package clientcmd import ( "crypto/x509" "errors" "fmt" "strings" kerrors "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" ) const ( unknownReason = iota noServerFoundReason certificateAuthorityUnknownReason certificateHostnameErrorReason certificateInvalidReason configurationInvalidReason tlsOversizedRecordReason certificateAuthorityUnknownMsg = "The server uses a certificate signed by unknown authority. You may need to use the --certificate-authority flag to provide the path to a certificate file for the certificate authority, or --insecure-skip-tls-verify to bypass the certificate check and use insecure connections." notConfiguredMsg = `The client is not configured. You need to run the login command in order to create a default config for your server and credentials: oc login You can also run this command again providing the path to a config file directly, either through the --config flag of the KUBECONFIG environment variable. ` tlsOversizedRecordMsg = `Unable to connect to %[2]s using TLS: %[1]s. Ensure the specified server supports HTTPS.` ) // GetPrettyMessageFor prettifys the message of the provided error func GetPrettyMessageFor(err error) string { return GetPrettyMessageForServer(err, "") } // GetPrettyMessageForServer prettifys the message of the provided error func GetPrettyMessageForServer(err error, serverName string) string { if err == nil { return "" } reason := detectReason(err) switch reason { case noServerFoundReason: return notConfiguredMsg case certificateAuthorityUnknownReason: return certificateAuthorityUnknownMsg case tlsOversizedRecordReason: if len(serverName) == 0 { serverName = "server" } return fmt.Sprintf(tlsOversizedRecordMsg, err, serverName) case certificateHostnameErrorReason: return fmt.Sprintf("The server is using a certificate that does not match its hostname: %s", err) case certificateInvalidReason: return fmt.Sprintf("The server is using an invalid certificate: %s", err) } return err.Error() } // GetPrettyErrorFor prettifys the message of the provided error func GetPrettyErrorFor(err error) error { return GetPrettyErrorForServer(err, "") } // GetPrettyErrorForServer prettifys the message of the provided error func GetPrettyErrorForServer(err error, serverName string) error { return errors.New(GetPrettyMessageForServer(err, serverName)) } // IsNoServerFound checks whether the provided error is a 'no server found' error or not func IsNoServerFound(err error) bool { return detectReason(err) == noServerFoundReason } // IsConfigurationInvalid checks whether the provided error is a 'invalid configuration' error or not func IsConfigurationInvalid(err error) bool { return detectReason(err) == configurationInvalidReason } // IsCertificateAuthorityUnknown checks whether the provided error is a 'certificate authority unknown' error or not func IsCertificateAuthorityUnknown(err error) bool { return detectReason(err) == certificateAuthorityUnknownReason } // IsForbidden checks whether the provided error is a 'forbidden' error or not func IsForbidden(err error) bool { return kerrors.IsForbidden(err) } // IsTLSOversizedRecord checks whether the provided error is a url.Error // with "tls: oversized record received", which usually means TLS not supported. func IsTLSOversizedRecord(err error) bool { return detectReason(err) == tlsOversizedRecordReason } // IsCertificateHostnameError checks whether the set of authorized names doesn't match the requested name func IsCertificateHostnameError(err error) bool { return detectReason(err) == certificateHostnameErrorReason } // IsCertificateInvalid checks whether the certificate is invalid for reasons like expired, CA not authorized // to sign, there are too many cert intermediates, or the cert usage is not valid for the wanted purpose. func IsCertificateInvalid(err error) bool { return detectReason(err) == certificateInvalidReason } func detectReason(err error) int { if err != nil { switch { case strings.Contains(err.Error(), "certificate signed by unknown authority"): return certificateAuthorityUnknownReason case strings.Contains(err.Error(), "no server defined"): return noServerFoundReason case clientcmd.IsConfigurationInvalid(err): return configurationInvalidReason case strings.Contains(err.Error(), "tls: oversized record received"): return tlsOversizedRecordReason } switch err.(type) { case x509.UnknownAuthorityError: return certificateAuthorityUnknownReason case x509.HostnameError: return certificateHostnameErrorReason case x509.CertificateInvalidError: return certificateInvalidReason } } return unknownReason }