chore: Define CheCluster v2alpha1 (#843)

Implements eclipse/che#19846.

Defines a new version of the CheCluster custom resource and implements
conversion functions from and to v1. The v2alpha1 is intentionally NOT
part of the CRD yet and is meant to be used only at runtime by
the operator code.
pull/859/head
Lukas Krejci 2021-06-07 12:55:14 +02:00 committed by GitHub
parent 8740c19c23
commit b2f4f44f45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1550 additions and 17 deletions

View File

@ -868,6 +868,38 @@ spec:
devfileRegistryURL:
description: Public URL to the devfile registry.
type: string
devworkspaceStatus:
description: The status of the Devworkspace subsystem
properties:
gatewayHost:
description: GatewayHost is the resolved host of the ingress/route.
This is equal to the Host in the spec on Kubernetes but contains
the actual host name of the route if Host is unspecified on OpenShift.
type: string
gatewayPhase:
description: GatewayPhase specifies the phase in which the gateway
deployment currently is. If the gateway is disabled, the phase
is "Inactive".
type: string
message:
description: Message contains further human-readable info for why
the Che cluster is in the phase it currently is.
type: string
phase:
description: Phase is the phase in which the Che cluster as a whole
finds itself in.
type: string
reason:
description: A brief CamelCase message indicating details about
why the Che cluster is in this state.
type: string
workspaceBaseDomain:
description: The resolved workspace base domain. This is either
the copy of the explicitly defined property of the same name in
the spec or, if it is undefined in the spec and we're running
on OpenShift, the automatically resolved basedomain for routes.
type: string
type: object
gitHubOAuthProvisioned:
description: Indicates whether an Identity Provider instance, Keycloak
or RH-SSO, has been configured to integrate with the GitHub OAuth.

View File

@ -885,6 +885,39 @@ spec:
devfileRegistryURL:
description: Public URL to the devfile registry.
type: string
devworkspaceStatus:
description: The status of the Devworkspace subsystem
properties:
gatewayHost:
description: GatewayHost is the resolved host of the ingress/route.
This is equal to the Host in the spec on Kubernetes but contains
the actual host name of the route if Host is unspecified on
OpenShift.
type: string
gatewayPhase:
description: GatewayPhase specifies the phase in which the gateway
deployment currently is. If the gateway is disabled, the phase
is "Inactive".
type: string
message:
description: Message contains further human-readable info for
why the Che cluster is in the phase it currently is.
type: string
phase:
description: Phase is the phase in which the Che cluster as a
whole finds itself in.
type: string
reason:
description: A brief CamelCase message indicating details about
why the Che cluster is in this state.
type: string
workspaceBaseDomain:
description: The resolved workspace base domain. This is either
the copy of the explicitly defined property of the same name
in the spec or, if it is undefined in the spec and we're running
on OpenShift, the automatically resolved basedomain for routes.
type: string
type: object
gitHubOAuthProvisioned:
description: Indicates whether an Identity Provider instance, Keycloak
or RH-SSO, has been configured to integrate with the GitHub OAuth.

View File

@ -885,6 +885,39 @@ spec:
devfileRegistryURL:
description: Public URL to the devfile registry.
type: string
devworkspaceStatus:
description: The status of the Devworkspace subsystem
properties:
gatewayHost:
description: GatewayHost is the resolved host of the ingress/route.
This is equal to the Host in the spec on Kubernetes but contains
the actual host name of the route if Host is unspecified on
OpenShift.
type: string
gatewayPhase:
description: GatewayPhase specifies the phase in which the gateway
deployment currently is. If the gateway is disabled, the phase
is "Inactive".
type: string
message:
description: Message contains further human-readable info for
why the Che cluster is in the phase it currently is.
type: string
phase:
description: Phase is the phase in which the Che cluster as a
whole finds itself in.
type: string
reason:
description: A brief CamelCase message indicating details about
why the Che cluster is in this state.
type: string
workspaceBaseDomain:
description: The resolved workspace base domain. This is either
the copy of the explicitly defined property of the same name
in the spec or, if it is undefined in the spec and we're running
on OpenShift, the automatically resolved basedomain for routes.
type: string
type: object
gitHubOAuthProvisioned:
description: Indicates whether an Identity Provider instance, Keycloak
or RH-SSO, has been configured to integrate with the GitHub OAuth.

View File

@ -898,6 +898,39 @@ spec:
devfileRegistryURL:
description: Public URL to the devfile registry.
type: string
devworkspaceStatus:
description: The status of the Devworkspace subsystem
properties:
gatewayHost:
description: GatewayHost is the resolved host of the ingress/route.
This is equal to the Host in the spec on Kubernetes but contains
the actual host name of the route if Host is unspecified on
OpenShift.
type: string
gatewayPhase:
description: GatewayPhase specifies the phase in which the gateway
deployment currently is. If the gateway is disabled, the phase
is "Inactive".
type: string
message:
description: Message contains further human-readable info for
why the Che cluster is in the phase it currently is.
type: string
phase:
description: Phase is the phase in which the Che cluster as
a whole finds itself in.
type: string
reason:
description: A brief CamelCase message indicating details about
why the Che cluster is in this state.
type: string
workspaceBaseDomain:
description: The resolved workspace base domain. This is either
the copy of the explicitly defined property of the same name
in the spec or, if it is undefined in the spec and we're running
on OpenShift, the automatically resolved basedomain for routes.
type: string
type: object
gitHubOAuthProvisioned:
description: Indicates whether an Identity Provider instance, Keycloak
or RH-SSO, has been configured to integrate with the GitHub OAuth.

1
go.mod
View File

@ -17,6 +17,7 @@ require (
k8s.io/apiextensions-apiserver v0.18.2
k8s.io/apimachinery v0.18.2
k8s.io/client-go v12.0.0+incompatible
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4
sigs.k8s.io/controller-runtime v0.6.0
sigs.k8s.io/yaml v1.2.0
)

17
go.sum
View File

@ -72,10 +72,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
@ -222,7 +220,6 @@ github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkg
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.11.1+incompatible h1:CjKsv3uWcCMvySPQYKxO8XX3f9zD4FeZRsW4G0B4ffE=
github.com/emicklei/go-restful v2.11.1+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
@ -273,13 +270,11 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
@ -291,7 +286,6 @@ github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nA
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
@ -301,7 +295,6 @@ github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.4/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
@ -509,7 +502,6 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/maorfr/helm-plugin-utils v0.0.0-20181205064038-588190cb5e3b/go.mod h1:p3gwmRSFqbWw6plBpR0sKl3n3vpu8kX70gvCJKMvvCA=
github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
@ -578,7 +570,6 @@ github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
@ -587,7 +578,6 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
@ -607,7 +597,6 @@ github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mo
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.0/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/operator-framework/api v0.0.0-20200120235816-80fd2f1a09c9 h1:HfxMEPJ0djo/RNfrmli3kI2oKS6IeuIZWu1Q5Rewt/o=
github.com/operator-framework/api v0.0.0-20200120235816-80fd2f1a09c9/go.mod h1:S5IdlJvmKkF84K2tBvsrqJbI2FVy03P88R75snpRxJo=
github.com/operator-framework/api v0.3.20 h1:2Ks8GXXl/H2sV9ll2iQBUO65ABQ5VuzN3IKEZCJWljo=
github.com/operator-framework/api v0.3.20/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q=
@ -636,7 +625,6 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -738,7 +726,6 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
@ -926,7 +913,6 @@ golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ=
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1014,7 +1000,6 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo=
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@ -1090,7 +1075,6 @@ k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65 h1:kThoiqgMsSw
k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65/go.mod h1:5BINdGqggRXXKnDgpwoJ7PyQH8f+Ypp02fvVNcIFy9s=
k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8 h1:Iieh/ZEgT3BWwbLD5qEKcY06jKuPEl6zC7gPSehoLw4=
k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ=
k8s.io/apiserver v0.0.0-20191016112112-5190913f932d h1:leksCBKKBrPJmW1jV4dZUvwqmVtXpKdzpHsqXfFS094=
k8s.io/apiserver v0.0.0-20191016112112-5190913f932d/go.mod h1:7OqfAolfWxUM/jJ/HBLyE+cdaWFBUoo5Q5pHgJVj2ws=
k8s.io/autoscaler v0.0.0-20190607113959-1b4f1855cb8e/go.mod h1:QEXezc9uKPT91dwqhSJq3GNI3B1HxFRQHiku9kmrsSA=
k8s.io/cli-runtime v0.0.0-20191016114015-74ad18325ed5/go.mod h1:sDl6WKSQkDM6zS1u9F49a0VooQ3ycYFBFLqd2jf2Xfo=
@ -1127,7 +1111,6 @@ k8s.io/kube-state-metrics v1.7.2/go.mod h1:U2Y6DRi07sS85rmVPmBFlmv+2peBcL8IWGjM+
k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51/go.mod h1:gL826ZTIfD4vXTGlmzgTbliCAT9NGiqpCqK2aNYv5MQ=
k8s.io/kubelet v0.0.0-20191016114556-7841ed97f1b2/go.mod h1:SBvrtLbuePbJygVXGGCMtWKH07+qrN2dE1iMnteSG8E=
k8s.io/kubernetes v1.16.0/go.mod h1:nlP2zevWKRGKuaaVbKIwozU0Rjg9leVDXkL4YTtjmVs=
k8s.io/kubernetes v1.16.2 h1:k0f/OVp6Yfv+UMTm6VYKhqjRgcvHh4QhN9coanjrito=
k8s.io/kubernetes v1.16.2/go.mod h1:SmhGgKfQ30imqjFVj8AI+iW+zSyFsswNErKYeTfgoH0=
k8s.io/legacy-cloud-providers v0.0.0-20191016115753-cf0698c3a16b/go.mod h1:tKW3pKqdRW8pMveUTpF5pJuCjQxg6a25iLo+Z9BXVH0=
k8s.io/metrics v0.0.0-20191016113814-3b1a734dba6e/go.mod h1:ve7/vMWeY5lEBkZf6Bt5TTbGS3b8wAxwGbdXAsufjRs=

280
pkg/apis/org/conversion.go Normal file
View File

@ -0,0 +1,280 @@
package org
import (
v1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
"github.com/eclipse-che/che-operator/pkg/apis/org/v2alpha1"
"github.com/eclipse-che/che-operator/pkg/util"
"sigs.k8s.io/yaml"
)
const (
v1StorageAnnotation = "che.eclipse.org/cheClusterV1Spec"
v2alpha1StorageAnnotation = "che.eclipse.org/cheClusterV2alpha1Spec"
routeDomainSuffixPropertyKey = "CHE_INFRA_OPENSHIFT_ROUTE_HOST_DOMAIN__SUFFIX"
defaultV2alpha1IngressClass = "nginx"
defaultV1IngressClass = "nginx"
)
func AsV1(v2 *v2alpha1.CheCluster) *v1.CheCluster {
ret := &v1.CheCluster{}
V2alpha1ToV1(v2, ret)
return ret
}
func AsV2alpha1(v1 *v1.CheCluster) *v2alpha1.CheCluster {
ret := &v2alpha1.CheCluster{}
V1ToV2alpha1(v1, ret)
return ret
}
func V1ToV2alpha1(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) error {
v2Data := v1.Annotations[v2alpha1StorageAnnotation]
v2Spec := v2alpha1.CheClusterSpec{}
if v2Data != "" {
err := yaml.Unmarshal([]byte(v2Data), &v2Spec)
if err != nil {
return err
}
}
v2.ObjectMeta = v1.ObjectMeta
v2.Spec = v2Spec
v1Spec, err := yaml.Marshal(v1.Spec)
if err != nil {
return err
}
if v2.Annotations == nil {
v2.Annotations = map[string]string{}
}
v2.Annotations[v1StorageAnnotation] = string(v1Spec)
v1ToV2alpha1_Enabled(v1, v2)
v1ToV2alpha1_Host(v1, v2)
v1ToV2alpha1_GatewayEnabled(v1, v2)
v1ToV2alpha1_GatewayImage(v1, v2)
v1ToV2alpha1_GatewayConfigurerImage(v1, v2)
v1ToV2alpha1_GatewayTlsSecretName(v1, v2)
v1ToV2alpha1_WorkspaceDomainEndpointsBaseDomain(v1, v2)
v1ToV2alpha1_WorkspaceDomainEndpointsTlsSecretName(v1, v2)
v1ToV2alpha1_K8sIngressAnnotations(v1, v2)
return nil
}
func V2alpha1ToV1(v2 *v2alpha1.CheCluster, v1Obj *v1.CheCluster) error {
v1Data := v2.Annotations[v1StorageAnnotation]
v1Spec := v1.CheClusterSpec{}
if v1Data != "" {
err := yaml.Unmarshal([]byte(v1Data), &v1Spec)
if err != nil {
return err
}
}
v1Obj.ObjectMeta = v2.ObjectMeta
v1Obj.Spec = v1Spec
v1Obj.Status = v1.CheClusterStatus{}
v2Spec, err := yaml.Marshal(v2.Spec)
if err != nil {
return err
}
if v1Obj.Annotations == nil {
v1Obj.Annotations = map[string]string{}
}
v1Obj.Annotations[v2alpha1StorageAnnotation] = string(v2Spec)
v2alpha1ToV1_Enabled(v1Obj, v2)
v2alpha1ToV1_Host(v1Obj, v2)
v2alpha1ToV1_GatewayEnabled(v1Obj, v2)
v2alpha1ToV1_GatewayImage(v1Obj, v2)
v2alpha1ToV1_GatewayConfigurerImage(v1Obj, v2)
v2alpha1ToV1_GatewayTlsSecretName(v1Obj, v2)
v2alpha1ToV1_WorkspaceDomainEndpointsBaseDomain(v1Obj, v2)
v2alpha1ToV1_WorkspaceDomainEndpointsTlsSecretName(v1Obj, v2)
v2alpha1ToV1_K8sIngressAnnotations(v1Obj, v2)
return nil
}
func v1ToV2alpha1_Enabled(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
v2.Spec.Enabled = &v1.Spec.DevWorkspace.Enable
}
func v1ToV2alpha1_Host(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
v2.Spec.Gateway.Host = v1.Spec.Server.CheHost
}
func v1ToV2alpha1_WorkspaceDomainEndpointsBaseDomain(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
if util.IsOpenShift {
v2.Spec.WorkspaceDomainEndpoints.BaseDomain = v1.Spec.Server.CustomCheProperties[routeDomainSuffixPropertyKey]
} else {
v2.Spec.WorkspaceDomainEndpoints.BaseDomain = v1.Spec.K8s.IngressDomain
}
}
func v1ToV2alpha1_WorkspaceDomainEndpointsTlsSecretName(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
// Che server always uses the default cluster certificate for subdomain workspace endpoints on OpenShift, and the K8s.TlsSecretName on K8s.
// Because we're dealing with endpoints, let's try to use the secret on Kubernetes and nothing (e.g. the default cluster cert on OpenShift)
// which is in line with the logic of the Che server.
if !util.IsOpenShift {
v2.Spec.WorkspaceDomainEndpoints.TlsSecretName = v1.Spec.K8s.TlsSecretName
}
}
func v1ToV2alpha1_GatewayEnabled(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
exposureStrategy := util.GetServerExposureStrategy(v1)
// On Kubernetes, we can have single-host realized using ingresses (that use the same host but different paths).
// This is actually not supported on DWCO where we always use the gateway for that. So here, we actually just
// ignore the Spec.K8s.SingleHostExposureType, but we need to be aware of it when converting back.
// Note that default-host is actually not supported on v2, but it is similar enough to default host that we
// treat it as such for v2. The difference between default-host and single-host is that the default-host uses
// the cluster domain itself as the base domain whereas single-host uses a configured domain. In v2 we always
// need a domain configured.
val := exposureStrategy == "single-host" || exposureStrategy == "default-host"
v2.Spec.Gateway.Enabled = &val
}
func v1ToV2alpha1_GatewayImage(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
v2.Spec.Gateway.Image = v1.Spec.Server.SingleHostGatewayImage
}
func v1ToV2alpha1_GatewayConfigurerImage(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
v2.Spec.Gateway.ConfigurerImage = v1.Spec.Server.SingleHostGatewayConfigSidecarImage
}
func v1ToV2alpha1_GatewayTlsSecretName(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
// v1.Spec.Server.CheHostTLSSecret is used specifically for Che Host - i.e. the host under which che server is deployed.
// In DW we would only used that for subpath endpoints but wouldn't know what TLS to use for subdomain endpoints.
v2.Spec.Gateway.TlsSecretName = v1.Spec.Server.CheHostTLSSecret
}
func v1ToV2alpha1_K8sIngressAnnotations(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
// The only property in v1 spec that boils down to the ingress annotations is the K8s.IngressClass
if v1.Spec.K8s.IngressClass != "" && v1.Spec.K8s.IngressClass != defaultV2alpha1IngressClass {
if v2.Spec.K8s.IngressAnnotations == nil {
v2.Spec.K8s.IngressAnnotations = map[string]string{}
}
v2.Spec.K8s.IngressAnnotations["kubernetes.io/ingress.class"] = v1.Spec.K8s.IngressClass
}
// This is what is applied in the deploy/ingress.go but I don't think it is applicable in our situation
// if ingressStrategy != "multi-host" && (component == DevfileRegistryName || component == PluginRegistryName) {
// annotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$1"
// }
}
func v2alpha1ToV1_Enabled(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
v1.Spec.DevWorkspace.Enable = v2.Spec.IsEnabled()
}
func v2alpha1ToV1_Host(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
v1.Spec.Server.CheHost = v2.Spec.Gateway.Host
}
func v2alpha1ToV1_WorkspaceDomainEndpointsBaseDomain(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
if util.IsOpenShift {
if v1.Spec.Server.CustomCheProperties == nil {
v1.Spec.Server.CustomCheProperties = map[string]string{}
}
v1.Spec.Server.CustomCheProperties[routeDomainSuffixPropertyKey] = v2.Spec.WorkspaceDomainEndpoints.BaseDomain
} else {
v1.Spec.K8s.IngressDomain = v2.Spec.WorkspaceDomainEndpoints.BaseDomain
}
}
func v2alpha1ToV1_WorkspaceDomainEndpointsTlsSecretName(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
// see the comments in the v1 to v2alpha1 conversion method
if !util.IsOpenShift {
v1.Spec.K8s.TlsSecretName = v2.Spec.WorkspaceDomainEndpoints.TlsSecretName
}
}
func v2alpha1ToV1_GatewayEnabled(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
v1Strategy := util.GetServerExposureStrategy(v1)
v1IngressStrategy := v1.Spec.K8s.IngressStrategy
var v2Strategy string
if v2.Spec.Gateway.IsEnabled() {
v2Strategy = "single-host"
} else {
v2Strategy = "multi-host"
}
if v1.Spec.Server.ServerExposureStrategy == "" {
// in the original, the server exposure strategy was undefined, so we need to check whether we can leave it that way
if util.IsOpenShift {
if v2Strategy != v1Strategy {
// only update if the v2Strategy doesn't correspond to the default determined from the v1
v1.Spec.Server.ServerExposureStrategy = v2Strategy
}
} else {
// on Kubernetes, the strategy might have been defined by the deprecated Spec.K8s.IngressStrategy
if v1IngressStrategy != "" {
// check for the default host
if v1IngressStrategy == "default-host" {
if v2Strategy != "single-host" {
v1.Spec.K8s.IngressStrategy = v2Strategy
}
} else if v2Strategy != v1Strategy {
// only change the strategy if the determined strategy would differ
v1.Spec.K8s.IngressStrategy = v2Strategy
}
} else {
if v2Strategy != v1Strategy {
// only update if the v2Strategy doesn't correspond to the default determined from the v1
v1.Spec.Server.ServerExposureStrategy = v2Strategy
}
}
}
} else {
// The below table specifies how to convert the v2Strategy back to v1 taking into the account the original state of v1
// from which v2 was converted before (which could also be just the default v1, if v2 was created on its own)
//
// v2Strategy | orig v1Strategy | orig v1ExposureType | resulting v1Strategy | resulting v1ExposureType
// ----------------------------------------------------------------------------------------------------
// single | single | native | single | orig
// single | single | gateway | single | orig
// single | default | NA | default | orig
// single | multi | NA | single | orig
// multi | single | native | multi | orig
// multi | single | gateway | multi | orig
// multi | default | NA | multi | orig
// multi | multi | NA | multi | orig
//
// Notice that we don't ever want to update the singlehost exposure type. This is only used on Kubernetes and dictates how
// we are going to expose the singlehost endpoints - either using ingresses (native) or using the gateway.
// Because this distinction is not made in DWCO, which always uses the gateway, we just keep whatever the value was originally.
//
// The default-host is actually not supported in v2... but it is quite similar to single host in that everything is exposed
// through the cluster hostname and when converting to v2, we convert it to single-host
if v1Strategy != "default-host" || v2Strategy != "single-host" {
v1.Spec.Server.ServerExposureStrategy = v2Strategy
}
}
}
func v2alpha1ToV1_GatewayImage(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
v1.Spec.Server.SingleHostGatewayImage = v2.Spec.Gateway.Image
}
func v2alpha1ToV1_GatewayConfigurerImage(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
v1.Spec.Server.SingleHostGatewayConfigSidecarImage = v2.Spec.Gateway.ConfigurerImage
}
func v2alpha1ToV1_GatewayTlsSecretName(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
// see the comments in the v1 to v2alpha1 conversion method
v1.Spec.Server.CheHostTLSSecret = v2.Spec.Gateway.TlsSecretName
}
func v2alpha1ToV1_K8sIngressAnnotations(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
ingressClass := v2.Spec.K8s.IngressAnnotations["kubernetes.io/ingress.class"]
if ingressClass == "" {
ingressClass = defaultV2alpha1IngressClass
}
if v1.Spec.K8s.IngressClass != "" || ingressClass != defaultV1IngressClass {
v1.Spec.K8s.IngressClass = ingressClass
}
}

View File

@ -0,0 +1,712 @@
package org
import (
"fmt"
"reflect"
"testing"
"github.com/che-incubator/kubernetes-image-puller-operator/pkg/apis/che/v1alpha1"
v1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
"github.com/eclipse-che/che-operator/pkg/apis/org/v2alpha1"
"github.com/eclipse-che/che-operator/pkg/util"
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
"sigs.k8s.io/yaml"
)
func TestV1ToV2alpha1(t *testing.T) {
v1Obj := v1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Name: "che-cluster",
Annotations: map[string]string{
"anno1": "annoValue1",
"anno2": "annoValue2",
},
},
Spec: v1.CheClusterSpec{
Auth: v1.CheClusterSpecAuth{
IdentityProviderURL: "kachny",
},
Database: v1.CheClusterSpecDB{
ExternalDb: true,
PostgresImage: "postgres:the-best-version",
},
DevWorkspace: v1.CheClusterSpecDevWorkspace{},
ImagePuller: v1.CheClusterSpecImagePuller{
Spec: v1alpha1.KubernetesImagePullerSpec{
ConfigMapName: "pulled-kachna",
},
},
K8s: v1.CheClusterSpecK8SOnly{
IngressDomain: "ingressDomain",
IngressClass: "traefik",
TlsSecretName: "k8sSecret",
IngressStrategy: "single-host",
},
Metrics: v1.CheClusterSpecMetrics{
Enable: true,
},
Server: v1.CheClusterSpecServer{
CheHost: "cheHost",
CheImage: "teh-che-severe",
SingleHostGatewayImage: "single-host-image-of-the-year",
CheHostTLSSecret: "cheSecret",
CustomCheProperties: map[string]string{
"CHE_INFRA_OPENSHIFT_ROUTE_HOST_DOMAIN__SUFFIX": "routeDomain",
},
},
Storage: v1.CheClusterSpecStorage{
PvcStrategy: "common",
},
},
}
t.Run("origInAnnos", func(t *testing.T) {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
anno1 := v2.Annotations["anno1"]
anno2 := v2.Annotations["anno2"]
storedV1 := v2.Annotations[v1StorageAnnotation]
if anno1 != "annoValue1" {
t.Errorf("anno1 not copied")
}
if anno2 != "annoValue2" {
t.Errorf("anno2 not copied")
}
if storedV1 == "" {
t.Errorf("v2 should contain v1 data in annnotation")
}
restoredV1Spec := v1.CheClusterSpec{}
if err = yaml.Unmarshal([]byte(storedV1), &restoredV1Spec); err != nil {
t.Error(err)
}
if !reflect.DeepEqual(&v1Obj.Spec, &restoredV1Spec) {
t.Errorf("The spec should be restored verbatim from the annotations, but there's a diff %s", cmp.Diff(&v1Obj.Spec, &restoredV1Spec))
}
})
t.Run("Enabled", func(t *testing.T) {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
if *v2.Spec.Enabled {
t.Errorf("Unexpected v2.Spec.Enabled: %s", v2.Spec.Gateway.Host)
}
})
t.Run("Host-k8s", func(t *testing.T) {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
if v2.Spec.Gateway.Host != "cheHost" {
t.Errorf("Unexpected v2.Spec.Host: %s", v2.Spec.Gateway.Host)
}
})
t.Run("WorkspaceDomainEndpointsBaseDomain-k8s", func(t *testing.T) {
onFakeKubernetes(func() {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
if v2.Spec.WorkspaceDomainEndpoints.BaseDomain != "ingressDomain" {
t.Errorf("Unexpected v2.Spec.WorkspaceDomainEndpoints.BaseDomain: %s", v2.Spec.WorkspaceDomainEndpoints.BaseDomain)
}
})
})
t.Run("WorkspaceDomainEndpointsBaseDomain-opensfhit", func(t *testing.T) {
onFakeOpenShift(func() {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
if v2.Spec.WorkspaceDomainEndpoints.BaseDomain != "routeDomain" {
t.Errorf("Unexpected v2.Spec.WorkspaceWorkspaceDomainEndpoints.BaseDomainBaseDomain: %s", v2.Spec.WorkspaceDomainEndpoints.BaseDomain)
}
})
})
t.Run("WorkspaceDomainEndpointsTlsSecretName_k8s", func(t *testing.T) {
onFakeKubernetes(func() {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
if v2.Spec.WorkspaceDomainEndpoints.TlsSecretName != "k8sSecret" {
t.Errorf("Unexpected TlsSecretName")
}
})
})
t.Run("WorkspaceDomainEndpointsTlsSecretName_OpenShift", func(t *testing.T) {
onFakeOpenShift(func() {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
if v2.Spec.WorkspaceDomainEndpoints.TlsSecretName != "" {
t.Errorf("Unexpected TlsSecretName")
}
})
})
t.Run("GatewayEnabled", func(t *testing.T) {
onFakeOpenShift(func() {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
if v2.Spec.Gateway.Enabled == nil {
t.Logf("The gateway.enabled attribute should be set explicitly after the conversion.")
t.FailNow()
}
if *v2.Spec.Gateway.Enabled {
t.Errorf("The default for OpenShift without devworkspace enabled (which is our testing object) is multihost, but we found v2 in singlehost.")
}
})
})
t.Run("GatewayImage", func(t *testing.T) {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
if v2.Spec.Gateway.Image != "single-host-image-of-the-year" {
t.Errorf("Unexpected gateway image")
}
})
t.Run("GatewayTlsSecretName", func(t *testing.T) {
v2 := &v2alpha1.CheCluster{}
err := V1ToV2alpha1(&v1Obj, v2)
if err != nil {
t.Error(err)
}
if v2.Spec.Gateway.TlsSecretName != "cheSecret" {
t.Errorf("Unexpected TlsSecretName")
}
})
}
func TestV2alpha1ToV1(t *testing.T) {
v2Obj := v2alpha1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Name: "che-cluster",
Annotations: map[string]string{
"anno1": "annoValue1",
"anno2": "annoValue2",
},
},
Spec: v2alpha1.CheClusterSpec{
Enabled: pointer.BoolPtr(true),
WorkspaceDomainEndpoints: v2alpha1.WorkspaceDomainEndpoints{
BaseDomain: "baseDomain",
TlsSecretName: "workspaceSecret",
},
Gateway: v2alpha1.CheGatewaySpec{
Host: "v2Host",
Enabled: pointer.BoolPtr(true),
Image: "gateway-image",
ConfigurerImage: "configurer-image",
TlsSecretName: "superSecret",
},
K8s: v2alpha1.CheClusterSpecK8s{
IngressAnnotations: map[string]string{
"kubernetes.io/ingress.class": "some-other-ingress",
"a": "b",
},
},
},
}
t.Run("origInAnnos", func(t *testing.T) {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
anno1 := v1.Annotations["anno1"]
anno2 := v1.Annotations["anno2"]
storedV2 := v1.Annotations[v2alpha1StorageAnnotation]
if anno1 != "annoValue1" {
t.Errorf("anno1 not copied")
}
if anno2 != "annoValue2" {
t.Errorf("anno2 not copied")
}
if storedV2 == "" {
t.Errorf("v1 should contain v2 data in annnotation")
}
restoredV2Spec := v2alpha1.CheClusterSpec{}
yaml.Unmarshal([]byte(storedV2), &restoredV2Spec)
if !reflect.DeepEqual(&v2Obj.Spec, &restoredV2Spec) {
t.Errorf("The spec should be restored verbatim from the annotations, but there's a diff %s", cmp.Diff(&v2Obj.Spec, &restoredV2Spec))
}
})
t.Run("Enabled", func(t *testing.T) {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
if !v1.Spec.DevWorkspace.Enable {
t.Errorf("Unexpected v1.Spec.DevWorkspace.Enable: %v", v1.Spec.DevWorkspace.Enable)
}
})
t.Run("Host", func(t *testing.T) {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
if v1.Spec.Server.CheHost != "v2Host" {
t.Errorf("Unexpected v1.Spec.Server.CheHost: %s", v1.Spec.Server.CheHost)
}
})
t.Run("WorkspaceDomainEndpointsBaseDomain-k8s", func(t *testing.T) {
onFakeKubernetes(func() {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
if v1.Spec.K8s.IngressDomain != "baseDomain" {
t.Errorf("Unexpected v1.Spec.K8s.IngressDomain: %s", v1.Spec.K8s.IngressDomain)
}
})
})
t.Run("WorkspaceDomainEndpointsBaseDomain-openshift", func(t *testing.T) {
onFakeOpenShift(func() {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
if v1.Spec.Server.CustomCheProperties[routeDomainSuffixPropertyKey] != "baseDomain" {
t.Errorf("Unexpected v1.Spec.Server.CustomCheProperties[%s]: %s", routeDomainSuffixPropertyKey, v1.Spec.Server.CustomCheProperties[routeDomainSuffixPropertyKey])
}
})
})
t.Run("WorkspaceDomainEndpointsTlsSecretName_k8s", func(t *testing.T) {
onFakeKubernetes(func() {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
if v1.Spec.K8s.TlsSecretName != "workspaceSecret" {
t.Errorf("Unexpected TlsSecretName: %s", v1.Spec.K8s.TlsSecretName)
}
})
})
t.Run("WorkspaceDomainEndpointsTlsSecretName_OpenShift", func(t *testing.T) {
onFakeOpenShift(func() {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
if v1.Spec.K8s.TlsSecretName != "" {
t.Errorf("Unexpected TlsSecretName")
}
})
})
t.Run("GatewayEnabled", func(t *testing.T) {
onFakeOpenShift(func() {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
if util.GetServerExposureStrategy(v1) != "single-host" {
t.Logf("When gateway.enabled is true in v2, v1 is single-host.")
t.FailNow()
}
})
})
t.Run("GatewayImage", func(t *testing.T) {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
if v1.Spec.Server.SingleHostGatewayImage != "gateway-image" {
t.Errorf("Unexpected gateway image")
}
})
t.Run("GatewayTlsSecretName", func(t *testing.T) {
v1 := &v1.CheCluster{}
err := V2alpha1ToV1(&v2Obj, v1)
if err != nil {
t.Error(err)
}
if v1.Spec.Server.CheHostTLSSecret != "superSecret" {
t.Errorf("Unexpected TlsSecretName: %s", v1.Spec.Server.CheHostTLSSecret)
}
})
}
func TestExposureStrategyConversions(t *testing.T) {
testWithExposure := func(v1ExposureStrategy string, v1IngressStrategy string, v1DevWorkspaceEnabled bool, v2GatewayEnabledChange *bool, test func(*testing.T, *v1.CheCluster)) {
origV1 := &v1.CheCluster{
Spec: v1.CheClusterSpec{
Server: v1.CheClusterSpecServer{
ServerExposureStrategy: v1ExposureStrategy,
},
K8s: v1.CheClusterSpecK8SOnly{
IngressStrategy: v1IngressStrategy,
},
DevWorkspace: v1.CheClusterSpecDevWorkspace{
Enable: v1DevWorkspaceEnabled,
},
},
}
t.Run(fmt.Sprintf("[v1ExposureStrategy=%v/v1IngressStrategy=%v/v1DevworkspaceEnabled=%v/v2GatewayEnabledChange=%v]", v1ExposureStrategy, v1IngressStrategy, v1DevWorkspaceEnabled, v2GatewayEnabledChange), func(t *testing.T) {
v2 := &v2alpha1.CheCluster{}
if err := V1ToV2alpha1(origV1, v2); err != nil {
t.Error(err)
}
if v2GatewayEnabledChange != nil {
v2.Spec.Gateway.Enabled = v2GatewayEnabledChange
}
// now convert back and run the test
v1Tested := &v1.CheCluster{}
if err := V2alpha1ToV1(v2, v1Tested); err != nil {
t.Error(err)
}
test(t, v1Tested)
})
}
testWithExposure("single-host", "", true, nil, func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "single-host" {
t.Errorf("The v1 should have single-host exposure after conversion")
}
})
testWithExposure("single-host", "", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "multi-host" {
t.Errorf("The v1 should have multi-host exposure after conversion")
}
})
testWithExposure("multi-host", "", true, nil, func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "multi-host" {
t.Errorf("The v1 should have multi-host exposure after conversion")
}
})
testWithExposure("multi-host", "", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "single-host" {
t.Errorf("The v1 should have single-host exposure after conversion")
}
})
testWithExposure("default-host", "", true, nil, func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "default-host" {
t.Errorf("The v1 should have default-host exposure after conversion")
}
})
testWithExposure("default-host", "", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "default-host" {
t.Errorf("The v1 should have default-host exposure after conversion")
}
})
testWithExposure("default-host", "", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "multi-host" {
t.Errorf("The v1 should have multi-host exposure after conversion")
}
})
onFakeKubernetes(func() {
testWithExposure("", "single-host", true, nil, func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
if old.Spec.K8s.IngressStrategy != "single-host" {
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
}
})
testWithExposure("", "single-host", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
if old.Spec.K8s.IngressStrategy != "multi-host" {
t.Errorf("The ingress strategy should have been set to multi-host after conversion but was: %v", old.Spec.K8s.IngressStrategy)
}
})
testWithExposure("", "single-host", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
if old.Spec.K8s.IngressStrategy != "single-host" {
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
}
})
testWithExposure("", "multi-host", true, nil, func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
if old.Spec.K8s.IngressStrategy != "multi-host" {
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
}
})
// the below two tests test that we're leaving the ingress strategy unchanged if it doesn't affect the effective exposure
// strategy
testWithExposure("", "multi-host", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
if old.Spec.K8s.IngressStrategy != "multi-host" {
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
}
})
testWithExposure("", "multi-host", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
if old.Spec.K8s.IngressStrategy != "multi-host" {
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
}
})
testWithExposure("", "default-host", true, nil, func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
if old.Spec.K8s.IngressStrategy != "default-host" {
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
}
})
})
onFakeOpenShift(func() {
testWithExposure("", "", true, nil, func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
})
testWithExposure("", "", false, nil, func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
})
testWithExposure("", "", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
// default on openshift with devworkspace enabled in v1 is single-host, but we've disabled the gateway in v2. So after the conversion
// v1 should change to an explicit multi-host.
if old.Spec.Server.ServerExposureStrategy != "multi-host" {
t.Errorf("The server exposure strategy should have been set to multi-host after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
})
testWithExposure("", "", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
if old.Spec.Server.ServerExposureStrategy != "" {
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
}
})
})
}
func TestFullCircleV1(t *testing.T) {
v1Obj := v1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Name: "che-cluster",
Annotations: map[string]string{
"anno1": "annoValue1",
"anno2": "annoValue2",
},
},
Spec: v1.CheClusterSpec{
Auth: v1.CheClusterSpecAuth{
IdentityProviderURL: "kachny",
},
Database: v1.CheClusterSpecDB{
ExternalDb: true,
PostgresImage: "postgres:the-best-version",
},
DevWorkspace: v1.CheClusterSpecDevWorkspace{},
ImagePuller: v1.CheClusterSpecImagePuller{
Spec: v1alpha1.KubernetesImagePullerSpec{
ConfigMapName: "pulled-kachna",
},
},
K8s: v1.CheClusterSpecK8SOnly{
IngressDomain: "ingressDomain",
IngressClass: "traefik",
TlsSecretName: "k8sSecret",
IngressStrategy: "single-host",
},
Metrics: v1.CheClusterSpecMetrics{
Enable: true,
},
Server: v1.CheClusterSpecServer{
CheHost: "cheHost",
CheImage: "teh-che-severe",
SingleHostGatewayImage: "single-host-image-of-the-year",
CheHostTLSSecret: "cheSecret",
CustomCheProperties: map[string]string{
"CHE_INFRA_OPENSHIFT_ROUTE_HOST_DOMAIN__SUFFIX": "routeDomain",
},
},
Storage: v1.CheClusterSpecStorage{
PvcStrategy: "common",
},
},
}
v2Obj := v2alpha1.CheCluster{}
V1ToV2alpha1(&v1Obj, &v2Obj)
convertedV1 := v1.CheCluster{}
V2alpha1ToV1(&v2Obj, &convertedV1)
if !reflect.DeepEqual(&v1Obj, &convertedV1) {
t.Errorf("V1 not equal to itself after the conversion through v2alpha1: %v", cmp.Diff(&v1Obj, &convertedV1))
}
}
func TestFullCircleV2(t *testing.T) {
v2Obj := v2alpha1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Name: "che-cluster",
Annotations: map[string]string{
"anno1": "annoValue1",
"anno2": "annoValue2",
},
},
Spec: v2alpha1.CheClusterSpec{
Enabled: pointer.BoolPtr(true),
WorkspaceDomainEndpoints: v2alpha1.WorkspaceDomainEndpoints{
BaseDomain: "baseDomain",
TlsSecretName: "workspaceSecret",
},
Gateway: v2alpha1.CheGatewaySpec{
Host: "v2Host",
Enabled: pointer.BoolPtr(true),
Image: "gateway-image",
ConfigurerImage: "configurer-image",
TlsSecretName: "superSecret",
},
K8s: v2alpha1.CheClusterSpecK8s{
IngressAnnotations: map[string]string{
"kubernetes.io/ingress.class": "some-other-ingress",
"a": "b",
},
},
},
}
v1Obj := v1.CheCluster{}
V2alpha1ToV1(&v2Obj, &v1Obj)
convertedV2 := v2alpha1.CheCluster{}
V1ToV2alpha1(&v1Obj, &convertedV2)
if !reflect.DeepEqual(&v2Obj, &convertedV2) {
t.Errorf("V2alpha1 not equal to itself after the conversion through v1: %v", cmp.Diff(&v2Obj, &convertedV2))
}
}
func onFakeOpenShift(f func()) {
origOpenshift := util.IsOpenShift
origOpenshift4 := util.IsOpenShift4
util.IsOpenShift = true
util.IsOpenShift4 = true
f()
util.IsOpenShift = origOpenshift
util.IsOpenShift4 = origOpenshift4
}
func onFakeKubernetes(f func()) {
origOpenshift := util.IsOpenShift
origOpenshift4 := util.IsOpenShift4
util.IsOpenShift = false
util.IsOpenShift4 = false
f()
util.IsOpenShift = origOpenshift
util.IsOpenShift4 = origOpenshift4
}
func toString(b *bool) string {
if b == nil {
return "nil"
} else if *b {
return "true"
} else {
return "false"
}
}

View File

@ -20,6 +20,7 @@ package v1
import (
chev1alpha1 "github.com/che-incubator/kubernetes-image-puller-operator/pkg/apis/che/v1alpha1"
"github.com/eclipse-che/che-operator/pkg/apis/org/v2alpha1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
@ -671,6 +672,10 @@ type CheClusterStatus struct {
// +operator-sdk:gen-csv:customresourcedefinitions.statusDescriptors.displayName="Help link"
// +operator-sdk:gen-csv:customresourcedefinitions.statusDescriptors.x-descriptors="urn:alm:descriptor:org.w3:link"
HelpLink string `json:"helpLink,omitempty"`
// The status of the Devworkspace subsystem
// +optional
DevworkspaceStatus v2alpha1.CheClusterStatus `json:"devworkspaceStatus,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@ -679,6 +684,7 @@ type CheClusterStatus struct {
// +k8s:openapi-gen=true
// +kubebuilder:subresource:status
// +operator-sdk:gen-csv:customresourcedefinitions.displayName="Eclipse Che Cluster"
// +kubebuilder:storageversion
type CheCluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

View File

@ -265,6 +265,7 @@ func (in *CheClusterSpecStorage) DeepCopy() *CheClusterSpecStorage {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CheClusterStatus) DeepCopyInto(out *CheClusterStatus) {
*out = *in
out.DevworkspaceStatus = in.DevworkspaceStatus
return
}

View File

@ -0,0 +1,203 @@
//
// Copyright (c) 2012-2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package v2alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE THAT THIS IS CURRENTLY INTENTIONALLY NOT PART OF THE GENERATED API
//
// (the generator comments are switched off by using a '\' instead of a '+')
//
// This is so that we can start using this spec in the code before we are
// actually ready to start deploying it in the cluster.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CheClusterSpec holds the configuration of the Che controller.
// \k8s:openapi-gen=true
type CheClusterSpec struct {
// If false, Che is disabled and does not resolve the devworkspaces with the che routingClass.
Enabled *bool `json:"enabled,omitempty"`
// Configuration of the workspace endpoints that are exposed on separate domains, as opposed to the subpaths
// of the gateway.
WorkspaceDomainEndpoints `json:"workspaceDomainEndpoints,omitempty"`
// Gateway contains the configuration of the gateway used for workspace endpoint routing.
Gateway CheGatewaySpec `json:"gateway,omitempty"`
// K8s contains the configuration specific only to Kubernetes
K8s CheClusterSpecK8s `json:"k8s,omitempty"`
}
type WorkspaceDomainEndpoints struct {
// The workspace endpoints that need to be deployed on a subdomain will be deployed on subdomains of this base domain.
// This is mandatory on Kubernetes. On OpenShift, an attempt is made to automatically figure out the base domain of
// the routes. The resolved value of this property is written to the status.
BaseDomain string `json:"baseDomain,omitempty"`
// Name of a secret that will be used to setup ingress/route TLS certificate for the workspace endpoints. The endpoints
// will be on randomly named subdomains of the `BaseDomain` and therefore the TLS certificate should a wildcard certificate.
//
// When the field is empty string, the endpoints are served over unecrypted HTTP. This might be OK because the workspace endpoints
// generally only expose applications in debugging sessions during development.
//
// The secret is assumed to exist in the same namespace as the CheCluster CR is copied to the namespace of the devworkspace on
// devworkspace start (so that the ingresses on Kubernetes can reference it).
//
// The secret has to be of type "tls".
//
// +optional
TlsSecretName string `json:"tlsSecretName,omitempty"`
}
type CheGatewaySpec struct {
// Enabled enables or disables routing of the url rewrite supporting devworkspace endpoints
// through a common gateway (the hostname of which is defined by the Host).
//
// Default value is "true" meaning that the gateway is enabled.
//
// If set to true (i.e. the gateway is enabled), endpoints marked using the "urlRewriteSupported" attribute
// are exposed on unique subpaths of the Host, while the rest of the devworkspace endpoints are exposed
// on subdomains of the Host.
//
// If set to false (i.e. the gateway is disabled), all endpoints are deployed on subdomains of
// the Host.
Enabled *bool `json:"enabled,omitempty"`
// Host is the full host name used to expose devworkspace endpoints that support url rewriting reverse proxy.
// See the gateway.enabled attribute for a more detailed description of where and how are devworkspace endpoints
// exposed in various configurations.
//
// This attribute is mandatory on Kubernetes, optional on OpenShift.
Host string `json:"host,omitempty"`
// Name of a secret that will be used to setup ingress/route TLS certificate for the gateway host.
// When the field is empty string, the default cluster certificate will be used.
// The secret is assumed to exist in the same namespace as the CheCluster CR.
//
// The secret has to be of type "tls".
//
// +optional
TlsSecretName string `json:"tlsSecretName,omitempty"`
// Image is the docker image to use for the Che gateway. This is only used if Enabled is true.
// If not defined in the CR, it is taken from
// the `RELATED_IMAGE_gateway` environment variable of the operator deployment/pod. If not defined there,
// it defaults to a hardcoded value.
Image string `json:"image,omitempty"`
// ConfigurerImage is the docker image to use for the sidecar of the Che gateway that is
// used to configure it. This is only used when Enabled is true. If not defined in the CR,
// it is taken from the `RELATED_IMAGE_gateway_configurer` environment variable of the operator
// deployment/pod. If not defined there, it defaults to a hardcoded value.
ConfigurerImage string `json:"configurerImage,omitempty"`
}
// CheClusterSpecK8s contains the configuration options specific to Kubernetes only.
type CheClusterSpecK8s struct {
// IngressAnnotations are the annotations to be put on the generated ingresses. This can be used to
// configure the ingress class and the ingress-controller-specific behavior for both the gateway
// and the ingresses created to expose the Devworkspace component endpoints.
// When not specified, this defaults to:
//
// kubernetes.io/ingress.class: "nginx"
// nginx.ingress.kubernetes.io/proxy-read-timeout: "3600",
// nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600",
// nginx.ingress.kubernetes.io/ssl-redirect: "true"
//
// +optional
IngressAnnotations map[string]string `json:"ingressAnnotations,omitempty"`
}
// GatewayPhase describes the different phases of the Che gateway lifecycle
type GatewayPhase string
const (
GatewayPhaseInitializing = "Initializing"
GatewayPhaseEstablished = "Established"
GatewayPhaseInactive = "Inactive"
)
// ClusterPhase describes the different phases of the Che cluster lifecycle
type ClusterPhase string
const (
ClusterPhaseActive = "Active"
ClusterPhaseInactive = "Inactive"
ClusterPhasePendingDeletion = "PendingDeletion"
)
// CheClusterStatus contains the status of the CheCluster object
// \k8s:openapi-gen=true
type CheClusterStatus struct {
// GatewayPhase specifies the phase in which the gateway deployment currently is.
// If the gateway is disabled, the phase is "Inactive".
GatewayPhase GatewayPhase `json:"gatewayPhase,omitempty"`
// GatewayHost is the resolved host of the ingress/route. This is equal to the Host in the spec
// on Kubernetes but contains the actual host name of the route if Host is unspecified on OpenShift.
GatewayHost string `json:"gatewayHost,omitempty"`
// Phase is the phase in which the Che cluster as a whole finds itself in.
Phase ClusterPhase `json:"phase,omitempty"`
// A brief CamelCase message indicating details about why the Che cluster is in this state.
Reason string `json:"reason,omitempty"`
// Message contains further human-readable info for why the Che cluster is in the phase it currently is.
Message string `json:"message,omitempty"`
// The resolved workspace base domain. This is either the copy of the explicitly defined property of the
// same name in the spec or, if it is undefined in the spec and we're running on OpenShift, the automatically
// resolved basedomain for routes.
WorkspaceBaseDomain string `json:"workspaceBaseDomain,omitempty"`
}
// CheCluster is the configuration of the CheCluster layer of Devworkspace.
// \k8s:openapi-gen=true
// \kubebuilder:subresource:status
// \kubebuilder:resource:path=checlusters,scope=Namespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type CheCluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec CheClusterSpec `json:"spec,omitempty"`
Status CheClusterStatus `json:"status,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// CheClusterList is the list type for CheCluster
type CheClusterList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []CheCluster `json:"items"`
}
func init() {
SchemeBuilder.Register(&CheCluster{}, &CheClusterList{})
}
// IsEnabled is a utility method checking the `Enabled` property using its optional value or the default.
func (s *CheClusterSpec) IsEnabled() bool {
return s.Enabled == nil || *s.Enabled
}
// IsEnabled is a utility method checking the `Enabled` property using its optional value or the default.
func (s *CheGatewaySpec) IsEnabled() bool {
return s.Enabled == nil || *s.Enabled
}

View File

@ -0,0 +1,25 @@
//
// Copyright (c) 2012-2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE THAT THIS IS CURRENTLY INTENTIONALLY NOT PART OF THE GENERATED API
//
// (the generator comments are switched off by using a '\' instead of a '+')
//
// This is so that we can start using this spec in the code before we are
// actually ready to start deploying it in the cluster.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Package v2alpha1 contains API Schema definitions for the org v2alpha1 API group
// \k8s:deepcopy-gen=package,register
// \groupName=org.eclipse.che
package v2alpha1

View File

@ -0,0 +1,42 @@
//
// Copyright (c) 2012-2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
// NOTE: Boilerplate only. Ignore this file.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE THAT THIS IS CURRENTLY INTENTIONALLY NOT PART OF THE GENERATED API
//
// (the generator comments are switched off by using a '\' instead of a '+')
//
// This is so that we can start using this spec in the code before we are
// actually ready to start deploying it in the cluster.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Package v2alpha1 contains API Schema definitions for the org v2alpha1 API group
// \k8s:deepcopy-gen=package,register
// \groupName=org.eclipse.che
package v2alpha1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
// SchemeGroupVersion is group version used to register these objects
SchemeGroupVersion = schema.GroupVersion{Group: "org.eclipse.che", Version: "v2alpha1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)

View File

@ -0,0 +1,148 @@
// +build !ignore_autogenerated
// Code generated by operator-sdk. DO NOT EDIT.
package v2alpha1
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 *CheCluster) DeepCopyInto(out *CheCluster) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
out.Status = in.Status
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheCluster.
func (in *CheCluster) DeepCopy() *CheCluster {
if in == nil {
return nil
}
out := new(CheCluster)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CheCluster) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CheClusterList) DeepCopyInto(out *CheClusterList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]CheCluster, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterList.
func (in *CheClusterList) DeepCopy() *CheClusterList {
if in == nil {
return nil
}
out := new(CheClusterList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CheClusterList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CheClusterSpec) DeepCopyInto(out *CheClusterSpec) {
*out = *in
in.Gateway.DeepCopyInto(&out.Gateway)
in.K8s.DeepCopyInto(&out.K8s)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpec.
func (in *CheClusterSpec) DeepCopy() *CheClusterSpec {
if in == nil {
return nil
}
out := new(CheClusterSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CheClusterSpecK8s) DeepCopyInto(out *CheClusterSpecK8s) {
*out = *in
if in.IngressAnnotations != nil {
in, out := &in.IngressAnnotations, &out.IngressAnnotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecK8s.
func (in *CheClusterSpecK8s) DeepCopy() *CheClusterSpecK8s {
if in == nil {
return nil
}
out := new(CheClusterSpecK8s)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CheClusterStatus) DeepCopyInto(out *CheClusterStatus) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterStatus.
func (in *CheClusterStatus) DeepCopy() *CheClusterStatus {
if in == nil {
return nil
}
out := new(CheClusterStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CheGatewaySpec) DeepCopyInto(out *CheGatewaySpec) {
*out = *in
if in.Enabled != nil {
in, out := &in.Enabled, &out.Enabled
*out = new(bool)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheGatewaySpec.
func (in *CheGatewaySpec) DeepCopy() *CheGatewaySpec {
if in == nil {
return nil
}
out := new(CheGatewaySpec)
in.DeepCopyInto(out)
return out
}

1
vendor/modules.txt vendored
View File

@ -404,6 +404,7 @@ k8s.io/klog
# k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
k8s.io/kube-openapi/pkg/util/proto
# k8s.io/utils v0.0.0-20191010214722-8d271d903fe4
## explicit
k8s.io/utils/buffer
k8s.io/utils/integer
k8s.io/utils/pointer