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:
		
						commit
						12ecfaa2b3
					
				|  | @ -16,6 +16,7 @@ import ( | |||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications" | ||||
| 	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/log" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/version" | ||||
|  | @ -45,8 +46,6 @@ var ( | |||
| 	operatorMetricsPort int32 = 8686 | ||||
| ) | ||||
| 
 | ||||
| //var log = logf.Log.WithName("cmd")
 | ||||
| 
 | ||||
| func printInfo() { | ||||
| 	log.Log.Info(fmt.Sprintf("Version: %s", version.Version)) | ||||
| 	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) | ||||
| 	} | ||||
| 
 | ||||
| 	if( resources.IsRouteAPIAvailable(clientSet) ) { | ||||
| 		log.Log.Info("Route API found: Route creation will be performed") | ||||
| 	} | ||||
| 	c := make(chan e.Event) | ||||
| 	go notifications.Listen(c, events, mgr.GetClient()) | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ package apis | |||
| 
 | ||||
| import ( | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	routev1 "github.com/openshift/api/route/v1" | ||||
| 
 | ||||
| 	"k8s.io/apimachinery/pkg/runtime" | ||||
| ) | ||||
|  | @ -17,4 +18,5 @@ func AddToScheme(s *runtime.Scheme) error { | |||
| func init() { | ||||
| 	// 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, routev1.AddToScheme) | ||||
| } | ||||
|  |  | |||
|  | @ -177,15 +177,25 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod | |||
| 	} | ||||
| 	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 | ||||
| 	} | ||||
| 	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 { | ||||
| 		return err | ||||
| 	} | ||||
| 	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 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  | @ -12,6 +12,8 @@ import ( | |||
| 	"net" | ||||
| 	"strings" | ||||
| ) | ||||
| //ServiceKind the kind name for Service
 | ||||
| const ServiceKind = "Service" | ||||
| 
 | ||||
| // UpdateService returns new service with override fields from config
 | ||||
| func UpdateService(actual corev1.Service, config v1alpha2.Service) corev1.Service { | ||||
|  |  | |||
|  | @ -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)) | ||||
| } | ||||
|  | @ -72,7 +72,6 @@ func (e *enqueueRequestForJenkins) getOwnerReconcileRequests(object metav1.Objec | |||
| 			Name:      object.GetLabels()[constants.LabelJenkinsCRKey], | ||||
| 		}} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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
 | ||||
| // 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 { | ||||
| 	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
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue