• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openshift-kni / lifecycle-agent / 567839dabd85027fcc379712ab73d3ce3dd9d8a8

20 May 2026 04:08PM UTC coverage: 30.271% (+0.5%) from 29.8%
567839dabd85027fcc379712ab73d3ce3dd9d8a8

push

web-flow
Merge pull request #6318 from sebrandon1/CNF-23417

CNF-23417: Add unit tests for rollback handlers

4920 of 16253 relevant lines covered (30.27%)

0.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lca-cli/initmonitor/initmonitor.go
1
package initmonitor
2

3
import (
4
        "errors"
5
        "fmt"
6
        "os"
7
        "time"
8

9
        "github.com/sirupsen/logrus"
10
        "k8s.io/apimachinery/pkg/runtime"
11

12
        "github.com/openshift-kni/lifecycle-agent/internal/ostreeclient"
13
        "github.com/openshift-kni/lifecycle-agent/internal/reboot"
14
        "github.com/openshift-kni/lifecycle-agent/lca-cli/ops"
15
        rpmostreeclient "github.com/openshift-kni/lifecycle-agent/lca-cli/ostreeclient"
16

17
        "github.com/go-logr/logr"
18
)
19

20
type InitMonitor struct {
21
        scheme               *runtime.Scheme
22
        log                  *logrus.Logger
23
        hostCommandsExecutor ops.Execute
24
        ops                  ops.Ops
25
        component            string
26
        rpmOstreeClient      *rpmostreeclient.Client
27
        ostreeClient         ostreeclient.IClient
28
        rebootClient         reboot.RebootIntf
29
        mode                 string
30
}
31

32
func NewInitMonitor(scheme *runtime.Scheme, log *logrus.Logger, hostCommandsExecutor ops.Execute, ops ops.Ops, component, mode string) *InitMonitor {
×
33
        rpmOstreeClient := rpmostreeclient.NewClient("initmonitor", hostCommandsExecutor)
×
34
        ostreeClient := ostreeclient.NewClient(hostCommandsExecutor, false)
×
35
        var rebootClient reboot.RebootIntf
×
36
        if mode == "ipconfig" {
×
37
                rebootClient = reboot.NewIPCRebootClient(&logr.Logger{}, hostCommandsExecutor, rpmOstreeClient, ostreeClient, ops)
×
38
        } else {
×
39
                rebootClient = reboot.NewIBURebootClient(&logr.Logger{}, hostCommandsExecutor, rpmOstreeClient, ostreeClient, ops)
×
40
        }
×
41
        return &InitMonitor{
×
42
                scheme:               scheme,
×
43
                log:                  log,
×
44
                hostCommandsExecutor: hostCommandsExecutor,
×
45
                ops:                  ops,
×
46
                component:            component,
×
47
                rpmOstreeClient:      rpmOstreeClient,
×
48
                ostreeClient:         ostreeClient,
×
49
                rebootClient:         rebootClient,
×
50
                mode:                 mode,
×
51
        }
×
52
}
53

54
func (m *InitMonitor) RunInitMonitor() error {
×
55
        rollbackCfg, err := m.rebootClient.ReadAutoRollbackConfigFile()
×
56
        if err != nil {
×
57
                if errors.Is(err, os.ErrNotExist) {
×
58
                        return nil
×
59
                }
×
60

61
                return fmt.Errorf("failed to read rollback config file: %w", err)
×
62
        }
63

64
        if !rollbackCfg.InitMonitorEnabled {
×
65
                m.log.Info("LCA Init Monitor automatic rollback is disabled in IBU configuration")
×
66
                return nil
×
67
        }
×
68

69
        if rollbackCfg.InitMonitorTimeout <= 0 {
×
70
                // This shouldn't happen, as value of <= 0 is treated as "use default" when config file is written
×
71
                m.log.Infof("LCA Init Monitor timeout value must be greater than 0: current value %d", rollbackCfg.InitMonitorTimeout)
×
72
                return nil
×
73
        }
×
74

75
        timeout := time.Duration(rollbackCfg.InitMonitorTimeout) * time.Second
×
76

×
77
        // Adjust log message based on mode
×
78
        contextText := "upgrade"
×
79
        if m.mode == "ipconfig" {
×
80
                contextText = "ip-config"
×
81
        }
×
82
        m.log.Infof("Launching LCA Init Monitor timeout. Automatic rollback will occur in %s if %s is not completed successfully within that time", timeout, contextText)
×
83

×
84
        time.Sleep(timeout)
×
85

×
86
        // If we reach this point, the init monitor was not shut down by the handler, so trigger rollback
×
87

×
88
        msg := fmt.Sprintf("Rollback due to LCA Init Monitor timeout, after %s", timeout)
×
89
        m.log.Info(msg)
×
90

×
91
        if err := m.rebootClient.InitiateRollback(msg); err != nil {
×
92
                return fmt.Errorf("unable to auto rollback: %w", err)
×
93
        }
×
94

95
        return nil
×
96
}
97

98
func (m *InitMonitor) checkSvcUnitRollbackNeeded() bool {
×
99
        rollbackCfg, err := m.rebootClient.ReadAutoRollbackConfigFile()
×
100
        if err != nil {
×
101
                if os.IsNotExist(err) {
×
102
                        return false
×
103
                }
×
104

105
                m.log.Error(err, "failed to read rollback config file")
×
106
                return false
×
107
        }
108

109
        if !rollbackCfg.EnabledComponents[m.component] {
×
110
                // Auto-rollback is disabled, so do nothing
×
111
                m.log.Info(fmt.Sprintf("LCA Init Monitor Auto-rollback is disabled for component %s", m.component))
×
112
                return false
×
113
        }
×
114

115
        // Get the systemd service-unit serviceResult
116
        serviceResult, ok := os.LookupEnv("SERVICE_RESULT")
×
117
        if !ok {
×
118
                m.log.Info("SERVICE_RESULT variable is not set")
×
119
                return false
×
120
        }
×
121

122
        m.log.Info(fmt.Sprintf("LCA Init Monitor: component %s exited with SERVICE_RESULT=%s", m.component, serviceResult))
×
123

×
124
        if serviceResult == "success" {
×
125
                // The service-unit succeeded, or auto-rollback is disabled, so do nothing
×
126
                return false
×
127
        }
×
128

129
        return true
×
130
}
131

132
func (m *InitMonitor) RunExitStopPostCheck() error {
×
133
        if m.checkSvcUnitRollbackNeeded() {
×
134
                msg := fmt.Sprintf("Rollback due to service-unit failure: component %s", m.component)
×
135
                m.log.Info(msg)
×
136

×
137
                if err := m.rebootClient.InitiateRollback(msg); err != nil {
×
138
                        return fmt.Errorf("unable to auto rollback: %w", err)
×
139
                }
×
140
        }
141

142
        return nil
×
143
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc