1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package time
17
18 import (
19 "fmt"
20 "sync"
21
22 "github.com/go-logr/logr"
23 "github.com/pkg/errors"
24
25 "github.com/chaos-mesh/chaos-mesh/pkg/cerr"
26 "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/tasks"
27 )
28
29
30 const clockGettimeSkewFakeImage = "fake_clock_gettime.o"
31
32
33 const clockGettime = "clock_gettime"
34
35
36 const (
37 externVarClockIdsMask = "CLOCK_IDS_MASK"
38 externVarTvSecDelta = "TV_SEC_DELTA"
39 externVarTvNsecDelta = "TV_NSEC_DELTA"
40 )
41
42
43 const timeOfDaySkewFakeImage = "fake_gettimeofday.o"
44
45
46 const getTimeOfDay = "gettimeofday"
47
48
49
50
51
52
53 type Config struct {
54 deltaSeconds int64
55 deltaNanoSeconds int64
56 clockIDsMask uint64
57 }
58
59 func NewConfig(deltaSeconds int64, deltaNanoSeconds int64, clockIDsMask uint64) Config {
60 return Config{
61 deltaSeconds: deltaSeconds,
62 deltaNanoSeconds: deltaNanoSeconds,
63 clockIDsMask: clockIDsMask,
64 }
65 }
66
67 func (c *Config) DeepCopy() tasks.Object {
68 return &Config{
69 c.deltaSeconds,
70 c.deltaNanoSeconds,
71 c.clockIDsMask,
72 }
73 }
74
75
76 func (c *Config) Merge(a tasks.Mergeable) error {
77 A, OK := a.(*Config)
78 if OK {
79
80 c.deltaSeconds += A.deltaSeconds
81 c.deltaNanoSeconds += A.deltaNanoSeconds
82 c.clockIDsMask |= A.clockIDsMask
83 return nil
84 }
85 return cerr.NotType[*Config]().WrapInput(a).Err()
86 }
87
88 type ConfigCreatorParas struct {
89 Logger logr.Logger
90 Config Config
91 PodProcessMap *tasks.PodContainerNameProcessMap
92 }
93
94
95
96 func (c *Config) New(values interface{}) (tasks.Injectable, error) {
97 paras, ok := values.(ConfigCreatorParas)
98 if !ok {
99 return nil, errors.New("not ConfigCreatorParas")
100 }
101
102 skew, err := GetSkew(paras.Logger, paras.Config)
103 if err != nil {
104 return nil, err
105 }
106
107 newGroupProcessHandler :=
108 tasks.NewProcessGroupHandler(paras.Logger, &skew)
109 newPodHandler := tasks.NewPodHandler(paras.PodProcessMap,
110 &newGroupProcessHandler, paras.Logger)
111 return &newPodHandler, nil
112 }
113
114
115
116
117 func (c *Config) Assign(injectable tasks.Injectable) error {
118 podHandler, ok := injectable.(*tasks.PodHandler)
119 if !ok {
120 return errors.New(fmt.Sprintf("type %T is not *tasks.PodHandler", injectable))
121 }
122 groupProcessHandler, ok := podHandler.SubProcess.(*tasks.ProcessGroupHandler)
123 if !ok {
124 return errors.New(fmt.Sprintf("type %T is not *tasks.ProcessGroupHandler", podHandler.SubProcess))
125 }
126 I, ok := groupProcessHandler.LeaderProcess.(*Skew)
127 if !ok {
128 return errors.New(fmt.Sprintf("type %T is not *Skew", groupProcessHandler.LeaderProcess))
129 }
130
131 I.SkewConfig = *c
132 return nil
133 }
134
135
136
137 type Skew struct {
138 SkewConfig Config
139 clockGetTime *FakeImage
140 getTimeOfDay *FakeImage
141
142 locker sync.Mutex
143 logger logr.Logger
144 }
145
146 func GetSkew(logger logr.Logger, c Config) (Skew, error) {
147 clockGetTimeImage, err := LoadFakeImageFromEmbedFs(clockGettimeSkewFakeImage, clockGettime, logger)
148 if err != nil {
149 return Skew{}, errors.Wrap(err, "load fake image")
150 }
151
152 getTimeOfDayimage, err := LoadFakeImageFromEmbedFs(timeOfDaySkewFakeImage, getTimeOfDay, logger)
153 if err != nil {
154 return Skew{}, errors.Wrap(err, "load fake image")
155 }
156
157 return Skew{
158 SkewConfig: c,
159 clockGetTime: clockGetTimeImage,
160 getTimeOfDay: getTimeOfDayimage,
161 locker: sync.Mutex{},
162 logger: logger,
163 }, nil
164 }
165
166 func (s *Skew) Fork() (tasks.ChaosOnProcessGroup, error) {
167
168 skew, err := GetSkew(s.logger, s.SkewConfig)
169 if err != nil {
170 return nil, err
171 }
172
173 return &skew, nil
174 }
175
176 func (s *Skew) Assign(injectable tasks.Injectable) error {
177 I, OK := injectable.(*Skew)
178 if OK {
179 I.SkewConfig = *s.SkewConfig.DeepCopy().(*Config)
180 return nil
181 }
182 return cerr.NotType[*Skew]().WrapInput(injectable).Err()
183 }
184
185 func (s *Skew) Inject(pid tasks.IsID) error {
186 s.locker.Lock()
187 defer s.locker.Unlock()
188 sysPID, ok := pid.(tasks.SysPID)
189 if !ok {
190 return tasks.ErrNotTypeSysID.WrapInput(pid).Err()
191 }
192
193 s.logger.Info("injecting time skew", "pid", pid)
194
195 err := s.clockGetTime.AttachToProcess(int(sysPID), map[string]uint64{
196 externVarClockIdsMask: s.SkewConfig.clockIDsMask,
197 externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds),
198 externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds),
199 })
200 if err != nil {
201 return err
202 }
203
204 err = s.getTimeOfDay.AttachToProcess(int(sysPID), map[string]uint64{
205 externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds),
206 externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds),
207 })
208 if err != nil {
209 return err
210 }
211 return nil
212 }
213
214
215
216
217 func (s *Skew) Recover(pid tasks.IsID) error {
218 s.locker.Lock()
219 defer s.locker.Unlock()
220 sysPID, ok := pid.(tasks.SysPID)
221 if !ok {
222 return tasks.ErrNotTypeSysID.WrapInput(pid).Err()
223 }
224
225 s.logger.Info("recovering time skew", "pid", pid)
226
227 err1 := s.clockGetTime.Recover(int(sysPID), map[string]uint64{
228 externVarClockIdsMask: s.SkewConfig.clockIDsMask,
229 externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds),
230 externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds),
231 })
232 if err1 != nil {
233 err2 := s.getTimeOfDay.Recover(int(sysPID), map[string]uint64{
234 externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds),
235 externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds),
236 })
237 if err2 != nil {
238 return errors.Wrapf(err1, "time skew all failed %v", err2)
239 }
240 return err1
241 }
242
243 err2 := s.getTimeOfDay.Recover(int(sysPID), map[string]uint64{
244 externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds),
245 externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds),
246 })
247 if err2 != nil {
248 return err2
249 }
250
251 return nil
252 }
253