Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #280 Unidle Jenkins only if needed #282

Merged
merged 1 commit into from
May 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 57 additions & 28 deletions internal/proxy/ui_requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,29 @@ func (p *Proxy) handleJenkinsUIRequest(w http.ResponseWriter, r *http.Request, r
nsLogger := requestLogEntry.WithFields(log.Fields{"ns": ns, "cluster": clusterURL})
nsLogger.Debug("Found token info in query")

state, err := p.idler.State(ns, clusterURL)
// we don't care about code here since only the state of jenkins pod
// running or not is what is relevant

state, _, err := p.startJenkins(ns, clusterURL)
if err != nil {
p.HandleError(w, err, requestLogEntry)
return
}

//Break the process if the Jenkins is idled, set a cookie and redirect to self
if state != clients.Running {
_, err := p.idler.UnIdle(ns, clusterURL)
if err != nil {
p.HandleError(w, err, requestLogEntry)
return
}
// Break the process if Jenkins isn't running.

// Set "idled" cookie to indicate that jenkins is idled
// also cache the ns & cluster for faster lookup next time
p.setIdledCookie(w, pci)
requestLogEntry.WithField("ns", ns).Info("Redirecting to remove token from URL")
http.Redirect(w, r, redirectURL.String(), http.StatusFound) //Redirect to get rid of token in URL

// Redirect to get rid of token in URL
nsLogger.Info("Redirecting to remove token from URL")
http.Redirect(w, r, redirectURL.String(), http.StatusFound)
return
}

// Jenkins is running at this point
osoToken, err := util.GetOSOToken(p.authURL, pci.ClusterURL, osioToken)
if err != nil {
p.HandleError(w, err, requestLogEntry)
Expand Down Expand Up @@ -118,7 +121,8 @@ func (p *Proxy) handleJenkinsUIRequest(w http.ResponseWriter, r *http.Request, r
if !ok {
continue
}
if strings.HasPrefix(cookie.Name, SessionCookie) { //We found a session cookie in cache
if strings.HasPrefix(cookie.Name, SessionCookie) {
// We found a session cookie in cache
cacheKey = cookie.Value
pci := cacheVal.(CacheItem)
r.Host = pci.Route //Configure proxy upstream
Expand All @@ -128,42 +132,39 @@ func (p *Proxy) handleJenkinsUIRequest(w http.ResponseWriter, r *http.Request, r
needsAuth = false //user is probably logged in, do not redirect
noProxy = false
break
} else if cookie.Name == CookieJenkinsIdled { //Found a cookie saying Jenkins is idled, verify and act accordingly
} else if cookie.Name == CookieJenkinsIdled {
// Found a cookie saying Jenkins is idled, verify and act accordingly
cacheKey = cookie.Value
needsAuth = false
pci := cacheVal.(CacheItem)
ns = pci.NS
clusterURL := pci.ClusterURL
state, err := p.idler.State(ns, clusterURL)

state, code, err := p.startJenkins(ns, clusterURL)
if err != nil {
p.HandleError(w, err, requestLogEntry)
return
}
// If jenkins is not "running", return loading page and status 202
if state != clients.Running {
code, err := p.idler.UnIdle(ns, clusterURL)
if err != nil {
p.HandleError(w, err, requestLogEntry)
return
}

if code == http.StatusOK {
code = http.StatusAccepted
} else if code != http.StatusServiceUnavailable {
p.HandleError(w, fmt.Errorf("Failed to send unidle request using fabric8-jenkins-idler"), requestLogEntry)
}
// error if unexpected code is returned
if code != http.StatusServiceUnavailable && code != http.StatusAccepted {
p.HandleError(w, fmt.Errorf("Failed to send unidle request using fabric8-jenkins-idler: code: %d", code), requestLogEntry)
}

if state != clients.Running {
w.WriteHeader(code)
err = p.processTemplate(w, ns, requestLogEntry)
if err != nil {
p.HandleError(w, err, requestLogEntry)
return
}
p.recordStatistics(pci.NS, time.Now().Unix(), 0) //FIXME - maybe do this at the beginning?
} else { //If Jenkins is running, remove the cookie
//OpenShift can take up to couple tens of second to update HAProxy configuration for new route
//so even if the pod is up, route might still return 500 - i.e. we need to check the route
//before claiming Jenkins is up

} else {
// Jenkins is running, remove the idled cookie
// OpenShift can take up to couple tens of second to update HAProxy configuration for new route
// so even if the pod is up, route might still return 500 - i.e. we need to check the route
// before claiming Jenkins is up
var statusCode int
statusCode, _, err = p.loginJenkins(pci, "", requestLogEntry)
if err != nil {
Expand Down Expand Up @@ -270,3 +271,31 @@ func (p *Proxy) processToken(tokenData []byte, requestLogEntry *log.Entry) (pci

return
}

// unidles Jenkins only if it is idled and returns the
// state of the pod, the http status of calling unidle, and error if any
func (p *Proxy) startJenkins(ns, clusterURL string) (state clients.PodState, code int, err error) {
// Assume pods are starting and unidle only if it is in "idled" state
code = http.StatusAccepted

state, err = p.idler.State(ns, clusterURL)
if err != nil {
return
}

if state == clients.Idled {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember you saying that even if jenkins is idling then also we have three states
Running -> Intermediate -> Idled. Is that right?

If the state is Intermediate, it would be worth knowing if Jenkins is idling or un-idling. But let's do that as a different PR, WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kishansagathiya at present idler does not give us that information. We need to build that logic into idler which should return state like "starting", "running", "idling", "idled" which at the moment, it doesn't and thus can't be built into proxy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Let's create an issue for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Unidle only if needed
if code, err = p.idler.UnIdle(ns, clusterURL); err != nil {
return
}
}

if code == http.StatusOK {
// XHR relies on 202 to retry and 200 to stop retrying and reload
// since we just started jenkins pods, change the code to 202 so
// that it retries
// SEE: static/html/index.html
code = http.StatusAccepted
}
return state, code, nil
}
5 changes: 4 additions & 1 deletion static/html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@
});
}

check()
// don't start immediately as the page is returned only if
// jenkins is idled and we assume that it won't be unidled
// as soon as the page is returned
setTimeout(check, timeout)
});
</script>
</head>
Expand Down