14087: Federated fetch by PDH WIP
[arvados.git] / lib / controller / federation.go
index c4ccb15d256f6a2d7a5dc59e66a948cdf3a66a69..d68f44d95b65ebd7afd2372c55a8b5fbf16d6cda 100644 (file)
@@ -24,13 +24,14 @@ import (
 
 var wfRe = regexp.MustCompile(`^/arvados/v1/workflows/([0-9a-z]{5})-[^/]+$`)
 var collectionRe = regexp.MustCompile(`^/arvados/v1/collections/([0-9a-z]{5})-[^/]+$`)
+var collectionByPDHRe = regexp.MustCompile(`^/arvados/v1/collections/([0-9a-fA-F]{32}\+[0-9]+)+$`)
 
-type GenericFederatedRequestHandler struct {
+type genericFederatedRequestHandler struct {
        next    http.Handler
        handler *Handler
 }
 
-type CollectionFederatedRequestHandler struct {
+type collectionFederatedRequestHandler struct {
        next    http.Handler
        handler *Handler
 }
@@ -64,7 +65,7 @@ func (h *Handler) remoteClusterRequest(remoteID string, w http.ResponseWriter, r
        h.proxy.Do(w, req, urlOut, client, filter)
 }
 
-func (h *GenericFederatedRequestHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+func (h *genericFederatedRequestHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
        m := wfRe.FindStringSubmatch(req.URL.Path)
        if len(m) < 2 || m[1] == h.handler.Cluster.ClusterID {
                h.next.ServeHTTP(w, req)
@@ -132,8 +133,49 @@ func (clusterId rewriteSignaturesClusterId) rewriteSignatures(resp *http.Respons
        return resp, nil
 }
 
-func (h *CollectionFederatedRequestHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
-       m := collectionRe.FindStringSubmatch(req.URL.Path)
+type searchLocalClusterForPDH struct {
+       needSearchFederation bool
+}
+
+func (s *searchLocalClusterForPDH) filterLocalClusterResponse(resp *http.Response) (newResponse *http.Response, err error) {
+       if resp.StatusCode == 404 {
+               // Suppress returning this result, because we want to
+               // search the federation.
+               s.needSearchFederation = true
+               return nil, nil
+       }
+       return resp, nil
+}
+
+func (h *collectionFederatedRequestHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+       m := collectionByPDHRe.FindStringSubmatch(req.URL.Path)
+       if len(m) == 2 {
+               urlOut, insecure, err := findRailsAPI(h.handler.Cluster, h.handler.NodeProfile)
+               if err != nil {
+                       httpserver.Error(w, err.Error(), http.StatusInternalServerError)
+                       return
+               }
+
+               urlOut = &url.URL{
+                       Scheme:   urlOut.Scheme,
+                       Host:     urlOut.Host,
+                       Path:     req.URL.Path,
+                       RawPath:  req.URL.RawPath,
+                       RawQuery: req.URL.RawQuery,
+               }
+               client := h.handler.secureClient
+               if insecure {
+                       client = h.handler.insecureClient
+               }
+               sf := &searchLocalClusterForPDH{false}
+               h.handler.proxy.Do(w, req, urlOut, client, sf.filterLocalClusterResponse)
+               if !sf.needSearchFederation {
+                       // a response was sent
+                       return
+               }
+       }
+
+       m = collectionRe.FindStringSubmatch(req.URL.Path)
        if len(m) < 2 || m[1] == h.handler.Cluster.ClusterID {
                h.next.ServeHTTP(w, req)
                return
@@ -145,8 +187,9 @@ func (h *CollectionFederatedRequestHandler) ServeHTTP(w http.ResponseWriter, req
 func (h *Handler) setupProxyRemoteCluster(next http.Handler) http.Handler {
        mux := http.NewServeMux()
        mux.Handle("/arvados/v1/workflows", next)
-       mux.Handle("/arvados/v1/workflows/", &GenericFederatedRequestHandler{next, h})
-       mux.Handle("/arvados/v1/collections/", &CollectionFederatedRequestHandler{next, h})
+       mux.Handle("/arvados/v1/workflows/", &genericFederatedRequestHandler{next, h})
+       mux.Handle("/arvados/v1/collections", next)
+       mux.Handle("/arvados/v1/collections/", &collectionFederatedRequestHandler{next, h})
        mux.Handle("/", next)
 
        return mux