@@ -3,18 +3,14 @@ package imagepruner
33import (
44 "context"
55 "fmt"
6- "os"
7- "path/filepath"
8- "strings"
96
7+ "github.com/openshift/machine-config-operator/pkg/imageutils"
108 corev1 "k8s.io/api/core/v1"
119 "k8s.io/klog/v2"
1210
1311 "github.com/containers/image/v5/types"
1412 "github.com/opencontainers/go-digest"
1513 mcfgv1 "github.com/openshift/api/machineconfiguration/v1"
16- "github.com/openshift/machine-config-operator/pkg/controller/template"
17- "github.com/openshift/machine-config-operator/pkg/secrets"
1814)
1915
2016// ImagePruner defines the interface for inspecting and deleting container images.
@@ -42,18 +38,18 @@ func NewImagePruner() ImagePruner {
4238// InspectImage inspects the given image using the provided secret. It also accepts a
4339// ControllerConfig so that certificates may be placed on the filesystem for authentication.
4440func (i * imagePrunerImpl ) InspectImage (ctx context.Context , pullspec string , secret * corev1.Secret , cc * mcfgv1.ControllerConfig ) (* types.ImageInspectInfo , * digest.Digest , error ) {
45- sysCtx , err := i . prepareSystemContext (secret , cc )
41+ sysCtx , err := imageutils . NewSysContextFromControllerConfig (secret , cc )
4642 if err != nil {
4743 return nil , nil , fmt .Errorf ("could not prepare for image inspection: %w" , err )
4844 }
4945
5046 defer func () {
51- if err := i . cleanup ( sysCtx ); err != nil {
47+ if err := sysCtx . Cleanup ( ); err != nil {
5248 klog .Warningf ("Unable to clean up after inspection of %s: %s" , pullspec , err )
5349 }
5450 }()
5551
56- info , digest , err := i .images .ImageInspect (ctx , sysCtx , pullspec )
52+ info , digest , err := i .images .ImageInspect (ctx , sysCtx . SysContext , pullspec )
5753 if err != nil {
5854 return nil , nil , fmt .Errorf ("could not inspect image: %w" , err )
5955 }
@@ -64,158 +60,20 @@ func (i *imagePrunerImpl) InspectImage(ctx context.Context, pullspec string, sec
6460// DeleteImage deletes the given image using the provided secret. It also accepts a
6561// ControllerConfig so that certificates may be placed on the filesystem for authentication.
6662func (i * imagePrunerImpl ) DeleteImage (ctx context.Context , pullspec string , secret * corev1.Secret , cc * mcfgv1.ControllerConfig ) error {
67- sysCtx , err := i . prepareSystemContext (secret , cc )
63+ sysCtx , err := imageutils . NewSysContextFromControllerConfig (secret , cc )
6864 if err != nil {
6965 return fmt .Errorf ("could not prepare for image deletion: %w" , err )
7066 }
7167
7268 defer func () {
73- if err := i . cleanup ( sysCtx ); err != nil {
69+ if err := sysCtx . Cleanup ( ); err != nil {
7470 klog .Warningf ("Unable to clean up after deletion of %s: %s" , pullspec , err )
7571 }
7672 }()
7773
78- if err := i .images .DeleteImage (ctx , sysCtx , pullspec ); err != nil {
74+ if err := i .images .DeleteImage (ctx , sysCtx . SysContext , pullspec ); err != nil {
7975 return fmt .Errorf ("could not delete image: %w" , err )
8076 }
8177
8278 return nil
8379}
84-
85- // prepareSystemContext prepares to perform the requested operation by first creating the
86- // certificate directory and then writing the authfile to the appropriate path.
87- func (i * imagePrunerImpl ) prepareSystemContext (secret * corev1.Secret , cc * mcfgv1.ControllerConfig ) (* types.SystemContext , error ) {
88- // Make a deep copy of the ControllerConfig because the write process mutates
89- // the ControllerConfig in-place.
90- certsDir , err := i .prepareCerts (cc .DeepCopy ())
91- if err != nil {
92- return nil , fmt .Errorf ("could not prepare certs: %w" , err )
93- }
94-
95- authfilePath , err := i .prepareAuthfile (secret )
96- if err != nil {
97- return nil , fmt .Errorf ("could not get authfile path for secret %s: %w" , secret .Name , err )
98- }
99-
100- return & types.SystemContext {
101- AuthFilePath : authfilePath ,
102- DockerPerHostCertDirPath : certsDir ,
103- }, nil
104- }
105-
106- // cleanup cleans up after an operation by removing the temporary certificates directory
107- // and the temporary authfile.
108- func (i * imagePrunerImpl ) cleanup (sysCtx * types.SystemContext ) error {
109- if err := os .RemoveAll (sysCtx .DockerPerHostCertDirPath ); err != nil && ! os .IsNotExist (err ) {
110- return fmt .Errorf ("could not clean up certs directory %s: %w" , sysCtx .DockerPerHostCertDirPath , err )
111- }
112-
113- if err := os .RemoveAll (sysCtx .AuthFilePath ); err != nil && ! os .IsNotExist (err ) {
114- return fmt .Errorf ("could not clean up authfile directory %s: %w" , sysCtx .AuthFilePath , err )
115- }
116-
117- return nil
118- }
119-
120- // prepareCerts prepares the certificates by first creating a temporary directory for them
121- // and then writing the certs from the ControllerConfig to that directory.
122- func (i * imagePrunerImpl ) prepareCerts (cc * mcfgv1.ControllerConfig ) (string , error ) {
123- certsDir , err := os .MkdirTemp ("" , "imagepruner-certs-dir" )
124- if err != nil {
125- return "" , fmt .Errorf ("could not create temp dir: %w" , err )
126- }
127-
128- if err := i .writeCerts (certsDir , cc ); err != nil {
129- return "" , fmt .Errorf ("could not write certs: %w" , err )
130- }
131-
132- return certsDir , nil
133- }
134-
135- // writeCerts extracts the certificates from the ControllerConfig and writes them
136- // to the appropriate directory, which defaults to /etc/docker/certs.d.
137- func (i * imagePrunerImpl ) writeCerts (certsDir string , cc * mcfgv1.ControllerConfig ) error {
138- template .UpdateControllerConfigCerts (cc )
139-
140- for _ , irb := range cc .Spec .ImageRegistryBundleData {
141- if err := i .writeCertFromImageRegistryBundle (certsDir , irb ); err != nil {
142- return fmt .Errorf ("could not write image registry bundle from ImageRegistryBundleData: %w" , err )
143- }
144- }
145-
146- for _ , irb := range cc .Spec .ImageRegistryBundleUserData {
147- if err := i .writeCertFromImageRegistryBundle (certsDir , irb ); err != nil {
148- return fmt .Errorf ("could not write image registry bundle from ImageRegistryBundleUserData: %w" , err )
149- }
150- }
151-
152- return nil
153- }
154-
155- // writeCertFromImageRegistryBundle writes a certificate from an image registry bundle
156- // to the specified certificates directory, creating necessary subdirectories.
157- func (i * imagePrunerImpl ) writeCertFromImageRegistryBundle (certsDir string , irb mcfgv1.ImageRegistryBundle ) error {
158- caFile := strings .ReplaceAll (irb .File , ".." , ":" )
159-
160- certDir := filepath .Join (certsDir , caFile )
161-
162- if err := os .MkdirAll (certDir , 0o755 ); err != nil {
163- return fmt .Errorf ("could not create cert dir %q: %w" , certDir , err )
164- }
165-
166- certFile := filepath .Join (certDir , "ca.crt" )
167-
168- if err := os .WriteFile (certFile , irb .Data , 0o644 ); err != nil {
169- return fmt .Errorf ("could not write cert file %q: %w" , certFile , err )
170- }
171-
172- return nil
173- }
174-
175- // prepareAuthfile creates a temporary directory and writes the Docker secret
176- // (authfile) into a file named "authfile.json" within that directory.
177- // It returns the path to the created authfile.
178- func (i * imagePrunerImpl ) prepareAuthfile (secret * corev1.Secret ) (string , error ) {
179- authfileDir , err := os .MkdirTemp ("" , "imagepruner-authfile" )
180- if err != nil {
181- return "" , fmt .Errorf ("could not create temp dir for authfile: %w" , err )
182- }
183-
184- authfilePath := filepath .Join (authfileDir , "authfile.json" )
185-
186- is , err := secrets .NewImageRegistrySecret (secret )
187- if err != nil {
188- return "" , fmt .Errorf ("could not create an ImageRegistrySecret for '%s/%s': %w" , secret .Namespace , secret .Name , err )
189- }
190-
191- secretBytes , err := is .JSONBytes (corev1 .SecretTypeDockerConfigJson )
192- if err != nil {
193- return "" , fmt .Errorf ("could not normalize secret '%s/%s' to %s: %w" , secret .Namespace , secret .Name , corev1 .SecretTypeDockerConfigJson , err )
194- }
195-
196- if err := os .WriteFile (authfilePath , secretBytes , 0o644 ); err != nil {
197- return "" , fmt .Errorf ("could not write temp authfile %q for secret %q: %w" , authfilePath , secret .Name , err )
198- }
199-
200- return authfilePath , nil
201- }
202-
203- // writeAuthfile ensures that the image registry secret is in the dockerconfigjson format
204- // and writes it to the specified path.
205- func (i * imagePrunerImpl ) writeAuthfile (secret * corev1.Secret , authfilePath string ) error {
206- is , err := secrets .NewImageRegistrySecret (secret )
207- if err != nil {
208- return fmt .Errorf ("could not create an ImageRegistrySecret for '%s/%s': %w" , secret .Namespace , secret .Name , err )
209- }
210-
211- secretBytes , err := is .JSONBytes (corev1 .SecretTypeDockerConfigJson )
212- if err != nil {
213- return fmt .Errorf ("could not normalize secret '%s/%s' to %s: %w" , secret .Namespace , secret .Name , corev1 .SecretTypeDockerConfigJson , err )
214- }
215-
216- if err := os .WriteFile (authfilePath , secretBytes , 0o644 ); err != nil {
217- return fmt .Errorf ("could not write temp authfile %q for secret %q: %w" , authfilePath , secret .Name , err )
218- }
219-
220- return nil
221- }
0 commit comments