diff --git a/go.mod b/go.mod index faffe78a45..1165d9a62b 100644 --- a/go.mod +++ b/go.mod @@ -29,10 +29,11 @@ require ( github.com/moby/buildkit v0.0.0-20181107081847-c3a857e3fca0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 - github.com/openshift/api v0.0.0-20230120195050-6ba31fa438f2 + github.com/openshift/api v0.0.0-20230330150608-05635858d40f github.com/openshift/build-machinery-go v0.0.0-20220913142420-e25cf57ea46d github.com/openshift/client-go v0.0.0-20230120202327-72f107311084 - github.com/openshift/library-go v0.0.0-20230227140230-39892725eed1 + github.com/openshift/library-go v0.0.0-20231115094609-5e510a6e9a52 + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 github.com/russross/blackfriday v1.6.0 diff --git a/go.sum b/go.sum index 11140726e2..09c3b3a02e 100644 --- a/go.sum +++ b/go.sum @@ -1082,16 +1082,16 @@ github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3 github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/openshift/api v0.0.0-20230120195050-6ba31fa438f2 h1:+nw0/d4spq880W7S74Twi5YU2ulsl3/a9o4OEZptYp0= -github.com/openshift/api v0.0.0-20230120195050-6ba31fa438f2/go.mod h1:ctXNyWanKEjGj8sss1KjjHQ3ENKFm33FFnS5BKaIPh4= +github.com/openshift/api v0.0.0-20230330150608-05635858d40f h1:mGpCtfoehMcvmg/sSYLiv6nCbTl04cmtkUfYzP7H1AQ= +github.com/openshift/api v0.0.0-20230330150608-05635858d40f/go.mod h1:ctXNyWanKEjGj8sss1KjjHQ3ENKFm33FFnS5BKaIPh4= github.com/openshift/build-machinery-go v0.0.0-20220913142420-e25cf57ea46d h1:RR4ah7FfaPR1WePizm0jlrsbmPu91xQZnAsVVreQV1k= github.com/openshift/build-machinery-go v0.0.0-20220913142420-e25cf57ea46d/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= github.com/openshift/client-go v0.0.0-20230120202327-72f107311084 h1:66uaqNwA+qYyQDwsMWUfjjau8ezmg1dzCqub13KZOcE= github.com/openshift/client-go v0.0.0-20230120202327-72f107311084/go.mod h1:M3h9m001PWac3eAudGG3isUud6yBjr5XpzLYLLTlHKo= github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b h1:it0YPE/evO6/m8t8wxis9KFI2F/aleOKsI6d9uz0cEk= github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b/go.mod h1:tNrEB5k8SI+g5kOlsCmL2ELASfpqEofI0+FLBgBdN08= -github.com/openshift/library-go v0.0.0-20230227140230-39892725eed1 h1:G7ynzkST2dNwSueO7GIJbZ9BLQnffwDJV85D8YHVSFA= -github.com/openshift/library-go v0.0.0-20230227140230-39892725eed1/go.mod h1:xO4nAf0qa56dgvEJWVD1WuwSJ8JWPU1TYLBQrlutWnE= +github.com/openshift/library-go v0.0.0-20231115094609-5e510a6e9a52 h1:qP0GMFLjUeviPIjLaynal3LYfKQUMpvsQnRYFNputIU= +github.com/openshift/library-go v0.0.0-20231115094609-5e510a6e9a52/go.mod h1:tedJaJsajpyrlPVNoSfjOst6w2HHvvR4VPqKWeZzrbY= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -1107,6 +1107,8 @@ github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1675,6 +1677,7 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/pkg/cli/login/login.go b/pkg/cli/login/login.go index 5b4339ea8c..96cc1dbe81 100644 --- a/pkg/cli/login/login.go +++ b/pkg/cli/login/login.go @@ -16,8 +16,8 @@ import ( "k8s.io/kubectl/pkg/util/templates" "k8s.io/kubectl/pkg/util/term" + "github.com/openshift/library-go/pkg/oauth/tokenrequest" "github.com/openshift/oc/pkg/helpers/flagtypes" - "github.com/openshift/oc/pkg/helpers/tokencmd" ) var ( @@ -31,7 +31,8 @@ var ( The information required to login -- like username and password, a session token, or the server details -- can be provided through flags. If not provided, the command will - prompt for user input as needed. + prompt for user input as needed. It is also possible to login through a web browser by + providing the respective flag. `) loginExample = templates.Examples(` @@ -43,6 +44,9 @@ var ( # Log in to the given server with the given credentials (will not prompt interactively) oc login localhost:8443 --username=myuser --password=mypass + + # Log in to the given server through a browser + oc login --web --callback-port 8280 localhost:8443 `) ) @@ -60,7 +64,7 @@ func NewCmdLogin(f kcmdutil.Factory, streams genericclioptions.IOStreams) *cobra if err := o.Run(); kapierrors.IsUnauthorized(err) { if err, isStatusErr := err.(*kapierrors.StatusError); isStatusErr { - if err.Status().Message != tokencmd.BasicAuthNoUsernameMessage { + if err.Status().Message != tokenrequest.BasicAuthNoUsernameMessage { fmt.Fprintln(streams.Out, "Login failed (401 Unauthorized)") fmt.Fprintln(streams.Out, "Verify you have provided the correct credentials.") } @@ -83,6 +87,8 @@ func NewCmdLogin(f kcmdutil.Factory, streams genericclioptions.IOStreams) *cobra cmds.Flags().StringVarP(&o.Username, "username", "u", o.Username, "Username for server") cmds.Flags().StringVarP(&o.Password, "password", "p", o.Password, "Password for server") + cmds.Flags().BoolVarP(&o.WebLogin, "web", "w", o.WebLogin, "Login with web browser") + cmds.Flags().Int32VarP(&o.CallbackPort, "callback-port", "c", o.CallbackPort, "Port for the callback server when using --web. Defaults to a random open port") return cmds } @@ -167,10 +173,18 @@ func (o LoginOptions) Validate(cmd *cobra.Command, serverFlag string, args []str return errors.New("Must have a config file already created") } + if o.WebLogin && (o.Username != "" || o.Password != "" || o.Token != "") { + return errors.New("--web cannot be used along with --username, --password or --token") + } + + if o.CallbackPort != 0 && !o.WebLogin { + return errors.New("--callback-port can only be specified along with --web") + } + return nil } -// RunLogin contains all the necessary functionality for the OpenShift cli login command +// Run contains all the necessary functionality for the OpenShift cli login command func (o LoginOptions) Run() error { if err := o.GatherInfo(); err != nil { return err diff --git a/pkg/cli/login/loginoptions.go b/pkg/cli/login/loginoptions.go index cf4a007f61..46fb63b296 100644 --- a/pkg/cli/login/loginoptions.go +++ b/pkg/cli/login/loginoptions.go @@ -6,7 +6,9 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "io" "net" + "net/url" "os" "path/filepath" "time" @@ -19,16 +21,21 @@ import ( restclient "k8s.io/client-go/rest" kclientcmd "k8s.io/client-go/tools/clientcmd" kclientcmdapi "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/klog/v2" kterm "k8s.io/kubectl/pkg/util/term" projectv1typedclient "github.com/openshift/client-go/project/clientset/versioned/typed/project/v1" + "github.com/openshift/library-go/pkg/oauth/tokenrequest" + "github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers" + occhallengers "github.com/openshift/oc/pkg/helpers/authchallengers" "github.com/openshift/oc/pkg/helpers/errors" cliconfig "github.com/openshift/oc/pkg/helpers/kubeconfig" "github.com/openshift/oc/pkg/helpers/motd" "github.com/openshift/oc/pkg/helpers/project" loginutil "github.com/openshift/oc/pkg/helpers/project" "github.com/openshift/oc/pkg/helpers/term" - "github.com/openshift/oc/pkg/helpers/tokencmd" + "github.com/openshift/oc/pkg/version" + "github.com/pkg/browser" ) const defaultClusterURL = "https://localhost:8443" @@ -47,9 +54,11 @@ type LoginOptions struct { InsecureTLS bool // flags and printing helpers - Username string - Password string - Project string + Username string + Password string + Project string + WebLogin bool + CallbackPort int32 // infra StartingKubeConfig *kclientcmdapi.Config @@ -70,6 +79,12 @@ type LoginOptions struct { genericclioptions.IOStreams } +type passwordPrompter func(r io.Reader, w io.Writer, format string, a ...interface{}) string + +func (p passwordPrompter) PromptForPassword(r io.Reader, w io.Writer, format string, a ...interface{}) string { + return p(r, w, format, a) +} + func NewLoginOptions(streams genericclioptions.IOStreams) *LoginOptions { return &LoginOptions{ IOStreams: streams, @@ -246,10 +261,21 @@ func (o *LoginOptions) gatherAuthInfo() error { clientConfig.CertFile = o.CertFile clientConfig.KeyFile = o.KeyFile - token, err := tokencmd.RequestToken(o.Config, o.In, o.Username, o.Password) + var token string + if o.WebLogin { + loginURLHandler := func(u *url.URL) error { + loginURL := u.String() + fmt.Fprintf(o.Out, "Opening login URL in the default browser: %s\n", loginURL) + return browser.OpenURL(loginURL) + } + token, err = tokenrequest.RequestTokenWithLocalCallback(o.Config, loginURLHandler, int(o.CallbackPort)) + } else { + token, err = tokenrequest.RequestTokenWithChallengeHandlers(o.Config, o.getAuthChallengeHandler()) + } if err != nil { return err } + clientConfig.BearerToken = token me, err := project.WhoAmI(clientConfig) @@ -263,6 +289,49 @@ func (o *LoginOptions) gatherAuthInfo() error { return nil } +func (o *LoginOptions) getAuthChallengeHandler() challengehandlers.ChallengeHandler { + var challengeHandlers []challengehandlers.ChallengeHandler + var webConsoleURL string + + serverVersionDetector := version.NewServerVersionRetriever(o.Config) + serverVersion, err := serverVersionDetector.RetrieveServerVersion() + // this feature was introduced in Openshift 4.11 which should correspond to 1.24 + if err == nil && serverVersion.MajorNumber >= 1 && serverVersion.MinorNumber >= 24 { + webConsoleURL = o.Config.Host + "/console" + } + + if occhallengers.GSSAPIEnabled() { + klog.V(6).Info("GSSAPI Enabled") + challengeHandlers = append(challengeHandlers, + occhallengers.NewNegotiateChallengeHandler(occhallengers.NewGSSAPINegotiator(o.Username)), + ) + } + + if occhallengers.SSPIEnabled() { + klog.V(6).Info("SSPI Enabled") + challengeHandlers = append(challengeHandlers, + occhallengers.NewNegotiateChallengeHandler(occhallengers.NewSSPINegotiator(o.Username, o.Password, o.Config.Host, webConsoleURL, o.In))) + } + + challengeHandlers = append(challengeHandlers, + challengehandlers.NewMultiHandler( + challengehandlers.NewBasicChallengeHandler( + o.Config.Host, + o.In, o.Out, + passwordPrompter(term.PromptForPasswordString), + o.Username, o.Password), + )) + + var handler challengehandlers.ChallengeHandler + if len(challengeHandlers) == 1 { + handler = challengeHandlers[0] + } else { + handler = challengehandlers.NewMultiHandler(challengeHandlers...) + } + + return handler +} + // Discover the projects available for the established session and take one to use. It // fails in case of no existing projects, and print out useful information in case of // multiple projects. diff --git a/pkg/cli/login/loginoptions_test.go b/pkg/cli/login/loginoptions_test.go index a43e3332dd..cd81feb438 100644 --- a/pkg/cli/login/loginoptions_test.go +++ b/pkg/cli/login/loginoptions_test.go @@ -273,7 +273,7 @@ func (r *oauthMetadataResponse) Serialize() ([]byte, error) { } func TestPreserveErrTypeAuthInfo(t *testing.T) { - invoked := make(chan struct{}, 3) + invoked := make(chan struct{}, 4) oauthResponse := []byte{} server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -284,10 +284,13 @@ func TestPreserveErrTypeAuthInfo(t *testing.T) { t.Fatalf("unexpected request handled by test server: %v: %v", r.Method, r.URL) } - if r.URL.Path == oauthMetadataEndpoint { + switch r.URL.Path { + case oauthMetadataEndpoint: w.WriteHeader(http.StatusOK) w.Write(oauthResponse) return + case "version": + return } w.WriteHeader(http.StatusUnauthorized) })) diff --git a/pkg/helpers/tokencmd/negotiate.go b/pkg/helpers/authchallengers/negotiate.go similarity index 95% rename from pkg/helpers/tokencmd/negotiate.go rename to pkg/helpers/authchallengers/negotiate.go index 64dc757954..dfe64c7386 100644 --- a/pkg/helpers/tokencmd/negotiate.go +++ b/pkg/helpers/authchallengers/negotiate.go @@ -1,4 +1,4 @@ -package tokencmd +package authchallengers import ( "encoding/base64" @@ -7,6 +7,8 @@ import ( "strings" "k8s.io/klog/v2" + + "github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers" ) // Negotiator defines the minimal interface needed to interact with GSSAPI to perform a negotiate challenge/response @@ -31,7 +33,7 @@ type NegotiateChallengeHandler struct { negotiator Negotiator } -func NewNegotiateChallengeHandler(negotiator Negotiator) ChallengeHandler { +func NewNegotiateChallengeHandler(negotiator Negotiator) challengehandlers.ChallengeHandler { return &NegotiateChallengeHandler{negotiator: negotiator} } diff --git a/pkg/helpers/tokencmd/negotiate_helpers.go b/pkg/helpers/authchallengers/negotiate_helpers.go similarity index 96% rename from pkg/helpers/tokencmd/negotiate_helpers.go rename to pkg/helpers/authchallengers/negotiate_helpers.go index e1d061db35..8c83767bc4 100644 --- a/pkg/helpers/tokencmd/negotiate_helpers.go +++ b/pkg/helpers/authchallengers/negotiate_helpers.go @@ -1,4 +1,4 @@ -package tokencmd +package authchallengers import ( "errors" diff --git a/pkg/helpers/tokencmd/negotiator_gssapi.go b/pkg/helpers/authchallengers/negotiator_gssapi.go similarity index 99% rename from pkg/helpers/tokencmd/negotiator_gssapi.go rename to pkg/helpers/authchallengers/negotiator_gssapi.go index 11df8d1798..caa0ead4ce 100644 --- a/pkg/helpers/tokencmd/negotiator_gssapi.go +++ b/pkg/helpers/authchallengers/negotiator_gssapi.go @@ -1,7 +1,7 @@ //go:build gssapi // +build gssapi -package tokencmd +package authchallengers import ( "errors" diff --git a/pkg/helpers/tokencmd/negotiator_gssapi_unsupported.go b/pkg/helpers/authchallengers/negotiator_gssapi_unsupported.go similarity index 87% rename from pkg/helpers/tokencmd/negotiator_gssapi_unsupported.go rename to pkg/helpers/authchallengers/negotiator_gssapi_unsupported.go index a211c9a963..013f62abc7 100644 --- a/pkg/helpers/tokencmd/negotiator_gssapi_unsupported.go +++ b/pkg/helpers/authchallengers/negotiator_gssapi_unsupported.go @@ -1,7 +1,7 @@ //go:build !gssapi // +build !gssapi -package tokencmd +package authchallengers func GSSAPIEnabled() bool { return false diff --git a/pkg/helpers/tokencmd/negotiator_sspi.go b/pkg/helpers/authchallengers/negotiator_sspi.go similarity index 91% rename from pkg/helpers/tokencmd/negotiator_sspi.go rename to pkg/helpers/authchallengers/negotiator_sspi.go index cbb7fadc0e..ee89fdc67f 100644 --- a/pkg/helpers/tokencmd/negotiator_sspi.go +++ b/pkg/helpers/authchallengers/negotiator_sspi.go @@ -1,7 +1,7 @@ //go:build windows // +build windows -package tokencmd +package authchallengers import ( "fmt" @@ -14,7 +14,6 @@ import ( "k8s.io/apimachinery/pkg/util/runtime" "github.com/openshift/oc/pkg/helpers/term" - "github.com/openshift/oc/pkg/version" "github.com/alexbrainman/sspi" "github.com/alexbrainman/sspi/negotiate" @@ -80,6 +79,9 @@ type sspiNegotiator struct { // host is the server being authenticated to. Used only for displaying messages when prompting for password. host string + // webConsoleURL is an optional URL to a web interface where the user might go if they prefer login from the browser instead + webConsoleURL string + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms721572(v=vs.85).aspx#_security_credentials_gly // phCredential [in, optional]: A handle to the credentials returned by AcquireCredentialsHandle (Negotiate). // This handle is used to build the security context. sspi.SECPKG_CRED_OUTBOUND is used to request OUTBOUND credentials. @@ -96,20 +98,18 @@ type sspiNegotiator struct { // https://msdn.microsoft.com/en-us/library/windows/desktop/aa374764(v=vs.85).aspx // Set to true once InitializeSecurityContext or CompleteAuthToken return sspi.SEC_E_OK complete bool - // serverVersionRetriever is used for fetching server version - serverVersionRetriever version.ServerVersionRetriever } -func NewSSPINegotiator(principalName, password, host string, reader io.Reader, serverVersionRetriever version.ServerVersionRetriever) Negotiator { +func NewSSPINegotiator(principalName, password, host, webConsoleURL string, reader io.Reader) Negotiator { return &sspiNegotiator{ - principalName: principalName, - password: password, - reader: reader, - writer: os.Stdout, - host: host, - desiredFlags: desiredFlags, - requiredFlags: requiredFlags, - serverVersionRetriever: serverVersionRetriever, + principalName: principalName, + password: password, + reader: reader, + writer: os.Stdout, + host: host, + webConsoleURL: webConsoleURL, + desiredFlags: desiredFlags, + requiredFlags: requiredFlags, } } @@ -246,19 +246,15 @@ func (s *sspiNegotiator) getPassword(domain, username string) (string, error) { password := s.password if missingPassword := len(password) == 0; missingPassword { + if len(s.webConsoleURL) > 0 { + fmt.Fprintf(s.writer, "Console URL: %s/console\n", s.webConsoleURL) + } // mimic output from basic auth prompt if hasDomain := len(domain) > 0; hasDomain { fmt.Fprintf(s.writer, "Authentication required for %s (%s)\n", s.host, domain) } else { fmt.Fprintf(s.writer, "Authentication required for %s\n", s.host) } - if s.serverVersionRetriever != nil { - serverVersion, err := s.serverVersionRetriever.RetrieveServerVersion() - // this feature was introduced in Openshift 4.11 which should correspond to 1.24 - if err == nil && serverVersion.MajorNumber >= 1 && serverVersion.MinorNumber >= 24 { - fmt.Fprintf(s.writer, "Console URL: %s/console\n", s.host) - } - } fmt.Fprintf(s.writer, "Username: %s\n", username) // empty password from prompt is ok // we do not need to worry about being stuck in a prompt loop because ClientContext.Update diff --git a/pkg/helpers/authchallengers/negotiator_sspi_unsupported.go b/pkg/helpers/authchallengers/negotiator_sspi_unsupported.go new file mode 100644 index 0000000000..8fa579e56c --- /dev/null +++ b/pkg/helpers/authchallengers/negotiator_sspi_unsupported.go @@ -0,0 +1,16 @@ +//go:build !windows +// +build !windows + +package authchallengers + +import ( + "io" +) + +func SSPIEnabled() bool { + return false +} + +func NewSSPINegotiator(string, string, string, string, io.Reader) Negotiator { + return newUnsupportedNegotiator("SSPI") +} diff --git a/pkg/helpers/tokencmd/request_token_test.go b/pkg/helpers/authchallengers/negotiator_test.go similarity index 75% rename from pkg/helpers/tokencmd/request_token_test.go rename to pkg/helpers/authchallengers/negotiator_test.go index d43798b885..30c21fa5c4 100644 --- a/pkg/helpers/tokencmd/request_token_test.go +++ b/pkg/helpers/authchallengers/negotiator_test.go @@ -1,4 +1,4 @@ -package tokencmd +package authchallengers import ( "bytes" @@ -6,6 +6,7 @@ import ( "encoding/pem" "errors" "fmt" + "io" "net/http" "net/http/httptest" "reflect" @@ -17,6 +18,8 @@ import ( restclient "k8s.io/client-go/rest" "github.com/openshift/library-go/pkg/oauth/oauthdiscovery" + "github.com/openshift/library-go/pkg/oauth/tokenrequest" + "github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers" ) type unloadableNegotiator struct { @@ -94,6 +97,15 @@ func (n *successfulNegotiator) Release() error { return nil } +type testPasswordPrompter struct{} + +func (*testPasswordPrompter) PromptForPassword(r io.Reader, w io.Writer, format string, a ...interface{}) string { + fmt.Fprintf(w, format, a...) + var result string + fmt.Fscan(r, &result) + return result +} + func TestRequestToken(t *testing.T) { type req struct { authorization string @@ -111,14 +123,14 @@ func TestRequestToken(t *testing.T) { serverResponse resp } - var verifyReleased func(test string, handler ChallengeHandler) - verifyReleased = func(test string, handler ChallengeHandler) { + var verifyReleased func(test string, handler challengehandlers.ChallengeHandler) + verifyReleased = func(test string, handler challengehandlers.ChallengeHandler) { switch handler := handler.(type) { - case *MultiHandler: - for _, subhandler := range handler.allHandlers { + case *challengehandlers.MultiHandler: + for _, subhandler := range handler.Handlers() { verifyReleased(test, subhandler) } - case *BasicChallengeHandler: + case *challengehandlers.BasicChallengeHandler: // we don't care case *NegotiateChallengeHandler: switch negotiator := handler.negotiator.(type) { @@ -165,14 +177,14 @@ func TestRequestToken(t *testing.T) { successWithNegotiate := resp{302, successfulLocation, []string{"Negotiate Y2hhbGxlbmdlMg=="}} testcases := map[string]struct { - Handler ChallengeHandler + Handler challengehandlers.ChallengeHandler Requests []requestResponse ExpectedToken string ExpectedError string }{ // Defaulting basic handler "defaulted basic handler, no challenge, success": { - Handler: &BasicChallengeHandler{Username: "myuser", Password: "mypassword"}, + Handler: challengehandlers.NewBasicChallengeHandler("", nil, nil, &testPasswordPrompter{}, "myuser", "mypassword"), Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, success}, @@ -180,7 +192,7 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "defaulted basic handler, basic challenge, success": { - Handler: &BasicChallengeHandler{Username: "myuser", Password: "mypassword"}, + Handler: challengehandlers.NewBasicChallengeHandler("", nil, nil, &testPasswordPrompter{}, "myuser", "mypassword"), Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, basicChallenge1}, @@ -189,7 +201,7 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "defaulted basic handler, basic+negotiate challenge, success": { - Handler: &BasicChallengeHandler{Username: "myuser", Password: "mypassword"}, + Handler: challengehandlers.NewBasicChallengeHandler("", nil, nil, &testPasswordPrompter{}, "myuser", "mypassword"), Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, doubleChallenge}, @@ -198,7 +210,7 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "defaulted basic handler, basic challenge, failure": { - Handler: &BasicChallengeHandler{Username: "myuser", Password: "mypassword"}, + Handler: challengehandlers.NewBasicChallengeHandler("", nil, nil, &testPasswordPrompter{}, "myuser", "mypassword"), Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, basicChallenge1}, @@ -207,7 +219,7 @@ func TestRequestToken(t *testing.T) { ExpectedError: "challenger chose not to retry the request", }, "defaulted basic handler, negotiate challenge, failure": { - Handler: &BasicChallengeHandler{Username: "myuser", Password: "mypassword"}, + Handler: challengehandlers.NewBasicChallengeHandler("", nil, nil, &testPasswordPrompter{}, "myuser", "mypassword"), Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, negotiateChallenge1}, @@ -215,15 +227,15 @@ func TestRequestToken(t *testing.T) { ExpectedError: "unhandled challenge", }, "no username, basic challenge, failure": { - Handler: &BasicChallengeHandler{}, + Handler: &challengehandlers.BasicChallengeHandler{}, Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, basicChallenge1}, }, - ExpectedError: BasicAuthNoUsernameMessage, + ExpectedError: tokenrequest.BasicAuthNoUsernameMessage, }, "failing basic handler, basic challenge, failure": { - Handler: &BasicChallengeHandler{Username: "myuser"}, + Handler: &challengehandlers.BasicChallengeHandler{Username: "myuser"}, Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, basicChallenge1}, @@ -234,7 +246,7 @@ func TestRequestToken(t *testing.T) { // Prompting basic handler "prompting basic handler, no challenge, success": { - Handler: &BasicChallengeHandler{Username: "myuser", Reader: bytes.NewBufferString("mypassword\n")}, + Handler: challengehandlers.NewBasicChallengeHandler("", bytes.NewBufferString("mypassword\n"), nil, &testPasswordPrompter{}, "myuser", ""), Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, success}, @@ -242,7 +254,7 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "prompting basic handler, basic challenge, success": { - Handler: &BasicChallengeHandler{Username: "myuser", Reader: bytes.NewBufferString("mypassword\n")}, + Handler: challengehandlers.NewBasicChallengeHandler("", bytes.NewBufferString("mypassword\n"), nil, &testPasswordPrompter{}, "myuser", ""), Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, basicChallenge1}, @@ -251,7 +263,7 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "prompting basic handler, basic+negotiate challenge, success": { - Handler: &BasicChallengeHandler{Username: "myuser", Reader: bytes.NewBufferString("mypassword\n")}, + Handler: challengehandlers.NewBasicChallengeHandler("", bytes.NewBufferString("mypassword\n"), nil, &testPasswordPrompter{}, "myuser", ""), Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, doubleChallenge}, @@ -260,7 +272,7 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "prompting basic handler, basic challenge, failure": { - Handler: &BasicChallengeHandler{Username: "myuser"}, + Handler: &challengehandlers.BasicChallengeHandler{Username: "myuser"}, Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, basicChallenge1}, @@ -269,7 +281,7 @@ func TestRequestToken(t *testing.T) { ExpectedError: "challenger chose not to retry the request", }, "prompting basic handler, negotiate challenge, failure": { - Handler: &BasicChallengeHandler{Reader: bytes.NewBufferString("myuser\nmypassword\n")}, + Handler: &challengehandlers.BasicChallengeHandler{Reader: bytes.NewBufferString("myuser\nmypassword\n")}, Requests: []requestResponse{ {initialHead, initialHeadResp}, {initialRequest, negotiateChallenge1}, @@ -378,9 +390,9 @@ func TestRequestToken(t *testing.T) { // Negotiate+Basic fallback cases "failing negotiate+prompting basic handler, no challenge, success": { - Handler: NewMultiHandler( + Handler: challengehandlers.NewMultiHandler( &NegotiateChallengeHandler{negotiator: &failingNegotiator{}}, - &BasicChallengeHandler{Reader: bytes.NewBufferString("myuser\nmypassword\n")}, + &challengehandlers.BasicChallengeHandler{Reader: bytes.NewBufferString("myuser\nmypassword\n")}, ), Requests: []requestResponse{ {initialHead, initialHeadResp}, @@ -389,9 +401,9 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "failing negotiate+prompting basic handler, negotiate+basic challenge, success": { - Handler: NewMultiHandler( + Handler: challengehandlers.NewMultiHandler( &NegotiateChallengeHandler{negotiator: &failingNegotiator{}}, - &BasicChallengeHandler{Username: "myuser", Reader: bytes.NewBufferString("mypassword\n")}, + challengehandlers.NewBasicChallengeHandler("", bytes.NewBufferString("mypassword\n"), nil, &testPasswordPrompter{}, "myuser", ""), ), Requests: []requestResponse{ {initialHead, initialHeadResp}, @@ -401,9 +413,9 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "negotiate+failing basic handler, negotiate+basic challenge, success": { - Handler: NewMultiHandler( + Handler: challengehandlers.NewMultiHandler( &NegotiateChallengeHandler{negotiator: &successfulNegotiator{rounds: 2}}, - &BasicChallengeHandler{}, + &challengehandlers.BasicChallengeHandler{}, ), Requests: []requestResponse{ {initialHead, initialHeadResp}, @@ -414,9 +426,9 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "negotiate+basic handler, negotiate+basic challenge, prefers negotiation, success": { - Handler: NewMultiHandler( + Handler: challengehandlers.NewMultiHandler( &NegotiateChallengeHandler{negotiator: &successfulNegotiator{rounds: 2}}, - &BasicChallengeHandler{Reader: bytes.NewBufferString("myuser\nmypassword\n")}, + &challengehandlers.BasicChallengeHandler{Reader: bytes.NewBufferString("myuser\nmypassword\n")}, ), Requests: []requestResponse{ {initialHead, initialHeadResp}, @@ -427,9 +439,9 @@ func TestRequestToken(t *testing.T) { ExpectedToken: successfulToken, }, "negotiate+basic handler, negotiate+basic challenge, prefers negotiation, sticks with selected handler on failure": { - Handler: NewMultiHandler( + Handler: challengehandlers.NewMultiHandler( &NegotiateChallengeHandler{negotiator: &successfulNegotiator{rounds: 2}}, - &BasicChallengeHandler{Reader: bytes.NewBufferString("myuser\nmypassword\n")}, + &challengehandlers.BasicChallengeHandler{Reader: bytes.NewBufferString("myuser\nmypassword\n")}, ), Requests: []requestResponse{ {initialHead, initialHeadResp}, @@ -442,86 +454,88 @@ func TestRequestToken(t *testing.T) { } for k, tc := range testcases { - i := 0 - s := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - defer func() { - if err := recover(); err != nil { - t.Errorf("test %s panicked: %v", k, err) + t.Run(k, func(t *testing.T) { + i := 0 + s := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + defer func() { + if err := recover(); err != nil { + t.Errorf("test %s panicked: %v", k, err) + } + }() + + if i >= len(tc.Requests) { + t.Errorf("%s: %d: more requests received than expected: %#v", k, i, req) + return } - }() + rr := tc.Requests[i] + i++ - if i >= len(tc.Requests) { - t.Errorf("%s: %d: more requests received than expected: %#v", k, i, req) - return - } - rr := tc.Requests[i] - i++ + method := rr.expectedRequest.method + if len(method) == 0 { + method = http.MethodGet + } + if req.Method != method { + t.Errorf("%s: %d: Expected %s, got %s", k, i, method, req.Method) + return + } - method := rr.expectedRequest.method - if len(method) == 0 { - method = http.MethodGet - } - if req.Method != method { - t.Errorf("%s: %d: Expected %s, got %s", k, i, method, req.Method) - return - } + path := rr.expectedRequest.path + if len(path) == 0 { + path = "/oauth/authorize" + } + if req.URL.Path != path { + t.Errorf("%s: %d: Expected %s, got %s", k, i, path, req.URL.Path) + return + } + + if e, a := rr.expectedRequest.authorization, req.Header.Get("Authorization"); e != a { + t.Errorf("%s: %d: expected 'Authorization: %s', got 'Authorization: %s'", k, i, e, a) + return + } - path := rr.expectedRequest.path - if len(path) == 0 { - path = "/oauth/authorize" + if len(rr.serverResponse.location) > 0 { + w.Header().Add("Location", rr.serverResponse.location) + } + for _, v := range rr.serverResponse.wwwAuthenticate { + w.Header().Add("WWW-Authenticate", v) + } + w.WriteHeader(rr.serverResponse.status) + })) + defer s.Close() + + opts := &tokenrequest.RequestTokenOptions{ + ClientConfig: &restclient.Config{ + Host: s.URL, + TLSClientConfig: restclient.TLSClientConfig{ + CAData: pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: s.Certificate().Raw}), + }, + }, + Handler: tc.Handler, + OsinConfig: &osincli.ClientConfig{ + ClientId: "openshift-challenging-client", + AuthorizeUrl: oauthdiscovery.OpenShiftOAuthAuthorizeURL(s.URL), + TokenUrl: oauthdiscovery.OpenShiftOAuthTokenURL(s.URL), + RedirectUrl: oauthdiscovery.OpenShiftOAuthTokenImplicitURL(s.URL), + }, + Issuer: s.URL, + TokenFlow: true, } - if req.URL.Path != path { - t.Errorf("%s: %d: Expected %s, got %s", k, i, path, req.URL.Path) - return + token, err := opts.RequestToken() + if token != tc.ExpectedToken { + t.Errorf("%s: expected token '%s', got '%s'", k, tc.ExpectedToken, token) } - - if e, a := rr.expectedRequest.authorization, req.Header.Get("Authorization"); e != a { - t.Errorf("%s: %d: expected 'Authorization: %s', got 'Authorization: %s'", k, i, e, a) - return + errStr := "" + if err != nil { + errStr = err.Error() } - - if len(rr.serverResponse.location) > 0 { - w.Header().Add("Location", rr.serverResponse.location) + if errStr != tc.ExpectedError { + t.Errorf("%s: expected error '%s', got '%s'", k, tc.ExpectedError, errStr) } - for _, v := range rr.serverResponse.wwwAuthenticate { - w.Header().Add("WWW-Authenticate", v) + if i != len(tc.Requests) { + t.Errorf("%s: expected %d requests, saw %d", k, len(tc.Requests), i) } - w.WriteHeader(rr.serverResponse.status) - })) - defer s.Close() - - opts := &RequestTokenOptions{ - ClientConfig: &restclient.Config{ - Host: s.URL, - TLSClientConfig: restclient.TLSClientConfig{ - CAData: pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: s.Certificate().Raw}), - }, - }, - Handler: tc.Handler, - OsinConfig: &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, - AuthorizeUrl: oauthdiscovery.OpenShiftOAuthAuthorizeURL(s.URL), - TokenUrl: oauthdiscovery.OpenShiftOAuthTokenURL(s.URL), - RedirectUrl: oauthdiscovery.OpenShiftOAuthTokenImplicitURL(s.URL), - }, - Issuer: s.URL, - TokenFlow: true, - } - token, err := opts.RequestToken() - if token != tc.ExpectedToken { - t.Errorf("%s: expected token '%s', got '%s'", k, tc.ExpectedToken, token) - } - errStr := "" - if err != nil { - errStr = err.Error() - } - if errStr != tc.ExpectedError { - t.Errorf("%s: expected error '%s', got '%s'", k, tc.ExpectedError, errStr) - } - if i != len(tc.Requests) { - t.Errorf("%s: expected %d requests, saw %d", k, len(tc.Requests), i) - } - verifyReleased(k, tc.Handler) + verifyReleased(k, tc.Handler) + }) } } @@ -542,18 +556,18 @@ func TestSetDefaultOsinConfig(t *testing.T) { Issuer: "a", AuthorizationEndpoint: "b", TokenEndpoint: "c", - CodeChallengeMethodsSupported: []string{pkce_s256}, + CodeChallengeMethodsSupported: []string{"S256"}, }, hostWrapper: noHostChange, tokenFlow: false, expectPKCE: true, expectedConfig: &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, + ClientId: "openshift-challenging-client", AuthorizeUrl: "b", TokenUrl: "c", RedirectUrl: "a/oauth/token/implicit", - CodeChallengeMethod: pkce_s256, + CodeChallengeMethod: "S256", }, }, { @@ -569,7 +583,7 @@ func TestSetDefaultOsinConfig(t *testing.T) { expectPKCE: false, expectedConfig: &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, + ClientId: "openshift-challenging-client", AuthorizeUrl: "b", TokenUrl: "c", RedirectUrl: "a/oauth/token/implicit", @@ -581,14 +595,14 @@ func TestSetDefaultOsinConfig(t *testing.T) { Issuer: "a", AuthorizationEndpoint: "b", TokenEndpoint: "c", - CodeChallengeMethodsSupported: []string{pkce_s256}, + CodeChallengeMethodsSupported: []string{"S256"}, }, hostWrapper: noHostChange, tokenFlow: true, expectPKCE: false, expectedConfig: &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, + ClientId: "openshift-challenging-client", AuthorizeUrl: "b", TokenUrl: "c", RedirectUrl: "a/oauth/token/implicit", @@ -607,7 +621,7 @@ func TestSetDefaultOsinConfig(t *testing.T) { expectPKCE: false, expectedConfig: &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, + ClientId: "openshift-challenging-client", AuthorizeUrl: "b", TokenUrl: "c", RedirectUrl: "a/oauth/token/implicit", @@ -626,7 +640,7 @@ func TestSetDefaultOsinConfig(t *testing.T) { expectPKCE: false, expectedConfig: &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, + ClientId: "openshift-challenging-client", AuthorizeUrl: "b", TokenUrl: "c", RedirectUrl: "a/oauth/token/implicit", @@ -638,18 +652,18 @@ func TestSetDefaultOsinConfig(t *testing.T) { Issuer: "a", AuthorizationEndpoint: "b", TokenEndpoint: "c", - CodeChallengeMethodsSupported: []string{pkce_s256}, + CodeChallengeMethodsSupported: []string{"S256"}, }, hostWrapper: func(host string) string { return host + "/////" }, tokenFlow: false, expectPKCE: true, expectedConfig: &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, + ClientId: "openshift-challenging-client", AuthorizeUrl: "b", TokenUrl: "c", RedirectUrl: "a/oauth/token/implicit", - CodeChallengeMethod: pkce_s256, + CodeChallengeMethod: "S256", }, }, { @@ -658,18 +672,18 @@ func TestSetDefaultOsinConfig(t *testing.T) { Issuer: "a/////", AuthorizationEndpoint: "b", TokenEndpoint: "c", - CodeChallengeMethodsSupported: []string{pkce_s256}, + CodeChallengeMethodsSupported: []string{"S256"}, }, hostWrapper: noHostChange, tokenFlow: false, expectPKCE: true, expectedConfig: &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, + ClientId: "openshift-challenging-client", AuthorizeUrl: "b", TokenUrl: "c", RedirectUrl: "a/oauth/token/implicit", - CodeChallengeMethod: pkce_s256, + CodeChallengeMethod: "S256", }, }, { @@ -678,18 +692,18 @@ func TestSetDefaultOsinConfig(t *testing.T) { Issuer: "arandomissuerthatisfun123!!!///", AuthorizationEndpoint: "44authzisanawesomeendpoint", TokenEndpoint: "&&buttokenendpointisprettygoodtoo", - CodeChallengeMethodsSupported: []string{pkce_s256}, + CodeChallengeMethodsSupported: []string{"S256"}, }, hostWrapper: noHostChange, tokenFlow: false, expectPKCE: true, expectedConfig: &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, + ClientId: "openshift-challenging-client", AuthorizeUrl: "44authzisanawesomeendpoint", TokenUrl: "&&buttokenendpointisprettygoodtoo", RedirectUrl: "arandomissuerthatisfun123!!!/oauth/token/implicit", - CodeChallengeMethod: pkce_s256, + CodeChallengeMethod: "S256", }, }, } { @@ -698,7 +712,7 @@ func TestSetDefaultOsinConfig(t *testing.T) { t.Errorf("%s: Expected GET, got %s", tc.name, req.Method) return } - if req.URL.Path != oauthMetadataEndpoint { + if req.URL.Path != "/.well-known/oauth-authorization-server" { t.Errorf("%s: Expected metadata endpoint, got %s", tc.name, req.URL.Path) return } @@ -711,11 +725,11 @@ func TestSetDefaultOsinConfig(t *testing.T) { })) defer s.Close() - opts := &RequestTokenOptions{ + opts := &tokenrequest.RequestTokenOptions{ ClientConfig: &restclient.Config{Host: tc.hostWrapper(s.URL)}, TokenFlow: tc.tokenFlow, } - if err := opts.SetDefaultOsinConfig(); err != nil { + if err := opts.SetDefaultOsinConfig("openshift-challenging-client", nil); err != nil { t.Errorf("%s: unexpected SetDefaultOsinConfig error: %v", tc.name, err) continue } diff --git a/pkg/helpers/tokencmd/basicauth_test.go b/pkg/helpers/tokencmd/basicauth_test.go deleted file mode 100644 index 19321ec957..0000000000 --- a/pkg/helpers/tokencmd/basicauth_test.go +++ /dev/null @@ -1,371 +0,0 @@ -package tokencmd - -import ( - "bytes" - "errors" - "net/http" - "reflect" - "testing" - - "github.com/openshift/oc/pkg/version" -) - -var ( - AUTHORIZATION = http.CanonicalHeaderKey("Authorization") - WWW_AUTHENTICATE = http.CanonicalHeaderKey("WWW-Authenticate") -) - -type Challenge struct { - Headers http.Header - - ExpectedCanHandle bool - ExpectedHeaders http.Header - ExpectedHandled bool - ExpectedErr error - ExpectedPrompt string -} - -type FakeServerVersionRetriever struct { - MajorNumber int - MinorNumber int -} - -func (r *FakeServerVersionRetriever) RetrieveServerVersion() (*version.ServerVersion, error) { - return &version.ServerVersion{ - MajorNumber: r.MajorNumber, - MinorNumber: r.MinorNumber, - }, nil -} - -func TestHandleChallenge(t *testing.T) { - - basicChallenge := http.Header{WWW_AUTHENTICATE: []string{`Basic realm="myrealm"`}} - - testCases := map[string]struct { - Handler *BasicChallengeHandler - Challenges []Challenge - }{ - "non-interactive with no defaults": { - Handler: &BasicChallengeHandler{ - Host: "myhost", - Reader: nil, - Username: "", - Password: "", - }, - Challenges: []Challenge{ - { - Headers: basicChallenge, - ExpectedCanHandle: true, - ExpectedHeaders: nil, - ExpectedHandled: false, - ExpectedErr: NewBasicAuthNoUsernameError(), - ExpectedPrompt: "", - }, - }, - }, - - "non-interactive challenge with defaults": { - Handler: &BasicChallengeHandler{ - Host: "myhost", - Reader: nil, - Username: "myuser", - Password: "mypassword", - }, - Challenges: []Challenge{ - { - Headers: basicChallenge, - ExpectedCanHandle: true, - ExpectedHeaders: http.Header{AUTHORIZATION: []string{getBasicHeader("myuser", "mypassword")}}, - ExpectedHandled: true, - ExpectedErr: nil, - ExpectedPrompt: "", - }, - { - Headers: basicChallenge, - ExpectedCanHandle: true, - ExpectedHeaders: nil, - ExpectedHandled: false, - ExpectedErr: nil, - ExpectedPrompt: "", - }, - }, - }, - - "interactive challenge with default user without console url": { - Handler: &BasicChallengeHandler{ - Host: "https://myhost", - serverVersionRetriever: &FakeServerVersionRetriever{1, 23}, - Reader: bytes.NewBufferString("mypassword\n"), - Username: "myuser", - Password: "", - }, - Challenges: []Challenge{ - { - Headers: basicChallenge, - ExpectedCanHandle: true, - ExpectedHeaders: http.Header{AUTHORIZATION: []string{getBasicHeader("myuser", "mypassword")}}, - ExpectedHandled: true, - ExpectedErr: nil, - ExpectedPrompt: `Authentication required for https://myhost (myrealm) -Username: myuser -Password: `, - }, - }, - }, - - "interactive challenge with default user with console url": { - Handler: &BasicChallengeHandler{ - Host: "https://myhost", - serverVersionRetriever: &FakeServerVersionRetriever{1, 24}, - Reader: bytes.NewBufferString("mypassword\n"), - Username: "myuser", - Password: "", - }, - Challenges: []Challenge{ - { - Headers: basicChallenge, - ExpectedCanHandle: true, - ExpectedHeaders: http.Header{AUTHORIZATION: []string{getBasicHeader("myuser", "mypassword")}}, - ExpectedHandled: true, - ExpectedErr: nil, - ExpectedPrompt: `Authentication required for https://myhost (myrealm) -Console URL: https://myhost/console -Username: myuser -Password: `, - }, - }, - }, - - "non-interactive challenge with reader defaults": { - Handler: &BasicChallengeHandler{ - Host: "myhost", - Reader: bytes.NewBufferString(""), - Username: "myuser", - Password: "mypassword", - }, - Challenges: []Challenge{ - { - Headers: basicChallenge, - ExpectedCanHandle: true, - ExpectedHeaders: http.Header{AUTHORIZATION: []string{getBasicHeader("myuser", "mypassword")}}, - ExpectedHandled: true, - ExpectedErr: nil, - ExpectedPrompt: "", - }, - { - Headers: basicChallenge, - ExpectedCanHandle: true, - ExpectedHeaders: nil, - ExpectedHandled: false, - ExpectedErr: nil, - ExpectedPrompt: "", - }, - }, - }, - - "invalid basic auth username": { - Handler: &BasicChallengeHandler{ - Host: "myhost", - Reader: bytes.NewBufferString(""), - Username: "system:admin", - Password: "mypassword", - }, - Challenges: []Challenge{ - { - Headers: basicChallenge, - ExpectedCanHandle: true, - ExpectedHeaders: nil, - ExpectedHandled: false, - ExpectedErr: errors.New("username system:admin is invalid for basic auth"), - ExpectedPrompt: "", - }, - }, - }, - "invalid basic auth username prompt": { - Handler: &BasicChallengeHandler{ - Host: "myhost", - Reader: bytes.NewBufferString(``), - Username: "system:admin", - Password: "", - }, - Challenges: []Challenge{ - { - Headers: basicChallenge, - ExpectedCanHandle: true, - ExpectedHeaders: nil, - ExpectedHandled: false, - ExpectedErr: errors.New("username system:admin is invalid for basic auth"), - ExpectedPrompt: "", - }, - }, - }, - } - - for k, tc := range testCases { - for i, challenge := range tc.Challenges { - out := &bytes.Buffer{} - tc.Handler.Writer = out - - canHandle := tc.Handler.CanHandle(challenge.Headers) - if canHandle != challenge.ExpectedCanHandle { - t.Errorf("%s: %d: Expected CanHandle=%v, got %v", k, i, challenge.ExpectedCanHandle, canHandle) - } - - if canHandle { - headers, handled, err := tc.Handler.HandleChallenge("", challenge.Headers) - if !reflect.DeepEqual(headers, challenge.ExpectedHeaders) { - t.Errorf("%s: %d: Expected headers\n\t%#v\ngot\n\t%#v", k, i, challenge.ExpectedHeaders, headers) - } - if handled != challenge.ExpectedHandled { - t.Errorf("%s: %d: Expected handled=%v, got %v", k, i, challenge.ExpectedHandled, handled) - } - if ((err == nil) != (challenge.ExpectedErr == nil)) || (err != nil && err.Error() != challenge.ExpectedErr.Error()) { - t.Errorf("%s: %d: Expected err=%v, got %v", k, i, challenge.ExpectedErr, err) - } - if out.String() != challenge.ExpectedPrompt { - t.Errorf("%s: %d: Expected prompt %q, got %q", k, i, challenge.ExpectedPrompt, out.String()) - } - } - } - } -} - -func TestBasicRealm(t *testing.T) { - - testCases := map[string]struct { - Headers http.Header - ExpectedBasic bool - ExpectedRealm string - }{ - "empty": { - Headers: http.Header{}, - ExpectedBasic: false, - ExpectedRealm: ``, - }, - - "non-challenge": { - Headers: http.Header{ - "test": []string{`value`}, - }, - ExpectedBasic: false, - ExpectedRealm: ``, - }, - - "non-basic": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{ - `basicrealm="myrealm"`, - `digest basic="realm"`, - }, - }, - ExpectedBasic: false, - ExpectedRealm: ``, - }, - - "basic multiple www-authenticate headers": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{ - `digest realm="digestrealm"`, - `basic realm="Foo"`, - `foo bar="baz"`, - }, - }, - ExpectedBasic: true, - ExpectedRealm: `Foo`, - }, - - "basic no realm": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{`basic`}, - }, - ExpectedBasic: true, - ExpectedRealm: ``, - }, - - "basic other param": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{`basic otherparam="othervalue"`}, - }, - ExpectedBasic: true, - ExpectedRealm: ``, - }, - - "basic token realm": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{`basic realm=Foo Bar `}, - }, - ExpectedBasic: true, - ExpectedRealm: `Foo Bar`, - }, - - "basic quoted realm": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{`basic realm="Foo Bar"`}, - }, - ExpectedBasic: true, - ExpectedRealm: `Foo Bar`, - }, - - "basic case-insensitive scheme": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{`BASIC realm="Foo"`}, - }, - ExpectedBasic: true, - ExpectedRealm: `Foo`, - }, - - "basic case-insensitive realm": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{`basic REALM="Foo"`}, - }, - ExpectedBasic: true, - ExpectedRealm: `Foo`, - }, - - "basic whitespace": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{` basic realm = "Foo\" Bar" `}, - }, - ExpectedBasic: true, - ExpectedRealm: `Foo\" Bar`, - }, - - "basic trailing comma": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{`basic realm="Foo", otherparam="value"`}, - }, - ExpectedBasic: true, - ExpectedRealm: `Foo`, - }, - - "realm containing quotes": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{`basic realm="F\"oo", otherparam="value"`}, - }, - ExpectedBasic: true, - ExpectedRealm: `F\"oo`, - }, - - "realm containing comma": { - Headers: http.Header{ - WWW_AUTHENTICATE: []string{`basic realm="Foo, bar", otherparam="value"`}, - }, - ExpectedBasic: true, - ExpectedRealm: `Foo, bar`, - }, - - // TODO: additional forms to support - // Basic param="value", realm="myrealm" - // Digest, Basic param="value", realm="myrealm" - } - - for k, tc := range testCases { - isBasic, realm := basicRealm(tc.Headers) - if isBasic != tc.ExpectedBasic { - t.Errorf("%s: Expected isBasicChallenge=%v, got %v", k, tc.ExpectedBasic, isBasic) - } - if realm != tc.ExpectedRealm { - t.Errorf("%s: Expected realm=%q, got %q", k, tc.ExpectedRealm, realm) - } - } -} diff --git a/pkg/helpers/tokencmd/negotiator_sspi_unsupported.go b/pkg/helpers/tokencmd/negotiator_sspi_unsupported.go deleted file mode 100644 index 3fcb40d707..0000000000 --- a/pkg/helpers/tokencmd/negotiator_sspi_unsupported.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build !windows -// +build !windows - -package tokencmd - -import ( - "io" - - "github.com/openshift/oc/pkg/version" -) - -func SSPIEnabled() bool { - return false -} - -func NewSSPINegotiator(string, string, string, io.Reader, version.ServerVersionRetriever) Negotiator { - return newUnsupportedNegotiator("SSPI") -} diff --git a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_apiserver.crd.yaml b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_apiserver-Default.crd.yaml similarity index 99% rename from vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_apiserver.crd.yaml rename to vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_apiserver-Default.crd.yaml index 3e53b28b9e..7edc7f23a7 100644 --- a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_apiserver.crd.yaml +++ b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_apiserver-Default.crd.yaml @@ -6,6 +6,7 @@ metadata: include.release.openshift.io/ibm-cloud-managed: "true" include.release.openshift.io/self-managed-high-availability: "true" include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-set: Default name: apiservers.config.openshift.io spec: group: config.openshift.io @@ -101,6 +102,7 @@ spec: - "" - identity - aescbc + - aesgcm servingCerts: description: servingCert is the TLS cert info for serving secure traffic. If not specified, operator managed certificates will be used for serving secure traffic. type: object diff --git a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_apiserver-TechPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_apiserver-TechPreviewNoUpgrade.crd.yaml new file mode 100644 index 0000000000..8ce5214c1d --- /dev/null +++ b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_apiserver-TechPreviewNoUpgrade.crd.yaml @@ -0,0 +1,179 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.openshift.io: https://github.com/openshift/api/pull/470 + include.release.openshift.io/ibm-cloud-managed: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-set: TechPreviewNoUpgrade + name: apiservers.config.openshift.io +spec: + group: config.openshift.io + names: + kind: APIServer + listKind: APIServerList + plural: apiservers + singular: apiserver + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: "APIServer holds configuration (like serving certificates, client CA and CORS domains) shared by all API servers in the system, among them especially kube-apiserver and openshift-apiserver. The canonical name of an instance is 'cluster'. \n Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer)." + type: object + required: + - spec + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: spec holds user settable values for configuration + type: object + properties: + additionalCORSAllowedOrigins: + description: additionalCORSAllowedOrigins lists additional, user-defined regular expressions describing hosts for which the API server allows access using the CORS headers. This may be needed to access the API and the integrated OAuth server from JavaScript applications. The values are regular expressions that correspond to the Golang regular expression language. + type: array + items: + type: string + audit: + description: audit specifies the settings for audit configuration to be applied to all OpenShift-provided API servers in the cluster. + type: object + default: + profile: Default + properties: + customRules: + description: customRules specify profiles per group. These profile take precedence over the top-level profile field if they apply. They are evaluation from top to bottom and the first one that matches, applies. + type: array + items: + description: AuditCustomRule describes a custom rule for an audit profile that takes precedence over the top-level profile. + type: object + required: + - group + - profile + properties: + group: + description: group is a name of group a request user must be member of in order to this profile to apply. + type: string + minLength: 1 + profile: + description: "profile specifies the name of the desired audit policy configuration to be deployed to all OpenShift-provided API servers in the cluster. \n The following profiles are provided: - Default: the existing default policy. - WriteRequestBodies: like 'Default', but logs request and response HTTP payloads for write requests (create, update, patch). - AllRequestBodies: like 'WriteRequestBodies', but also logs request and response HTTP payloads for read requests (get, list). - None: no requests are logged at all, not even oauthaccesstokens and oauthauthorizetokens. \n If unset, the 'Default' profile is used as the default." + type: string + enum: + - Default + - WriteRequestBodies + - AllRequestBodies + - None + x-kubernetes-list-map-keys: + - group + x-kubernetes-list-type: map + profile: + description: "profile specifies the name of the desired top-level audit profile to be applied to all requests sent to any of the OpenShift-provided API servers in the cluster (kube-apiserver, openshift-apiserver and oauth-apiserver), with the exception of those requests that match one or more of the customRules. \n The following profiles are provided: - Default: default policy which means MetaData level logging with the exception of events (not logged at all), oauthaccesstokens and oauthauthorizetokens (both logged at RequestBody level). - WriteRequestBodies: like 'Default', but logs request and response HTTP payloads for write requests (create, update, patch). - AllRequestBodies: like 'WriteRequestBodies', but also logs request and response HTTP payloads for read requests (get, list). - None: no requests are logged at all, not even oauthaccesstokens and oauthauthorizetokens. \n Warning: It is not recommended to disable audit logging by using the `None` profile unless you are fully aware of the risks of not logging data that can be beneficial when troubleshooting issues. If you disable audit logging and a support situation arises, you might need to enable audit logging and reproduce the issue in order to troubleshoot properly. \n If unset, the 'Default' profile is used as the default." + type: string + default: Default + enum: + - Default + - WriteRequestBodies + - AllRequestBodies + - None + clientCA: + description: 'clientCA references a ConfigMap containing a certificate bundle for the signers that will be recognized for incoming client certificates in addition to the operator managed signers. If this is empty, then only operator managed signers are valid. You usually only have to set this if you have your own PKI you wish to honor client certificates from. The ConfigMap must exist in the openshift-config namespace and contain the following required fields: - ConfigMap.Data["ca-bundle.crt"] - CA bundle.' + type: object + required: + - name + properties: + name: + description: name is the metadata.name of the referenced config map + type: string + encryption: + description: encryption allows the configuration of encryption of resources at the datastore layer. + type: object + properties: + type: + description: "type defines what encryption type should be used to encrypt resources at the datastore layer. When this field is unset (i.e. when it is set to the empty string), identity is implied. The behavior of unset can and will change over time. Even if encryption is enabled by default, the meaning of unset may change to a different encryption type based on changes in best practices. \n When encryption is enabled, all sensitive resources shipped with the platform are encrypted. This list of sensitive resources can and will change over time. The current authoritative list is: \n 1. secrets 2. configmaps 3. routes.route.openshift.io 4. oauthaccesstokens.oauth.openshift.io 5. oauthauthorizetokens.oauth.openshift.io" + type: string + enum: + - "" + - identity + - aescbc + - aesgcm + servingCerts: + description: servingCert is the TLS cert info for serving secure traffic. If not specified, operator managed certificates will be used for serving secure traffic. + type: object + properties: + namedCertificates: + description: namedCertificates references secrets containing the TLS cert info for serving secure traffic to specific hostnames. If no named certificates are provided, or no named certificates match the server name as understood by a client, the defaultServingCertificate will be used. + type: array + items: + description: APIServerNamedServingCert maps a server DNS name, as understood by a client, to a certificate. + type: object + properties: + names: + description: names is a optional list of explicit DNS names (leading wildcards allowed) that should use this certificate to serve secure traffic. If no names are provided, the implicit names will be extracted from the certificates. Exact names trump over wildcard names. Explicit names defined here trump over extracted implicit names. + type: array + items: + type: string + servingCertificate: + description: 'servingCertificate references a kubernetes.io/tls type secret containing the TLS cert info for serving secure traffic. The secret must exist in the openshift-config namespace and contain the following required fields: - Secret.Data["tls.key"] - TLS private key. - Secret.Data["tls.crt"] - TLS certificate.' + type: object + required: + - name + properties: + name: + description: name is the metadata.name of the referenced secret + type: string + tlsSecurityProfile: + description: "tlsSecurityProfile specifies settings for TLS connections for externally exposed servers. \n If unset, a default (which may change between releases) is chosen. Note that only Old, Intermediate and Custom profiles are currently supported, and the maximum available MinTLSVersions is VersionTLS12." + type: object + properties: + custom: + description: "custom is a user-defined TLS security profile. Be extremely careful using a custom profile as invalid configurations can be catastrophic. An example custom profile looks like this: \n ciphers: - ECDHE-ECDSA-CHACHA20-POLY1305 - ECDHE-RSA-CHACHA20-POLY1305 - ECDHE-RSA-AES128-GCM-SHA256 - ECDHE-ECDSA-AES128-GCM-SHA256 minTLSVersion: TLSv1.1" + type: object + properties: + ciphers: + description: "ciphers is used to specify the cipher algorithms that are negotiated during the TLS handshake. Operators may remove entries their operands do not support. For example, to use DES-CBC3-SHA (yaml): \n ciphers: - DES-CBC3-SHA" + type: array + items: + type: string + minTLSVersion: + description: "minTLSVersion is used to specify the minimal version of the TLS protocol that is negotiated during the TLS handshake. For example, to use TLS versions 1.1, 1.2 and 1.3 (yaml): \n minTLSVersion: TLSv1.1 \n NOTE: currently the highest minTLSVersion allowed is VersionTLS12" + type: string + enum: + - VersionTLS10 + - VersionTLS11 + - VersionTLS12 + - VersionTLS13 + nullable: true + intermediate: + description: "intermediate is a TLS security profile based on: \n https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29 \n and looks like this (yaml): \n ciphers: - TLS_AES_128_GCM_SHA256 - TLS_AES_256_GCM_SHA384 - TLS_CHACHA20_POLY1305_SHA256 - ECDHE-ECDSA-AES128-GCM-SHA256 - ECDHE-RSA-AES128-GCM-SHA256 - ECDHE-ECDSA-AES256-GCM-SHA384 - ECDHE-RSA-AES256-GCM-SHA384 - ECDHE-ECDSA-CHACHA20-POLY1305 - ECDHE-RSA-CHACHA20-POLY1305 - DHE-RSA-AES128-GCM-SHA256 - DHE-RSA-AES256-GCM-SHA384 minTLSVersion: TLSv1.2" + type: object + nullable: true + modern: + description: "modern is a TLS security profile based on: \n https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility \n and looks like this (yaml): \n ciphers: - TLS_AES_128_GCM_SHA256 - TLS_AES_256_GCM_SHA384 - TLS_CHACHA20_POLY1305_SHA256 minTLSVersion: TLSv1.3 \n NOTE: Currently unsupported." + type: object + nullable: true + old: + description: "old is a TLS security profile based on: \n https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility \n and looks like this (yaml): \n ciphers: - TLS_AES_128_GCM_SHA256 - TLS_AES_256_GCM_SHA384 - TLS_CHACHA20_POLY1305_SHA256 - ECDHE-ECDSA-AES128-GCM-SHA256 - ECDHE-RSA-AES128-GCM-SHA256 - ECDHE-ECDSA-AES256-GCM-SHA384 - ECDHE-RSA-AES256-GCM-SHA384 - ECDHE-ECDSA-CHACHA20-POLY1305 - ECDHE-RSA-CHACHA20-POLY1305 - DHE-RSA-AES128-GCM-SHA256 - DHE-RSA-AES256-GCM-SHA384 - DHE-RSA-CHACHA20-POLY1305 - ECDHE-ECDSA-AES128-SHA256 - ECDHE-RSA-AES128-SHA256 - ECDHE-ECDSA-AES128-SHA - ECDHE-RSA-AES128-SHA - ECDHE-ECDSA-AES256-SHA384 - ECDHE-RSA-AES256-SHA384 - ECDHE-ECDSA-AES256-SHA - ECDHE-RSA-AES256-SHA - DHE-RSA-AES128-SHA256 - DHE-RSA-AES256-SHA256 - AES128-GCM-SHA256 - AES256-GCM-SHA384 - AES128-SHA256 - AES256-SHA256 - AES128-SHA - AES256-SHA - DES-CBC3-SHA minTLSVersion: TLSv1.0" + type: object + nullable: true + type: + description: "type is one of Old, Intermediate, Modern or Custom. Custom provides the ability to specify individual TLS security profile parameters. Old, Intermediate and Modern are TLS security profiles based on: \n https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations \n The profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be reduced. \n Note that the Modern profile is currently not supported because it is not yet well adopted by common software libraries." + type: string + enum: + - Old + - Intermediate + - Modern + - Custom + status: + description: status holds observed values from the cluster. They may not be overridden. + type: object + served: true + storage: true + subresources: + status: {} diff --git a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-Default.crd.yaml b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-Default.crd.yaml index fe57bddfc6..8a449e8430 100644 --- a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-Default.crd.yaml +++ b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-Default.crd.yaml @@ -21,9 +21,6 @@ spec: schema: openAPIV3Schema: description: "Infrastructure holds cluster-wide information about Infrastructure. The canonical name is `cluster` \n Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer)." - type: object - required: - - spec properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' @@ -35,43 +32,41 @@ spec: type: object spec: description: spec holds user settable values for configuration - type: object properties: cloudConfig: description: "cloudConfig is a reference to a ConfigMap containing the cloud provider configuration file. This configuration file is used to configure the Kubernetes cloud provider integration when using the built-in cloud provider integration or the external cloud controller manager. The namespace for this config map is openshift-config. \n cloudConfig should only be consumed by the kube_cloud_config controller. The controller is responsible for using the user configuration in the spec for various platforms and combining that with the user provided ConfigMap in this field to create a stitched kube cloud config. The controller generates a ConfigMap `kube-cloud-config` in `openshift-config-managed` namespace with the kube cloud config is stored in `cloud.conf` key. All the clients are expected to use the generated ConfigMap only." - type: object properties: key: description: Key allows pointing to a specific key/value inside of the configmap. This is useful for logical file references. type: string name: type: string + type: object platformSpec: description: platformSpec holds desired information specific to the underlying infrastructure provider. - type: object properties: alibabaCloud: description: AlibabaCloud contains settings specific to the Alibaba Cloud infrastructure provider. type: object aws: description: AWS contains settings specific to the Amazon Web Services infrastructure provider. - type: object properties: serviceEndpoints: description: serviceEndpoints list contains custom endpoints which will override default service endpoint of AWS Services. There must be only one ServiceEndpoint for a service. - type: array items: description: AWSServiceEndpoint store the configuration of a custom url to override existing defaults of AWS Services. - type: object properties: name: description: name is the name of the AWS service. The list of all the service names can be found at https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html This must be provided and cannot be empty. - type: string pattern: ^[a-z0-9-]+$ + type: string url: description: url is fully qualified URI with scheme https, that overrides the default generated endpoint for a client. This must be provided and cannot be empty. - type: string pattern: ^https:// + type: string + type: object + type: array + type: object azure: description: Azure contains settings specific to the Azure infrastructure provider. type: object @@ -83,26 +78,15 @@ spec: type: object external: description: ExternalPlatformType represents generic infrastructure provider. Platform-specific components should be supplemented separately. - type: object properties: - cloudControllerManager: - description: CloudControllerManager contains settings specific to the external Cloud Controller Manager (a.k.a. CCM or CPI) - type: object - properties: - state: - description: "state determines whether or not an external Cloud Controller Manager is expected to be installed within the cluster. https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller/#running-cloud-controller-manager \n When set to \"External\", new nodes will be tainted as uninitialized when created, preventing them from running workloads until they are initialized by the cloud controller manager. When omitted or set to \"None\", new nodes will be not tainted and no extra initialization from the cloud controller manager is expected." - type: string - enum: - - "" - - External - - None platformName: + default: Unknown description: PlatformName holds the arbitrary string representing the infrastructure provider name, expected to be set at the installation time. This field is solely for informational and reporting purposes and is not expected to be used for decision-making. type: string - default: Unknown x-kubernetes-validations: - - rule: oldSelf == 'Unknown' || self == oldSelf - message: platform name cannot be changed once set + - message: platform name cannot be changed once set + rule: oldSelf == 'Unknown' || self == oldSelf + type: object gcp: description: GCP contains settings specific to the Google Cloud Platform infrastructure provider. type: object @@ -114,62 +98,62 @@ spec: type: object nutanix: description: Nutanix contains settings specific to the Nutanix infrastructure provider. - type: object - required: - - prismCentral - - prismElements properties: prismCentral: description: prismCentral holds the endpoint address and port to access the Nutanix Prism Central. When a cluster-wide proxy is installed, by default, this endpoint will be accessed via the proxy. Should you wish for communication with this endpoint not to be proxied, please add the endpoint to the proxy spec.noProxy list. - type: object - required: - - address - - port properties: address: description: address is the endpoint address (DNS name or IP address) of the Nutanix Prism Central or Element (cluster) - type: string maxLength: 256 + type: string port: description: port is the port number to access the Nutanix Prism Central or Element (cluster) - type: integer format: int32 maximum: 65535 minimum: 1 + type: integer + required: + - address + - port + type: object prismElements: description: prismElements holds one or more endpoint address and port data to access the Nutanix Prism Elements (clusters) of the Nutanix Prism Central. Currently we only support one Prism Element (cluster) for an OpenShift cluster, where all the Nutanix resources (VMs, subnets, volumes, etc.) used in the OpenShift cluster are located. In the future, we may support Nutanix resources (VMs, etc.) spread over multiple Prism Elements (clusters) of the Prism Central. - type: array items: description: NutanixPrismElementEndpoint holds the name and endpoint data for a Prism Element (cluster) - type: object - required: - - endpoint - - name properties: endpoint: description: endpoint holds the endpoint address and port data of the Prism Element (cluster). When a cluster-wide proxy is installed, by default, this endpoint will be accessed via the proxy. Should you wish for communication with this endpoint not to be proxied, please add the endpoint to the proxy spec.noProxy list. - type: object - required: - - address - - port properties: address: description: address is the endpoint address (DNS name or IP address) of the Nutanix Prism Central or Element (cluster) - type: string maxLength: 256 + type: string port: description: port is the port number to access the Nutanix Prism Central or Element (cluster) - type: integer format: int32 maximum: 65535 minimum: 1 + type: integer + required: + - address + - port + type: object name: description: name is the name of the Prism Element (cluster). This value will correspond with the cluster field configured on other resources (eg Machines, PVCs, etc). - type: string maxLength: 256 + type: string + required: + - endpoint + - name + type: object + type: array x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + required: + - prismCentral + - prismElements + type: object openstack: description: OpenStack contains settings specific to the OpenStack infrastructure provider. type: object @@ -178,33 +162,32 @@ spec: type: object powervs: description: PowerVS contains settings specific to the IBM Power Systems Virtual Servers infrastructure provider. - type: object properties: serviceEndpoints: description: serviceEndpoints is a list of custom endpoints which will override the default service endpoints of a Power VS service. - type: array items: description: PowervsServiceEndpoint stores the configuration of a custom url to override existing defaults of PowerVS Services. - type: object - required: - - name - - url properties: name: description: name is the name of the Power VS service. Few of the services are IAM - https://cloud.ibm.com/apidocs/iam-identity-token-api ResourceController - https://cloud.ibm.com/apidocs/resource-controller/resource-controller Power Cloud - https://cloud.ibm.com/apidocs/power-cloud - type: string pattern: ^[a-z0-9-]+$ + type: string url: description: url is fully qualified URI with scheme https, that overrides the default generated endpoint for a client. This must be provided and cannot be empty. - type: string format: uri pattern: ^https:// + type: string + required: + - name + - url + type: object + type: array x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + type: object type: description: type is the underlying infrastructure provider for the cluster. This value controls whether infrastructure automation such as service load balancers, dynamic volume provisioning, machine creation and deletion, and other integrations are enabled. If None, no infrastructure automation is enabled. Allowed values are "AWS", "Azure", "BareMetal", "GCP", "Libvirt", "OpenStack", "VSphere", "oVirt", "KubeVirt", "EquinixMetal", "PowerVS", "AlibabaCloud", "Nutanix" and "None". Individual components may not support all platforms, and must handle unrecognized platforms as None if they do not support that platform. - type: string enum: - "" - AWS @@ -223,12 +206,166 @@ spec: - AlibabaCloud - Nutanix - External + type: string vsphere: description: VSphere contains settings specific to the VSphere infrastructure provider. + properties: + failureDomains: + description: failureDomains contains the definition of region, zone and the vCenter topology. If this is omitted failure domains (regions and zones) will not be used. + items: + description: VSpherePlatformFailureDomainSpec holds the region and zone failure domain and the vCenter topology of that failure domain. + properties: + name: + description: name defines the arbitrary but unique name of a failure domain. + maxLength: 256 + minLength: 1 + type: string + region: + description: region defines the name of a region tag that will be attached to a vCenter datacenter. The tag category in vCenter must be named openshift-region. + maxLength: 80 + minLength: 1 + type: string + server: + anyOf: + - format: ipv4 + - format: ipv6 + - format: hostname + description: server is the fully-qualified domain name or the IP address of the vCenter server. --- + maxLength: 255 + minLength: 1 + type: string + topology: + description: Topology describes a given failure domain using vSphere constructs + properties: + computeCluster: + description: computeCluster the absolute path of the vCenter cluster in which virtual machine will be located. The absolute path is of the form //host/. The maximum length of the path is 2048 characters. + maxLength: 2048 + pattern: ^/.*?/host/.*? + type: string + datacenter: + description: datacenter is the name of vCenter datacenter in which virtual machines will be located. The maximum length of the datacenter name is 80 characters. + maxLength: 80 + type: string + datastore: + description: datastore is the absolute path of the datastore in which the virtual machine is located. The absolute path is of the form //datastore/ The maximum length of the path is 2048 characters. + maxLength: 2048 + pattern: ^/.*?/datastore/.*? + type: string + folder: + description: folder is the absolute path of the folder where virtual machines are located. The absolute path is of the form //vm/. The maximum length of the path is 2048 characters. + maxLength: 2048 + pattern: ^/.*?/vm/.*? + type: string + networks: + description: networks is the list of port group network names within this failure domain. Currently, we only support a single interface per RHCOS virtual machine. The available networks (port groups) can be listed using `govc ls 'network/*'` The single interface should be the absolute path of the form //network/. + items: + type: string + maxItems: 1 + minItems: 1 + type: array + resourcePool: + description: resourcePool is the absolute path of the resource pool where virtual machines will be created. The absolute path is of the form //host//Resources/. The maximum length of the path is 2048 characters. + maxLength: 2048 + pattern: ^/.*?/host/.*?/Resources.* + type: string + required: + - computeCluster + - datacenter + - datastore + - networks + type: object + zone: + description: zone defines the name of a zone tag that will be attached to a vCenter cluster. The tag category in vCenter must be named openshift-zone. + maxLength: 80 + minLength: 1 + type: string + required: + - name + - region + - server + - topology + - zone + type: object + type: array + nodeNetworking: + description: nodeNetworking contains the definition of internal and external network constraints for assigning the node's networking. If this field is omitted, networking defaults to the legacy address selection behavior which is to only support a single address and return the first one found. + properties: + external: + description: external represents the network configuration of the node that is externally routable. + properties: + excludeNetworkSubnetCidr: + description: excludeNetworkSubnetCidr IP addresses in subnet ranges will be excluded when selecting the IP address from the VirtualMachine's VM for use in the status.addresses fields. --- + items: + format: cidr + type: string + type: array + network: + description: network VirtualMachine's VM Network names that will be used to when searching for status.addresses fields. Note that if internal.networkSubnetCIDR and external.networkSubnetCIDR are not set, then the vNIC associated to this network must only have a single IP address assigned to it. The available networks (port groups) can be listed using `govc ls 'network/*'` + type: string + networkSubnetCidr: + description: networkSubnetCidr IP address on VirtualMachine's network interfaces included in the fields' CIDRs that will be used in respective status.addresses fields. --- + items: + format: cidr + type: string + type: array + type: object + internal: + description: internal represents the network configuration of the node that is routable only within the cluster. + properties: + excludeNetworkSubnetCidr: + description: excludeNetworkSubnetCidr IP addresses in subnet ranges will be excluded when selecting the IP address from the VirtualMachine's VM for use in the status.addresses fields. --- + items: + format: cidr + type: string + type: array + network: + description: network VirtualMachine's VM Network names that will be used to when searching for status.addresses fields. Note that if internal.networkSubnetCIDR and external.networkSubnetCIDR are not set, then the vNIC associated to this network must only have a single IP address assigned to it. The available networks (port groups) can be listed using `govc ls 'network/*'` + type: string + networkSubnetCidr: + description: networkSubnetCidr IP address on VirtualMachine's network interfaces included in the fields' CIDRs that will be used in respective status.addresses fields. --- + items: + format: cidr + type: string + type: array + type: object + type: object + vcenters: + description: vcenters holds the connection details for services to communicate with vCenter. Currently, only a single vCenter is supported. --- + items: + description: VSpherePlatformVCenterSpec stores the vCenter connection fields. This is used by the vSphere CCM. + properties: + datacenters: + description: The vCenter Datacenters in which the RHCOS vm guests are located. This field will be used by the Cloud Controller Manager. Each datacenter listed here should be used within a topology. + items: + type: string + minItems: 1 + type: array + port: + description: port is the TCP port that will be used to communicate to the vCenter endpoint. When omitted, this means the user has no opinion and it is up to the platform to choose a sensible default, which is subject to change over time. + format: int32 + maximum: 32767 + minimum: 1 + type: integer + server: + anyOf: + - format: ipv4 + - format: ipv6 + - format: hostname + description: server is the fully-qualified domain name or the IP address of the vCenter server. --- + maxLength: 255 + type: string + required: + - datacenters + - server + type: object + maxItems: 1 + minItems: 0 + type: array type: object + type: object + type: object status: description: status holds observed values from the cluster. They may not be overridden. - type: object properties: apiServerInternalURI: description: apiServerInternalURL is a valid URI with scheme 'https', address and optionally a port (defaulting to 443). apiServerInternalURL can be used by components like kubelets, to contact the Kubernetes API server using the infrastructure provider rather than Kubernetes networking. @@ -237,13 +374,13 @@ spec: description: apiServerURL is a valid URI with scheme 'https', address and optionally a port (defaulting to 443). apiServerURL can be used by components like the web console to tell users where to find the Kubernetes API. type: string controlPlaneTopology: - description: controlPlaneTopology expresses the expectations for operands that normally run on control nodes. The default is 'HighlyAvailable', which represents the behavior operators have in a "normal" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation The 'External' mode indicates that the control plane is hosted externally to the cluster and that its components are not visible within the cluster. - type: string default: HighlyAvailable + description: controlPlaneTopology expresses the expectations for operands that normally run on control nodes. The default is 'HighlyAvailable', which represents the behavior operators have in a "normal" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation The 'External' mode indicates that the control plane is hosted externally to the cluster and that its components are not visible within the cluster. enum: - HighlyAvailable - SingleReplica - External + type: string etcdDiscoveryDomain: description: 'etcdDiscoveryDomain is the domain used to fetch the SRV records for discovering etcd servers and clients. For more info: https://github.com/etcd-io/etcd/blob/329be66e8b3f9e2e6af83c123ff89297e49ebd15/Documentation/op-guide/clustering.md#dns-discovery deprecated: as of 4.7, this field is no longer set or honored. It will be removed in a future release.' type: string @@ -251,15 +388,14 @@ spec: description: infrastructureName uniquely identifies a cluster with a human friendly name. Once set it should not be changed. Must be of max length 27 and must have only alphanumeric or hyphen characters. type: string infrastructureTopology: - description: 'infrastructureTopology expresses the expectations for infrastructure services that do not run on control plane nodes, usually indicated by a node selector for a `role` value other than `master`. The default is ''HighlyAvailable'', which represents the behavior operators have in a "normal" cluster. The ''SingleReplica'' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation NOTE: External topology mode is not applicable for this field.' - type: string default: HighlyAvailable + description: 'infrastructureTopology expresses the expectations for infrastructure services that do not run on control plane nodes, usually indicated by a node selector for a `role` value other than `master`. The default is ''HighlyAvailable'', which represents the behavior operators have in a "normal" cluster. The ''SingleReplica'' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation NOTE: External topology mode is not applicable for this field.' enum: - HighlyAvailable - SingleReplica + type: string platform: description: "platform is the underlying infrastructure provider for the cluster. \n Deprecated: Use platformStatus.type instead." - type: string enum: - "" - AWS @@ -278,103 +414,101 @@ spec: - AlibabaCloud - Nutanix - External + type: string platformStatus: description: platformStatus holds status information specific to the underlying infrastructure provider. - type: object properties: alibabaCloud: description: AlibabaCloud contains settings specific to the Alibaba Cloud infrastructure provider. - type: object - required: - - region properties: region: description: region specifies the region for Alibaba Cloud resources created for the cluster. - type: string pattern: ^[0-9A-Za-z-]+$ + type: string resourceGroupID: description: resourceGroupID is the ID of the resource group for the cluster. - type: string pattern: ^(rg-[0-9A-Za-z]+)?$ + type: string resourceTags: description: resourceTags is a list of additional tags to apply to Alibaba Cloud resources created for the cluster. - type: array - maxItems: 20 items: description: AlibabaCloudResourceTag is the set of tags to add to apply to resources. - type: object - required: - - key - - value properties: key: description: key is the key of the tag. - type: string maxLength: 128 minLength: 1 + type: string value: description: value is the value of the tag. - type: string maxLength: 128 minLength: 1 + type: string + required: + - key + - value + type: object + maxItems: 20 + type: array x-kubernetes-list-map-keys: - key x-kubernetes-list-type: map + required: + - region + type: object aws: description: AWS contains settings specific to the Amazon Web Services infrastructure provider. - type: object properties: region: description: region holds the default AWS region for new AWS resources created by the cluster. type: string resourceTags: description: resourceTags is a list of additional tags to apply to AWS resources created for the cluster. See https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html for information on tagging AWS resources. AWS supports a maximum of 50 tags per resource. OpenShift reserves 25 tags for its use, leaving 25 tags available for the user. - type: array - maxItems: 25 items: description: AWSResourceTag is a tag to apply to AWS resources created for the cluster. - type: object - required: - - key - - value properties: key: description: key is the key of the tag - type: string maxLength: 128 minLength: 1 pattern: ^[0-9A-Za-z_.:/=+-@]+$ + type: string value: description: value is the value of the tag. Some AWS service do not support empty values. Since tags are added to resources in many services, the length of the tag value must meet the requirements of all services. - type: string maxLength: 256 minLength: 1 pattern: ^[0-9A-Za-z_.:/=+-@]+$ + type: string + required: + - key + - value + type: object + maxItems: 25 + type: array serviceEndpoints: description: ServiceEndpoints list contains custom endpoints which will override default service endpoint of AWS Services. There must be only one ServiceEndpoint for a service. - type: array items: description: AWSServiceEndpoint store the configuration of a custom url to override existing defaults of AWS Services. - type: object properties: name: description: name is the name of the AWS service. The list of all the service names can be found at https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html This must be provided and cannot be empty. - type: string pattern: ^[a-z0-9-]+$ + type: string url: description: url is fully qualified URI with scheme https, that overrides the default generated endpoint for a client. This must be provided and cannot be empty. - type: string pattern: ^https:// + type: string + type: object + type: array + type: object azure: description: Azure contains settings specific to the Azure infrastructure provider. - type: object properties: armEndpoint: description: armEndpoint specifies a URL to use for resource management in non-soverign clouds such as Azure Stack. type: string cloudName: description: cloudName is the name of the Azure cloud environment which can be used to configure the Azure SDK with the appropriate Azure API endpoints. If empty, the value is equal to `AzurePublicCloud`. - type: string enum: - "" - AzurePublicCloud @@ -382,42 +516,72 @@ spec: - AzureChinaCloud - AzureGermanCloud - AzureStackCloud + type: string networkResourceGroupName: description: networkResourceGroupName is the Resource Group for network resources like the Virtual Network and Subnets used by the cluster. If empty, the value is same as ResourceGroupName. type: string resourceGroupName: description: resourceGroupName is the Resource Group for new Azure resources created for the cluster. type: string + resourceTags: + description: resourceTags is a list of additional tags to apply to Azure resources created for the cluster. See https://docs.microsoft.com/en-us/rest/api/resources/tags for information on tagging Azure resources. Due to limitations on Automation, Content Delivery Network, DNS Azure resources, a maximum of 15 tags may be applied. OpenShift reserves 5 tags for internal use, allowing 10 tags for user configuration. + items: + description: AzureResourceTag is a tag to apply to Azure resources created for the cluster. + properties: + key: + description: key is the key part of the tag. A tag key can have a maximum of 128 characters and cannot be empty. Key must begin with a letter, end with a letter, number or underscore, and must contain only alphanumeric characters and the following special characters `_ . -`. + maxLength: 128 + minLength: 1 + pattern: ^[a-zA-Z]([0-9A-Za-z_.-]*[0-9A-Za-z_])?$ + type: string + value: + description: 'value is the value part of the tag. A tag value can have a maximum of 256 characters and cannot be empty. Value must contain only alphanumeric characters and the following special characters `_ + , - . / : ; < = > ? @`.' + maxLength: 256 + minLength: 1 + pattern: ^[0-9A-Za-z_.=+-@]+$ + type: string + required: + - key + - value + type: object + maxItems: 10 + type: array + x-kubernetes-validations: + - message: resourceTags are immutable and may only be configured during installation + rule: self.all(x, x in oldSelf) && oldSelf.all(x, x in self) + type: object + x-kubernetes-validations: + - message: resourceTags may only be configured during installation + rule: '!has(oldSelf.resourceTags) && !has(self.resourceTags) || has(oldSelf.resourceTags) && has(self.resourceTags)' baremetal: description: BareMetal contains settings specific to the BareMetal platform. - type: object properties: apiServerInternalIP: description: "apiServerInternalIP is an IP address to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. It is the IP that the Infrastructure.status.apiServerInternalURI points to. It is the IP for a self-hosted load balancer in front of the API servers. \n Deprecated: Use APIServerInternalIPs instead." type: string apiServerInternalIPs: description: apiServerInternalIPs are the IP addresses to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. These are the IPs for a self-hosted load balancer in front of the API servers. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array ingressIP: description: "ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names. \n Deprecated: Use IngressIPs instead." type: string ingressIPs: description: ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array nodeDNSIP: description: nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for BareMetal deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster. type: string + type: object equinixMetal: description: EquinixMetal contains settings specific to the Equinix Metal infrastructure provider. - type: object properties: apiServerInternalIP: description: apiServerInternalIP is an IP address to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. It is the IP that the Infrastructure.status.apiServerInternalURI points to. It is the IP for a self-hosted load balancer in front of the API servers. @@ -425,12 +589,12 @@ spec: ingressIP: description: ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names. type: string + type: object external: description: External contains settings specific to the generic External infrastructure provider. type: object gcp: description: GCP contains settings specific to the Google Cloud Platform infrastructure provider. - type: object properties: projectID: description: resourceGroupName is the Project ID for new GCP resources created for the cluster. @@ -438,9 +602,9 @@ spec: region: description: region holds the region for new GCP resources created for the cluster. type: string + type: object ibmcloud: description: IBMCloud contains settings specific to the IBMCloud infrastructure provider. - type: object properties: cisInstanceCRN: description: CISInstanceCRN is the CRN of the Cloud Internet Services instance managing the DNS zone for the cluster's base domain @@ -457,9 +621,9 @@ spec: resourceGroupName: description: ResourceGroupName is the Resource Group for new IBMCloud resources created for the cluster. type: string + type: object kubevirt: description: Kubevirt contains settings specific to the kubevirt infrastructure provider. - type: object properties: apiServerInternalIP: description: apiServerInternalIP is an IP address to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. It is the IP that the Infrastructure.status.apiServerInternalURI points to. It is the IP for a self-hosted load balancer in front of the API servers. @@ -467,44 +631,44 @@ spec: ingressIP: description: ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names. type: string + type: object nutanix: description: Nutanix contains settings specific to the Nutanix infrastructure provider. - type: object properties: apiServerInternalIP: description: "apiServerInternalIP is an IP address to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. It is the IP that the Infrastructure.status.apiServerInternalURI points to. It is the IP for a self-hosted load balancer in front of the API servers. \n Deprecated: Use APIServerInternalIPs instead." type: string apiServerInternalIPs: description: apiServerInternalIPs are the IP addresses to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. These are the IPs for a self-hosted load balancer in front of the API servers. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array ingressIP: description: "ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names. \n Deprecated: Use IngressIPs instead." type: string ingressIPs: description: ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array + type: object openstack: description: OpenStack contains settings specific to the OpenStack infrastructure provider. - type: object properties: apiServerInternalIP: description: "apiServerInternalIP is an IP address to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. It is the IP that the Infrastructure.status.apiServerInternalURI points to. It is the IP for a self-hosted load balancer in front of the API servers. \n Deprecated: Use APIServerInternalIPs instead." type: string apiServerInternalIPs: description: apiServerInternalIPs are the IP addresses to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. These are the IPs for a self-hosted load balancer in front of the API servers. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array cloudName: description: cloudName is the name of the desired OpenStack cloud in the client configuration file (`clouds.yaml`). type: string @@ -513,44 +677,44 @@ spec: type: string ingressIPs: description: ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array nodeDNSIP: description: nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for OpenStack deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster. type: string + type: object ovirt: description: Ovirt contains settings specific to the oVirt infrastructure provider. - type: object properties: apiServerInternalIP: description: "apiServerInternalIP is an IP address to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. It is the IP that the Infrastructure.status.apiServerInternalURI points to. It is the IP for a self-hosted load balancer in front of the API servers. \n Deprecated: Use APIServerInternalIPs instead." type: string apiServerInternalIPs: description: apiServerInternalIPs are the IP addresses to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. These are the IPs for a self-hosted load balancer in front of the API servers. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array ingressIP: description: "ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names. \n Deprecated: Use IngressIPs instead." type: string ingressIPs: description: ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array nodeDNSIP: description: 'deprecated: as of 4.6, this field is no longer set or honored. It will be removed in a future release.' type: string + type: object powervs: description: PowerVS contains settings specific to the Power Systems Virtual Servers infrastructure provider. - type: object properties: cisInstanceCRN: description: CISInstanceCRN is the CRN of the Cloud Internet Services instance managing the DNS zone for the cluster's base domain @@ -561,31 +725,42 @@ spec: region: description: region holds the default Power VS region for new Power VS resources created by the cluster. type: string + resourceGroup: + description: 'resourceGroup is the resource group name for new IBMCloud resources created for a cluster. The resource group specified here will be used by cluster-image-registry-operator to set up a COS Instance in IBMCloud for the cluster registry. More about resource groups can be found here: https://cloud.ibm.com/docs/account?topic=account-rgs. When omitted, the image registry operator won''t be able to configure storage, which results in the image registry cluster operator not being in an available state.' + maxLength: 40 + pattern: ^[a-zA-Z0-9-_ ]+$ + type: string + x-kubernetes-validations: + - message: resourceGroup is immutable once set + rule: oldSelf == '' || self == oldSelf serviceEndpoints: description: serviceEndpoints is a list of custom endpoints which will override the default service endpoints of a Power VS service. - type: array items: description: PowervsServiceEndpoint stores the configuration of a custom url to override existing defaults of PowerVS Services. - type: object - required: - - name - - url properties: name: description: name is the name of the Power VS service. Few of the services are IAM - https://cloud.ibm.com/apidocs/iam-identity-token-api ResourceController - https://cloud.ibm.com/apidocs/resource-controller/resource-controller Power Cloud - https://cloud.ibm.com/apidocs/power-cloud - type: string pattern: ^[a-z0-9-]+$ + type: string url: description: url is fully qualified URI with scheme https, that overrides the default generated endpoint for a client. This must be provided and cannot be empty. - type: string format: uri pattern: ^https:// + type: string + required: + - name + - url + type: object + type: array zone: description: 'zone holds the default zone for the new Power VS resources created by the cluster. Note: Currently only single-zone OCP clusters are supported' type: string + type: object + x-kubernetes-validations: + - message: cannot unset resourceGroup once set + rule: '!has(oldSelf.resourceGroup) || has(self.resourceGroup)' type: description: "type is the underlying infrastructure provider for the cluster. This value controls whether infrastructure automation such as service load balancers, dynamic volume provisioning, machine creation and deletion, and other integrations are enabled. If None, no infrastructure automation is enabled. Allowed values are \"AWS\", \"Azure\", \"BareMetal\", \"GCP\", \"Libvirt\", \"OpenStack\", \"VSphere\", \"oVirt\", \"EquinixMetal\", \"PowerVS\", \"AlibabaCloud\", \"Nutanix\" and \"None\". Individual components may not support all platforms, and must handle unrecognized platforms as None if they do not support that platform. \n This value will be synced with to the `status.platform` and `status.platformStatus.type`. Currently this value cannot be changed once set." - type: string enum: - "" - AWS @@ -604,33 +779,39 @@ spec: - AlibabaCloud - Nutanix - External + type: string vsphere: description: VSphere contains settings specific to the VSphere infrastructure provider. - type: object properties: apiServerInternalIP: description: "apiServerInternalIP is an IP address to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. It is the IP that the Infrastructure.status.apiServerInternalURI points to. It is the IP for a self-hosted load balancer in front of the API servers. \n Deprecated: Use APIServerInternalIPs instead." type: string apiServerInternalIPs: description: apiServerInternalIPs are the IP addresses to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. These are the IPs for a self-hosted load balancer in front of the API servers. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array ingressIP: description: "ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names. \n Deprecated: Use IngressIPs instead." type: string ingressIPs: description: ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one. - type: array format: ip - maxItems: 2 items: type: string + maxItems: 2 + type: array nodeDNSIP: description: nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for vSphere deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster. type: string + type: object + type: object + type: object + required: + - spec + type: object served: true storage: true subresources: diff --git a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-Default.crd.yaml-patch b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-Default.crd.yaml-patch new file mode 100644 index 0000000000..d127130add --- /dev/null +++ b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-Default.crd.yaml-patch @@ -0,0 +1,24 @@ +- op: add + path: /spec/versions/name=v1/schema/openAPIV3Schema/properties/spec/properties/platformSpec/properties/vsphere/properties/vcenters/items/properties/server/anyOf + value: + - format: ipv4 + - format: ipv6 + - format: hostname +- op: add + path: /spec/versions/name=v1/schema/openAPIV3Schema/properties/spec/properties/platformSpec/properties/vsphere/properties/failureDomains/items/properties/server/anyOf + value: + - format: ipv4 + - format: ipv6 + - format: hostname +- op: add + path: /spec/versions/name=v1/schema/openAPIV3Schema/properties/spec/properties/platformSpec/properties/vsphere/properties/nodeNetworking/properties/external/properties/excludeNetworkSubnetCidr/items/format + value: cidr +- op: add + path: /spec/versions/name=v1/schema/openAPIV3Schema/properties/spec/properties/platformSpec/properties/vsphere/properties/nodeNetworking/properties/external/properties/networkSubnetCidr/items/format + value: cidr +- op: add + path: /spec/versions/name=v1/schema/openAPIV3Schema/properties/spec/properties/platformSpec/properties/vsphere/properties/nodeNetworking/properties/internal/properties/excludeNetworkSubnetCidr/items/format + value: cidr +- op: add + path: /spec/versions/name=v1/schema/openAPIV3Schema/properties/spec/properties/platformSpec/properties/vsphere/properties/nodeNetworking/properties/internal/properties/networkSubnetCidr/items/format + value: cidr diff --git a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-TechPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-TechPreviewNoUpgrade.crd.yaml index 01eeb09289..495e4a5581 100644 --- a/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-TechPreviewNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/config/v1/0000_10_config-operator_01_infrastructure-TechPreviewNoUpgrade.crd.yaml @@ -79,17 +79,6 @@ spec: external: description: ExternalPlatformType represents generic infrastructure provider. Platform-specific components should be supplemented separately. properties: - cloudControllerManager: - description: CloudControllerManager contains settings specific to the external Cloud Controller Manager (a.k.a. CCM or CPI) - properties: - state: - description: "state determines whether or not an external Cloud Controller Manager is expected to be installed within the cluster. https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller/#running-cloud-controller-manager \n When set to \"External\", new nodes will be tainted as uninitialized when created, preventing them from running workloads until they are initialized by the cloud controller manager. When omitted or set to \"None\", new nodes will be not tainted and no extra initialization from the cloud controller manager is expected." - enum: - - "" - - External - - None - type: string - type: object platformName: default: Unknown description: PlatformName holds the arbitrary string representing the infrastructure provider name, expected to be set at the installation time. This field is solely for informational and reporting purposes and is not expected to be used for decision-making. @@ -392,6 +381,13 @@ spec: - SingleReplica - External type: string + cpuPartitioning: + default: None + description: cpuPartitioning expresses if CPU partitioning is a currently enabled feature in the cluster. CPU Partitioning means that this cluster can support partitioning workloads to specific CPU Sets. Valid values are "None" and "AllNodes". When omitted, the default value is "None". The default value of "None" indicates that no nodes will be setup with CPU partitioning. The "AllNodes" value indicates that all nodes have been setup with CPU partitioning, and can then be further configured via the PerformanceProfile API. + enum: + - None + - AllNodes + type: string etcdDiscoveryDomain: description: 'etcdDiscoveryDomain is the domain used to fetch the SRV records for discovering etcd servers and clients. For more info: https://github.com/etcd-io/etcd/blob/329be66e8b3f9e2e6af83c123ff89297e49ebd15/Documentation/op-guide/clustering.md#dns-discovery deprecated: as of 4.7, this field is no longer set or honored. It will be removed in a future release.' type: string @@ -534,7 +530,36 @@ spec: resourceGroupName: description: resourceGroupName is the Resource Group for new Azure resources created for the cluster. type: string + resourceTags: + description: resourceTags is a list of additional tags to apply to Azure resources created for the cluster. See https://docs.microsoft.com/en-us/rest/api/resources/tags for information on tagging Azure resources. Due to limitations on Automation, Content Delivery Network, DNS Azure resources, a maximum of 15 tags may be applied. OpenShift reserves 5 tags for internal use, allowing 10 tags for user configuration. + items: + description: AzureResourceTag is a tag to apply to Azure resources created for the cluster. + properties: + key: + description: key is the key part of the tag. A tag key can have a maximum of 128 characters and cannot be empty. Key must begin with a letter, end with a letter, number or underscore, and must contain only alphanumeric characters and the following special characters `_ . -`. + maxLength: 128 + minLength: 1 + pattern: ^[a-zA-Z]([0-9A-Za-z_.-]*[0-9A-Za-z_])?$ + type: string + value: + description: 'value is the value part of the tag. A tag value can have a maximum of 256 characters and cannot be empty. Value must contain only alphanumeric characters and the following special characters `_ + , - . / : ; < = > ? @`.' + maxLength: 256 + minLength: 1 + pattern: ^[0-9A-Za-z_.=+-@]+$ + type: string + required: + - key + - value + type: object + maxItems: 10 + type: array + x-kubernetes-validations: + - message: resourceTags are immutable and may only be configured during installation + rule: self.all(x, x in oldSelf) && oldSelf.all(x, x in self) type: object + x-kubernetes-validations: + - message: resourceTags may only be configured during installation + rule: '!has(oldSelf.resourceTags) && !has(self.resourceTags) || has(oldSelf.resourceTags) && has(self.resourceTags)' baremetal: description: BareMetal contains settings specific to the BareMetal platform. properties: @@ -558,6 +583,22 @@ spec: type: string maxItems: 2 type: array + loadBalancer: + default: + type: OpenShiftManagedDefault + description: loadBalancer defines how the load balancer used by the cluster is configured. + properties: + type: + default: OpenShiftManagedDefault + description: type defines the type of load balancer used by the cluster on BareMetal platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault. + enum: + - OpenShiftManagedDefault + - UserManaged + type: string + x-kubernetes-validations: + - message: type is immutable once set + rule: oldSelf == '' || self == oldSelf + type: object nodeDNSIP: description: nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for BareMetal deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster. type: string @@ -637,6 +678,22 @@ spec: type: string maxItems: 2 type: array + loadBalancer: + default: + type: OpenShiftManagedDefault + description: loadBalancer defines how the load balancer used by the cluster is configured. + properties: + type: + default: OpenShiftManagedDefault + description: type defines the type of load balancer used by the cluster on Nutanix platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault. + enum: + - OpenShiftManagedDefault + - UserManaged + type: string + x-kubernetes-validations: + - message: type is immutable once set + rule: oldSelf == '' || self == oldSelf + type: object type: object openstack: description: OpenStack contains settings specific to the OpenStack infrastructure provider. @@ -664,6 +721,22 @@ spec: type: string maxItems: 2 type: array + loadBalancer: + default: + type: OpenShiftManagedDefault + description: loadBalancer defines how the load balancer used by the cluster is configured. + properties: + type: + default: OpenShiftManagedDefault + description: type defines the type of load balancer used by the cluster on OpenStack platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault. + enum: + - OpenShiftManagedDefault + - UserManaged + type: string + x-kubernetes-validations: + - message: type is immutable once set + rule: oldSelf == '' || self == oldSelf + type: object nodeDNSIP: description: nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for OpenStack deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster. type: string @@ -691,6 +764,22 @@ spec: type: string maxItems: 2 type: array + loadBalancer: + default: + type: OpenShiftManagedDefault + description: loadBalancer defines how the load balancer used by the cluster is configured. + properties: + type: + default: OpenShiftManagedDefault + description: type defines the type of load balancer used by the cluster on Ovirt platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault. + enum: + - OpenShiftManagedDefault + - UserManaged + type: string + x-kubernetes-validations: + - message: type is immutable once set + rule: oldSelf == '' || self == oldSelf + type: object nodeDNSIP: description: 'deprecated: as of 4.6, this field is no longer set or honored. It will be removed in a future release.' type: string @@ -707,6 +796,14 @@ spec: region: description: region holds the default Power VS region for new Power VS resources created by the cluster. type: string + resourceGroup: + description: 'resourceGroup is the resource group name for new IBMCloud resources created for a cluster. The resource group specified here will be used by cluster-image-registry-operator to set up a COS Instance in IBMCloud for the cluster registry. More about resource groups can be found here: https://cloud.ibm.com/docs/account?topic=account-rgs. When omitted, the image registry operator won''t be able to configure storage, which results in the image registry cluster operator not being in an available state.' + maxLength: 40 + pattern: ^[a-zA-Z0-9-_ ]+$ + type: string + x-kubernetes-validations: + - message: resourceGroup is immutable once set + rule: oldSelf == '' || self == oldSelf serviceEndpoints: description: serviceEndpoints is a list of custom endpoints which will override the default service endpoints of a Power VS service. items: @@ -730,6 +827,9 @@ spec: description: 'zone holds the default zone for the new Power VS resources created by the cluster. Note: Currently only single-zone OCP clusters are supported' type: string type: object + x-kubernetes-validations: + - message: cannot unset resourceGroup once set + rule: '!has(oldSelf.resourceGroup) || has(self.resourceGroup)' type: description: "type is the underlying infrastructure provider for the cluster. This value controls whether infrastructure automation such as service load balancers, dynamic volume provisioning, machine creation and deletion, and other integrations are enabled. If None, no infrastructure automation is enabled. Allowed values are \"AWS\", \"Azure\", \"BareMetal\", \"GCP\", \"Libvirt\", \"OpenStack\", \"VSphere\", \"oVirt\", \"EquinixMetal\", \"PowerVS\", \"AlibabaCloud\", \"Nutanix\" and \"None\". Individual components may not support all platforms, and must handle unrecognized platforms as None if they do not support that platform. \n This value will be synced with to the `status.platform` and `status.platformStatus.type`. Currently this value cannot be changed once set." enum: @@ -774,6 +874,22 @@ spec: type: string maxItems: 2 type: array + loadBalancer: + default: + type: OpenShiftManagedDefault + description: loadBalancer defines how the load balancer used by the cluster is configured. + properties: + type: + default: OpenShiftManagedDefault + description: type defines the type of load balancer used by the cluster on VSphere platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault. + enum: + - OpenShiftManagedDefault + - UserManaged + type: string + x-kubernetes-validations: + - message: type is immutable once set + rule: oldSelf == '' || self == oldSelf + type: object nodeDNSIP: description: nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for vSphere deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster. type: string diff --git a/vendor/github.com/openshift/api/config/v1/stable.apiserver.testsuite.yaml b/vendor/github.com/openshift/api/config/v1/stable.apiserver.testsuite.yaml index 5c28143d54..75f846a3db 100644 --- a/vendor/github.com/openshift/api/config/v1/stable.apiserver.testsuite.yaml +++ b/vendor/github.com/openshift/api/config/v1/stable.apiserver.testsuite.yaml @@ -1,16 +1,36 @@ apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this name: "[Stable] APIServer" -crd: 0000_10_config-operator_01_apiserver.crd.yaml +crd: 0000_10_config-operator_01_apiserver-Default.crd.yaml tests: onCreate: - - name: Should be able to create a minimal ClusterOperator + - name: Should be able to create encrypt with aescbc initial: | apiVersion: config.openshift.io/v1 kind: APIServer - spec: {} # No spec is required for a APIServer + spec: + encryption: + type: aescbc + expected: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + audit: + profile: Default + encryption: + type: aescbc + - name: Should be able to create encrypt with aesgcm + initial: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + encryption: + type: aesgcm expected: | apiVersion: config.openshift.io/v1 kind: APIServer spec: audit: profile: Default + encryption: + type: aesgcm + diff --git a/vendor/github.com/openshift/api/config/v1/stable.infrastructure.testsuite.yaml b/vendor/github.com/openshift/api/config/v1/stable.infrastructure.testsuite.yaml index bbafe4c478..0896992622 100644 --- a/vendor/github.com/openshift/api/config/v1/stable.infrastructure.testsuite.yaml +++ b/vendor/github.com/openshift/api/config/v1/stable.infrastructure.testsuite.yaml @@ -56,3 +56,258 @@ tests: external: platformName: SomeOtherCoolplatformName expectedError: " spec.platformSpec.external.platformName: Invalid value: \"string\": platform name cannot be changed once set" + - name: Should not be able to modify an existing Azure ResourceTags Tag + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: "HighlyAvailable" + infrastructureTopology: "HighlyAvailable" + platform: Azure + platformStatus: + type: Azure + azure: + resourceTags: + - {key: "key", value: "value"} + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + type: Azure + azure: + resourceTags: + - {key: "key", value: "changed"} + expectedStatusError: "status.platformStatus.azure.resourceTags: Invalid value: \"array\": resourceTags are immutable and may only be configured during installation" + - name: Should not be able to add a Tag to an existing Azure ResourceTags + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: "HighlyAvailable" + infrastructureTopology: "HighlyAvailable" + platform: Azure + platformStatus: + type: Azure + azure: + resourceTags: + - {key: "key", value: "value"} + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + type: Azure + azure: + resourceTags: + - {key: "key", value: "value"} + - {key: "new", value: "entry"} + expectedStatusError: "status.platformStatus.azure.resourceTags: Invalid value: \"array\": resourceTags are immutable and may only be configured during installation" + - name: Should not be able to remove a Tag from an existing Azure ResourceTags + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + type: Azure + azure: + resourceTags: + - {key: "key", value: "value"} + - {key: "new", value: "entry"} + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + type: Azure + azure: + resourceTags: + - {key: "key", value: "value"} + expectedStatusError: "status.platformStatus.azure.resourceTags: Invalid value: \"array\": resourceTags are immutable and may only be configured during installation" + - name: Should not be able to add Azure ResourceTags to an empty platformStatus.azure + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + type: Azure + azure: {} + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + azure: + resourceTags: + - {key: "key", value: "value"} + expectedStatusError: "status.platformStatus.azure: Invalid value: \"object\": resourceTags may only be configured during installation" + - name: Should not be able to remove Azure ResourceTags from platformStatus.azure + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + type: Azure + azure: + resourceTags: + - {key: "key", value: "value"} + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + type: Azure + azure: {} + expectedStatusError: "status.platformStatus.azure: Invalid value: \"object\": resourceTags may only be configured during installation" + - name: Should be able to modify the ResourceGroupName while Azure ResourceTags are present + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + type: Azure + azure: + resourceGroupName: foo + resourceTags: + - {key: "key", value: "value"} + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + platform: Azure + platformStatus: + azure: + resourceGroupName: bar + resourceTags: + - {key: "key", value: "value"} + expected: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: "HighlyAvailable" + infrastructureTopology: "HighlyAvailable" + platform: Azure + platformStatus: + azure: + resourceGroupName: bar + resourceTags: + - {key: "key", value: "value"} + - name: PowerVS platform status's resourceGroup length should not exceed the max length set + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: PowerVS + status: + platform: PowerVS + platformStatus: + powervs: + resourceGroup: resource-group + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: PowerVS + status: + platform: PowerVS + platformStatus: + powervs: + resourceGroup: resource-group-should-not-accept-the-string-that-exceeds-max-length-set + expectedStatusError: "status.platformStatus.powervs.resourceGroup: Too long: may not be longer than 40" + - name: PowerVS platform status's resourceGroup should match the regex configured + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: PowerVS + status: + platform: PowerVS + platformStatus: + powervs: + resourceGroup: resource-group + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: PowerVS + status: + platform: PowerVS + platformStatus: + powervs: + resourceGroup: re$ource-group + expectedStatusError: "status.platformStatus.powervs.resourceGroup in body should match '^[a-zA-Z0-9-_ ]+$'" + - name: Should not be able to change PowerVS platform status's resourceGroup once it was set + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: PowerVS + status: + platform: PowerVS + platformStatus: + powervs: + resourceGroup: resource-group + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: PowerVS + status: + platform: PowerVS + platformStatus: + powervs: + resourceGroup: other-resource-group-name + expectedStatusError: "status.platformStatus.powervs.resourceGroup: Invalid value: \"string\": resourceGroup is immutable once set" + - name: Should not be able to unset PowerVS platform status's resourceGroup once it was set + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: PowerVS + status: + platform: PowerVS + platformStatus: + powervs: + region: some-region + resourceGroup: resource-group + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: PowerVS + status: + platform: PowerVS + platformStatus: + powervs: + region: some-region + expectedStatusError: "status.platformStatus.powervs: Invalid value: \"object\": cannot unset resourceGroup once set" diff --git a/vendor/github.com/openshift/api/config/v1/techpreview.apiserver.testsuite.yaml b/vendor/github.com/openshift/api/config/v1/techpreview.apiserver.testsuite.yaml new file mode 100644 index 0000000000..74aa92b470 --- /dev/null +++ b/vendor/github.com/openshift/api/config/v1/techpreview.apiserver.testsuite.yaml @@ -0,0 +1,35 @@ +apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this +name: "[TechPreviewNoUpgrade] APIServer" +crd: 0000_10_config-operator_01_apiserver-TechPreviewNoUpgrade.crd.yaml +tests: + onCreate: + - name: Should be able to create encrypt with aescbc + initial: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + encryption: + type: aescbc + expected: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + audit: + profile: Default + encryption: + type: aescbc + - name: Should be able to create encrypt with aesgcm + initial: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + encryption: + type: aesgcm + expected: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + audit: + profile: Default + encryption: + type: aesgcm diff --git a/vendor/github.com/openshift/api/config/v1/techpreview.infrastructure.testsuite.yaml b/vendor/github.com/openshift/api/config/v1/techpreview.infrastructure.testsuite.yaml index 23580beea3..f9829b9a39 100644 --- a/vendor/github.com/openshift/api/config/v1/techpreview.infrastructure.testsuite.yaml +++ b/vendor/github.com/openshift/api/config/v1/techpreview.infrastructure.testsuite.yaml @@ -12,3 +12,202 @@ tests: apiVersion: config.openshift.io/v1 kind: Infrastructure spec: {} + onUpdate: + - name: Status Should contain default fields + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: {} + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: {} + expected: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + cpuPartitioning: None + infrastructureTopology: HighlyAvailable + controlPlaneTopology: HighlyAvailable + - name: Status update cpuPartitioning should fail validation check + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + cpuPartitioning: None + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + cpuPartitioning: "Invalid" + expectedStatusError: 'status.cpuPartitioning: Unsupported value: "Invalid": supported values: "None", "AllNodes"' + - name: Should set load balancer type to OpenShiftManagedDefault if not specified + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + status: + platform: BareMetal + platformStatus: + baremetal: {} + type: BareMetal + expected: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + status: + controlPlaneTopology: HighlyAvailable + cpuPartitioning: None + infrastructureTopology: HighlyAvailable + platform: BareMetal + platformStatus: + baremetal: + loadBalancer: + type: OpenShiftManagedDefault + type: BareMetal + - name: Should be able to override the default load balancer with a valid value + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + status: + platform: BareMetal + platformStatus: + baremetal: + loadBalancer: + type: UserManaged + type: BareMetal + expected: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + status: + controlPlaneTopology: HighlyAvailable + cpuPartitioning: None + infrastructureTopology: HighlyAvailable + platform: BareMetal + platformStatus: + baremetal: + loadBalancer: + type: UserManaged + type: BareMetal + - name: Should not allow changing the immutable load balancer type field + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + status: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + platform: BareMetal + platformStatus: + baremetal: + loadBalancer: + type: OpenShiftManagedDefault + type: BareMetal + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: BareMetal + baremetal: {} + status: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + platform: BareMetal + platformStatus: + baremetal: + loadBalancer: + type: UserManaged + type: BareMetal + expectedStatusError: "status.platformStatus.baremetal.loadBalancer.type: Invalid value: \"string\": type is immutable once set" + - name: Should not allow removing the immutable load balancer type field that was initially set + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + status: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + platform: BareMetal + platformStatus: + baremetal: + loadBalancer: + type: UserManaged + type: BareMetal + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + type: BareMetal + baremetal: {} + status: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + platform: BareMetal + platformStatus: + baremetal: {} + type: BareMetal + expectedStatusError: "status.platformStatus.baremetal.loadBalancer.type: Invalid value: \"string\": type is immutable once set" + - name: Should not allow setting the load balancer type to a wrong value + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: + platformSpec: + baremetal: {} + type: BareMetal + status: + platform: BareMetal + platformStatus: + baremetal: + loadBalancer: + type: FooBar + type: BareMetal + expectedStatusError: "status.platformStatus.baremetal.loadBalancer.type: Unsupported value: \"FooBar\": supported values: \"OpenShiftManagedDefault\", \"UserManaged\"" diff --git a/vendor/github.com/openshift/api/config/v1/types_apiserver.go b/vendor/github.com/openshift/api/config/v1/types_apiserver.go index 31801aacf0..f4b52a2277 100644 --- a/vendor/github.com/openshift/api/config/v1/types_apiserver.go +++ b/vendor/github.com/openshift/api/config/v1/types_apiserver.go @@ -184,7 +184,7 @@ type APIServerEncryption struct { Type EncryptionType `json:"type,omitempty"` } -// +kubebuilder:validation:Enum="";identity;aescbc +// +kubebuilder:validation:Enum="";identity;aescbc;aesgcm type EncryptionType string const ( @@ -195,6 +195,10 @@ const ( // aescbc refers to a type where AES-CBC with PKCS#7 padding and a 32-byte key // is used to perform encryption at the datastore layer. EncryptionTypeAESCBC EncryptionType = "aescbc" + + // aesgcm refers to a type where AES-GCM with random nonce and a 32-byte key + // is used to perform encryption at the datastore layer. + EncryptionTypeAESGCM EncryptionType = "aesgcm" ) type APIServerStatus struct { diff --git a/vendor/github.com/openshift/api/config/v1/types_feature.go b/vendor/github.com/openshift/api/config/v1/types_feature.go index 644eb650b6..a254cac4fe 100644 --- a/vendor/github.com/openshift/api/config/v1/types_feature.go +++ b/vendor/github.com/openshift/api/config/v1/types_feature.go @@ -114,12 +114,12 @@ var FeatureSets = map[FeatureSet]*FeatureGateEnabledDisabled{ with("BuildCSIVolumes"). // sig-build, adkaplan, OCP specific with("NodeSwap"). // sig-node, ehashman, Kubernetes feature gate with("MachineAPIProviderOpenStack"). // openstack, egarcia (#forum-openstack), OCP specific - with("CGroupsV2"). // sig-node, harche, OCP specific - with("Crun"). // sig-node, haircommander, OCP specific with("InsightsConfigAPI"). // insights, tremes (#ccx), OCP specific - with("CSIInlineVolumeAdmission"). // sig-storage, jdobson, OCP specific with("MatchLabelKeysInPodTopologySpread"). // sig-scheduling, ingvagabund (#forum-workloads), Kubernetes feature gate with("RetroactiveDefaultStorageClass"). // sig-storage, RomanBednar, Kubernetes feature gate + with("PDBUnhealthyPodEvictionPolicy"). // sig-apps, atiratree (#forum-workloads), Kubernetes feature gate + with("DynamicResourceAllocation"). // sig-scheduling, jchaloup (#forum-workloads), Kubernetes feature gate + with("OpenShiftPodSecurityAdmission"). // bz-auth, stlaz, OCP specific toFeatures(), LatencySensitive: newDefaultFeatures(). with( @@ -133,7 +133,6 @@ var defaultFeatures = &FeatureGateEnabledDisabled{ "APIPriorityAndFairness", // sig-apimachinery, deads2k "RotateKubeletServerCertificate", // sig-pod, sjenning "DownwardAPIHugePages", // sig-node, rphillips - "OpenShiftPodSecurityAdmission", // bz-auth, stlaz, OCP specific }, Disabled: []string{ "RetroactiveDefaultStorageClass", // sig-storage, RomanBednar, Kubernetes feature gate diff --git a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go index f1f1697a70..c6e3c23874 100644 --- a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go +++ b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go @@ -101,6 +101,19 @@ type InfrastructureStatus struct { // +kubebuilder:default=HighlyAvailable // +kubebuilder:validation:Enum=HighlyAvailable;SingleReplica InfrastructureTopology TopologyMode `json:"infrastructureTopology"` + + // cpuPartitioning expresses if CPU partitioning is a currently enabled feature in the cluster. + // CPU Partitioning means that this cluster can support partitioning workloads to specific CPU Sets. + // Valid values are "None" and "AllNodes". When omitted, the default value is "None". + // The default value of "None" indicates that no nodes will be setup with CPU partitioning. + // The "AllNodes" value indicates that all nodes have been setup with CPU partitioning, + // and can then be further configured via the PerformanceProfile API. + // +kubebuilder:default=None + // +default="None" + // +kubebuilder:validation:Enum=None;AllNodes + // +openshift:enable:FeatureSets=TechPreviewNoUpgrade + // +optional + CPUPartitioning CPUPartitioningMode `json:"cpuPartitioning,omitempty"` } // TopologyMode defines the topology mode of the control/infra nodes. @@ -123,6 +136,28 @@ const ( ExternalTopologyMode TopologyMode = "External" ) +// CPUPartitioningMode defines the mode for CPU partitioning +type CPUPartitioningMode string + +const ( + // CPUPartitioningNone means that no CPU Partitioning is on in this cluster infrastructure + CPUPartitioningNone CPUPartitioningMode = "None" + + // CPUPartitioningAllNodes means that all nodes are configured with CPU Partitioning in this cluster + CPUPartitioningAllNodes CPUPartitioningMode = "AllNodes" +) + +// PlatformLoadBalancerType defines the type of load balancer used by the cluster. +type PlatformLoadBalancerType string + +const ( + // LoadBalancerTypeUserManaged is a load balancer with control-plane VIPs managed outside of the cluster by the customer. + LoadBalancerTypeUserManaged PlatformLoadBalancerType = "UserManaged" + + // LoadBalancerTypeOpenShiftManagedDefault is the default load balancer with control-plane VIPs managed by the OpenShift cluster. + LoadBalancerTypeOpenShiftManagedDefault PlatformLoadBalancerType = "OpenShiftManagedDefault" +) + // PlatformType is a specific supported infrastructure provider. // +kubebuilder:validation:Enum="";AWS;Azure;BareMetal;GCP;Libvirt;OpenStack;None;VSphere;oVirt;IBMCloud;KubeVirt;EquinixMetal;PowerVS;AlibabaCloud;Nutanix;External type PlatformType string @@ -192,36 +227,6 @@ const ( IBMCloudProviderTypeUPI IBMCloudProviderType = "UPI" ) -// CloudControllerManagerState defines whether Cloud Controller Manager presence is expected or not -type CloudControllerManagerState string - -const ( - // Cloud Controller Manager is enabled and expected to be installed. - // This value indicates that new nodes should be tainted as uninitialized when created, - // preventing them from running workloads until they are initialized by the cloud controller manager. - CloudControllerManagerExternal CloudControllerManagerState = "External" - - // Cloud Controller Manager is disabled and not expected to be installed. - // This value indicates that new nodes should not be tainted - // and no extra node initialization is expected from the cloud controller manager. - CloudControllerManagerNone CloudControllerManagerState = "None" -) - -// CloudControllerManagerSpec holds Cloud Controller Manager (a.k.a. CCM or CPI) related settings -type CloudControllerManagerSpec struct { - // state determines whether or not an external Cloud Controller Manager is expected to - // be installed within the cluster. - // https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller/#running-cloud-controller-manager - // - // When set to "External", new nodes will be tainted as uninitialized when created, - // preventing them from running workloads until they are initialized by the cloud controller manager. - // When omitted or set to "None", new nodes will be not tainted - // and no extra initialization from the cloud controller manager is expected. - // +kubebuilder:validation:Enum="";External;None - // +optional - State CloudControllerManagerState `json:"state"` -} - // ExternalPlatformSpec holds the desired state for the generic External infrastructure provider. type ExternalPlatformSpec struct { // PlatformName holds the arbitrary string representing the infrastructure provider name, expected to be set at the installation time. @@ -231,9 +236,6 @@ type ExternalPlatformSpec struct { // +kubebuilder:validation:XValidation:rule="oldSelf == 'Unknown' || self == oldSelf",message="platform name cannot be changed once set" // +optional PlatformName string `json:"platformName,omitempty"` - // CloudControllerManager contains settings specific to the external Cloud Controller Manager (a.k.a. CCM or CPI) - // +optional - CloudControllerManager CloudControllerManagerSpec `json:"cloudControllerManager"` } // PlatformSpec holds the desired state specific to the underlying infrastructure provider @@ -460,6 +462,7 @@ type AWSResourceTag struct { type AzurePlatformSpec struct{} // AzurePlatformStatus holds the current status of the Azure infrastructure provider. +// +kubebuilder:validation:XValidation:rule="!has(oldSelf.resourceTags) && !has(self.resourceTags) || has(oldSelf.resourceTags) && has(self.resourceTags)",message="resourceTags may only be configured during installation" type AzurePlatformStatus struct { // resourceGroupName is the Resource Group for new Azure resources created for the cluster. ResourceGroupName string `json:"resourceGroupName"` @@ -478,6 +481,34 @@ type AzurePlatformStatus struct { // armEndpoint specifies a URL to use for resource management in non-soverign clouds such as Azure Stack. // +optional ARMEndpoint string `json:"armEndpoint,omitempty"` + + // resourceTags is a list of additional tags to apply to Azure resources created for the cluster. + // See https://docs.microsoft.com/en-us/rest/api/resources/tags for information on tagging Azure resources. + // Due to limitations on Automation, Content Delivery Network, DNS Azure resources, a maximum of 15 tags + // may be applied. OpenShift reserves 5 tags for internal use, allowing 10 tags for user configuration. + // +kubebuilder:validation:MaxItems=10 + // +kubebuilder:validation:XValidation:rule="self.all(x, x in oldSelf) && oldSelf.all(x, x in self)",message="resourceTags are immutable and may only be configured during installation" + // +optional + ResourceTags []AzureResourceTag `json:"resourceTags,omitempty"` +} + +// AzureResourceTag is a tag to apply to Azure resources created for the cluster. +type AzureResourceTag struct { + // key is the key part of the tag. A tag key can have a maximum of 128 characters and cannot be empty. Key + // must begin with a letter, end with a letter, number or underscore, and must contain only alphanumeric + // characters and the following special characters `_ . -`. + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=128 + // +kubebuilder:validation:Pattern=`^[a-zA-Z]([0-9A-Za-z_.-]*[0-9A-Za-z_])?$` + Key string `json:"key"` + // value is the value part of the tag. A tag value can have a maximum of 256 characters and cannot be empty. Value + // must contain only alphanumeric characters and the following special characters `_ + , - . / : ; < = > ? @`. + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=256 + // +kubebuilder:validation:Pattern=`^[0-9A-Za-z_.=+-@]+$` + Value string `json:"value"` } // AzureCloudEnvironment is the name of the Azure cloud environment @@ -514,6 +545,27 @@ type GCPPlatformStatus struct { Region string `json:"region"` } +// BareMetalPlatformLoadBalancer defines the load balancer used by the cluster on BareMetal platform. +// +union +type BareMetalPlatformLoadBalancer struct { + // type defines the type of load balancer used by the cluster on BareMetal platform + // which can be a user-managed or openshift-managed load balancer + // that is to be used for the OpenShift API and Ingress endpoints. + // When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing + // defined in the machine config operator will be deployed. + // When set to UserManaged these static pods will not be deployed and it is expected that + // the load balancer is configured out of band by the deployer. + // When omitted, this means no opinion and the platform is left to choose a reasonable default. + // The default value is OpenShiftManagedDefault. + // +default="OpenShiftManagedDefault" + // +kubebuilder:default:="OpenShiftManagedDefault" + // +kubebuilder:validation:Enum:="OpenShiftManagedDefault";"UserManaged" + // +kubebuilder:validation:XValidation:rule="oldSelf == '' || self == oldSelf",message="type is immutable once set" + // +optional + // +unionDiscriminator + Type PlatformLoadBalancerType `json:"type,omitempty"` +} + // BareMetalPlatformSpec holds the desired state of the BareMetal infrastructure provider. // This only includes fields that can be modified in the cluster. type BareMetalPlatformSpec struct{} @@ -562,6 +614,34 @@ type BareMetalPlatformStatus struct { // datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames // to the nodes in the cluster. NodeDNSIP string `json:"nodeDNSIP,omitempty"` + + // loadBalancer defines how the load balancer used by the cluster is configured. + // +default={"type": "OpenShiftManagedDefault"} + // +kubebuilder:default={"type": "OpenShiftManagedDefault"} + // +openshift:enable:FeatureSets=TechPreviewNoUpgrade + // +optional + LoadBalancer *BareMetalPlatformLoadBalancer `json:"loadBalancer,omitempty"` +} + +// OpenStackPlatformLoadBalancer defines the load balancer used by the cluster on OpenStack platform. +// +union +type OpenStackPlatformLoadBalancer struct { + // type defines the type of load balancer used by the cluster on OpenStack platform + // which can be a user-managed or openshift-managed load balancer + // that is to be used for the OpenShift API and Ingress endpoints. + // When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing + // defined in the machine config operator will be deployed. + // When set to UserManaged these static pods will not be deployed and it is expected that + // the load balancer is configured out of band by the deployer. + // When omitted, this means no opinion and the platform is left to choose a reasonable default. + // The default value is OpenShiftManagedDefault. + // +default="OpenShiftManagedDefault" + // +kubebuilder:default:="OpenShiftManagedDefault" + // +kubebuilder:validation:Enum:="OpenShiftManagedDefault";"UserManaged" + // +kubebuilder:validation:XValidation:rule="oldSelf == '' || self == oldSelf",message="type is immutable once set" + // +optional + // +unionDiscriminator + Type PlatformLoadBalancerType `json:"type,omitempty"` } // OpenStackPlatformSpec holds the desired state of the OpenStack infrastructure provider. @@ -614,6 +694,34 @@ type OpenStackPlatformStatus struct { // datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames // to the nodes in the cluster. NodeDNSIP string `json:"nodeDNSIP,omitempty"` + + // loadBalancer defines how the load balancer used by the cluster is configured. + // +default={"type": "OpenShiftManagedDefault"} + // +kubebuilder:default={"type": "OpenShiftManagedDefault"} + // +openshift:enable:FeatureSets=TechPreviewNoUpgrade + // +optional + LoadBalancer *OpenStackPlatformLoadBalancer `json:"loadBalancer,omitempty"` +} + +// OvirtPlatformLoadBalancer defines the load balancer used by the cluster on Ovirt platform. +// +union +type OvirtPlatformLoadBalancer struct { + // type defines the type of load balancer used by the cluster on Ovirt platform + // which can be a user-managed or openshift-managed load balancer + // that is to be used for the OpenShift API and Ingress endpoints. + // When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing + // defined in the machine config operator will be deployed. + // When set to UserManaged these static pods will not be deployed and it is expected that + // the load balancer is configured out of band by the deployer. + // When omitted, this means no opinion and the platform is left to choose a reasonable default. + // The default value is OpenShiftManagedDefault. + // +default="OpenShiftManagedDefault" + // +kubebuilder:default:="OpenShiftManagedDefault" + // +kubebuilder:validation:Enum:="OpenShiftManagedDefault";"UserManaged" + // +kubebuilder:validation:XValidation:rule="oldSelf == '' || self == oldSelf",message="type is immutable once set" + // +optional + // +unionDiscriminator + Type PlatformLoadBalancerType `json:"type,omitempty"` } // OvirtPlatformSpec holds the desired state of the oVirt infrastructure provider. @@ -657,6 +765,34 @@ type OvirtPlatformStatus struct { // deprecated: as of 4.6, this field is no longer set or honored. It will be removed in a future release. NodeDNSIP string `json:"nodeDNSIP,omitempty"` + + // loadBalancer defines how the load balancer used by the cluster is configured. + // +default={"type": "OpenShiftManagedDefault"} + // +kubebuilder:default={"type": "OpenShiftManagedDefault"} + // +openshift:enable:FeatureSets=TechPreviewNoUpgrade + // +optional + LoadBalancer *OvirtPlatformLoadBalancer `json:"loadBalancer,omitempty"` +} + +// VSpherePlatformLoadBalancer defines the load balancer used by the cluster on VSphere platform. +// +union +type VSpherePlatformLoadBalancer struct { + // type defines the type of load balancer used by the cluster on VSphere platform + // which can be a user-managed or openshift-managed load balancer + // that is to be used for the OpenShift API and Ingress endpoints. + // When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing + // defined in the machine config operator will be deployed. + // When set to UserManaged these static pods will not be deployed and it is expected that + // the load balancer is configured out of band by the deployer. + // When omitted, this means no opinion and the platform is left to choose a reasonable default. + // The default value is OpenShiftManagedDefault. + // +default="OpenShiftManagedDefault" + // +kubebuilder:default:="OpenShiftManagedDefault" + // +kubebuilder:validation:Enum:="OpenShiftManagedDefault";"UserManaged" + // +kubebuilder:validation:XValidation:rule="oldSelf == '' || self == oldSelf",message="type is immutable once set" + // +optional + // +unionDiscriminator + Type PlatformLoadBalancerType `json:"type,omitempty"` } // VSpherePlatformFailureDomainSpec holds the region and zone failure domain and @@ -834,7 +970,6 @@ type VSpherePlatformSpec struct { // --- // + If VCenters is not defined use the existing cloud-config configmap defined // + in openshift-config. - // +openshift:enable:FeatureSets=TechPreviewNoUpgrade // +kubebuilder:validation:MaxItems=1 // +kubebuilder:validation:MinItems=0 // +optional @@ -842,7 +977,6 @@ type VSpherePlatformSpec struct { // failureDomains contains the definition of region, zone and the vCenter topology. // If this is omitted failure domains (regions and zones) will not be used. - // +openshift:enable:FeatureSets=TechPreviewNoUpgrade // +optional FailureDomains []VSpherePlatformFailureDomainSpec `json:"failureDomains,omitempty"` @@ -851,7 +985,6 @@ type VSpherePlatformSpec struct { // If this field is omitted, networking defaults to the legacy // address selection behavior which is to only support a single address and // return the first one found. - // +openshift:enable:FeatureSets=TechPreviewNoUpgrade // +optional NodeNetworking VSpherePlatformNodeNetworking `json:"nodeNetworking,omitempty"` } @@ -898,6 +1031,13 @@ type VSpherePlatformStatus struct { // datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames // to the nodes in the cluster. NodeDNSIP string `json:"nodeDNSIP,omitempty"` + + // loadBalancer defines how the load balancer used by the cluster is configured. + // +default={"type": "OpenShiftManagedDefault"} + // +kubebuilder:default={"type": "OpenShiftManagedDefault"} + // +openshift:enable:FeatureSets=TechPreviewNoUpgrade + // +optional + LoadBalancer *VSpherePlatformLoadBalancer `json:"loadBalancer,omitempty"` } // IBMCloudPlatformSpec holds the desired state of the IBMCloud infrastructure provider. @@ -994,6 +1134,7 @@ type PowerVSPlatformSpec struct { } // PowerVSPlatformStatus holds the current status of the IBM Power Systems Virtual Servers infrastrucutre provider. +// +kubebuilder:validation:XValidation:rule="!has(oldSelf.resourceGroup) || has(self.resourceGroup)",message="cannot unset resourceGroup once set" type PowerVSPlatformStatus struct { // region holds the default Power VS region for new Power VS resources created by the cluster. Region string `json:"region"` @@ -1002,6 +1143,18 @@ type PowerVSPlatformStatus struct { // Note: Currently only single-zone OCP clusters are supported Zone string `json:"zone"` + // resourceGroup is the resource group name for new IBMCloud resources created for a cluster. + // The resource group specified here will be used by cluster-image-registry-operator to set up a COS Instance in IBMCloud for the cluster registry. + // More about resource groups can be found here: https://cloud.ibm.com/docs/account?topic=account-rgs. + // When omitted, the image registry operator won't be able to configure storage, + // which results in the image registry cluster operator not being in an available state. + // + // +kubebuilder:validation:Pattern=^[a-zA-Z0-9-_ ]+$ + // +kubebuilder:validation:MaxLength=40 + // +kubebuilder:validation:XValidation:rule="oldSelf == '' || self == oldSelf",message="resourceGroup is immutable once set" + // +optional + ResourceGroup string `json:"resourceGroup"` + // serviceEndpoints is a list of custom endpoints which will override the default // service endpoints of a Power VS service. // +optional @@ -1055,6 +1208,27 @@ type AlibabaCloudResourceTag struct { Value string `json:"value"` } +// NutanixPlatformLoadBalancer defines the load balancer used by the cluster on Nutanix platform. +// +union +type NutanixPlatformLoadBalancer struct { + // type defines the type of load balancer used by the cluster on Nutanix platform + // which can be a user-managed or openshift-managed load balancer + // that is to be used for the OpenShift API and Ingress endpoints. + // When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing + // defined in the machine config operator will be deployed. + // When set to UserManaged these static pods will not be deployed and it is expected that + // the load balancer is configured out of band by the deployer. + // When omitted, this means no opinion and the platform is left to choose a reasonable default. + // The default value is OpenShiftManagedDefault. + // +default="OpenShiftManagedDefault" + // +kubebuilder:default:="OpenShiftManagedDefault" + // +kubebuilder:validation:Enum:="OpenShiftManagedDefault";"UserManaged" + // +kubebuilder:validation:XValidation:rule="oldSelf == '' || self == oldSelf",message="type is immutable once set" + // +optional + // +unionDiscriminator + Type PlatformLoadBalancerType `json:"type,omitempty"` +} + // NutanixPlatformSpec holds the desired state of the Nutanix infrastructure provider. // This only includes fields that can be modified in the cluster. type NutanixPlatformSpec struct { @@ -1140,6 +1314,13 @@ type NutanixPlatformStatus struct { // +kubebuilder:validation:Format=ip // +kubebuilder:validation:MaxItems=2 IngressIPs []string `json:"ingressIPs"` + + // loadBalancer defines how the load balancer used by the cluster is configured. + // +default={"type": "OpenShiftManagedDefault"} + // +kubebuilder:default={"type": "OpenShiftManagedDefault"} + // +openshift:enable:FeatureSets=TechPreviewNoUpgrade + // +optional + LoadBalancer *NutanixPlatformLoadBalancer `json:"loadBalancer,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go index a9babbc7f2..254a9eb73d 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go @@ -555,6 +555,11 @@ func (in *AzurePlatformSpec) DeepCopy() *AzurePlatformSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzurePlatformStatus) DeepCopyInto(out *AzurePlatformStatus) { *out = *in + if in.ResourceTags != nil { + in, out := &in.ResourceTags, &out.ResourceTags + *out = make([]AzureResourceTag, len(*in)) + copy(*out, *in) + } return } @@ -568,6 +573,38 @@ func (in *AzurePlatformStatus) DeepCopy() *AzurePlatformStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureResourceTag) DeepCopyInto(out *AzureResourceTag) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureResourceTag. +func (in *AzureResourceTag) DeepCopy() *AzureResourceTag { + if in == nil { + return nil + } + out := new(AzureResourceTag) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BareMetalPlatformLoadBalancer) DeepCopyInto(out *BareMetalPlatformLoadBalancer) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BareMetalPlatformLoadBalancer. +func (in *BareMetalPlatformLoadBalancer) DeepCopy() *BareMetalPlatformLoadBalancer { + if in == nil { + return nil + } + out := new(BareMetalPlatformLoadBalancer) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BareMetalPlatformSpec) DeepCopyInto(out *BareMetalPlatformSpec) { *out = *in @@ -597,6 +634,11 @@ func (in *BareMetalPlatformStatus) DeepCopyInto(out *BareMetalPlatformStatus) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.LoadBalancer != nil { + in, out := &in.LoadBalancer, &out.LoadBalancer + *out = new(BareMetalPlatformLoadBalancer) + **out = **in + } return } @@ -817,22 +859,6 @@ func (in *ClientConnectionOverrides) DeepCopy() *ClientConnectionOverrides { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CloudControllerManagerSpec) DeepCopyInto(out *CloudControllerManagerSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudControllerManagerSpec. -func (in *CloudControllerManagerSpec) DeepCopy() *CloudControllerManagerSpec { - if in == nil { - return nil - } - out := new(CloudControllerManagerSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterCondition) DeepCopyInto(out *ClusterCondition) { *out = *in @@ -1794,7 +1820,6 @@ func (in *ExternalIPPolicy) DeepCopy() *ExternalIPPolicy { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ExternalPlatformSpec) DeepCopyInto(out *ExternalPlatformSpec) { *out = *in - out.CloudControllerManager = in.CloudControllerManager return } @@ -3494,6 +3519,22 @@ func (in *NodeStatus) DeepCopy() *NodeStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NutanixPlatformLoadBalancer) DeepCopyInto(out *NutanixPlatformLoadBalancer) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixPlatformLoadBalancer. +func (in *NutanixPlatformLoadBalancer) DeepCopy() *NutanixPlatformLoadBalancer { + if in == nil { + return nil + } + out := new(NutanixPlatformLoadBalancer) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NutanixPlatformSpec) DeepCopyInto(out *NutanixPlatformSpec) { *out = *in @@ -3529,6 +3570,11 @@ func (in *NutanixPlatformStatus) DeepCopyInto(out *NutanixPlatformStatus) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.LoadBalancer != nil { + in, out := &in.LoadBalancer, &out.LoadBalancer + *out = new(NutanixPlatformLoadBalancer) + **out = **in + } return } @@ -3814,6 +3860,22 @@ func (in *OpenIDIdentityProvider) DeepCopy() *OpenIDIdentityProvider { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenStackPlatformLoadBalancer) DeepCopyInto(out *OpenStackPlatformLoadBalancer) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackPlatformLoadBalancer. +func (in *OpenStackPlatformLoadBalancer) DeepCopy() *OpenStackPlatformLoadBalancer { + if in == nil { + return nil + } + out := new(OpenStackPlatformLoadBalancer) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackPlatformSpec) DeepCopyInto(out *OpenStackPlatformSpec) { *out = *in @@ -3843,6 +3905,11 @@ func (in *OpenStackPlatformStatus) DeepCopyInto(out *OpenStackPlatformStatus) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.LoadBalancer != nil { + in, out := &in.LoadBalancer, &out.LoadBalancer + *out = new(OpenStackPlatformLoadBalancer) + **out = **in + } return } @@ -3975,6 +4042,22 @@ func (in *OperatorHubStatus) DeepCopy() *OperatorHubStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OvirtPlatformLoadBalancer) DeepCopyInto(out *OvirtPlatformLoadBalancer) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OvirtPlatformLoadBalancer. +func (in *OvirtPlatformLoadBalancer) DeepCopy() *OvirtPlatformLoadBalancer { + if in == nil { + return nil + } + out := new(OvirtPlatformLoadBalancer) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OvirtPlatformSpec) DeepCopyInto(out *OvirtPlatformSpec) { *out = *in @@ -4004,6 +4087,11 @@ func (in *OvirtPlatformStatus) DeepCopyInto(out *OvirtPlatformStatus) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.LoadBalancer != nil { + in, out := &in.LoadBalancer, &out.LoadBalancer + *out = new(OvirtPlatformLoadBalancer) + **out = **in + } return } @@ -4114,7 +4202,7 @@ func (in *PlatformStatus) DeepCopyInto(out *PlatformStatus) { if in.Azure != nil { in, out := &in.Azure, &out.Azure *out = new(AzurePlatformStatus) - **out = **in + (*in).DeepCopyInto(*out) } if in.GCP != nil { in, out := &in.GCP, &out.GCP @@ -4956,6 +5044,22 @@ func (in *VSpherePlatformFailureDomainSpec) DeepCopy() *VSpherePlatformFailureDo return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VSpherePlatformLoadBalancer) DeepCopyInto(out *VSpherePlatformLoadBalancer) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VSpherePlatformLoadBalancer. +func (in *VSpherePlatformLoadBalancer) DeepCopy() *VSpherePlatformLoadBalancer { + if in == nil { + return nil + } + out := new(VSpherePlatformLoadBalancer) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VSpherePlatformNodeNetworking) DeepCopyInto(out *VSpherePlatformNodeNetworking) { *out = *in @@ -5044,6 +5148,11 @@ func (in *VSpherePlatformStatus) DeepCopyInto(out *VSpherePlatformStatus) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.LoadBalancer != nil { + in, out := &in.LoadBalancer, &out.LoadBalancer + *out = new(VSpherePlatformLoadBalancer) + **out = **in + } return } diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go index 0f149c9900..e52d01ecee 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go @@ -1064,12 +1064,32 @@ var map_AzurePlatformStatus = map[string]string{ "networkResourceGroupName": "networkResourceGroupName is the Resource Group for network resources like the Virtual Network and Subnets used by the cluster. If empty, the value is same as ResourceGroupName.", "cloudName": "cloudName is the name of the Azure cloud environment which can be used to configure the Azure SDK with the appropriate Azure API endpoints. If empty, the value is equal to `AzurePublicCloud`.", "armEndpoint": "armEndpoint specifies a URL to use for resource management in non-soverign clouds such as Azure Stack.", + "resourceTags": "resourceTags is a list of additional tags to apply to Azure resources created for the cluster. See https://docs.microsoft.com/en-us/rest/api/resources/tags for information on tagging Azure resources. Due to limitations on Automation, Content Delivery Network, DNS Azure resources, a maximum of 15 tags may be applied. OpenShift reserves 5 tags for internal use, allowing 10 tags for user configuration.", } func (AzurePlatformStatus) SwaggerDoc() map[string]string { return map_AzurePlatformStatus } +var map_AzureResourceTag = map[string]string{ + "": "AzureResourceTag is a tag to apply to Azure resources created for the cluster.", + "key": "key is the key part of the tag. A tag key can have a maximum of 128 characters and cannot be empty. Key must begin with a letter, end with a letter, number or underscore, and must contain only alphanumeric characters and the following special characters `_ . -`.", + "value": "value is the value part of the tag. A tag value can have a maximum of 256 characters and cannot be empty. Value must contain only alphanumeric characters and the following special characters `_ + , - . / : ; < = > ? @`.", +} + +func (AzureResourceTag) SwaggerDoc() map[string]string { + return map_AzureResourceTag +} + +var map_BareMetalPlatformLoadBalancer = map[string]string{ + "": "BareMetalPlatformLoadBalancer defines the load balancer used by the cluster on BareMetal platform.", + "type": "type defines the type of load balancer used by the cluster on BareMetal platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault.", +} + +func (BareMetalPlatformLoadBalancer) SwaggerDoc() map[string]string { + return map_BareMetalPlatformLoadBalancer +} + var map_BareMetalPlatformSpec = map[string]string{ "": "BareMetalPlatformSpec holds the desired state of the BareMetal infrastructure provider. This only includes fields that can be modified in the cluster.", } @@ -1085,21 +1105,13 @@ var map_BareMetalPlatformStatus = map[string]string{ "ingressIP": "ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names.\n\nDeprecated: Use IngressIPs instead.", "ingressIPs": "ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one.", "nodeDNSIP": "nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for BareMetal deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster.", + "loadBalancer": "loadBalancer defines how the load balancer used by the cluster is configured.", } func (BareMetalPlatformStatus) SwaggerDoc() map[string]string { return map_BareMetalPlatformStatus } -var map_CloudControllerManagerSpec = map[string]string{ - "": "CloudControllerManagerSpec holds Cloud Controller Manager (a.k.a. CCM or CPI) related settings", - "state": "state determines whether or not an external Cloud Controller Manager is expected to be installed within the cluster. https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller/#running-cloud-controller-manager\n\nWhen set to \"External\", new nodes will be tainted as uninitialized when created, preventing them from running workloads until they are initialized by the cloud controller manager. When omitted or set to \"None\", new nodes will be not tainted and no extra initialization from the cloud controller manager is expected.", -} - -func (CloudControllerManagerSpec) SwaggerDoc() map[string]string { - return map_CloudControllerManagerSpec -} - var map_EquinixMetalPlatformSpec = map[string]string{ "": "EquinixMetalPlatformSpec holds the desired state of the Equinix Metal infrastructure provider. This only includes fields that can be modified in the cluster.", } @@ -1119,9 +1131,8 @@ func (EquinixMetalPlatformStatus) SwaggerDoc() map[string]string { } var map_ExternalPlatformSpec = map[string]string{ - "": "ExternalPlatformSpec holds the desired state for the generic External infrastructure provider.", - "platformName": "PlatformName holds the arbitrary string representing the infrastructure provider name, expected to be set at the installation time. This field is solely for informational and reporting purposes and is not expected to be used for decision-making.", - "cloudControllerManager": "CloudControllerManager contains settings specific to the external Cloud Controller Manager (a.k.a. CCM or CPI)", + "": "ExternalPlatformSpec holds the desired state for the generic External infrastructure provider.", + "platformName": "PlatformName holds the arbitrary string representing the infrastructure provider name, expected to be set at the installation time. This field is solely for informational and reporting purposes and is not expected to be used for decision-making.", } func (ExternalPlatformSpec) SwaggerDoc() map[string]string { @@ -1213,6 +1224,7 @@ var map_InfrastructureStatus = map[string]string{ "apiServerInternalURI": "apiServerInternalURL is a valid URI with scheme 'https', address and optionally a port (defaulting to 443). apiServerInternalURL can be used by components like kubelets, to contact the Kubernetes API server using the infrastructure provider rather than Kubernetes networking.", "controlPlaneTopology": "controlPlaneTopology expresses the expectations for operands that normally run on control nodes. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation The 'External' mode indicates that the control plane is hosted externally to the cluster and that its components are not visible within the cluster.", "infrastructureTopology": "infrastructureTopology expresses the expectations for infrastructure services that do not run on control plane nodes, usually indicated by a node selector for a `role` value other than `master`. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation NOTE: External topology mode is not applicable for this field.", + "cpuPartitioning": "cpuPartitioning expresses if CPU partitioning is a currently enabled feature in the cluster. CPU Partitioning means that this cluster can support partitioning workloads to specific CPU Sets. Valid values are \"None\" and \"AllNodes\". When omitted, the default value is \"None\". The default value of \"None\" indicates that no nodes will be setup with CPU partitioning. The \"AllNodes\" value indicates that all nodes have been setup with CPU partitioning, and can then be further configured via the PerformanceProfile API.", } func (InfrastructureStatus) SwaggerDoc() map[string]string { @@ -1237,6 +1249,15 @@ func (KubevirtPlatformStatus) SwaggerDoc() map[string]string { return map_KubevirtPlatformStatus } +var map_NutanixPlatformLoadBalancer = map[string]string{ + "": "NutanixPlatformLoadBalancer defines the load balancer used by the cluster on Nutanix platform.", + "type": "type defines the type of load balancer used by the cluster on Nutanix platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault.", +} + +func (NutanixPlatformLoadBalancer) SwaggerDoc() map[string]string { + return map_NutanixPlatformLoadBalancer +} + var map_NutanixPlatformSpec = map[string]string{ "": "NutanixPlatformSpec holds the desired state of the Nutanix infrastructure provider. This only includes fields that can be modified in the cluster.", "prismCentral": "prismCentral holds the endpoint address and port to access the Nutanix Prism Central. When a cluster-wide proxy is installed, by default, this endpoint will be accessed via the proxy. Should you wish for communication with this endpoint not to be proxied, please add the endpoint to the proxy spec.noProxy list.", @@ -1253,6 +1274,7 @@ var map_NutanixPlatformStatus = map[string]string{ "apiServerInternalIPs": "apiServerInternalIPs are the IP addresses to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. These are the IPs for a self-hosted load balancer in front of the API servers. In dual stack clusters this list contains two IPs otherwise only one.", "ingressIP": "ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names.\n\nDeprecated: Use IngressIPs instead.", "ingressIPs": "ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one.", + "loadBalancer": "loadBalancer defines how the load balancer used by the cluster is configured.", } func (NutanixPlatformStatus) SwaggerDoc() map[string]string { @@ -1279,6 +1301,15 @@ func (NutanixPrismEndpoint) SwaggerDoc() map[string]string { return map_NutanixPrismEndpoint } +var map_OpenStackPlatformLoadBalancer = map[string]string{ + "": "OpenStackPlatformLoadBalancer defines the load balancer used by the cluster on OpenStack platform.", + "type": "type defines the type of load balancer used by the cluster on OpenStack platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault.", +} + +func (OpenStackPlatformLoadBalancer) SwaggerDoc() map[string]string { + return map_OpenStackPlatformLoadBalancer +} + var map_OpenStackPlatformSpec = map[string]string{ "": "OpenStackPlatformSpec holds the desired state of the OpenStack infrastructure provider. This only includes fields that can be modified in the cluster.", } @@ -1295,12 +1326,22 @@ var map_OpenStackPlatformStatus = map[string]string{ "ingressIP": "ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names.\n\nDeprecated: Use IngressIPs instead.", "ingressIPs": "ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one.", "nodeDNSIP": "nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for OpenStack deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster.", + "loadBalancer": "loadBalancer defines how the load balancer used by the cluster is configured.", } func (OpenStackPlatformStatus) SwaggerDoc() map[string]string { return map_OpenStackPlatformStatus } +var map_OvirtPlatformLoadBalancer = map[string]string{ + "": "OvirtPlatformLoadBalancer defines the load balancer used by the cluster on Ovirt platform.", + "type": "type defines the type of load balancer used by the cluster on Ovirt platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault.", +} + +func (OvirtPlatformLoadBalancer) SwaggerDoc() map[string]string { + return map_OvirtPlatformLoadBalancer +} + var map_OvirtPlatformSpec = map[string]string{ "": "OvirtPlatformSpec holds the desired state of the oVirt infrastructure provider. This only includes fields that can be modified in the cluster.", } @@ -1316,6 +1357,7 @@ var map_OvirtPlatformStatus = map[string]string{ "ingressIP": "ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names.\n\nDeprecated: Use IngressIPs instead.", "ingressIPs": "ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one.", "nodeDNSIP": "deprecated: as of 4.6, this field is no longer set or honored. It will be removed in a future release.", + "loadBalancer": "loadBalancer defines how the load balancer used by the cluster is configured.", } func (OvirtPlatformStatus) SwaggerDoc() map[string]string { @@ -1381,6 +1423,7 @@ var map_PowerVSPlatformStatus = map[string]string{ "": "PowerVSPlatformStatus holds the current status of the IBM Power Systems Virtual Servers infrastrucutre provider.", "region": "region holds the default Power VS region for new Power VS resources created by the cluster.", "zone": "zone holds the default zone for the new Power VS resources created by the cluster. Note: Currently only single-zone OCP clusters are supported", + "resourceGroup": "resourceGroup is the resource group name for new IBMCloud resources created for a cluster. The resource group specified here will be used by cluster-image-registry-operator to set up a COS Instance in IBMCloud for the cluster registry. More about resource groups can be found here: https://cloud.ibm.com/docs/account?topic=account-rgs. When omitted, the image registry operator won't be able to configure storage, which results in the image registry cluster operator not being in an available state.", "serviceEndpoints": "serviceEndpoints is a list of custom endpoints which will override the default service endpoints of a Power VS service.", "cisInstanceCRN": "CISInstanceCRN is the CRN of the Cloud Internet Services instance managing the DNS zone for the cluster's base domain", "dnsInstanceCRN": "DNSInstanceCRN is the CRN of the DNS Services instance managing the DNS zone for the cluster's base domain", @@ -1413,6 +1456,15 @@ func (VSpherePlatformFailureDomainSpec) SwaggerDoc() map[string]string { return map_VSpherePlatformFailureDomainSpec } +var map_VSpherePlatformLoadBalancer = map[string]string{ + "": "VSpherePlatformLoadBalancer defines the load balancer used by the cluster on VSphere platform.", + "type": "type defines the type of load balancer used by the cluster on VSphere platform which can be a user-managed or openshift-managed load balancer that is to be used for the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault the static pods in charge of API and Ingress traffic load-balancing defined in the machine config operator will be deployed. When set to UserManaged these static pods will not be deployed and it is expected that the load balancer is configured out of band by the deployer. When omitted, this means no opinion and the platform is left to choose a reasonable default. The default value is OpenShiftManagedDefault.", +} + +func (VSpherePlatformLoadBalancer) SwaggerDoc() map[string]string { + return map_VSpherePlatformLoadBalancer +} + var map_VSpherePlatformNodeNetworking = map[string]string{ "": "VSpherePlatformNodeNetworking holds the external and internal node networking spec.", "external": "external represents the network configuration of the node that is externally routable.", @@ -1452,6 +1504,7 @@ var map_VSpherePlatformStatus = map[string]string{ "ingressIP": "ingressIP is an external IP which routes to the default ingress controller. The IP is a suitable target of a wildcard DNS record used to resolve default route host names.\n\nDeprecated: Use IngressIPs instead.", "ingressIPs": "ingressIPs are the external IPs which route to the default ingress controller. The IPs are suitable targets of a wildcard DNS record used to resolve default route host names. In dual stack clusters this list contains two IPs otherwise only one.", "nodeDNSIP": "nodeDNSIP is the IP address for the internal DNS used by the nodes. Unlike the one managed by the DNS operator, `NodeDNSIP` provides name resolution for the nodes themselves. There is no DNS-as-a-service for vSphere deployments. In order to minimize necessary changes to the datacenter DNS, a DNS service is hosted as a static pod to serve those hostnames to the nodes in the cluster.", + "loadBalancer": "loadBalancer defines how the load balancer used by the cluster is configured.", } func (VSpherePlatformStatus) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/machine/v1/types_nutanixprovider.go b/vendor/github.com/openshift/api/machine/v1/types_nutanixprovider.go index 6eae01a21a..1bcb28d203 100644 --- a/vendor/github.com/openshift/api/machine/v1/types_nutanixprovider.go +++ b/vendor/github.com/openshift/api/machine/v1/types_nutanixprovider.go @@ -56,6 +56,25 @@ type NutanixMachineProviderConfig struct { // +kubebuilder:validation:Required SystemDiskSize resource.Quantity `json:"systemDiskSize"` + // bootType indicates the boot type (Legacy, UEFI or SecureBoot) the Machine's VM uses to boot. + // If this field is empty or omitted, the VM will use the default boot type "Legacy" to boot. + // "SecureBoot" depends on "UEFI" boot, i.e., enabling "SecureBoot" means that "UEFI" boot is also enabled. + // +kubebuilder:validation:Enum="";Legacy;UEFI;SecureBoot + // +optional + BootType NutanixBootType `json:"bootType"` + + // project optionally identifies a Prism project for the Machine's VM to associate with. + // +optional + Project NutanixResourceIdentifier `json:"project"` + + // categories optionally adds one or more prism categories (each with key and value) for + // the Machine's VM to associate with. All the category key and value pairs specified must + // already exist in the prism central. + // +listType=map + // +listMapKey=key + // +optional + Categories []NutanixCategory `json:"categories"` + // userDataSecret is a local reference to a secret that contains the // UserData to apply to the VM UserDataSecret *corev1.LocalObjectReference `json:"userDataSecret,omitempty"` @@ -66,6 +85,35 @@ type NutanixMachineProviderConfig struct { CredentialsSecret *corev1.LocalObjectReference `json:"credentialsSecret"` } +// NutanixCategory identifies a pair of prism category key and value +type NutanixCategory struct { + // key is the prism category key name + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=64 + // +kubebuilder:validation:Required + Key string `json:"key"` + + // value is the prism category value associated with the key + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=64 + // +kubebuilder:validation:Required + Value string `json:"value"` +} + +// NutanixBootType is an enumeration of different boot types for Nutanix VM. +type NutanixBootType string + +const ( + // NutanixLegacyBoot is the legacy BIOS boot type + NutanixLegacyBoot NutanixBootType = "Legacy" + + // NutanixUEFIBoot is the UEFI boot type + NutanixUEFIBoot NutanixBootType = "UEFI" + + // NutanixSecureBoot is the Secure boot type + NutanixSecureBoot NutanixBootType = "SecureBoot" +) + // NutanixIdentifierType is an enumeration of different resource identifier types. type NutanixIdentifierType string diff --git a/vendor/github.com/openshift/api/machine/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/machine/v1/zz_generated.deepcopy.go index 9cb1a1219b..d63873943d 100644 --- a/vendor/github.com/openshift/api/machine/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/machine/v1/zz_generated.deepcopy.go @@ -559,6 +559,22 @@ func (in *GCPFailureDomain) DeepCopy() *GCPFailureDomain { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NutanixCategory) DeepCopyInto(out *NutanixCategory) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixCategory. +func (in *NutanixCategory) DeepCopy() *NutanixCategory { + if in == nil { + return nil + } + out := new(NutanixCategory) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NutanixMachineProviderConfig) DeepCopyInto(out *NutanixMachineProviderConfig) { *out = *in @@ -575,6 +591,12 @@ func (in *NutanixMachineProviderConfig) DeepCopyInto(out *NutanixMachineProvider } out.MemorySize = in.MemorySize.DeepCopy() out.SystemDiskSize = in.SystemDiskSize.DeepCopy() + in.Project.DeepCopyInto(&out.Project) + if in.Categories != nil { + in, out := &in.Categories, &out.Categories + *out = make([]NutanixCategory, len(*in)) + copy(*out, *in) + } if in.UserDataSecret != nil { in, out := &in.UserDataSecret, &out.UserDataSecret *out = new(corev1.LocalObjectReference) diff --git a/vendor/github.com/openshift/api/machine/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/machine/v1/zz_generated.swagger_doc_generated.go index 8bd2674bf7..226c28d5c8 100644 --- a/vendor/github.com/openshift/api/machine/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/machine/v1/zz_generated.swagger_doc_generated.go @@ -268,6 +268,16 @@ func (OpenShiftMachineV1Beta1MachineTemplate) SwaggerDoc() map[string]string { return map_OpenShiftMachineV1Beta1MachineTemplate } +var map_NutanixCategory = map[string]string{ + "": "NutanixCategory identifies a pair of prism category key and value", + "key": "key is the prism category key name", + "value": "value is the prism category value associated with the key", +} + +func (NutanixCategory) SwaggerDoc() map[string]string { + return map_NutanixCategory +} + var map_NutanixMachineProviderConfig = map[string]string{ "": "NutanixMachineProviderConfig is the Schema for the nutanixmachineproviderconfigs API Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", "cluster": "cluster is to identify the cluster (the Prism Element under management of the Prism Central), in which the Machine's VM will be created. The cluster identifier (uuid or name) can be obtained from the Prism Central console or using the prism_central API.", @@ -277,6 +287,9 @@ var map_NutanixMachineProviderConfig = map[string]string{ "vcpuSockets": "vcpuSockets is the number of vCPU sockets of the VM", "memorySize": "memorySize is the memory size (in Quantity format) of the VM The minimum memorySize is 2Gi bytes", "systemDiskSize": "systemDiskSize is size (in Quantity format) of the system disk of the VM The minimum systemDiskSize is 20Gi bytes", + "bootType": "bootType indicates the boot type (Legacy, UEFI or SecureBoot) the Machine's VM uses to boot. If this field is empty or omitted, the VM will use the default boot type \"Legacy\" to boot. \"SecureBoot\" depends on \"UEFI\" boot, i.e., enabling \"SecureBoot\" means that \"UEFI\" boot is also enabled.", + "project": "project optionally identifies a Prism project for the Machine's VM to associate with.", + "categories": "categories optionally adds one or more prism categories (each with key and value) for the Machine's VM to associate with. All the category key and value pairs specified must already exist in the prism central.", "userDataSecret": "userDataSecret is a local reference to a secret that contains the UserData to apply to the VM", "credentialsSecret": "credentialsSecret is a local reference to a secret that contains the credentials data to access Nutanix PC client", } diff --git a/vendor/github.com/openshift/api/machine/v1beta1/types_gcpprovider.go b/vendor/github.com/openshift/api/machine/v1beta1/types_gcpprovider.go index 90366857c6..7461eec9f0 100644 --- a/vendor/github.com/openshift/api/machine/v1beta1/types_gcpprovider.go +++ b/vendor/github.com/openshift/api/machine/v1beta1/types_gcpprovider.go @@ -55,6 +55,16 @@ const ( IntegrityMonitoringPolicyDisabled IntegrityMonitoringPolicy = "Disabled" ) +// ConfidentialComputePolicy represents the confidential compute configuration for the GCP machine. +type ConfidentialComputePolicy string + +const ( + // ConfidentialComputePolicyEnabled enables confidential compute for the GCP machine. + ConfidentialComputePolicyEnabled ConfidentialComputePolicy = "Enabled" + // ConfidentialComputePolicyDisabled disables confidential compute for the GCP machine. + ConfidentialComputePolicyDisabled ConfidentialComputePolicy = "Disabled" +) + // GCPMachineProviderSpec is the type that will be embedded in a Machine.Spec.ProviderSpec field // for an GCP virtual machine. It is used by the GCP machine actuator to create a single Machine. // Compatibility level 2: Stable within a major release for a minimum of 9 months or 3 minor releases (whichever is longer). @@ -129,6 +139,13 @@ type GCPMachineProviderSpec struct { // ShieldedInstanceConfig is the Shielded VM configuration for the VM // +optional ShieldedInstanceConfig GCPShieldedInstanceConfig `json:"shieldedInstanceConfig,omitempty"` + + // confidentialCompute Defines whether the instance should have confidential compute enabled. + // If enabled OnHostMaintenance is required to be set to "Terminate". + // If omitted, the platform chooses a default, which is subject to change over time, currently that default is false. + // +kubebuilder:validation:Enum=Enabled;Disabled + // +optional + ConfidentialCompute ConfidentialComputePolicy `json:"confidentialCompute,omitempty"` } // GCPDisk describes disks for GCP. diff --git a/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go index b89b321c40..db002492d4 100644 --- a/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go @@ -388,6 +388,7 @@ var map_GCPMachineProviderSpec = map[string]string{ "onHostMaintenance": "OnHostMaintenance determines the behavior when a maintenance event occurs that might cause the instance to reboot. This is required to be set to \"Terminate\" if you want to provision machine with attached GPUs. Otherwise, allowed values are \"Migrate\" and \"Terminate\". If omitted, the platform chooses a default, which is subject to change over time, currently that default is \"Migrate\".", "restartPolicy": "RestartPolicy determines the behavior when an instance crashes or the underlying infrastructure provider stops the instance as part of a maintenance event (default \"Always\"). Cannot be \"Always\" with preemptible instances. Otherwise, allowed values are \"Always\" and \"Never\". If omitted, the platform chooses a default, which is subject to change over time, currently that default is \"Always\". RestartPolicy represents AutomaticRestart in GCP compute api", "shieldedInstanceConfig": "ShieldedInstanceConfig is the Shielded VM configuration for the VM", + "confidentialCompute": "confidentialCompute Defines whether the instance should have confidential compute enabled. If enabled OnHostMaintenance is required to be set to \"Terminate\". If omitted, the platform chooses a default, which is subject to change over time, currently that default is false.", } func (GCPMachineProviderSpec) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/operator/v1/0000_50_cluster_storage_operator_01_crd.yaml b/vendor/github.com/openshift/api/operator/v1/0000_50_cluster_storage_operator_01_crd.yaml index 2bf1818626..484576c1aa 100644 --- a/vendor/github.com/openshift/api/operator/v1/0000_50_cluster_storage_operator_01_crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/0000_50_cluster_storage_operator_01_crd.yaml @@ -69,6 +69,19 @@ spec: type: object nullable: true x-kubernetes-preserve-unknown-fields: true + vsphereStorageDriver: + description: 'VSphereStorageDriver indicates the storage driver to use on VSphere clusters. Once this field is set to CSIWithMigrationDriver, it can not be changed. If this is empty, the platform will choose a good default, which may change over time without notice. DEPRECATED: This field will be removed in a future release.' + type: string + enum: + - "" + - LegacyDeprecatedInTreeDriver + - CSIWithMigrationDriver + x-kubernetes-validations: + - rule: self == oldSelf || oldSelf == "" || self == "CSIWithMigrationDriver" + message: VSphereStorageDriver can not be changed once it is set to CSIWithMigrationDriver + x-kubernetes-validations: + - rule: '!has(oldSelf.vsphereStorageDriver) || has(self.vsphereStorageDriver)' + message: VSphereStorageDriver is required once set status: description: status holds observed values from the cluster. They may not be overridden. type: object diff --git a/vendor/github.com/openshift/api/operator/v1/0000_50_ingress-operator_00-ingresscontroller.crd.yaml b/vendor/github.com/openshift/api/operator/v1/0000_50_ingress-operator_00-ingresscontroller.crd.yaml index b6ff95a92e..fb8dd8e5ec 100644 --- a/vendor/github.com/openshift/api/operator/v1/0000_50_ingress-operator_00-ingresscontroller.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/0000_50_ingress-operator_00-ingresscontroller.crd.yaml @@ -161,8 +161,19 @@ spec: - Local type: string type: object + ibm: + description: "ibm provides configuration settings that are specific to IBM Cloud load balancers. \n If empty, defaults will be applied. See specific ibm fields for details about their defaults." + properties: + protocol: + description: "protocol specifies whether the load balancer uses PROXY protocol to forward connections to the IngressController. See \"service.kubernetes.io/ibm-load-balancer-cloud-provider-enable-features: \"proxy-protocol\"\" at https://cloud.ibm.com/docs/containers?topic=containers-vpc-lbaas\" \n PROXY protocol can be used with load balancers that support it to communicate the source addresses of client connections when forwarding those connections to the IngressController. Using PROXY protocol enables the IngressController to report those source addresses instead of reporting the load balancer's address in HTTP headers and logs. Note that enabling PROXY protocol on the IngressController will cause connections to fail if you are not using a load balancer that uses PROXY protocol to forward connections to the IngressController. See http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt for information about PROXY protocol. \n Valid values for protocol are TCP, PROXY and omitted. When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time. The current default is TCP, without the proxy protocol enabled." + enum: + - "" + - TCP + - PROXY + type: string + type: object type: - description: type is the underlying infrastructure provider for the load balancer. Allowed values are "AWS", "Azure", "BareMetal", "GCP", "Nutanix", "OpenStack", and "VSphere". + description: type is the underlying infrastructure provider for the load balancer. Allowed values are "AWS", "Azure", "BareMetal", "GCP", "IBM", "Nutanix", "OpenStack", and "VSphere". enum: - AWS - Azure @@ -827,8 +838,19 @@ spec: - Local type: string type: object + ibm: + description: "ibm provides configuration settings that are specific to IBM Cloud load balancers. \n If empty, defaults will be applied. See specific ibm fields for details about their defaults." + properties: + protocol: + description: "protocol specifies whether the load balancer uses PROXY protocol to forward connections to the IngressController. See \"service.kubernetes.io/ibm-load-balancer-cloud-provider-enable-features: \"proxy-protocol\"\" at https://cloud.ibm.com/docs/containers?topic=containers-vpc-lbaas\" \n PROXY protocol can be used with load balancers that support it to communicate the source addresses of client connections when forwarding those connections to the IngressController. Using PROXY protocol enables the IngressController to report those source addresses instead of reporting the load balancer's address in HTTP headers and logs. Note that enabling PROXY protocol on the IngressController will cause connections to fail if you are not using a load balancer that uses PROXY protocol to forward connections to the IngressController. See http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt for information about PROXY protocol. \n Valid values for protocol are TCP, PROXY and omitted. When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time. The current default is TCP, without the proxy protocol enabled." + enum: + - "" + - TCP + - PROXY + type: string + type: object type: - description: type is the underlying infrastructure provider for the load balancer. Allowed values are "AWS", "Azure", "BareMetal", "GCP", "Nutanix", "OpenStack", and "VSphere". + description: type is the underlying infrastructure provider for the load balancer. Allowed values are "AWS", "Azure", "BareMetal", "GCP", "IBM", "Nutanix", "OpenStack", and "VSphere". enum: - AWS - Azure diff --git a/vendor/github.com/openshift/api/operator/v1/0000_70_cluster-network-operator_01.crd.yaml b/vendor/github.com/openshift/api/operator/v1/0000_70_cluster-network-operator_01.crd.yaml index 8d6d837132..6e76545a74 100644 --- a/vendor/github.com/openshift/api/operator/v1/0000_70_cluster-network-operator_01.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/0000_70_cluster-network-operator_01.crd.yaml @@ -156,7 +156,7 @@ spec: description: enablePortPoolsPrepopulation when true will make Kuryr prepopulate each newly created port pool with a minimum number of ports. Kuryr uses Neutron port pooling to fight the fact that it takes a significant amount of time to create one. It creates a number of ports when the first pod that is configured to use the dedicated network for pods is created in a namespace, and keeps them ready to be attached to pods. Port prepopulation is disabled by default. type: boolean mtu: - description: mtu is the MTU that Kuryr should use when creating pod networks in Neutron. The value has to be lower or equal to the MTU of the nodes network and Neutron has to allow creation of tenant networks with such MTU. If unset Pod networks will be created with the same MTU as the nodes network has. + description: mtu is the MTU that Kuryr should use when creating pod networks in Neutron. The value has to be lower or equal to the MTU of the nodes network and Neutron has to allow creation of tenant networks with such MTU. If unset Pod networks will be created with the same MTU as the nodes network has. This also affects the services network created by cluster-network-operator. type: integer format: int32 minimum: 0 diff --git a/vendor/github.com/openshift/api/operator/v1/0000_90_cluster_csi_driver_01_config.crd.yaml b/vendor/github.com/openshift/api/operator/v1/0000_90_cluster_csi_driver_01_config.crd.yaml index 5c7496bca3..54776a1b75 100644 --- a/vendor/github.com/openshift/api/operator/v1/0000_90_cluster_csi_driver_01_config.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/0000_90_cluster_csi_driver_01_config.crd.yaml @@ -53,12 +53,84 @@ spec: driverConfig: description: driverConfig can be used to specify platform specific driver configuration. When omitted, this means no opinion and the platform is left to choose reasonable defaults. These defaults are subject to change over time. properties: + aws: + description: aws is used to configure the AWS CSI driver. + properties: + kmsKeyARN: + description: kmsKeyARN sets the cluster default storage class to encrypt volumes with a user-defined KMS key, rather than the default KMS key used by AWS. The value may be either the ARN or Alias ARN of a KMS key. + pattern: ^arn:(aws|aws-cn|aws-us-gov):kms:[a-z0-9-]+:[0-9]{12}:(key|alias)\/.*$ + type: string + type: object + azure: + description: azure is used to configure the Azure CSI driver. + properties: + diskEncryptionSet: + description: diskEncryptionSet sets the cluster default storage class to encrypt volumes with a customer-managed encryption set, rather than the default platform-managed keys. + properties: + name: + description: name is the name of the disk encryption set that will be set on the default storage class. The value should consist of only alphanumberic characters, underscores (_), hyphens, and be at most 80 characters in length. + maxLength: 80 + pattern: ^[a-zA-Z0-9\_-]+$ + type: string + resourceGroup: + description: resourceGroup defines the Azure resource group that contains the disk encryption set. The value should consist of only alphanumberic characters, underscores (_), parentheses, hyphens and periods. The value should not end in a period and be at most 90 characters in length. + maxLength: 90 + pattern: ^[\w\.\-\(\)]*[\w\-\(\)]$ + type: string + subscriptionID: + description: 'subscriptionID defines the Azure subscription that contains the disk encryption set. The value should meet the following conditions: 1. It should be a 128-bit number. 2. It should be 36 characters (32 hexadecimal characters and 4 hyphens) long. 3. It should be displayed in five groups separated by hyphens (-). 4. The first group should be 8 characters long. 5. The second, third, and fourth groups should be 4 characters long. 6. The fifth group should be 12 characters long. An Example SubscrionID: f2007bbf-f802-4a47-9336-cf7c6b89b378' + maxLength: 36 + pattern: ^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$ + type: string + required: + - name + - resourceGroup + - subscriptionID + type: object + type: object driverType: - description: "driverType indicates type of CSI driver for which the driverConfig is being applied to. \n Valid values are: \n * vSphere \n Allows configuration of vsphere CSI driver topology. \n --- Consumers should treat unknown values as a NO-OP." + description: 'driverType indicates type of CSI driver for which the driverConfig is being applied to. Valid values are: AWS, Azure, GCP, vSphere and omitted. Consumers should treat unknown values as a NO-OP.' enum: - "" + - AWS + - Azure + - GCP - vSphere type: string + gcp: + description: gcp is used to configure the GCP CSI driver. + properties: + kmsKey: + description: kmsKey sets the cluster default storage class to encrypt volumes with customer-supplied encryption keys, rather than the default keys managed by GCP. + properties: + keyRing: + description: keyRing is the name of the KMS Key Ring which the KMS Key belongs to. The value should correspond to an existing KMS key ring and should consist of only alphanumeric characters, hyphens (-) and underscores (_), and be at most 63 characters in length. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z0-9\_-]+$ + type: string + location: + description: location is the GCP location in which the Key Ring exists. The value must match an existing GCP location, or "global". Defaults to global, if not set. + pattern: ^[a-zA-Z0-9\_-]+$ + type: string + name: + description: name is the name of the customer-managed encryption key to be used for disk encryption. The value should correspond to an existing KMS key and should consist of only alphanumeric characters, hyphens (-) and underscores (_), and be at most 63 characters in length. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z0-9\_-]+$ + type: string + projectID: + description: projectID is the ID of the Project in which the KMS Key Ring exists. It must be 6 to 30 lowercase letters, digits, or hyphens. It must start with a letter. Trailing hyphens are prohibited. + maxLength: 30 + minLength: 6 + pattern: ^[a-z][a-z0-9-]+[a-z0-9]$ + type: string + required: + - keyRing + - name + - projectID + type: object + type: object vSphere: description: vsphere is used to configure the vsphere CSI driver. properties: diff --git a/vendor/github.com/openshift/api/operator/v1/stable.storage.testsuite.yaml b/vendor/github.com/openshift/api/operator/v1/stable.storage.testsuite.yaml index 42903f22de..63a7ca4543 100644 --- a/vendor/github.com/openshift/api/operator/v1/stable.storage.testsuite.yaml +++ b/vendor/github.com/openshift/api/operator/v1/stable.storage.testsuite.yaml @@ -14,3 +14,91 @@ tests: spec: logLevel: Normal operatorLogLevel: Normal + onUpdate: + - name: Should allow enabling CSI migration for vSphere + initial: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: {} # No spec is required + updated: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: CSIWithMigrationDriver + expected: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: CSIWithMigrationDriver + logLevel: Normal + operatorLogLevel: Normal + - name: Should allow disabling CSI migration for vSphere + initial: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: {} # No spec is required + updated: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: LegacyDeprecatedInTreeDriver + expected: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: LegacyDeprecatedInTreeDriver + logLevel: Normal + operatorLogLevel: Normal + - name: Should allow changing LegacyDeprecatedInTreeDriver to CSIWithMigrationDriver + initial: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: LegacyDeprecatedInTreeDriver + updated: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: CSIWithMigrationDriver + expected: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: CSIWithMigrationDriver + logLevel: Normal + operatorLogLevel: Normal + - name: Should not allow changing CSIWithMigrationDriver to LegacyDeprecatedInTreeDriver + initial: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: CSIWithMigrationDriver + updated: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: LegacyDeprecatedInTreeDriver + expectedError: "VSphereStorageDriver can not be changed once it is set to CSIWithMigrationDriver" + - name: Should not allow changing CSIWithMigrationDriver to empty string + initial: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: CSIWithMigrationDriver + updated: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: "" + expectedError: "VSphereStorageDriver can not be changed once it is set to CSIWithMigrationDriver" + - name: Should not allow unsetting VSphereStorageDriver once it is set + initial: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: + vsphereStorageDriver: CSIWithMigrationDriver + updated: | + apiVersion: operator.openshift.io/v1 + kind: Storage + spec: {} + expectedError: "VSphereStorageDriver is required once set" diff --git a/vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go b/vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go index b295340152..d6d91c95ad 100644 --- a/vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go +++ b/vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go @@ -105,10 +105,13 @@ type ClusterCSIDriverSpec struct { } // CSIDriverType indicates type of CSI driver being configured. -// +kubebuilder:validation:Enum="";vSphere +// +kubebuilder:validation:Enum="";AWS;Azure;GCP;vSphere type CSIDriverType string const ( + AWSDriverType CSIDriverType = "AWS" + AzureDriverType CSIDriverType = "Azure" + GCPDriverType CSIDriverType = "GCP" VSphereDriverType CSIDriverType = "vSphere" ) @@ -118,25 +121,129 @@ const ( type CSIDriverConfigSpec struct { // driverType indicates type of CSI driver for which the // driverConfig is being applied to. - // - // Valid values are: - // - // * vSphere - // - // Allows configuration of vsphere CSI driver topology. - // - // --- + // Valid values are: AWS, Azure, GCP, vSphere and omitted. // Consumers should treat unknown values as a NO-OP. - // // +kubebuilder:validation:Required // +unionDiscriminator DriverType CSIDriverType `json:"driverType"` + // aws is used to configure the AWS CSI driver. + // +optional + AWS *AWSCSIDriverConfigSpec `json:"aws,omitempty"` + + // azure is used to configure the Azure CSI driver. + // +optional + Azure *AzureCSIDriverConfigSpec `json:"azure,omitempty"` + + // gcp is used to configure the GCP CSI driver. + // +optional + GCP *GCPCSIDriverConfigSpec `json:"gcp,omitempty"` + // vsphere is used to configure the vsphere CSI driver. // +optional VSphere *VSphereCSIDriverConfigSpec `json:"vSphere,omitempty"` } +// AWSCSIDriverConfigSpec defines properties that can be configured for the AWS CSI driver. +type AWSCSIDriverConfigSpec struct { + // kmsKeyARN sets the cluster default storage class to encrypt volumes with a user-defined KMS key, + // rather than the default KMS key used by AWS. + // The value may be either the ARN or Alias ARN of a KMS key. + // +kubebuilder:validation:Pattern:=`^arn:(aws|aws-cn|aws-us-gov):kms:[a-z0-9-]+:[0-9]{12}:(key|alias)\/.*$` + // +optional + KMSKeyARN string `json:"kmsKeyARN,omitempty"` +} + +// AzureDiskEncryptionSet defines the configuration for a disk encryption set. +type AzureDiskEncryptionSet struct { + // subscriptionID defines the Azure subscription that contains the disk encryption set. + // The value should meet the following conditions: + // 1. It should be a 128-bit number. + // 2. It should be 36 characters (32 hexadecimal characters and 4 hyphens) long. + // 3. It should be displayed in five groups separated by hyphens (-). + // 4. The first group should be 8 characters long. + // 5. The second, third, and fourth groups should be 4 characters long. + // 6. The fifth group should be 12 characters long. + // An Example SubscrionID: f2007bbf-f802-4a47-9336-cf7c6b89b378 + // +kubebuilder:validation:Required + // +kubebuilder:validation:MaxLength:=36 + // +kubebuilder:validation:Pattern:=`^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$` + SubscriptionID string `json:"subscriptionID"` + + // resourceGroup defines the Azure resource group that contains the disk encryption set. + // The value should consist of only alphanumberic characters, + // underscores (_), parentheses, hyphens and periods. + // The value should not end in a period and be at most 90 characters in + // length. + // +kubebuilder:validation:Required + // +kubebuilder:validation:MaxLength:=90 + // +kubebuilder:validation:Pattern:=`^[\w\.\-\(\)]*[\w\-\(\)]$` + ResourceGroup string `json:"resourceGroup"` + + // name is the name of the disk encryption set that will be set on the default storage class. + // The value should consist of only alphanumberic characters, + // underscores (_), hyphens, and be at most 80 characters in length. + // +kubebuilder:validation:Required + // +kubebuilder:validation:MaxLength:=80 + // +kubebuilder:validation:Pattern:=`^[a-zA-Z0-9\_-]+$` + Name string `json:"name"` +} + +// AzureCSIDriverConfigSpec defines properties that can be configured for the Azure CSI driver. +type AzureCSIDriverConfigSpec struct { + // diskEncryptionSet sets the cluster default storage class to encrypt volumes with a + // customer-managed encryption set, rather than the default platform-managed keys. + // +optional + DiskEncryptionSet *AzureDiskEncryptionSet `json:"diskEncryptionSet,omitempty"` +} + +// GCPKMSKeyReference gathers required fields for looking up a GCP KMS Key +type GCPKMSKeyReference struct { + // name is the name of the customer-managed encryption key to be used for disk encryption. + // The value should correspond to an existing KMS key and should + // consist of only alphanumeric characters, hyphens (-) and underscores (_), + // and be at most 63 characters in length. + // +kubebuilder:validation:Pattern:=`^[a-zA-Z0-9\_-]+$` + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=63 + // +kubebuilder:validation:Required + Name string `json:"name"` + + // keyRing is the name of the KMS Key Ring which the KMS Key belongs to. + // The value should correspond to an existing KMS key ring and should + // consist of only alphanumeric characters, hyphens (-) and underscores (_), + // and be at most 63 characters in length. + // +kubebuilder:validation:Pattern:=`^[a-zA-Z0-9\_-]+$` + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=63 + // +kubebuilder:validation:Required + KeyRing string `json:"keyRing"` + + // projectID is the ID of the Project in which the KMS Key Ring exists. + // It must be 6 to 30 lowercase letters, digits, or hyphens. + // It must start with a letter. Trailing hyphens are prohibited. + // +kubebuilder:validation:Pattern:=`^[a-z][a-z0-9-]+[a-z0-9]$` + // +kubebuilder:validation:MinLength:=6 + // +kubebuilder:validation:MaxLength:=30 + // +kubebuilder:validation:Required + ProjectID string `json:"projectID"` + + // location is the GCP location in which the Key Ring exists. + // The value must match an existing GCP location, or "global". + // Defaults to global, if not set. + // +kubebuilder:validation:Pattern:=`^[a-zA-Z0-9\_-]+$` + // +optional + Location string `json:"location,omitempty"` +} + +// GCPCSIDriverConfigSpec defines properties that can be configured for the GCP CSI driver. +type GCPCSIDriverConfigSpec struct { + // kmsKey sets the cluster default storage class to encrypt volumes with customer-supplied + // encryption keys, rather than the default keys managed by GCP. + // +optional + KMSKey *GCPKMSKeyReference `json:"kmsKey,omitempty"` +} + // VSphereCSIDriverConfigSpec defines properties that // can be configured for vsphere CSI driver. type VSphereCSIDriverConfigSpec struct { diff --git a/vendor/github.com/openshift/api/operator/v1/types_ingress.go b/vendor/github.com/openshift/api/operator/v1/types_ingress.go index 0a0b3ca74d..f69f8a8c32 100644 --- a/vendor/github.com/openshift/api/operator/v1/types_ingress.go +++ b/vendor/github.com/openshift/api/operator/v1/types_ingress.go @@ -280,18 +280,18 @@ type HTTPCompressionPolicy struct { // // The format should follow the Content-Type definition in RFC 1341: // Content-Type := type "/" subtype *[";" parameter] -// - The type in Content-Type can be one of: -// application, audio, image, message, multipart, text, video, or a custom -// type preceded by "X-" and followed by a token as defined below. -// - The token is a string of at least one character, and not containing white -// space, control characters, or any of the characters in the tspecials set. -// - The tspecials set contains the characters ()<>@,;:\"/[]?.= -// - The subtype in Content-Type is also a token. -// - The optional parameter/s following the subtype are defined as: -// token "=" (token / quoted-string) -// - The quoted-string, as defined in RFC 822, is surrounded by double quotes -// and can contain white space plus any character EXCEPT \, ", and CR. -// It can also contain any single ASCII character as long as it is escaped by \. +// - The type in Content-Type can be one of: +// application, audio, image, message, multipart, text, video, or a custom +// type preceded by "X-" and followed by a token as defined below. +// - The token is a string of at least one character, and not containing white +// space, control characters, or any of the characters in the tspecials set. +// - The tspecials set contains the characters ()<>@,;:\"/[]?.= +// - The subtype in Content-Type is also a token. +// - The optional parameter/s following the subtype are defined as: +// token "=" (token / quoted-string) +// - The quoted-string, as defined in RFC 822, is surrounded by double quotes +// and can contain white space plus any character EXCEPT \, ", and CR. +// It can also contain any single ASCII character as long as it is escaped by \. // // +kubebuilder:validation:Pattern=`^(?i)(x-[^][ ()\\<>@,;:"/?.=\x00-\x1F\x7F]+|application|audio|image|message|multipart|text|video)/[^][ ()\\<>@,;:"/?.=\x00-\x1F\x7F]+(; *[^][ ()\\<>@,;:"/?.=\x00-\x1F\x7F]+=([^][ ()\\<>@,;:"/?.=\x00-\x1F\x7F]+|"(\\[\x00-\x7F]|[^\x0D"\\])*"))*$` type CompressionMIMEType string @@ -448,7 +448,7 @@ const ( // +union type ProviderLoadBalancerParameters struct { // type is the underlying infrastructure provider for the load balancer. - // Allowed values are "AWS", "Azure", "BareMetal", "GCP", "Nutanix", + // Allowed values are "AWS", "Azure", "BareMetal", "GCP", "IBM", "Nutanix", // "OpenStack", and "VSphere". // // +unionDiscriminator @@ -473,10 +473,19 @@ type ProviderLoadBalancerParameters struct { // // +optional GCP *GCPLoadBalancerParameters `json:"gcp,omitempty"` + + // ibm provides configuration settings that are specific to IBM Cloud + // load balancers. + // + // If empty, defaults will be applied. See specific ibm fields for + // details about their defaults. + // + // +optional + IBM *IBMLoadBalancerParameters `json:"ibm,omitempty"` } // LoadBalancerProviderType is the underlying infrastructure provider for the -// load balancer. Allowed values are "AWS", "Azure", "BareMetal", "GCP", "Nutanix", +// load balancer. Allowed values are "AWS", "Azure", "BareMetal", "GCP", "IBM", "Nutanix", // "OpenStack", and "VSphere". // // +kubebuilder:validation:Enum=AWS;Azure;BareMetal;GCP;Nutanix;OpenStack;VSphere;IBM @@ -573,6 +582,33 @@ const ( GCPLocalAccess GCPClientAccess = "Local" ) +// IBMLoadBalancerParameters provides configuration settings that are +// specific to IBM Cloud load balancers. +type IBMLoadBalancerParameters struct { + // protocol specifies whether the load balancer uses PROXY protocol to forward connections to + // the IngressController. See "service.kubernetes.io/ibm-load-balancer-cloud-provider-enable-features: + // "proxy-protocol"" at https://cloud.ibm.com/docs/containers?topic=containers-vpc-lbaas" + // + // PROXY protocol can be used with load balancers that support it to + // communicate the source addresses of client connections when + // forwarding those connections to the IngressController. Using PROXY + // protocol enables the IngressController to report those source + // addresses instead of reporting the load balancer's address in HTTP + // headers and logs. Note that enabling PROXY protocol on the + // IngressController will cause connections to fail if you are not using + // a load balancer that uses PROXY protocol to forward connections to + // the IngressController. See + // http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt for + // information about PROXY protocol. + // + // Valid values for protocol are TCP, PROXY and omitted. + // When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time. + // The current default is TCP, without the proxy protocol enabled. + // + // +optional + Protocol IngressControllerProtocol `json:"protocol,omitempty"` +} + // AWSClassicLoadBalancerParameters holds configuration parameters for an // AWS Classic load balancer. type AWSClassicLoadBalancerParameters struct { diff --git a/vendor/github.com/openshift/api/operator/v1/types_network.go b/vendor/github.com/openshift/api/operator/v1/types_network.go index 29d795318e..d01758115a 100644 --- a/vendor/github.com/openshift/api/operator/v1/types_network.go +++ b/vendor/github.com/openshift/api/operator/v1/types_network.go @@ -404,7 +404,8 @@ type KuryrConfig struct { // mtu is the MTU that Kuryr should use when creating pod networks in Neutron. // The value has to be lower or equal to the MTU of the nodes network and Neutron has // to allow creation of tenant networks with such MTU. If unset Pod networks will be - // created with the same MTU as the nodes network has. + // created with the same MTU as the nodes network has. This also affects the services + // network created by cluster-network-operator. // +kubebuilder:validation:Minimum=0 // +optional MTU *uint32 `json:"mtu,omitempty"` diff --git a/vendor/github.com/openshift/api/operator/v1/types_storage.go b/vendor/github.com/openshift/api/operator/v1/types_storage.go index 38ffe26d52..044c9c32ae 100644 --- a/vendor/github.com/openshift/api/operator/v1/types_storage.go +++ b/vendor/github.com/openshift/api/operator/v1/types_storage.go @@ -26,9 +26,28 @@ type Storage struct { Status StorageStatus `json:"status"` } +// StorageDriverType indicates whether CSI migration should be enabled for drivers where it is optional. +// +kubebuilder:validation:Enum="";LegacyDeprecatedInTreeDriver;CSIWithMigrationDriver +type StorageDriverType string + +const ( + LegacyDeprecatedInTreeDriver StorageDriverType = "LegacyDeprecatedInTreeDriver" + CSIWithMigrationDriver StorageDriverType = "CSIWithMigrationDriver" +) + // StorageSpec is the specification of the desired behavior of the cluster storage operator. +// +kubebuilder:validation:XValidation:rule="!has(oldSelf.vsphereStorageDriver) || has(self.vsphereStorageDriver)", message="VSphereStorageDriver is required once set" type StorageSpec struct { OperatorSpec `json:",inline"` + + // VSphereStorageDriver indicates the storage driver to use on VSphere clusters. + // Once this field is set to CSIWithMigrationDriver, it can not be changed. + // If this is empty, the platform will choose a good default, + // which may change over time without notice. + // DEPRECATED: This field will be removed in a future release. + // +kubebuilder:validation:XValidation:rule="self == oldSelf || oldSelf == \"\" || self == \"CSIWithMigrationDriver\"",message="VSphereStorageDriver can not be changed once it is set to CSIWithMigrationDriver" + // +optional + VSphereStorageDriver StorageDriverType `json:"vsphereStorageDriver"` } // StorageStatus defines the observed status of the cluster storage operator. diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go index 5304a39011..609219c065 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go @@ -13,6 +13,22 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSCSIDriverConfigSpec) DeepCopyInto(out *AWSCSIDriverConfigSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSCSIDriverConfigSpec. +func (in *AWSCSIDriverConfigSpec) DeepCopy() *AWSCSIDriverConfigSpec { + if in == nil { + return nil + } + out := new(AWSCSIDriverConfigSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AWSClassicLoadBalancerParameters) DeepCopyInto(out *AWSClassicLoadBalancerParameters) { *out = *in @@ -233,9 +249,61 @@ func (in *AuthenticationStatus) DeepCopy() *AuthenticationStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureCSIDriverConfigSpec) DeepCopyInto(out *AzureCSIDriverConfigSpec) { + *out = *in + if in.DiskEncryptionSet != nil { + in, out := &in.DiskEncryptionSet, &out.DiskEncryptionSet + *out = new(AzureDiskEncryptionSet) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureCSIDriverConfigSpec. +func (in *AzureCSIDriverConfigSpec) DeepCopy() *AzureCSIDriverConfigSpec { + if in == nil { + return nil + } + out := new(AzureCSIDriverConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureDiskEncryptionSet) DeepCopyInto(out *AzureDiskEncryptionSet) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureDiskEncryptionSet. +func (in *AzureDiskEncryptionSet) DeepCopy() *AzureDiskEncryptionSet { + if in == nil { + return nil + } + out := new(AzureDiskEncryptionSet) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CSIDriverConfigSpec) DeepCopyInto(out *CSIDriverConfigSpec) { *out = *in + if in.AWS != nil { + in, out := &in.AWS, &out.AWS + *out = new(AWSCSIDriverConfigSpec) + **out = **in + } + if in.Azure != nil { + in, out := &in.Azure, &out.Azure + *out = new(AzureCSIDriverConfigSpec) + (*in).DeepCopyInto(*out) + } + if in.GCP != nil { + in, out := &in.GCP, &out.GCP + *out = new(GCPCSIDriverConfigSpec) + (*in).DeepCopyInto(*out) + } if in.VSphere != nil { in, out := &in.VSphere, &out.VSphere *out = new(VSphereCSIDriverConfigSpec) @@ -1409,6 +1477,43 @@ func (in *ForwardPlugin) DeepCopy() *ForwardPlugin { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GCPCSIDriverConfigSpec) DeepCopyInto(out *GCPCSIDriverConfigSpec) { + *out = *in + if in.KMSKey != nil { + in, out := &in.KMSKey, &out.KMSKey + *out = new(GCPKMSKeyReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPCSIDriverConfigSpec. +func (in *GCPCSIDriverConfigSpec) DeepCopy() *GCPCSIDriverConfigSpec { + if in == nil { + return nil + } + out := new(GCPCSIDriverConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GCPKMSKeyReference) DeepCopyInto(out *GCPKMSKeyReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPKMSKeyReference. +func (in *GCPKMSKeyReference) DeepCopy() *GCPKMSKeyReference { + if in == nil { + return nil + } + out := new(GCPKMSKeyReference) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GCPLoadBalancerParameters) DeepCopyInto(out *GCPLoadBalancerParameters) { *out = *in @@ -1585,6 +1690,22 @@ func (in *HybridOverlayConfig) DeepCopy() *HybridOverlayConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IBMLoadBalancerParameters) DeepCopyInto(out *IBMLoadBalancerParameters) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IBMLoadBalancerParameters. +func (in *IBMLoadBalancerParameters) DeepCopy() *IBMLoadBalancerParameters { + if in == nil { + return nil + } + out := new(IBMLoadBalancerParameters) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IPAMConfig) DeepCopyInto(out *IPAMConfig) { *out = *in @@ -3454,6 +3575,11 @@ func (in *ProviderLoadBalancerParameters) DeepCopyInto(out *ProviderLoadBalancer *out = new(GCPLoadBalancerParameters) **out = **in } + if in.IBM != nil { + in, out := &in.IBM, &out.IBM + *out = new(IBMLoadBalancerParameters) + **out = **in + } return } diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go index 50ecdf3723..1248ffb1b0 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go @@ -380,9 +380,41 @@ func (StatuspageProvider) SwaggerDoc() map[string]string { return map_StatuspageProvider } +var map_AWSCSIDriverConfigSpec = map[string]string{ + "": "AWSCSIDriverConfigSpec defines properties that can be configured for the AWS CSI driver.", + "kmsKeyARN": "kmsKeyARN sets the cluster default storage class to encrypt volumes with a user-defined KMS key, rather than the default KMS key used by AWS. The value may be either the ARN or Alias ARN of a KMS key.", +} + +func (AWSCSIDriverConfigSpec) SwaggerDoc() map[string]string { + return map_AWSCSIDriverConfigSpec +} + +var map_AzureCSIDriverConfigSpec = map[string]string{ + "": "AzureCSIDriverConfigSpec defines properties that can be configured for the Azure CSI driver.", + "diskEncryptionSet": "diskEncryptionSet sets the cluster default storage class to encrypt volumes with a customer-managed encryption set, rather than the default platform-managed keys.", +} + +func (AzureCSIDriverConfigSpec) SwaggerDoc() map[string]string { + return map_AzureCSIDriverConfigSpec +} + +var map_AzureDiskEncryptionSet = map[string]string{ + "": "AzureDiskEncryptionSet defines the configuration for a disk encryption set.", + "subscriptionID": "subscriptionID defines the Azure subscription that contains the disk encryption set. The value should meet the following conditions: 1. It should be a 128-bit number. 2. It should be 36 characters (32 hexadecimal characters and 4 hyphens) long. 3. It should be displayed in five groups separated by hyphens (-). 4. The first group should be 8 characters long. 5. The second, third, and fourth groups should be 4 characters long. 6. The fifth group should be 12 characters long. An Example SubscrionID: f2007bbf-f802-4a47-9336-cf7c6b89b378", + "resourceGroup": "resourceGroup defines the Azure resource group that contains the disk encryption set. The value should consist of only alphanumberic characters, underscores (_), parentheses, hyphens and periods. The value should not end in a period and be at most 90 characters in length.", + "name": "name is the name of the disk encryption set that will be set on the default storage class. The value should consist of only alphanumberic characters, underscores (_), hyphens, and be at most 80 characters in length.", +} + +func (AzureDiskEncryptionSet) SwaggerDoc() map[string]string { + return map_AzureDiskEncryptionSet +} + var map_CSIDriverConfigSpec = map[string]string{ "": "CSIDriverConfigSpec defines configuration spec that can be used to optionally configure a specific CSI Driver.", - "driverType": "driverType indicates type of CSI driver for which the driverConfig is being applied to.\n\nValid values are:\n\n* vSphere\n\nAllows configuration of vsphere CSI driver topology.", + "driverType": "driverType indicates type of CSI driver for which the driverConfig is being applied to. Valid values are: AWS, Azure, GCP, vSphere and omitted. Consumers should treat unknown values as a NO-OP.", + "aws": "aws is used to configure the AWS CSI driver.", + "azure": "azure is used to configure the Azure CSI driver.", + "gcp": "gcp is used to configure the GCP CSI driver.", "vSphere": "vsphere is used to configure the vsphere CSI driver.", } @@ -426,6 +458,27 @@ func (ClusterCSIDriverStatus) SwaggerDoc() map[string]string { return map_ClusterCSIDriverStatus } +var map_GCPCSIDriverConfigSpec = map[string]string{ + "": "GCPCSIDriverConfigSpec defines properties that can be configured for the GCP CSI driver.", + "kmsKey": "kmsKey sets the cluster default storage class to encrypt volumes with customer-supplied encryption keys, rather than the default keys managed by GCP.", +} + +func (GCPCSIDriverConfigSpec) SwaggerDoc() map[string]string { + return map_GCPCSIDriverConfigSpec +} + +var map_GCPKMSKeyReference = map[string]string{ + "": "GCPKMSKeyReference gathers required fields for looking up a GCP KMS Key", + "name": "name is the name of the customer-managed encryption key to be used for disk encryption. The value should correspond to an existing KMS key and should consist of only alphanumeric characters, hyphens (-) and underscores (_), and be at most 63 characters in length.", + "keyRing": "keyRing is the name of the KMS Key Ring which the KMS Key belongs to. The value should correspond to an existing KMS key ring and should consist of only alphanumeric characters, hyphens (-) and underscores (_), and be at most 63 characters in length.", + "projectID": "projectID is the ID of the Project in which the KMS Key Ring exists. It must be 6 to 30 lowercase letters, digits, or hyphens. It must start with a letter. Trailing hyphens are prohibited.", + "location": "location is the GCP location in which the Key Ring exists. The value must match an existing GCP location, or \"global\". Defaults to global, if not set.", +} + +func (GCPKMSKeyReference) SwaggerDoc() map[string]string { + return map_GCPKMSKeyReference +} + var map_VSphereCSIDriverConfigSpec = map[string]string{ "": "VSphereCSIDriverConfigSpec defines properties that can be configured for vsphere CSI driver.", "topologyCategories": "topologyCategories indicates tag categories with which vcenter resources such as hostcluster or datacenter were tagged with. If cluster Infrastructure object has a topology, values specified in Infrastructure object will be used and modifications to topologyCategories will be rejected.", @@ -717,6 +770,15 @@ func (HostNetworkStrategy) SwaggerDoc() map[string]string { return map_HostNetworkStrategy } +var map_IBMLoadBalancerParameters = map[string]string{ + "": "IBMLoadBalancerParameters provides configuration settings that are specific to IBM Cloud load balancers.", + "protocol": "protocol specifies whether the load balancer uses PROXY protocol to forward connections to the IngressController. See \"service.kubernetes.io/ibm-load-balancer-cloud-provider-enable-features: \"proxy-protocol\"\" at https://cloud.ibm.com/docs/containers?topic=containers-vpc-lbaas\"\n\nPROXY protocol can be used with load balancers that support it to communicate the source addresses of client connections when forwarding those connections to the IngressController. Using PROXY protocol enables the IngressController to report those source addresses instead of reporting the load balancer's address in HTTP headers and logs. Note that enabling PROXY protocol on the IngressController will cause connections to fail if you are not using a load balancer that uses PROXY protocol to forward connections to the IngressController. See http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt for information about PROXY protocol.\n\nValid values for protocol are TCP, PROXY and omitted. When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time. The current default is TCP, without the proxy protocol enabled.", +} + +func (IBMLoadBalancerParameters) SwaggerDoc() map[string]string { + return map_IBMLoadBalancerParameters +} + var map_IngressController = map[string]string{ "": "IngressController describes a managed ingress controller for the cluster. The controller can service OpenShift Route and Kubernetes Ingress resources.\n\nWhen an IngressController is created, a new ingress controller deployment is created to allow external traffic to reach the services that expose Ingress or Route resources. Updating this resource may lead to disruption for public facing network connections as a new ingress controller revision may be rolled out.\n\nhttps://kubernetes.io/docs/concepts/services-networking/ingress-controllers\n\nWhenever possible, sensible defaults for the platform are used. See each field for more details.\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", "spec": "spec is the specification of the desired behavior of the IngressController.", @@ -920,9 +982,10 @@ func (PrivateStrategy) SwaggerDoc() map[string]string { var map_ProviderLoadBalancerParameters = map[string]string{ "": "ProviderLoadBalancerParameters holds desired load balancer information specific to the underlying infrastructure provider.", - "type": "type is the underlying infrastructure provider for the load balancer. Allowed values are \"AWS\", \"Azure\", \"BareMetal\", \"GCP\", \"Nutanix\", \"OpenStack\", and \"VSphere\".", + "type": "type is the underlying infrastructure provider for the load balancer. Allowed values are \"AWS\", \"Azure\", \"BareMetal\", \"GCP\", \"IBM\", \"Nutanix\", \"OpenStack\", and \"VSphere\".", "aws": "aws provides configuration settings that are specific to AWS load balancers.\n\nIf empty, defaults will be applied. See specific aws fields for details about their defaults.", "gcp": "gcp provides configuration settings that are specific to GCP load balancers.\n\nIf empty, defaults will be applied. See specific gcp fields for details about their defaults.", + "ibm": "ibm provides configuration settings that are specific to IBM Cloud load balancers.\n\nIf empty, defaults will be applied. See specific ibm fields for details about their defaults.", } func (ProviderLoadBalancerParameters) SwaggerDoc() map[string]string { @@ -1209,7 +1272,7 @@ var map_KuryrConfig = map[string]string{ "poolMaxPorts": "poolMaxPorts sets a maximum number of free ports that are being kept in a port pool. If the number of ports exceeds this setting, free ports will get deleted. Setting 0 will disable this upper bound, effectively preventing pools from shrinking and this is the default value. For more information about port pools see enablePortPoolsPrepopulation setting.", "poolMinPorts": "poolMinPorts sets a minimum number of free ports that should be kept in a port pool. If the number of ports is lower than this setting, new ports will get created and added to pool. The default is 1. For more information about port pools see enablePortPoolsPrepopulation setting.", "poolBatchPorts": "poolBatchPorts sets a number of ports that should be created in a single batch request to extend the port pool. The default is 3. For more information about port pools see enablePortPoolsPrepopulation setting.", - "mtu": "mtu is the MTU that Kuryr should use when creating pod networks in Neutron. The value has to be lower or equal to the MTU of the nodes network and Neutron has to allow creation of tenant networks with such MTU. If unset Pod networks will be created with the same MTU as the nodes network has.", + "mtu": "mtu is the MTU that Kuryr should use when creating pod networks in Neutron. The value has to be lower or equal to the MTU of the nodes network and Neutron has to allow creation of tenant networks with such MTU. If unset Pod networks will be created with the same MTU as the nodes network has. This also affects the services network created by cluster-network-operator.", } func (KuryrConfig) SwaggerDoc() map[string]string { @@ -1547,7 +1610,8 @@ func (StorageList) SwaggerDoc() map[string]string { } var map_StorageSpec = map[string]string{ - "": "StorageSpec is the specification of the desired behavior of the cluster storage operator.", + "": "StorageSpec is the specification of the desired behavior of the cluster storage operator.", + "vsphereStorageDriver": "VSphereStorageDriver indicates the storage driver to use on VSphere clusters. Once this field is set to CSIWithMigrationDriver, it can not be changed. If this is empty, the platform will choose a good default, which may change over time without notice. DEPRECATED: This field will be removed in a future release.", } func (StorageSpec) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/callback_server.go b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/callback_server.go new file mode 100644 index 0000000000..bff4911343 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/callback_server.go @@ -0,0 +1,126 @@ +package tokenrequest + +import ( + "context" + "errors" + "fmt" + "net" + "net/http" + "strconv" + + "k8s.io/klog/v2" +) + +type callbackResult struct { + token string + err error +} + +type callbackHandlerFunc func(*http.Request) (string, error) + +type callbackServer struct { + server *http.Server + tcpListener net.Listener + listenAddr *net.TCPAddr + + // the channel to deliver the access token or error + resultChan chan callbackResult + + // function to call when the callback redirect is received; this should be + // used to request an access token based on the received callback + callbackHandler callbackHandlerFunc +} + +func newCallbackServer(port int) (*callbackServer, error) { + callbackServer := &callbackServer{ + resultChan: make(chan callbackResult, 1), + } + + loopbackAddr, err := getLoopbackAddr() + if err != nil { + return nil, err + } + + callbackServer.tcpListener, err = net.Listen("tcp", net.JoinHostPort(loopbackAddr, strconv.Itoa(port))) + if err != nil { + return nil, err + } + + listenAddr, ok := callbackServer.tcpListener.Addr().(*net.TCPAddr) + if !ok { + return nil, fmt.Errorf("listener is not of TCP type: %v", callbackServer.tcpListener.Addr()) + } + callbackServer.listenAddr = listenAddr + + mux := http.NewServeMux() + mux.Handle("/callback", callbackServer) + + callbackServer.server = &http.Server{ + Handler: mux, + } + + return callbackServer, nil +} + +func (c *callbackServer) ListenAddr() *net.TCPAddr { + return c.listenAddr +} + +func (c *callbackServer) SetCallbackHandler(callbackHandler callbackHandlerFunc) { + c.callbackHandler = callbackHandler +} + +func (c *callbackServer) Start() { + err := c.server.Serve(c.tcpListener) + if err != nil && err != http.ErrServerClosed { + klog.V(4).Infof("callback server failed: %v", err) + c.resultChan <- callbackResult{err: err} + } + + close(c.resultChan) +} + +func (c *callbackServer) Shutdown(ctx context.Context) { + err := c.server.Shutdown(ctx) + if err != nil { + klog.V(4).Infof("failed to shutdown callback server: %v", err) + } +} + +func (c *callbackServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if c.callbackHandler == nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("access token request failed; please return to your terminal")) + c.resultChan <- callbackResult{err: fmt.Errorf("no callback handler set")} + return + } + + token, err := c.callbackHandler(r) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("access token request failed; please return to your terminal")) + c.resultChan <- callbackResult{err: err} + return + } + + w.Write([]byte("access token received successfully; please return to your terminal")) + c.resultChan <- callbackResult{token: token} +} + +// getLoopbackAddr returns the first address from the host's network interfaces which is a loopback address +func getLoopbackAddr() (string, error) { + interfaces, err := net.InterfaceAddrs() + if err != nil { + return "", err + } + + for _, iface := range interfaces { + if ipaddr, ok := iface.(*net.IPNet); ok { + if ipaddr.IP.IsLoopback() { + return ipaddr.IP.String(), nil + } + } + } + + return "", errors.New("no loopback network interfaces found") +} diff --git a/pkg/helpers/tokencmd/basicauth.go b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers/basicauth.go similarity index 77% rename from pkg/helpers/tokencmd/basicauth.go rename to vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers/basicauth.go index 6b7f7be1aa..76d9f1441a 100644 --- a/pkg/helpers/tokencmd/basicauth.go +++ b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers/basicauth.go @@ -1,4 +1,4 @@ -package tokencmd +package challengehandlers import ( "encoding/base64" @@ -10,9 +10,6 @@ import ( "strings" "k8s.io/klog/v2" - - "github.com/openshift/oc/pkg/helpers/term" - "github.com/openshift/oc/pkg/version" ) // BasicAuthNoUsernameError when basic authentication challenge handling was attempted @@ -28,19 +25,39 @@ func NewBasicAuthNoUsernameError() error { return &BasicAuthNoUsernameError{} } +func NewBasicChallengeHandler( + host string, + reader io.Reader, + writer io.Writer, + passwordPrompter PasswordPrompter, + username, password string, +) *BasicChallengeHandler { + return &BasicChallengeHandler{ + Host: host, + Reader: reader, + Writer: writer, + passwordPrompter: passwordPrompter, + Username: username, + Password: password, + } +} + +// BasicChallengeHandler handles the "WWW-Authenticate: Basic" challenges. +// It implements the `ChallengeHandler` interface. type BasicChallengeHandler struct { // Host is the server being authenticated to. Used only for displaying messages when prompting for username/password Host string - // serverVersionRetriever is used for fetching server version - serverVersionRetriever version.ServerVersionRetriever - // Reader is used to prompt for username/password. If nil, no prompting is done Reader io.Reader // Writer is used to output prompts. If nil, stdout is used Writer io.Writer - // Username is the username to use when challenged. If empty, a prompt is issued to a non-nil Reader + // passwordPrompter is used to retrieve the password as a string + passwordPrompter PasswordPrompter + + // Username is the username to use when challenged. If empty, a `BasicAuthNoUsernameError` is returned + // when handling the challenge. Username string // Password is the password to use when challenged. If empty, a prompt is issued to a non-nil Reader Password string @@ -55,13 +72,18 @@ func (c *BasicChallengeHandler) CanHandle(headers http.Header) bool { isBasic, _ := basicRealm(headers) return isBasic } + +// HandleChallenge attempts to handle the "WWW-Authenticate: Basic" challenge. +// It may prompt for a password matching the username that should already be a part +// of the BasicChallengeHandler. The prompt is supposed to be called only once +// but this assertion is thread unsafe. func (c *BasicChallengeHandler) HandleChallenge(requestURL string, headers http.Header) (http.Header, bool, error) { if c.prompted { - klog.V(2).Info("already prompted for challenge, won't prompt again") + klog.V(4).Info("already prompted for challenge, won't prompt again") return nil, false, nil } if c.handled { - klog.V(2).Info("already handled basic challenge") + klog.V(4).Info("already handled basic challenge") return nil, false, nil } @@ -90,16 +112,9 @@ func (c *BasicChallengeHandler) HandleChallenge(requestURL string, headers http. } else { fmt.Fprintf(w, "Authentication required for %s\n", c.Host) } - if c.serverVersionRetriever != nil { - serverVersion, err := c.serverVersionRetriever.RetrieveServerVersion() - // this feature was introduced in Openshift 4.11 which should correspond to 1.24 - if err == nil && serverVersion.MajorNumber >= 1 && serverVersion.MinorNumber >= 24 { - fmt.Fprintf(w, "Console URL: %s/console\n", c.Host) - } - } fmt.Fprintf(w, "Username: %s\n", username) if missingPassword { - password = term.PromptForPasswordString(c.Reader, w, "Password: ") + password = c.passwordPrompter.PromptForPassword(c.Reader, w, "Password: ") } // remember so we don't re-prompt c.prompted = true diff --git a/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers/interfaces.go b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers/interfaces.go new file mode 100644 index 0000000000..49a5fddd47 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers/interfaces.go @@ -0,0 +1,29 @@ +package challengehandlers + +import ( + "io" + "net/http" +) + +// ChallengeHandler handles responses to WWW-Authenticate challenges. +type ChallengeHandler interface { + // CanHandle returns true if the handler recognizes a challenge it thinks it can handle. + CanHandle(headers http.Header) bool + // HandleChallenge lets the handler attempt to handle a challenge. + // It is only invoked if CanHandle() returned true for the given headers. + // Returns response headers and true if the challenge is successfully handled. + // Returns false if the challenge was not handled, and an optional error in error cases. + HandleChallenge(requestURL string, headers http.Header) (http.Header, bool, error) + // CompleteChallenge is invoked with the headers from a successful server response + // received after having handled one or more challenges. + // Returns an error if the handler does not consider the challenge/response interaction complete. + CompleteChallenge(requestURL string, headers http.Header) error + // Release gives the handler a chance to release any resources held during a challenge/response sequence. + // It is always invoked, even in cases where no challenges were received or handled. + Release() error +} + +// PasswordPrompter is an interface for requesting passwords in the form of a string +type PasswordPrompter interface { + PromptForPassword(r io.Reader, w io.Writer, format string, a ...interface{}) string +} diff --git a/pkg/helpers/tokencmd/multi.go b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers/multi.go similarity index 96% rename from pkg/helpers/tokencmd/multi.go rename to vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers/multi.go index bcdb3774e7..76f76935f1 100644 --- a/pkg/helpers/tokencmd/multi.go +++ b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers/multi.go @@ -1,4 +1,4 @@ -package tokencmd +package challengehandlers import ( "net/http" @@ -103,3 +103,7 @@ func (h *MultiHandler) Release() error { } return utilerrors.NewAggregate(errs) } + +func (h *MultiHandler) Handlers() []ChallengeHandler { + return h.allHandlers +} diff --git a/pkg/helpers/tokencmd/request_token.go b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/request_token.go similarity index 69% rename from pkg/helpers/tokencmd/request_token.go rename to vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/request_token.go index 3066509314..d084e23548 100644 --- a/pkg/helpers/tokencmd/request_token.go +++ b/vendor/github.com/openshift/library-go/pkg/oauth/tokenrequest/request_token.go @@ -1,6 +1,7 @@ -package tokencmd +package tokenrequest import ( + "context" "crypto/tls" "crypto/x509" "encoding/json" @@ -20,9 +21,8 @@ import ( restclient "k8s.io/client-go/rest" "k8s.io/klog/v2" - "github.com/openshift/oc/pkg/version" - "github.com/openshift/library-go/pkg/oauth/oauthdiscovery" + "github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers" ) const ( @@ -40,6 +40,9 @@ const ( // openShiftCLIClientID is the name of the CLI OAuth client, copied from pkg/oauth/apiserver/auth.go openShiftCLIClientID = "openshift-challenging-client" + // openShiftCLIBrowserClientID the name of the CLI client for logging in through a browser + openShiftCLIBrowserClientID = "openshift-cli-client" + // pkce_s256 is sha256 hash per RFC7636, copied from github.com/RangelReale/osincli/pkce.go pkce_s256 = "S256" @@ -50,74 +53,107 @@ const ( BasicAuthNoUsernameMessage = "BasicChallengeNoUsername" ) -// ChallengeHandler handles responses to WWW-Authenticate challenges. -type ChallengeHandler interface { - // CanHandle returns true if the handler recognizes a challenge it thinks it can handle. - CanHandle(headers http.Header) bool - // HandleChallenge lets the handler attempt to handle a challenge. - // It is only invoked if CanHandle() returned true for the given headers. - // Returns response headers and true if the challenge is successfully handled. - // Returns false if the challenge was not handled, and an optional error in error cases. - HandleChallenge(requestURL string, headers http.Header) (http.Header, bool, error) - // CompleteChallenge is invoked with the headers from a successful server response - // received after having handled one or more challenges. - // Returns an error if the handler does not consider the challenge/response interaction complete. - CompleteChallenge(requestURL string, headers http.Header) error - // Release gives the handler a chance to release any resources held during a challenge/response sequence. - // It is always invoked, even in cases where no challenges were received or handled. - Release() error -} - type RequestTokenOptions struct { ClientConfig *restclient.Config - Handler ChallengeHandler + Handler challengehandlers.ChallengeHandler OsinConfig *osincli.ClientConfig Issuer string TokenFlow bool -} -// RequestToken uses the cmd arguments to locate an openshift oauth server and attempts to authenticate via an -// OAuth code flow and challenge handling. It returns the access token if it gets one or an error if it does not. -func RequestToken(clientCfg *restclient.Config, reader io.Reader, defaultUsername string, defaultPassword string) (string, error) { - return NewRequestTokenOptions(clientCfg, reader, defaultUsername, defaultPassword, false).RequestToken() -} + // AuthorizationURLHandler defines how the authorization URL of the OAuth Code Grant flow + // should be handled; for example use this function to take the URL and open it in a browser + AuthorizationURLHandler AuthorizationURLHandlerFunc -func NewRequestTokenOptions(clientCfg *restclient.Config, reader io.Reader, defaultUsername string, defaultPassword string, tokenFlow bool) *RequestTokenOptions { - // priority ordered list of challenge handlers - // the SPNEGO ones must come before basic auth - var handlers []ChallengeHandler + // LocalCallbackServer receives the callback once the user authorizes the request + // as a redirect from the OAuth server, and exchanges the authorization code for an access token + LocalCallbackServer *callbackServer +} - serverVersionDetector := version.NewServerVersionRetriever(clientCfg) +type AuthorizationURLHandlerFunc func(url *url.URL) error - if GSSAPIEnabled() { - klog.V(6).Info("GSSAPI Enabled") - handlers = append(handlers, NewNegotiateChallengeHandler(NewGSSAPINegotiator(defaultUsername))) +// RequestTokenWithChallengeHandlers uses the cmd arguments to locate an openshift oauth server +// and attempts to authenticate with the OAuth code flow and challenge handling. +// It returns the access token if it gets one or an error if it does not. +func RequestTokenWithChallengeHandlers(clientCfg *restclient.Config, challengeHandlers ...challengehandlers.ChallengeHandler) (string, error) { + o, err := NewRequestTokenOptions(clientCfg, false).WithChallengeHandlers(challengeHandlers...) + if err != nil { + return "", err } - if SSPIEnabled() { - klog.V(6).Info("SSPI Enabled") - handlers = append(handlers, NewNegotiateChallengeHandler(NewSSPINegotiator(defaultUsername, defaultPassword, clientCfg.Host, reader, serverVersionDetector))) + return o.RequestToken() +} + +// RequestTokenWithLocalCallback will perform the OAuth authorization code grant flow to obtain an access token. +// authzURLHandler is used to forward the user to the OAuth server's parametrized authorization URL to +// retrieve the authorization code. +// It starts a localhost server on port `callbackPort` (random port if unspecified) to exchange the authorization code for an access token. +func RequestTokenWithLocalCallback(clientCfg *restclient.Config, authzURLHandler AuthorizationURLHandlerFunc, callbackPort int) (string, error) { + o, err := NewRequestTokenOptions(clientCfg, false).WithLocalCallback(authzURLHandler, callbackPort) + if err != nil { + return "", err } - handlers = append(handlers, &BasicChallengeHandler{Host: clientCfg.Host, serverVersionRetriever: serverVersionDetector, Reader: reader, Username: defaultUsername, Password: defaultPassword}) + return o.RequestToken() +} - var handler ChallengeHandler - if len(handlers) == 1 { - handler = handlers[0] - } else { - handler = NewMultiHandler(handlers...) - } +func NewRequestTokenOptions( + clientCfg *restclient.Config, + tokenFlow bool, +) *RequestTokenOptions { return &RequestTokenOptions{ ClientConfig: clientCfg, - Handler: handler, TokenFlow: tokenFlow, } } +// WithChallengeHandlers sets up the RequestTokenOptions with the provided challengeHandlers to be +// used in the OAuth code flow. +// If RequestTokenOptions.OsinConfig is nil, it will be defaulted using SetDefaultOsinConfig. +// The caller is responsible for setting up the entire OsinConfig if the value is not nil. +func (o *RequestTokenOptions) WithChallengeHandlers(challengeHandlers ...challengehandlers.ChallengeHandler) (*RequestTokenOptions, error) { + var handler challengehandlers.ChallengeHandler + if len(challengeHandlers) == 1 { + handler = challengeHandlers[0] + } else { + handler = challengehandlers.NewMultiHandler(challengeHandlers...) + } + o.Handler = handler + + if o.OsinConfig == nil { + if err := o.SetDefaultOsinConfig(openShiftCLIClientID, nil); err != nil { + return nil, err + } + } + + return o, nil +} + +// WithLocalCallback sets up the RequestTokenOptions with an AuthorizationURLHanderFunc and an +// unstarted local callback server on the specified port. +// If RequestTokenOptions.OsinConfig is nil, it will be defaulted using SetDefaultOsinConfig. +// The caller is responsible for setting up the entire OsinConfig if the value is not nil. +func (o *RequestTokenOptions) WithLocalCallback(handleAuthzURL AuthorizationURLHandlerFunc, localCallbackPort int) (*RequestTokenOptions, error) { + var err error + o.AuthorizationURLHandler = handleAuthzURL + o.LocalCallbackServer, err = newCallbackServer(localCallbackPort) + if err != nil { + return nil, err + } + + if o.OsinConfig == nil { + redirectUrl := fmt.Sprintf("http://%s/callback", o.LocalCallbackServer.ListenAddr()) + if err := o.SetDefaultOsinConfig(openShiftCLIBrowserClientID, &redirectUrl); err != nil { + return nil, err + } + } + + return o, nil +} + // SetDefaultOsinConfig overwrites RequestTokenOptions.OsinConfig with the default CLI // OAuth client and PKCE support if the server supports S256 / a code flow is being used -func (o *RequestTokenOptions) SetDefaultOsinConfig() error { +func (o *RequestTokenOptions) SetDefaultOsinConfig(clientID string, redirectURL *string) error { if o.OsinConfig != nil { return fmt.Errorf("osin config is already set to: %#v", *o.OsinConfig) } @@ -147,11 +183,16 @@ func (o *RequestTokenOptions) SetDefaultOsinConfig() error { // use the metadata to build the osin config config := &osincli.ClientConfig{ - ClientId: openShiftCLIClientID, + ClientId: clientID, AuthorizeUrl: metadata.AuthorizationEndpoint, TokenUrl: metadata.TokenEndpoint, RedirectUrl: oauthdiscovery.OpenShiftOAuthTokenImplicitURL(metadata.Issuer), } + + if redirectURL != nil { + config.RedirectUrl = *redirectURL + } + if !o.TokenFlow && sets.NewString(metadata.CodeChallengeMethodsSupported...).Has(pkce_s256) { if err := osincli.PopulatePKCE(config); err != nil { return err @@ -163,13 +204,29 @@ func (o *RequestTokenOptions) SetDefaultOsinConfig() error { return nil } -// RequestToken locates an openshift oauth server and attempts to authenticate. +// RequestToken decides on how to perform the token request based on the configured +// RequestTokenOptions object and performs the request. // It returns the access token if it gets one, or an error if it does not. // It should only be invoked once on a given RequestTokenOptions instance. -// The Handler held by the options is released as part of this call. -// If RequestTokenOptions.OsinConfig is nil, it will be defaulted using SetDefaultOsinConfig. -// The caller is responsible for setting up the entire OsinConfig if the value is not nil. func (o *RequestTokenOptions) RequestToken() (string, error) { + + switch { + case o.LocalCallbackServer != nil: + return o.requestTokenWithLocalCallback() + + case o.Handler != nil: + return o.requestTokenWithChallengeHandlers() + + default: + return "", fmt.Errorf("no challenge handlers or localhost callback server were provided") + } +} + +// requestTokenWithChallengeHandlers performs the OAuth code flow using the configured +// challenge handlers. +// It returns the access token if it gets one, or an error if it does not. +// The Handler held by the options is released as part of this call. +func (o *RequestTokenOptions) requestTokenWithChallengeHandlers() (string, error) { defer func() { // Always release the handler if err := o.Handler.Release(); err != nil { @@ -178,30 +235,11 @@ func (o *RequestTokenOptions) RequestToken() (string, error) { } }() - if o.OsinConfig == nil { - if err := o.SetDefaultOsinConfig(); err != nil { - return "", err - } - } - - // we are going to use this transport to talk - // with a server that may not be the api server - // thus we need to include the system roots - // in our ca data otherwise an external - // oauth server with a valid cert will fail with - // error: x509: certificate signed by unknown authority - rt, err := transportWithSystemRoots(o.Issuer, o.ClientConfig) + client, authorizeRequest, err := o.newOsinClient() if err != nil { return "", err } - client, err := osincli.NewClient(o.OsinConfig) - if err != nil { - return "", err - } - client.Transport = rt - authorizeRequest := client.NewAuthorizeRequest(osincli.CODE) // assume code flow to start with - var oauthTokenFunc func(redirectURL string) (accessToken string, oauthError error) if o.TokenFlow { // access_token in fragment or error parameter @@ -225,7 +263,7 @@ func (o *RequestTokenOptions) RequestToken() (string, error) { for { // Make the request - resp, err := request(rt, requestURL, requestHeaders) + resp, err := request(client.Transport, requestURL, requestHeaders) if err != nil { return "", err } @@ -239,12 +277,16 @@ func (o *RequestTokenOptions) RequestToken() (string, error) { // Handle the challenge newRequestHeaders, shouldRetry, err := o.Handler.HandleChallenge(requestURL, resp.Header) if err != nil { - if _, ok := err.(*BasicAuthNoUsernameError); ok { + if _, ok := err.(*challengehandlers.BasicAuthNoUsernameError); ok { tokenPromptErr := apierrs.NewUnauthorized(BasicAuthNoUsernameMessage) klog.V(2).Infof("%v", err) tokenPromptErr.ErrStatus.Details = &metav1.StatusDetails{ Causes: []metav1.StatusCause{ - {Message: fmt.Sprintf("You must obtain an API token by visiting %s/request", o.OsinConfig.TokenUrl)}, + {Message: fmt.Sprintf( + "You must obtain an API token by visiting %s/request\n\n%s", + o.OsinConfig.TokenUrl, + `Alternatively, use "oc login --web" to login via your browser. See "oc login --help" for more information.`, + )}, }, } return "", tokenPromptErr @@ -316,6 +358,63 @@ func (o *RequestTokenOptions) RequestToken() (string, error) { } } +// requestTokenWithLocalCallback performs the OAuth authorization code grant flow. +// It will start the local callback server, invoke the authorization URL handler, +// and exchange the code for an access token. Once done, it will also shut down +// the callback server. +// It returns the access token if it gets one, or an error if it does not. +func (o *RequestTokenOptions) requestTokenWithLocalCallback() (string, error) { + + client, authorizeRequest, err := o.newOsinClient() + if err != nil { + return "", err + } + + o.LocalCallbackServer.SetCallbackHandler(func(callback *http.Request) (string, error) { + // once the redirect callback is received, use it to request an access token + // from the oauth server + return requestAccessToken(client, authorizeRequest, callback) + }) + + go func() { o.LocalCallbackServer.Start() }() + defer func() { o.LocalCallbackServer.Shutdown(context.Background()) }() + + if err := o.AuthorizationURLHandler(authorizeRequest.GetAuthorizeUrl()); err != nil { + return "", err + } + + result := <-o.LocalCallbackServer.resultChan + if result.err != nil { + return "", result.err + } + + return result.token, nil +} + +func (o *RequestTokenOptions) newOsinClient() (*osincli.Client, *osincli.AuthorizeRequest, error) { + + // we are going to use this transport to talk + // with a server that may not be the api server + // thus we need to include the system roots + // in our ca data otherwise an external + // oauth server with a valid cert will fail with + // error: x509: certificate signed by unknown authority + rt, err := transportWithSystemRoots(o.Issuer, o.ClientConfig) + if err != nil { + return nil, nil, err + } + + client, err := osincli.NewClient(o.OsinConfig) + if err != nil { + return nil, nil, err + } + client.Transport = rt + + authorizeRequest := client.NewAuthorizeRequest(osincli.CODE) // assume code flow to start with + + return client, authorizeRequest, nil +} + // oauthTokenFlow attempts to extract an OAuth token from location's fragment's access_token value. // It only returns an error if something "impossible" happens (location is not a valid URL) or a definite // OAuth error is contained in the location URL. No error is returned if location does not contain a token. @@ -364,6 +463,11 @@ func oauthCodeFlow(client *osincli.Client, authorizeRequest *osincli.AuthorizeRe return "", nil // no code parameter so this is not part of the OAuth flow } + return requestAccessToken(client, authorizeRequest, req) +} + +func requestAccessToken(client *osincli.Client, authorizeRequest *osincli.AuthorizeRequest, req *http.Request) (string, error) { + // any errors after this are fatal because we are committed to an OAuth flow now authorizeData, err := authorizeRequest.HandleRequest(req) if err != nil { @@ -431,7 +535,14 @@ func transportWithSystemRoots(issuer string, clientConfig *restclient.Config) (h // perform the retrieval with insecure transport, otherwise oauth-server // logs remote tls error which is confusing during troubleshooting client := http.Client{ - Transport: insecureTransport(clientConfig.Transport, issuerURL), + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{ + Certificates: []tls.Certificate{}, + InsecureSkipVerify: true, + ServerName: issuerURL.Hostname(), + }, + }, } resp, err := client.Head(issuer) if err != nil { @@ -496,22 +607,3 @@ func verifyServerCertChain(dnsName string, chain []*x509.Certificate) ([][]*x509 DNSName: dnsName, }) } - -func insecureTransport(roundTripper http.RoundTripper, issuerURL *url.URL) *http.Transport { - tlsConfig := &tls.Config{ - Certificates: []tls.Certificate{}, - InsecureSkipVerify: true, - ServerName: issuerURL.Hostname(), - } - if transport, ok := roundTripper.(*http.Transport); ok { - return &http.Transport{ - Proxy: transport.Proxy, - DialContext: transport.DialContext, - TLSClientConfig: tlsConfig, - } - } - return &http.Transport{ - Proxy: http.ProxyFromEnvironment, - TLSClientConfig: tlsConfig, - } -} diff --git a/vendor/github.com/pkg/browser/LICENSE b/vendor/github.com/pkg/browser/LICENSE new file mode 100644 index 0000000000..65f78fb629 --- /dev/null +++ b/vendor/github.com/pkg/browser/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2014, Dave Cheney +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/pkg/browser/README.md b/vendor/github.com/pkg/browser/README.md new file mode 100644 index 0000000000..72b1976e30 --- /dev/null +++ b/vendor/github.com/pkg/browser/README.md @@ -0,0 +1,55 @@ + +# browser + import "github.com/pkg/browser" + +Package browser provides helpers to open files, readers, and urls in a browser window. + +The choice of which browser is started is entirely client dependant. + + + + + +## Variables +``` go +var Stderr io.Writer = os.Stderr +``` +Stderr is the io.Writer to which executed commands write standard error. + +``` go +var Stdout io.Writer = os.Stdout +``` +Stdout is the io.Writer to which executed commands write standard output. + + +## func OpenFile +``` go +func OpenFile(path string) error +``` +OpenFile opens new browser window for the file path. + + +## func OpenReader +``` go +func OpenReader(r io.Reader) error +``` +OpenReader consumes the contents of r and presents the +results in a new browser window. + + +## func OpenURL +``` go +func OpenURL(url string) error +``` +OpenURL opens a new browser window pointing to url. + + + + + + + + + +- - - +Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md) diff --git a/vendor/github.com/pkg/browser/browser.go b/vendor/github.com/pkg/browser/browser.go new file mode 100644 index 0000000000..d7969d74d8 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser.go @@ -0,0 +1,57 @@ +// Package browser provides helpers to open files, readers, and urls in a browser window. +// +// The choice of which browser is started is entirely client dependant. +package browser + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" +) + +// Stdout is the io.Writer to which executed commands write standard output. +var Stdout io.Writer = os.Stdout + +// Stderr is the io.Writer to which executed commands write standard error. +var Stderr io.Writer = os.Stderr + +// OpenFile opens new browser window for the file path. +func OpenFile(path string) error { + path, err := filepath.Abs(path) + if err != nil { + return err + } + return OpenURL("file://" + path) +} + +// OpenReader consumes the contents of r and presents the +// results in a new browser window. +func OpenReader(r io.Reader) error { + f, err := ioutil.TempFile("", "browser.*.html") + if err != nil { + return fmt.Errorf("browser: could not create temporary file: %v", err) + } + if _, err := io.Copy(f, r); err != nil { + f.Close() + return fmt.Errorf("browser: caching temporary file failed: %v", err) + } + if err := f.Close(); err != nil { + return fmt.Errorf("browser: caching temporary file failed: %v", err) + } + return OpenFile(f.Name()) +} + +// OpenURL opens a new browser window pointing to url. +func OpenURL(url string) error { + return openBrowser(url) +} + +func runCmd(prog string, args ...string) error { + cmd := exec.Command(prog, args...) + cmd.Stdout = Stdout + cmd.Stderr = Stderr + return cmd.Run() +} diff --git a/vendor/github.com/pkg/browser/browser_darwin.go b/vendor/github.com/pkg/browser/browser_darwin.go new file mode 100644 index 0000000000..8507cf7c2b --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_darwin.go @@ -0,0 +1,5 @@ +package browser + +func openBrowser(url string) error { + return runCmd("open", url) +} diff --git a/vendor/github.com/pkg/browser/browser_freebsd.go b/vendor/github.com/pkg/browser/browser_freebsd.go new file mode 100644 index 0000000000..4fc7ff0761 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_freebsd.go @@ -0,0 +1,14 @@ +package browser + +import ( + "errors" + "os/exec" +) + +func openBrowser(url string) error { + err := runCmd("xdg-open", url) + if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound { + return errors.New("xdg-open: command not found - install xdg-utils from ports(8)") + } + return err +} diff --git a/vendor/github.com/pkg/browser/browser_linux.go b/vendor/github.com/pkg/browser/browser_linux.go new file mode 100644 index 0000000000..d26cdddf9c --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_linux.go @@ -0,0 +1,21 @@ +package browser + +import ( + "os/exec" + "strings" +) + +func openBrowser(url string) error { + providers := []string{"xdg-open", "x-www-browser", "www-browser"} + + // There are multiple possible providers to open a browser on linux + // One of them is xdg-open, another is x-www-browser, then there's www-browser, etc. + // Look for one that exists and run it + for _, provider := range providers { + if _, err := exec.LookPath(provider); err == nil { + return runCmd(provider, url) + } + } + + return &exec.Error{Name: strings.Join(providers, ","), Err: exec.ErrNotFound} +} diff --git a/vendor/github.com/pkg/browser/browser_netbsd.go b/vendor/github.com/pkg/browser/browser_netbsd.go new file mode 100644 index 0000000000..65a5e5a293 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_netbsd.go @@ -0,0 +1,14 @@ +package browser + +import ( + "errors" + "os/exec" +) + +func openBrowser(url string) error { + err := runCmd("xdg-open", url) + if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound { + return errors.New("xdg-open: command not found - install xdg-utils from pkgsrc(7)") + } + return err +} diff --git a/vendor/github.com/pkg/browser/browser_openbsd.go b/vendor/github.com/pkg/browser/browser_openbsd.go new file mode 100644 index 0000000000..4fc7ff0761 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_openbsd.go @@ -0,0 +1,14 @@ +package browser + +import ( + "errors" + "os/exec" +) + +func openBrowser(url string) error { + err := runCmd("xdg-open", url) + if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound { + return errors.New("xdg-open: command not found - install xdg-utils from ports(8)") + } + return err +} diff --git a/vendor/github.com/pkg/browser/browser_unsupported.go b/vendor/github.com/pkg/browser/browser_unsupported.go new file mode 100644 index 0000000000..7c5c17d34d --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_unsupported.go @@ -0,0 +1,12 @@ +// +build !linux,!windows,!darwin,!openbsd,!freebsd,!netbsd + +package browser + +import ( + "fmt" + "runtime" +) + +func openBrowser(url string) error { + return fmt.Errorf("openBrowser: unsupported operating system: %v", runtime.GOOS) +} diff --git a/vendor/github.com/pkg/browser/browser_windows.go b/vendor/github.com/pkg/browser/browser_windows.go new file mode 100644 index 0000000000..63e192959a --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_windows.go @@ -0,0 +1,7 @@ +package browser + +import "golang.org/x/sys/windows" + +func openBrowser(url string) error { + return windows.ShellExecute(0, nil, windows.StringToUTF16Ptr(url), nil, nil, windows.SW_SHOWNORMAL) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 113f81b94b..1407507316 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -536,7 +536,7 @@ github.com/opencontainers/runc/libcontainer/user # github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 ## explicit github.com/opencontainers/runtime-spec/specs-go -# github.com/openshift/api v0.0.0-20230120195050-6ba31fa438f2 +# github.com/openshift/api v0.0.0-20230330150608-05635858d40f ## explicit; go 1.19 github.com/openshift/api github.com/openshift/api/annotations @@ -715,7 +715,7 @@ github.com/openshift/client-go/user/clientset/versioned/fake github.com/openshift/client-go/user/clientset/versioned/scheme github.com/openshift/client-go/user/clientset/versioned/typed/user/v1 github.com/openshift/client-go/user/clientset/versioned/typed/user/v1/fake -# github.com/openshift/library-go v0.0.0-20230227140230-39892725eed1 +# github.com/openshift/library-go v0.0.0-20231115094609-5e510a6e9a52 ## explicit; go 1.19 github.com/openshift/library-go/pkg/apps/appsserialization github.com/openshift/library-go/pkg/apps/appsutil @@ -745,6 +745,8 @@ github.com/openshift/library-go/pkg/network github.com/openshift/library-go/pkg/network/networkapihelpers github.com/openshift/library-go/pkg/network/networkutils github.com/openshift/library-go/pkg/oauth/oauthdiscovery +github.com/openshift/library-go/pkg/oauth/tokenrequest +github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers github.com/openshift/library-go/pkg/operator/certrotation github.com/openshift/library-go/pkg/operator/condition github.com/openshift/library-go/pkg/operator/events @@ -773,6 +775,9 @@ github.com/openshift/library-go/pkg/verify/util # github.com/peterbourgon/diskv v2.0.1+incompatible ## explicit github.com/peterbourgon/diskv +# github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 +## explicit; go 1.14 +github.com/pkg/browser # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors