Skip to content

Commit

Permalink
Merge pull request #462 from myeung18/consolelink
Browse files Browse the repository at this point in the history
Add ConsoleLink Creation/Remove
  • Loading branch information
eguzki authored Oct 2, 2020
2 parents 842bb38 + d0baac2 commit e35bb84
Show file tree
Hide file tree
Showing 10 changed files with 434 additions and 15 deletions.
6 changes: 6 additions & 0 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
crmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
consolev1 "github.com/openshift/api/console/v1"
)

// Change below variables to serve metrics on different host or port.
Expand Down Expand Up @@ -118,6 +119,11 @@ func main() {
os.Exit(1)
}

if err := consolev1.AddToScheme(mgr.GetScheme()); err != nil {
log.Error(err, "")
os.Exit(1)
}

// Setup Scheme for OpenShift imagestreams and related
if err := imagev1.AddToScheme(mgr.GetScheme()); err != nil {
log.Error(err, "")
Expand Down
14 changes: 14 additions & 0 deletions deploy/cluster_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: 3scale-operator
rules:
- apiGroups:
- console.openshift.io
resources:
- consolelinks
verbs:
- create
- delete
- get
- update
12 changes: 12 additions & 0 deletions deploy/cluster_role_binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: 3scale-operator
subjects:
- kind: ServiceAccount
name: 3scale-operator
namespace: <placeholder>
roleRef:
kind: ClusterRole
name: 3scale-operator
apiGroup: rbac.authorization.k8s.io
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,18 @@ spec:
mediatype: image/png
install:
spec:
clusterPermissions:
- rules:
- apiGroups:
- console.openshift.io
resources:
- consolelinks
verbs:
- create
- delete
- get
- update
serviceAccountName: 3scale-operator
deployments:
- name: 3scale-operator
spec:
Expand Down
20 changes: 11 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@ go 1.13

require (
github.com/3scale/3scale-porta-go-client v0.0.4
github.com/RHsyseng/operator-utils v0.0.0-20200204194854-c5b0d8533458
github.com/coreos/prometheus-operator v0.34.0
github.com/RHsyseng/operator-utils v0.0.0-20200506183821-e3b4a2ba9c30
github.com/coreos/prometheus-operator v0.35.1
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/go-bindata/go-bindata v3.1.1+incompatible
github.com/go-bindata/go-bindata v3.1.2+incompatible
github.com/go-logr/logr v0.1.0
github.com/go-openapi/spec v0.19.4
github.com/go-openapi/spec v0.19.6
github.com/go-playground/validator/v10 v10.2.0
github.com/google/go-cmp v0.3.1
github.com/integr8ly/grafana-operator/v3 v3.5.0
github.com/luci/go-render v0.0.0-20160219211803-9a04cc21af0f
github.com/mitchellh/go-homedir v1.1.0
github.com/openshift/api v3.9.1-0.20190924102528-32369d4db2ad+incompatible
github.com/openshift/client-go v0.0.0-20190923180330-3b6373338c9b
github.com/openshift/client-go v3.9.0+incompatible
github.com/operator-framework/operator-sdk v0.16.0
github.com/prometheus/client_golang v1.2.1
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.4.0
gopkg.in/yaml.v2 v2.2.4
k8s.io/api v0.0.0
k8s.io/apimachinery v0.0.0
gopkg.in/yaml.v2 v2.2.8
k8s.io/api v0.17.2
k8s.io/apimachinery v0.17.2
k8s.io/client-go v12.0.0+incompatible
k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d
sigs.k8s.io/controller-runtime v0.4.0
Expand Down Expand Up @@ -58,6 +58,8 @@ replace (

replace github.com/docker/docker => github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309 // Required by Helm

replace github.com/openshift/api => github.com/openshift/api v0.0.0-20190924102528-32369d4db2ad // Required until https://github.com/operator-framework/operator-lifecycle-manager/pull/1241 is resolved
replace github.com/openshift/api => github.com/openshift/api v0.0.0-20200527184302-a843dc3262a0 // Required until https://github.com/operator-framework/operator-lifecycle-manager/pull/1241 is resolved

replace github.com/openshift/client-go => github.com/openshift/client-go v0.0.0-20191125132246-f6563a70e19a

replace github.com/operator-framework/operator-sdk => github.com/operator-framework/operator-sdk v0.15.2
150 changes: 144 additions & 6 deletions go.sum

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions pkg/controller/add_webconsole.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package controller

import (
"github.com/3scale/3scale-operator/pkg/controller/webconsole"
)

func init() {
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
AddToManagerFuncs = append(AddToManagerFuncs, webconsole.Add)
}
148 changes: 148 additions & 0 deletions pkg/controller/webconsole/webconsole_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package webconsole

import (
"context"
"strings"

"github.com/3scale/3scale-operator/pkg/common"
"github.com/3scale/3scale-operator/pkg/helper"
"github.com/3scale/3scale-operator/version"

"github.com/3scale/3scale-operator/pkg/reconcilers"
"github.com/go-logr/logr"
consolev1 "github.com/openshift/api/console/v1"
routev1 "github.com/openshift/api/route/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)

var (
// controllerName is the name of this controller
controllerName = "controller_webconsole"
log = logf.Log.WithName(controllerName)
)

// Add creates a new WebConsole Controller and adds it to the Manager. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func Add(mgr manager.Manager) error {
reconciler, err := newReconciler(mgr)
if err != nil {
return err
}
return add(mgr, reconciler)
}

// newReconciler returns a new reconcile.Reconciler
func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) {
discoveryClient, err := discovery.NewDiscoveryClientForConfig(mgr.GetConfig())
if err != nil {
return nil, err
}

apiClientReader, err := common.NewAPIClientReader(mgr)
if err != nil {
return nil, err
}

client := mgr.GetClient()
scheme := mgr.GetScheme()
ctx := context.TODO()
recorder := mgr.GetEventRecorderFor(controllerName)
return &ReconcileWebConsole{
BaseReconciler: reconcilers.NewBaseReconciler(client, scheme, apiClientReader, ctx, log, discoveryClient, recorder),
}, nil
}

// add adds a new Controller to mgr with r as the reconcile.Reconciler
func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Create a new controller
c, err := controller.New("webconsole-controller", mgr, controller.Options{Reconciler: r})
if err != nil {
return err
}

// Watch for Route resources
err = c.Watch(&source.Kind{Type: &routev1.Route{}}, &handler.EnqueueRequestForObject{})
if err != nil {
return err
}

return nil
}

// blank assignment to verify that ReconcileWebConsole implements reconcile.Reconciler
var _ reconcile.Reconciler = &ReconcileWebConsole{}

// ReconcileWebConsole reconciles a WebConsole object
type ReconcileWebConsole struct {
*reconcilers.BaseReconciler
}

//Reconcile reads the state of the Routes and makes changes to the corresponding Consolelinks
func (r *ReconcileWebConsole) Reconcile(request reconcile.Request) (reconcile.Result, error) {
logger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
logger.Info("Reconciling ReconcileWebConsole", "Operator version", version.Version)

kindExists, err := r.HasConsoleLink()
if err != nil {
return reconcile.Result{}, err
}
if !kindExists {
logger.Info("Console link not supported in the cluster")
return reconcile.Result{}, nil
}

result, err := r.reconcileMasterLink(request, logger)
if err != nil {
return result, err
}
if result.Requeue {
logger.Info("Master link reconciled. Needs Requeueing.")
return result, nil
}

logger.V(1).Info("END")
return reconcile.Result{}, nil
}

func (r *ReconcileWebConsole) reconcileMasterLink(request reconcile.Request, logger logr.Logger) (reconcile.Result, error) {
if !strings.Contains(request.Name, "zync-3scale-master") {
// Nothing to do
return reconcile.Result{}, nil
}

route := &routev1.Route{}
err := r.Client().Get(r.Context(), request.NamespacedName, route)
if err != nil && !errors.IsNotFound(err) {
// Error reading the object - requeue the request.
return reconcile.Result{}, err
}

if errors.IsNotFound(err) {
logger.V(1).Info("Master route not found", "name", request.Name)
// cluster-scoped resource must not have a namespace-scoped owner
// So consolelinks cannot have owners like apimanager or route object
// delete consolelink if exists
desired := &consolev1.ConsoleLink{
ObjectMeta: metav1.ObjectMeta{
Name: helper.GetMasterConsoleLinkName(request.Namespace),
},
}
common.TagObjectToDelete(desired)
err := r.ReconcileResource(&consolev1.ConsoleLink{}, desired, reconcilers.CreateOnlyMutator)
return reconcile.Result{}, err
}

logger.V(1).Info("Master route found", "name", request.Name)

err = r.ReconcileResource(&consolev1.ConsoleLink{}, helper.GetMasterConsoleLink(route), helper.GenericConsoleLinkMutator)
logger.V(1).Info("Reconcile master consolelink", "err", err)
return reconcile.Result{}, err
}
69 changes: 69 additions & 0 deletions pkg/helper/webconsole.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package helper

import (
"fmt"

"github.com/3scale/3scale-operator/pkg/common"
consolev1 "github.com/openshift/api/console/v1"
routev1 "github.com/openshift/api/route/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ConsoleLinkText is the text of the consoleLink shown on the webconsole
const ConsoleLinkText = "APIManager - 3scale"

// ConsoleLinkMasterNamePrefix is the prefix applied to Console link for system master
const ConsoleLinkMasterNamePrefix = "system-master-link"

//GenericConsoleLinkMutator performs the reconciliation for consolelink objects
func GenericConsoleLinkMutator(existingObj, desiredObj common.KubernetesObject) (bool, error) {
existing, ok := existingObj.(*consolev1.ConsoleLink)
if !ok {
return false, fmt.Errorf("%T is not a *consolev1.ConsoleLink", existingObj)
}
desired, ok := desiredObj.(*consolev1.ConsoleLink)
if !ok {
return false, fmt.Errorf("%T is not a *consolev1.ConsoleLink", desiredObj)
}

update := false

if existing.Spec.Href != desired.Spec.Href {
existing.Spec.Href = desired.Spec.Href
update = true
}

if existing.Spec.Text != desired.Spec.Text {
existing.Spec.Text = desired.Spec.Text
update = true
}

return update, nil
}

//GetMasterConsoleLink creates the consolelink obj for a target
func GetMasterConsoleLink(route *routev1.Route) *consolev1.ConsoleLink {
return &consolev1.ConsoleLink{
ObjectMeta: metav1.ObjectMeta{
Name: GetMasterConsoleLinkName(route.Namespace),
Labels: map[string]string{
"3scale.net/route-name": route.Name,
},
},
Spec: consolev1.ConsoleLinkSpec{
Link: consolev1.Link{
Text: ConsoleLinkText,
Href: "https://" + route.Spec.Host,
},
Location: consolev1.NamespaceDashboard,
NamespaceDashboard: &consolev1.NamespaceDashboardSpec{
Namespaces: []string{route.Namespace},
},
},
}
}

//GetMasterConsoleLinkName returns the consolelink name
func GetMasterConsoleLinkName(namespace string) string {
return fmt.Sprintf("%s-%s", ConsoleLinkMasterNamePrefix, namespace)
}
8 changes: 8 additions & 0 deletions pkg/reconcilers/base_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/3scale/3scale-operator/pkg/common"

"github.com/go-logr/logr"
consolev1 "github.com/openshift/api/console/v1"
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -164,3 +166,9 @@ func (b *BaseReconciler) UpdateResourceStatus(obj common.KubernetesObject) error
b.Logger().Info(fmt.Sprintf("Updated status of object '%s/%s'", strings.Replace(fmt.Sprintf("%T", obj), "*", "", 1), obj.GetName()))
return b.Client().Status().Update(context.TODO(), obj)
}

//HasConsoleLink checks if the ConsoleLink is supported in current cluster
func (b *BaseReconciler) HasConsoleLink() (bool, error) {
return k8sutil.ResourceExists(b.DiscoveryClient(),
consolev1.GroupVersion.String(), "ConsoleLink")
}

0 comments on commit e35bb84

Please sign in to comment.