Skip to content

Commit 97c6248

Browse files
authored
run --olm: support metadata/annotations.yaml (#2840)
1 parent 0fea297 commit 97c6248

File tree

11 files changed

+266
-122
lines changed

11 files changed

+266
-122
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- Add support to release SDK arm64 binaries and images. ([#2742](https://github.com/operator-framework/operator-sdk/pull/2715))
1616
- Add annotation `helm.operator-sdk/upgrade-force: "True"` to allow force resources replacement (`helm upgrade --force`) for Helm based-operators. ([#2773](https://github.com/operator-framework/operator-sdk/pull/2773))
1717
- The [`--make-manifests`](website/content/en/docs/cli/operator-sdk_generate_csv.md#options) flag directs `operator-sdk generate csv` to create a `manifests/` directory for the latest operator bundle, including CRDs. This flag is set by default. ([#2776](https://github.com/operator-framework/operator-sdk/pull/2776))
18+
- `operator-sdk run --olm` supports the new operator metadata format in `metadata/annotations.yaml`. ([#2840](https://github.com/operator-framework/operator-sdk/issues/2839))
1819

1920
### Changed
2021

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ require (
5555
k8s.io/kubectl v0.17.4
5656
sigs.k8s.io/controller-runtime v0.5.2
5757
sigs.k8s.io/controller-tools v0.2.8
58+
sigs.k8s.io/yaml v1.1.0
5859
)
5960

6061
replace (

hack/tests/integration.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ set -eu
44

55
source hack/lib/image_lib.sh
66

7-
export OSDK_INTEGRATION_IMAGE="quay.io/example/memcached-operator:v0.0.1"
7+
export OSDK_INTEGRATION_IMAGE="quay.io/example/memcached-operator:v0.0.2"
88

99
# Build the operator image.
1010
pushd test/test-framework

internal/olm/operator/internal/configmap.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@ import (
3030
"k8s.io/apimachinery/pkg/types"
3131
)
3232

33-
const (
34-
// The directory containing all manifests for an operator, with the
35-
// package manifest being top-level.
36-
containerManifestsDir = "/registry/manifests"
37-
)
38-
3933
// IsManifestDataStale checks if manifest data stored in the registry is stale
4034
// by comparing it to manifest data currently managed by m.
4135
func (m *RegistryResources) IsManifestDataStale(ctx context.Context, namespace string) (bool, error) {

internal/olm/operator/internal/registry.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ import (
2525
"k8s.io/apimachinery/pkg/types"
2626
)
2727

28+
const (
29+
// The directory containing all manifests for an operator, with the
30+
// package manifest being top-level.
31+
containerManifestsDir = "/registry/manifests"
32+
)
33+
2834
// SDKLabels are used to identify certain operator-sdk resources.
2935
var SDKLabels = map[string]string{
3036
"owner": "operator-sdk",

internal/olm/operator/manager.go

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,28 @@ import (
1919
"errors"
2020
"fmt"
2121
"io/ioutil"
22+
"os"
23+
"path/filepath"
2224

2325
"github.com/operator-framework/operator-sdk/internal/olm"
2426
olmresourceclient "github.com/operator-framework/operator-sdk/internal/olm/client"
2527
opinternal "github.com/operator-framework/operator-sdk/internal/olm/operator/internal"
2628
"github.com/operator-framework/operator-sdk/internal/util/k8sutil"
2729

28-
manifests "github.com/operator-framework/api/pkg/manifests"
30+
"github.com/operator-framework/api/pkg/manifests"
2931
valerrors "github.com/operator-framework/api/pkg/validation/errors"
3032
olmapiv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
3133
olmapiv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
32-
registry "github.com/operator-framework/operator-registry/pkg/registry"
34+
"github.com/operator-framework/operator-registry/pkg/lib/bundle"
35+
"github.com/operator-framework/operator-registry/pkg/registry"
3336
log "github.com/sirupsen/logrus"
3437
apiextinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
3538
apierrors "k8s.io/apimachinery/pkg/api/errors"
3639
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3740
"k8s.io/apimachinery/pkg/runtime"
3841
"k8s.io/apimachinery/pkg/types"
3942
"k8s.io/client-go/kubernetes/scheme"
43+
"sigs.k8s.io/yaml"
4044
)
4145

4246
const defaultNamespace = "default"
@@ -71,14 +75,17 @@ func (c *OLMCmd) newManager() (*operatorManager, error) {
7175
version: c.OperatorVersion,
7276
forceRegistry: c.ForceRegistry,
7377
}
74-
rc, ns, err := k8sutil.GetKubeconfigAndNamespace(c.KubeconfigPath)
75-
if err != nil {
76-
return nil, fmt.Errorf("failed to get namespace from kubeconfig %s: %w", c.KubeconfigPath, err)
77-
}
78+
79+
// Namespace in which OLM is deployed.
7880
if m.olmNamespace = c.OLMNamespace; m.olmNamespace == "" {
7981
m.olmNamespace = olm.DefaultOLMNamespace
8082
}
8183

84+
// Cluster and operator namespace info.
85+
rc, ns, err := k8sutil.GetKubeconfigAndNamespace(c.KubeconfigPath)
86+
if err != nil {
87+
return nil, fmt.Errorf("failed to get namespace from kubeconfig %s: %w", c.KubeconfigPath, err)
88+
}
8289
if ns == "" {
8390
ns = defaultNamespace
8491
}
@@ -91,6 +98,8 @@ func (c *OLMCmd) newManager() (*operatorManager, error) {
9198
return nil, fmt.Errorf("failed to create SDK OLM client: %w", err)
9299
}
93100
}
101+
102+
// Parse k8s objects.
94103
for _, path := range c.IncludePaths {
95104
if path != "" {
96105
objs, err := readObjectsFromFile(path)
@@ -108,7 +117,10 @@ func (c *OLMCmd) newManager() (*operatorManager, error) {
108117
if hasSub || hasCatSrc && !(hasSub && hasCatSrc) {
109118
return nil, errors.New("both a CatalogSource and Subscription must be supplied if one is supplied")
110119
}
111-
pkg, bundles, results := manifests.GetManifestsDir(c.ManifestsDir)
120+
121+
// Operator bundles and metadata.
122+
var results []valerrors.ManifestResult
123+
m.pkg, m.bundles, results = manifests.GetManifestsDir(c.ManifestsDir)
112124
if len(results) != 0 {
113125
badResults := []valerrors.ManifestResult{}
114126
for _, result := range results {
@@ -120,7 +132,17 @@ func (c *OLMCmd) newManager() (*operatorManager, error) {
120132
return nil, fmt.Errorf("bundle dir had errors: %s", badResults)
121133
}
122134
}
123-
m.pkg, m.bundles = pkg, bundles
135+
// Prefer annotations over a package manifest, which is now deprecated.
136+
if annotations, err := findAnnotations(c.ManifestsDir); err == nil {
137+
m.pkg = translateAnnotationsToPackage(annotations, fmt.Sprintf("%s.v%s", annotations.GetName(), m.version))
138+
} else if !os.IsNotExist(err) {
139+
return nil, fmt.Errorf("error finding annotations: %v", err)
140+
}
141+
if m.pkg.PackageName == "" {
142+
return nil, errors.New("no package metadata found")
143+
}
144+
145+
// Handle installModes.
124146
if c.InstallMode == "" {
125147
// Default to OwnNamespace.
126148
m.installMode = olmapiv1alpha1.InstallModeTypeOwnNamespace
@@ -134,15 +156,51 @@ func (c *OLMCmd) newManager() (*operatorManager, error) {
134156
if err := m.installModeCompatible(m.installMode); err != nil {
135157
return nil, err
136158
}
159+
137160
return m, nil
138161
}
139162

163+
// findAnnotations returns annotations metadata from '<dir>/metadata/annotations.yaml'.
164+
func findAnnotations(dir string) (annotations registry.AnnotationsFile, err error) {
165+
annotationsPath := filepath.Join(dir, bundle.MetadataDir, bundle.AnnotationsFile)
166+
b, err := ioutil.ReadFile(annotationsPath)
167+
if err != nil {
168+
return annotations, err
169+
}
170+
if err = yaml.Unmarshal(b, &annotations); err != nil {
171+
return annotations, err
172+
}
173+
return annotations, nil
174+
}
175+
176+
// translateAnnotationsToPackage creates a package manifest from an annotations
177+
// file. We use this workaround because registry-server will not populate the
178+
// database directory from an annotations.yaml file. This is what an index image
179+
// build does:
180+
// https://github.com/operator-framework/operator-registry/blob/v1.9.0/pkg/registry/populator.go#L285
181+
func translateAnnotationsToPackage(annotations registry.AnnotationsFile, csvName string) registry.PackageManifest {
182+
pkg := registry.PackageManifest{
183+
PackageName: annotations.GetName(),
184+
DefaultChannelName: annotations.GetDefaultChannelName(),
185+
}
186+
187+
for _, channel := range annotations.GetChannels() {
188+
pkg.Channels = append(pkg.Channels, registry.PackageChannel{
189+
Name: channel,
190+
CurrentCSVName: csvName,
191+
})
192+
}
193+
194+
return pkg
195+
}
196+
140197
func (m *operatorManager) run(ctx context.Context) (err error) {
141198
// Ensure OLM is installed.
142199
olmVer, err := m.client.GetInstalledVersion(ctx, m.olmNamespace)
143200
if err != nil {
144201
return fmt.Errorf("error getting installed OLM version: %w", err)
145202
}
203+
146204
pkgName := m.pkg.PackageName
147205
bundle, err := getBundleForVersion(m.bundles, m.version)
148206
if err != nil {
@@ -152,6 +210,7 @@ func (m *operatorManager) run(ctx context.Context) (err error) {
152210
if err != nil {
153211
return fmt.Errorf("error getting CSV from bundle: %w", err)
154212
}
213+
155214
// Only check CSV here, since other deployed operators/versions may be
156215
// running with shared CRDs.
157216
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(csv)
@@ -169,6 +228,7 @@ func (m *operatorManager) run(ctx context.Context) (err error) {
169228
if err = m.registryUp(ctx, m.olmNamespace); err != nil {
170229
return fmt.Errorf("error creating registry resources: %w", err)
171230
}
231+
172232
log.Info("Creating resources")
173233
if !m.hasCatalogSource() {
174234
registryGRPCAddr := opinternal.GetRegistryServiceAddr(pkgName, m.olmNamespace)
@@ -205,6 +265,7 @@ func (m *operatorManager) run(ctx context.Context) (err error) {
205265
if err = m.client.DoCreate(ctx, objects...); err != nil {
206266
return fmt.Errorf("error creating operator resources: %w", err)
207267
}
268+
208269
// BUG(estroz): if m.namespace is not contained in m.installModeNamespaces,
209270
// DoCSVWait will fail.
210271
nn := types.NamespacedName{
@@ -234,6 +295,7 @@ func (m *operatorManager) cleanup(ctx context.Context) (err error) {
234295
if err != nil {
235296
return fmt.Errorf("error getting installed OLM version: %w", err)
236297
}
298+
237299
pkgName := m.pkg.PackageName
238300
bundle, err := getBundleForVersion(m.bundles, m.version)
239301
if err != nil {
@@ -247,6 +309,7 @@ func (m *operatorManager) cleanup(ctx context.Context) (err error) {
247309
if err = m.registryDown(ctx, m.olmNamespace); err != nil {
248310
return fmt.Errorf("error removing registry resources: %w", err)
249311
}
312+
250313
log.Info("Deleting resources")
251314
if !m.hasCatalogSource() {
252315
m.olmObjects = append(m.olmObjects, newCatalogSource(pkgName, m.namespace))
@@ -287,6 +350,7 @@ func (m operatorManager) registryUp(ctx context.Context, namespace string) error
287350
Pkg: m.pkg,
288351
Bundles: m.bundles,
289352
}
353+
290354
registryStale, err := rr.IsManifestDataStale(ctx, namespace)
291355
if err != nil {
292356
if !apierrors.IsNotFound(err) {
@@ -310,6 +374,7 @@ func (m operatorManager) registryUp(ctx context.Context, namespace string) error
310374
if err = rr.CreateRegistryManifests(ctx, namespace); err != nil {
311375
return fmt.Errorf("error registering bundle: %w", err)
312376
}
377+
313378
return nil
314379
}
315380

@@ -319,12 +384,14 @@ func (m *operatorManager) registryDown(ctx context.Context, namespace string) er
319384
Pkg: m.pkg,
320385
Bundles: m.bundles,
321386
}
387+
322388
if m.forceRegistry {
323389
log.Printf("Deleting registry")
324390
if err := rr.DeleteRegistryManifests(ctx, namespace); err != nil {
325391
return fmt.Errorf("error deleting registered bundle: %w", err)
326392
}
327393
}
394+
328395
return nil
329396
}
330397

internal/olm/operator/operator.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ const (
3636
// OLMCmd configures deployment and teardown of an operator via an OLM
3737
// installation existing on a cluster.
3838
type OLMCmd struct { // nolint:golint
39-
// ManifestsDir is a directory containing a package manifest and N bundles
40-
// of the operator's CSV and CRD's. OperatorVersion can be set to the
41-
// version of the desired operator version's subdir and Run()/Cleanup() will
42-
// deploy the operator version in that subdir.
39+
// ManifestsDir is a directory containing 1..N bundle directories and either
40+
// a package manifest or metadata/annotations.yaml. OperatorVersion can be
41+
// set to the version of the desired operator bundle and Run()/Cleanup() will
42+
// deploy that operator version.
4343
ManifestsDir string
4444
// OperatorVersion is the version of the operator to deploy. It must be
4545
// a semantic version, ex. 0.0.1.
@@ -93,11 +93,10 @@ func (c *OLMCmd) AddToFlagSet(fs *pflag.FlagSet) {
9393
fs.StringVar(&c.OLMNamespace, "olm-namespace", olm.DefaultOLMNamespace,
9494
prefix+"The namespace where OLM is installed")
9595
fs.StringVar(&c.OperatorNamespace, "operator-namespace", "",
96-
prefix+"The namespace where operator resources are created in --olm mode. It "+
97-
"must already exist in the cluster or be defined in"+
98-
" a manifest passed to IncludePaths.")
96+
prefix+"The namespace where operator resources are created. It must already exist "+
97+
"in the cluster or be defined in a manifest passed to --include")
9998
fs.StringVar(&c.ManifestsDir, "manifests", "",
100-
prefix+"Directory containing package manifest and operator bundles.")
99+
prefix+"Directory containing operator bundle directories and metadata")
101100
fs.StringVar(&c.OperatorVersion, "operator-version", "",
102101
prefix+"Version of operator to deploy")
103102
fs.StringVar(&c.InstallMode, "install-mode", "",

0 commit comments

Comments
 (0)