From 937816dd1fc98e988eb9fc45a23d4e359cf27e2f Mon Sep 17 00:00:00 2001 From: lynzabo Date: Mon, 9 Oct 2017 07:48:27 -0700 Subject: [PATCH] clair code review --- api/v1/routes.go | 5 +- cmd/clair/config.go | 114 -------------------------------------------- cmd/clair/main.go | 89 ++++++++++++++++++++++++++++++++++ config.yaml | 80 +++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+), 115 deletions(-) delete mode 100644 cmd/clair/config.go create mode 100644 config.yaml diff --git a/api/v1/routes.go b/api/v1/routes.go index f44dde67..e2ba84bb 100644 --- a/api/v1/routes.go +++ b/api/v1/routes.go @@ -111,11 +111,14 @@ func postLayer(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx err = clair.ProcessLayer(ctx.Store, request.Layer.Format, request.Layer.Name, request.Layer.ParentName, request.Layer.Path, request.Layer.Headers) if err != nil { + //tarutil: could not extract the archive if err == tarutil.ErrCouldNotExtract || + //tarutil: could not extract one or more files from the archive: file too big err == tarutil.ErrExtractedFileTooBig || + //worker: OS and/or package manager are not supported err == clair.ErrUnsupported { writeResponse(w, r, statusUnprocessableEntity, LayerEnvelope{Error: &Error{err.Error()}}) - return postLayerRoute, statusUnprocessableEntity + return postLayerRoute, statusUnprocessableEntity //422 } if _, badreq := err.(*commonerr.ErrBadRequest); badreq { diff --git a/cmd/clair/config.go b/cmd/clair/config.go deleted file mode 100644 index 3e57a979..00000000 --- a/cmd/clair/config.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2017 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 main - -import ( - "errors" - "io/ioutil" - "os" - "time" - - "gopkg.in/yaml.v2" - - "github.com/coreos/clair" - "github.com/coreos/clair/api" - "github.com/coreos/clair/database" - "github.com/coreos/clair/ext/notification" - "github.com/fernet/fernet-go" -) - -// ErrDatasourceNotLoaded is returned when the datasource variable in the -// configuration file is not loaded properly -var ErrDatasourceNotLoaded = errors.New("could not load configuration: no database source specified") - -// File represents a YAML configuration file that namespaces all Clair -// configuration under the top-level "clair" key. -type File struct { - Clair Config `yaml:"clair"` -} - -// Config is the global configuration for an instance of Clair. -type Config struct { - Database database.RegistrableComponentConfig - Updater *clair.UpdaterConfig - Notifier *notification.Config - API *api.Config -} - -// DefaultConfig is a configuration that can be used as a fallback value. -func DefaultConfig() Config { - return Config{ - Database: database.RegistrableComponentConfig{ - Type: "pgsql", - }, - Updater: &clair.UpdaterConfig{ - Interval: 1 * time.Hour, - }, - API: &api.Config{ - Port: 6060, - HealthPort: 6061, - Timeout: 900 * time.Second, - }, - Notifier: ¬ification.Config{ - Attempts: 5, - RenotifyInterval: 2 * time.Hour, - }, - } -} - -// LoadConfig is a shortcut to open a file, read it, and generate a Config. -// -// It supports relative and absolute paths. Given "", it returns DefaultConfig. -func LoadConfig(path string) (config *Config, err error) { - var cfgFile File - cfgFile.Clair = DefaultConfig() - if path == "" { - return &cfgFile.Clair, nil - } - - f, err := os.Open(os.ExpandEnv(path)) - if err != nil { - return - } - defer f.Close() - - d, err := ioutil.ReadAll(f) - if err != nil { - return - } - - err = yaml.Unmarshal(d, &cfgFile) - if err != nil { - return - } - config = &cfgFile.Clair - - // Generate a pagination key if none is provided. - if config.API.PaginationKey == "" { - var key fernet.Key - if err = key.Generate(); err != nil { - return - } - config.API.PaginationKey = key.Encode() - } else { - _, err = fernet.DecodeKey(config.API.PaginationKey) - if err != nil { - err = errors.New("Invalid Pagination key; must be 32-bit URL-safe base64") - return - } - } - - return -} diff --git a/cmd/clair/main.go b/cmd/clair/main.go index efed24ba..2328bc11 100644 --- a/cmd/clair/main.go +++ b/cmd/clair/main.go @@ -55,8 +55,97 @@ import ( _ "github.com/coreos/clair/ext/vulnsrc/oracle" _ "github.com/coreos/clair/ext/vulnsrc/rhel" _ "github.com/coreos/clair/ext/vulnsrc/ubuntu" + "gopkg.in/yaml.v2" + + "github.com/coreos/clair/ext/notification" + "io/ioutil" + "github.com/fernet/fernet-go" + "errors" ) +// ErrDatasourceNotLoaded is returned when the datasource variable in the +// configuration file is not loaded properly +var ErrDatasourceNotLoaded = errors.New("could not load configuration: no database source specified") + +// File represents a YAML configuration file that namespaces all Clair +// configuration under the top-level "clair" key. +type File struct { + Clair Config `yaml:"clair"` +} + +// Config is the global configuration for an instance of Clair. +type Config struct { + Database database.RegistrableComponentConfig + Updater *clair.UpdaterConfig + Notifier *notification.Config + API *api.Config +} + +// DefaultConfig is a configuration that can be used as a fallback value. +func DefaultConfig() Config { + return Config{ + Database: database.RegistrableComponentConfig{ + Type: "pgsql", + }, + Updater: &clair.UpdaterConfig{ + Interval: 1 * time.Hour, + }, + API: &api.Config{ + Port: 6060, + HealthPort: 6061, + Timeout: 900 * time.Second, + }, + Notifier: ¬ification.Config{ + Attempts: 5, + RenotifyInterval: 2 * time.Hour, + }, + } +} + +// LoadConfig is a shortcut to open a file, read it, and generate a Config. +// +// It supports relative and absolute paths. Given "", it returns DefaultConfig. +func LoadConfig(path string) (config *Config, err error) { + var cfgFile File + cfgFile.Clair = DefaultConfig() + if path == "" { + return &cfgFile.Clair, nil + } + + f, err := os.Open(os.ExpandEnv(path)) + if err != nil { + return + } + defer f.Close() + + d, err := ioutil.ReadAll(f) + if err != nil { + return + } + + err = yaml.Unmarshal(d, &cfgFile) + if err != nil { + return + } + config = &cfgFile.Clair + + // Generate a pagination key if none is provided. + if config.API.PaginationKey == "" { + var key fernet.Key + if err = key.Generate(); err != nil { + return + } + config.API.PaginationKey = key.Encode() + } else { + _, err = fernet.DecodeKey(config.API.PaginationKey) + if err != nil { + err = errors.New("Invalid Pagination key; must be 32-bit URL-safe base64") + return + } + } + + return +} func waitForSignals(signals ...os.Signal) { interrupts := make(chan os.Signal, 1) signal.Notify(interrupts, signals...) diff --git a/config.yaml b/config.yaml new file mode 100644 index 00000000..7c269259 --- /dev/null +++ b/config.yaml @@ -0,0 +1,80 @@ +# 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. + +# The values specified here are the default values that Clair uses if no configuration file is specified or if the keys are not defined. +clair: + database: + # Database driver + type: pgsql + options: + # PostgreSQL Connection string + # https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING + source: host=192.168.10.11 port=5432 user=postgres password=123456 sslmode=disable statement_timeout=60000 + + # Number of elements kept in the cache + # Values unlikely to change (e.g. namespaces) are cached in order to save prevent needless roundtrips to the database. + cachesize: 16384 + + api: + # API server port + port: 6060 + + # Health server port + # This is an unencrypted endpoint useful for load balancers to check to healthiness of the clair server. + healthport: 6061 + + # Deadline before an API request will respond with a 503 + timeout: 900s + + # 32-bit URL-safe base64 key used to encrypt pagination tokens + # If one is not provided, it will be generated. + # Multiple clair instances in the same cluster need the same value. + paginationkey: + + # Optional PKI configuration + # If you want to easily generate client certificates and CAs, try the following projects: + # https://github.com/coreos/etcd-ca + # https://github.com/cloudflare/cfssl + servername: + cafile: + keyfile: + certfile: + + updater: + # Frequency the database will be updated with vulnerabilities from the default data sources + # The value 0 disables the updater entirely. + interval: 2h + + notifier: + # Number of attempts before the notification is marked as failed to be sent + attempts: 3 + + # Duration before a failed notification is retried + renotifyinterval: 2h + + http: + # Optional endpoint that will receive notifications via POST requests + endpoint: + + # Optional PKI configuration + # If you want to easily generate client certificates and CAs, try the following projects: + # https://github.com/cloudflare/cfssl + # https://github.com/coreos/etcd-ca + servername: + cafile: + keyfile: + certfile: + + # Optional HTTP Proxy: must be a valid URL (including the scheme). + proxy: