diff --git a/go.work.sum b/go.work.sum index ad5810785..bdad31cca 100644 --- a/go.work.sum +++ b/go.work.sum @@ -127,6 +127,7 @@ cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIE cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/apex/log v1.1.4 h1:3Zk+boorIQAAGBrHn0JUtAau4ihMamT4WdnfdnXM1zQ= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= @@ -146,7 +147,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1: github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -191,8 +191,5 @@ google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsA k8s.io/api v0.27.1/go.mod h1:z5g/BpAiD+f6AArpqNjkY+cji8ueZDU/WV1jcj5Jk4E= k8s.io/gengo v0.0.0-20220913193501-391367153a38/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a h1:gmovKNur38vgoWfGtP5QOGNOA7ki4n6qNYoFAgMlNvg= k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= -k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= diff --git a/pkg/airgapped/helper.go b/pkg/airgapped/helper.go index 6d50e9cf6..0e75eab16 100644 --- a/pkg/airgapped/helper.go +++ b/pkg/airgapped/helper.go @@ -23,11 +23,11 @@ func GetPluginInventoryMetadataImage(pluginInventoryImage string) (string, error return fmt.Sprintf("%s-metadata:%s", ref.Repository(), ref.Tag()), nil } -// GetImageRelativePath returns relative path of the image based on `basePath` -// E.g. If image is `fake.repo.com/plugin/plugin-inventory:latest` with +// GetImageRelativePath returns the relative path of the image with respect to `basePath` +// E.g. If the image is `fake.repo.com/plugin/database/plugin-inventory:latest` with // basePath as `fake.repo.com/plugin` it should return -// `plugin-inventory:latest` if withTag is true and -// `plugin-inventory` if withTag is false +// `database/plugin-inventory:latest` if withTag is true and +// `database/plugin-inventory` if withTag is false func GetImageRelativePath(image, basePath string, withTag bool) string { relativePath := strings.TrimPrefix(image, basePath) if withTag { diff --git a/pkg/airgapped/plugin_bundle_upload.go b/pkg/airgapped/plugin_bundle_upload.go index fab9f2d59..b360735d3 100644 --- a/pkg/airgapped/plugin_bundle_upload.go +++ b/pkg/airgapped/plugin_bundle_upload.go @@ -98,6 +98,7 @@ func (o *UploadPluginBundleOptions) mergePluginInventoryMetadata(pluginInventory if err != nil { return err } + log.Infof("plugin inventory metadata image %q is present. Merging the plugin inventory metadata", pluginInventoryMetadataImageWithTag) } else { log.Infof("plugin inventory metadata image %q is not present. Skipping merging of the plugin inventory metadata", pluginInventoryMetadataImageWithTag) } diff --git a/pkg/plugininventory/plugin_inventory_metadata.go b/pkg/plugininventory/plugin_inventory_metadata.go index 0fdba945e..5d06d2e6a 100644 --- a/pkg/plugininventory/plugin_inventory_metadata.go +++ b/pkg/plugininventory/plugin_inventory_metadata.go @@ -3,18 +3,8 @@ package plugininventory -import ( - "database/sql" - - // Import the sqlite3 driver - _ "modernc.org/sqlite" - - "github.com/pkg/errors" -) - // PluginInventoryMetadata is the interface to interact with a plugin inventory // metadata database and plugin inventory database. -// plugin and plugin group identifier // It can be used to create database schema for metadata db, insert // plugin and plugin group identifier and merging metadata database // This interface also provides function to update plugin inventory database @@ -38,117 +28,7 @@ type PluginInventoryMetadata interface { MergeInventoryMetadataDatabase(additionalMetadataDBFilePath string) error // UpdatePluginInventoryDatabase updates the plugin inventory database based - // on the plugin inventory metadata database by deleting entries that doesn't + // on the plugin inventory metadata database by deleting entries that don't // exists in plugin inventory metadata database UpdatePluginInventoryDatabase(pluginInventoryDBFilePath string) error } - -// SQLiteInventoryMetadata is an inventory metadata stored using SQLite -type SQLiteInventoryMetadata struct { - // inventoryMetadataDBFile represents the full path to the SQLite DB file - inventoryMetadataDBFile string -} - -const ( - // SQliteInventoryMetadataDBFileName is the name of the DB file that is stored in - // the OCI image describing the plugin inventory metadata. - SQliteInventoryMetadataDBFileName = "plugin_inventory_metadata.db" -) - -// NewSQLiteInventoryMetadata returns a new PluginInventoryMetadata connected to the data found at 'inventoryMetadataDBFile'. -func NewSQLiteInventoryMetadata(inventoryMetadataDBFile string) PluginInventoryMetadata { - return &SQLiteInventoryMetadata{ - inventoryMetadataDBFile: inventoryMetadataDBFile, - } -} - -// CreateInventoryMetadataDBSchema creates table schemas for -// plugin inventory metadata database -// returns error if table creation fails for any reason -func (b *SQLiteInventoryMetadata) CreateInventoryMetadataDBSchema() error { - db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) - if err != nil { - return errors.Wrapf(err, "failed to open the DB at '%s'", b.inventoryMetadataDBFile) - } - defer db.Close() - - _, err = db.Exec(PluginInventoryMetadataCreateTablesSchema) - if err != nil { - return errors.Wrap(err, "error while creating tables to the database") - } - - return nil -} - -// InsertPluginIdentifier inserts the PluginIdentifier entry to the -// AvailablePluginBinaries table -func (b *SQLiteInventoryMetadata) InsertPluginIdentifier(pi *PluginIdentifier) error { - db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) - if err != nil { - return errors.Wrapf(err, "failed to open the DB from '%s' file", b.inventoryMetadataDBFile) - } - defer db.Close() - - _, err = db.Exec("INSERT INTO AvailablePluginBinaries VALUES(?,?,?);", pi.Name, pi.Target, pi.Version) - if err != nil { - return errors.Wrapf(err, "unable to insert plugin identifier %v", pi) - } - return nil -} - -// InsertPluginGroupIdentifier inserts the PluginGroupIdentifier entry to the -// AvailablePluginGroups table -func (b *SQLiteInventoryMetadata) InsertPluginGroupIdentifier(pgi *PluginGroupIdentifier) error { - db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) - if err != nil { - return errors.Wrapf(err, "failed to open the DB from '%s' file", b.inventoryMetadataDBFile) - } - defer db.Close() - - _, err = db.Exec("INSERT INTO AvailablePluginGroups VALUES(?,?,?);", pgi.Vendor, pgi.Publisher, pgi.Name) - if err != nil { - return errors.Wrapf(err, "unable to insert plugin group identifier %v", pgi) - } - return nil -} - -// MergeInventoryMetadataDatabase merges two inventory metadata database by -// merging the content of AvailablePluginBinaries and AvailablePluginGroups tables -func (b *SQLiteInventoryMetadata) MergeInventoryMetadataDatabase(additionalMetadataDBFilePath string) error { - db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) - if err != nil { - return errors.Wrapf(err, "failed to open the DB from '%s' file", b.inventoryMetadataDBFile) - } - defer db.Close() - - mergeQuery := `attach ? as additionalMetadataDB; - INSERT OR REPLACE INTO AvailablePluginGroups SELECT Vendor,Publisher,GroupName FROM additionalMetadataDB.AvailablePluginGroups; - INSERT OR REPLACE INTO AvailablePluginBinaries SELECT PluginName,Target,Version FROM additionalMetadataDB.AvailablePluginBinaries;` - - _, err = db.Exec(mergeQuery, additionalMetadataDBFilePath) - if err != nil { - return errors.Wrapf(err, "unable to execute the query %v", mergeQuery) - } - return nil -} - -// UpdatePluginInventoryDatabase updates the plugin inventory database based -// on the plugin inventory metadata database by deleting entries that doesn't -// exists in plugin inventory metadata database -func (b *SQLiteInventoryMetadata) UpdatePluginInventoryDatabase(pluginInventoryDBFilePath string) error { - db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) - if err != nil { - return errors.Wrapf(err, "failed to open the DB from '%s' file", b.inventoryMetadataDBFile) - } - defer db.Close() - - updateQuery := `attach ? as piDB; - DELETE FROM piDB.PluginGroups WHERE ROWID IN (SELECT a.ROWID FROM piDB.PluginGroups a LEFT JOIN AvailablePluginGroups b ON b.Vendor = a.Vendor AND b.Publisher = a.Publisher AND b.GroupName = a.GroupName WHERE b.GroupName IS null); - DELETE FROM piDB.PluginBinaries WHERE ROWID IN (SELECT a.ROWID FROM piDB.PluginBinaries a LEFT JOIN AvailablePluginBinaries b ON b.PluginName = a.PluginName AND b.Target = a.Target AND b.Version = a.Version WHERE b.PluginName IS null);` - - _, err = db.Exec(updateQuery, pluginInventoryDBFilePath) - if err != nil { - return errors.Wrap(err, "error while updating plugin inventory database") - } - return nil -} diff --git a/pkg/plugininventory/sqlite_inventory_metadata.go b/pkg/plugininventory/sqlite_inventory_metadata.go new file mode 100644 index 000000000..133824aa4 --- /dev/null +++ b/pkg/plugininventory/sqlite_inventory_metadata.go @@ -0,0 +1,123 @@ +// Copyright 2023 VMware, Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package plugininventory + +import ( + "database/sql" + + // Import the sqlite3 driver + _ "modernc.org/sqlite" + + "github.com/pkg/errors" +) + +// SQLiteInventoryMetadata is an inventory metadata stored using SQLite +type SQLiteInventoryMetadata struct { + // inventoryMetadataDBFile represents the full path to the SQLite DB file + inventoryMetadataDBFile string +} + +const ( + // SQliteInventoryMetadataDBFileName is the name of the DB file that is stored in + // the OCI image describing the plugin inventory metadata. + SQliteInventoryMetadataDBFileName = "plugin_inventory_metadata.db" +) + +// NewSQLiteInventoryMetadata returns a new PluginInventoryMetadata connected to the data found at 'inventoryMetadataDBFile'. +func NewSQLiteInventoryMetadata(inventoryMetadataDBFile string) PluginInventoryMetadata { + return &SQLiteInventoryMetadata{ + inventoryMetadataDBFile: inventoryMetadataDBFile, + } +} + +// CreateInventoryMetadataDBSchema creates table schemas for +// plugin inventory metadata database +// returns error if table creation fails for any reason +func (b *SQLiteInventoryMetadata) CreateInventoryMetadataDBSchema() error { + db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) + if err != nil { + return errors.Wrapf(err, "failed to open the DB at '%s'", b.inventoryMetadataDBFile) + } + defer db.Close() + + _, err = db.Exec(PluginInventoryMetadataCreateTablesSchema) + if err != nil { + return errors.Wrap(err, "error while creating tables to the database") + } + + return nil +} + +// InsertPluginIdentifier inserts the PluginIdentifier entry to the +// AvailablePluginBinaries table +func (b *SQLiteInventoryMetadata) InsertPluginIdentifier(pi *PluginIdentifier) error { + db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) + if err != nil { + return errors.Wrapf(err, "failed to open the DB from '%s' file", b.inventoryMetadataDBFile) + } + defer db.Close() + + _, err = db.Exec("INSERT INTO AvailablePluginBinaries VALUES(?,?,?);", pi.Name, pi.Target, pi.Version) + if err != nil { + return errors.Wrapf(err, "unable to insert plugin identifier %v", pi) + } + return nil +} + +// InsertPluginGroupIdentifier inserts the PluginGroupIdentifier entry to the +// AvailablePluginGroups table +func (b *SQLiteInventoryMetadata) InsertPluginGroupIdentifier(pgi *PluginGroupIdentifier) error { + db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) + if err != nil { + return errors.Wrapf(err, "failed to open the DB from '%s' file", b.inventoryMetadataDBFile) + } + defer db.Close() + + _, err = db.Exec("INSERT INTO AvailablePluginGroups VALUES(?,?,?);", pgi.Vendor, pgi.Publisher, pgi.Name) + if err != nil { + return errors.Wrapf(err, "unable to insert plugin group identifier %v", pgi) + } + return nil +} + +// MergeInventoryMetadataDatabase merges two inventory metadata database by +// merging the content of AvailablePluginBinaries and AvailablePluginGroups tables +func (b *SQLiteInventoryMetadata) MergeInventoryMetadataDatabase(additionalMetadataDBFilePath string) error { + db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) + if err != nil { + return errors.Wrapf(err, "failed to open the DB from '%s' file", b.inventoryMetadataDBFile) + } + defer db.Close() + + mergeQuery := `attach ? as additionalMetadataDB; + INSERT OR REPLACE INTO AvailablePluginGroups SELECT Vendor,Publisher,GroupName FROM additionalMetadataDB.AvailablePluginGroups; + INSERT OR REPLACE INTO AvailablePluginBinaries SELECT PluginName,Target,Version FROM additionalMetadataDB.AvailablePluginBinaries;` + + _, err = db.Exec(mergeQuery, additionalMetadataDBFilePath) + if err != nil { + return errors.Wrapf(err, "unable to execute the query %v", mergeQuery) + } + return nil +} + +// UpdatePluginInventoryDatabase updates the plugin inventory database based +// on the plugin inventory metadata database by deleting entries that don't +// exists in plugin inventory metadata database +func (b *SQLiteInventoryMetadata) UpdatePluginInventoryDatabase(pluginInventoryDBFilePath string) error { + db, err := sql.Open("sqlite", b.inventoryMetadataDBFile) + if err != nil { + return errors.Wrapf(err, "failed to open the DB from '%s' file", b.inventoryMetadataDBFile) + } + defer db.Close() + + updateQuery := `ATTACH ? as piDB; + DELETE FROM piDB.PluginGroups WHERE ROWID IN (SELECT a.ROWID FROM piDB.PluginGroups a LEFT JOIN AvailablePluginGroups b ON b.Vendor = a.Vendor AND b.Publisher = a.Publisher AND b.GroupName = a.GroupName WHERE b.GroupName IS null); + DELETE FROM piDB.PluginBinaries WHERE ROWID IN (SELECT a.ROWID FROM piDB.PluginBinaries a LEFT JOIN AvailablePluginBinaries b ON b.PluginName = a.PluginName AND b.Target = a.Target AND b.Version = a.Version WHERE b.PluginName IS null);` + + _, err = db.Exec(updateQuery, pluginInventoryDBFilePath) + if err != nil { + return errors.Wrap(err, "error while updating plugin inventory database") + } + return nil +} diff --git a/pkg/plugininventory/plugin_inventory_metadata_test.go b/pkg/plugininventory/sqlite_inventory_metadata_test.go similarity index 100% rename from pkg/plugininventory/plugin_inventory_metadata_test.go rename to pkg/plugininventory/sqlite_inventory_metadata_test.go