Respect openshift cluster wide proxy (#272)

* Respect OpenShift cluster wide proxy

Signed-off-by: Anatoliy Bazko <abazko@redhat.com>
pull/330/head
Anatolii Bazko 2020-07-08 16:08:20 +03:00 committed by GitHub
parent adfe698031
commit 110149a5c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 2800 additions and 343 deletions

3
.vscode/launch.json vendored
View File

@ -50,7 +50,8 @@
"CONSOLE_LINK_IMAGE": "/dashboard/assets/branding/loader.svg",
"CHE_IDENTITY_SECRET": "che-identity-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}",
"args": [

View File

@ -30,8 +30,11 @@ rules:
resources:
- infrastructures
- oauths
- proxies
verbs:
- get
- list
- watch
- apiGroups:
- user.openshift.io
resources:

View File

@ -81,3 +81,5 @@ spec:
value: che-identity-postgres-secret
- name: CHE_POSTGRES_SECRET
value: che-postgres-secret
- name: CHE_SERVER_TRUST_STORE_CONFIGMAP_NAME
value: ca-certs

View File

@ -80,6 +80,8 @@ spec:
value: che-identity-postgres-secret
- name: CHE_POSTGRES_SECRET
value: che-postgres-secret
- name: CHE_SERVER_TRUST_STORE_CONFIGMAP_NAME
value: ca-certs
restartPolicy: Always
serviceAccountName: che-operator
terminationGracePeriodSeconds: 5

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
channels:
- currentCSV: eclipse-che-preview-kubernetes.v9.9.9-nightly.1594133420
- currentCSV: eclipse-che-preview-kubernetes.v9.9.9-nightly.1594209360
name: nightly
- currentCSV: eclipse-che-preview-kubernetes.v7.15.1
name: stable

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
channels:
- currentCSV: eclipse-che-preview-openshift.v9.9.9-nightly.1594133421
- currentCSV: eclipse-che-preview-openshift.v9.9.9-nightly.1594209361
name: nightly
- currentCSV: eclipse-che-preview-openshift.v7.15.1
name: stable

View File

@ -21,6 +21,7 @@ import (
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"
oauthv1 "github.com/openshift/api/config/v1"
consolev1 "github.com/openshift/api/console/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 {
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 err := consolev1.AddToScheme(mgr.GetScheme()); err != nil {
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)
cheDeploymentName := cheFlavor
@ -319,7 +343,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
// Detect whether self-signed certificate is used
selfSignedCertUsed, err := deploy.IsSelfSignedCertificateUsed(instance, clusterAPI)
selfSignedCertUsed, err := deploy.IsSelfSignedCertificateUsed(instance, proxy, clusterAPI)
if err != nil {
logrus.Errorf("Failed to detect if self-signed certificate used. Cause: %v", 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)
// 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) {
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
}
}
@ -353,7 +377,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
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")
} 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
}
}
@ -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 !deploymentStatus.Continue {
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)
return reconcile.Result{}, err
}
logrus.Info(" Updating plugin-registry ConfigMap")
logrus.Info("Updating plugin-registry ConfigMap")
err = r.client.Update(context.TODO(), pluginRegistryConfigMap)
if err != nil {
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
// controller will reconcile this CM with CR spec
cheEnv := deploy.GetConfigMapData(instance)
configMapStatus := deploy.SyncConfigMapToCluster(instance, cheEnv, clusterAPI)
cheConfigMap, err := deploy.SyncCheConfigMapToCluster(instance, proxy, clusterAPI)
if !tests {
if !configMapStatus.Continue {
logrus.Infof("Waiting on config map '%s' to be created", cheFlavor)
if configMapStatus.Err != nil {
logrus.Error(configMapStatus.Err)
if cheConfigMap == nil {
logrus.Infof("Waiting on config map '%s' to be created", deploy.CheConfigMapName)
if err != nil {
logrus.Error(err)
}
return reconcile.Result{Requeue: configMapStatus.Requeue}, configMapStatus.Err
return reconcile.Result{}, err
}
}
@ -1107,11 +1129,11 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
if tests {
cmResourceVersion = r.GetEffectiveConfigMap(instance, deploy.CheConfigMapName).ResourceVersion
} else {
cmResourceVersion = configMapStatus.ConfigMap.ResourceVersion
cmResourceVersion = cheConfigMap.ResourceVersion
}
// Create a new che deployment
deploymentStatus := deploy.SyncCheDeploymentToCluster(instance, cmResourceVersion, clusterAPI)
deploymentStatus := deploy.SyncCheDeploymentToCluster(instance, cmResourceVersion, proxy, clusterAPI)
if !tests {
if !deploymentStatus.Continue {
logrus.Infof("Waiting on deployment '%s' to be ready", cheFlavor)

View File

@ -135,9 +135,7 @@ func (r *ReconcileChe) GenerateAndSaveFields(instance *orgv1.CheCluster, request
if len(instance.Spec.Auth.IdentityProviderPostgresSecret) < 1 {
keycloakPostgresPassword := util.GeneratePasswd(12)
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
if err != nil {
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating passwd")
} else {
if err == nil {
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))
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
if err != nil {
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating admin username and password")
} else {
if err == nil {
keycloakAdminUserName = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_USERNAME")
keycloakAdminPassword = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_PASSWORD")
}

View File

@ -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
}

View File

@ -12,7 +12,6 @@
package deploy
import (
"context"
"encoding/json"
"fmt"
"os"
@ -20,14 +19,8 @@ import (
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"
)
const (
@ -83,54 +76,19 @@ type CheConfigMap struct {
CheJGroupsKubernetesLabels string `json:"KUBERNETES_LABELS,omitempty"`
}
type ConfigMapProvisioningStatus struct {
ProvisioningStatus
ConfigMap *corev1.ConfigMap
}
func SyncConfigMapToCluster(checluster *orgv1.CheCluster, cheEnv map[string]string, clusterAPI ClusterAPI) ConfigMapProvisioningStatus {
specConfigMap, err := GetSpecConfigMap(checluster, cheEnv, clusterAPI)
func SyncCheConfigMapToCluster(checluster *orgv1.CheCluster, proxy *Proxy, clusterAPI ClusterAPI) (*corev1.ConfigMap, error) {
data := GetCheConfigMapData(checluster, proxy)
specConfigMap, err := GetSpecConfigMap(checluster, CheConfigMapName, data, clusterAPI)
if err != nil {
return ConfigMapProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Err: err},
}
return nil, err
}
clusterConfigMap, err := getClusterConfigMap(specConfigMap.Name, specConfigMap.Namespace, clusterAPI.Client)
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,
}
return SyncConfigMapToCluster(checluster, specConfigMap, clusterAPI)
}
// 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
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
keycloakURL := cr.Spec.Auth.IdentityProviderURL
isOpenShift, isOpenshift4, err := util.DetectOpenShift()
@ -165,31 +123,20 @@ func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
wsprotocol = "wss"
tls = "true"
}
proxyJavaOpts := ""
proxyUser := cr.Spec.Server.ProxyUser
proxyPassword := cr.Spec.Server.ProxyPassword
proxySecret := cr.Spec.Server.ProxySecret
nonProxyHosts := cr.Spec.Server.NonProxyHosts
if len(nonProxyHosts) < 1 && len(cr.Spec.Server.ProxyURL) > 1 {
nonProxyHosts = os.Getenv("KUBERNETES_SERVICE_HOST")
} else {
nonProxyHosts = nonProxyHosts + "|" + os.Getenv("KUBERNETES_SERVICE_HOST")
}
if len(cr.Spec.Server.ProxyURL) > 1 {
proxyJavaOpts, err = util.GenerateProxyJavaOpts(cr.Spec.Server.ProxyURL, cr.Spec.Server.ProxyPort, nonProxyHosts, proxyUser, proxyPassword, proxySecret, cr.Namespace)
proxyJavaOpts := ""
cheWorkspaceNoProxy := proxy.NoProxy
if proxy.HttpProxy != "" {
if proxy.NoProxy == "" {
cheWorkspaceNoProxy = os.Getenv("KUBERNETES_SERVICE_HOST")
} else {
cheWorkspaceNoProxy = cheWorkspaceNoProxy + "," + os.Getenv("KUBERNETES_SERVICE_HOST")
}
proxyJavaOpts, err = GenerateProxyJavaOpts(proxy, cheWorkspaceNoProxy)
if err != nil {
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
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)
cheDebug := util.GetValue(cr.Spec.Server.CheDebug, DefaultCheDebug)
cheMetrics := strconv.FormatBool(cr.Spec.Metrics.Enable)
cheLabels := util.MapToKeyValuePairs(GetLabels(cr, cheFlavor))
cheLabels := util.MapToKeyValuePairs(GetLabels(cr, DefaultCheFlavor(cr)))
cheMultiUser := GetCheMultiUser(cr)
data := &CheConfigMap{
@ -248,8 +195,8 @@ func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
WorkspaceJavaOpts: DefaultWorkspaceJavaOpts + " " + proxyJavaOpts,
WorkspaceMavenOpts: DefaultWorkspaceJavaOpts + " " + proxyJavaOpts,
WorkspaceProxyJavaOpts: proxyJavaOpts,
WorkspaceHttpProxy: cheWorkspaceHttpProxy,
WorkspaceHttpsProxy: cheWorkspaceHttpProxy,
WorkspaceHttpProxy: proxy.HttpProxy,
WorkspaceHttpsProxy: proxy.HttpsProxy,
WorkspaceNoProxy: cheWorkspaceNoProxy,
PluginRegistryUrl: pluginRegistryUrl,
DevfileRegistryUrl: devfileRegistryUrl,
@ -295,44 +242,3 @@ func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
addMap(cheEnv, cr.Spec.Server.CustomCheProperties)
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
}

View File

@ -28,8 +28,8 @@ func TestNewCheConfigMap(t *testing.T) {
cr.Spec.Server.CheHost = "myhostname.com"
cr.Spec.Server.TlsSupport = true
cr.Spec.Auth.OpenShiftoAuth = true
cheEnv := GetConfigMapData(cr)
testCm, _ := GetSpecConfigMap(cr, cheEnv, ClusterAPI{})
cheEnv := GetCheConfigMapData(cr, &Proxy{})
testCm, _ := GetSpecConfigMap(cr, CheConfigMapName, cheEnv, ClusterAPI{})
identityProvider := testCm.Data["CHE_INFRA_OPENSHIFT_OAUTH__IDENTITY__PROVIDER"]
_, isOpenshiftv4, _ := util.DetectOpenShift()
protocol := strings.Split(testCm.Data["CHE_API"], "://")[0]
@ -53,8 +53,8 @@ func TestConfigMapOverride(t *testing.T) {
"CHE_WORKSPACE_NO_PROXY": "myproxy.myhostname.com",
}
cr.Spec.Auth.OpenShiftoAuth = true
cheEnv := GetConfigMapData(cr)
testCm, _ := GetSpecConfigMap(cr, cheEnv, ClusterAPI{})
cheEnv := GetCheConfigMapData(cr, &Proxy{})
testCm, _ := GetSpecConfigMap(cr, CheConfigMapName, cheEnv, ClusterAPI{})
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"])
}

98
pkg/deploy/configmap.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -27,3 +27,20 @@ type ClusterAPI struct {
Client client.Client
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
}

View File

@ -177,6 +177,10 @@ func MigratingToCRW2_0(cr *orgv1.CheCluster) bool {
return false
}
func DefaultServerTrustStoreConfigMapName() string {
return getDefaultFromEnv("CHE_SERVER_TRUST_STORE_CONFIGMAP_NAME")
}
func DefaultCheFlavor(cr *orgv1.CheCluster) string {
return util.GetValue(cr.Spec.Server.CheFlavor, getDefaultFromEnv("CHE_FLAVOR"))
}

View File

@ -25,7 +25,7 @@ import (
"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)
if err != nil {
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 {
return DeploymentProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Err: err},
@ -43,13 +43,13 @@ func SyncCheDeploymentToCluster(checluster *orgv1.CheCluster, cmResourceVersion
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()
if err != nil {
return nil, err
}
selfSignedCertUsed, err := IsSelfSignedCertificateUsed(checluster, clusterAPI)
selfSignedCertUsed, err := IsSelfSignedCertificateUsed(checluster, proxy, clusterAPI)
if err != nil {
return nil, err
}

View File

@ -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)
if err != nil {
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 {
return DeploymentProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Err: err},
@ -74,7 +74,11 @@ func SyncKeycloakDeploymentToCluster(checluster *orgv1.CheCluster, clusterAPI Cl
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
labels := GetLabels(checluster, KeycloakDeploymentName)
cheFlavor := DefaultCheFlavor(checluster)
@ -164,29 +168,29 @@ func getSpecKeycloakDeployment(checluster *orgv1.CheCluster, clusterDeployment *
applyProxyCliCommand := ""
proxyEnvVars := []corev1.EnvVar{}
if len(checluster.Spec.Server.ProxyURL) > 1 {
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)
}
if proxy.HttpProxy != "" {
proxyEnvVars = []corev1.EnvVar{
corev1.EnvVar{
Name: "HTTP_PROXY",
Value: cheWorkspaceHttpProxy,
Value: proxy.HttpProxy,
},
corev1.EnvVar{
Name: "HTTPS_PROXY",
Value: cheWorkspaceHttpProxy,
Value: proxy.HttpsProxy,
},
corev1.EnvVar{
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"
serverConfig := "standalone.xml"
@ -196,7 +200,7 @@ func getSpecKeycloakDeployment(checluster *orgv1.CheCluster, clusterDeployment *
}
addProxyCliCommand = " && echo Configuring Proxy && " +
"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"
applyProxyCliCommand = " && " + jbossCli + " --file=" + jbossDir + "/setup-http-proxy.cli"

171
pkg/deploy/proxy.go Normal file
View File

@ -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
}
}

261
pkg/deploy/proxy_test.go Normal file
View File

@ -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)
}
}

View File

@ -50,7 +50,6 @@ func CreateDevfileRegistryConfigMap(cr *orgv1.CheCluster, endpoint string) *core
func CreatePluginRegistryConfigMap(cr *orgv1.CheCluster) *corev1.ConfigMap {
labels := GetLabels(cr, DefaultCheFlavor(cr))
fmt.Println("Cr namespace " + cr.Namespace)
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",

View File

@ -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.
// If the url is empty string, then router certificate will be obtained.
// 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{}
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 {
logrus.Errorf("Failed to extract certificate for secret %s. Failed to create a secret with a self signed crt: %s", name, err)
return err

View File

@ -18,15 +18,12 @@ import (
"encoding/pem"
stderrors "errors"
"net/http"
"net/url"
"strings"
"time"
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
"github.com/eclipse/che-operator/pkg/util"
routev1 "github.com/openshift/api/route/v1"
"github.com/sirupsen/logrus"
"golang.org/x/net/http/httpproxy"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
@ -47,7 +44,7 @@ const (
)
// 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() {
return true, nil
}
@ -65,7 +62,7 @@ func IsSelfSignedCertificateUsed(checluster *orgv1.CheCluster, clusterAPI Cluste
if util.IsOpenShift {
// Get router TLS certificates chain
peerCertificates, err := GetEndpointTLSCrtChain(checluster, "", clusterAPI)
peerCertificates, err := GetEndpointTLSCrtChain(checluster, "", proxy, clusterAPI)
if err != nil {
return false, err
}
@ -105,7 +102,7 @@ func IsSelfSignedCertificateUsed(checluster *orgv1.CheCluster, clusterAPI Cluste
// 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.
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() {
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
transport := &http.Transport{}
if instance.Spec.Server.ProxyURL != "" {
logrus.Infof("Configuring proxy with %s to extract crt from the following URL: %s", instance.Spec.Server.ProxyURL, requestURL)
configureProxy(instance, transport)
if proxy.HttpProxy != "" {
logrus.Infof("Configuring proxy with %s to extract crt from the following URL: %s", proxy.HttpProxy, requestURL)
ConfigureProxy(instance, transport, proxy)
}
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
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
// 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
func GetEndpointTLSCrtBytes(instance *orgv1.CheCluster, endpointURL string, clusterAPI ClusterAPI) (certificates []byte, err error) {
peerCertificates, err := GetEndpointTLSCrtChain(instance, endpointURL, clusterAPI)
func GetEndpointTLSCrtBytes(instance *orgv1.CheCluster, endpointURL string, proxy *Proxy, clusterAPI ClusterAPI) (certificates []byte, err error) {
peerCertificates, err := GetEndpointTLSCrtChain(instance, endpointURL, proxy, clusterAPI)
if err != nil {
if util.IsTestMode() {
fakeCrt := make([]byte, 5)
@ -195,57 +192,6 @@ func GetEndpointTLSCrtBytes(instance *orgv1.CheCluster, endpointURL string, clus
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.
func K8sHandleCheTLSSecrets(checluster *orgv1.CheCluster, clusterAPI ClusterAPI) (reconcile.Result, error) {
cheTLSSecretName := checluster.Spec.K8s.TlsSecretName

View File

@ -243,62 +243,6 @@ func getClusterPublicHostnameForOpenshiftV4() (hostname string, err error) {
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) {
env := deployment.Spec.Template.Spec.Containers[0].Env
for i := range env {

View File

@ -12,73 +12,10 @@
package util
import (
"os"
"reflect"
"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) {
chars := 12
passwd := GeneratePasswd(chars)