88 "os"
99 "path/filepath"
1010 "regexp"
11+ "strings"
1112 "sync"
1213 "time"
1314
@@ -23,6 +24,7 @@ type HostManager interface {
2324 NeedsUpdate () (bool , error )
2425 Diff () (string , error )
2526 Apply (exporterConfig * v1alpha1.ExporterConfigTemplate , dryRun bool ) error
27+ RunHostCommand (command string ) (* CommandResult , error )
2628}
2729
2830// CommandResult represents the result of running a command via SSH
@@ -166,6 +168,20 @@ func (m *SSHHostManager) Apply(exporterConfig *v1alpha1.ExporterConfigTemplate,
166168 return fmt .Errorf ("both SystemdContainerTemplate and SystemdServiceTemplate specified - only one should be used" )
167169 }
168170
171+ // Helper function to restart service
172+ restartService := func (serviceName string , dryRun bool ) {
173+ if ! dryRun {
174+ _ , enableErr := m .runCommand ("systemctl restart " + fmt .Sprintf ("%q" , serviceName ))
175+ if enableErr != nil {
176+ fmt .Printf (" ❌ Failed to start service %s: %v\n " , serviceName , enableErr )
177+ } else {
178+ fmt .Printf (" ✅ Service %s started\n " , serviceName )
179+ }
180+ } else {
181+ fmt .Printf (" 📄 Would restart service %s\n " , serviceName )
182+ }
183+ }
184+
169185 svcName := exporterConfig .Spec .ExporterMetadata .Name
170186 containerSystemdFile := "/etc/containers/systemd/" + svcName + ".container"
171187 serviceSystemdFile := "/etc/systemd/system/" + svcName + ".service"
@@ -194,26 +210,54 @@ func (m *SSHHostManager) Apply(exporterConfig *v1alpha1.ExporterConfigTemplate,
194210 return fmt .Errorf ("failed to reload systemd: %w" , err )
195211 }
196212 if changedService {
197- _ , err = m .runCommand ("systemctl enable " + svcName )
213+ _ , err = m .runCommand ("systemctl enable " + fmt . Sprintf ( "%q" , svcName ) )
198214 if err != nil {
199215 return fmt .Errorf ("failed to enable exporter: %w" , err )
200216 }
201217 }
202- _ , err = m .runCommand ("systemctl restart " + svcName )
203- if err != nil {
204- return fmt .Errorf ("failed to restart exporter: %w" , err )
205- }
206- fmt .Printf (" ✅ Exporter service started\n " )
218+ restartService (svcName , dryRun )
207219 }
208220 } else {
209- if dryRun {
210- fmt .Printf (" ✅ dry run: No changes needed\n " )
221+ // Check if service is running and start if needed
222+ statusResult , err := m .runCommand ("systemctl is-active " + fmt .Sprintf ("%q" , svcName ))
223+ if err != nil || statusResult .Stdout != "active\n " {
224+ fmt .Printf (" ⚠️ Service %s is not running...\n " , svcName )
225+ restartService (svcName , dryRun )
226+ }
227+
228+ // Check if container needs updating using podman auto-update (if podman exists)
229+ autoUpdateResult , err := m .runCommand (fmt .Sprintf ("command -v podman >/dev/null 2>&1 && podman auto-update --dry-run --format json | jq -r '.[] | select(.ContainerName == %q) | .Updated'" , svcName ))
230+ if err != nil {
231+ fmt .Printf (" ℹ️ Podman not available, skipping auto-update check\n " )
232+ } else {
233+ updatedOutput := strings .TrimSpace (autoUpdateResult .Stdout )
234+ switch updatedOutput {
235+ case "" :
236+ fmt .Printf (" ⚠️ Container %s not found in auto-update check\n " , svcName )
237+ case "false" :
238+ if dryRun {
239+ fmt .Printf (" ✅ Exporter container image is up to date\n " )
240+ }
241+ case "true" :
242+ if dryRun {
243+ fmt .Printf (" 📄 Would update container %s\n " , svcName )
244+ } else {
245+ restartService (svcName , dryRun )
246+ }
247+ default :
248+ return fmt .Errorf ("unexpected auto-update result: %s" , updatedOutput )
249+ }
211250 }
212251 }
213252
214253 return nil
215254}
216255
256+ // RunHostCommand implements the HostManager interface by exposing runCommand
257+ func (m * SSHHostManager ) RunHostCommand (command string ) (* CommandResult , error ) {
258+ return m .runCommand (command )
259+ }
260+
217261// sanitizeDiff removes sensitive information from diff output
218262func sanitizeDiff (diff string ) string {
219263 // Regex patterns to match sensitive fields
0 commit comments