Class: IgnitionDiskGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/vagrant-ignition/action/IgnitionDiskGenerator.rb

Overview

Note: gpt and gpt2 are the primary and secondary headers respectively

Class Method Summary collapse

Class Method Details

.create_disk(ignition_name, config_drive) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/vagrant-ignition/action/IgnitionDiskGenerator.rb', line 13

def self.create_disk(ignition_name, config_drive)
  # Constants
  @first_usable_lba  = 2048
  @gpt_entrysize     = 128
  @gpt_max_entries   = 128
  gpt_lba            = 1
  arr_lba            = 2
  lba_size           = 512
  pmbr_length        = lba_size
  @gpt_length        = lba_size
  arr_length         = @gpt_max_entries * @gpt_entrysize
  minimum_disk_size  = 1536000                                                             # ~1.5M; there are issues with udev not registering the device if it is less than this...
  partitioner_reserved_space = (@first_usable_lba * lba_size) + (@gpt_length + arr_length) # this is space reserved by the partition tables and arrays
  part_label         = "Ignition Config Drive"
  part_label_encoded = part_label.encode("utf-16le").bytes
 
  ignition_conf = File.open(ignition_name, "r")
  contents = ignition_conf.sysread(File.size?(ignition_name))
  ignition_conf.close
  file_size_unrounded = contents.bytesize
  if file_size_unrounded < minimum_disk_size
    file_size = minimum_disk_size - partitioner_reserved_space
  elsif (file_size_unrounded % lba_size) != 0
    file_size = lba_size * ((file_size_unrounded / lba_size) + 1)
  else
    file_size = file_size_unrounded
  end
  drive_size = file_size + partitioner_reserved_space

  # Calculated variables
  drive_sectors    = drive_size / lba_size
  gpt2_lba         = drive_sectors - 1
  arr2_lba         = drive_sectors - 33
  # This is global as gen_gpt requires it
  @last_usable_lba = drive_sectors - 34

  ## START PMBR ##
  pmbr  = ("\0".bytes) * 446         # bootloader code
  pmbr += "\x00".bytes               # status code
  pmbr += "\x00\x01\x00".bytes       # first CHS (for a protective MBR, we can just use the min value)
  pmbr += "\xee".bytes               # partition type
  pmbr += "\xfe\xff\xff".bytes       # last CHS (for a protective MBR, we can just use the max value)
  pmbr += "\x01\x00\x00\x00".bytes   # first LBA of first partition
  pmbr += [gpt2_lba].pack('L').bytes # last LBA of first partition
  pmbr += ("\x00".bytes) * 48        # other partition data
  pmbr += "\x55\xaa".bytes           # MBR signature
  ## END PMBR ##

  ## START PART ##

  # UUID format on disk according to cgpt:
  # typedef struct {
  # UINT32 Data1;
  # UINT16 Data2;
  # UINT16 Data3;
  # UINT8 Data4[8];
  # } EFI_GUID;

  # Partition Type GUID is 0FC63DAF-8483-4772-8E79-3D69D8477DE4 (Linux Filesystem)
  part1  = [0x0FC63DAF].pack('L').bytes + [0x8483].pack('S').bytes + [0x4772].pack('S').bytes + [0x8E793D69D8477DE4].pack('Q').bytes.reverse!
  # Partition GUID is 99570A8A-F826-4EB0-BA4E-9DD72D55EA13
  part1 += [0x99570A8A].pack('L').bytes + [0xF826].pack('S').bytes + [0x4EB0].pack('S').bytes + [0xBA4E9DD72D55EA13].pack('Q').bytes.reverse!
  part1 += [@first_usable_lba].pack('Q').bytes                                                                # first LBA of first partition
  part1 += [@last_usable_lba].pack('Q').bytes                                                                 # last LBA of first partition
  part1 += "\0".bytes * 8                                                                                     # partition attributes
  part1 += part_label_encoded + ("\0".bytes * (72 - part_label_encoded.length))                               # partition name (length of 72 bytes, or 36 utf16le characters)
  part_others = "\0".bytes * (arr_length - part1.length)                                                      # other partition data
  part_arr = part1 + part_others
  part_extra_space = "\0".bytes * ((@first_usable_lba * lba_size) - (pmbr_length + @gpt_length + arr_length)) # this adds a buffer so that our partition starts at sector 2048
  part_full = part_arr + part_extra_space
  ## END PART ##


  ## START GPT ##
  gpt = gen_gpt(gpt_lba, gpt2_lba, arr_lba, part_arr)
  ## END GPT ##

  ## START GPT2 ##
  gpt2 = gen_gpt(gpt2_lba, gpt_lba, arr2_lba, part_arr)
  ## END GPT2 ##

  ## START DATA ##
  if file_size_unrounded < minimum_disk_size
    data = contents.bytes + ("\x00".bytes * (file_size - contents.bytesize))
  else
    data = contents.bytes + ("\x00".bytes * (lba_size - (file_size_unrounded % lba_size)))
  end
  ## END DATA ##

  device = pmbr + gpt + part_full + data + part1 + part_others + gpt2

  File.open(config_drive, 'wb' ) do |output|
    device.each do | byte |
      output.print byte.chr
    end
  end
end