From 822ac7ab4c10f57463b3d2712f7ebedb26721354 Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Wed, 27 Jan 2016 14:07:58 -0500 Subject: [PATCH] api: add initial work on the new API --- api/api.go | 44 ++++----------- api/context/context.go | 45 +++++++++++++++ api/handlers.go | 102 ---------------------------------- api/logger.go | 69 ----------------------- api/router.go | 71 ++++++++---------------- api/timeout.go | 101 --------------------------------- api/v1/models.go | 62 +++++++++++++++++++++ api/v1/router.go | 56 +++++++++++++++++++ api/v1/routes.go | 123 +++++++++++++++++++++++++++++++++++++++++ clair.go | 5 +- 10 files changed, 323 insertions(+), 355 deletions(-) create mode 100644 api/context/context.go delete mode 100644 api/handlers.go delete mode 100644 api/logger.go delete mode 100644 api/timeout.go create mode 100644 api/v1/models.go create mode 100644 api/v1/router.go create mode 100644 api/v1/routes.go diff --git a/api/api.go b/api/api.go index a8a9972b..9f8bf2fd 100644 --- a/api/api.go +++ b/api/api.go @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package api provides a RESTful HTTP API, enabling external apps to interact -// with clair. package api import ( @@ -25,37 +23,17 @@ import ( "strconv" "time" - "github.com/coreos/pkg/capnslog" - "github.com/julienschmidt/httprouter" + "github.com/prometheus/common/log" "github.com/tylerb/graceful" + "github.com/coreos/clair/api/context" "github.com/coreos/clair/config" - "github.com/coreos/clair/database" "github.com/coreos/clair/utils" ) -var log = capnslog.NewPackageLogger("github.com/coreos/clair", "api") +const timeoutResponse = `{"Error":{"Message":"Clair failed to respond within the configured timeout window.","Type":"Timeout"}}` -// Env stores the environment used by the API. -type Env struct { - Datastore database.Datastore -} - -// Handle adds a fourth parameter to httprouter.Handle: a pointer to *Env, -// allowing us to pass our environment to the handler. -type Handle func(http.ResponseWriter, *http.Request, httprouter.Params, *Env) - -// WrapHandle encloses a Handle into a httprouter.Handle to make it usable by -// httprouter. -func WrapHandle(fn Handle, e *Env) httprouter.Handle { - return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { - fn(w, r, p, e) - } -} - -// Run launches the main API, which exposes every possible interactions -// with clair. -func Run(config *config.APIConfig, env *Env, st *utils.Stopper) { +func Run(config *config.APIConfig, ctx *context.RouteContext, st *utils.Stopper) { defer st.End() // Do not run the API service if there is no config. @@ -79,18 +57,16 @@ func Run(config *config.APIConfig, env *Env, st *utils.Stopper) { Server: &http.Server{ Addr: ":" + strconv.Itoa(config.Port), TLSConfig: tlsConfig, - Handler: NewVersionRouter(config.Timeout, env), + Handler: http.TimeoutHandler(newAPIHandler(ctx), config.Timeout, timeoutResponse), }, } + listenAndServeWithStopper(srv, st, config.CertFile, config.KeyFile) + log.Info("main API stopped") } -// RunHealth launches the Health API, which only exposes a method to fetch -// Clair's health without any security or authentication mechanism. -func RunHealth(config *config.APIConfig, env *Env, st *utils.Stopper) { - defer st.End() - +func RunHealth(config *config.APIConfig, ctx *context.RouteContext, st *utils.Stopper) { // Do not run the API service if there is no config. if config == nil { log.Infof("health API service is disabled.") @@ -103,10 +79,12 @@ func RunHealth(config *config.APIConfig, env *Env, st *utils.Stopper) { NoSignalHandling: true, // We want to use our own Stopper Server: &http.Server{ Addr: ":" + strconv.Itoa(config.HealthPort), - Handler: NewHealthRouter(env), + Handler: http.TimeoutHandler(newHealthHandler(ctx), config.Timeout, timeoutResponse), }, } + listenAndServeWithStopper(srv, st, "", "") + log.Info("health API stopped") } diff --git a/api/context/context.go b/api/context/context.go new file mode 100644 index 00000000..ae81f87b --- /dev/null +++ b/api/context/context.go @@ -0,0 +1,45 @@ +// Copyright 2015 clair authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package context + +import ( + "fmt" + "net/http" + + "github.com/coreos/pkg/capnslog" + "github.com/julienschmidt/httprouter" + + "github.com/coreos/clair/database" +) + +var log = capnslog.NewPackageLogger("github.com/coreos/clair", "api") + +type Handler func(http.ResponseWriter, *http.Request, httprouter.Params, *RouteContext) int + +func HTTPHandler(handler Handler, ctx *RouteContext) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + status := handler(w, r, p, ctx) + statusStr := fmt.Sprintf("%d", status) + if status == 0 { + statusStr = "???" + } + + log.Infof("%s %s %s %s", statusStr, r.Method, r.RequestURI, r.RemoteAddr) + } +} + +type RouteContext struct { + Store database.Datastore +} diff --git a/api/handlers.go b/api/handlers.go deleted file mode 100644 index 3a6b0624..00000000 --- a/api/handlers.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2015 clair authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package api - -import ( - "net/http" - "strconv" - - "github.com/julienschmidt/httprouter" - - "github.com/coreos/clair/database" - httputils "github.com/coreos/clair/utils/http" - "github.com/coreos/clair/worker" -) - -// Version is an integer representing the API version. -const Version = 1 - -// POSTLayersParameters represents the expected parameters for POSTLayers. -type POSTLayersParameters struct { - Name, Path, ParentName string -} - -// GETVersions returns API and Engine versions. -func GETVersions(w http.ResponseWriter, r *http.Request, _ httprouter.Params, _ *Env) { - httputils.WriteHTTP(w, http.StatusOK, struct { - APIVersion string - EngineVersion string - }{ - APIVersion: strconv.Itoa(Version), - EngineVersion: strconv.Itoa(worker.Version), - }) -} - -// GETHealth sums up the health of all the registered services. -func GETHealth(w http.ResponseWriter, r *http.Request, _ httprouter.Params, e *Env) { - // globalHealth, statuses := health.Healthcheck(e.Datastore) - // - // httpStatus := http.StatusOK - // if !globalHealth { - // httpStatus = http.StatusServiceUnavailable - // } - // - // httputils.WriteHTTP(w, httpStatus, statuses) - return -} - -// POSTLayers analyzes a layer and returns the engine version that has been used -// for the analysis. -func POSTLayers(w http.ResponseWriter, r *http.Request, _ httprouter.Params, e *Env) { - var parameters POSTLayersParameters - if s, err := httputils.ParseHTTPBody(r, ¶meters); err != nil { - httputils.WriteHTTPError(w, s, err) - return - } - - // Process data. - if err := worker.Process(e.Datastore, parameters.Name, parameters.ParentName, parameters.Path); err != nil { - httputils.WriteHTTPError(w, 0, err) - return - } - - // Get engine version and return. - httputils.WriteHTTP(w, http.StatusCreated, struct{ Version string }{Version: strconv.Itoa(worker.Version)}) -} - -// DELETELayers deletes the specified layer and any child layers that are -// dependent on the specified layer. -func DELETELayers(w http.ResponseWriter, r *http.Request, p httprouter.Params, e *Env) { - if err := e.Datastore.DeleteLayer(p.ByName("name")); err != nil { - httputils.WriteHTTPError(w, 0, err) - return - } - httputils.WriteHTTP(w, http.StatusNoContent, nil) -} - -// GETLayers returns informations about an existing layer, optionally with its features -// and vulnerabilities. -func GETLayers(w http.ResponseWriter, r *http.Request, p httprouter.Params, e *Env) { - _, withFeatures := r.URL.Query()["withFeatures"] - _, withVulnerabilities := r.URL.Query()["withVulnerabilities"] - - layer, err := e.Datastore.FindLayer(p.ByName("name"), withFeatures, withVulnerabilities) - if err != nil { - httputils.WriteHTTPError(w, 0, err) - return - } - - httputils.WriteHTTP(w, http.StatusOK, struct{ Layer database.Layer }{Layer: layer}) -} diff --git a/api/logger.go b/api/logger.go deleted file mode 100644 index adbfd9e3..00000000 --- a/api/logger.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2015 clair authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package wrappers contains httprouter.Handle wrappers that are used in the API. -package api - -import ( - "net/http" - "time" - - "github.com/julienschmidt/httprouter" -) - -type logWriter struct { - http.ResponseWriter - status int - size int -} - -func (lw *logWriter) Header() http.Header { - return lw.ResponseWriter.Header() -} - -func (lw *logWriter) Write(b []byte) (int, error) { - if !lw.Written() { - lw.WriteHeader(http.StatusOK) - } - size, err := lw.ResponseWriter.Write(b) - lw.size += size - return size, err -} - -func (lw *logWriter) WriteHeader(s int) { - lw.status = s - lw.ResponseWriter.WriteHeader(s) -} - -func (lw *logWriter) Size() int { - return lw.size -} - -func (lw *logWriter) Written() bool { - return lw.status != 0 -} - -func (lw *logWriter) Status() int { - return lw.status -} - -// Logger wraps an Handler and logs the API call -func Logger(fn httprouter.Handle) httprouter.Handle { - return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { - lw := &logWriter{ResponseWriter: w} - start := time.Now() - fn(lw, r, p) - log.Infof("%d %s %s (%s)", lw.Status(), r.Method, r.RequestURI, time.Since(start)) - } -} diff --git a/api/router.go b/api/router.go index 61f70d1f..7eab8256 100644 --- a/api/router.go +++ b/api/router.go @@ -17,75 +17,50 @@ package api import ( "net/http" "strings" - "time" "github.com/julienschmidt/httprouter" + + "github.com/coreos/clair/api/context" + "github.com/coreos/clair/api/v1" ) -// VersionRouter is an HTTP router that forwards requests to the appropriate -// router depending on the API version specified in the requested URI. -type VersionRouter map[string]*httprouter.Router +// router is an HTTP router that forwards requests to the appropriate sub-router +// depending on the API version specified in the request URI. +type router map[string]*httprouter.Router -// NewVersionRouter instantiates a VersionRouter and every sub-routers that are -// necessary to handle supported API versions. -func NewVersionRouter(to time.Duration, env *Env) *VersionRouter { - return &VersionRouter{ - "/v1": NewRouterV1(to, env), - } +// Let's hope we never have more than 99 API versions. +const apiVersionLength = len("v99") + +func newAPIHandler(ctx *context.RouteContext) http.Handler { + router := make(router) + router["v1"] = v1.NewRouter(ctx) + return router } -// ServeHTTP forwards requests to the appropriate router depending on the API -// version specified in the requested URI and remove the version information -// from the request URL.Path, without modifying the request uRequestURI. -func (vs VersionRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (rtr router) ServeHTTP(w http.ResponseWriter, r *http.Request) { urlStr := r.URL.String() var version string - if len(urlStr) >= 3 { - version = urlStr[:3] + if len(urlStr) >= apiVersionLength { + version = urlStr[:apiVersionLength] } - if router, _ := vs[version]; router != nil { + + if router, _ := rtr[version]; router != nil { // Remove the version number from the request path to let the router do its // job but do not update the RequestURI r.URL.Path = strings.Replace(r.URL.Path, version, "", 1) router.ServeHTTP(w, r) return } + http.NotFound(w, r) } -// NewRouterV1 creates a new router for the API (Version 1) -func NewRouterV1(to time.Duration, env *Env) *httprouter.Router { +func newHealthHandler(ctx *context.RouteContext) http.Handler { router := httprouter.New() - - // Create a wrapper that will wrap a Handle into a httprouter.Handle and that adds - // logging and time-out capabilities. - wrap := func(fn Handle, e *Env) httprouter.Handle { - return Logger(TimeOut(to, WrapHandle(fn, e))) - } - - // General - router.GET("/versions", wrap(GETVersions, env)) - router.GET("/health", wrap(GETHealth, env)) - - // Layers - router.POST("/layers", wrap(POSTLayers, env)) - router.DELETE("/layers/:name", wrap(DELETELayers, env)) - router.GET("/layers/:name", wrap(GETLayers, env)) - - // Vulnerabilities - // router.POST("/vulnerabilities", wrap(logic.POSTVulnerabilities)) - // router.PUT("/vulnerabilities/:id", wrap(logic.PUTVulnerabilities)) - // router.GET("/vulnerabilities/:id", wrap(logic.GETVulnerabilities)) - // router.DELETE("/vulnerabilities/:id", wrap(logic.DELVulnerabilities)) - // router.GET("/vulnerabilities/:id/introducing-layers", wrap(logic.GETVulnerabilitiesIntroducingLayers)) - // router.POST("/vulnerabilities/:id/affected-layers", wrap(logic.POSTVulnerabilitiesAffectedLayers)) - + router.GET("/health", context.HTTPHandler(getHealth, ctx)) return router } -// NewHealthRouter creates a new router that only serve the Health function on / -func NewHealthRouter(env *Env) *httprouter.Router { - router := httprouter.New() - router.GET("/", WrapHandle(GETHealth, env)) - return router +func getHealth(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + return 0 } diff --git a/api/timeout.go b/api/timeout.go deleted file mode 100644 index 2819fc12..00000000 --- a/api/timeout.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2015 clair authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package api - -import ( - "errors" - "net/http" - "sync" - "time" - - "github.com/julienschmidt/httprouter" - - httputils "github.com/coreos/clair/utils/http" -) - -// ErrHandlerTimeout is returned on ResponseWriter Write calls -// in handlers which have timed out. -var ErrHandlerTimeout = errors.New("http: Handler timeout") - -type timeoutWriter struct { - http.ResponseWriter - - mu sync.Mutex - timedOut bool - wroteHeader bool -} - -func (tw *timeoutWriter) Header() http.Header { - return tw.ResponseWriter.Header() -} - -func (tw *timeoutWriter) Write(p []byte) (int, error) { - tw.mu.Lock() - defer tw.mu.Unlock() - tw.wroteHeader = true // implicitly at least - if tw.timedOut { - return 0, ErrHandlerTimeout - } - return tw.ResponseWriter.Write(p) -} - -func (tw *timeoutWriter) WriteHeader(status int) { - tw.mu.Lock() - defer tw.mu.Unlock() - if tw.timedOut || tw.wroteHeader { - return - } - tw.wroteHeader = true - tw.ResponseWriter.WriteHeader(status) -} - -// TimeOut wraps an Handler and ensure that a response is given under -// the specified duration. -// -// If the handler takes longer than the time limit, the wrapper responds with -// a Service Unavailable error, an error message and the handler response which -// may come later is ignored. -// -// After a timeout, any write the handler to its ResponseWriter will return -// ErrHandlerTimeout. -// -// If the duration is 0, the wrapper does nothing. -func TimeOut(d time.Duration, fn httprouter.Handle) httprouter.Handle { - if d == 0 { - return fn - } - - return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { - done := make(chan bool) - tw := &timeoutWriter{ResponseWriter: w} - - go func() { - fn(tw, r, p) - done <- true - }() - - select { - case <-done: - return - case <-time.After(d): - tw.mu.Lock() - defer tw.mu.Unlock() - if !tw.wroteHeader { - httputils.WriteHTTPError(tw.ResponseWriter, http.StatusServiceUnavailable, ErrHandlerTimeout) - } - tw.timedOut = true - } - } -} diff --git a/api/v1/models.go b/api/v1/models.go new file mode 100644 index 00000000..21159115 --- /dev/null +++ b/api/v1/models.go @@ -0,0 +1,62 @@ +// Copyright 2015 clair authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +type ErrorResponse struct { + Error string + Type string +} + +type Layer struct { + Name string + Path string + Parent string + IndexedByVersion int + Features []Feature +} + +type Vulnerability struct { + Name string + Namespace string + Description string + Severity string + FixedBy string + FixedIn []Feature +} + +type Feature struct { + Name string + Namespace string + Version string + Vulnerabilities []Vulnerability +} + +type Notification struct { + Name string + Created string + Notified string + Deleted string + Limit int + Page string + NextPage string + Old VulnerabilityWithLayers + New VulnerabilityWithLayers + Changed []string +} + +type VulnerabilityWithLayers struct { + Vulnerability Vulnerability + LayersIntroducingVulnerability []string +} diff --git a/api/v1/router.go b/api/v1/router.go new file mode 100644 index 00000000..5613dd93 --- /dev/null +++ b/api/v1/router.go @@ -0,0 +1,56 @@ +// Copyright 2015 clair authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package v1 implements the first version of the Clair API. +package v1 + +import ( + "github.com/julienschmidt/httprouter" + + "github.com/coreos/clair/api/context" +) + +// NewRouter creates an HTTP router for version 1 of the Clair API. +func NewRouter(ctx *context.RouteContext) *httprouter.Router { + router := httprouter.New() + + // Layers + router.POST("/layers", context.HTTPHandler(postLayer, ctx)) + router.GET("/layers/:layerName", context.HTTPHandler(getLayer, ctx)) + router.DELETE("/layers/:layerName", context.HTTPHandler(deleteLayer, ctx)) + + // Namespaces + router.GET("/namespaces", context.HTTPHandler(getNamespaces, ctx)) + + // Vulnerabilities + router.POST("/namespaces/:namespaceName/vulnerabilities", context.HTTPHandler(postVulnerability, ctx)) + router.GET("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName", context.HTTPHandler(getVulnerability, ctx)) + router.PATCH("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName", context.HTTPHandler(patchVulnerability, ctx)) + router.DELETE("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName", context.HTTPHandler(deleteVulnerability, ctx)) + + // Fixes + router.POST("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName/fixes", context.HTTPHandler(postFix, ctx)) + router.GET("/namespaces/:namespaceName/vulnerabilities/:vulernabilityName/fixes", context.HTTPHandler(getFixes, ctx)) + router.PUT("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(putFix, ctx)) + router.DELETE("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(deleteFix, ctx)) + + // Notifications + router.GET("/notifications/:notificationName", context.HTTPHandler(getNotification, ctx)) + router.DELETE("/notifications/:notificationName", context.HTTPHandler(deleteNotification, ctx)) + + // Metrics + router.GET("/metrics", context.HTTPHandler(getMetrics, ctx)) + + return router +} diff --git a/api/v1/routes.go b/api/v1/routes.go new file mode 100644 index 00000000..af8de1c5 --- /dev/null +++ b/api/v1/routes.go @@ -0,0 +1,123 @@ +// Copyright 2015 clair authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +import ( + "encoding/json" + "io" + "net/http" + + "github.com/julienschmidt/httprouter" + "github.com/prometheus/client_golang/prometheus" + + "github.com/coreos/clair/api/context" + cerrors "github.com/coreos/clair/utils/errors" + "github.com/coreos/clair/worker" +) + +// maxBodySize restricts client requests to 1MiB. +const maxBodySize int64 = 1048576 + +func decodeJSON(r *http.Request, v interface{}) error { + defer r.Body.Close() + return json.NewDecoder(io.LimitReader(r.Body, maxBodySize)).Decode(v) +} + +func writeError(w io.Writer, err error, errType string) { + err = json.NewEncoder(w).Encode(ErrorResponse{Error{err.Error(), errType}}) + if err != nil { + panic("v1: failed to marshal error response: " + err.Error()) + } +} + +func postLayer(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + request := LayerRequest{} + err := decodeJSON(r, &request) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + writeError(w, err, "BadRequest") + return http.StatusBadRequest + } + + err = worker.Process(ctx.Store, request.Layer.Name, request.Layer.ParentName, request.Layer.Path, request.Layer.Format) + if err != nil { + if _, ok := err.(*cerrors.ErrBadRequest); ok { + w.WriteHeader(http.StatusBadRequest) + writeError(w, err, "BadRequest") + } + w.WriteHeader(http.StatusInternalServerError) + writeError(w, err, "InternalServerError") + } + + w.WriteHeader(http.StatusCreated) + return http.StatusCreated +} + +func getLayer(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + // ez + return 0 +} +func deleteLayer(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + // ez + return 0 +} + +func getNamespaces(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + return 0 +} + +func postVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + // ez + return 0 +} +func getVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + // ez + return 0 +} +func patchVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + // ez + return 0 +} +func deleteVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + // ez + return 0 +} + +func postFix(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + return 0 +} +func getFixes(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + return 0 +} +func putFix(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + return 0 +} +func deleteFix(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + return 0 +} + +func getNotification(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + // ez + return 0 +} +func deleteNotification(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + // ez + return 0 +} + +func getMetrics(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) int { + prometheus.Handler().ServeHTTP(w, r) + return 0 +} diff --git a/clair.go b/clair.go index 9d9f4685..64e2acc0 100644 --- a/clair.go +++ b/clair.go @@ -23,6 +23,7 @@ import ( "time" "github.com/coreos/clair/api" + "github.com/coreos/clair/api/context" "github.com/coreos/clair/config" "github.com/coreos/clair/database/pgsql" "github.com/coreos/clair/notifier" @@ -52,9 +53,9 @@ func Boot(config *config.Config) { // Start API st.Begin() - go api.Run(config.API, &api.Env{Datastore: db}, st) + go api.Run(config.API, &context.RouteContext{db}, st) st.Begin() - go api.RunHealth(config.API, &api.Env{Datastore: db}, st) + go api.RunHealth(config.API, &context.RouteContext{db}, st) // Start updater st.Begin()