@@ -16,23 +16,18 @@ import (
1616 "github.com/cosi-project/runtime/pkg/resource"
1717 "github.com/cosi-project/runtime/pkg/safe"
1818 "go.uber.org/zap"
19- "golang.org/x/sys/unix"
2019
21- "github.com/siderolabs/talos/internal/pkg/mount/v3"
2220 "github.com/siderolabs/talos/internal/pkg/selinux"
2321 "github.com/siderolabs/talos/pkg/machinery/resources/files"
2422 "github.com/siderolabs/talos/pkg/xfs"
2523)
2624
2725// EtcFileController watches EtcFileSpecs, creates/updates files.
2826type EtcFileController struct {
29- // Path to /etc directory, read-only filesystem.
30- EtcPath string
31- // EtcRoot is the root for /etc filesystem operations .
27+ // EtcRoot is the root for /etc filesystem operations. Files written here surface
28+ // read-only at /etc through the composed /etc overlay (see setupEtcOverlay), so no
29+ // per-file bind mounts are needed .
3230 EtcRoot xfs.Root
33-
34- // Cache of bind mounts created.
35- bindMounts map [string ]any
3631}
3732
3833// Name implements controller.Controller interface.
@@ -63,12 +58,8 @@ func (ctrl *EtcFileController) Outputs() []controller.Output {
6358
6459// Run implements controller.Controller interface.
6560//
66- //nolint:gocyclo,cyclop
61+ //nolint:gocyclo
6762func (ctrl * EtcFileController ) Run (ctx context.Context , r controller.Runtime , logger * zap.Logger ) error {
68- if ctrl .bindMounts == nil {
69- ctrl .bindMounts = make (map [string ]any )
70- }
71-
7263 for {
7364 select {
7465 case <- ctx .Done ():
@@ -96,56 +87,24 @@ func (ctrl *EtcFileController) Run(ctx context.Context, r controller.Runtime, lo
9687
9788 for spec := range list .All () {
9889 filename := spec .Metadata ().ID ()
99- _ , mountExists := ctrl .bindMounts [filename ]
100-
101- dst := filepath .Join (ctrl .EtcPath , filename )
102- src := filename
10390
10491 switch spec .Metadata ().Phase () {
10592 case resource .PhaseTearingDown :
106- if mountExists {
107- logger .Debug ("removing bind mount" , zap .String ("src" , src ), zap .String ("dst" , dst ))
108-
109- if err = unix .Unmount (dst , 0 ); err != nil && ! errors .Is (err , os .ErrNotExist ) {
110- return fmt .Errorf ("failed to unmount bind mount %q: %w" , dst , err )
111- }
93+ logger .Debug ("removing file" , zap .String ("name" , filename ))
11294
113- delete (ctrl .bindMounts , filename )
95+ if err = xfs .Remove (ctrl .EtcRoot , filename ); err != nil && ! errors .Is (err , os .ErrNotExist ) {
96+ return fmt .Errorf ("failed to remove %q: %w" , filename , err )
11497 }
11598
116- logger .Debug ("removing file" , zap .String ("src" , src ))
117-
118- if err = xfs .Remove (ctrl .EtcRoot , src ); err != nil && ! errors .Is (err , os .ErrNotExist ) {
119- return fmt .Errorf ("failed to remove %q: %w" , src , err )
120- }
121-
122- // now remove finalizer as the link was deleted
99+ // now remove finalizer as the file was deleted
123100 if err = r .RemoveFinalizer (ctx , spec .Metadata (), ctrl .Name ()); err != nil {
124101 return fmt .Errorf ("error removing finalizer: %w" , err )
125102 }
126103 case resource .PhaseRunning :
127- if ! mountExists {
128- logger .Debug ("creating bind mount" , zap .String ("src" , src ), zap .String ("dst" , dst ))
129-
130- if ctrl .EtcRoot .FSType () == "os" {
131- shadow := filepath .Join (ctrl .EtcRoot .Source (), src )
104+ logger .Debug ("writing file contents" , zap .String ("name" , filename ), zap .Stringer ("version" , spec .Metadata ().Version ()))
132105
133- if err = createBindMountFile (shadow , dst , spec .TypedSpec ().Mode ); err != nil {
134- return fmt .Errorf ("failed to create shadow bind mount %q -> %q (mode: os): %w" , shadow , dst , err )
135- }
136- } else {
137- if err = createBindMountFileFd (ctrl .EtcRoot , src , dst , spec .TypedSpec ().Mode ); err != nil {
138- return fmt .Errorf ("failed to create shadow bind mount %q -> %q (mode: fd): %w" , src , dst , err )
139- }
140- }
141-
142- ctrl .bindMounts [filename ] = struct {}{}
143- }
144-
145- logger .Debug ("writing file contents" , zap .String ("src" , src ), zap .Stringer ("version" , spec .Metadata ().Version ()))
146-
147- if err = UpdateFile (ctrl .EtcRoot , src , spec .TypedSpec ().Contents , spec .TypedSpec ().Mode , spec .TypedSpec ().SelinuxLabel ); err != nil {
148- return fmt .Errorf ("error updating %q: %w" , src , err )
106+ if err = UpdateFile (ctrl .EtcRoot , filename , spec .TypedSpec ().Contents , spec .TypedSpec ().Mode , spec .TypedSpec ().SelinuxLabel ); err != nil {
107+ return fmt .Errorf ("error updating %q: %w" , filename , err )
149108 }
150109
151110 if err = safe .WriterModify (ctx , r , files .NewEtcFileStatus (files .NamespaceName , filename ), func (r * files.EtcFileStatus ) error {
@@ -178,73 +137,6 @@ func (ctrl *EtcFileController) Run(ctx context.Context, r controller.Runtime, lo
178137 }
179138}
180139
181- // createBindMountFile creates a common way to create a writable source file with a
182- // bind mounted destination. This is most commonly used for well known files
183- // under /etc that need to be adjusted during startup.
184- func createBindMountFile (src , dst string , mode os.FileMode ) (err error ) {
185- if err = os .MkdirAll (filepath .Dir (src ), 0o755 ); err != nil {
186- return fmt .Errorf ("mkdir all failed: %w" , err )
187- }
188-
189- var f * os.File
190-
191- if f , err = os .OpenFile (src , os .O_WRONLY | os .O_CREATE , mode ); err != nil {
192- return fmt .Errorf ("open file failed: %w" , err )
193- }
194-
195- if err = f .Close (); err != nil {
196- return fmt .Errorf ("close file failed: %w" , err )
197- }
198-
199- return mount .BindReadonly (src , dst )
200- }
201-
202- // createBindMountDir creates a common way to create a writable source dir with a
203- // bind mounted destination. This is most commonly used for well known directories
204- // under /etc that need to be adjusted during startup.
205- func createBindMountDir (src , dst string ) (err error ) {
206- if err = os .MkdirAll (src , 0o755 ); err != nil {
207- return err
208- }
209-
210- return mount .BindReadonly (src , dst )
211- }
212-
213- // createBindMountFileFd creates a common way to create a writable source file with a
214- // bind mounted destination. This is most commonly used for well known files
215- // under /etc that need to be adjusted during startup.
216- func createBindMountFileFd (root xfs.Root , src , dst string , mode os.FileMode ) (err error ) {
217- if err = xfs .MkdirAll (root , filepath .Dir (src ), 0o755 ); err != nil {
218- return err
219- }
220-
221- fsrc , err := xfs .OpenFile (root , src , os .O_WRONLY | os .O_CREATE , mode )
222- if err != nil {
223- return err
224- }
225- defer fsrc .Close () //nolint:errcheck
226-
227- return mount .BindReadonlyFd (int (fsrc .Fd ()), dst )
228- }
229-
230- // createBindMountDirFd creates a common way to create a writable source dir with a
231- // bind mounted destination. This is most commonly used for well known directories
232- // under /etc that need to be adjusted during startup.
233- func createBindMountDirFd (root xfs.Root , src , dst string ) (err error ) {
234- if err = xfs .MkdirAll (root , src , 0o755 ); err != nil {
235- return fmt .Errorf ("mkdir all failed: %w" , err )
236- }
237-
238- f , err := xfs .OpenFile (root , src , os .O_RDONLY , 0 )
239- if err != nil {
240- return fmt .Errorf ("open file failed: %w" , err )
241- }
242-
243- defer f .Close () //nolint:errcheck
244-
245- return mount .BindReadonlyFd (int (f .Fd ()), dst )
246- }
247-
248140// UpdateFile is like `os.WriteFile`, but it will only update the file if the
249141// contents have changed.
250142func UpdateFile (root xfs.Root , filename string , contents []byte , mode os.FileMode , selinuxLabel string ) error {
0 commit comments