From 45bf0ef86a6d9f9329131394e39db1afa1749284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Unbekandt?= Date: Thu, 29 Jun 2017 11:26:13 +0200 Subject: [PATCH] Api: add NamespaceName attribute to post Layer Allow user to specify NamespaceName if not found by featurens --- api/v1/routes.go | 2 +- worker.go | 22 +++++++++++++++++++--- worker_test.go | 29 ++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/api/v1/routes.go b/api/v1/routes.go index f44dde67..800d2b23 100644 --- a/api/v1/routes.go +++ b/api/v1/routes.go @@ -109,7 +109,7 @@ func postLayer(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx return postLayerRoute, http.StatusBadRequest } - err = clair.ProcessLayer(ctx.Store, request.Layer.Format, request.Layer.Name, request.Layer.ParentName, request.Layer.Path, request.Layer.Headers) + err = clair.ProcessLayer(ctx.Store, request.Layer.Format, request.Layer.Name, request.Layer.ParentName, request.Layer.Path, request.Layer.Headers, request.Layer.NamespaceName) if err != nil { if err == tarutil.ErrCouldNotExtract || err == tarutil.ErrExtractedFileTooBig || diff --git a/worker.go b/worker.go index 76e2605c..76d3e660 100644 --- a/worker.go +++ b/worker.go @@ -56,7 +56,7 @@ func cleanURL(str string) string { // // TODO(Quentin-M): We could have a goroutine that looks for layers that have // been analyzed with an older engine version and that processes them. -func ProcessLayer(datastore database.Datastore, imageFormat, name, parentName, path string, headers map[string]string) error { +func ProcessLayer(datastore database.Datastore, imageFormat, name, parentName, path string, headers map[string]string, namespaceName string) error { // Verify parameters. if name == "" { return commonerr.NewBadRequestError("could not process a layer which does not have a name") @@ -104,8 +104,19 @@ func ProcessLayer(datastore database.Datastore, imageFormat, name, parentName, p log.WithFields(log.Fields{logLayerName: name, "past engine version": layer.EngineVersion, "current engine version": Version}).Debug("layer content has already been processed in the past with older engine. analyzing again") } + // Check to see if the user's provided Namespace exists + var namespace *database.Namespace + if namespaceName != "" { + namespace, err = datastore.GetNamespace(namespaceName) + if err != nil { + if err == commonerr.ErrNotFound { + return commonerr.NewBadRequestError("could not find provided namespace") + } + return err + } + } // Analyze the content. - layer.Namespace, layer.Features, err = detectContent(imageFormat, name, path, headers, layer.Parent) + layer.Namespace, layer.Features, err = detectContent(imageFormat, name, path, headers, layer.Parent, namespace) if err != nil { return err } @@ -115,7 +126,7 @@ func ProcessLayer(datastore database.Datastore, imageFormat, name, parentName, p // detectContent downloads a layer's archive and extracts its Namespace and // Features. -func detectContent(imageFormat, name, path string, headers map[string]string, parent *database.Layer) (namespace *database.Namespace, featureVersions []database.FeatureVersion, err error) { +func detectContent(imageFormat, name, path string, headers map[string]string, parent *database.Layer, ns *database.Namespace) (namespace *database.Namespace, featureVersions []database.FeatureVersion, err error) { totalRequiredFiles := append(featurefmt.RequiredFilenames(), featurens.RequiredFilenames()...) files, err := imagefmt.Extract(imageFormat, path, headers, totalRequiredFiles) if err != nil { @@ -128,6 +139,11 @@ func detectContent(imageFormat, name, path string, headers map[string]string, pa return } + if namespace == nil && ns != nil { + log.WithFields(log.Fields{logLayerName: name, "namespace provided by user": ns.Name}).Debug("detected namespace") + namespace = ns + } + // Detect features. featureVersions, err = detectFeatureVersions(name, files, namespace, parent) if err != nil { diff --git a/worker_test.go b/worker_test.go index b0f14dbc..c04786eb 100644 --- a/worker_test.go +++ b/worker_test.go @@ -34,12 +34,14 @@ import ( type mockDatastore struct { database.MockDatastore - layers map[string]database.Layer + layers map[string]database.Layer + namespaces map[string]database.Namespace } func newMockDatastore() *mockDatastore { return &mockDatastore{ - layers: make(map[string]database.Layer), + layers: make(map[string]database.Layer), + namespaces: make(map[string]database.Namespace), } } @@ -59,6 +61,15 @@ func TestProcessWithDistUpgrade(t *testing.T) { } return database.Layer{}, commonerr.ErrNotFound } + datastore.FctGetNamespace = func(namespaceName string) (*database.Namespace, error) { + if namespace, exists := datastore.namespaces[namespaceName]; exists { + return &namespace, nil + } + return nil, commonerr.ErrNotFound + } + + // Add Namespace + datastore.namespaces["debian:7"] = database.Namespace{Name: "debian:7"} // Create the list of FeatureVersions that should not been upgraded from one layer to another. nonUpgradedFeatureVersions := []database.FeatureVersion{ @@ -78,9 +89,17 @@ func TestProcessWithDistUpgrade(t *testing.T) { // wheezy.tar: FROM debian:wheezy // jessie.tar: RUN sed -i "s/precise/trusty/" /etc/apt/sources.list && apt-get update && // apt-get -y dist-upgrade - assert.Nil(t, ProcessLayer(datastore, "Docker", "blank", "", testDataPath+"blank.tar.gz", nil)) - assert.Nil(t, ProcessLayer(datastore, "Docker", "wheezy", "blank", testDataPath+"wheezy.tar.gz", nil)) - assert.Nil(t, ProcessLayer(datastore, "Docker", "jessie", "wheezy", testDataPath+"jessie.tar.gz", nil)) + assert.Nil(t, ProcessLayer(datastore, "Docker", "blank", "", testDataPath+"blank.tar.gz", nil, "")) + assert.Nil(t, ProcessLayer(datastore, "Docker", "blankWithNamespace", "", testDataPath+"blank.tar.gz", nil, "debian:7")) + assert.Nil(t, ProcessLayer(datastore, "Docker", "wheezy", "blank", testDataPath+"wheezy.tar.gz", nil, "")) + assert.Nil(t, ProcessLayer(datastore, "Docker", "jessie", "wheezy", testDataPath+"jessie.tar.gz", nil, "")) + + // Ensure that the 'blankWithNamespace' layer has the provided namespace + blankWithNamespace, ok := datastore.layers["blankWithNamespace"] + if assert.True(t, ok, "layer 'blankWithNamespace' not processed") { + assert.Equal(t, "debian:7", blankWithNamespace.Namespace.Name) + assert.Len(t, blankWithNamespace.Features, 0) + } // Ensure that the 'wheezy' layer has the expected namespace and features. wheezy, ok := datastore.layers["wheezy"]