Make Che Operator create consolelink if it's supported

Signed-off-by: Sergii Leshchenko <sleshche@redhat.com>
pull/71/head
Sergii Leshchenko 2019-09-03 17:28:08 +03:00
parent 0a2c701444
commit 5552439b71
5 changed files with 129 additions and 23 deletions

View File

@ -108,7 +108,7 @@ func main() {
os.Exit(1)
}
logrus.Info("Registering Components")
logrus.Info("Registering Che Components Types")
// Setup Scheme for all resources
if err := apis.AddToScheme(mgr.GetScheme()); err != nil {

View File

@ -13,11 +13,13 @@ package che
import (
"context"
"fmt"
"time"
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
"github.com/eclipse/che-operator/pkg/deploy"
"github.com/eclipse/che-operator/pkg/util"
consolev1 "github.com/openshift/api/console/v1"
oauth "github.com/openshift/api/oauth/v1"
routev1 "github.com/openshift/api/route/v1"
userv1 "github.com/openshift/api/user/v1"
@ -63,9 +65,9 @@ func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) {
return nil, err
}
return &ReconcileChe{
client: mgr.GetClient(),
client: mgr.GetClient(),
nonCachedClient: noncachedClient,
scheme: mgr.GetScheme(),
scheme: mgr.GetScheme(),
}, nil
}
@ -81,7 +83,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
if err != nil {
return err
}
// register OpenShift routes in the scheme
// register OpenShift specific types in the scheme
if isOpenShift {
if err := routev1.AddToScheme(mgr.GetScheme()); err != nil {
logrus.Errorf("Failed to add OpenShift route to scheme: %s", err)
@ -92,6 +94,11 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
if err := userv1.AddToScheme(mgr.GetScheme()); err != nil {
logrus.Errorf("Failed to add OpenShift User 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)
}
}
}
// register RBAC in the scheme
@ -202,8 +209,8 @@ type ReconcileChe struct {
// to simply read objects thta we don't intend
// to further watch
nonCachedClient client.Client
scheme *runtime.Scheme
tests bool
scheme *runtime.Scheme
tests bool
}
const (
@ -237,6 +244,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
if err != nil {
logrus.Errorf("An error occurred when detecting current infra: %s", err)
}
if isOpenShift {
// delete oAuthClient before CR is deleted
doInstallOpenShiftoAuthProvider := instance.Spec.Auth.OpenShiftOauth
@ -303,7 +311,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
}
}
if err := r.SetStatusDetails(instance, request, "", "", ""); err != nil {
return reconcile.Result{}, err
}
@ -499,6 +507,11 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
}
}
if err := createConsoleLink(isOpenShift4, protocol, instance, r); err != nil {
return reconcile.Result{}, err
}
// create and provision Keycloak related objects
ExternalKeycloak := instance.Spec.Auth.ExternalKeycloak
@ -895,7 +908,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
effectiveCheDeployment, err = r.GetEffectiveDeployment(instance, cheDeploymentToCreate.Name)
}
if effectiveCheDeployment.Status.AvailableReplicas == 1 &&
instance.Status.CheClusterRunning != AvailableStatus {
instance.Status.CheClusterRunning != AvailableStatus {
if err := r.SetCheAvailableStatus(instance, request, protocol, cheHost); err != nil {
instance, _ = r.GetCR(request)
return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 1}, err
@ -1042,3 +1055,67 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
return reconcile.Result{}, nil
}
func createConsoleLink(isOpenShift4 bool, protocol string, instance *orgv1.CheCluster, r *ReconcileChe) error {
if !isOpenShift4 || !hasConsolelinkObject() {
logrus.Debug("Console link won't be created. It's not supported by cluster")
// console link is supported only on OpenShift >= 4.2
return nil
}
if protocol != "https" {
logrus.Debug("Console link won't be created. It's not supported when http connection is used")
// console link is supported only with https
return nil
}
cheHost := instance.Spec.Server.CheHost
preparedConsoleLink := &consolev1.ConsoleLink{
ObjectMeta: metav1.ObjectMeta{
Name: deploy.DefaultConsoleLinkName,
},
Spec: consolev1.ConsoleLinkSpec{
Link: consolev1.Link{
Href: protocol + "://" + cheHost,
Text: deploy.DefaultConsoleLinkDisplayName},
Location: consolev1.ApplicationMenu,
ApplicationMenu: &consolev1.ApplicationMenuSpec{
Section: deploy.DefaultConsoleLinkSection,
ImageURL: fmt.Sprintf("%s://%s%s", protocol, cheHost, deploy.DefaultConsoleLinkImage),
},
},
}
existingConsoleLink := &consolev1.ConsoleLink{}
if getErr := r.nonCachedClient.Get(context.TODO(), client.ObjectKey{Name: deploy.DefaultConsoleLinkName}, existingConsoleLink); getErr == nil {
// if found, update existing one. We need ResourceVersion from current one.
preparedConsoleLink.ResourceVersion = existingConsoleLink.ResourceVersion
logrus.Debugf("Updating the object: ConsoleLink, name: %s", existingConsoleLink.Name)
return r.nonCachedClient.Update(context.TODO(), preparedConsoleLink)
} else {
// if not found, create new one
if statusError, ok := getErr.(*errors.StatusError); ok &&
statusError.Status().Reason == metav1.StatusReasonNotFound {
logrus.Infof("Creating a new object: ConsoleLink, name: %s", preparedConsoleLink.Name)
return r.nonCachedClient.Create(context.TODO(), preparedConsoleLink)
} else {
return getErr
}
}
}
func hasConsolelinkObject() bool {
resourceList, err := util.GetServerResources()
if err != nil {
return false
}
for _, res := range resourceList {
for _, r := range res.APIResources {
if r.Name == "consolelinks" {
return true
}
}
}
return false
}

View File

@ -13,6 +13,7 @@ package che
import (
"context"
console "github.com/openshift/api/console/v1"
"time"
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
@ -104,6 +105,8 @@ func TestCheController(t *testing.T) {
s.AddKnownTypes(oauth.SchemeGroupVersion, oAuthClient)
s.AddKnownTypes(userv1.SchemeGroupVersion, users, user)
s.AddKnownTypes(console.GroupVersion, &console.ConsoleLink{})
// Create a fake client to mock API calls
cl := fake.NewFakeClient(objs...)
tests := true

View File

@ -66,6 +66,12 @@ const (
OldDefaultKeycloakUpstreamImageToDetect = "eclipse/che-keycloak:7.0.0"
OldDefaultPvcJobsUpstreamImageToDetect = "registry.access.redhat.com/ubi8-minimal:8.0-127"
OldDefaultPostgresUpstreamImageToDetect = "centos/postgresql-96-centos7:9.6"
// ConsoleLink default
DefaultConsoleLinkName = "che"
DefaultConsoleLinkImage = "/dashboard/assets/branding/che-logo.svg"
DefaultConsoleLinkDisplayName = "Eclipse Che"
DefaultConsoleLinkSection = "Red Hat Applications"
)
func DefaultCheServerImageTag(cheFlavor string) string {

View File

@ -12,11 +12,12 @@
package util
import (
"errors"
"crypto/tls"
"encoding/json"
"errors"
"github.com/sirupsen/logrus"
"io/ioutil"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
"math/rand"
"net/http"
@ -63,24 +64,15 @@ func GeneratePasswd(stringLength int) (passwd string) {
func DetectOpenShift() (isOpenshift bool, isOpenshift4 bool, anError error) {
tests := IsTestMode()
if !tests {
kubeconfig, err := config.GetConfig()
if err != nil {
apiGroups, err := getApiList()
if err != nil{
return false, false, err
}
discoveryClient, err := discovery.NewDiscoveryClientForConfig(kubeconfig)
if err != nil {
return false, false, err
}
apiList, err := discoveryClient.ServerGroups()
if err != nil {
return false, false, err
}
apiGroups := apiList.Groups
for i := 0; i < len(apiGroups); i++ {
if apiGroups[i].Name == "route.openshift.io" {
for _, apiGroup := range apiGroups {
if apiGroup.Name == "route.openshift.io" {
isOpenshift = true
}
if apiGroups[i].Name == "config.openshift.io" {
if apiGroup.Name == "config.openshift.io" {
isOpenshift4 = true
}
}
@ -89,6 +81,34 @@ func DetectOpenShift() (isOpenshift bool, isOpenshift4 bool, anError error) {
return true, false, nil
}
func getDiscoveryClient() (*discovery.DiscoveryClient, error) {
kubeconfig, err := config.GetConfig()
if err != nil {
return nil, err
}
return discovery.NewDiscoveryClientForConfig(kubeconfig)
}
func getApiList() ([]v1.APIGroup, error) {
discoveryClient, err := getDiscoveryClient()
if err != nil {
return nil, err
}
apiList, err := discoveryClient.ServerGroups()
if err != nil {
return nil, err
}
return apiList.Groups, nil
}
func GetServerResources() ([]*v1.APIResourceList, error) {
discoveryClient, err := getDiscoveryClient()
if err != nil {
return nil, err
}
return discoveryClient.ServerResources()
}
func GetValue(key string, defaultValue string) (value string) {
value = key