@@ -19,9 +19,13 @@ import (
19
19
"fmt"
20
20
"io"
21
21
"os/exec"
22
+ "regexp"
23
+ "strconv"
24
+ "strings"
22
25
26
+ sharedErrors "github.com/coreos/ignition/v2/config/shared/errors"
23
27
"github.com/coreos/ignition/v2/config/util"
24
- "github.com/coreos/ignition/v2/config/v3_5_experimental/types "
28
+ "github.com/coreos/ignition/v2/internal/device_managers "
25
29
"github.com/coreos/ignition/v2/internal/distro"
26
30
"github.com/coreos/ignition/v2/internal/log"
27
31
)
@@ -30,30 +34,18 @@ type Operation struct {
30
34
logger * log.Logger
31
35
dev string
32
36
wipe bool
33
- parts []Partition
37
+ parts []device_managers. Partition
34
38
deletions []int
35
39
infos []int
36
40
}
37
41
38
- // We ignore types.Partition.StartMiB/SizeMiB in favor of
39
- // StartSector/SizeInSectors. The caller is expected to do the conversion.
40
- type Partition struct {
41
- types.Partition
42
- StartSector * int64
43
- SizeInSectors * int64
44
-
45
- // shadow StartMiB/SizeMiB so they're not accidentally used
46
- StartMiB string
47
- SizeMiB string
48
- }
49
-
50
42
// Begin begins an sfdisk operation
51
43
func Begin (logger * log.Logger , dev string ) * Operation {
52
44
return & Operation {logger : logger , dev : dev }
53
45
}
54
46
55
- // CreatePartition adds the supplied partition to the list of partitions to be created as part of an operation.
56
- func (op * Operation ) CreatePartition (p Partition ) {
47
+ // CreatePartition adds the supplied partition to the list of partitions to be created as part of an operation
48
+ func (op * Operation ) CreatePartition (p device_managers. Partition ) {
57
49
op .parts = append (op .parts , p )
58
50
}
59
51
@@ -81,7 +73,7 @@ func (op *Operation) Pretend() (string, error) {
81
73
return "" , err
82
74
}
83
75
84
- script := op .sfdiskBuildOptions ()
76
+ script := op .buildOptions ()
85
77
cmd := exec .Command ("sh" , "-c" , fmt .Sprintf ("echo -e \" %s\" | sudo %s --no-act %s" , script , distro .SfdiskCmd (), op .dev ))
86
78
stdout , err := cmd .StdoutPipe ()
87
79
@@ -114,8 +106,8 @@ func (op *Operation) Pretend() (string, error) {
114
106
}
115
107
116
108
// Commit commits an partitioning operation.
117
- func (op * Operation ) SfdiskCommit () error {
118
- script := op .sfdiskBuildOptions ()
109
+ func (op * Operation ) Commit () error {
110
+ script := op .buildOptions ()
119
111
if len (script ) == 0 {
120
112
return nil
121
113
}
@@ -139,7 +131,60 @@ func (op *Operation) SfdiskCommit() error {
139
131
return nil
140
132
}
141
133
142
- func (op Operation ) sfdiskBuildOptions () string {
134
+ // ParseOutput takes the output from sfdisk. Similarly to sgdisk
135
+ // it then uses regex to parse the output into understood values like 'start' 'size' and attempts
136
+ // to catch any failures and wrap them to return to the caller.
137
+ func (op * Operation ) ParseOutput (sfdiskOutput string , partitionNumbers []int ) (map [int ]device_managers.Output , error ) {
138
+ if len (partitionNumbers ) == 0 {
139
+ return nil , nil
140
+ }
141
+
142
+ // Prepare the data, and a regex for matching on partitions
143
+ partitionRegex := regexp .MustCompile (`^/dev/\S+\s+\S*\s+(\d+)\s+(\d+)\s+\d+\s+\S+\s+\S+\s+\S+.*$` )
144
+ output := map [int ]device_managers.Output {}
145
+ current := device_managers.Output {}
146
+ i := 0
147
+ lines := strings .Split (sfdiskOutput , "\n " )
148
+ for _ , line := range lines {
149
+ matches := partitionRegex .FindStringSubmatch (line )
150
+
151
+ // Sanity check number of partition entries
152
+ if i > len (partitionNumbers ) {
153
+ return nil , sharedErrors .ErrBadSfdiskPretend
154
+ }
155
+
156
+ // Verify that we are not reading a 'failed' or 'error'
157
+ errorRegex := regexp .MustCompile (`(?i)(failed|error)` )
158
+ if errorRegex .MatchString (line ) {
159
+ return nil , fmt .Errorf ("%w: sfdisk returned :%v" , sharedErrors .ErrBadSfdiskPretend , line )
160
+ }
161
+
162
+ // When we get a match it should be
163
+ // Whole line at [0]
164
+ // Start at [1]
165
+ // Size at [2]
166
+ if len (matches ) > 2 {
167
+ start , err := strconv .Atoi (matches [1 ])
168
+ if err != nil {
169
+ return nil , err
170
+ }
171
+ end , err := strconv .Atoi (matches [2 ])
172
+ if err != nil {
173
+ return nil , err
174
+ }
175
+
176
+ current .Start = int64 (start )
177
+ // Add one due to overlap
178
+ current .Size = int64 (end - start + 1 )
179
+ output [partitionNumbers [i ]] = current
180
+ i ++
181
+ }
182
+ }
183
+
184
+ return output , nil
185
+ }
186
+
187
+ func (op Operation ) buildOptions () string {
143
188
var script bytes.Buffer
144
189
145
190
for _ , p := range op .parts {
@@ -202,75 +247,3 @@ func (op *Operation) handleInfo() error {
202
247
}
203
248
return nil
204
249
}
205
-
206
- // Copy old functionality from sgdisk to switch between the two during testing.
207
- // Will be removed.
208
- func (op * Operation ) SgdiskCommit () error {
209
- opts := op .sgdiskBuildOptions ()
210
- if len (opts ) == 0 {
211
- return nil
212
- }
213
- op .logger .Info ("running sgdisk with options: %v" , opts )
214
- cmd := exec .Command (distro .SgdiskCmd (), opts ... )
215
-
216
- if _ , err := op .logger .LogCmd (cmd , "deleting %d partitions and creating %d partitions on %q" , len (op .deletions ), len (op .parts ), op .dev ); err != nil {
217
- return fmt .Errorf ("create partitions failed: %v" , err )
218
- }
219
-
220
- return nil
221
- }
222
-
223
- // Copy old functionality from sgdisk to switch between the two during testing.
224
- // Will be removed.
225
- func (op Operation ) sgdiskBuildOptions () []string {
226
- opts := []string {}
227
-
228
- if op .wipe {
229
- opts = append (opts , "--zap-all" )
230
- }
231
-
232
- // Do all deletions before creations
233
- for _ , partition := range op .deletions {
234
- opts = append (opts , fmt .Sprintf ("--delete=%d" , partition ))
235
- }
236
-
237
- for _ , p := range op .parts {
238
- opts = append (opts , fmt .Sprintf ("--new=%d:%s:+%s" , p .Number , partitionGetStart (p ), partitionGetSize (p )))
239
- if p .Label != nil {
240
- opts = append (opts , fmt .Sprintf ("--change-name=%d:%s" , p .Number , * p .Label ))
241
- }
242
- if util .NotEmpty (p .TypeGUID ) {
243
- opts = append (opts , fmt .Sprintf ("--typecode=%d:%s" , p .Number , * p .TypeGUID ))
244
- }
245
- if util .NotEmpty (p .GUID ) {
246
- opts = append (opts , fmt .Sprintf ("--partition-guid=%d:%s" , p .Number , * p .GUID ))
247
- }
248
- }
249
-
250
- for _ , partition := range op .infos {
251
- opts = append (opts , fmt .Sprintf ("--info=%d" , partition ))
252
- }
253
-
254
- if len (opts ) == 0 {
255
- return nil
256
- }
257
-
258
- opts = append (opts , op .dev )
259
- return opts
260
- }
261
-
262
- // Copy old functionality from sgdisk to switch between the two during testing.
263
- // Will be removed.
264
- func partitionGetStart (p Partition ) string {
265
- if p .StartSector != nil {
266
- return fmt .Sprintf ("%d" , * p .StartSector )
267
- }
268
- return "0"
269
- }
270
-
271
- func partitionGetSize (p Partition ) string {
272
- if p .SizeInSectors != nil {
273
- return fmt .Sprintf ("%d" , * p .SizeInSectors )
274
- }
275
- return "0"
276
- }
0 commit comments