package instancectl import ( "context" "errors" "fmt" "os" "path/filepath" "github.com/carlosframework/platform/internal/safefile" ) // clearLegacyClaimLaunch removes a claim launch snapshot before the legacy // controller may reuse the main run unit. Artifact-free hosts keep the old // path: they do not acquire a systemd query or cgroup read. func (s *Server) clearLegacyClaimLaunch(ctx context.Context, host string) error { if s.DropInDir == "" || s.ExeRoot == "" || s.DataRoot == "" || s.CgroupRoot == "" { return nil } u := ClaimUnits{ Systemctl: s.Systemctl, CgroupRoot: s.CgroupRoot, ExeRoot: s.ExeRoot, UnitRoot: s.DropInDir, DataRoot: s.DataRoot, } source, dropin, err := u.launchPaths(host) if err != nil { return err } found := false dropinPath := filepath.Join(dropin, "60-claim-launch.conf") var dropinBody []byte for _, path := range []string{ filepath.Join(source, "launch.json"), filepath.Join(source, "permit.json"), filepath.Join(source, "exec.sock"), dropinPath, } { if _, err := os.Lstat(path); err == nil { found = true if path == dropinPath { dropinBody, err = safefile.ReadFile(path) if err != nil { return fmt.Errorf("read claim launch %s: %w", path, err) } } } else if !errors.Is(err, os.ErrNotExist) { return fmt.Errorf("inspect claim launch %s: %w", path, err) } } if !found { return nil } // Gone proves both facts required before clearLaunch mutates either // artifact: systemd says the unit is idle and its cgroup is empty. if err := u.Gone(ctx, host, ""); err != nil { // clearLaunch removes the drop-in before daemon-reload. Restore it // when that reload fails, so a later attempt cannot mistake a cached // systemd binding for an artifact-free host and start through it. if dropinBody != nil { if _, statErr := os.Lstat(dropinPath); errors.Is(statErr, os.ErrNotExist) { restoreErr := safefile.WriteFile(dropinPath, dropinBody, 0644) if restoreErr != nil { err = errors.Join(err, fmt.Errorf("restore claim launch drop-in: %w", restoreErr)) } } } return fmt.Errorf("clear claim launch for %s: %w", host, err) } return nil }