@@ -25,6 +25,7 @@ import (
25
25
"fmt"
26
26
"github.com/FoundationDB/fdb-kubernetes-operator/pkg/fdbstatus"
27
27
"sort"
28
+ "strconv"
28
29
"time"
29
30
30
31
fdbv1beta2 "github.com/FoundationDB/fdb-kubernetes-operator/api/v1beta2"
@@ -126,15 +127,17 @@ kubectl fdb get exclusion-status c1 --interval=5m
126
127
127
128
type exclusionResult struct {
128
129
id string
129
- storedBytes int
130
130
estimate string
131
+ storedBytes int
132
+ timestamp time.Time
131
133
}
132
134
133
135
func getExclusionStatus (cmd * cobra.Command , restConfig * rest.Config , kubeClient * kubernetes.Clientset , clientPod string , namespace string , ignoreFullyExcluded bool , interval time.Duration ) error {
134
136
timer := time .NewTicker (interval )
135
- previousRun := map [string ]int {}
137
+ previousRun := map [string ]exclusionResult {}
136
138
137
139
for {
140
+ // TODO: Keeping a stream open is probably more efficient.
138
141
out , serr , err := executeCmd (restConfig , kubeClient , clientPod , namespace , "fdbcli --exec 'status json'" )
139
142
if err != nil {
140
143
// If an error occurs retry
@@ -162,38 +165,48 @@ func getExclusionStatus(cmd *cobra.Command, restConfig *rest.Config, kubeClient
162
165
}
163
166
164
167
var ongoingExclusions []exclusionResult
168
+ timestamp := time .Now ()
165
169
for _ , process := range status .Cluster .Processes {
166
170
if ! process .Excluded {
167
171
continue
168
172
}
169
173
174
+ // If more than one storage server per Pod is running we have to differentiate those processes. If the
175
+ // process ID is not set, fall back to the instance ID.
176
+ instance , ok := process .Locality [fdbv1beta2 .FDBLocalityProcessIDKey ]
177
+ if ! ok {
178
+ instance = process .Locality [fdbv1beta2 .FDBLocalityInstanceIDKey ]
179
+ }
180
+
170
181
if ! ignoreFullyExcluded && len (process .Roles ) == 0 {
171
- cmd .Println (process .Locality ["instance_id" ], "is fully excluded" )
182
+ cmd .Println (instance , "is fully excluded" )
183
+ continue
172
184
}
173
185
174
- instance := process .Locality ["instance_id" ]
175
- // TODO: Add estimate when an exclusion is done
176
186
// TODO: Add progress bars
177
187
for _ , role := range process .Roles {
178
188
roleClass := fdbv1beta2 .ProcessClass (role .Role )
179
189
if roleClass .IsStateful () {
180
190
var estimate string
181
191
182
- previousBytes , ok := previousRun [instance ]
192
+ previousResult , ok := previousRun [instance ]
183
193
if ok {
184
- // TODO calculate estimates for duration
185
- _ = previousBytes
194
+ estimateDuration := time .Duration (role .StoredBytes / (previousResult .storedBytes - role .StoredBytes )) * timestamp .Sub (previousResult .timestamp )
195
+ estimate = estimateDuration .String ()
196
+ } else {
186
197
estimate = "N/A"
187
198
}
188
199
189
- // TODO: Check if StoredBytes is the correct value
190
- ongoingExclusions = append (ongoingExclusions , exclusionResult {
200
+ result := exclusionResult {
191
201
id : instance ,
192
202
storedBytes : role .StoredBytes ,
193
203
estimate : estimate ,
194
- })
204
+ timestamp : timestamp ,
205
+ }
206
+ // TODO: Check if StoredBytes is the correct value
207
+ ongoingExclusions = append (ongoingExclusions , result )
195
208
196
- previousRun [instance ] = role . StoredBytes
209
+ previousRun [instance ] = result
197
210
}
198
211
}
199
212
}
@@ -208,7 +221,7 @@ func getExclusionStatus(cmd *cobra.Command, restConfig *rest.Config, kubeClient
208
221
})
209
222
210
223
for _ , exclusion := range ongoingExclusions {
211
- cmd .Printf ("%s:\t %d bytes are left - estimate: %s\n " , exclusion .id , exclusion .storedBytes , exclusion .estimate )
224
+ cmd .Printf ("%s:\t %s are left - estimate: %s\n " , exclusion .id , prettyPrintStoredBytes ( exclusion .storedBytes ) , exclusion .estimate )
212
225
}
213
226
214
227
cmd .Println ("There are" , len (ongoingExclusions ), "processes that are not fully excluded." )
@@ -218,3 +231,20 @@ func getExclusionStatus(cmd *cobra.Command, restConfig *rest.Config, kubeClient
218
231
219
232
return nil
220
233
}
234
+
235
+ // prettyPrintStoredBytes will return a string that represents the storedBytes in a human-readable format.
236
+ func prettyPrintStoredBytes (storedBytes int ) string {
237
+ units := []string {"" , "Ki" , "Mi" , "Gi" , "Ti" , "Pi" }
238
+
239
+ currentBytes := float64 (storedBytes )
240
+ for _ , unit := range units {
241
+ if currentBytes < 1024 {
242
+ return fmt .Sprintf ("%3.2f%s" , currentBytes , unit )
243
+ }
244
+
245
+ currentBytes /= 1024
246
+ }
247
+
248
+ // Fallback will be to printout the bytes.
249
+ return strconv .Itoa (storedBytes )
250
+ }
0 commit comments