Respect openshift cluster wide proxy (#272)
* Respect OpenShift cluster wide proxy Signed-off-by: Anatoliy Bazko <abazko@redhat.com>pull/330/head
parent
adfe698031
commit
110149a5c7
|
|
@ -50,7 +50,8 @@
|
||||||
"CONSOLE_LINK_IMAGE": "/dashboard/assets/branding/loader.svg",
|
"CONSOLE_LINK_IMAGE": "/dashboard/assets/branding/loader.svg",
|
||||||
"CHE_IDENTITY_SECRET": "che-identity-secret",
|
"CHE_IDENTITY_SECRET": "che-identity-secret",
|
||||||
"CHE_IDENTITY_POSTGRES_SECRET": "che-identity-postgres-secret",
|
"CHE_IDENTITY_POSTGRES_SECRET": "che-identity-postgres-secret",
|
||||||
"CHE_POSTGRES_SECRET": "che-postgres-secret"
|
"CHE_POSTGRES_SECRET": "che-postgres-secret",
|
||||||
|
"CHE_SERVER_TRUST_STORE_CONFIGMAP_NAME": "ca-certs"
|
||||||
},
|
},
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"args": [
|
"args": [
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,11 @@ rules:
|
||||||
resources:
|
resources:
|
||||||
- infrastructures
|
- infrastructures
|
||||||
- oauths
|
- oauths
|
||||||
|
- proxies
|
||||||
verbs:
|
verbs:
|
||||||
- get
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- user.openshift.io
|
- user.openshift.io
|
||||||
resources:
|
resources:
|
||||||
|
|
|
||||||
|
|
@ -81,3 +81,5 @@ spec:
|
||||||
value: che-identity-postgres-secret
|
value: che-identity-postgres-secret
|
||||||
- name: CHE_POSTGRES_SECRET
|
- name: CHE_POSTGRES_SECRET
|
||||||
value: che-postgres-secret
|
value: che-postgres-secret
|
||||||
|
- name: CHE_SERVER_TRUST_STORE_CONFIGMAP_NAME
|
||||||
|
value: ca-certs
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,8 @@ spec:
|
||||||
value: che-identity-postgres-secret
|
value: che-identity-postgres-secret
|
||||||
- name: CHE_POSTGRES_SECRET
|
- name: CHE_POSTGRES_SECRET
|
||||||
value: che-postgres-secret
|
value: che-postgres-secret
|
||||||
|
- name: CHE_SERVER_TRUST_STORE_CONFIGMAP_NAME
|
||||||
|
value: ca-certs
|
||||||
restartPolicy: Always
|
restartPolicy: Always
|
||||||
serviceAccountName: che-operator
|
serviceAccountName: che-operator
|
||||||
terminationGracePeriodSeconds: 5
|
terminationGracePeriodSeconds: 5
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,548 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012-2020 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
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: checlusters.org.eclipse.che
|
||||||
|
spec:
|
||||||
|
group: org.eclipse.che
|
||||||
|
names:
|
||||||
|
kind: CheCluster
|
||||||
|
listKind: CheClusterList
|
||||||
|
plural: checlusters
|
||||||
|
singular: checluster
|
||||||
|
scope: Namespaced
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
validation:
|
||||||
|
openAPIV3Schema:
|
||||||
|
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/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/api-conventions.md#types-kinds'
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: Desired configuration of the Che installation. Based on these
|
||||||
|
settings, the operator automatically creates and maintains several config
|
||||||
|
maps that will contain the appropriate environment variables the various
|
||||||
|
components of the Che installation. These generated config maps should
|
||||||
|
NOT be updated manually.
|
||||||
|
properties:
|
||||||
|
auth:
|
||||||
|
description: Configuration settings related to the Authentication used
|
||||||
|
by the Che installation.
|
||||||
|
properties:
|
||||||
|
externalIdentityProvider:
|
||||||
|
description: 'Instructs the operator on whether or not to deploy
|
||||||
|
a dedicated Identity Provider (Keycloak or RH SSO instance). By
|
||||||
|
default a dedicated Identity Provider server is deployed as part
|
||||||
|
of the Che installation. But if `externalIdentityProvider` is
|
||||||
|
`true`, then no dedicated identity provider will be deployed by
|
||||||
|
the operator and you might need to provide details about the external
|
||||||
|
identity provider you want to use. See also all the other fields
|
||||||
|
starting with: `identityProvider`.'
|
||||||
|
type: boolean
|
||||||
|
identityProviderAdminUserName:
|
||||||
|
description: Overrides the name of the Identity Provider admin user.
|
||||||
|
Defaults to `admin`.
|
||||||
|
type: string
|
||||||
|
identityProviderClientId:
|
||||||
|
description: Name of a Identity provider (Keycloak / RH SSO) `client-id`
|
||||||
|
that should be used for Che. This is useful to override it ONLY
|
||||||
|
if you use an external Identity Provider (see the `externalIdentityProvider`
|
||||||
|
field). If omitted or left blank, it will be set to the value
|
||||||
|
of the `flavour` field suffixed with `-public`.
|
||||||
|
type: string
|
||||||
|
identityProviderImage:
|
||||||
|
description: Overrides the container image used in the Identity
|
||||||
|
Provider (Keycloak / RH SSO) deployment. This includes the image
|
||||||
|
tag. Omit it or leave it empty to use the defaut container image
|
||||||
|
provided by the operator.
|
||||||
|
type: string
|
||||||
|
identityProviderImagePullPolicy:
|
||||||
|
description: Overrides the image pull policy used in the Identity
|
||||||
|
Provider (Keycloak / RH SSO) deployment. Default value is `Always`
|
||||||
|
for `nightly` or `latest` images, and `IfNotPresent` in other
|
||||||
|
cases.
|
||||||
|
type: string
|
||||||
|
identityProviderPassword:
|
||||||
|
description: Overrides the password of Keycloak admin user. This
|
||||||
|
is useful to override it ONLY if you use an external Identity
|
||||||
|
Provider (see the `externalIdentityProvider` field). If omitted
|
||||||
|
or left blank, it will be set to an auto-generated password.
|
||||||
|
type: string
|
||||||
|
identityProviderPostgresPassword:
|
||||||
|
description: Password for The Identity Provider (Keycloak / RH SSO)
|
||||||
|
to connect to the database. This is useful to override it ONLY
|
||||||
|
if you use an external Identity Provider (see the `externalIdentityProvider`
|
||||||
|
field). If omitted or left blank, it will be set to an auto-generated
|
||||||
|
password.
|
||||||
|
type: string
|
||||||
|
identityProviderPostgresSecret:
|
||||||
|
description: 'The secret that contains `password` for The Identity
|
||||||
|
Provider (Keycloak / RH SSO) to connect to the database. If the
|
||||||
|
secret is defined then `identityProviderPostgresPassword` will
|
||||||
|
be ignored. If the value is omitted or left blank then there are
|
||||||
|
two scenarios: 1. `identityProviderPostgresPassword` is defined,
|
||||||
|
then it will be used to connect to the database. 2. `identityProviderPostgresPassword`
|
||||||
|
is not defined, then a new secret with the name `che-identity-postgres-secret`
|
||||||
|
will be created with an auto-generated value for `password`.'
|
||||||
|
type: string
|
||||||
|
identityProviderRealm:
|
||||||
|
description: Name of a Identity provider (Keycloak / RH SSO) realm
|
||||||
|
that should be used for Che. This is useful to override it ONLY
|
||||||
|
if you use an external Identity Provider (see the `externalIdentityProvider`
|
||||||
|
field). If omitted or left blank, it will be set to the value
|
||||||
|
of the `flavour` field.
|
||||||
|
type: string
|
||||||
|
identityProviderSecret:
|
||||||
|
description: 'The secret that contains `user` and `password` for
|
||||||
|
Identity Provider. If the secret is defined then `identityProviderAdminUserName`
|
||||||
|
and `identityProviderPassword` are ignored. If the value is omitted
|
||||||
|
or left blank then there are two scenarios: 1. `identityProviderAdminUserName`
|
||||||
|
and `identityProviderPassword` are defined, then they will be
|
||||||
|
used. 2. `identityProviderAdminUserName` or `identityProviderPassword`
|
||||||
|
are not defined, then a new secret with the name `che-identity-secret`
|
||||||
|
will be created with default value `admin` for `user` and with
|
||||||
|
an auto-generated value for `password`.'
|
||||||
|
type: string
|
||||||
|
identityProviderURL:
|
||||||
|
description: Public URL of the Identity Provider server (Keycloak
|
||||||
|
/ RH SSO server). You should set it ONLY if you use an external
|
||||||
|
Identity Provider (see the `externalIdentityProvider` field).
|
||||||
|
By default this will be automatically calculated and set by the
|
||||||
|
operator.
|
||||||
|
type: string
|
||||||
|
oAuthClientName:
|
||||||
|
description: Name of the OpenShift `OAuthClient` resource used to
|
||||||
|
setup identity federation on the OpenShift side. Auto-generated
|
||||||
|
if left blank. See also the `OpenShiftoAuth` field.
|
||||||
|
type: string
|
||||||
|
oAuthSecret:
|
||||||
|
description: Name of the secret set in the OpenShift `OAuthClient`
|
||||||
|
resource used to setup identity federation on the OpenShift side.
|
||||||
|
Auto-generated if left blank. See also the `OAuthClientName` field.
|
||||||
|
type: string
|
||||||
|
openShiftoAuth:
|
||||||
|
description: 'Enables the integration of the identity provider (Keycloak
|
||||||
|
/ RHSSO) with OpenShift OAuth. Enabled by default on OpenShift.
|
||||||
|
This will allow users to directly login with their Openshift user
|
||||||
|
through the Openshift login, and have their workspaces created
|
||||||
|
under personal OpenShift namespaces. WARNING: the `kubeadmin`
|
||||||
|
user is NOT supported, and logging through it will NOT allow accessing
|
||||||
|
the Che Dashboard.'
|
||||||
|
type: boolean
|
||||||
|
updateAdminPassword:
|
||||||
|
description: Forces the default `admin` Che user to update password
|
||||||
|
on first login. Defaults to `false`.
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
database:
|
||||||
|
description: Configuration settings related to the database used by
|
||||||
|
the Che installation.
|
||||||
|
properties:
|
||||||
|
chePostgresDb:
|
||||||
|
description: Postgres database name that the Che server uses to
|
||||||
|
connect to the DB. Defaults to `dbche`.
|
||||||
|
type: string
|
||||||
|
chePostgresHostName:
|
||||||
|
description: Postgres Database hostname that the Che server uses
|
||||||
|
to connect to. Defaults to postgres. This value should be overridden
|
||||||
|
ONLY when using an external database (see field `externalDb`).
|
||||||
|
In the default case it will be automatically set by the operator.
|
||||||
|
type: string
|
||||||
|
chePostgresPassword:
|
||||||
|
description: Postgres password that the Che server should use to
|
||||||
|
connect to the DB. If omitted or left blank, it will be set to
|
||||||
|
an auto-generated value.
|
||||||
|
type: string
|
||||||
|
chePostgresPort:
|
||||||
|
description: Postgres Database port that the Che server uses to
|
||||||
|
connect to. Defaults to 5432. This value should be overridden
|
||||||
|
ONLY when using an external database (see field `externalDb`).
|
||||||
|
In the default case it will be automatically set by the operator.
|
||||||
|
type: string
|
||||||
|
chePostgresSecret:
|
||||||
|
description: 'The secret that contains Postgres `user` and `password`
|
||||||
|
that the Che server should use to connect to the DB. If the secret
|
||||||
|
is defined then `chePostgresUser` and `chePostgresPassword` are
|
||||||
|
ignored. If the value is omitted or left blank then there are
|
||||||
|
two scenarios: 1. `chePostgresUser` and `chePostgresPassword`
|
||||||
|
are defined, then they will be used to connect to the DB. 2. `chePostgresUser`
|
||||||
|
or `chePostgresPassword` are not defined, then a new secret with
|
||||||
|
the name `che-postgres-secret` will be created with default value
|
||||||
|
of `pgche` for `user` and with an auto-generated value for `password`.'
|
||||||
|
type: string
|
||||||
|
chePostgresUser:
|
||||||
|
description: Postgres user that the Che server should use to connect
|
||||||
|
to the DB. Defaults to `pgche`.
|
||||||
|
type: string
|
||||||
|
externalDb:
|
||||||
|
description: 'Instructs the operator on whether or not to deploy
|
||||||
|
a dedicated database. By default a dedicated Postgres database
|
||||||
|
is deployed as part of the Che installation. But if `externalDb`
|
||||||
|
is `true`, then no dedicated database will be deployed by the
|
||||||
|
operator and you might need to provide connection details to the
|
||||||
|
external DB you want to use. See also all the fields starting
|
||||||
|
with: `chePostgres`.'
|
||||||
|
type: boolean
|
||||||
|
postgresImage:
|
||||||
|
description: Overrides the container image used in the Postgres
|
||||||
|
database deployment. This includes the image tag. Omit it or leave
|
||||||
|
it empty to use the defaut container image provided by the operator.
|
||||||
|
type: string
|
||||||
|
postgresImagePullPolicy:
|
||||||
|
description: Overrides the image pull policy used in the Postgres
|
||||||
|
database deployment. Default value is `Always` for `nightly` or
|
||||||
|
`latest` images, and `IfNotPresent` in other cases.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
k8s:
|
||||||
|
description: Configuration settings specific to Che installations made
|
||||||
|
on upstream Kubernetes.
|
||||||
|
properties:
|
||||||
|
ingressClass:
|
||||||
|
description: 'Ingress class that will define the which controler
|
||||||
|
will manage ingresses. Defaults to `nginx`. NB: This drives the
|
||||||
|
`is kubernetes.io/ingress.class` annotation on Che-related ingresses.'
|
||||||
|
type: string
|
||||||
|
ingressDomain:
|
||||||
|
description: 'Global ingress domain for a K8S cluster. This MUST
|
||||||
|
be explicitly specified: there are no defaults.'
|
||||||
|
type: string
|
||||||
|
ingressStrategy:
|
||||||
|
description: Strategy for ingress creation. This can be `multi-host`
|
||||||
|
(host is explicitly provided in ingress), `single-host` (host
|
||||||
|
is provided, path-based rules) and `default-host.*`(no host is
|
||||||
|
provided, path-based rules). Defaults to `"multi-host`
|
||||||
|
type: string
|
||||||
|
securityContextFsGroup:
|
||||||
|
description: FSGroup the Che pod and Workspace pods containers should
|
||||||
|
run in. Defaults to `1724`.
|
||||||
|
type: string
|
||||||
|
securityContextRunAsUser:
|
||||||
|
description: ID of the user the Che pod and Workspace pods containers
|
||||||
|
should run as. Default to `1724`.
|
||||||
|
type: string
|
||||||
|
tlsSecretName:
|
||||||
|
description: Name of a secret that will be used to setup ingress
|
||||||
|
TLS termination if TLS is enabled. See also the `tlsSupport` field.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
metrics:
|
||||||
|
description: Configuration settings related to the metrics collection
|
||||||
|
used by the Che installation.
|
||||||
|
properties:
|
||||||
|
enable:
|
||||||
|
description: Enables `metrics` Che server endpoint. Default to `true`.
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
server:
|
||||||
|
description: General configuration settings related to the Che server
|
||||||
|
and the plugin and devfile registries
|
||||||
|
properties:
|
||||||
|
airGapContainerRegistryHostname:
|
||||||
|
description: Optional hostname (or url) to an alternate container
|
||||||
|
registry to pull images from. This value overrides the container
|
||||||
|
registry hostname defined in all the default container images
|
||||||
|
involved in a Che deployment. This is particularly useful to install
|
||||||
|
Che in an air-gapped environment.
|
||||||
|
type: string
|
||||||
|
airGapContainerRegistryOrganization:
|
||||||
|
description: Optional repository name of an alternate container
|
||||||
|
registry to pull images from. This value overrides the container
|
||||||
|
registry organization defined in all the default container images
|
||||||
|
involved in a Che deployment. This is particularly useful to install
|
||||||
|
Che in an air-gapped environment.
|
||||||
|
type: string
|
||||||
|
allowUserDefinedWorkspaceNamespaces:
|
||||||
|
description: Defines if a user is able to specify Kubernetes namespace
|
||||||
|
(or OpenShift project) different from the default. It's NOT RECOMMENDED
|
||||||
|
to configured true without OAuth configured. This property is
|
||||||
|
also used by the OpenShift infra.
|
||||||
|
type: boolean
|
||||||
|
cheDebug:
|
||||||
|
description: Enables the debug mode for Che server. Defaults to
|
||||||
|
`false`.
|
||||||
|
type: string
|
||||||
|
cheFlavor:
|
||||||
|
description: Flavor of the installation. This is either `che` for
|
||||||
|
upstream Che installations, or `codeready` for CodeReady Workspaces
|
||||||
|
installation. In most cases the default value should not be overriden.
|
||||||
|
type: string
|
||||||
|
cheHost:
|
||||||
|
description: Public hostname of the installed Che server. This will
|
||||||
|
be automatically set by the operator. In most cases the default
|
||||||
|
value set by the operator should not be overriden.
|
||||||
|
type: string
|
||||||
|
cheImage:
|
||||||
|
description: Overrides the container image used in Che deployment.
|
||||||
|
This does NOT include the container image tag. Omit it or leave
|
||||||
|
it empty to use the defaut container image provided by the operator.
|
||||||
|
type: string
|
||||||
|
cheImagePullPolicy:
|
||||||
|
description: Overrides the image pull policy used in Che deployment.
|
||||||
|
Default value is `Always` for `nightly` or `latest` images, and
|
||||||
|
`IfNotPresent` in other cases.
|
||||||
|
type: string
|
||||||
|
cheImageTag:
|
||||||
|
description: Overrides the tag of the container image used in Che
|
||||||
|
deployment. Omit it or leave it empty to use the defaut image
|
||||||
|
tag provided by the operator.
|
||||||
|
type: string
|
||||||
|
cheLogLevel:
|
||||||
|
description: 'Log level for the Che server: `INFO` or `DEBUG`. Defaults
|
||||||
|
to `INFO`.'
|
||||||
|
type: string
|
||||||
|
cheWorkspaceClusterRole:
|
||||||
|
description: Custom cluster role bound to the user for the Che workspaces.
|
||||||
|
The default roles are used if this is omitted or left blank.
|
||||||
|
type: string
|
||||||
|
customCheProperties:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Map of additional environment variables that will be
|
||||||
|
applied in the generated `che` config map to be used by the Che
|
||||||
|
server, in addition to the values already generated from other
|
||||||
|
fields of the `CheCluster` custom resource (CR). If `customCheProperties`
|
||||||
|
contains a property that would be normally generated in `che`
|
||||||
|
config map from other CR fields, then the value defined in the
|
||||||
|
`customCheProperties` will be used instead.
|
||||||
|
type: object
|
||||||
|
devfileRegistryImage:
|
||||||
|
description: Overrides the container image used in the Devfile registry
|
||||||
|
deployment. This includes the image tag. Omit it or leave it empty
|
||||||
|
to use the defaut container image provided by the operator.
|
||||||
|
type: string
|
||||||
|
devfileRegistryMemoryLimit:
|
||||||
|
description: Overrides the memory limit used in the Devfile registry
|
||||||
|
deployment. Defaults to 256Mi.
|
||||||
|
type: string
|
||||||
|
devfileRegistryMemoryRequest:
|
||||||
|
description: Overrides the memory request used in the Devfile registry
|
||||||
|
deployment. Defaults to 16Mi.
|
||||||
|
type: string
|
||||||
|
devfileRegistryPullPolicy:
|
||||||
|
description: Overrides the image pull policy used in the Devfile
|
||||||
|
registry deployment. Default value is `Always` for `nightly` or
|
||||||
|
`latest` images, and `IfNotPresent` in other cases.
|
||||||
|
type: string
|
||||||
|
devfileRegistryUrl:
|
||||||
|
description: Public URL of the Devfile registry, that serves sample,
|
||||||
|
ready-to-use devfiles. You should set it ONLY if you use an external
|
||||||
|
devfile registry (see the `externalDevfileRegistry` field). By
|
||||||
|
default this will be automatically calculated by the operator.
|
||||||
|
type: string
|
||||||
|
externalDevfileRegistry:
|
||||||
|
description: Instructs the operator on whether or not to deploy
|
||||||
|
a dedicated Devfile registry server. By default a dedicated devfile
|
||||||
|
registry server is started. But if `externalDevfileRegistry` is
|
||||||
|
`true`, then no such dedicated server will be started by the operator
|
||||||
|
and you will have to manually set the `devfileRegistryUrl` field
|
||||||
|
type: boolean
|
||||||
|
externalPluginRegistry:
|
||||||
|
description: Instructs the operator on whether or not to deploy
|
||||||
|
a dedicated Plugin registry server. By default a dedicated plugin
|
||||||
|
registry server is started. But if `externalPluginRegistry` is
|
||||||
|
`true`, then no such dedicated server will be started by the operator
|
||||||
|
and you will have to manually set the `pluginRegistryUrl` field.
|
||||||
|
type: boolean
|
||||||
|
gitSelfSignedCert:
|
||||||
|
description: If enabled, then the certificate from `che-git-self-signed-cert`
|
||||||
|
config map will be propagated to the Che components and provide
|
||||||
|
particular configuration for Git.
|
||||||
|
type: boolean
|
||||||
|
nonProxyHosts:
|
||||||
|
description: List of hosts that should not use the configured proxy.
|
||||||
|
Use `|`` as delimiter, eg `localhost|my.host.com|123.42.12.32`
|
||||||
|
Only use when configuring a proxy is required (see also the `proxyURL`
|
||||||
|
field).
|
||||||
|
type: string
|
||||||
|
pluginRegistryImage:
|
||||||
|
description: Overrides the container image used in the Plugin registry
|
||||||
|
deployment. This includes the image tag. Omit it or leave it empty
|
||||||
|
to use the defaut container image provided by the operator.
|
||||||
|
type: string
|
||||||
|
pluginRegistryMemoryLimit:
|
||||||
|
description: Overrides the memory limit used in the Plugin registry
|
||||||
|
deployment. Defaults to 256Mi.
|
||||||
|
type: string
|
||||||
|
pluginRegistryMemoryRequest:
|
||||||
|
description: Overrides the memory request used in the Plugin registry
|
||||||
|
deployment. Defaults to 16Mi.
|
||||||
|
type: string
|
||||||
|
pluginRegistryPullPolicy:
|
||||||
|
description: Overrides the image pull policy used in the Plugin
|
||||||
|
registry deployment. Default value is `Always` for `nightly` or
|
||||||
|
`latest` images, and `IfNotPresent` in other cases.
|
||||||
|
type: string
|
||||||
|
pluginRegistryUrl:
|
||||||
|
description: Public URL of the Plugin registry, that serves sample
|
||||||
|
ready-to-use devfiles. You should set it ONLY if you use an external
|
||||||
|
devfile registry (see the `externalPluginRegistry` field). By
|
||||||
|
default this will be automatically calculated by the operator.
|
||||||
|
type: string
|
||||||
|
proxyPassword:
|
||||||
|
description: Password of the proxy server Only use when proxy configuration
|
||||||
|
is required (see also the `proxyUser` and `proxySecret` fields).
|
||||||
|
type: string
|
||||||
|
proxyPort:
|
||||||
|
description: Port of the proxy server. Only use when configuring
|
||||||
|
a proxy is required (see also the `proxyURL` field).
|
||||||
|
type: string
|
||||||
|
proxySecret:
|
||||||
|
description: The secret that contains `user` and `password` for
|
||||||
|
a proxy server. If the secret is defined then `proxyUser` and
|
||||||
|
`proxyPassword` are ignored
|
||||||
|
type: string
|
||||||
|
proxyURL:
|
||||||
|
description: URL (protocol+hostname) of the proxy server. This drives
|
||||||
|
the appropriate changes in the `JAVA_OPTS` and `https(s)_proxy`
|
||||||
|
variables in the Che server and workspaces containers. Only use
|
||||||
|
when configuring a proxy is required.
|
||||||
|
type: string
|
||||||
|
proxyUser:
|
||||||
|
description: User name of the proxy server. Only use when configuring
|
||||||
|
a proxy is required (see also the `proxyURL` `proxySecret` fields).
|
||||||
|
type: string
|
||||||
|
selfSignedCert:
|
||||||
|
description: Deprecated. The value of this flag is ignored. Che
|
||||||
|
operator will automatically detect if router certificate is self-signed.
|
||||||
|
If so it will be propagated to Che server and some other components.
|
||||||
|
type: boolean
|
||||||
|
serverMemoryLimit:
|
||||||
|
description: Overrides the memory limit used in the Che server deployment.
|
||||||
|
Defaults to 1Gi.
|
||||||
|
type: string
|
||||||
|
serverMemoryRequest:
|
||||||
|
description: Overrides the memory request used in the Che server
|
||||||
|
deployment. Defaults to 512Mi.
|
||||||
|
type: string
|
||||||
|
serverTrustStoreConfigMapName:
|
||||||
|
description: Name of the config-map with public certificates to
|
||||||
|
add to Java trust store of the Che server. This is usually required
|
||||||
|
when adding the OpenShift OAuth provider which has https endpoint
|
||||||
|
signed with self-signed cert. So, Che server must be aware of
|
||||||
|
its CA cert to be able to request it. This is disabled by default.
|
||||||
|
type: string
|
||||||
|
tlsSupport:
|
||||||
|
description: Deprecated. Instructs the operator to deploy Che in
|
||||||
|
TLS mode. This is enabled by default. Disabling TLS may cause
|
||||||
|
malfunction of some Che components.
|
||||||
|
type: boolean
|
||||||
|
workspaceNamespaceDefault:
|
||||||
|
description: 'Defines Kubernetes default namespace in which user''s
|
||||||
|
workspaces are created if user does not override it. It''s possible
|
||||||
|
to use <username>, <userid> and <workspaceid> placeholders (e.g.:
|
||||||
|
che-workspace-<username>). In that case, new namespace will be
|
||||||
|
created for each user (or workspace). Is used by OpenShift infra
|
||||||
|
as well to specify Project'
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
storage:
|
||||||
|
description: Configuration settings related to the persistent storage
|
||||||
|
used by the Che installation.
|
||||||
|
properties:
|
||||||
|
postgresPVCStorageClassName:
|
||||||
|
description: Storage class for the Persistent Volume Claim dedicated
|
||||||
|
to the Postgres database. If omitted or left blank, default storage
|
||||||
|
class is used.
|
||||||
|
type: string
|
||||||
|
preCreateSubPaths:
|
||||||
|
description: Instructs the Che server to launch a special pod to
|
||||||
|
pre-create a subpath in the Persistent Volumes. Defaults to `false`,
|
||||||
|
however it might need to enable it according to the configuration
|
||||||
|
of your K8S cluster.
|
||||||
|
type: boolean
|
||||||
|
pvcClaimSize:
|
||||||
|
description: Size of the persistent volume claim for workspaces.
|
||||||
|
Defaults to `1Gi`
|
||||||
|
type: string
|
||||||
|
pvcJobsImage:
|
||||||
|
description: Overrides the container image used to create sub-paths
|
||||||
|
in the Persistent Volumes. This includes the image tag. Omit it
|
||||||
|
or leave it empty to use the defaut container image provided by
|
||||||
|
the operator. See also the `preCreateSubPaths` field.
|
||||||
|
type: string
|
||||||
|
pvcStrategy:
|
||||||
|
description: Persistent volume claim strategy for the Che server.
|
||||||
|
This Can be:`common` (all workspaces PVCs in one volume), `per-workspace`
|
||||||
|
(one PVC per workspace for all declared volumes) and `unique`
|
||||||
|
(one PVC per declared volume). Defaults to `common`.
|
||||||
|
type: string
|
||||||
|
workspacePVCStorageClassName:
|
||||||
|
description: Storage class for the Persistent Volume Claims dedicated
|
||||||
|
to the Che workspaces. If omitted or left blank, default storage
|
||||||
|
class is used.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: CheClusterStatus defines the observed state of Che installation
|
||||||
|
properties:
|
||||||
|
cheClusterRunning:
|
||||||
|
description: Status of a Che installation. Can be `Available`, `Unavailable`,
|
||||||
|
or `Available, Rolling Update in Progress`
|
||||||
|
type: string
|
||||||
|
cheURL:
|
||||||
|
description: Public URL to the Che server
|
||||||
|
type: string
|
||||||
|
cheVersion:
|
||||||
|
description: Current installed Che version
|
||||||
|
type: string
|
||||||
|
dbProvisioned:
|
||||||
|
description: Indicates if or not a Postgres instance has been correctly
|
||||||
|
provisioned
|
||||||
|
type: boolean
|
||||||
|
devfileRegistryURL:
|
||||||
|
description: Public URL to the Devfile registry
|
||||||
|
type: string
|
||||||
|
helpLink:
|
||||||
|
description: A URL that can point to some URL where to find help related
|
||||||
|
to the current Operator status.
|
||||||
|
type: string
|
||||||
|
keycloakProvisioned:
|
||||||
|
description: Indicates whether an Identity Provider instance (Keycloak
|
||||||
|
/ RH SSO) has been provisioned with realm, client and user
|
||||||
|
type: boolean
|
||||||
|
keycloakURL:
|
||||||
|
description: Public URL to the Identity Provider server (Keycloak /
|
||||||
|
RH SSO).
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: A human readable message indicating details about why the
|
||||||
|
pod is in this condition.
|
||||||
|
type: string
|
||||||
|
openShiftoAuthProvisioned:
|
||||||
|
description: Indicates whether an Identity Provider instance (Keycloak
|
||||||
|
/ RH SSO) has been configured to integrate with the OpenShift OAuth.
|
||||||
|
type: boolean
|
||||||
|
pluginRegistryURL:
|
||||||
|
description: Public URL to the Plugin registry
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: A brief CamelCase message indicating details about why
|
||||||
|
the pod is in this state.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
version: v1
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,34 @@
|
||||||
|
--- /home/tolusha/gocode/src/github.com/eclipse/che-operator/olm/eclipse-che-preview-kubernetes/deploy/olm-catalog/eclipse-che-preview-kubernetes/9.9.9-nightly.1594133420/eclipse-che-preview-kubernetes.v9.9.9-nightly.1594133420.clusterserviceversion.yaml 2020-07-08 14:55:47.702990053 +0300
|
||||||
|
+++ /home/tolusha/gocode/src/github.com/eclipse/che-operator/olm/eclipse-che-preview-kubernetes/deploy/olm-catalog/eclipse-che-preview-kubernetes/9.9.9-nightly.1594209360/eclipse-che-preview-kubernetes.v9.9.9-nightly.1594209360.clusterserviceversion.yaml 2020-07-08 14:56:01.247006488 +0300
|
||||||
|
@@ -52,12 +52,12 @@
|
||||||
|
categories: Developer Tools
|
||||||
|
certified: "false"
|
||||||
|
containerImage: quay.io/eclipse/che-operator:nightly
|
||||||
|
- createdAt: "2020-07-07T14:50:21Z"
|
||||||
|
+ createdAt: "2020-07-08T11:56:01Z"
|
||||||
|
description: A Kube-native development solution that delivers portable and collaborative
|
||||||
|
developer workspaces.
|
||||||
|
repository: https://github.com/eclipse/che-operator
|
||||||
|
support: Eclipse Foundation
|
||||||
|
- name: eclipse-che-preview-kubernetes.v9.9.9-nightly.1594133420
|
||||||
|
+ name: eclipse-che-preview-kubernetes.v9.9.9-nightly.1594209360
|
||||||
|
namespace: placeholder
|
||||||
|
spec:
|
||||||
|
apiservicedefinitions: {}
|
||||||
|
@@ -288,6 +288,8 @@
|
||||||
|
value: che-identity-postgres-secret
|
||||||
|
- name: CHE_POSTGRES_SECRET
|
||||||
|
value: che-postgres-secret
|
||||||
|
+ - name: CHE_SERVER_TRUST_STORE_CONFIGMAP_NAME
|
||||||
|
+ value: ca-certs
|
||||||
|
image: quay.io/eclipse/che-operator:nightly
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: che-operator
|
||||||
|
@@ -397,5 +399,5 @@
|
||||||
|
maturity: stable
|
||||||
|
provider:
|
||||||
|
name: Eclipse Foundation
|
||||||
|
- replaces: eclipse-che-preview-kubernetes.v9.9.9-nightly.1594019197
|
||||||
|
- version: 9.9.9-nightly.1594133420
|
||||||
|
+ replaces: eclipse-che-preview-kubernetes.v9.9.9-nightly.1594133420
|
||||||
|
+ version: 9.9.9-nightly.1594209360
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
channels:
|
channels:
|
||||||
- currentCSV: eclipse-che-preview-kubernetes.v9.9.9-nightly.1594133420
|
- currentCSV: eclipse-che-preview-kubernetes.v9.9.9-nightly.1594209360
|
||||||
name: nightly
|
name: nightly
|
||||||
- currentCSV: eclipse-che-preview-kubernetes.v7.15.1
|
- currentCSV: eclipse-che-preview-kubernetes.v7.15.1
|
||||||
name: stable
|
name: stable
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,548 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012-2020 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
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: checlusters.org.eclipse.che
|
||||||
|
spec:
|
||||||
|
group: org.eclipse.che
|
||||||
|
names:
|
||||||
|
kind: CheCluster
|
||||||
|
listKind: CheClusterList
|
||||||
|
plural: checlusters
|
||||||
|
singular: checluster
|
||||||
|
scope: Namespaced
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
validation:
|
||||||
|
openAPIV3Schema:
|
||||||
|
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/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/api-conventions.md#types-kinds'
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: Desired configuration of the Che installation. Based on these
|
||||||
|
settings, the operator automatically creates and maintains several config
|
||||||
|
maps that will contain the appropriate environment variables the various
|
||||||
|
components of the Che installation. These generated config maps should
|
||||||
|
NOT be updated manually.
|
||||||
|
properties:
|
||||||
|
auth:
|
||||||
|
description: Configuration settings related to the Authentication used
|
||||||
|
by the Che installation.
|
||||||
|
properties:
|
||||||
|
externalIdentityProvider:
|
||||||
|
description: 'Instructs the operator on whether or not to deploy
|
||||||
|
a dedicated Identity Provider (Keycloak or RH SSO instance). By
|
||||||
|
default a dedicated Identity Provider server is deployed as part
|
||||||
|
of the Che installation. But if `externalIdentityProvider` is
|
||||||
|
`true`, then no dedicated identity provider will be deployed by
|
||||||
|
the operator and you might need to provide details about the external
|
||||||
|
identity provider you want to use. See also all the other fields
|
||||||
|
starting with: `identityProvider`.'
|
||||||
|
type: boolean
|
||||||
|
identityProviderAdminUserName:
|
||||||
|
description: Overrides the name of the Identity Provider admin user.
|
||||||
|
Defaults to `admin`.
|
||||||
|
type: string
|
||||||
|
identityProviderClientId:
|
||||||
|
description: Name of a Identity provider (Keycloak / RH SSO) `client-id`
|
||||||
|
that should be used for Che. This is useful to override it ONLY
|
||||||
|
if you use an external Identity Provider (see the `externalIdentityProvider`
|
||||||
|
field). If omitted or left blank, it will be set to the value
|
||||||
|
of the `flavour` field suffixed with `-public`.
|
||||||
|
type: string
|
||||||
|
identityProviderImage:
|
||||||
|
description: Overrides the container image used in the Identity
|
||||||
|
Provider (Keycloak / RH SSO) deployment. This includes the image
|
||||||
|
tag. Omit it or leave it empty to use the defaut container image
|
||||||
|
provided by the operator.
|
||||||
|
type: string
|
||||||
|
identityProviderImagePullPolicy:
|
||||||
|
description: Overrides the image pull policy used in the Identity
|
||||||
|
Provider (Keycloak / RH SSO) deployment. Default value is `Always`
|
||||||
|
for `nightly` or `latest` images, and `IfNotPresent` in other
|
||||||
|
cases.
|
||||||
|
type: string
|
||||||
|
identityProviderPassword:
|
||||||
|
description: Overrides the password of Keycloak admin user. This
|
||||||
|
is useful to override it ONLY if you use an external Identity
|
||||||
|
Provider (see the `externalIdentityProvider` field). If omitted
|
||||||
|
or left blank, it will be set to an auto-generated password.
|
||||||
|
type: string
|
||||||
|
identityProviderPostgresPassword:
|
||||||
|
description: Password for The Identity Provider (Keycloak / RH SSO)
|
||||||
|
to connect to the database. This is useful to override it ONLY
|
||||||
|
if you use an external Identity Provider (see the `externalIdentityProvider`
|
||||||
|
field). If omitted or left blank, it will be set to an auto-generated
|
||||||
|
password.
|
||||||
|
type: string
|
||||||
|
identityProviderPostgresSecret:
|
||||||
|
description: 'The secret that contains `password` for The Identity
|
||||||
|
Provider (Keycloak / RH SSO) to connect to the database. If the
|
||||||
|
secret is defined then `identityProviderPostgresPassword` will
|
||||||
|
be ignored. If the value is omitted or left blank then there are
|
||||||
|
two scenarios: 1. `identityProviderPostgresPassword` is defined,
|
||||||
|
then it will be used to connect to the database. 2. `identityProviderPostgresPassword`
|
||||||
|
is not defined, then a new secret with the name `che-identity-postgres-secret`
|
||||||
|
will be created with an auto-generated value for `password`.'
|
||||||
|
type: string
|
||||||
|
identityProviderRealm:
|
||||||
|
description: Name of a Identity provider (Keycloak / RH SSO) realm
|
||||||
|
that should be used for Che. This is useful to override it ONLY
|
||||||
|
if you use an external Identity Provider (see the `externalIdentityProvider`
|
||||||
|
field). If omitted or left blank, it will be set to the value
|
||||||
|
of the `flavour` field.
|
||||||
|
type: string
|
||||||
|
identityProviderSecret:
|
||||||
|
description: 'The secret that contains `user` and `password` for
|
||||||
|
Identity Provider. If the secret is defined then `identityProviderAdminUserName`
|
||||||
|
and `identityProviderPassword` are ignored. If the value is omitted
|
||||||
|
or left blank then there are two scenarios: 1. `identityProviderAdminUserName`
|
||||||
|
and `identityProviderPassword` are defined, then they will be
|
||||||
|
used. 2. `identityProviderAdminUserName` or `identityProviderPassword`
|
||||||
|
are not defined, then a new secret with the name `che-identity-secret`
|
||||||
|
will be created with default value `admin` for `user` and with
|
||||||
|
an auto-generated value for `password`.'
|
||||||
|
type: string
|
||||||
|
identityProviderURL:
|
||||||
|
description: Public URL of the Identity Provider server (Keycloak
|
||||||
|
/ RH SSO server). You should set it ONLY if you use an external
|
||||||
|
Identity Provider (see the `externalIdentityProvider` field).
|
||||||
|
By default this will be automatically calculated and set by the
|
||||||
|
operator.
|
||||||
|
type: string
|
||||||
|
oAuthClientName:
|
||||||
|
description: Name of the OpenShift `OAuthClient` resource used to
|
||||||
|
setup identity federation on the OpenShift side. Auto-generated
|
||||||
|
if left blank. See also the `OpenShiftoAuth` field.
|
||||||
|
type: string
|
||||||
|
oAuthSecret:
|
||||||
|
description: Name of the secret set in the OpenShift `OAuthClient`
|
||||||
|
resource used to setup identity federation on the OpenShift side.
|
||||||
|
Auto-generated if left blank. See also the `OAuthClientName` field.
|
||||||
|
type: string
|
||||||
|
openShiftoAuth:
|
||||||
|
description: 'Enables the integration of the identity provider (Keycloak
|
||||||
|
/ RHSSO) with OpenShift OAuth. Enabled by default on OpenShift.
|
||||||
|
This will allow users to directly login with their Openshift user
|
||||||
|
through the Openshift login, and have their workspaces created
|
||||||
|
under personal OpenShift namespaces. WARNING: the `kubeadmin`
|
||||||
|
user is NOT supported, and logging through it will NOT allow accessing
|
||||||
|
the Che Dashboard.'
|
||||||
|
type: boolean
|
||||||
|
updateAdminPassword:
|
||||||
|
description: Forces the default `admin` Che user to update password
|
||||||
|
on first login. Defaults to `false`.
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
database:
|
||||||
|
description: Configuration settings related to the database used by
|
||||||
|
the Che installation.
|
||||||
|
properties:
|
||||||
|
chePostgresDb:
|
||||||
|
description: Postgres database name that the Che server uses to
|
||||||
|
connect to the DB. Defaults to `dbche`.
|
||||||
|
type: string
|
||||||
|
chePostgresHostName:
|
||||||
|
description: Postgres Database hostname that the Che server uses
|
||||||
|
to connect to. Defaults to postgres. This value should be overridden
|
||||||
|
ONLY when using an external database (see field `externalDb`).
|
||||||
|
In the default case it will be automatically set by the operator.
|
||||||
|
type: string
|
||||||
|
chePostgresPassword:
|
||||||
|
description: Postgres password that the Che server should use to
|
||||||
|
connect to the DB. If omitted or left blank, it will be set to
|
||||||
|
an auto-generated value.
|
||||||
|
type: string
|
||||||
|
chePostgresPort:
|
||||||
|
description: Postgres Database port that the Che server uses to
|
||||||
|
connect to. Defaults to 5432. This value should be overridden
|
||||||
|
ONLY when using an external database (see field `externalDb`).
|
||||||
|
In the default case it will be automatically set by the operator.
|
||||||
|
type: string
|
||||||
|
chePostgresSecret:
|
||||||
|
description: 'The secret that contains Postgres `user` and `password`
|
||||||
|
that the Che server should use to connect to the DB. If the secret
|
||||||
|
is defined then `chePostgresUser` and `chePostgresPassword` are
|
||||||
|
ignored. If the value is omitted or left blank then there are
|
||||||
|
two scenarios: 1. `chePostgresUser` and `chePostgresPassword`
|
||||||
|
are defined, then they will be used to connect to the DB. 2. `chePostgresUser`
|
||||||
|
or `chePostgresPassword` are not defined, then a new secret with
|
||||||
|
the name `che-postgres-secret` will be created with default value
|
||||||
|
of `pgche` for `user` and with an auto-generated value for `password`.'
|
||||||
|
type: string
|
||||||
|
chePostgresUser:
|
||||||
|
description: Postgres user that the Che server should use to connect
|
||||||
|
to the DB. Defaults to `pgche`.
|
||||||
|
type: string
|
||||||
|
externalDb:
|
||||||
|
description: 'Instructs the operator on whether or not to deploy
|
||||||
|
a dedicated database. By default a dedicated Postgres database
|
||||||
|
is deployed as part of the Che installation. But if `externalDb`
|
||||||
|
is `true`, then no dedicated database will be deployed by the
|
||||||
|
operator and you might need to provide connection details to the
|
||||||
|
external DB you want to use. See also all the fields starting
|
||||||
|
with: `chePostgres`.'
|
||||||
|
type: boolean
|
||||||
|
postgresImage:
|
||||||
|
description: Overrides the container image used in the Postgres
|
||||||
|
database deployment. This includes the image tag. Omit it or leave
|
||||||
|
it empty to use the defaut container image provided by the operator.
|
||||||
|
type: string
|
||||||
|
postgresImagePullPolicy:
|
||||||
|
description: Overrides the image pull policy used in the Postgres
|
||||||
|
database deployment. Default value is `Always` for `nightly` or
|
||||||
|
`latest` images, and `IfNotPresent` in other cases.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
k8s:
|
||||||
|
description: Configuration settings specific to Che installations made
|
||||||
|
on upstream Kubernetes.
|
||||||
|
properties:
|
||||||
|
ingressClass:
|
||||||
|
description: 'Ingress class that will define the which controler
|
||||||
|
will manage ingresses. Defaults to `nginx`. NB: This drives the
|
||||||
|
`is kubernetes.io/ingress.class` annotation on Che-related ingresses.'
|
||||||
|
type: string
|
||||||
|
ingressDomain:
|
||||||
|
description: 'Global ingress domain for a K8S cluster. This MUST
|
||||||
|
be explicitly specified: there are no defaults.'
|
||||||
|
type: string
|
||||||
|
ingressStrategy:
|
||||||
|
description: Strategy for ingress creation. This can be `multi-host`
|
||||||
|
(host is explicitly provided in ingress), `single-host` (host
|
||||||
|
is provided, path-based rules) and `default-host.*`(no host is
|
||||||
|
provided, path-based rules). Defaults to `"multi-host`
|
||||||
|
type: string
|
||||||
|
securityContextFsGroup:
|
||||||
|
description: FSGroup the Che pod and Workspace pods containers should
|
||||||
|
run in. Defaults to `1724`.
|
||||||
|
type: string
|
||||||
|
securityContextRunAsUser:
|
||||||
|
description: ID of the user the Che pod and Workspace pods containers
|
||||||
|
should run as. Default to `1724`.
|
||||||
|
type: string
|
||||||
|
tlsSecretName:
|
||||||
|
description: Name of a secret that will be used to setup ingress
|
||||||
|
TLS termination if TLS is enabled. See also the `tlsSupport` field.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
metrics:
|
||||||
|
description: Configuration settings related to the metrics collection
|
||||||
|
used by the Che installation.
|
||||||
|
properties:
|
||||||
|
enable:
|
||||||
|
description: Enables `metrics` Che server endpoint. Default to `true`.
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
server:
|
||||||
|
description: General configuration settings related to the Che server
|
||||||
|
and the plugin and devfile registries
|
||||||
|
properties:
|
||||||
|
airGapContainerRegistryHostname:
|
||||||
|
description: Optional hostname (or url) to an alternate container
|
||||||
|
registry to pull images from. This value overrides the container
|
||||||
|
registry hostname defined in all the default container images
|
||||||
|
involved in a Che deployment. This is particularly useful to install
|
||||||
|
Che in an air-gapped environment.
|
||||||
|
type: string
|
||||||
|
airGapContainerRegistryOrganization:
|
||||||
|
description: Optional repository name of an alternate container
|
||||||
|
registry to pull images from. This value overrides the container
|
||||||
|
registry organization defined in all the default container images
|
||||||
|
involved in a Che deployment. This is particularly useful to install
|
||||||
|
Che in an air-gapped environment.
|
||||||
|
type: string
|
||||||
|
allowUserDefinedWorkspaceNamespaces:
|
||||||
|
description: Defines if a user is able to specify Kubernetes namespace
|
||||||
|
(or OpenShift project) different from the default. It's NOT RECOMMENDED
|
||||||
|
to configured true without OAuth configured. This property is
|
||||||
|
also used by the OpenShift infra.
|
||||||
|
type: boolean
|
||||||
|
cheDebug:
|
||||||
|
description: Enables the debug mode for Che server. Defaults to
|
||||||
|
`false`.
|
||||||
|
type: string
|
||||||
|
cheFlavor:
|
||||||
|
description: Flavor of the installation. This is either `che` for
|
||||||
|
upstream Che installations, or `codeready` for CodeReady Workspaces
|
||||||
|
installation. In most cases the default value should not be overriden.
|
||||||
|
type: string
|
||||||
|
cheHost:
|
||||||
|
description: Public hostname of the installed Che server. This will
|
||||||
|
be automatically set by the operator. In most cases the default
|
||||||
|
value set by the operator should not be overriden.
|
||||||
|
type: string
|
||||||
|
cheImage:
|
||||||
|
description: Overrides the container image used in Che deployment.
|
||||||
|
This does NOT include the container image tag. Omit it or leave
|
||||||
|
it empty to use the defaut container image provided by the operator.
|
||||||
|
type: string
|
||||||
|
cheImagePullPolicy:
|
||||||
|
description: Overrides the image pull policy used in Che deployment.
|
||||||
|
Default value is `Always` for `nightly` or `latest` images, and
|
||||||
|
`IfNotPresent` in other cases.
|
||||||
|
type: string
|
||||||
|
cheImageTag:
|
||||||
|
description: Overrides the tag of the container image used in Che
|
||||||
|
deployment. Omit it or leave it empty to use the defaut image
|
||||||
|
tag provided by the operator.
|
||||||
|
type: string
|
||||||
|
cheLogLevel:
|
||||||
|
description: 'Log level for the Che server: `INFO` or `DEBUG`. Defaults
|
||||||
|
to `INFO`.'
|
||||||
|
type: string
|
||||||
|
cheWorkspaceClusterRole:
|
||||||
|
description: Custom cluster role bound to the user for the Che workspaces.
|
||||||
|
The default roles are used if this is omitted or left blank.
|
||||||
|
type: string
|
||||||
|
customCheProperties:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Map of additional environment variables that will be
|
||||||
|
applied in the generated `che` config map to be used by the Che
|
||||||
|
server, in addition to the values already generated from other
|
||||||
|
fields of the `CheCluster` custom resource (CR). If `customCheProperties`
|
||||||
|
contains a property that would be normally generated in `che`
|
||||||
|
config map from other CR fields, then the value defined in the
|
||||||
|
`customCheProperties` will be used instead.
|
||||||
|
type: object
|
||||||
|
devfileRegistryImage:
|
||||||
|
description: Overrides the container image used in the Devfile registry
|
||||||
|
deployment. This includes the image tag. Omit it or leave it empty
|
||||||
|
to use the defaut container image provided by the operator.
|
||||||
|
type: string
|
||||||
|
devfileRegistryMemoryLimit:
|
||||||
|
description: Overrides the memory limit used in the Devfile registry
|
||||||
|
deployment. Defaults to 256Mi.
|
||||||
|
type: string
|
||||||
|
devfileRegistryMemoryRequest:
|
||||||
|
description: Overrides the memory request used in the Devfile registry
|
||||||
|
deployment. Defaults to 16Mi.
|
||||||
|
type: string
|
||||||
|
devfileRegistryPullPolicy:
|
||||||
|
description: Overrides the image pull policy used in the Devfile
|
||||||
|
registry deployment. Default value is `Always` for `nightly` or
|
||||||
|
`latest` images, and `IfNotPresent` in other cases.
|
||||||
|
type: string
|
||||||
|
devfileRegistryUrl:
|
||||||
|
description: Public URL of the Devfile registry, that serves sample,
|
||||||
|
ready-to-use devfiles. You should set it ONLY if you use an external
|
||||||
|
devfile registry (see the `externalDevfileRegistry` field). By
|
||||||
|
default this will be automatically calculated by the operator.
|
||||||
|
type: string
|
||||||
|
externalDevfileRegistry:
|
||||||
|
description: Instructs the operator on whether or not to deploy
|
||||||
|
a dedicated Devfile registry server. By default a dedicated devfile
|
||||||
|
registry server is started. But if `externalDevfileRegistry` is
|
||||||
|
`true`, then no such dedicated server will be started by the operator
|
||||||
|
and you will have to manually set the `devfileRegistryUrl` field
|
||||||
|
type: boolean
|
||||||
|
externalPluginRegistry:
|
||||||
|
description: Instructs the operator on whether or not to deploy
|
||||||
|
a dedicated Plugin registry server. By default a dedicated plugin
|
||||||
|
registry server is started. But if `externalPluginRegistry` is
|
||||||
|
`true`, then no such dedicated server will be started by the operator
|
||||||
|
and you will have to manually set the `pluginRegistryUrl` field.
|
||||||
|
type: boolean
|
||||||
|
gitSelfSignedCert:
|
||||||
|
description: If enabled, then the certificate from `che-git-self-signed-cert`
|
||||||
|
config map will be propagated to the Che components and provide
|
||||||
|
particular configuration for Git.
|
||||||
|
type: boolean
|
||||||
|
nonProxyHosts:
|
||||||
|
description: List of hosts that should not use the configured proxy.
|
||||||
|
Use `|`` as delimiter, eg `localhost|my.host.com|123.42.12.32`
|
||||||
|
Only use when configuring a proxy is required (see also the `proxyURL`
|
||||||
|
field).
|
||||||
|
type: string
|
||||||
|
pluginRegistryImage:
|
||||||
|
description: Overrides the container image used in the Plugin registry
|
||||||
|
deployment. This includes the image tag. Omit it or leave it empty
|
||||||
|
to use the defaut container image provided by the operator.
|
||||||
|
type: string
|
||||||
|
pluginRegistryMemoryLimit:
|
||||||
|
description: Overrides the memory limit used in the Plugin registry
|
||||||
|
deployment. Defaults to 256Mi.
|
||||||
|
type: string
|
||||||
|
pluginRegistryMemoryRequest:
|
||||||
|
description: Overrides the memory request used in the Plugin registry
|
||||||
|
deployment. Defaults to 16Mi.
|
||||||
|
type: string
|
||||||
|
pluginRegistryPullPolicy:
|
||||||
|
description: Overrides the image pull policy used in the Plugin
|
||||||
|
registry deployment. Default value is `Always` for `nightly` or
|
||||||
|
`latest` images, and `IfNotPresent` in other cases.
|
||||||
|
type: string
|
||||||
|
pluginRegistryUrl:
|
||||||
|
description: Public URL of the Plugin registry, that serves sample
|
||||||
|
ready-to-use devfiles. You should set it ONLY if you use an external
|
||||||
|
devfile registry (see the `externalPluginRegistry` field). By
|
||||||
|
default this will be automatically calculated by the operator.
|
||||||
|
type: string
|
||||||
|
proxyPassword:
|
||||||
|
description: Password of the proxy server Only use when proxy configuration
|
||||||
|
is required (see also the `proxyUser` and `proxySecret` fields).
|
||||||
|
type: string
|
||||||
|
proxyPort:
|
||||||
|
description: Port of the proxy server. Only use when configuring
|
||||||
|
a proxy is required (see also the `proxyURL` field).
|
||||||
|
type: string
|
||||||
|
proxySecret:
|
||||||
|
description: The secret that contains `user` and `password` for
|
||||||
|
a proxy server. If the secret is defined then `proxyUser` and
|
||||||
|
`proxyPassword` are ignored
|
||||||
|
type: string
|
||||||
|
proxyURL:
|
||||||
|
description: URL (protocol+hostname) of the proxy server. This drives
|
||||||
|
the appropriate changes in the `JAVA_OPTS` and `https(s)_proxy`
|
||||||
|
variables in the Che server and workspaces containers. Only use
|
||||||
|
when configuring a proxy is required.
|
||||||
|
type: string
|
||||||
|
proxyUser:
|
||||||
|
description: User name of the proxy server. Only use when configuring
|
||||||
|
a proxy is required (see also the `proxyURL` `proxySecret` fields).
|
||||||
|
type: string
|
||||||
|
selfSignedCert:
|
||||||
|
description: Deprecated. The value of this flag is ignored. Che
|
||||||
|
operator will automatically detect if router certificate is self-signed.
|
||||||
|
If so it will be propagated to Che server and some other components.
|
||||||
|
type: boolean
|
||||||
|
serverMemoryLimit:
|
||||||
|
description: Overrides the memory limit used in the Che server deployment.
|
||||||
|
Defaults to 1Gi.
|
||||||
|
type: string
|
||||||
|
serverMemoryRequest:
|
||||||
|
description: Overrides the memory request used in the Che server
|
||||||
|
deployment. Defaults to 512Mi.
|
||||||
|
type: string
|
||||||
|
serverTrustStoreConfigMapName:
|
||||||
|
description: Name of the config-map with public certificates to
|
||||||
|
add to Java trust store of the Che server. This is usually required
|
||||||
|
when adding the OpenShift OAuth provider which has https endpoint
|
||||||
|
signed with self-signed cert. So, Che server must be aware of
|
||||||
|
its CA cert to be able to request it. This is disabled by default.
|
||||||
|
type: string
|
||||||
|
tlsSupport:
|
||||||
|
description: Deprecated. Instructs the operator to deploy Che in
|
||||||
|
TLS mode. This is enabled by default. Disabling TLS may cause
|
||||||
|
malfunction of some Che components.
|
||||||
|
type: boolean
|
||||||
|
workspaceNamespaceDefault:
|
||||||
|
description: 'Defines Kubernetes default namespace in which user''s
|
||||||
|
workspaces are created if user does not override it. It''s possible
|
||||||
|
to use <username>, <userid> and <workspaceid> placeholders (e.g.:
|
||||||
|
che-workspace-<username>). In that case, new namespace will be
|
||||||
|
created for each user (or workspace). Is used by OpenShift infra
|
||||||
|
as well to specify Project'
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
storage:
|
||||||
|
description: Configuration settings related to the persistent storage
|
||||||
|
used by the Che installation.
|
||||||
|
properties:
|
||||||
|
postgresPVCStorageClassName:
|
||||||
|
description: Storage class for the Persistent Volume Claim dedicated
|
||||||
|
to the Postgres database. If omitted or left blank, default storage
|
||||||
|
class is used.
|
||||||
|
type: string
|
||||||
|
preCreateSubPaths:
|
||||||
|
description: Instructs the Che server to launch a special pod to
|
||||||
|
pre-create a subpath in the Persistent Volumes. Defaults to `false`,
|
||||||
|
however it might need to enable it according to the configuration
|
||||||
|
of your K8S cluster.
|
||||||
|
type: boolean
|
||||||
|
pvcClaimSize:
|
||||||
|
description: Size of the persistent volume claim for workspaces.
|
||||||
|
Defaults to `1Gi`
|
||||||
|
type: string
|
||||||
|
pvcJobsImage:
|
||||||
|
description: Overrides the container image used to create sub-paths
|
||||||
|
in the Persistent Volumes. This includes the image tag. Omit it
|
||||||
|
or leave it empty to use the defaut container image provided by
|
||||||
|
the operator. See also the `preCreateSubPaths` field.
|
||||||
|
type: string
|
||||||
|
pvcStrategy:
|
||||||
|
description: Persistent volume claim strategy for the Che server.
|
||||||
|
This Can be:`common` (all workspaces PVCs in one volume), `per-workspace`
|
||||||
|
(one PVC per workspace for all declared volumes) and `unique`
|
||||||
|
(one PVC per declared volume). Defaults to `common`.
|
||||||
|
type: string
|
||||||
|
workspacePVCStorageClassName:
|
||||||
|
description: Storage class for the Persistent Volume Claims dedicated
|
||||||
|
to the Che workspaces. If omitted or left blank, default storage
|
||||||
|
class is used.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: CheClusterStatus defines the observed state of Che installation
|
||||||
|
properties:
|
||||||
|
cheClusterRunning:
|
||||||
|
description: Status of a Che installation. Can be `Available`, `Unavailable`,
|
||||||
|
or `Available, Rolling Update in Progress`
|
||||||
|
type: string
|
||||||
|
cheURL:
|
||||||
|
description: Public URL to the Che server
|
||||||
|
type: string
|
||||||
|
cheVersion:
|
||||||
|
description: Current installed Che version
|
||||||
|
type: string
|
||||||
|
dbProvisioned:
|
||||||
|
description: Indicates if or not a Postgres instance has been correctly
|
||||||
|
provisioned
|
||||||
|
type: boolean
|
||||||
|
devfileRegistryURL:
|
||||||
|
description: Public URL to the Devfile registry
|
||||||
|
type: string
|
||||||
|
helpLink:
|
||||||
|
description: A URL that can point to some URL where to find help related
|
||||||
|
to the current Operator status.
|
||||||
|
type: string
|
||||||
|
keycloakProvisioned:
|
||||||
|
description: Indicates whether an Identity Provider instance (Keycloak
|
||||||
|
/ RH SSO) has been provisioned with realm, client and user
|
||||||
|
type: boolean
|
||||||
|
keycloakURL:
|
||||||
|
description: Public URL to the Identity Provider server (Keycloak /
|
||||||
|
RH SSO).
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: A human readable message indicating details about why the
|
||||||
|
pod is in this condition.
|
||||||
|
type: string
|
||||||
|
openShiftoAuthProvisioned:
|
||||||
|
description: Indicates whether an Identity Provider instance (Keycloak
|
||||||
|
/ RH SSO) has been configured to integrate with the OpenShift OAuth.
|
||||||
|
type: boolean
|
||||||
|
pluginRegistryURL:
|
||||||
|
description: Public URL to the Plugin registry
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: A brief CamelCase message indicating details about why
|
||||||
|
the pod is in this state.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
version: v1
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,46 @@
|
||||||
|
--- /home/tolusha/gocode/src/github.com/eclipse/che-operator/olm/eclipse-che-preview-openshift/deploy/olm-catalog/eclipse-che-preview-openshift/9.9.9-nightly.1594133421/eclipse-che-preview-openshift.v9.9.9-nightly.1594133421.clusterserviceversion.yaml 2020-07-08 14:55:47.710990063 +0300
|
||||||
|
+++ /home/tolusha/gocode/src/github.com/eclipse/che-operator/olm/eclipse-che-preview-openshift/deploy/olm-catalog/eclipse-che-preview-openshift/9.9.9-nightly.1594209361/eclipse-che-preview-openshift.v9.9.9-nightly.1594209361.clusterserviceversion.yaml 2020-07-08 14:56:02.467007934 +0300
|
||||||
|
@@ -49,12 +49,12 @@
|
||||||
|
categories: Developer Tools, OpenShift Optional
|
||||||
|
certified: "false"
|
||||||
|
containerImage: quay.io/eclipse/che-operator:nightly
|
||||||
|
- createdAt: "2020-07-07T14:50:21Z"
|
||||||
|
+ createdAt: "2020-07-08T11:56:01Z"
|
||||||
|
description: A Kube-native development solution that delivers portable and collaborative
|
||||||
|
developer workspaces in OpenShift.
|
||||||
|
repository: https://github.com/eclipse/che-operator
|
||||||
|
support: Eclipse Foundation
|
||||||
|
- name: eclipse-che-preview-openshift.v9.9.9-nightly.1594133421
|
||||||
|
+ name: eclipse-che-preview-openshift.v9.9.9-nightly.1594209361
|
||||||
|
namespace: placeholder
|
||||||
|
spec:
|
||||||
|
apiservicedefinitions: {}
|
||||||
|
@@ -244,8 +244,11 @@
|
||||||
|
resources:
|
||||||
|
- infrastructures
|
||||||
|
- oauths
|
||||||
|
+ - proxies
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
+ - list
|
||||||
|
+ - watch
|
||||||
|
- apiGroups:
|
||||||
|
- user.openshift.io
|
||||||
|
resources:
|
||||||
|
@@ -327,6 +330,8 @@
|
||||||
|
value: che-identity-postgres-secret
|
||||||
|
- name: CHE_POSTGRES_SECRET
|
||||||
|
value: che-postgres-secret
|
||||||
|
+ - name: CHE_SERVER_TRUST_STORE_CONFIGMAP_NAME
|
||||||
|
+ value: ca-certs
|
||||||
|
image: quay.io/eclipse/che-operator:nightly
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: che-operator
|
||||||
|
@@ -441,5 +446,5 @@
|
||||||
|
maturity: stable
|
||||||
|
provider:
|
||||||
|
name: Eclipse Foundation
|
||||||
|
- replaces: eclipse-che-preview-openshift.v9.9.9-nightly.1594019198
|
||||||
|
- version: 9.9.9-nightly.1594133421
|
||||||
|
+ replaces: eclipse-che-preview-openshift.v9.9.9-nightly.1594133421
|
||||||
|
+ version: 9.9.9-nightly.1594209361
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
channels:
|
channels:
|
||||||
- currentCSV: eclipse-che-preview-openshift.v9.9.9-nightly.1594133421
|
- currentCSV: eclipse-che-preview-openshift.v9.9.9-nightly.1594209361
|
||||||
name: nightly
|
name: nightly
|
||||||
- currentCSV: eclipse-che-preview-openshift.v7.15.1
|
- currentCSV: eclipse-che-preview-openshift.v7.15.1
|
||||||
name: stable
|
name: stable
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||||
"github.com/eclipse/che-operator/pkg/deploy"
|
"github.com/eclipse/che-operator/pkg/deploy"
|
||||||
"github.com/eclipse/che-operator/pkg/util"
|
"github.com/eclipse/che-operator/pkg/util"
|
||||||
|
configv1 "github.com/openshift/api/config/v1"
|
||||||
oauthv1 "github.com/openshift/api/config/v1"
|
oauthv1 "github.com/openshift/api/config/v1"
|
||||||
consolev1 "github.com/openshift/api/console/v1"
|
consolev1 "github.com/openshift/api/console/v1"
|
||||||
oauth "github.com/openshift/api/oauth/v1"
|
oauth "github.com/openshift/api/oauth/v1"
|
||||||
|
|
@ -96,6 +97,9 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||||
if err := oauthv1.AddToScheme(mgr.GetScheme()); err != nil {
|
if err := oauthv1.AddToScheme(mgr.GetScheme()); err != nil {
|
||||||
logrus.Errorf("Failed to add OpenShift OAuth to scheme: %s", err)
|
logrus.Errorf("Failed to add OpenShift OAuth to scheme: %s", err)
|
||||||
}
|
}
|
||||||
|
if err := configv1.AddToScheme(mgr.GetScheme()); err != nil {
|
||||||
|
logrus.Errorf("Failed to add OpenShift Config to scheme: %s", err)
|
||||||
|
}
|
||||||
if hasConsolelinkObject() {
|
if hasConsolelinkObject() {
|
||||||
if err := consolev1.AddToScheme(mgr.GetScheme()); err != nil {
|
if err := consolev1.AddToScheme(mgr.GetScheme()); err != nil {
|
||||||
logrus.Errorf("Failed to add OpenShift ConsoleLink to scheme: %s", err)
|
logrus.Errorf("Failed to add OpenShift ConsoleLink to scheme: %s", err)
|
||||||
|
|
@ -307,6 +311,26 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read proxy configuration
|
||||||
|
proxy, err := r.getProxyConfiguration(instance)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Error on reading proxy configuration: %v", err)
|
||||||
|
return reconcile.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if proxy.TrustedCAMapName != "" {
|
||||||
|
provisioned, err := r.putOpenShiftCertsIntoConfigMap(instance, proxy, clusterAPI)
|
||||||
|
if !provisioned {
|
||||||
|
configMapName := instance.Spec.Server.ServerTrustStoreConfigMapName
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Error on provisioning config map '%s': %v", configMapName, err)
|
||||||
|
} else {
|
||||||
|
logrus.Infof("Waiting on provisioning config map '%s'", configMapName)
|
||||||
|
}
|
||||||
|
return reconcile.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cheFlavor := deploy.DefaultCheFlavor(instance)
|
cheFlavor := deploy.DefaultCheFlavor(instance)
|
||||||
cheDeploymentName := cheFlavor
|
cheDeploymentName := cheFlavor
|
||||||
|
|
||||||
|
|
@ -319,7 +343,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect whether self-signed certificate is used
|
// Detect whether self-signed certificate is used
|
||||||
selfSignedCertUsed, err := deploy.IsSelfSignedCertificateUsed(instance, clusterAPI)
|
selfSignedCertUsed, err := deploy.IsSelfSignedCertificateUsed(instance, proxy, clusterAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Failed to detect if self-signed certificate used. Cause: %v", err)
|
logrus.Errorf("Failed to detect if self-signed certificate used. Cause: %v", err)
|
||||||
return reconcile.Result{}, err
|
return reconcile.Result{}, err
|
||||||
|
|
@ -332,7 +356,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
|
||||||
// and NOT from the Openshift API Master URL (as in v3)
|
// and NOT from the Openshift API Master URL (as in v3)
|
||||||
// So we also need the self-signed certificate to access them (same as the Che server)
|
// So we also need the self-signed certificate to access them (same as the Che server)
|
||||||
(isOpenShift4 && instance.Spec.Auth.OpenShiftoAuth && !instance.Spec.Server.TlsSupport) {
|
(isOpenShift4 && instance.Spec.Auth.OpenShiftoAuth && !instance.Spec.Server.TlsSupport) {
|
||||||
if err := deploy.CreateTLSSecretFromRoute(instance, "", deploy.CheTLSSelfSignedCertificateSecretName, clusterAPI); err != nil {
|
if err := deploy.CreateTLSSecretFromRoute(instance, "", deploy.CheTLSSelfSignedCertificateSecretName, proxy, clusterAPI); err != nil {
|
||||||
return reconcile.Result{}, err
|
return reconcile.Result{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -353,7 +377,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Failed to get OpenShift cluster public hostname. A secret with API crt will not be created and consumed by RH-SSO/Keycloak")
|
logrus.Errorf("Failed to get OpenShift cluster public hostname. A secret with API crt will not be created and consumed by RH-SSO/Keycloak")
|
||||||
} else {
|
} else {
|
||||||
if err := deploy.CreateTLSSecretFromRoute(instance, baseURL, "openshift-api-crt", clusterAPI); err != nil {
|
if err := deploy.CreateTLSSecretFromRoute(instance, baseURL, "openshift-api-crt", proxy, clusterAPI); err != nil {
|
||||||
return reconcile.Result{}, err
|
return reconcile.Result{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -793,7 +817,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deploymentStatus := deploy.SyncKeycloakDeploymentToCluster(instance, clusterAPI)
|
deploymentStatus := deploy.SyncKeycloakDeploymentToCluster(instance, proxy, clusterAPI)
|
||||||
if !tests {
|
if !tests {
|
||||||
if !deploymentStatus.Continue {
|
if !deploymentStatus.Continue {
|
||||||
logrus.Info("Waiting on deployment 'keycloak' to be ready")
|
logrus.Info("Waiting on deployment 'keycloak' to be ready")
|
||||||
|
|
@ -992,7 +1016,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
|
||||||
logrus.Errorf("An error occurred: %v", err)
|
logrus.Errorf("An error occurred: %v", err)
|
||||||
return reconcile.Result{}, err
|
return reconcile.Result{}, err
|
||||||
}
|
}
|
||||||
logrus.Info(" Updating plugin-registry ConfigMap")
|
logrus.Info("Updating plugin-registry ConfigMap")
|
||||||
err = r.client.Update(context.TODO(), pluginRegistryConfigMap)
|
err = r.client.Update(context.TODO(), pluginRegistryConfigMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Error updating plugin-registry ConfigMap: %v", err)
|
logrus.Errorf("Error updating plugin-registry ConfigMap: %v", err)
|
||||||
|
|
@ -1088,16 +1112,14 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
|
||||||
|
|
||||||
// create Che ConfigMap which is synced with CR and is not supposed to be manually edited
|
// create Che ConfigMap which is synced with CR and is not supposed to be manually edited
|
||||||
// controller will reconcile this CM with CR spec
|
// controller will reconcile this CM with CR spec
|
||||||
cheEnv := deploy.GetConfigMapData(instance)
|
cheConfigMap, err := deploy.SyncCheConfigMapToCluster(instance, proxy, clusterAPI)
|
||||||
configMapStatus := deploy.SyncConfigMapToCluster(instance, cheEnv, clusterAPI)
|
|
||||||
if !tests {
|
if !tests {
|
||||||
if !configMapStatus.Continue {
|
if cheConfigMap == nil {
|
||||||
logrus.Infof("Waiting on config map '%s' to be created", cheFlavor)
|
logrus.Infof("Waiting on config map '%s' to be created", deploy.CheConfigMapName)
|
||||||
if configMapStatus.Err != nil {
|
if err != nil {
|
||||||
logrus.Error(configMapStatus.Err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
|
return reconcile.Result{}, err
|
||||||
return reconcile.Result{Requeue: configMapStatus.Requeue}, configMapStatus.Err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1107,11 +1129,11 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
|
||||||
if tests {
|
if tests {
|
||||||
cmResourceVersion = r.GetEffectiveConfigMap(instance, deploy.CheConfigMapName).ResourceVersion
|
cmResourceVersion = r.GetEffectiveConfigMap(instance, deploy.CheConfigMapName).ResourceVersion
|
||||||
} else {
|
} else {
|
||||||
cmResourceVersion = configMapStatus.ConfigMap.ResourceVersion
|
cmResourceVersion = cheConfigMap.ResourceVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new che deployment
|
// Create a new che deployment
|
||||||
deploymentStatus := deploy.SyncCheDeploymentToCluster(instance, cmResourceVersion, clusterAPI)
|
deploymentStatus := deploy.SyncCheDeploymentToCluster(instance, cmResourceVersion, proxy, clusterAPI)
|
||||||
if !tests {
|
if !tests {
|
||||||
if !deploymentStatus.Continue {
|
if !deploymentStatus.Continue {
|
||||||
logrus.Infof("Waiting on deployment '%s' to be ready", cheFlavor)
|
logrus.Infof("Waiting on deployment '%s' to be ready", cheFlavor)
|
||||||
|
|
|
||||||
|
|
@ -135,9 +135,7 @@ func (r *ReconcileChe) GenerateAndSaveFields(instance *orgv1.CheCluster, request
|
||||||
if len(instance.Spec.Auth.IdentityProviderPostgresSecret) < 1 {
|
if len(instance.Spec.Auth.IdentityProviderPostgresSecret) < 1 {
|
||||||
keycloakPostgresPassword := util.GeneratePasswd(12)
|
keycloakPostgresPassword := util.GeneratePasswd(12)
|
||||||
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
|
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
|
||||||
if err != nil {
|
if err == nil {
|
||||||
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating passwd")
|
|
||||||
} else {
|
|
||||||
keycloakPostgresPassword = util.GetDeploymentEnv(keycloakDeployment, "DB_PASSWORD")
|
keycloakPostgresPassword = util.GetDeploymentEnv(keycloakDeployment, "DB_PASSWORD")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,9 +154,7 @@ func (r *ReconcileChe) GenerateAndSaveFields(instance *orgv1.CheCluster, request
|
||||||
keycloakAdminPassword := util.GetValue(instance.Spec.Auth.IdentityProviderPassword, util.GeneratePasswd(12))
|
keycloakAdminPassword := util.GetValue(instance.Spec.Auth.IdentityProviderPassword, util.GeneratePasswd(12))
|
||||||
|
|
||||||
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
|
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
|
||||||
if err != nil {
|
if err == nil {
|
||||||
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating admin username and password")
|
|
||||||
} else {
|
|
||||||
keycloakAdminUserName = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_USERNAME")
|
keycloakAdminUserName = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_USERNAME")
|
||||||
keycloakAdminPassword = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_PASSWORD")
|
keycloakAdminPassword = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_PASSWORD")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 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 che
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||||
|
"github.com/eclipse/che-operator/pkg/deploy"
|
||||||
|
"github.com/eclipse/che-operator/pkg/util"
|
||||||
|
configv1 "github.com/openshift/api/config/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *ReconcileChe) getProxyConfiguration(checluster *orgv1.CheCluster) (*deploy.Proxy, error) {
|
||||||
|
proxy, err := deploy.ReadCheClusterProxyConfiguration(checluster)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if util.IsOpenShift4 {
|
||||||
|
clusterProxy := &configv1.Proxy{}
|
||||||
|
if err := r.client.Get(context.TODO(), types.NamespacedName{Name: "cluster"}, clusterProxy); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If proxy configuration exists in CR then cluster wide proxy configuration is ignored
|
||||||
|
// otherwise cluster wide proxy configuration is used and non proxy hosts
|
||||||
|
// are merted with defined ones in CR
|
||||||
|
if proxy.HttpProxy == "" && clusterProxy.Status.HTTPProxy != "" {
|
||||||
|
proxy, err = deploy.ReadClusterWideProxyConfiguration(clusterProxy, proxy.NoProxy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ReconcileChe) putOpenShiftCertsIntoConfigMap(checluster *orgv1.CheCluster, proxy *deploy.Proxy, clusterAPI deploy.ClusterAPI) (bool, error) {
|
||||||
|
if checluster.Spec.Server.ServerTrustStoreConfigMapName == "" {
|
||||||
|
checluster.Spec.Server.ServerTrustStoreConfigMapName = deploy.DefaultServerTrustStoreConfigMapName()
|
||||||
|
if err := r.UpdateCheCRSpec(checluster, "truststore configmap", deploy.DefaultServerTrustStoreConfigMapName()); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
certConfigMap, err := deploy.SyncTrustStoreConfigMapToCluster(checluster, clusterAPI)
|
||||||
|
return certConfigMap != nil, err
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
package deploy
|
package deploy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -20,14 +19,8 @@ import (
|
||||||
|
|
||||||
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||||
"github.com/eclipse/che-operator/pkg/util"
|
"github.com/eclipse/che-operator/pkg/util"
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
runtimeClient "sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -83,54 +76,19 @@ type CheConfigMap struct {
|
||||||
CheJGroupsKubernetesLabels string `json:"KUBERNETES_LABELS,omitempty"`
|
CheJGroupsKubernetesLabels string `json:"KUBERNETES_LABELS,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigMapProvisioningStatus struct {
|
func SyncCheConfigMapToCluster(checluster *orgv1.CheCluster, proxy *Proxy, clusterAPI ClusterAPI) (*corev1.ConfigMap, error) {
|
||||||
ProvisioningStatus
|
data := GetCheConfigMapData(checluster, proxy)
|
||||||
ConfigMap *corev1.ConfigMap
|
specConfigMap, err := GetSpecConfigMap(checluster, CheConfigMapName, data, clusterAPI)
|
||||||
}
|
|
||||||
|
|
||||||
func SyncConfigMapToCluster(checluster *orgv1.CheCluster, cheEnv map[string]string, clusterAPI ClusterAPI) ConfigMapProvisioningStatus {
|
|
||||||
specConfigMap, err := GetSpecConfigMap(checluster, cheEnv, clusterAPI)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigMapProvisioningStatus{
|
return nil, err
|
||||||
ProvisioningStatus: ProvisioningStatus{Err: err},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clusterConfigMap, err := getClusterConfigMap(specConfigMap.Name, specConfigMap.Namespace, clusterAPI.Client)
|
return SyncConfigMapToCluster(checluster, specConfigMap, clusterAPI)
|
||||||
if err != nil {
|
|
||||||
return ConfigMapProvisioningStatus{
|
|
||||||
ProvisioningStatus: ProvisioningStatus{Err: err},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if clusterConfigMap == nil {
|
|
||||||
logrus.Infof("Creating a new object: %s, name %s", specConfigMap.Kind, specConfigMap.Name)
|
|
||||||
err := clusterAPI.Client.Create(context.TODO(), specConfigMap)
|
|
||||||
return ConfigMapProvisioningStatus{
|
|
||||||
ProvisioningStatus: ProvisioningStatus{Requeue: true, Err: err},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff := cmp.Diff(clusterConfigMap.Data, specConfigMap.Data)
|
|
||||||
if len(diff) > 0 {
|
|
||||||
logrus.Infof("Updating existed object: %s, name: %s", specConfigMap.Kind, specConfigMap.Name)
|
|
||||||
fmt.Printf("Difference:\n%s", diff)
|
|
||||||
clusterConfigMap.Data = specConfigMap.Data
|
|
||||||
err := clusterAPI.Client.Update(context.TODO(), clusterConfigMap)
|
|
||||||
return ConfigMapProvisioningStatus{
|
|
||||||
ProvisioningStatus: ProvisioningStatus{Requeue: true, Err: err},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConfigMapProvisioningStatus{
|
|
||||||
ProvisioningStatus: ProvisioningStatus{Continue: true},
|
|
||||||
ConfigMap: clusterConfigMap,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConfigMapData gets env values from CR spec and returns a map with key:value
|
// GetConfigMapData gets env values from CR spec and returns a map with key:value
|
||||||
// which is used in CheCluster ConfigMap to configure CheCluster master behavior
|
// which is used in CheCluster ConfigMap to configure CheCluster master behavior
|
||||||
func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
|
func GetCheConfigMapData(cr *orgv1.CheCluster, proxy *Proxy) (cheEnv map[string]string) {
|
||||||
cheHost := cr.Spec.Server.CheHost
|
cheHost := cr.Spec.Server.CheHost
|
||||||
keycloakURL := cr.Spec.Auth.IdentityProviderURL
|
keycloakURL := cr.Spec.Auth.IdentityProviderURL
|
||||||
isOpenShift, isOpenshift4, err := util.DetectOpenShift()
|
isOpenShift, isOpenshift4, err := util.DetectOpenShift()
|
||||||
|
|
@ -165,31 +123,20 @@ func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
|
||||||
wsprotocol = "wss"
|
wsprotocol = "wss"
|
||||||
tls = "true"
|
tls = "true"
|
||||||
}
|
}
|
||||||
proxyJavaOpts := ""
|
|
||||||
proxyUser := cr.Spec.Server.ProxyUser
|
|
||||||
proxyPassword := cr.Spec.Server.ProxyPassword
|
|
||||||
proxySecret := cr.Spec.Server.ProxySecret
|
|
||||||
|
|
||||||
nonProxyHosts := cr.Spec.Server.NonProxyHosts
|
proxyJavaOpts := ""
|
||||||
if len(nonProxyHosts) < 1 && len(cr.Spec.Server.ProxyURL) > 1 {
|
cheWorkspaceNoProxy := proxy.NoProxy
|
||||||
nonProxyHosts = os.Getenv("KUBERNETES_SERVICE_HOST")
|
if proxy.HttpProxy != "" {
|
||||||
} else {
|
if proxy.NoProxy == "" {
|
||||||
nonProxyHosts = nonProxyHosts + "|" + os.Getenv("KUBERNETES_SERVICE_HOST")
|
cheWorkspaceNoProxy = os.Getenv("KUBERNETES_SERVICE_HOST")
|
||||||
}
|
} else {
|
||||||
if len(cr.Spec.Server.ProxyURL) > 1 {
|
cheWorkspaceNoProxy = cheWorkspaceNoProxy + "," + os.Getenv("KUBERNETES_SERVICE_HOST")
|
||||||
proxyJavaOpts, err = util.GenerateProxyJavaOpts(cr.Spec.Server.ProxyURL, cr.Spec.Server.ProxyPort, nonProxyHosts, proxyUser, proxyPassword, proxySecret, cr.Namespace)
|
}
|
||||||
|
proxyJavaOpts, err = GenerateProxyJavaOpts(proxy, cheWorkspaceNoProxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Failed to generate java proxy options: %v", err)
|
logrus.Errorf("Failed to generate java proxy options: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cheWorkspaceHttpProxy := ""
|
|
||||||
cheWorkspaceNoProxy := ""
|
|
||||||
if len(cr.Spec.Server.ProxyURL) > 1 {
|
|
||||||
cheWorkspaceHttpProxy, cheWorkspaceNoProxy, err = util.GenerateProxyEnvs(cr.Spec.Server.ProxyURL, cr.Spec.Server.ProxyPort, nonProxyHosts, proxyUser, proxyPassword, proxySecret, cr.Namespace)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("Failed to generate proxy env variables: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ingressDomain := cr.Spec.K8s.IngressDomain
|
ingressDomain := cr.Spec.K8s.IngressDomain
|
||||||
tlsSecretName := cr.Spec.K8s.TlsSecretName
|
tlsSecretName := cr.Spec.K8s.TlsSecretName
|
||||||
|
|
@ -220,7 +167,7 @@ func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
|
||||||
cheLogLevel := util.GetValue(cr.Spec.Server.CheLogLevel, DefaultCheLogLevel)
|
cheLogLevel := util.GetValue(cr.Spec.Server.CheLogLevel, DefaultCheLogLevel)
|
||||||
cheDebug := util.GetValue(cr.Spec.Server.CheDebug, DefaultCheDebug)
|
cheDebug := util.GetValue(cr.Spec.Server.CheDebug, DefaultCheDebug)
|
||||||
cheMetrics := strconv.FormatBool(cr.Spec.Metrics.Enable)
|
cheMetrics := strconv.FormatBool(cr.Spec.Metrics.Enable)
|
||||||
cheLabels := util.MapToKeyValuePairs(GetLabels(cr, cheFlavor))
|
cheLabels := util.MapToKeyValuePairs(GetLabels(cr, DefaultCheFlavor(cr)))
|
||||||
cheMultiUser := GetCheMultiUser(cr)
|
cheMultiUser := GetCheMultiUser(cr)
|
||||||
|
|
||||||
data := &CheConfigMap{
|
data := &CheConfigMap{
|
||||||
|
|
@ -248,8 +195,8 @@ func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
|
||||||
WorkspaceJavaOpts: DefaultWorkspaceJavaOpts + " " + proxyJavaOpts,
|
WorkspaceJavaOpts: DefaultWorkspaceJavaOpts + " " + proxyJavaOpts,
|
||||||
WorkspaceMavenOpts: DefaultWorkspaceJavaOpts + " " + proxyJavaOpts,
|
WorkspaceMavenOpts: DefaultWorkspaceJavaOpts + " " + proxyJavaOpts,
|
||||||
WorkspaceProxyJavaOpts: proxyJavaOpts,
|
WorkspaceProxyJavaOpts: proxyJavaOpts,
|
||||||
WorkspaceHttpProxy: cheWorkspaceHttpProxy,
|
WorkspaceHttpProxy: proxy.HttpProxy,
|
||||||
WorkspaceHttpsProxy: cheWorkspaceHttpProxy,
|
WorkspaceHttpsProxy: proxy.HttpsProxy,
|
||||||
WorkspaceNoProxy: cheWorkspaceNoProxy,
|
WorkspaceNoProxy: cheWorkspaceNoProxy,
|
||||||
PluginRegistryUrl: pluginRegistryUrl,
|
PluginRegistryUrl: pluginRegistryUrl,
|
||||||
DevfileRegistryUrl: devfileRegistryUrl,
|
DevfileRegistryUrl: devfileRegistryUrl,
|
||||||
|
|
@ -295,44 +242,3 @@ func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
|
||||||
addMap(cheEnv, cr.Spec.Server.CustomCheProperties)
|
addMap(cheEnv, cr.Spec.Server.CustomCheProperties)
|
||||||
return cheEnv
|
return cheEnv
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSpecConfigMap(checluster *orgv1.CheCluster, cheEnv map[string]string, clusterAPI ClusterAPI) (*corev1.ConfigMap, error) {
|
|
||||||
labels := GetLabels(checluster, DefaultCheFlavor(checluster))
|
|
||||||
configMap := &corev1.ConfigMap{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: "ConfigMap",
|
|
||||||
APIVersion: "v1",
|
|
||||||
},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: CheConfigMapName,
|
|
||||||
Namespace: checluster.Namespace,
|
|
||||||
Labels: labels,
|
|
||||||
},
|
|
||||||
Data: cheEnv,
|
|
||||||
}
|
|
||||||
|
|
||||||
if !util.IsTestMode() {
|
|
||||||
err := controllerutil.SetControllerReference(checluster, configMap, clusterAPI.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return configMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getClusterConfigMap(name string, namespace string, client runtimeClient.Client) (*corev1.ConfigMap, error) {
|
|
||||||
configMap := &corev1.ConfigMap{}
|
|
||||||
namespacedName := types.NamespacedName{
|
|
||||||
Namespace: namespace,
|
|
||||||
Name: name,
|
|
||||||
}
|
|
||||||
err := client.Get(context.TODO(), namespacedName, configMap)
|
|
||||||
if err != nil {
|
|
||||||
if errors.IsNotFound(err) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return configMap, nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ func TestNewCheConfigMap(t *testing.T) {
|
||||||
cr.Spec.Server.CheHost = "myhostname.com"
|
cr.Spec.Server.CheHost = "myhostname.com"
|
||||||
cr.Spec.Server.TlsSupport = true
|
cr.Spec.Server.TlsSupport = true
|
||||||
cr.Spec.Auth.OpenShiftoAuth = true
|
cr.Spec.Auth.OpenShiftoAuth = true
|
||||||
cheEnv := GetConfigMapData(cr)
|
cheEnv := GetCheConfigMapData(cr, &Proxy{})
|
||||||
testCm, _ := GetSpecConfigMap(cr, cheEnv, ClusterAPI{})
|
testCm, _ := GetSpecConfigMap(cr, CheConfigMapName, cheEnv, ClusterAPI{})
|
||||||
identityProvider := testCm.Data["CHE_INFRA_OPENSHIFT_OAUTH__IDENTITY__PROVIDER"]
|
identityProvider := testCm.Data["CHE_INFRA_OPENSHIFT_OAUTH__IDENTITY__PROVIDER"]
|
||||||
_, isOpenshiftv4, _ := util.DetectOpenShift()
|
_, isOpenshiftv4, _ := util.DetectOpenShift()
|
||||||
protocol := strings.Split(testCm.Data["CHE_API"], "://")[0]
|
protocol := strings.Split(testCm.Data["CHE_API"], "://")[0]
|
||||||
|
|
@ -53,8 +53,8 @@ func TestConfigMapOverride(t *testing.T) {
|
||||||
"CHE_WORKSPACE_NO_PROXY": "myproxy.myhostname.com",
|
"CHE_WORKSPACE_NO_PROXY": "myproxy.myhostname.com",
|
||||||
}
|
}
|
||||||
cr.Spec.Auth.OpenShiftoAuth = true
|
cr.Spec.Auth.OpenShiftoAuth = true
|
||||||
cheEnv := GetConfigMapData(cr)
|
cheEnv := GetCheConfigMapData(cr, &Proxy{})
|
||||||
testCm, _ := GetSpecConfigMap(cr, cheEnv, ClusterAPI{})
|
testCm, _ := GetSpecConfigMap(cr, CheConfigMapName, cheEnv, ClusterAPI{})
|
||||||
if testCm.Data["CHE_WORKSPACE_NO_PROXY"] != "myproxy.myhostname.com" {
|
if testCm.Data["CHE_WORKSPACE_NO_PROXY"] != "myproxy.myhostname.com" {
|
||||||
t.Errorf("Test failed. Expected myproxy.myhostname.com but was %s", testCm.Data["CHE_WORKSPACE_NO_PROXY"])
|
t.Errorf("Test failed. Expected myproxy.myhostname.com but was %s", testCm.Data["CHE_WORKSPACE_NO_PROXY"])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 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 deploy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||||
|
"github.com/eclipse/che-operator/pkg/util"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
runtimeClient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SyncConfigMapToCluster(checluster *orgv1.CheCluster, specConfigMap *corev1.ConfigMap, clusterAPI ClusterAPI) (*corev1.ConfigMap, error) {
|
||||||
|
clusterConfigMap, err := getClusterConfigMap(specConfigMap.Name, specConfigMap.Namespace, clusterAPI.Client)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if clusterConfigMap == nil {
|
||||||
|
logrus.Infof("Creating a new object: %s, name %s", specConfigMap.Kind, specConfigMap.Name)
|
||||||
|
err := clusterAPI.Client.Create(context.TODO(), specConfigMap)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := cmp.Diff(clusterConfigMap.Data, specConfigMap.Data)
|
||||||
|
if len(diff) > 0 {
|
||||||
|
logrus.Infof("Updating existed object: %s, name: %s", specConfigMap.Kind, specConfigMap.Name)
|
||||||
|
fmt.Printf("Difference:\n%s", diff)
|
||||||
|
clusterConfigMap.Data = specConfigMap.Data
|
||||||
|
err := clusterAPI.Client.Update(context.TODO(), clusterConfigMap)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return clusterConfigMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSpecConfigMap(
|
||||||
|
checluster *orgv1.CheCluster,
|
||||||
|
name string,
|
||||||
|
data map[string]string,
|
||||||
|
clusterAPI ClusterAPI) (*corev1.ConfigMap, error) {
|
||||||
|
|
||||||
|
labels := GetLabels(checluster, DefaultCheFlavor(checluster))
|
||||||
|
configMap := &corev1.ConfigMap{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "ConfigMap",
|
||||||
|
APIVersion: "v1",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: checluster.Namespace,
|
||||||
|
Labels: labels,
|
||||||
|
},
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !util.IsTestMode() {
|
||||||
|
err := controllerutil.SetControllerReference(checluster, configMap, clusterAPI.Scheme)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return configMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getClusterConfigMap(name string, namespace string, client runtimeClient.Client) (*corev1.ConfigMap, error) {
|
||||||
|
configMap := &corev1.ConfigMap{}
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
err := client.Get(context.TODO(), namespacedName, configMap)
|
||||||
|
if err != nil {
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return configMap, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 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 deploy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
injector = "config.openshift.io/inject-trusted-cabundle"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SyncTrustStoreConfigMapToCluster(checluster *orgv1.CheCluster, clusterAPI ClusterAPI) (*corev1.ConfigMap, error) {
|
||||||
|
name := checluster.Spec.Server.ServerTrustStoreConfigMapName
|
||||||
|
specConfigMap, err := GetSpecConfigMap(checluster, name, map[string]string{}, clusterAPI)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenShift will automatically injects all certs into the configmap
|
||||||
|
specConfigMap.ObjectMeta.Labels[injector] = "true"
|
||||||
|
|
||||||
|
clusterConfigMap, err := getClusterConfigMap(specConfigMap.Name, specConfigMap.Namespace, clusterAPI.Client)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if clusterConfigMap == nil {
|
||||||
|
logrus.Infof("Creating a new object: %s, name %s", specConfigMap.Kind, specConfigMap.Name)
|
||||||
|
err := clusterAPI.Client.Create(context.TODO(), specConfigMap)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if clusterConfigMap.ObjectMeta.Labels[injector] != "true" {
|
||||||
|
clusterConfigMap.ObjectMeta.Labels[injector] = "true"
|
||||||
|
logrus.Infof("Updating existed object: %s, name: %s", specConfigMap.Kind, specConfigMap.Name)
|
||||||
|
err := clusterAPI.Client.Update(context.TODO(), clusterConfigMap)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return clusterConfigMap, nil
|
||||||
|
}
|
||||||
|
|
@ -27,3 +27,20 @@ type ClusterAPI struct {
|
||||||
Client client.Client
|
Client client.Client
|
||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Proxy struct {
|
||||||
|
HttpProxy string
|
||||||
|
HttpUser string
|
||||||
|
HttpPassword string
|
||||||
|
HttpHost string
|
||||||
|
HttpPort string
|
||||||
|
|
||||||
|
HttpsProxy string
|
||||||
|
HttpsUser string
|
||||||
|
HttpsPassword string
|
||||||
|
HttpsHost string
|
||||||
|
HttpsPort string
|
||||||
|
|
||||||
|
NoProxy string
|
||||||
|
TrustedCAMapName string
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,10 @@ func MigratingToCRW2_0(cr *orgv1.CheCluster) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DefaultServerTrustStoreConfigMapName() string {
|
||||||
|
return getDefaultFromEnv("CHE_SERVER_TRUST_STORE_CONFIGMAP_NAME")
|
||||||
|
}
|
||||||
|
|
||||||
func DefaultCheFlavor(cr *orgv1.CheCluster) string {
|
func DefaultCheFlavor(cr *orgv1.CheCluster) string {
|
||||||
return util.GetValue(cr.Spec.Server.CheFlavor, getDefaultFromEnv("CHE_FLAVOR"))
|
return util.GetValue(cr.Spec.Server.CheFlavor, getDefaultFromEnv("CHE_FLAVOR"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SyncCheDeploymentToCluster(checluster *orgv1.CheCluster, cmResourceVersion string, clusterAPI ClusterAPI) DeploymentProvisioningStatus {
|
func SyncCheDeploymentToCluster(checluster *orgv1.CheCluster, cmResourceVersion string, proxy *Proxy, clusterAPI ClusterAPI) DeploymentProvisioningStatus {
|
||||||
clusterDeployment, err := getClusterDeployment(DefaultCheFlavor(checluster), checluster.Namespace, clusterAPI.Client)
|
clusterDeployment, err := getClusterDeployment(DefaultCheFlavor(checluster), checluster.Namespace, clusterAPI.Client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DeploymentProvisioningStatus{
|
return DeploymentProvisioningStatus{
|
||||||
|
|
@ -33,7 +33,7 @@ func SyncCheDeploymentToCluster(checluster *orgv1.CheCluster, cmResourceVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
specDeployment, err := getSpecCheDeployment(checluster, cmResourceVersion, clusterAPI)
|
specDeployment, err := getSpecCheDeployment(checluster, cmResourceVersion, proxy, clusterAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DeploymentProvisioningStatus{
|
return DeploymentProvisioningStatus{
|
||||||
ProvisioningStatus: ProvisioningStatus{Err: err},
|
ProvisioningStatus: ProvisioningStatus{Err: err},
|
||||||
|
|
@ -43,13 +43,13 @@ func SyncCheDeploymentToCluster(checluster *orgv1.CheCluster, cmResourceVersion
|
||||||
return SyncDeploymentToCluster(checluster, specDeployment, clusterDeployment, nil, nil, clusterAPI)
|
return SyncDeploymentToCluster(checluster, specDeployment, clusterDeployment, nil, nil, clusterAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSpecCheDeployment(checluster *orgv1.CheCluster, cmResourceVersion string, clusterAPI ClusterAPI) (*appsv1.Deployment, error) {
|
func getSpecCheDeployment(checluster *orgv1.CheCluster, cmResourceVersion string, proxy *Proxy, clusterAPI ClusterAPI) (*appsv1.Deployment, error) {
|
||||||
isOpenShift, _, err := util.DetectOpenShift()
|
isOpenShift, _, err := util.DetectOpenShift()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
selfSignedCertUsed, err := IsSelfSignedCertificateUsed(checluster, clusterAPI)
|
selfSignedCertUsed, err := IsSelfSignedCertificateUsed(checluster, proxy, clusterAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func SyncKeycloakDeploymentToCluster(checluster *orgv1.CheCluster, clusterAPI ClusterAPI) DeploymentProvisioningStatus {
|
func SyncKeycloakDeploymentToCluster(checluster *orgv1.CheCluster, proxy *Proxy, clusterAPI ClusterAPI) DeploymentProvisioningStatus {
|
||||||
clusterDeployment, err := getClusterDeployment(KeycloakDeploymentName, checluster.Namespace, clusterAPI.Client)
|
clusterDeployment, err := getClusterDeployment(KeycloakDeploymentName, checluster.Namespace, clusterAPI.Client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DeploymentProvisioningStatus{
|
return DeploymentProvisioningStatus{
|
||||||
|
|
@ -64,7 +64,7 @@ func SyncKeycloakDeploymentToCluster(checluster *orgv1.CheCluster, clusterAPI Cl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
specDeployment, err := getSpecKeycloakDeployment(checluster, clusterDeployment, clusterAPI)
|
specDeployment, err := getSpecKeycloakDeployment(checluster, clusterDeployment, proxy, clusterAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DeploymentProvisioningStatus{
|
return DeploymentProvisioningStatus{
|
||||||
ProvisioningStatus: ProvisioningStatus{Err: err},
|
ProvisioningStatus: ProvisioningStatus{Err: err},
|
||||||
|
|
@ -74,7 +74,11 @@ func SyncKeycloakDeploymentToCluster(checluster *orgv1.CheCluster, clusterAPI Cl
|
||||||
return SyncDeploymentToCluster(checluster, specDeployment, clusterDeployment, keycloakCustomDiffOpts, keycloakAdditionalDeploymentMerge, clusterAPI)
|
return SyncDeploymentToCluster(checluster, specDeployment, clusterDeployment, keycloakCustomDiffOpts, keycloakAdditionalDeploymentMerge, clusterAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSpecKeycloakDeployment(checluster *orgv1.CheCluster, clusterDeployment *appsv1.Deployment, clusterAPI ClusterAPI) (*appsv1.Deployment, error) {
|
func getSpecKeycloakDeployment(
|
||||||
|
checluster *orgv1.CheCluster,
|
||||||
|
clusterDeployment *appsv1.Deployment,
|
||||||
|
proxy *Proxy,
|
||||||
|
clusterAPI ClusterAPI) (*appsv1.Deployment, error) {
|
||||||
optionalEnv := true
|
optionalEnv := true
|
||||||
labels := GetLabels(checluster, KeycloakDeploymentName)
|
labels := GetLabels(checluster, KeycloakDeploymentName)
|
||||||
cheFlavor := DefaultCheFlavor(checluster)
|
cheFlavor := DefaultCheFlavor(checluster)
|
||||||
|
|
@ -164,29 +168,29 @@ func getSpecKeycloakDeployment(checluster *orgv1.CheCluster, clusterDeployment *
|
||||||
applyProxyCliCommand := ""
|
applyProxyCliCommand := ""
|
||||||
proxyEnvVars := []corev1.EnvVar{}
|
proxyEnvVars := []corev1.EnvVar{}
|
||||||
|
|
||||||
if len(checluster.Spec.Server.ProxyURL) > 1 {
|
if proxy.HttpProxy != "" {
|
||||||
proxySecret := checluster.Spec.Server.ProxySecret
|
|
||||||
cheWorkspaceHttpProxy, cheWorkspaceNoProxy, err := util.GenerateProxyEnvs(checluster.Spec.Server.ProxyURL, checluster.Spec.Server.ProxyPort, checluster.Spec.Server.NonProxyHosts, checluster.Spec.Server.ProxyUser, checluster.Spec.Server.ProxyPassword, proxySecret, checluster.Namespace)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("Failed to read '%s' secret: %v", proxySecret, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyEnvVars = []corev1.EnvVar{
|
proxyEnvVars = []corev1.EnvVar{
|
||||||
corev1.EnvVar{
|
corev1.EnvVar{
|
||||||
Name: "HTTP_PROXY",
|
Name: "HTTP_PROXY",
|
||||||
Value: cheWorkspaceHttpProxy,
|
Value: proxy.HttpProxy,
|
||||||
},
|
},
|
||||||
corev1.EnvVar{
|
corev1.EnvVar{
|
||||||
Name: "HTTPS_PROXY",
|
Name: "HTTPS_PROXY",
|
||||||
Value: cheWorkspaceHttpProxy,
|
Value: proxy.HttpsProxy,
|
||||||
},
|
},
|
||||||
corev1.EnvVar{
|
corev1.EnvVar{
|
||||||
Name: "NO_PROXY",
|
Name: "NO_PROXY",
|
||||||
Value: cheWorkspaceNoProxy,
|
Value: proxy.NoProxy,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cheWorkspaceNoProxy = strings.ReplaceAll(regexp.QuoteMeta(cheWorkspaceNoProxy), "\\", "\\\\\\")
|
quotedNoProxy := ""
|
||||||
|
for _, noProxyHost := range strings.Split(proxy.NoProxy, ",") {
|
||||||
|
if len(quotedNoProxy) != 0 {
|
||||||
|
quotedNoProxy += ","
|
||||||
|
}
|
||||||
|
quotedNoProxy += "\"" + strings.ReplaceAll(regexp.QuoteMeta(noProxyHost), "\\", "\\\\\\") + ";NO_PROXY\""
|
||||||
|
}
|
||||||
|
|
||||||
jbossCli := "/opt/jboss/keycloak/bin/jboss-cli.sh"
|
jbossCli := "/opt/jboss/keycloak/bin/jboss-cli.sh"
|
||||||
serverConfig := "standalone.xml"
|
serverConfig := "standalone.xml"
|
||||||
|
|
@ -196,7 +200,7 @@ func getSpecKeycloakDeployment(checluster *orgv1.CheCluster, clusterDeployment *
|
||||||
}
|
}
|
||||||
addProxyCliCommand = " && echo Configuring Proxy && " +
|
addProxyCliCommand = " && echo Configuring Proxy && " +
|
||||||
"echo -e 'embed-server --server-config=" + serverConfig + " --std-out=echo \n" +
|
"echo -e 'embed-server --server-config=" + serverConfig + " --std-out=echo \n" +
|
||||||
"/subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:write-attribute(name=properties.proxy-mappings,value=[\"" + cheWorkspaceNoProxy + ";NO_PROXY\",\".*;" + cheWorkspaceHttpProxy + "\"]) \n" +
|
"/subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:write-attribute(name=properties.proxy-mappings,value=[" + quotedNoProxy + ",\".*;" + proxy.HttpProxy + "\"]) \n" +
|
||||||
"stop-embedded-server' > " + jbossDir + "/setup-http-proxy.cli"
|
"stop-embedded-server' > " + jbossDir + "/setup-http-proxy.cli"
|
||||||
|
|
||||||
applyProxyCliCommand = " && " + jbossCli + " --file=" + jbossDir + "/setup-http-proxy.cli"
|
applyProxyCliCommand = " && " + jbossCli + " --file=" + jbossDir + "/setup-http-proxy.cli"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 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 deploy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/eclipse/che-operator/pkg/util"
|
||||||
|
|
||||||
|
"golang.org/x/net/http/httpproxy"
|
||||||
|
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||||
|
configv1 "github.com/openshift/api/config/v1"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ReadClusterWideProxyConfiguration(clusterProxy *configv1.Proxy, noProxy string) (*Proxy, error) {
|
||||||
|
proxy := &Proxy{}
|
||||||
|
|
||||||
|
// Cluster components consume the status values to configure the proxy for their component.
|
||||||
|
proxy.HttpProxy = clusterProxy.Status.HTTPProxy
|
||||||
|
proxy.HttpsProxy = clusterProxy.Status.HTTPSProxy
|
||||||
|
if len(proxy.HttpsProxy) == 0 {
|
||||||
|
proxy.HttpsProxy = proxy.HttpProxy
|
||||||
|
}
|
||||||
|
proxy.NoProxy = clusterProxy.Status.NoProxy
|
||||||
|
if proxy.NoProxy == "" {
|
||||||
|
proxy.NoProxy = noProxy
|
||||||
|
} else if noProxy != "" {
|
||||||
|
proxy.NoProxy += "," + noProxy
|
||||||
|
}
|
||||||
|
|
||||||
|
httpProxy, err := url.Parse(proxy.HttpProxy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
proxy.HttpHost = httpProxy.Hostname()
|
||||||
|
proxy.HttpPort = httpProxy.Port()
|
||||||
|
proxy.HttpUser = httpProxy.User.Username()
|
||||||
|
proxy.HttpPassword, _ = httpProxy.User.Password()
|
||||||
|
|
||||||
|
httpsProxy, err := url.Parse(proxy.HttpsProxy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
proxy.HttpsHost = httpsProxy.Hostname()
|
||||||
|
proxy.HttpsPort = httpsProxy.Port()
|
||||||
|
proxy.HttpsUser = httpsProxy.User.Username()
|
||||||
|
proxy.HttpsPassword, _ = httpsProxy.User.Password()
|
||||||
|
proxy.TrustedCAMapName = clusterProxy.Spec.TrustedCA.Name
|
||||||
|
|
||||||
|
return proxy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadCheClusterProxyConfiguration(checluster *orgv1.CheCluster) (*Proxy, error) {
|
||||||
|
proxyParts := strings.Split(checluster.Spec.Server.ProxyURL, "://")
|
||||||
|
proxyProtocol := ""
|
||||||
|
proxyHost := ""
|
||||||
|
if len(proxyParts) == 1 {
|
||||||
|
proxyProtocol = ""
|
||||||
|
proxyHost = proxyParts[0]
|
||||||
|
} else {
|
||||||
|
proxyProtocol = proxyParts[0]
|
||||||
|
proxyHost = proxyParts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyURL := proxyHost
|
||||||
|
if checluster.Spec.Server.ProxyPort != "" {
|
||||||
|
proxyURL = proxyURL + ":" + checluster.Spec.Server.ProxyPort
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyUser := checluster.Spec.Server.ProxyUser
|
||||||
|
proxyPassword := checluster.Spec.Server.ProxyPassword
|
||||||
|
proxySecret := checluster.Spec.Server.ProxySecret
|
||||||
|
if len(proxySecret) > 0 {
|
||||||
|
user, password, err := util.K8sclient.ReadSecret(proxySecret, checluster.Namespace)
|
||||||
|
if err == nil {
|
||||||
|
proxyUser = user
|
||||||
|
proxyPassword = password
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(proxyUser) > 1 && len(proxyPassword) > 1 {
|
||||||
|
proxyURL = proxyUser + ":" + proxyPassword + "@" + proxyURL
|
||||||
|
}
|
||||||
|
|
||||||
|
if proxyProtocol != "" {
|
||||||
|
proxyURL = proxyProtocol + "://" + proxyURL
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Proxy{
|
||||||
|
HttpProxy: proxyURL,
|
||||||
|
HttpUser: proxyUser,
|
||||||
|
HttpHost: proxyHost,
|
||||||
|
HttpPort: checluster.Spec.Server.ProxyPort,
|
||||||
|
HttpPassword: proxyPassword,
|
||||||
|
|
||||||
|
HttpsProxy: proxyURL,
|
||||||
|
HttpsUser: proxyUser,
|
||||||
|
HttpsHost: proxyHost,
|
||||||
|
HttpsPort: checluster.Spec.Server.ProxyPort,
|
||||||
|
HttpsPassword: proxyPassword,
|
||||||
|
|
||||||
|
NoProxy: strings.Replace(checluster.Spec.Server.NonProxyHosts, "|", ",", -1),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateProxyJavaOpts(proxy *Proxy, noProxy string) (javaOpts string, err error) {
|
||||||
|
if noProxy == "" {
|
||||||
|
noProxy = proxy.NoProxy
|
||||||
|
}
|
||||||
|
noProxy = strings.Replace(noProxy, ",", "|", -1)
|
||||||
|
|
||||||
|
proxyUserPassword := ""
|
||||||
|
if len(proxy.HttpUser) > 1 && len(proxy.HttpPassword) > 1 {
|
||||||
|
proxyUserPassword = " -Dhttp.proxyUser=" + proxy.HttpUser + " -Dhttp.proxyPassword=" + proxy.HttpPassword +
|
||||||
|
" -Dhttps.proxyUser=" + proxy.HttpsUser + " -Dhttps.proxyPassword=" + proxy.HttpsPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
javaOpts =
|
||||||
|
" -Dhttp.proxyHost=" + removeProtocolPrefix(proxy.HttpHost) + " -Dhttp.proxyPort=" + proxy.HttpPort +
|
||||||
|
" -Dhttps.proxyHost=" + removeProtocolPrefix(proxy.HttpsHost) + " -Dhttps.proxyPort=" + proxy.HttpsPort +
|
||||||
|
" -Dhttp.nonProxyHosts='" + noProxy + "'" + proxyUserPassword
|
||||||
|
return javaOpts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeProtocolPrefix(url string) string {
|
||||||
|
if strings.HasPrefix(url, "https://") {
|
||||||
|
return strings.TrimPrefix(url, "https://")
|
||||||
|
} else if strings.HasPrefix(url, "http://") {
|
||||||
|
return strings.TrimPrefix(url, "http://")
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConfigureProxy(instance *orgv1.CheCluster, transport *http.Transport, proxy *Proxy) {
|
||||||
|
config := httpproxy.Config{
|
||||||
|
HTTPProxy: proxy.HttpProxy,
|
||||||
|
HTTPSProxy: proxy.HttpsProxy,
|
||||||
|
NoProxy: proxy.NoProxy,
|
||||||
|
}
|
||||||
|
proxyFunc := config.ProxyFunc()
|
||||||
|
transport.Proxy = func(r *http.Request) (*url.URL, error) {
|
||||||
|
theProxyUrl, err := proxyFunc(r.URL)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("Error when trying to get the proxy to access TLS endpoint URL: %s - %s", r.URL, err)
|
||||||
|
}
|
||||||
|
if theProxyUrl != nil {
|
||||||
|
logrus.Infof("Using proxy: %s to access TLS endpoint URL: %s", theProxyUrl, r.URL)
|
||||||
|
} else {
|
||||||
|
logrus.Infof("Proxy isn't used to access TLS endpoint URL: %s", r.URL)
|
||||||
|
}
|
||||||
|
return theProxyUrl, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,261 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 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 deploy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||||
|
configv1 "github.com/openshift/api/config/v1"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
expectedProxyURLWithUsernamePassword = "https://user:password@myproxy.com:1234"
|
||||||
|
expectedProxyURLWithoutUsernamePassword = "https://myproxy.com:1234"
|
||||||
|
expectedNoProxy = "localhost,myhost.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateProxyJavaOpts(t *testing.T) {
|
||||||
|
proxy := &Proxy{
|
||||||
|
HttpProxy: "https://user:password@myproxy.com:1234",
|
||||||
|
HttpUser: "user",
|
||||||
|
HttpPassword: "password",
|
||||||
|
HttpHost: "myproxy.com",
|
||||||
|
HttpPort: "1234",
|
||||||
|
|
||||||
|
HttpsProxy: "https://user:password@myproxy.com:1234",
|
||||||
|
HttpsUser: "user",
|
||||||
|
HttpsPassword: "password",
|
||||||
|
HttpsHost: "myproxy.com",
|
||||||
|
HttpsPort: "1234",
|
||||||
|
|
||||||
|
NoProxy: "localhost,myhost.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Setenv("KUBERNETES_SERVICE_HOST", "172.30.0.1"); err != nil {
|
||||||
|
logrus.Errorf("Failed to set env %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
javaOpts, _ := GenerateProxyJavaOpts(proxy, "")
|
||||||
|
expectedJavaOpts := " -Dhttp.proxyHost=myproxy.com -Dhttp.proxyPort=1234 -Dhttps.proxyHost=myproxy.com " +
|
||||||
|
"-Dhttps.proxyPort=1234 -Dhttp.nonProxyHosts='localhost|myhost.com' -Dhttp.proxyUser=user " +
|
||||||
|
"-Dhttp.proxyPassword=password -Dhttps.proxyUser=user -Dhttps.proxyPassword=password"
|
||||||
|
if !reflect.DeepEqual(javaOpts, expectedJavaOpts) {
|
||||||
|
t.Errorf("Test failed. Expected '%s' but got '%s'", expectedJavaOpts, javaOpts)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy = &Proxy{
|
||||||
|
HttpProxy: "http://user:password@myproxy.com:1234",
|
||||||
|
HttpHost: "myproxy.com",
|
||||||
|
HttpPort: "1234",
|
||||||
|
|
||||||
|
HttpsProxy: "https://user:password@myproxy.com:1234",
|
||||||
|
HttpsHost: "myproxy.com",
|
||||||
|
HttpsPort: "1234",
|
||||||
|
|
||||||
|
NoProxy: "localhost,myhost.com",
|
||||||
|
}
|
||||||
|
javaOpts, _ = GenerateProxyJavaOpts(proxy, "test-no-proxy.com")
|
||||||
|
expectedJavaOptsWithoutUsernamePassword := " -Dhttp.proxyHost=myproxy.com -Dhttp.proxyPort=1234 -Dhttps.proxyHost=myproxy.com " +
|
||||||
|
"-Dhttps.proxyPort=1234 -Dhttp.nonProxyHosts='test-no-proxy.com'"
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(javaOpts, expectedJavaOptsWithoutUsernamePassword) {
|
||||||
|
t.Errorf("Test failed. Expected '%s' but got '%s'", expectedJavaOptsWithoutUsernamePassword, javaOpts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadCheClusterProxyConfiguration(t *testing.T) {
|
||||||
|
checluster := &orgv1.CheCluster{
|
||||||
|
Spec: orgv1.CheClusterSpec{
|
||||||
|
Server: orgv1.CheClusterSpecServer{
|
||||||
|
ProxyPassword: "password",
|
||||||
|
ProxyUser: "user",
|
||||||
|
ProxyPort: "1234",
|
||||||
|
ProxyURL: "https://myproxy.com",
|
||||||
|
NonProxyHosts: "host1|host2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expectedProxy := &Proxy{
|
||||||
|
HttpProxy: "https://user:password@myproxy.com:1234",
|
||||||
|
HttpUser: "user",
|
||||||
|
HttpPassword: "password",
|
||||||
|
HttpHost: "myproxy.com",
|
||||||
|
HttpPort: "1234",
|
||||||
|
|
||||||
|
HttpsProxy: "https://user:password@myproxy.com:1234",
|
||||||
|
HttpsUser: "user",
|
||||||
|
HttpsPassword: "password",
|
||||||
|
HttpsHost: "myproxy.com",
|
||||||
|
HttpsPort: "1234",
|
||||||
|
|
||||||
|
NoProxy: "host1,host2",
|
||||||
|
}
|
||||||
|
|
||||||
|
actualProxy, _ := ReadCheClusterProxyConfiguration(checluster)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actualProxy, expectedProxy) {
|
||||||
|
t.Errorf("Test failed. Expected '%v', but got '%v'", expectedProxy, actualProxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadCheClusterProxyConfigurationNoUser(t *testing.T) {
|
||||||
|
checluster := &orgv1.CheCluster{
|
||||||
|
Spec: orgv1.CheClusterSpec{
|
||||||
|
Server: orgv1.CheClusterSpecServer{
|
||||||
|
ProxyPort: "1234",
|
||||||
|
ProxyURL: "https://myproxy.com",
|
||||||
|
NonProxyHosts: "host1|host2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expectedProxy := &Proxy{
|
||||||
|
HttpProxy: "https://myproxy.com:1234",
|
||||||
|
HttpHost: "myproxy.com",
|
||||||
|
HttpPort: "1234",
|
||||||
|
|
||||||
|
HttpsProxy: "https://myproxy.com:1234",
|
||||||
|
HttpsHost: "myproxy.com",
|
||||||
|
HttpsPort: "1234",
|
||||||
|
|
||||||
|
NoProxy: "host1,host2",
|
||||||
|
}
|
||||||
|
|
||||||
|
actualProxy, _ := ReadCheClusterProxyConfiguration(checluster)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actualProxy, expectedProxy) {
|
||||||
|
t.Errorf("Test failed. Expected '%v', but got '%v'", expectedProxy, actualProxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadCheClusterProxyConfigurationNoPort(t *testing.T) {
|
||||||
|
checluster := &orgv1.CheCluster{
|
||||||
|
Spec: orgv1.CheClusterSpec{
|
||||||
|
Server: orgv1.CheClusterSpecServer{
|
||||||
|
ProxyPassword: "password",
|
||||||
|
ProxyUser: "user",
|
||||||
|
ProxyURL: "https://myproxy.com",
|
||||||
|
NonProxyHosts: "host1|host2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expectedProxy := &Proxy{
|
||||||
|
HttpProxy: "https://user:password@myproxy.com",
|
||||||
|
HttpUser: "user",
|
||||||
|
HttpPassword: "password",
|
||||||
|
HttpHost: "myproxy.com",
|
||||||
|
|
||||||
|
HttpsProxy: "https://user:password@myproxy.com",
|
||||||
|
HttpsUser: "user",
|
||||||
|
HttpsPassword: "password",
|
||||||
|
HttpsHost: "myproxy.com",
|
||||||
|
|
||||||
|
NoProxy: "host1,host2",
|
||||||
|
}
|
||||||
|
|
||||||
|
actualProxy, _ := ReadCheClusterProxyConfiguration(checluster)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actualProxy, expectedProxy) {
|
||||||
|
t.Errorf("Test failed. Expected '%v', but got '%v'", expectedProxy, actualProxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadClusterWideProxyConfiguration(t *testing.T) {
|
||||||
|
clusterProxy := &configv1.Proxy{
|
||||||
|
Status: configv1.ProxyStatus{
|
||||||
|
HTTPProxy: "http://user1:password1@myproxy1.com:1234",
|
||||||
|
HTTPSProxy: "https://user2:password2@myproxy2.com:2345",
|
||||||
|
NoProxy: "host1,host2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedProxy := &Proxy{
|
||||||
|
HttpProxy: "http://user1:password1@myproxy1.com:1234",
|
||||||
|
HttpUser: "user1",
|
||||||
|
HttpPassword: "password1",
|
||||||
|
HttpHost: "myproxy1.com",
|
||||||
|
HttpPort: "1234",
|
||||||
|
|
||||||
|
HttpsProxy: "https://user2:password2@myproxy2.com:2345",
|
||||||
|
HttpsUser: "user2",
|
||||||
|
HttpsPassword: "password2",
|
||||||
|
HttpsHost: "myproxy2.com",
|
||||||
|
HttpsPort: "2345",
|
||||||
|
|
||||||
|
NoProxy: "host1,host2",
|
||||||
|
}
|
||||||
|
|
||||||
|
actualProxy, _ := ReadClusterWideProxyConfiguration(clusterProxy, "")
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actualProxy, expectedProxy) {
|
||||||
|
t.Errorf("Test failed. Expected '%v', but got '%v'", expectedProxy, actualProxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadClusterWideProxyConfigurationNoUser(t *testing.T) {
|
||||||
|
clusterProxy := &configv1.Proxy{
|
||||||
|
Status: configv1.ProxyStatus{
|
||||||
|
HTTPProxy: "http://myproxy.com:1234",
|
||||||
|
NoProxy: "host1,host2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedProxy := &Proxy{
|
||||||
|
HttpProxy: "http://myproxy.com:1234",
|
||||||
|
HttpHost: "myproxy.com",
|
||||||
|
HttpPort: "1234",
|
||||||
|
|
||||||
|
HttpsProxy: "http://myproxy.com:1234",
|
||||||
|
NoProxy: "host1,host2",
|
||||||
|
HttpsHost: "myproxy.com",
|
||||||
|
HttpsPort: "1234",
|
||||||
|
}
|
||||||
|
|
||||||
|
actualProxy, _ := ReadClusterWideProxyConfiguration(clusterProxy, "")
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actualProxy, expectedProxy) {
|
||||||
|
t.Errorf("Test failed. Expected '%v', but got '%v'", expectedProxy, actualProxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadClusterWideProxyConfigurationNoPort(t *testing.T) {
|
||||||
|
clusterProxy := &configv1.Proxy{
|
||||||
|
Status: configv1.ProxyStatus{
|
||||||
|
HTTPProxy: "http://user:password@myproxy.com",
|
||||||
|
NoProxy: "host1,host2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedProxy := &Proxy{
|
||||||
|
HttpProxy: "http://user:password@myproxy.com",
|
||||||
|
HttpUser: "user",
|
||||||
|
HttpPassword: "password",
|
||||||
|
HttpHost: "myproxy.com",
|
||||||
|
|
||||||
|
HttpsProxy: "http://user:password@myproxy.com",
|
||||||
|
HttpsUser: "user",
|
||||||
|
HttpsPassword: "password",
|
||||||
|
HttpsHost: "myproxy.com",
|
||||||
|
|
||||||
|
NoProxy: "host1,host2,host3",
|
||||||
|
}
|
||||||
|
|
||||||
|
actualProxy, _ := ReadClusterWideProxyConfiguration(clusterProxy, "host3")
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actualProxy, expectedProxy) {
|
||||||
|
t.Errorf("Test failed. Expected '%v', but got '%v'", expectedProxy, actualProxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -50,7 +50,6 @@ func CreateDevfileRegistryConfigMap(cr *orgv1.CheCluster, endpoint string) *core
|
||||||
|
|
||||||
func CreatePluginRegistryConfigMap(cr *orgv1.CheCluster) *corev1.ConfigMap {
|
func CreatePluginRegistryConfigMap(cr *orgv1.CheCluster) *corev1.ConfigMap {
|
||||||
labels := GetLabels(cr, DefaultCheFlavor(cr))
|
labels := GetLabels(cr, DefaultCheFlavor(cr))
|
||||||
fmt.Println("Cr namespace " + cr.Namespace)
|
|
||||||
return &corev1.ConfigMap{
|
return &corev1.ConfigMap{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: "ConfigMap",
|
Kind: "ConfigMap",
|
||||||
|
|
|
||||||
|
|
@ -105,10 +105,10 @@ func GetSpecSecret(cr *orgv1.CheCluster, name string, data map[string][]byte) *c
|
||||||
// CreateTLSSecretFromRoute creates TLS secret with given name which contains certificates obtained from give url.
|
// CreateTLSSecretFromRoute creates TLS secret with given name which contains certificates obtained from give url.
|
||||||
// If the url is empty string, then router certificate will be obtained.
|
// If the url is empty string, then router certificate will be obtained.
|
||||||
// Works only on Openshift family infrastructures.
|
// Works only on Openshift family infrastructures.
|
||||||
func CreateTLSSecretFromRoute(checluster *orgv1.CheCluster, url string, name string, clusterAPI ClusterAPI) (err error) {
|
func CreateTLSSecretFromRoute(checluster *orgv1.CheCluster, url string, name string, proxy *Proxy, clusterAPI ClusterAPI) (err error) {
|
||||||
secret := &corev1.Secret{}
|
secret := &corev1.Secret{}
|
||||||
if err := clusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: checluster.Namespace}, secret); err != nil && errors.IsNotFound(err) {
|
if err := clusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: checluster.Namespace}, secret); err != nil && errors.IsNotFound(err) {
|
||||||
crtBytes, err := GetEndpointTLSCrtBytes(checluster, url, clusterAPI)
|
crtBytes, err := GetEndpointTLSCrtBytes(checluster, url, proxy, clusterAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Failed to extract certificate for secret %s. Failed to create a secret with a self signed crt: %s", name, err)
|
logrus.Errorf("Failed to extract certificate for secret %s. Failed to create a secret with a self signed crt: %s", name, err)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,12 @@ import (
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
stderrors "errors"
|
stderrors "errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||||
"github.com/eclipse/che-operator/pkg/util"
|
"github.com/eclipse/che-operator/pkg/util"
|
||||||
routev1 "github.com/openshift/api/route/v1"
|
routev1 "github.com/openshift/api/route/v1"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/http/httpproxy"
|
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
batchv1 "k8s.io/api/batch/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
|
@ -47,7 +44,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsSelfSignedCertificateUsed detects whether endpoints are/should be secured by self-signed certificate.
|
// IsSelfSignedCertificateUsed detects whether endpoints are/should be secured by self-signed certificate.
|
||||||
func IsSelfSignedCertificateUsed(checluster *orgv1.CheCluster, clusterAPI ClusterAPI) (bool, error) {
|
func IsSelfSignedCertificateUsed(checluster *orgv1.CheCluster, proxy *Proxy, clusterAPI ClusterAPI) (bool, error) {
|
||||||
if util.IsTestMode() {
|
if util.IsTestMode() {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +62,7 @@ func IsSelfSignedCertificateUsed(checluster *orgv1.CheCluster, clusterAPI Cluste
|
||||||
|
|
||||||
if util.IsOpenShift {
|
if util.IsOpenShift {
|
||||||
// Get router TLS certificates chain
|
// Get router TLS certificates chain
|
||||||
peerCertificates, err := GetEndpointTLSCrtChain(checluster, "", clusterAPI)
|
peerCertificates, err := GetEndpointTLSCrtChain(checluster, "", proxy, clusterAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +102,7 @@ func IsSelfSignedCertificateUsed(checluster *orgv1.CheCluster, clusterAPI Cluste
|
||||||
|
|
||||||
// GetEndpointTLSCrtChain retrieves TLS certificates chain from given endpoint.
|
// GetEndpointTLSCrtChain retrieves TLS certificates chain from given endpoint.
|
||||||
// If endpoint is not specified, then a test route will be created and used to get router certificates.
|
// If endpoint is not specified, then a test route will be created and used to get router certificates.
|
||||||
func GetEndpointTLSCrtChain(instance *orgv1.CheCluster, endpointURL string, clusterAPI ClusterAPI) ([]*x509.Certificate, error) {
|
func GetEndpointTLSCrtChain(instance *orgv1.CheCluster, endpointURL string, proxy *Proxy, clusterAPI ClusterAPI) ([]*x509.Certificate, error) {
|
||||||
if util.IsTestMode() {
|
if util.IsTestMode() {
|
||||||
return nil, stderrors.New("Not allowed for tests")
|
return nil, stderrors.New("Not allowed for tests")
|
||||||
}
|
}
|
||||||
|
|
@ -151,9 +148,9 @@ func GetEndpointTLSCrtChain(instance *orgv1.CheCluster, endpointURL string, clus
|
||||||
|
|
||||||
// Adding the proxy settings to the Transport object
|
// Adding the proxy settings to the Transport object
|
||||||
transport := &http.Transport{}
|
transport := &http.Transport{}
|
||||||
if instance.Spec.Server.ProxyURL != "" {
|
if proxy.HttpProxy != "" {
|
||||||
logrus.Infof("Configuring proxy with %s to extract crt from the following URL: %s", instance.Spec.Server.ProxyURL, requestURL)
|
logrus.Infof("Configuring proxy with %s to extract crt from the following URL: %s", proxy.HttpProxy, requestURL)
|
||||||
configureProxy(instance, transport)
|
ConfigureProxy(instance, transport, proxy)
|
||||||
}
|
}
|
||||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
|
|
@ -173,8 +170,8 @@ func GetEndpointTLSCrtChain(instance *orgv1.CheCluster, endpointURL string, clus
|
||||||
// GetEndpointTLSCrtBytes creates a test TLS route and gets it to extract certificate chain
|
// GetEndpointTLSCrtBytes creates a test TLS route and gets it to extract certificate chain
|
||||||
// There's an easier way which is to read tls secret in default (3.11) or openshift-ingress (4.0) namespace
|
// There's an easier way which is to read tls secret in default (3.11) or openshift-ingress (4.0) namespace
|
||||||
// which however requires extra privileges for operator service account
|
// which however requires extra privileges for operator service account
|
||||||
func GetEndpointTLSCrtBytes(instance *orgv1.CheCluster, endpointURL string, clusterAPI ClusterAPI) (certificates []byte, err error) {
|
func GetEndpointTLSCrtBytes(instance *orgv1.CheCluster, endpointURL string, proxy *Proxy, clusterAPI ClusterAPI) (certificates []byte, err error) {
|
||||||
peerCertificates, err := GetEndpointTLSCrtChain(instance, endpointURL, clusterAPI)
|
peerCertificates, err := GetEndpointTLSCrtChain(instance, endpointURL, proxy, clusterAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if util.IsTestMode() {
|
if util.IsTestMode() {
|
||||||
fakeCrt := make([]byte, 5)
|
fakeCrt := make([]byte, 5)
|
||||||
|
|
@ -195,57 +192,6 @@ func GetEndpointTLSCrtBytes(instance *orgv1.CheCluster, endpointURL string, clus
|
||||||
return certificates, nil
|
return certificates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureProxy(instance *orgv1.CheCluster, transport *http.Transport) {
|
|
||||||
proxyParts := strings.Split(instance.Spec.Server.ProxyURL, "://")
|
|
||||||
proxyProtocol := ""
|
|
||||||
proxyHost := ""
|
|
||||||
if len(proxyParts) == 1 {
|
|
||||||
proxyProtocol = ""
|
|
||||||
proxyHost = proxyParts[0]
|
|
||||||
} else {
|
|
||||||
proxyProtocol = proxyParts[0]
|
|
||||||
proxyHost = proxyParts[1]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyURL := proxyHost
|
|
||||||
if instance.Spec.Server.ProxyPort != "" {
|
|
||||||
proxyURL = proxyURL + ":" + instance.Spec.Server.ProxyPort
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyUser := instance.Spec.Server.ProxyUser
|
|
||||||
proxyPassword := instance.Spec.Server.ProxyPassword
|
|
||||||
proxySecret := instance.Spec.Server.ProxySecret
|
|
||||||
user, password, err := util.K8sclient.ReadSecret(proxySecret, instance.Namespace)
|
|
||||||
if err == nil {
|
|
||||||
proxyUser = user
|
|
||||||
proxyPassword = password
|
|
||||||
} else {
|
|
||||||
logrus.Errorf("Failed to read '%s' secret: %s", proxySecret, err)
|
|
||||||
}
|
|
||||||
if len(proxyUser) > 1 && len(proxyPassword) > 1 {
|
|
||||||
proxyURL = proxyUser + ":" + proxyPassword + "@" + proxyURL
|
|
||||||
}
|
|
||||||
|
|
||||||
if proxyProtocol != "" {
|
|
||||||
proxyURL = proxyProtocol + "://" + proxyURL
|
|
||||||
}
|
|
||||||
config := httpproxy.Config{
|
|
||||||
HTTPProxy: proxyURL,
|
|
||||||
HTTPSProxy: proxyURL,
|
|
||||||
NoProxy: strings.Replace(instance.Spec.Server.NonProxyHosts, "|", ",", -1),
|
|
||||||
}
|
|
||||||
proxyFunc := config.ProxyFunc()
|
|
||||||
transport.Proxy = func(r *http.Request) (*url.URL, error) {
|
|
||||||
theProxyURL, err := proxyFunc(r.URL)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Warnf("Error when trying to get the proxy to access TLS endpoint URL: %s - %s", r.URL, err)
|
|
||||||
}
|
|
||||||
logrus.Infof("Using proxy: %s to access TLS endpoint URL: %s", theProxyURL, r.URL)
|
|
||||||
return theProxyURL, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// K8sHandleCheTLSSecrets handles TLS secrets required for Che deployment on Kubernetes infrastructure.
|
// K8sHandleCheTLSSecrets handles TLS secrets required for Che deployment on Kubernetes infrastructure.
|
||||||
func K8sHandleCheTLSSecrets(checluster *orgv1.CheCluster, clusterAPI ClusterAPI) (reconcile.Result, error) {
|
func K8sHandleCheTLSSecrets(checluster *orgv1.CheCluster, clusterAPI ClusterAPI) (reconcile.Result, error) {
|
||||||
cheTLSSecretName := checluster.Spec.K8s.TlsSecretName
|
cheTLSSecretName := checluster.Spec.K8s.TlsSecretName
|
||||||
|
|
|
||||||
|
|
@ -243,62 +243,6 @@ func getClusterPublicHostnameForOpenshiftV4() (hostname string, err error) {
|
||||||
return hostname, nil
|
return hostname, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateProxyJavaOpts(proxyURL string, proxyPort string, nonProxyHosts string, proxyUser string, proxyPassword string, proxySecret string, namespace string) (javaOpts string, err error) {
|
|
||||||
if len(proxySecret) > 0 {
|
|
||||||
user, password, err := k8sclient.ReadSecret(proxySecret, namespace)
|
|
||||||
if err == nil {
|
|
||||||
proxyUser = user
|
|
||||||
proxyPassword = password
|
|
||||||
} else {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var proxyHost string
|
|
||||||
if strings.HasPrefix(proxyURL, "https://") {
|
|
||||||
proxyHost = strings.TrimPrefix(proxyURL, "https://")
|
|
||||||
} else if strings.HasPrefix(proxyURL, "http://") {
|
|
||||||
proxyHost = strings.TrimPrefix(proxyURL, "http://")
|
|
||||||
} else {
|
|
||||||
proxyHost = proxyURL
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyUserPassword := ""
|
|
||||||
if len(proxyUser) > 1 && len(proxyPassword) > 1 {
|
|
||||||
proxyUserPassword =
|
|
||||||
" -Dhttp.proxyUser=" + proxyUser + " -Dhttp.proxyPassword=" + proxyPassword +
|
|
||||||
" -Dhttps.proxyUser=" + proxyUser + " -Dhttps.proxyPassword=" + proxyPassword
|
|
||||||
}
|
|
||||||
javaOpts =
|
|
||||||
" -Dhttp.proxyHost=" + proxyHost + " -Dhttp.proxyPort=" + proxyPort +
|
|
||||||
" -Dhttps.proxyHost=" + proxyHost + " -Dhttps.proxyPort=" + proxyPort +
|
|
||||||
" -Dhttp.nonProxyHosts='" + nonProxyHosts + "'" + proxyUserPassword
|
|
||||||
return javaOpts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenerateProxyEnvs(proxyHost string, proxyPort string, nonProxyHosts string, proxyUser string, proxyPassword string, proxySecret string, namespace string) (proxyUrl string, noProxy string, err error) {
|
|
||||||
if len(proxySecret) > 0 {
|
|
||||||
user, password, err := k8sclient.ReadSecret(proxySecret, namespace)
|
|
||||||
if err == nil {
|
|
||||||
proxyUser = user
|
|
||||||
proxyPassword = password
|
|
||||||
} else {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyUrl = proxyHost + ":" + proxyPort
|
|
||||||
if len(proxyUser) > 1 && len(proxyPassword) > 1 {
|
|
||||||
protocol := strings.Split(proxyHost, "://")[0]
|
|
||||||
host := strings.Split(proxyHost, "://")[1]
|
|
||||||
proxyUrl = protocol + "://" + proxyUser + ":" + proxyPassword + "@" + host + ":" + proxyPort
|
|
||||||
}
|
|
||||||
|
|
||||||
noProxy = strings.Replace(nonProxyHosts, "|", ",", -1)
|
|
||||||
|
|
||||||
return proxyUrl, noProxy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDeploymentEnv(deployment *appsv1.Deployment, key string) (value string) {
|
func GetDeploymentEnv(deployment *appsv1.Deployment, key string) (value string) {
|
||||||
env := deployment.Spec.Template.Spec.Containers[0].Env
|
env := deployment.Spec.Template.Spec.Containers[0].Env
|
||||||
for i := range env {
|
for i := range env {
|
||||||
|
|
|
||||||
|
|
@ -12,73 +12,10 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
proxyHost = "https://myproxy.com"
|
|
||||||
proxyPort = "1234"
|
|
||||||
nonProxyHosts = "localhost|myhost.com"
|
|
||||||
proxyUser = "user"
|
|
||||||
proxyPassword = "password"
|
|
||||||
expectedProxyURLWithUsernamePassword = "https://user:password@myproxy.com:1234"
|
|
||||||
expectedProxyURLWithoutUsernamePassword = "https://myproxy.com:1234"
|
|
||||||
expectedNoProxy = "localhost,myhost.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGenerateProxyEnvs(t *testing.T) {
|
|
||||||
|
|
||||||
proxyUrl, noProxy, _ := GenerateProxyEnvs(proxyHost, proxyPort, nonProxyHosts, proxyUser, proxyPassword, "", "")
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(proxyUrl, expectedProxyURLWithUsernamePassword) {
|
|
||||||
t.Errorf("Test failed. Expected %s but got %s", expectedProxyURLWithUsernamePassword, proxyUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(noProxy, expectedNoProxy) {
|
|
||||||
t.Errorf("Test failed. Expected %s but got %s", expectedNoProxy, noProxy)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyUrl, _, _ = GenerateProxyEnvs(proxyHost, proxyPort, nonProxyHosts, "", proxyPassword, "", "")
|
|
||||||
if !reflect.DeepEqual(proxyUrl, expectedProxyURLWithoutUsernamePassword) {
|
|
||||||
t.Errorf("Test failed. Expected %s but got %s", expectedProxyURLWithoutUsernamePassword, proxyUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenerateProxyJavaOpts(t *testing.T) {
|
|
||||||
if err := os.Setenv("KUBERNETES_SERVICE_HOST", "172.30.0.1"); err != nil {
|
|
||||||
logrus.Errorf("Failed to set env %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
javaOpts, _ := GenerateProxyJavaOpts(proxyHost, proxyPort, nonProxyHosts, proxyUser, proxyPassword, "", "")
|
|
||||||
expectedJavaOpts := " -Dhttp.proxyHost=myproxy.com -Dhttp.proxyPort=1234 -Dhttps.proxyHost=myproxy.com " +
|
|
||||||
"-Dhttps.proxyPort=1234 -Dhttp.nonProxyHosts='localhost|myhost.com' -Dhttp.proxyUser=user " +
|
|
||||||
"-Dhttp.proxyPassword=password -Dhttps.proxyUser=user -Dhttps.proxyPassword=password"
|
|
||||||
if !reflect.DeepEqual(javaOpts, expectedJavaOpts) {
|
|
||||||
t.Errorf("Test failed. Expected '%s' but got '%s'", expectedJavaOpts, javaOpts)
|
|
||||||
}
|
|
||||||
|
|
||||||
javaOpts, _ = GenerateProxyJavaOpts(proxyHost, proxyPort, nonProxyHosts, "", proxyPassword, "", "")
|
|
||||||
expectedJavaOptsWithoutUsernamePassword := " -Dhttp.proxyHost=myproxy.com -Dhttp.proxyPort=1234 -Dhttps.proxyHost=myproxy.com " +
|
|
||||||
"-Dhttps.proxyPort=1234 -Dhttp.nonProxyHosts='localhost|myhost.com'"
|
|
||||||
if !reflect.DeepEqual(javaOpts, expectedJavaOptsWithoutUsernamePassword) {
|
|
||||||
t.Errorf("Test failed. Expected '%s' but got '%s'", expectedJavaOptsWithoutUsernamePassword, javaOpts)
|
|
||||||
}
|
|
||||||
|
|
||||||
javaOpts, _ = GenerateProxyJavaOpts("http://myproxy.com", proxyPort, nonProxyHosts, "", proxyPassword, "", "")
|
|
||||||
expectedJavaOptsWithoutUsernamePassword = " -Dhttp.proxyHost=myproxy.com -Dhttp.proxyPort=1234 -Dhttps.proxyHost=myproxy.com " +
|
|
||||||
"-Dhttps.proxyPort=1234 -Dhttp.nonProxyHosts='localhost|myhost.com'"
|
|
||||||
if !reflect.DeepEqual(javaOpts, expectedJavaOptsWithoutUsernamePassword) {
|
|
||||||
t.Errorf("Test failed. Expected '%s' but got '%s'", expectedJavaOptsWithoutUsernamePassword, javaOpts)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGeneratePasswd(t *testing.T) {
|
func TestGeneratePasswd(t *testing.T) {
|
||||||
chars := 12
|
chars := 12
|
||||||
passwd := GeneratePasswd(chars)
|
passwd := GeneratePasswd(chars)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue