index with interval

Signed-off-by: Jess Frazelle <acidburn@google.com>
This commit is contained in:
Jess Frazelle 2017-04-24 14:39:00 -04:00
parent 183c0d5ba3
commit abc0d51801
No known key found for this signature in database
GPG key ID: 18F3685C0022BFF3
5 changed files with 92 additions and 52 deletions

View file

@ -4,12 +4,12 @@ import (
"encoding/json"
"fmt"
"net/http"
log "github.com/Sirupsen/logrus"
"github.com/gorilla/mux"
"os"
"path/filepath"
"time"
"github.com/Sirupsen/logrus"
"github.com/gorilla/mux"
"github.com/jessfraz/reg/clair"
"github.com/jessfraz/reg/registry"
)
@ -40,25 +40,17 @@ type AnalysisResult struct {
Name string `json:"name"`
}
func (rc *registryController) repositoriesHandler(w http.ResponseWriter, r *http.Request) {
log.WithFields(log.Fields{
"func": "repositories",
"URL": r.URL,
"method": r.Method,
}).Info("fetching repositories")
func (rc *registryController) repositories(staticDir string) error {
updating = true
logrus.Info("fetching catalog")
result := AnalysisResult{}
result.RegistryDomain = rc.reg.Domain
result := AnalysisResult{
RegistryDomain: rc.reg.Domain,
}
repoList, err := rc.reg.Catalog("")
repoList, err := r.Catalog("")
if err != nil {
log.WithFields(log.Fields{
"func": "repositories",
"URL": r.URL,
"method": r.Method,
}).Errorf("getting catalog failed: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
return fmt.Errorf("getting catalog failed: %v", err)
}
for _, repo := range repoList {
@ -71,19 +63,31 @@ func (rc *registryController) repositoriesHandler(w http.ResponseWriter, r *http
result.Repositories = append(result.Repositories, r)
}
if err := tmpl.ExecuteTemplate(w, "repositories", result); err != nil {
log.WithFields(log.Fields{
"func": "repositories",
"URL": r.URL,
"method": r.Method,
}).Errorf("template rendering failed: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
// parse & execute the template
logrus.Info("executing the template repositories")
path := filepath.Join(staticDir, "index.html")
if err := os.MkdirAll(filepath.Dir(path), 0644); err != nil {
return err
}
logrus.Debugf("creating/opening file %s", path)
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
if err := tmpl.ExecuteTemplate(f, "repositories", result); err != nil {
f.Close()
return fmt.Errorf("execute template repositories failed: %v", err)
}
updating = false
return nil
}
func (rc *registryController) tagsHandler(w http.ResponseWriter, r *http.Request) {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "tags",
"URL": r.URL,
"method": r.Method,
@ -99,7 +103,7 @@ func (rc *registryController) tagsHandler(w http.ResponseWriter, r *http.Request
tags, err := rc.reg.Tags(repo)
if err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "tags",
"URL": r.URL,
"method": r.Method,
@ -117,7 +121,7 @@ func (rc *registryController) tagsHandler(w http.ResponseWriter, r *http.Request
// get the manifest
m1, err := rc.reg.ManifestV1(repo, tag)
if err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "tags",
"URL": r.URL,
"method": r.Method,
@ -132,7 +136,7 @@ func (rc *registryController) tagsHandler(w http.ResponseWriter, r *http.Request
var comp v1Compatibility
if err := json.Unmarshal([]byte(h.V1Compatibility), &comp); err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "tags",
"URL": r.URL,
"method": r.Method,
@ -159,7 +163,7 @@ func (rc *registryController) tagsHandler(w http.ResponseWriter, r *http.Request
if rc.cl != nil {
vuln, err := rc.cl.Vulnerabilities(rc.reg, repo, tag, m1)
if err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "tags",
"URL": r.URL,
"method": r.Method,
@ -174,7 +178,7 @@ func (rc *registryController) tagsHandler(w http.ResponseWriter, r *http.Request
}
if err := tmpl.ExecuteTemplate(w, "tags", result); err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "tags",
"URL": r.URL,
"method": r.Method,
@ -186,7 +190,7 @@ func (rc *registryController) tagsHandler(w http.ResponseWriter, r *http.Request
}
func (rc *registryController) vulnerabilitiesHandler(w http.ResponseWriter, r *http.Request) {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "vulnerabilities",
"URL": r.URL,
"method": r.Method,
@ -210,7 +214,7 @@ func (rc *registryController) vulnerabilitiesHandler(w http.ResponseWriter, r *h
m1, err := rc.reg.ManifestV1(repo, tag)
if err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "vulnerabilities",
"URL": r.URL,
"method": r.Method,
@ -224,7 +228,7 @@ func (rc *registryController) vulnerabilitiesHandler(w http.ResponseWriter, r *h
var comp v1Compatibility
if err := json.Unmarshal([]byte(h.V1Compatibility), &comp); err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "vulnerabilities",
"URL": r.URL,
"method": r.Method,
@ -241,7 +245,7 @@ func (rc *registryController) vulnerabilitiesHandler(w http.ResponseWriter, r *h
if rc.cl != nil {
result, err = rc.cl.Vulnerabilities(rc.reg, repo, tag, m1)
if err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "vulnerabilities",
"URL": r.URL,
"method": r.Method,
@ -254,7 +258,7 @@ func (rc *registryController) vulnerabilitiesHandler(w http.ResponseWriter, r *h
if r.Header.Get("Accept-Encoding") == "application/json" {
js, err := json.Marshal(result)
if err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "vulnerabilities",
"URL": r.URL,
"method": r.Method,
@ -269,7 +273,7 @@ func (rc *registryController) vulnerabilitiesHandler(w http.ResponseWriter, r *h
}
if err := tmpl.ExecuteTemplate(w, "vulns", result); err != nil {
log.WithFields(log.Fields{
logrus.WithFields(logrus.Fields{
"func": "vulnerabilities",
"URL": r.URL,
"method": r.Method,

View file

@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/gorilla/mux"
@ -24,9 +25,10 @@ const (
)
var (
r *registry.Registry
cl *clair.Clair
tmpl *template.Template
updating = false
r *registry.Registry
cl *clair.Clair
tmpl *template.Template
)
// preload initializes any global options and configuration
@ -81,6 +83,11 @@ func main() {
Name: "key",
Usage: "path to ssl key",
},
cli.StringFlag{
Name: "interval",
Value: "5m",
Usage: "interval to generate new index.html's at",
},
cli.StringFlag{
Name: "clair",
Usage: "url to clair instance",
@ -170,17 +177,46 @@ func main() {
cl: cl,
}
// create the initial index
logrus.Info("creating initial static index")
if err := rc.repositories(staticDir); err != nil {
logrus.Fatalf("Error creating index: %v", err)
}
// parse the duration
dur, err := time.ParseDuration(c.String("interval"))
if err != nil {
logrus.Fatalf("parsing %s as duration failed: %v", c.String("interval"), err)
}
ticker := time.NewTicker(dur)
go func() {
// create more indexes every X minutes based off interval
for range ticker.C {
if !updating {
logrus.Info("creating timer based static index")
if err := rc.repositories(staticDir); err != nil {
logrus.Warnf("creating static index failed: %v", err)
updating = false
}
} else {
logrus.Warnf("skipping timer based static index update for %s", c.String("interval"))
}
}
}()
// create mux server
mux := mux.NewRouter()
// static files handler
staticHandler := http.FileServer(http.Dir(staticDir))
mux.Handle("/static/", http.StripPrefix("/static/", staticHandler))
mux.Handle("/", staticHandler)
mux.HandleFunc("/repo/{repo}", rc.tagsHandler)
mux.HandleFunc("/repo/{repo}/", rc.tagsHandler)
mux.HandleFunc("/repo/{repo}/{tag}", rc.vulnerabilitiesHandler)
mux.HandleFunc("/repo/{repo}/{tag}/", rc.vulnerabilitiesHandler)
mux.HandleFunc("/repo/{repo}/{tag}/vulns", rc.vulnerabilitiesHandler)
mux.HandleFunc("/", rc.repositoriesHandler)
mux.HandleFunc("/repo/{repo}/{tag}/vulns/", rc.vulnerabilitiesHandler)
// set up the server
port := c.String("port")

View file

@ -9,8 +9,8 @@
<base href="/" >
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>{{ .RegistryDomain }}</title>
<link rel="icon" type="image/ico" href="/static/favicon.ico">
<link rel="stylesheet" href="/static/css/styles.css" />
<link rel="icon" type="image/ico" href="/favicon.ico">
<link rel="stylesheet" href="/css/styles.css" />
</head>
<body>
<h1>{{ .RegistryDomain }}</h1>
@ -45,7 +45,7 @@
<div class="footer">
<a href="https://twitter.com/jessfraz">@jessfraz</a>
</div><!--/.footer-->
<script src="/static/js/scripts.js"></script>
<script src="/js/scripts.js"></script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),

View file

@ -9,8 +9,8 @@
<base href="/" >
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>{{ .RegistryDomain }}/{{ .Name }}</title>
<link rel="icon" type="image/ico" href="/static/favicon.ico">
<link rel="stylesheet" href="/static/css/styles.css" />
<link rel="icon" type="image/ico" href="/favicon.ico">
<link rel="stylesheet" href="/css/styles.css" />
</head>
<body>
<h1>{{ .RegistryDomain }}/{{ .Name }}</h1>

View file

@ -9,8 +9,8 @@
<base href="/" >
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>{{ .RegistryURL }}/{{ .Repo }}:{{ .Tag }} Vulnerability Report</title>
<link rel="icon" type="image/ico" href="/static/favicon.ico">
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<link rel="icon" type="image/ico" href="/favicon.ico">
<link rel="stylesheet" href="/css/bootstrap.min.css" />
</head>
<body>
<div class="container">