diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 5fbf4a4d..010998b5 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -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()) diff --git a/pkg/apis/apis.go b/pkg/apis/apis.go index ea8a5783..a3782ece 100644 --- a/pkg/apis/apis.go +++ b/pkg/apis/apis.go @@ -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) } diff --git a/pkg/controller/jenkins/configuration/base/reconcile.go b/pkg/controller/jenkins/configuration/base/reconcile.go index e2679ad7..c59f812f 100644 --- a/pkg/controller/jenkins/configuration/base/reconcile.go +++ b/pkg/controller/jenkins/configuration/base/reconcile.go @@ -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 } diff --git a/pkg/controller/jenkins/configuration/base/resources/route.go b/pkg/controller/jenkins/configuration/base/resources/route.go new file mode 100644 index 00000000..369113a6 --- /dev/null +++ b/pkg/controller/jenkins/configuration/base/resources/route.go @@ -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 +} diff --git a/pkg/controller/jenkins/configuration/base/resources/service.go b/pkg/controller/jenkins/configuration/base/resources/service.go index 44a2b348..71cbec29 100644 --- a/pkg/controller/jenkins/configuration/base/resources/service.go +++ b/pkg/controller/jenkins/configuration/base/resources/service.go @@ -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 { diff --git a/pkg/controller/jenkins/configuration/base/route.go b/pkg/controller/jenkins/configuration/base/route.go new file mode 100644 index 00000000..fa0a956a --- /dev/null +++ b/pkg/controller/jenkins/configuration/base/route.go @@ -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)) +} diff --git a/pkg/controller/jenkins/handler.go b/pkg/controller/jenkins/handler.go index 6a6ca73a..1fb694ab 100644 --- a/pkg/controller/jenkins/handler.go +++ b/pkg/controller/jenkins/handler.go @@ -72,7 +72,6 @@ func (e *enqueueRequestForJenkins) getOwnerReconcileRequests(object metav1.Objec Name: object.GetLabels()[constants.LabelJenkinsCRKey], }} } - return nil } diff --git a/pkg/controller/jenkins/jenkins_controller.go b/pkg/controller/jenkins/jenkins_controller.go index 63a96a88..3c5ce315 100644 --- a/pkg/controller/jenkins/jenkins_controller.go +++ b/pkg/controller/jenkins/jenkins_controller.go @@ -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