Skip to content

Commit dcc7e50

Browse files
committed
Adding deprecated property type to bundles
Adding support marking bundles as deprecated and truncating the update graph of a given package. Deprecated versions will not be installable. Deprecating a bundle can result in the removal of channels but this is not permitted for the default channel. Bundles that are not in the index will be ignored during deprecation.
1 parent 3403f43 commit dcc7e50

File tree

14 files changed

+844
-8
lines changed

14 files changed

+844
-8
lines changed
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
annotations:
22
operators.operatorframework.io.bundle.package.v1: "etcd"
3-
operators.operatorframework.io.bundle.channels.v1: "alpha,stable"
4-
operators.operatorframework.io.bundle.channel.default.v1: "stable"
3+
operators.operatorframework.io.bundle.channels.v1: "alpha,stable,beta"
4+
operators.operatorframework.io.bundle.channel.default.v1: "stable"
5+

cmd/opm/index/cmd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ func AddCommand(parent *cobra.Command) {
2525
addIndexAddCmd(cmd)
2626
cmd.AddCommand(newIndexExportCmd())
2727
cmd.AddCommand(newIndexPruneCmd())
28+
cmd.AddCommand(newIndexDeprecateTruncateCmd())
2829
}

cmd/opm/index/deprecate.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package index
2+
3+
import (
4+
"github.com/sirupsen/logrus"
5+
"github.com/spf13/cobra"
6+
"k8s.io/kubectl/pkg/util/templates"
7+
8+
"github.com/operator-framework/operator-registry/pkg/containertools"
9+
"github.com/operator-framework/operator-registry/pkg/lib/indexer"
10+
)
11+
12+
var deprecateLong = templates.LongDesc(`
13+
Deprecate and truncate operator bundles from an index.
14+
15+
Deprecated bundles will no longer be installable. Bundles that are replaced by deprecated bundles will be removed enirely from the index.
16+
17+
For example:
18+
19+
Given the update graph in quay.io/my/index:v1
20+
1.4.0 -- replaces -> 1.3.0 -- replaces -> 1.2.0 -- replaces -> 1.1.0
21+
22+
Applying the command:
23+
opm index deprecate --bundles "quay.io/my/bundle:1.3.0" --from-index "quay.io/my/index:v1" --tag "quay.io/my/index:v2"
24+
25+
Produces the following update graph in quay.io/my/index:v2
26+
1.4.0 -- replaces -> 1.3.0 [deprecated]
27+
28+
Deprecating a bundle that removes the default channel is not allowed. Changing the default channel prior to deprecation is possible by publishing a new bundle to the index.
29+
`)
30+
31+
func newIndexDeprecateTruncateCmd() *cobra.Command {
32+
indexCmd := &cobra.Command{
33+
Hidden: true,
34+
Use: "deprecatetruncate",
35+
Short: "Deprecate and truncate operator bundles from an index.",
36+
Long: deprecateLong,
37+
PreRunE: func(cmd *cobra.Command, args []string) error {
38+
if debug, _ := cmd.Flags().GetBool("debug"); debug {
39+
logrus.SetLevel(logrus.DebugLevel)
40+
}
41+
return nil
42+
},
43+
RunE: runIndexDeprecateTruncateCmdFunc,
44+
}
45+
46+
indexCmd.Flags().Bool("debug", false, "enable debug logging")
47+
indexCmd.Flags().Bool("generate", false, "if enabled, just creates the dockerfile and saves it to local disk")
48+
indexCmd.Flags().StringP("out-dockerfile", "d", "", "if generating the dockerfile, this flag is used to (optionally) specify a dockerfile name")
49+
indexCmd.Flags().StringP("from-index", "f", "", "previous index to add to")
50+
indexCmd.Flags().StringSliceP("bundles", "b", nil, "comma separated list of bundles to add")
51+
if err := indexCmd.MarkFlagRequired("bundles"); err != nil {
52+
logrus.Panic("Failed to set required `bundles` flag for `index add`")
53+
}
54+
indexCmd.Flags().StringP("binary-image", "i", "", "container image for on-image `opm` command")
55+
indexCmd.Flags().StringP("container-tool", "c", "", "tool to interact with container images (save, build, etc.). One of: [docker, podman]")
56+
indexCmd.Flags().StringP("build-tool", "u", "", "tool to build container images. One of: [docker, podman]. Defaults to podman. Overrides part of container-tool.")
57+
indexCmd.Flags().StringP("pull-tool", "p", "", "tool to pull container images. One of: [none, docker, podman]. Defaults to none. Overrides part of container-tool.")
58+
indexCmd.Flags().StringP("tag", "t", "", "custom tag for container image being built")
59+
indexCmd.Flags().Bool("permissive", false, "allow registry load errors")
60+
if err := indexCmd.Flags().MarkHidden("debug"); err != nil {
61+
logrus.Panic(err.Error())
62+
}
63+
64+
return indexCmd
65+
}
66+
67+
func runIndexDeprecateTruncateCmdFunc(cmd *cobra.Command, args []string) error {
68+
generate, err := cmd.Flags().GetBool("generate")
69+
if err != nil {
70+
return err
71+
}
72+
73+
outDockerfile, err := cmd.Flags().GetString("out-dockerfile")
74+
if err != nil {
75+
return err
76+
}
77+
78+
fromIndex, err := cmd.Flags().GetString("from-index")
79+
if err != nil {
80+
return err
81+
}
82+
83+
bundles, err := cmd.Flags().GetStringSlice("bundles")
84+
if err != nil {
85+
return err
86+
}
87+
88+
binaryImage, err := cmd.Flags().GetString("binary-image")
89+
if err != nil {
90+
return err
91+
}
92+
93+
tag, err := cmd.Flags().GetString("tag")
94+
if err != nil {
95+
return err
96+
}
97+
98+
permissive, err := cmd.Flags().GetBool("permissive")
99+
if err != nil {
100+
return err
101+
}
102+
103+
pullTool, buildTool, err := getContainerTools(cmd)
104+
if err != nil {
105+
return err
106+
}
107+
108+
logger := logrus.WithFields(logrus.Fields{"bundles": bundles})
109+
110+
logger.Info("deprecating bundles from the index")
111+
112+
indexDeprecator := indexer.NewIndexDeprecator(
113+
containertools.NewContainerTool(buildTool, containertools.PodmanTool),
114+
containertools.NewContainerTool(pullTool, containertools.NoneTool),
115+
logger)
116+
117+
request := indexer.DeprecateFromIndexRequest{
118+
Generate: generate,
119+
FromIndex: fromIndex,
120+
BinarySourceImage: binaryImage,
121+
OutDockerfile: outDockerfile,
122+
Tag: tag,
123+
Bundles: bundles,
124+
Permissive: permissive,
125+
}
126+
127+
err = indexDeprecator.DeprecateFromIndex(request)
128+
if err != nil {
129+
return err
130+
}
131+
132+
return nil
133+
}

pkg/lib/indexer/indexer.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type ImageIndexer struct {
4141
RegistryAdder registry.RegistryAdder
4242
RegistryDeleter registry.RegistryDeleter
4343
RegistryPruner registry.RegistryPruner
44+
RegistryDeprecator registry.RegistryDeprecator
4445
BuildTool containertools.ContainerTool
4546
PullTool containertools.ContainerTool
4647
Logger *logrus.Entry
@@ -527,3 +528,61 @@ func generatePackageYaml(dbQuerier pregistry.Query, packageName, downloadPath st
527528

528529
return utilerrors.NewAggregate(errs)
529530
}
531+
532+
// DeprecateFromIndexRequest defines the parameters to send to the PruneFromIndex API
533+
type DeprecateFromIndexRequest struct {
534+
Generate bool
535+
Permissive bool
536+
BinarySourceImage string
537+
FromIndex string
538+
OutDockerfile string
539+
Bundles []string
540+
Tag string
541+
}
542+
543+
// DeprecateFromIndex takes a DeprecateFromIndexRequest and deprecates the requested
544+
// bundles.
545+
func (i ImageIndexer) DeprecateFromIndex(request DeprecateFromIndexRequest) error {
546+
buildDir, outDockerfile, cleanup, err := buildContext(request.Generate, request.OutDockerfile)
547+
defer cleanup()
548+
if err != nil {
549+
return err
550+
}
551+
552+
databasePath, err := i.extractDatabase(buildDir, request.FromIndex)
553+
if err != nil {
554+
return err
555+
}
556+
557+
// Run opm registry prune on the database
558+
deprecateFromRegistryReq := registry.DeprecateFromRegistryRequest{
559+
Bundles: request.Bundles,
560+
InputDatabase: databasePath,
561+
Permissive: request.Permissive,
562+
}
563+
564+
// Prune the bundles from the registry
565+
err = i.RegistryDeprecator.DeprecateFromRegistry(deprecateFromRegistryReq)
566+
if err != nil {
567+
return err
568+
}
569+
570+
// generate the dockerfile
571+
dockerfile := i.DockerfileGenerator.GenerateIndexDockerfile(request.BinarySourceImage, databasePath)
572+
err = write(dockerfile, outDockerfile, i.Logger)
573+
if err != nil {
574+
return err
575+
}
576+
577+
if request.Generate {
578+
return nil
579+
}
580+
581+
// build the dockerfile with requested tooling
582+
err = build(outDockerfile, request.Tag, i.CommandRunner, i.Logger)
583+
if err != nil {
584+
return err
585+
}
586+
587+
return nil
588+
}

pkg/lib/indexer/interfaces.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,20 @@ func NewIndexPruner(containerTool containertools.ContainerTool, logger *logrus.E
8080
Logger: logger,
8181
}
8282
}
83+
84+
// IndexDeprecator prunes operators out of an index
85+
type IndexDeprecator interface {
86+
DeprecateFromIndex(DeprecateFromIndexRequest) error
87+
}
88+
89+
func NewIndexDeprecator(buildTool, pullTool containertools.ContainerTool, logger *logrus.Entry) IndexDeprecator {
90+
return ImageIndexer{
91+
DockerfileGenerator: containertools.NewDockerfileGenerator(logger),
92+
CommandRunner: containertools.NewCommandRunner(buildTool, logger),
93+
LabelReader: containertools.NewLabelReader(pullTool, logger),
94+
RegistryDeprecator: registry.NewRegistryDeprecator(logger),
95+
BuildTool: buildTool,
96+
PullTool: pullTool,
97+
Logger: logger,
98+
}
99+
}

pkg/lib/registry/interfaces.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,13 @@ func NewRegistryPruner(logger *logrus.Entry) RegistryPruner {
3636
Logger: logger,
3737
}
3838
}
39+
40+
type RegistryDeprecator interface {
41+
DeprecateFromRegistry(DeprecateFromRegistryRequest) error
42+
}
43+
44+
func NewRegistryDeprecator(logger *logrus.Entry) RegistryDeprecator {
45+
return RegistryUpdater{
46+
Logger: logger,
47+
}
48+
}

pkg/lib/registry/registry.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,37 @@ func (r RegistryUpdater) PruneFromRegistry(request PruneFromRegistryRequest) err
228228

229229
return nil
230230
}
231+
232+
type DeprecateFromRegistryRequest struct {
233+
Permissive bool
234+
InputDatabase string
235+
Bundles []string
236+
}
237+
238+
func (r RegistryUpdater) DeprecateFromRegistry(request DeprecateFromRegistryRequest) error {
239+
db, err := sql.Open("sqlite3", request.InputDatabase)
240+
if err != nil {
241+
return err
242+
}
243+
defer db.Close()
244+
245+
dbLoader, err := sqlite.NewSQLLiteLoader(db)
246+
if err != nil {
247+
return err
248+
}
249+
if err := dbLoader.Migrate(context.TODO()); err != nil {
250+
return fmt.Errorf("unable to migrate database: %s", err)
251+
}
252+
253+
deprecator := sqlite.NewSQLDeprecatorForBundles(dbLoader, request.Bundles)
254+
if err := deprecator.Deprecate(); err != nil {
255+
r.Logger.Debugf("unable to deprecate bundles from database: %s", err)
256+
if !request.Permissive {
257+
r.Logger.WithError(err).Error("permissive mode disabled")
258+
return err
259+
}
260+
r.Logger.WithError(err).Warn("permissive mode enabled")
261+
}
262+
263+
return nil
264+
}

pkg/registry/interface.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type Load interface {
1212
AddPackageChannels(manifest PackageManifest) error
1313
AddBundlePackageChannels(manifest PackageManifest, bundle *Bundle) error
1414
RemovePackage(packageName string) error
15+
DeprecateBundle(path string) error
1516
ClearNonHeadBundles() error
1617
}
1718

0 commit comments

Comments
 (0)