Skip to content

Commit

Permalink
Status handling for RouteHealth
Browse files Browse the repository at this point in the history
  • Loading branch information
jhadvig committed Mar 23, 2020
1 parent 7a9c899 commit 76ecdd5
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 7 deletions.
74 changes: 74 additions & 0 deletions pkg/console/controllers/route/controller.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package route

import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"net/http"
"time"

// k8s
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
coreclientv1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog"
Expand Down Expand Up @@ -38,6 +43,7 @@ type RouteSyncController struct {
// clients
operatorConfigClient operatorclientv1.ConsoleInterface
routeClient routeclientv1.RoutesGetter
configMapClient coreclientv1.ConfigMapsGetter
// names
targetNamespace string
routeName string
Expand All @@ -51,6 +57,7 @@ func NewRouteSyncController(
// clients
operatorConfigClient operatorclientv1.ConsoleInterface,
routev1Client routeclientv1.RoutesGetter,
configMapClient coreclientv1.ConfigMapsGetter,
// informers
operatorConfigInformer v1.ConsoleInformer,
routeInformer routesinformersv1.RouteInformer,
Expand All @@ -63,6 +70,7 @@ func NewRouteSyncController(
ctrl := &RouteSyncController{
operatorConfigClient: operatorConfigClient,
routeClient: routev1Client,
configMapClient: configMapClient,
targetNamespace: targetNamespace,
routeName: routeName,
// events
Expand Down Expand Up @@ -128,6 +136,8 @@ func (c *RouteSyncController) SyncRoute(operatorConfig *operatorsv1.Console) (co
if rtErr != nil {
return nil, false, "FailedCreate", rtErr
}
// Check if the console is reachable
c.CheckRouteHealth(operatorConfig, rt)

// we will not proceed until the route is valid. this eliminates complexity with the
// configmap, secret & oauth client as they can be certain they have a host if we pass this point.
Expand Down Expand Up @@ -192,3 +202,67 @@ func (c *RouteSyncController) newEventHandler() cache.ResourceEventHandler {
DeleteFunc: func(obj interface{}) { c.queue.Add(controllerWorkQueueKey) },
}
}

func (c *RouteSyncController) CheckRouteHealth(opConfig *operatorsv1.Console, rt *routev1.Route) {
status.HandleDegraded(func() (conf *operatorsv1.Console, prefix string, reason string, err error) {
prefix = "RouteHealth"

caPool, err := c.getCA()
if err != nil {
return opConfig, prefix, "FailedLoadCA", fmt.Errorf("failed to read CA to check route health: %v", err)
}
client := clientWithCA(caPool)

url := "https://" + rt.Spec.Host + "/health"
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return opConfig, prefix, "FailedRequest", fmt.Errorf("failed to build request to route (%s): %v", url, err)
}
resp, err := client.Do(req)
if err != nil {
return opConfig, prefix, "FailedGet", fmt.Errorf("failed to GET route (%s): %v", url, err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return opConfig, prefix, "StatusError", fmt.Errorf("route not yet available, %s returns '%s'", url, resp.Status)

}
return opConfig, prefix, "", nil
}())

status.HandleAvailable(opConfig, "Route", "FailedAdmittedIngress", func() error {
if !routesub.IsAdmitted(rt) {
return errors.New("console route is not admitted")
}
return nil
}())
}

func (c *RouteSyncController) getCA() (*x509.CertPool, error) {
caCertPool := x509.NewCertPool()

for _, cmName := range []string{api.TrustedCAConfigMapName, api.DefaultIngressCertConfigMapName} {
cm, err := c.configMapClient.ConfigMaps(api.OpenShiftConsoleNamespace).Get(cmName, metav1.GetOptions{})
if err != nil {
klog.V(4).Infof("failed to GET configmap %s / %s ", api.OpenShiftConsoleNamespace, cmName)
return nil, err
}
if ok := caCertPool.AppendCertsFromPEM([]byte(cm.Data["ca-bundle.crt"])); !ok {
klog.V(4).Infof("failed to parse %s ca-bundle.crt", cmName)
}
}

return caCertPool, nil
}

func clientWithCA(caPool *x509.CertPool) *http.Client {
return &http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: caPool,
},
},
}
}
7 changes: 0 additions & 7 deletions pkg/console/operator/sync_v400.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,6 @@ func (co *consoleOperator) sync_v400(updatedOperatorConfig *operatorv1.Console,
return updatedOperatorConfig, prefix, "", nil
}())

status.HandleAvailable(updatedOperatorConfig, "Route", "FailedAdmittedIngress", func() error {
if !routesub.IsAdmitted(rt) {
return errors.New("console route is not admitted")
}
return nil
}())

// if we survive the gauntlet, we need to update the console config with the
// public hostname so that the world can know the console is ready to roll
klog.V(4).Infoln("sync_v400: updating console status")
Expand Down
1 change: 1 addition & 0 deletions pkg/console/starter/starter.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
// operator config
operatorConfigClient.OperatorV1().Consoles(),
routesClient.RouteV1(),
kubeClient.CoreV1(),
// route
operatorConfigInformers.Operator().V1().Consoles(),
routesInformersNamespaced.Route().V1().Routes(),
Expand Down

0 comments on commit 76ecdd5

Please sign in to comment.