81
82
choices=choices, required=False,
82
83
error_messages={'invalid_choice': invalid_choice_message})
84
def get_boot_disk(self):
85
"""Return the boot disk for the node."""
86
if len(self.block_devices) > 0:
87
return self.block_devices[0]
91
85
def _clean_size(self, field, min_size=None, max_size=None):
92
86
"""Clean a size field."""
93
87
size = self.cleaned_data[field]
96
90
if is_precentage(size):
97
91
# Calculate the precentage not counting the EFI partition.
98
92
size = calculate_size_from_precentage(
99
self.get_boot_disk().size - EFI_PARTITION_SIZE, size)
93
self.boot_disk.size - EFI_PARTITION_SIZE, size)
100
94
if min_size is not None and size < min_size:
101
95
raise ValidationError(
102
96
"Size is too small. Minimum size is %s." % min_size)
108
102
def clean_boot_size(self):
109
103
"""Clean the boot_size field."""
110
boot_disk = self.get_boot_disk()
111
if boot_disk is not None:
104
if self.boot_disk is not None:
112
105
return self._clean_size(
113
106
'boot_size', MIN_BOOT_PARTITION_SIZE, (
114
boot_disk.size - EFI_PARTITION_SIZE -
107
self.boot_disk.size - EFI_PARTITION_SIZE -
115
108
MIN_ROOT_PARTITION_SIZE))
119
112
def clean_root_size(self):
120
113
"""Clean the root_size field."""
121
boot_disk = self.get_boot_disk()
122
if boot_disk is not None:
114
if self.boot_disk is not None:
123
115
return self._clean_size(
124
116
'root_size', MIN_ROOT_PARTITION_SIZE, (
125
boot_disk.size - EFI_PARTITION_SIZE -
117
self.boot_disk.size - EFI_PARTITION_SIZE -
126
118
MIN_BOOT_PARTITION_SIZE))
133
125
if len(self.block_devices) == 0:
134
126
raise StorageLayoutMissingBootDiskError(
135
127
"Node doesn't have any storage devices to configure.")
136
disk_size = self.get_boot_disk().size
128
disk_size = self.boot_disk.size
138
130
EFI_PARTITION_SIZE + self.get_boot_size())
139
131
root_size = self.get_root_size()
179
171
# Circular imports.
180
172
from maasserver.models.filesystem import Filesystem
181
173
from maasserver.models.partitiontable import PartitionTable
182
boot_disk = self.get_boot_disk()
183
174
boot_partition_table = PartitionTable.objects.create(
184
block_device=boot_disk)
185
efi_partition = boot_partition_table.add_partition(
186
size=EFI_PARTITION_SIZE, bootable=True)
187
boot_partition = boot_partition_table.add_partition(
188
size=self.get_boot_size(), bootable=True)
175
block_device=self.boot_disk)
176
if boot_partition_table.table_type == PARTITION_TABLE_TYPE.GPT:
177
efi_partition = boot_partition_table.add_partition(
178
size=EFI_PARTITION_SIZE, bootable=True)
179
Filesystem.objects.create(
180
partition=efi_partition,
181
fstype=FILESYSTEM_TYPE.FAT32,
183
mount_point="/boot/efi")
184
boot_size = self.get_boot_size()
186
boot_partition = boot_partition_table.add_partition(
187
size=self.get_boot_size(), bootable=True)
188
Filesystem.objects.create(
189
partition=boot_partition,
190
fstype=FILESYSTEM_TYPE.EXT4,
189
193
root_device = self.get_root_device()
190
if root_device is None or root_device == boot_disk:
194
if root_device is None or root_device == self.boot_disk:
191
195
root_partition = boot_partition_table.add_partition(
192
196
size=self.get_root_size())
195
199
block_device=root_device)
196
200
root_partition = root_partition_table.add_partition(
197
201
size=self.get_root_size())
198
Filesystem.objects.create(
199
partition=efi_partition,
200
fstype=FILESYSTEM_TYPE.FAT32,
202
mount_point="/boot/efi")
203
Filesystem.objects.create(
204
partition=boot_partition,
205
fstype=FILESYSTEM_TYPE.EXT4,
208
202
return root_partition
210
204
def configure(self, allow_fallback=True):
355
347
def setup_cache_device_field(self):
356
348
"""Setup the possible cache devices."""
357
boot_disk = self.get_boot_disk()
358
if boot_disk is None:
349
if self.boot_disk is None:
361
352
(block_device.id, block_device.id)
362
353
for block_device in self.block_devices
363
if block_device != boot_disk
354
if block_device != self.boot_disk
365
356
invalid_choice_message = compose_invalid_choice_text(
366
357
'cache_device', choices)
371
362
def _find_best_cache_device(self):
372
363
"""Return the best possible cache device on the node."""
373
boot_disk = self.get_boot_disk()
374
if boot_disk is None:
364
if self.boot_disk is None:
376
366
block_devices = self.node.physicalblockdevice_set.exclude(
377
id__in=[boot_disk.id]).order_by('size')
367
id__in=[self.boot_disk.id]).order_by('size')
378
368
for block_device in block_devices:
379
369
if "ssd" in block_device.tags:
380
370
return block_device
465
455
NAME SIZE TYPE FSTYPE MOUNTPOINT
467
sda15 512M part fat32 /boot/efi
468
sda1 1G part ext4 /boot
469
sda2 98.5G part bc-backing
457
sda1 512M part fat32 /boot/efi
458
sda2 99.5G part bc-backing
471
460
sdb1 50G part bc-cache
472
bcache0 98.5G disk ext4 /
461
bcache0 99.5G disk ext4 /
475
464
def __init__(self, node, params={}):
514
class BcacheLVMStorageLayout(LVMStorageLayout, BcacheStorageLayoutBase):
515
"""Bcache+LVM layout.
517
NAME SIZE TYPE FSTYPE MOUNTPOINT
519
sda15 512M part fat32 /boot/efi
520
sda1 1G part ext4 /boot
521
sda2 98.5G part lvm-pv(vgroot)
523
sdb1 50G part bc-cache
525
lvroot 98.5G lvm bc-backing
526
bcache0 98.5G disk ext4 /
529
def __init__(self, node, params={}):
530
super(BcacheLVMStorageLayout, self).__init__(node, params=params)
531
self.setup_cache_device_field()
533
def configure_storage(self, allow_fallback):
534
"""Create the Bcache+LVM configuration."""
536
from maasserver.models.filesystem import Filesystem
537
from maasserver.models.filesystemgroup import (
541
cache_block_device = self.get_cache_device()
542
if cache_block_device is None:
544
# No cache device so just configure using the lvm layout.
545
return super(BcacheLVMStorageLayout, self).configure_storage(
548
raise StorageLayoutError(
549
"Node doesn't have an available cache device to "
552
root_partition = self.create_basic_layout()
553
volume_group = VolumeGroup.objects.create_volume_group(
554
self.get_vg_name(), block_devices=[], partitions=[root_partition])
555
logical_volume = volume_group.create_logical_volume(
556
self.get_lv_name(), self.get_calculated_lv_size(volume_group))
557
cache_device = self.create_cache_device()
559
"backing_device": logical_volume,
560
"cache_mode": self.get_cache_mode(),
562
if cache_device.type == "partition":
563
create_kwargs['cache_partition'] = cache_device
565
create_kwargs['cache_device'] = cache_device
566
bcache = Bcache.objects.create_bcache(**create_kwargs)
567
Filesystem.objects.create(
568
block_device=bcache.virtual_device,
569
fstype=FILESYSTEM_TYPE.EXT4,
575
503
# Holds all the storage layouts that can be used.
576
504
STORAGE_LAYOUTS = {
577
505
"flat": ("Flat layout", FlatStorageLayout),
578
506
"lvm": ("LVM layout", LVMStorageLayout),
579
507
"bcache": ("Bcache layout", BcacheStorageLayout),
580
"bcache+lvm": ("Bcache+LVM layout", BcacheLVMStorageLayout),