@@ -24,20 +24,28 @@ import (
2424 "net/url"
2525 "os"
2626 "path/filepath"
27+ "strings"
2728 "time"
2829
2930 "github.com/containers/image/v5/types"
3031 "github.com/go-logr/logr"
3132 "github.com/spf13/pflag"
33+ corev1 "k8s.io/api/core/v1"
34+ "k8s.io/apimachinery/pkg/fields"
35+ k8slabels "k8s.io/apimachinery/pkg/labels"
3236 "k8s.io/apimachinery/pkg/runtime"
37+ k8stypes "k8s.io/apimachinery/pkg/types"
38+ apimachineryrand "k8s.io/apimachinery/pkg/util/rand"
3339 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3440 clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3541 "k8s.io/client-go/metadata"
3642 _ "k8s.io/client-go/plugin/pkg/client/auth"
3743 "k8s.io/klog/v2"
3844 "k8s.io/klog/v2/textlogger"
3945 ctrl "sigs.k8s.io/controller-runtime"
46+ crcache "sigs.k8s.io/controller-runtime/pkg/cache"
4047 "sigs.k8s.io/controller-runtime/pkg/certwatcher"
48+ "sigs.k8s.io/controller-runtime/pkg/client"
4149 "sigs.k8s.io/controller-runtime/pkg/healthz"
4250 "sigs.k8s.io/controller-runtime/pkg/metrics"
4351 metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
6169)
6270
6371const (
64- storageDir = "catalogs"
65- authFilePath = "/etc/ catalogd/auth.json "
72+ storageDir = "catalogs"
73+ authFilePrefix = "catalogd-global-pull-secret "
6674)
6775
6876func init () {
@@ -88,6 +96,7 @@ func main() {
8896 keyFile string
8997 webhookPort int
9098 caCertDir string
99+ globalPullSecret string
91100 )
92101 flag .StringVar (& metricsAddr , "metrics-bind-address" , ":8080" , "The address the metric endpoint binds to." )
93102 flag .StringVar (& probeAddr , "health-probe-bind-address" , ":8081" , "The address the probe endpoint binds to." )
@@ -105,6 +114,7 @@ func main() {
105114 flag .StringVar (& keyFile , "tls-key" , "" , "The key file used for serving catalog contents over HTTPS. Requires tls-cert." )
106115 flag .IntVar (& webhookPort , "webhook-server-port" , 9443 , "The port that the mutating webhook server serves at." )
107116 flag .StringVar (& caCertDir , "ca-certs-dir" , "" , "The directory of CA certificate to use for verifying HTTPS connections to image registries." )
117+ flag .StringVar (& globalPullSecret , "global-pull-secret" , "" , "The <namespace>/<name> of the global pull secret that is going to be used to pull bundle images." )
108118
109119 klog .InitFlags (flag .CommandLine )
110120
@@ -120,6 +130,17 @@ func main() {
120130
121131 ctrl .SetLogger (textlogger .NewLogger (textlogger .NewConfig ()))
122132
133+ authFilePath := filepath .Join (os .TempDir (), fmt .Sprintf ("%s-%s.json" , authFilePrefix , apimachineryrand .String (8 )))
134+ var globalPullSecretKey * k8stypes.NamespacedName
135+ if globalPullSecret != "" {
136+ secretParts := strings .Split (globalPullSecret , "/" )
137+ if len (secretParts ) != 2 {
138+ setupLog .Error (fmt .Errorf ("incorrect number of components" ), "value of global-pull-secret should be of the format <namespace>/<name>" )
139+ os .Exit (1 )
140+ }
141+ globalPullSecretKey = & k8stypes.NamespacedName {Name : secretParts [1 ], Namespace : secretParts [0 ]}
142+ }
143+
123144 if (certFile != "" && keyFile == "" ) || (certFile == "" && keyFile != "" ) {
124145 setupLog .Error (nil , "unable to configure TLS certificates: tls-cert and tls-key flags must be used together" )
125146 os .Exit (1 )
@@ -148,6 +169,22 @@ func main() {
148169 },
149170 })
150171
172+ cacheOptions := crcache.Options {
173+ ByObject : map [client.Object ]crcache.ByObject {},
174+ }
175+ if globalPullSecretKey != nil {
176+ cacheOptions .ByObject [& corev1.Secret {}] = crcache.ByObject {
177+ Namespaces : map [string ]crcache.Config {
178+ globalPullSecretKey .Namespace : {
179+ LabelSelector : k8slabels .Everything (),
180+ FieldSelector : fields .SelectorFromSet (map [string ]string {
181+ "metadata.name" : globalPullSecretKey .Name ,
182+ }),
183+ },
184+ },
185+ }
186+ }
187+
151188 // Create manager
152189 mgr , err := ctrl .NewManager (cfg , ctrl.Options {
153190 Scheme : scheme ,
@@ -159,6 +196,7 @@ func main() {
159196 LeaderElection : enableLeaderElection ,
160197 LeaderElectionID : "catalogd-operator-lock" ,
161198 WebhookServer : webhookServer ,
199+ Cache : cacheOptions ,
162200 })
163201 if err != nil {
164202 setupLog .Error (err , "unable to create manager" )
@@ -188,10 +226,20 @@ func main() {
188226 }
189227 unpacker := & source.ContainersImageRegistry {
190228 BaseCachePath : unpackCacheBasePath ,
191- SourceContext : & types.SystemContext {
192- OCICertPath : caCertDir ,
193- DockerCertPath : caCertDir ,
194- AuthFilePath : authFilePathIfPresent (setupLog ),
229+ SourceContextFunc : func (logger logr.Logger ) (* types.SystemContext , error ) {
230+ srcContext := & types.SystemContext {
231+ DockerCertPath : caCertDir ,
232+ OCICertPath : caCertDir ,
233+ }
234+ if _ , err := os .Stat (authFilePath ); err == nil && globalPullSecretKey != nil {
235+ logger .Info ("using available authentication information for pulling image" )
236+ srcContext .AuthFilePath = authFilePath
237+ } else if os .IsNotExist (err ) {
238+ logger .Info ("no authentication information found for pulling image, proceeding without auth" )
239+ } else {
240+ return nil , fmt .Errorf ("could not stat auth file, error: %w" , err )
241+ }
242+ return srcContext , nil
195243 },
196244 }
197245
@@ -234,6 +282,19 @@ func main() {
234282 setupLog .Error (err , "unable to create controller" , "controller" , "ClusterCatalog" )
235283 os .Exit (1 )
236284 }
285+
286+ if globalPullSecretKey != nil {
287+ setupLog .Info ("creating SecretSyncer controller for watching secret" , "Secret" , globalPullSecret )
288+ err := (& corecontrollers.PullSecretReconciler {
289+ Client : mgr .GetClient (),
290+ AuthFilePath : authFilePath ,
291+ SecretKey : * globalPullSecretKey ,
292+ }).SetupWithManager (mgr )
293+ if err != nil {
294+ setupLog .Error (err , "unable to create controller" , "controller" , "SecretSyncer" )
295+ os .Exit (1 )
296+ }
297+ }
237298 //+kubebuilder:scaffold:builder
238299
239300 if err := mgr .AddHealthzCheck ("healthz" , healthz .Ping ); err != nil {
@@ -274,6 +335,10 @@ func main() {
274335 setupLog .Error (err , "problem running manager" )
275336 os .Exit (1 )
276337 }
338+ if err := os .Remove (authFilePath ); err != nil {
339+ setupLog .Error (err , "failed to cleanup temporary auth file" )
340+ os .Exit (1 )
341+ }
277342}
278343
279344func podNamespace () string {
@@ -283,17 +348,3 @@ func podNamespace() string {
283348 }
284349 return string (namespace )
285350}
286-
287- func authFilePathIfPresent (logger logr.Logger ) string {
288- _ , err := os .Stat (authFilePath )
289- if os .IsNotExist (err ) {
290- logger .Info ("auth file not found, skipping configuration of global auth file" , "path" , authFilePath )
291- return ""
292- }
293- if err != nil {
294- logger .Error (err , "unable to access auth file path" , "path" , authFilePath )
295- os .Exit (1 )
296- }
297- logger .Info ("auth file found, configuring globally for image registry interactions" , "path" , authFilePath )
298- return authFilePath
299- }
0 commit comments