@@ -4,9 +4,16 @@ import (
44	"context" 
55	"encoding/json" 
66	"fmt" 
7+ 	"io" 
8+ 	"path" 
79	"strings" 
810	"time" 
911
12+ 	"github.com/containerd/containerd/archive/compression" 
13+ 	"github.com/containerd/containerd/images" 
14+ 	"github.com/containerd/containerd/namespaces" 
15+ 	"github.com/containerd/containerd/platforms" 
16+ 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" 
1017	"github.com/operator-framework/api/pkg/operators/v1alpha1" 
1118	"github.com/operator-framework/operator-registry/pkg/image" 
1219	"github.com/operator-framework/operator-registry/pkg/image/containerdregistry" 
@@ -23,7 +30,13 @@ import (
2330	"github.com/operator-framework/kubectl-operator/internal/pkg/catalog" 
2431)
2532
26- const  grpcPort  =  "50051" 
33+ const  (
34+ 	grpcPort               =  "50051" 
35+ 	dbPathLabel            =  "operators.operatorframework.io.index.database.v1" 
36+ 	alphaDisplayNameLabel  =  "alpha.operators.operatorframework.io.index.display-name.v1" 
37+ 	alphaPublisherLabel    =  "alpha.operators.operatorframework.io.index.publisher.v1" 
38+ 	defaultDatabasePath    =  "/database/index.db" 
39+ )
2740
2841type  CatalogAdd  struct  {
2942	config  * Configuration 
@@ -81,7 +94,7 @@ func (a *CatalogAdd) Run(ctx context.Context) (*v1alpha1.CatalogSource, error) {
8194
8295	labels , err  :=  a .labelsFor (ctx , a .IndexImage )
8396	if  err  !=  nil  {
84- 		return  nil , err 
97+ 		return  nil , fmt . Errorf ( "get image labels: %v" ,  err ) 
8598	}
8699
87100	a .setDefaults (labels )
@@ -96,20 +109,33 @@ func (a *CatalogAdd) Run(ctx context.Context) (*v1alpha1.CatalogSource, error) {
96109	}
97110
98111	cs  :=  catalog .Build (csKey , opts ... )
99- 	if  err  :=  a .createCatalogSource (ctx , cs ); err  !=  nil  {
100- 		return  nil , err 
112+ 	if  err  :=  a .config . Client . Create (ctx , cs ); err  !=  nil  {
113+ 		return  nil , fmt . Errorf ( "create catalogsource: %v" ,  err ) 
101114	}
102115
103116	var  registryPod  * corev1.Pod 
104117	if  len (a .InjectBundles ) >  0  {
105- 		if  registryPod , err  =  a .createRegistryPod (ctx , cs ); err  !=  nil  {
118+ 		dbPath , ok  :=  labels [dbPathLabel ]
119+ 		if  ! ok  {
120+ 			// No database path label, so assume this is an index base image. 
121+ 			// Choose "semver" bundle add mode (if not explicitly set) and 
122+ 			// use the default database path. 
123+ 			if  a .InjectBundleMode  ==  ""  {
124+ 				a .InjectBundleMode  =  "semver" 
125+ 			}
126+ 			dbPath  =  defaultDatabasePath 
127+ 		}
128+ 		if  a .InjectBundleMode  ==  ""  {
129+ 			a .InjectBundleMode  =  "replaces" 
130+ 		}
131+ 		if  registryPod , err  =  a .createRegistryPod (ctx , cs , dbPath ); err  !=  nil  {
106132			defer  a .cleanup (cs )
107133			return  nil , err 
108134		}
109135
110136		if  err  :=  a .updateCatalogSource (ctx , cs , registryPod ); err  !=  nil  {
111137			defer  a .cleanup (cs )
112- 			return  nil , err 
138+ 			return  nil , fmt . Errorf ( "update catalog source: %v" ,  err ) 
113139		}
114140	}
115141
@@ -122,51 +148,61 @@ func (a *CatalogAdd) Run(ctx context.Context) (*v1alpha1.CatalogSource, error) {
122148}
123149
124150func  (a  * CatalogAdd ) labelsFor (ctx  context.Context , indexImage  string ) (map [string ]string , error ) {
125- 	simpleRef  :=  image .SimpleReference (indexImage )
126- 	if  err  :=  a .registry .Pull (ctx , simpleRef ); err  !=  nil  {
151+ 	ref  :=  image .SimpleReference (indexImage )
152+ 	if  err  :=  a .registry .Pull (ctx , ref ); err  !=  nil  {
127153		return  nil , fmt .Errorf ("pull image: %v" , err )
128154	}
129- 	labels , err  :=  a .registry .Labels (ctx , simpleRef )
155+ 
156+ 	ctx  =  namespaces .WithNamespace (ctx , namespaces .Default )
157+ 	img , err  :=  a .registry .Images ().Get (ctx , ref .String ())
130158	if  err  !=  nil  {
131- 		return  nil , fmt .Errorf ("get image labels : %v" , err )
159+ 		return  nil , fmt .Errorf ("get image from local registry : %v" , err )
132160	}
133- 	return  labels , nil 
161+ 
162+ 	manifest , err  :=  images .Manifest (ctx , a .registry .Content (), img .Target , platforms .All )
163+ 	if  err  !=  nil  {
164+ 		return  nil , fmt .Errorf ("resolve image manifest: %v" , err )
165+ 	}
166+ 
167+ 	ra , err  :=  a .registry .Content ().ReaderAt (ctx , manifest .Config )
168+ 	if  err  !=  nil  {
169+ 		return  nil , fmt .Errorf ("get image reader: %v" , err )
170+ 	}
171+ 	defer  ra .Close ()
172+ 
173+ 	decompressed , err  :=  compression .DecompressStream (io .NewSectionReader (ra , 0 , ra .Size ()))
174+ 	if  err  !=  nil  {
175+ 		return  nil , fmt .Errorf ("decompress image data: %v" , err )
176+ 	}
177+ 	var  imageMeta  ocispec.Image 
178+ 	dec  :=  json .NewDecoder (decompressed )
179+ 	if  err  :=  dec .Decode (& imageMeta ); err  !=  nil  {
180+ 		return  nil , fmt .Errorf ("decode image metadata: %v" , err )
181+ 	}
182+ 	return  imageMeta .Config .Labels , nil 
134183}
135184
136185func  (a  * CatalogAdd ) setDefaults (labels  map [string ]string ) {
137186	if  a .DisplayName  ==  ""  {
138- 		if  v , ok  :=  labels ["operators.operatorframework.io.index.display-name" ]; ok  {
187+ 		if  v , ok  :=  labels [alphaDisplayNameLabel ]; ok  {
139188			a .DisplayName  =  v 
140189		}
141190	}
142191	if  a .Publisher  ==  ""  {
143- 		if  v , ok  :=  labels ["operators.operatorframework.io.index.publisher" ]; ok  {
192+ 		if  v , ok  :=  labels [alphaPublisherLabel ]; ok  {
144193			a .Publisher  =  v 
145194		}
146195	}
147- 	if  a .InjectBundleMode  ==  ""  {
148- 		if  strings .HasPrefix (a .IndexImage , "quay.io/operator-framework/upstream-opm-builder" ) {
149- 			a .InjectBundleMode  =  "semver" 
150- 		} else  {
151- 			a .InjectBundleMode  =  "replaces" 
152- 		}
153- 	}
154- }
155- 
156- func  (a  * CatalogAdd ) createCatalogSource (ctx  context.Context , cs  * v1alpha1.CatalogSource ) error  {
157- 	if  err  :=  a .config .Client .Create (ctx , cs ); err  !=  nil  {
158- 		return  fmt .Errorf ("create catalogsource: %v" , err )
159- 	}
160- 	return  nil 
161196}
162197
163- func  (a  * CatalogAdd ) createRegistryPod (ctx  context.Context , cs  * v1alpha1.CatalogSource ) (* corev1.Pod , error ) {
198+ func  (a  * CatalogAdd ) createRegistryPod (ctx  context.Context , cs  * v1alpha1.CatalogSource , dbPath  string ) (* corev1.Pod , error ) {
199+ 	dbDir  :=  path .Dir (dbPath )
164200	command  :=  []string {
165201		"/bin/sh" ,
166202		"-c" ,
167- 		fmt .Sprintf (`mkdir -p /database  && \ 
168- /bin/opm registry add   -d /database/index.db  --mode=%s -b %s && \ 
169- /bin/opm registry serve -d /database/index.db  -p %s` , a .InjectBundleMode , strings .Join (a .InjectBundles , "," ), grpcPort ),
203+ 		fmt .Sprintf (`mkdir -p %s  && \ 
204+ /bin/opm registry add   -d %s  --mode=%s -b %s && \ 
205+ /bin/opm registry serve -d %s  -p %s` , dbDir ,  dbPath ,  a .InjectBundleMode , strings .Join (a .InjectBundles , "," ),  dbPath , grpcPort ),
170206	}
171207
172208	pod  :=  & corev1.Pod {
@@ -184,26 +220,15 @@ func (a *CatalogAdd) createRegistryPod(ctx context.Context, cs *v1alpha1.Catalog
184220			},
185221		},
186222	}
223+ 
224+ 	if  err  :=  controllerutil .SetOwnerReference (cs , pod , a .config .Scheme ); err  !=  nil  {
225+ 		return  nil , fmt .Errorf ("set registry pod owner reference: %v" , err )
226+ 	}
187227	if  err  :=  a .config .Client .Create (ctx , pod ); err  !=  nil  {
188228		return  nil , fmt .Errorf ("create registry pod: %v" , err )
189229	}
190230
191231	podKey  :=  objectKeyForObject (pod )
192- 	if  err  :=  retry .RetryOnConflict (retry .DefaultBackoff , func () error  {
193- 		if  err  :=  a .config .Client .Get (ctx , podKey , pod ); err  !=  nil  {
194- 			return  fmt .Errorf ("get registry pod: %v" , err )
195- 		}
196- 		if  err  :=  controllerutil .SetOwnerReference (cs , pod , a .config .Scheme ); err  !=  nil  {
197- 			return  fmt .Errorf ("set registry pod owner reference: %v" , err )
198- 		}
199- 		if  err  :=  a .config .Client .Update (ctx , pod ); err  !=  nil  {
200- 			return  fmt .Errorf ("update registry pod owner reference: %v" , err )
201- 		}
202- 		return  nil 
203- 	}); err  !=  nil  {
204- 		return  nil , err 
205- 	}
206- 
207232	if  err  :=  wait .PollImmediateUntil (time .Millisecond * 250 , func () (bool , error ) {
208233		if  err  :=  a .config .Client .Get (ctx , podKey , pod ); err  !=  nil  {
209234			return  false , err 
@@ -219,26 +244,25 @@ func (a *CatalogAdd) createRegistryPod(ctx context.Context, cs *v1alpha1.Catalog
219244}
220245
221246func  (a  * CatalogAdd ) updateCatalogSource (ctx  context.Context , cs  * v1alpha1.CatalogSource , pod  * corev1.Pod ) error  {
222- 	cs .Spec .Address  =  fmt .Sprintf ("%s:%s" , pod .Status .PodIP , grpcPort )
223- 
224247	injectedBundlesJSON , err  :=  json .Marshal (a .InjectBundles )
225248	if  err  !=  nil  {
226249		return  fmt .Errorf ("json marshal injected bundles: %v" , err )
227250	}
228- 	cs .ObjectMeta .Annotations  =  map [string ]string {
229- 		"operators.operatorframework.io/index-image" :        a .IndexImage ,
230- 		"operators.operatorframework.io/inject-bundle-mode" : a .InjectBundleMode ,
231- 		"operators.operatorframework.io/injected-bundles" :   string (injectedBundlesJSON ),
232- 	}
251+ 
233252	csKey  :=  objectKeyForObject (cs )
234253	if  err  :=  retry .RetryOnConflict (retry .DefaultBackoff , func () error  {
235254		if  err  :=  a .config .Client .Get (ctx , csKey , cs ); err  !=  nil  {
236255			return  fmt .Errorf ("get catalog source: %v" , err )
237256		}
238- 		if  err  :=  a .config .Client .Update (ctx , cs ); err  !=  nil  {
239- 			return  fmt .Errorf ("update catalog source: %v" , err )
257+ 
258+ 		cs .Spec .Address  =  fmt .Sprintf ("%s:%s" , pod .Status .PodIP , grpcPort )
259+ 		cs .ObjectMeta .Annotations  =  map [string ]string {
260+ 			"operators.operatorframework.io/index-image" :        a .IndexImage ,
261+ 			"operators.operatorframework.io/inject-bundle-mode" : a .InjectBundleMode ,
262+ 			"operators.operatorframework.io/injected-bundles" :   string (injectedBundlesJSON ),
240263		}
241- 		return  nil 
264+ 
265+ 		return  a .config .Client .Update (ctx , cs )
242266	}); err  !=  nil  {
243267		return  err 
244268	}
0 commit comments