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/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()) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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" | 	"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 { | ||||||
|  |  | ||||||
|  | @ -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], | 			Name:      object.GetLabels()[constants.LabelJenkinsCRKey], | ||||||
| 		}} | 		}} | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	return nil | 	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
 | // 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
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue