Skip to content
This repository has been archived by the owner on Dec 9, 2022. It is now read-only.

Commit

Permalink
Merge pull request #39 from enoodle/image-server
Browse files Browse the repository at this point in the history
factor out image serving
  • Loading branch information
simon3z authored Apr 6, 2017
2 parents b1e0dc7 + aad87b9 commit 89148d8
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 141 deletions.
3 changes: 2 additions & 1 deletion cmd/image-inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"

iiapi "github.com/openshift/image-inspector/pkg/api"
iicmd "github.com/openshift/image-inspector/pkg/cmd"
ii "github.com/openshift/image-inspector/pkg/inspector"
)
Expand All @@ -20,7 +21,7 @@ func main() {
flag.Var(&inspectorOptions.DockerCfg, "dockercfg", "Location of the docker configuration files. May be specified more than once")
flag.StringVar(&inspectorOptions.Username, "username", inspectorOptions.Username, "username for authenticating with the docker registry")
flag.StringVar(&inspectorOptions.PasswordFile, "password-file", inspectorOptions.PasswordFile, "Location of a file that contains the password for authentication with the docker registry")
flag.StringVar(&inspectorOptions.ScanType, "scan-type", inspectorOptions.ScanType, fmt.Sprintf("The type of the scan to be done on the inspected image. Available scan types are: %v", iicmd.ScanOptions))
flag.StringVar(&inspectorOptions.ScanType, "scan-type", inspectorOptions.ScanType, fmt.Sprintf("The type of the scan to be done on the inspected image. Available scan types are: %v", iiapi.ScanOptions))
flag.StringVar(&inspectorOptions.ScanResultsDir, "scan-results-dir", inspectorOptions.ScanResultsDir, "The directory that will contain the results of the scan")
flag.BoolVar(&inspectorOptions.OpenScapHTML, "openscap-html-report", inspectorOptions.OpenScapHTML, "Generate an OpenScap HTML report in addition to the ARF formatted report")
flag.StringVar(&inspectorOptions.CVEUrlPath, "cve-url", inspectorOptions.CVEUrlPath, "An alternative URL source for CVE files")
Expand Down
44 changes: 44 additions & 0 deletions pkg/api/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package api

import (
docker "github.com/fsouza/go-dockerclient"
"time"
)

// OpenSCAPStatus is the status of openscap scan
type OpenSCAPStatus string

const (
StatusNotRequested OpenSCAPStatus = "NotRequested"
StatusSuccess OpenSCAPStatus = "Success"
StatusError OpenSCAPStatus = "Error"
)

type OpenSCAPMetadata struct {
Status OpenSCAPStatus // Status of the OpenSCAP scan report
ErrorMessage string // Error message from the openscap
ContentTimeStamp string // Timestamp for this data
}

func (osm *OpenSCAPMetadata) SetError(err error) {
osm.Status = StatusError
osm.ErrorMessage = err.Error()
osm.ContentTimeStamp = string(time.Now().Format(time.RFC850))
}

var (
ScanOptions = []string{"openscap"}
)

// InspectorMetadata is the metadata type with information about image-inspector's operation
type InspectorMetadata struct {
docker.Image // Metadata about the inspected image
// OpenSCAP describes the state of the OpenSCAP scan
OpenSCAP *OpenSCAPMetadata
}

// APIVersions holds a slice of supported API versions.
type APIVersions struct {
// Versions is the supported API versions
Versions []string `json:"versions"`
}
13 changes: 7 additions & 6 deletions pkg/cmd/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package cmd

import (
"fmt"

oscapscanner "github.com/openshift/image-inspector/pkg/openscap"
"os"
)

var (
ScanOptions = []string{"openscap"}
iiapi "github.com/openshift/image-inspector/pkg/api"

"os"
)

// MultiStringVar is implementing flag.Value
Expand Down Expand Up @@ -110,14 +110,15 @@ func (i *ImageInspectorOptions) Validate() error {
}
if len(i.ScanType) > 0 {
var found bool = false
for _, opt := range ScanOptions {
for _, opt := range iiapi.ScanOptions {
if i.ScanType == opt {
found = true
break
}
}
if !found {
return fmt.Errorf("%s is not one of the available scan-types which are %v", i.ScanType, ScanOptions)
return fmt.Errorf("%s is not one of the available scan-types which are %v",
i.ScanType, iiapi.ScanOptions)
}

}
Expand Down
41 changes: 41 additions & 0 deletions pkg/imageserver/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package imageserver

import (
iiapi "github.com/openshift/image-inspector/pkg/api"
)

// ImageServer abstracts the serving of image information.
type ImageServer interface {
// ServeImage Serves the image
ServeImage(meta *iiapi.InspectorMetadata,
scanReport []byte,
htmlScanReport []byte) error
}

// ImageServerOptions is used to configure an image server.
type ImageServerOptions struct {
// ServePath is the root path/port of serving. ex 0.0.0.0:8080
ServePath string
// HealthzURL is the relative url of the health check. ex /healthz
HealthzURL string
// APIURL is the relative url where the api will be served. ex /api
APIURL string
// APIVersions are the supported API versions.
APIVersions iiapi.APIVersions
// MetadataURL is the relative url of the metadata content. ex /api/v1/metadata
MetadataURL string
// ContentURL is the relative url of the content. ex /api/v1/content/
ContentURL string
// ImageServeURL is the location that the image is being served from.
// NOTE: if the image server supports a chroot the server implementation will perform
// the chroot based on this URL.
ImageServeURL string
// ScanType is the type of the scan that was done on the inspected image
ScanType string
// ScanReportURL is the url to publish the scan report
ScanReportURL string
// HTMLScanReport wether or not to publish an HTML scan report
HTMLScanReport bool
// HTMLScanReportURL url for the scan html report
HTMLScanReportURL string
}
112 changes: 112 additions & 0 deletions pkg/imageserver/webdav.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package imageserver

import (
"encoding/json"
"fmt"
"log"
"net/http"
"syscall"

"golang.org/x/net/webdav"

iiapi "github.com/openshift/image-inspector/pkg/api"
)

const (
// CHROOT_SERVE_PATH is the path to server if we are performing a chroot
// this probably does not belong here.
CHROOT_SERVE_PATH = "/"
)

// webdavImageServer implements ImageServer.
type webdavImageServer struct {
opts ImageServerOptions
chroot bool
}

// ensures this always implements the interface or fail compilation.
var _ ImageServer = &webdavImageServer{}

// NewWebdavImageServer creates a new webdav image server.
func NewWebdavImageServer(opts ImageServerOptions, chroot bool) ImageServer {
return &webdavImageServer{
opts: opts,
chroot: chroot,
}
}

// ServeImage Serves the image.
func (s *webdavImageServer) ServeImage(meta *iiapi.InspectorMetadata,
scanReport []byte,
htmlScanReport []byte) error {

servePath := s.opts.ImageServeURL
if s.chroot {
if err := syscall.Chroot(s.opts.ImageServeURL); err != nil {
return fmt.Errorf("Unable to chroot into %s: %v\n", s.opts.ImageServeURL, err)
}
servePath = CHROOT_SERVE_PATH
} else {
log.Printf("!!!WARNING!!! It is insecure to serve the image content without changing")
log.Printf("root (--chroot). Absolute-path symlinks in the image can lead to disclose")
log.Printf("information of the hosting system.")
}

log.Printf("Serving image content %s on webdav://%s%s", s.opts.ImageServeURL, s.opts.ServePath, s.opts.ContentURL)

http.HandleFunc(s.opts.HealthzURL, func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok\n"))
})

http.HandleFunc(s.opts.APIURL, func(w http.ResponseWriter, r *http.Request) {
body, err := json.MarshalIndent(s.opts.APIVersions, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(body)
})

http.HandleFunc(s.opts.MetadataURL, func(w http.ResponseWriter, r *http.Request) {
body, err := json.MarshalIndent(meta, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(body)
})

http.HandleFunc(s.opts.ScanReportURL, func(w http.ResponseWriter, r *http.Request) {
if s.opts.ScanType != "" && meta.OpenSCAP.Status == iiapi.StatusSuccess {
w.Write(scanReport)
} else {
if meta.OpenSCAP.Status == iiapi.StatusError {
http.Error(w, fmt.Sprintf("OpenSCAP Error: %s", meta.OpenSCAP.ErrorMessage),
http.StatusInternalServerError)
} else {
http.Error(w, "OpenSCAP option was not chosen", http.StatusNotFound)
}
}
})

http.HandleFunc(s.opts.HTMLScanReportURL, func(w http.ResponseWriter, r *http.Request) {
if s.opts.ScanType != "" && meta.OpenSCAP.Status == iiapi.StatusSuccess && s.opts.HTMLScanReport {
w.Write(htmlScanReport)
} else {
if meta.OpenSCAP.Status == iiapi.StatusError {
http.Error(w, fmt.Sprintf("OpenSCAP Error: %s", meta.OpenSCAP.ErrorMessage),
http.StatusInternalServerError)
} else {
http.Error(w, "OpenSCAP option was not chosen", http.StatusNotFound)
}
}
})

http.Handle(s.opts.ContentURL, &webdav.Handler{
Prefix: s.opts.ContentURL,
FileSystem: webdav.Dir(servePath),
LockSystem: webdav.NewMemLS(),
})

return http.ListenAndServe(s.opts.ServePath, nil)
}
Loading

0 comments on commit 89148d8

Please sign in to comment.