Merge pull request #357 from akram/add-route-creation

Add Route pointing to the HTTP Service when the Route API is present
This commit is contained in:
Tomasz Sęk 2020-05-05 16:06:24 +02:00 committed by GitHub
commit 12ecfaa2b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 128 additions and 5 deletions

View File

@ -16,6 +16,7 @@ import (
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications"
e "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications/event" e "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications/event"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources"
"github.com/jenkinsci/kubernetes-operator/pkg/event" "github.com/jenkinsci/kubernetes-operator/pkg/event"
"github.com/jenkinsci/kubernetes-operator/pkg/log" "github.com/jenkinsci/kubernetes-operator/pkg/log"
"github.com/jenkinsci/kubernetes-operator/version" "github.com/jenkinsci/kubernetes-operator/version"
@ -45,8 +46,6 @@ var (
operatorMetricsPort int32 = 8686 operatorMetricsPort int32 = 8686
) )
//var log = logf.Log.WithName("cmd")
func printInfo() { func printInfo() {
log.Log.Info(fmt.Sprintf("Version: %s", version.Version)) log.Log.Info(fmt.Sprintf("Version: %s", version.Version))
log.Log.Info(fmt.Sprintf("Git commit: %s", version.GitCommit)) log.Log.Info(fmt.Sprintf("Git commit: %s", version.GitCommit))
@ -120,6 +119,9 @@ func main() {
fatal(errors.Wrap(err, "failed to create Kubernetes client set"), *debug) fatal(errors.Wrap(err, "failed to create Kubernetes client set"), *debug)
} }
if( resources.IsRouteAPIAvailable(clientSet) ) {
log.Log.Info("Route API found: Route creation will be performed")
}
c := make(chan e.Event) c := make(chan e.Event)
go notifications.Listen(c, events, mgr.GetClient()) go notifications.Listen(c, events, mgr.GetClient())

View File

@ -2,6 +2,7 @@ package apis
import ( import (
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
routev1 "github.com/openshift/api/route/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -17,4 +18,5 @@ func AddToScheme(s *runtime.Scheme) error {
func init() { func init() {
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
AddToSchemes = append(AddToSchemes, v1alpha2.SchemeBuilder.AddToScheme) AddToSchemes = append(AddToSchemes, v1alpha2.SchemeBuilder.AddToScheme)
AddToSchemes = append(AddToSchemes, routev1.AddToScheme)
} }

View File

@ -177,15 +177,25 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod
} }
r.logger.V(log.VDebug).Info("Extra role bindings are present") r.logger.V(log.VDebug).Info("Extra role bindings are present")
if err := r.createService(metaObject, resources.GetJenkinsHTTPServiceName(r.Configuration.Jenkins), r.Configuration.Jenkins.Spec.Service); err != nil { httpServiceName := resources.GetJenkinsHTTPServiceName(r.Configuration.Jenkins)
if err := r.createService(metaObject, httpServiceName, r.Configuration.Jenkins.Spec.Service); err != nil {
return err return err
} }
r.logger.V(log.VDebug).Info("Jenkins HTTP Service is present") r.logger.V(log.VDebug).Info("Jenkins HTTP Service is present")
if err := r.createService(metaObject, resources.GetJenkinsSlavesServiceName(r.Configuration.Jenkins), r.Configuration.Jenkins.Spec.SlaveService); err != nil { if err := r.createService(metaObject, resources.GetJenkinsSlavesServiceName(r.Configuration.Jenkins), r.Configuration.Jenkins.Spec.SlaveService); err != nil {
return err return err
} }
r.logger.V(log.VDebug).Info("Jenkins slave Service is present") r.logger.V(log.VDebug).Info("Jenkins slave Service is present")
if resources.IsRouteAPIAvailable(&r.ClientSet) {
r.logger.V(log.VDebug).Info("Route API is available. Now creating route.")
if err := r.createRoute(metaObject, httpServiceName, r.Configuration.Jenkins); err != nil {
return err
}
r.logger.V(log.VDebug).Info("Jenkins Route is present")
}
return nil return nil
} }

View File

@ -0,0 +1,50 @@
package resources
import (
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
routev1 "github.com/openshift/api/route/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes"
)
//RouteKind the kind name for route
const RouteKind = "Route"
var isRouteAPIAvailable = false
var routeAPIChecked = false
// UpdateRoute returns new route matching the service
func UpdateRoute(actual routev1.Route,jenkins *v1alpha2.Jenkins) routev1.Route {
actualTargetService := actual.Spec.To
serviceName := GetJenkinsHTTPServiceName(jenkins)
if( actualTargetService.Name != serviceName ) {
actual.Spec.To.Name = serviceName
}
port := jenkins.Spec.Service.Port
if( actual.Spec.Port.TargetPort.IntVal != port){
actual.Spec.Port.TargetPort = intstr.FromInt(int(port))
}
return actual
}
//IsRouteAPIAvailable tells if the Route API is installed and discoverable
func IsRouteAPIAvailable(clientSet *kubernetes.Clientset) (bool) {
if (routeAPIChecked){
return isRouteAPIAvailable
}
gv := schema.GroupVersion{
Group: routev1.GroupName,
Version: routev1.SchemeGroupVersion.Version,
}
if err := discovery.ServerSupportsVersion(clientSet, gv); err != nil {
// error, API not available
routeAPIChecked = true
isRouteAPIAvailable = false
} else {
// API Exists
routeAPIChecked = true
isRouteAPIAvailable = true
}
return isRouteAPIAvailable
}

View File

@ -12,6 +12,8 @@ import (
"net" "net"
"strings" "strings"
) )
//ServiceKind the kind name for Service
const ServiceKind = "Service"
// UpdateService returns new service with override fields from config // UpdateService returns new service with override fields from config
func UpdateService(actual corev1.Service, config v1alpha2.Service) corev1.Service { func UpdateService(actual corev1.Service, config v1alpha2.Service) corev1.Service {

View File

@ -0,0 +1,57 @@
package base
import (
"context"
"fmt"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"k8s.io/apimachinery/pkg/util/intstr"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources"
routev1 "github.com/openshift/api/route/v1"
stackerr "github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
// createRoute takes the ServiceName and Creates the Route based on it
func (r *ReconcileJenkinsBaseConfiguration) createRoute(meta metav1.ObjectMeta, serviceName string, config *v1alpha2.Jenkins) error{
route := routev1.Route{}
name := fmt.Sprintf("%s-%s", config.ObjectMeta.Name, config.ObjectMeta.Namespace)
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: meta.Namespace}, &route)
if err != nil && apierrors.IsNotFound(err) {
port := &routev1.RoutePort{
TargetPort: intstr.FromString(""),
}
routeSpec := routev1.RouteSpec{
TLS: &routev1.TLSConfig{
InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
Termination: routev1.TLSTerminationEdge,
},
To: routev1.RouteTargetReference{
Kind: resources.ServiceKind,
Name: serviceName,
},
Port: port,
}
actual := routev1.Route{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: meta.Namespace,
Labels: meta.Labels,
},
Spec: routeSpec,
}
route = resources.UpdateRoute(actual, config)
if err = r.CreateResource(&route); err != nil {
return stackerr.WithStack(err)
}
} else if err != nil {
return stackerr.WithStack(err)
}
route.ObjectMeta.Labels = meta.Labels // make sure that user won't break service by hand
route = resources.UpdateRoute(route, config)
return stackerr.WithStack(r.UpdateResource(&route))
}

View File

@ -72,7 +72,6 @@ func (e *enqueueRequestForJenkins) getOwnerReconcileRequests(object metav1.Objec
Name: object.GetLabels()[constants.LabelJenkinsCRKey], Name: object.GetLabels()[constants.LabelJenkinsCRKey],
}} }}
} }
return nil return nil
} }

View File

@ -47,7 +47,8 @@ var reconcileErrors = map[string]reconcileError{}
// Add creates a new Jenkins Controller and adds it to the Manager. The Manager will set fields on the Controller // Add creates a new Jenkins Controller and adds it to the Manager. The Manager will set fields on the Controller
// and Start it when the Manager is Started. // and Start it when the Manager is Started.
func Add(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings, clientSet kubernetes.Clientset, config rest.Config, notificationEvents *chan event.Event) error { func Add(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings, clientSet kubernetes.Clientset, config rest.Config, notificationEvents *chan event.Event) error {
return add(mgr, newReconciler(mgr, jenkinsAPIConnectionSettings, clientSet, config, notificationEvents)) reconciler := newReconciler(mgr, jenkinsAPIConnectionSettings, clientSet, config, notificationEvents)
return add(mgr, reconciler)
} }
// newReconciler returns a new reconcile.Reconciler // newReconciler returns a new reconcile.Reconciler