Skip to content

Commit

Permalink
Automate the setup of github identity provider with internal keycloak (
Browse files Browse the repository at this point in the history
…#589)

* GitHub identity provider provision

Signed-off-by: Anatolii Bazko <abazko@redhat.com>
  • Loading branch information
tolusha authored Jan 13, 2021
1 parent 5b78d6b commit 482155b
Show file tree
Hide file tree
Showing 31 changed files with 757 additions and 389 deletions.
5 changes: 3 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"stable",
"che"
]
},
},
{
"type": "bashdb",
"request": "launch",
Expand Down Expand Up @@ -145,7 +145,8 @@
"mode": "test",
"program": "${file}",
"env": {
"MOCK_API": true
"MOCK_API": true,
"CHE_FLAVOR": "che"
},
},
{
Expand Down
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ RUN export ARCH="$(uname -m)" && if [[ ${ARCH} == "x86_64" ]]; then export ARCH=
FROM registry.access.redhat.com/ubi8-minimal:8.3-230

COPY --from=builder /tmp/che-operator/che-operator /usr/local/bin/che-operator
COPY --from=builder /che-operator/templates/keycloak_provision /tmp/keycloak_provision
COPY --from=builder /che-operator/templates/oauth_provision /tmp/oauth_provision
COPY --from=builder /che-operator/templates/keycloak-provision.sh /tmp/keycloak-provision.sh
COPY --from=builder /che-operator/templates/oauth-provision.sh /tmp/oauth-provision.sh
COPY --from=builder /che-operator/templates/delete-identity-provider.sh /tmp/delete-identity-provider.sh
COPY --from=builder /che-operator/templates/create-github-identity-provider.sh /tmp/create-github-identity-provider.sh
# apply CVE fixes, if required
RUN microdnf update -y librepo libnghttp2 && microdnf clean all && rm -rf /var/cache/yum && echo "Installed Packages" && rpm -qa | sort -V && echo "End Of Installed Packages"
CMD ["che-operator"]
Expand Down
4 changes: 4 additions & 0 deletions deploy/crds/org_v1_che_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,10 @@ spec:
devfileRegistryURL:
description: Public URL to the Devfile registry
type: string
gitHubOAuthProvisioned:
description: Indicates whether an Identity Provider instance (Keycloak
/ RH SSO) has been configured to integrate with the GitHub OAuth.
type: boolean
helpLink:
description: A URL that can point to some URL where to find help related
to the current Operator status.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ metadata:
categories: Developer Tools
certified: "false"
containerImage: quay.io/eclipse/che-operator:nightly
createdAt: "2021-01-08T14:09:35Z"
createdAt: "2021-01-13T13:41:43Z"
description: A Kube-native development solution that delivers portable and collaborative
developer workspaces.
operatorframework.io/suggested-namespace: eclipse-che
repository: https://github.com/eclipse/che-operator
support: Eclipse Foundation
name: eclipse-che-preview-kubernetes.v7.25.0-66.nightly
name: eclipse-che-preview-kubernetes.v7.25.0-68.nightly
namespace: placeholder
spec:
apiservicedefinitions: {}
Expand Down Expand Up @@ -514,4 +514,4 @@ spec:
maturity: stable
provider:
name: Eclipse Foundation
version: 7.25.0-66.nightly
version: 7.25.0-68.nightly
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,10 @@ spec:
devfileRegistryURL:
description: Public URL to the Devfile registry
type: string
gitHubOAuthProvisioned:
description: Indicates whether an Identity Provider instance (Keycloak
/ RH SSO) has been configured to integrate with the GitHub OAuth.
type: boolean
helpLink:
description: A URL that can point to some URL where to find help related
to the current Operator status.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@ metadata:
categories: Developer Tools, OpenShift Optional
certified: "false"
containerImage: quay.io/eclipse/che-operator:nightly
createdAt: "2021-01-08T14:09:42Z"
createdAt: "2021-01-13T13:41:52Z"
description: A Kube-native development solution that delivers portable and collaborative
developer workspaces in OpenShift.
operatorframework.io/suggested-namespace: eclipse-che
repository: https://github.com/eclipse/che-operator
support: Eclipse Foundation
name: eclipse-che-preview-openshift.v7.25.0-66.nightly
name: eclipse-che-preview-openshift.v7.25.0-68.nightly
namespace: placeholder
spec:
apiservicedefinitions: {}
Expand Down Expand Up @@ -533,4 +533,4 @@ spec:
maturity: stable
provider:
name: Eclipse Foundation
version: 7.25.0-66.nightly
version: 7.25.0-68.nightly
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,10 @@ spec:
devfileRegistryURL:
description: Public URL to the Devfile registry
type: string
gitHubOAuthProvisioned:
description: Indicates whether an Identity Provider instance (Keycloak
/ RH SSO) has been configured to integrate with the GitHub OAuth.
type: boolean
helpLink:
description: A URL that can point to some URL where to find help related
to the current Operator status.
Expand Down
7 changes: 4 additions & 3 deletions local-debug.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ echo "[INFO] CR file path: ${CR}"

kubectl apply -f deploy/crds/org_v1_che_crd.yaml
kubectl apply -f "${CR}" -n $CHE_NAMESPACE
cp templates/keycloak_provision /tmp/keycloak_provision
cp templates/oauth_provision /tmp/oauth_provision
cp templates/keycloak-provision.sh /tmp/keycloak-provision.sh
cp templates/delete-identity-provider.sh /tmp/delete-identity-provider.sh
cp templates/create-github-identity-provider.sh /tmp/create-github-identity-provider.sh

ENV_FILE=/tmp/che-operator-debug.env
rm -rf "${ENV_FILE}"
Expand All @@ -72,7 +73,7 @@ echo "WATCH_NAMESPACE='${CHE_NAMESPACE}'" >> ${ENV_FILE}

echo "[WARN] Make sure that your CR contains valid ingress domain!"

operator-sdk run --local --namespace ${CHE_NAMESPACE} --enable-delve &
operator-sdk run --local --watch-namespace ${CHE_NAMESPACE} --enable-delve &
OPERATOR_SDK_PID=$!

wait ${OPERATOR_SDK_PID}
3 changes: 3 additions & 0 deletions pkg/apis/org/v1/che_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,9 @@ type CheClusterStatus struct {
// Indicates whether an Identity Provider instance (Keycloak / RH SSO) has been configured to integrate with the OpenShift OAuth.
// +optional
OpenShiftoAuthProvisioned bool `json:"openShiftoAuthProvisioned"`
// Indicates whether an Identity Provider instance (Keycloak / RH SSO) has been configured to integrate with the GitHub OAuth.
// +optional
GitHubOAuthProvisioned bool `json:"gitHubOAuthProvisioned"`
// Status of a Che installation. Can be `Available`, `Unavailable`, or `Available, Rolling Update in Progress`
// +optional
// +operator-sdk:gen-csv:customresourcedefinitions.statusDescriptors=true
Expand Down
35 changes: 18 additions & 17 deletions pkg/controller/che/che_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -718,15 +718,15 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}

// Create a new Postgres deployment
deploymentStatus := postgres.SyncPostgresDeploymentToCluster(deployContext)
provisioned, err := postgres.SyncPostgresDeploymentToCluster(deployContext)
if !tests {
if !deploymentStatus.Continue {
if !provisioned {
logrus.Infof("Waiting on deployment '%s' to be ready", postgres.PostgresDeploymentName)
if deploymentStatus.Err != nil {
logrus.Error(deploymentStatus.Err)
if err != nil {
logrus.Error(err)
}

return reconcile.Result{Requeue: deploymentStatus.Requeue}, deploymentStatus.Err
return reconcile.Result{}, err
}
}

Expand All @@ -741,15 +741,16 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
identityProviderPostgresPassword = password
}
pgCommand := identity_provider.GetPostgresProvisionCommand(identityProviderPostgresPassword)
dbStatus := instance.Status.DbProvisoned
// provision Db and users for Che and Keycloak servers
if !dbStatus {
podToExec, err := util.K8sclient.GetDeploymentPod(postgres.PostgresDeploymentName, instance.Namespace)
if err != nil {
return reconcile.Result{}, err
}
_, err = util.K8sclient.ExecIntoPod(podToExec, pgCommand, "create Keycloak DB, user, privileges", instance.Namespace)
_, err := util.K8sclient.ExecIntoPod(
instance,
postgres.PostgresDeploymentName,
func(cr *orgv1.CheCluster) (string, error) {
return identity_provider.GetPostgresProvisionCommand(identityProviderPostgresPassword), nil
},
"create Keycloak DB, user, privileges")
if err == nil {
for {
instance.Status.DbProvisoned = true
Expand Down Expand Up @@ -842,7 +843,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
if err != nil {
logrus.Errorf("Error provisioning the identity provider to cluster: %v", err)
}
return reconcile.Result{RequeueAfter: time.Second * 1}, err
return reconcile.Result{}, err
}
}

Expand Down Expand Up @@ -886,12 +887,12 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}

// Create a new che deployment
deploymentStatus := server.SyncCheDeploymentToCluster(deployContext)
provisioned, err = server.SyncCheDeploymentToCluster(deployContext)
if !tests {
if !deploymentStatus.Continue {
if !provisioned {
logrus.Infof("Waiting on deployment '%s' to be ready", cheFlavor)
if deploymentStatus.Err != nil {
logrus.Error(deploymentStatus.Err)
if err != nil {
logrus.Error(err)
}

deployment, err := r.GetEffectiveDeployment(instance, cheFlavor)
Expand All @@ -912,7 +913,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
}
}
return reconcile.Result{Requeue: deploymentStatus.Requeue}, deploymentStatus.Err
return reconcile.Result{}, err
}
}
// Update available status
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/che/che_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ func TestCheController(t *testing.T) {
if err = r.client.Get(context.TODO(), types.NamespacedName{Name: cheCR.Name, Namespace: cheCR.Namespace}, cheCR); err != nil {
t.Errorf("Failed to get the Che custom resource %s: %s", cheCR.Name, err)
}
if err = identity_provider.SyncIdentityProviderItems(deployContext, "che"); err != nil {
if _, err = identity_provider.SyncOpenShiftIdentityProviderItems(deployContext); err != nil {
t.Errorf("Failed to create the items for the identity provider: %s", err)
}
oAuthClientName := cheCR.Spec.Auth.OAuthClientName
Expand Down
17 changes: 12 additions & 5 deletions pkg/controller/che/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package che

import (
"context"

identity_provider "github.com/eclipse/che-operator/pkg/deploy/identity-provider"

orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
Expand Down Expand Up @@ -51,12 +52,18 @@ func (r *ReconcileChe) ReconcileIdentityProvider(instance *orgv1.CheCluster, isO
if err := r.client.Get(context.TODO(), types.NamespacedName{Name: "keycloak", Namespace: instance.Namespace}, keycloakDeployment); err != nil {
logrus.Errorf("Deployment %s not found: %s", keycloakDeployment.Name, err)
}
deleteOpenShiftIdentityProviderProvisionCommand := identity_provider.GetDeleteOpenShiftIdentityProviderProvisionCommand(instance, isOpenShift4)
podToExec, err := util.K8sclient.GetDeploymentPod(keycloakDeployment.Name, instance.Namespace)
if err != nil {
logrus.Errorf("Failed to retrieve pod name. Further exec will fail")

providerName := "openshift-v3"
if isOpenShift4 {
providerName = "openshift-v4"
}
_, err = util.K8sclient.ExecIntoPod(podToExec, deleteOpenShiftIdentityProviderProvisionCommand, "delete OpenShift identity provider", instance.Namespace)
_, err := util.K8sclient.ExecIntoPod(
instance,
keycloakDeployment.Name,
func(cr *orgv1.CheCluster) (string, error) {
return identity_provider.GetIdentityProviderDeleteCommand(instance, providerName)
},
"delete OpenShift identity provider")
if err == nil {
oAuthClient := &oauth.OAuthClient{}
oAuthClientName := instance.Spec.Auth.OAuthClientName
Expand Down
7 changes: 4 additions & 3 deletions pkg/deploy/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,10 @@ const (
CheEclipseOrg = "che.eclipse.org"

// che.eclipse.org annotations
CheEclipseOrgMountPath = "che.eclipse.org/mount-path"
CheEclipseOrgMountAs = "che.eclipse.org/mount-as"
CheEclipseOrgEnvName = "che.eclipse.org/env-name"
CheEclipseOrgMountPath = "che.eclipse.org/mount-path"
CheEclipseOrgMountAs = "che.eclipse.org/mount-as"
CheEclipseOrgEnvName = "che.eclipse.org/env-name"
CheEclipseOrgGithubOAuthCredentials = "che.eclipse.org/github-oauth-credentials"
)

func InitDefaults(defaultsPath string) {
Expand Down
33 changes: 8 additions & 25 deletions pkg/deploy/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,26 @@ var DeploymentDiffOpts = cmp.Options{
}),
}

type DeploymentProvisioningStatus struct {
ProvisioningStatus
Deployment *appsv1.Deployment
}

func SyncDeploymentToCluster(
deployContext *DeployContext,
specDeployment *appsv1.Deployment,
clusterDeployment *appsv1.Deployment,
additionalDeploymentDiffOpts cmp.Options,
additionalDeploymentMerge func(*appsv1.Deployment, *appsv1.Deployment) *appsv1.Deployment) DeploymentProvisioningStatus {
additionalDeploymentMerge func(*appsv1.Deployment, *appsv1.Deployment) *appsv1.Deployment) (bool, error) {

if err := MountSecrets(specDeployment, deployContext); err != nil {
return DeploymentProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Requeue: true, Err: err},
}
return false, err
}

clusterDeployment, err := GetClusterDeployment(specDeployment.Name, specDeployment.Namespace, deployContext.ClusterAPI.Client)
if err != nil {
return DeploymentProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Err: err},
}
return false, err
}

if clusterDeployment == nil {
logrus.Infof("Creating a new object: %s, name %s", specDeployment.Kind, specDeployment.Name)
err := deployContext.ClusterAPI.Client.Create(context.TODO(), specDeployment)
return DeploymentProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Requeue: true, Err: err},
}
return false, err
}

// 2-step comparation process
Expand All @@ -89,9 +78,7 @@ func SyncDeploymentToCluster(
fmt.Printf("Difference:\n%s", diff)
clusterDeployment = additionalDeploymentMerge(specDeployment, clusterDeployment)
err := deployContext.ClusterAPI.Client.Update(context.TODO(), clusterDeployment)
return DeploymentProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Requeue: true, Err: err},
}
return false, err
}
}

Expand All @@ -101,19 +88,15 @@ func SyncDeploymentToCluster(
fmt.Printf("Difference:\n%s", diff)
clusterDeployment.Spec = specDeployment.Spec
err := deployContext.ClusterAPI.Client.Update(context.TODO(), clusterDeployment)
return DeploymentProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Requeue: true, Err: err},
}
return false, err
}

if clusterDeployment.Spec.Strategy.Type == appsv1.RollingUpdateDeploymentStrategyType && clusterDeployment.Status.Replicas > 1 {
logrus.Infof("Deployment %s is in the rolling update state.", specDeployment.Name)
}

return DeploymentProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Continue: clusterDeployment.Status.AvailableReplicas == 1 && clusterDeployment.Status.Replicas == 1},
Deployment: clusterDeployment,
}
provisioned := clusterDeployment.Status.AvailableReplicas == 1 && clusterDeployment.Status.Replicas == 1
return provisioned, nil
}

func GetClusterDeployment(name string, namespace string, client runtimeClient.Client) (*appsv1.Deployment, error) {
Expand Down
10 changes: 3 additions & 7 deletions pkg/deploy/devfile-registry/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
v1 "k8s.io/api/core/v1"
)

func SyncDevfileRegistryDeploymentToCluster(deployContext *deploy.DeployContext) deploy.DeploymentProvisioningStatus {
func SyncDevfileRegistryDeploymentToCluster(deployContext *deploy.DeployContext) (bool, error) {
registryType := "devfile"
registryImage := util.GetValue(deployContext.CheCluster.Spec.Server.DevfileRegistryImage, deploy.DefaultDevfileRegistryImage(deployContext.CheCluster))
registryImagePullPolicy := v1.PullPolicy(util.GetValue(string(deployContext.CheCluster.Spec.Server.PluginRegistryPullPolicy), deploy.DefaultPullPolicyFromDockerImage(registryImage)))
Expand All @@ -29,9 +29,7 @@ func SyncDevfileRegistryDeploymentToCluster(deployContext *deploy.DeployContext)

clusterDeployment, err := deploy.GetClusterDeployment(deploy.DevfileRegistry, deployContext.CheCluster.Namespace, deployContext.ClusterAPI.Client)
if err != nil {
return deploy.DeploymentProvisioningStatus{
ProvisioningStatus: deploy.ProvisioningStatus{Err: err},
}
return false, err
}

specDeployment, err := registry.GetSpecRegistryDeployment(
Expand All @@ -45,9 +43,7 @@ func SyncDevfileRegistryDeploymentToCluster(deployContext *deploy.DeployContext)
probePath)

if err != nil {
return deploy.DeploymentProvisioningStatus{
ProvisioningStatus: deploy.ProvisioningStatus{Err: err},
}
return false, err
}

return deploy.SyncDeploymentToCluster(deployContext, specDeployment, clusterDeployment, nil, nil)
Expand Down
Loading

0 comments on commit 482155b

Please sign in to comment.