Skip to content

Boom

Boom boot manager — creates and manages boot entries, profiles, and host profiles for GRUB2 and systemd-boot. Used for snapshot-based boot environments (boot from LVM snapshots, etc.).

sts.boom.entry

Boom boot entry management.

BoomEntry pydantic-model

Bases: BoomBase

Boom boot entry representation.

Show JSON schema:
{
  "$defs": {
    "BoomConfig": {
      "additionalProperties": false,
      "description": "Boom configuration.",
      "properties": {
        "debug": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Debug"
        },
        "boot_dir": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Boot Dir"
        },
        "verbose": {
          "default": 0,
          "title": "Verbose",
          "type": "integer"
        }
      },
      "title": "BoomConfig",
      "type": "object"
    }
  },
  "description": "Boom boot entry representation.",
  "properties": {
    "config": {
      "$ref": "#/$defs/BoomConfig"
    },
    "boot_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Boot Id"
    },
    "entry_title": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Entry Title"
    },
    "param_version": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Param Version"
    },
    "profile_osid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Osid"
    },
    "entry_kernel": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Entry Kernel"
    },
    "entry_initramfs": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Entry Initramfs"
    },
    "param_rootdev": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Param Rootdev"
    },
    "param_rootlv": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Param Rootlv"
    },
    "entry_options": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Entry Options"
    },
    "entry_machineid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Entry Machineid"
    },
    "param_subvolpath": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Param Subvolpath"
    },
    "param_subvolid": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Param Subvolid"
    },
    "entry_entrypath": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Entry Entrypath"
    },
    "entry_entryfile": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Entry Entryfile"
    },
    "entry_readonly": {
      "default": false,
      "title": "Entry Readonly",
      "type": "boolean"
    }
  },
  "title": "BoomEntry",
  "type": "object"
}

Config:

  • populate_by_name: True
  • extra: ignore

Fields:

  • config (BoomConfig)
  • boot_id (str | None)
  • title (str | None)
  • version (str | None)
  • profile_id (str | None)
  • linux (str | None)
  • initramfs (str | None)
  • root_device (str | None)
  • root_lv (str | None)
  • options (str | None)
  • machine_id (str | None)
  • btrfs_subvol_path (str | None)
  • btrfs_subvol_id (int | None)
  • entry_path (str | None)
  • entry_file (str | None)
  • readonly (bool)
Source code in sts_libs/src/sts/boom/entry.py
 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
class BoomEntry(BoomBase):
    """Boom boot entry representation."""

    model_config = ConfigDict(populate_by_name=True, extra='ignore')

    COMMAND: ClassVar[str] = 'entry'
    JSON_KEY: ClassVar[str] = 'Entries'
    ID_FIELD: ClassVar[str] = 'boot_id'
    RAW_ID_KEY: ClassVar[str] = 'entry_bootid'
    ID_FILTER_FLAG: ClassVar[str] = '--boot-id'
    OPTIONS_FIELDS: ClassVar[str] = '+entry_all,param_all,profile_all'

    boot_id: str | None = None
    title: str | None = Field(default=None, alias='entry_title')
    version: str | None = Field(default=None, alias='param_version')
    profile_id: str | None = Field(default=None, alias='profile_osid')
    linux: str | None = Field(default=None, alias='entry_kernel')
    initramfs: str | None = Field(default=None, alias='entry_initramfs')
    root_device: str | None = Field(default=None, alias='param_rootdev')
    root_lv: str | None = Field(default=None, alias='param_rootlv')
    options: str | None = Field(default=None, alias='entry_options')
    machine_id: str | None = Field(default=None, alias='entry_machineid')
    btrfs_subvol_path: str | None = Field(default=None, alias='param_subvolpath')
    btrfs_subvol_id: int | None = Field(default=None, alias='param_subvolid')
    entry_path: str | None = Field(default=None, alias='entry_entrypath')
    entry_file: str | None = Field(default=None, alias='entry_entryfile')
    readonly: bool = Field(default=False, alias='entry_readonly')

    def refresh_report(self) -> bool:
        """Refresh entry data from the system."""
        if not self._load_data():
            logger.warning('No identifiers available for entry refresh')
            return False
        return True

    @staticmethod
    def _set_kernel_options(
        *,
        options: BoomOptions,
        version: str | None = None,
        linux: str | None = None,
        initramfs: str | None = None,
    ) -> None:
        """Sets kernel-related options in the provided dictionary.

        This helper method was created to comply with Ruff's complexity warning.
        """
        if version:
            options['--version'] = version
        if linux:
            options['--linux'] = linux
        if initramfs:
            options['--initrd'] = initramfs

    @staticmethod
    def _set_boot_options(
        *,
        options: BoomOptions,
        add_opts: str | None = None,
        del_opts: str | None = None,
        backup: bool = False,
        update: bool = False,
        no_fstab: bool = False,
        mount: str | None = None,
        swap: str | None = None,
    ) -> None:
        """Sets general boot options in the provided dictionary.

        This helper method was created to comply with Ruff's complexity warning.
        """
        if add_opts:
            options['--add-opts'] = add_opts
        if del_opts:
            options['--del-opts'] = del_opts
        if backup:
            options['--backup'] = None
        if update:
            options['--update'] = None
        if no_fstab:
            options['--no-fstab'] = None
        if mount:
            options['--mount'] = mount
        if swap:
            options['--swap'] = swap

    @staticmethod
    def _set_device_options(
        *,
        options: BoomOptions,
        root_device: str | None = None,
        root_lv: str | None = None,
    ) -> None:
        """Sets device-related options in the provided dictionary.

        This helper method was created to comply with Ruff's complexity warning.
        """
        if root_device:
            options['--root-device'] = root_device
        if root_lv:
            options['--root-lv'] = root_lv

    @staticmethod
    def _resolve_uuid_device(root_device: str | None) -> str | None:
        """Resolve a ``UUID=`` device specification to a device path via blkid.

        Boom clone's ``--root-device`` does not accept ``UUID=`` format, so
        entries using it must be resolved first.
        """
        if not root_device or not root_device.startswith('UUID='):
            return root_device

        uuid = root_device.split('=', 1)[1]
        result = run(f'blkid -U {uuid}')
        if result.succeeded and result.stdout.strip():
            resolved = result.stdout.strip()
            logger.debug(f'Resolved UUID {uuid} to device path: {resolved}')
            return resolved
        logger.warning(f'Failed to resolve UUID to device path: {root_device}')
        return None

    def create(
        self,
        *,
        title: str | None = None,
        version: str | None = None,
        profile_id: str | None = None,
        root_device: str | None = None,
        root_lv: str | None = None,
        linux: str | None = None,
        initramfs: str | None = None,
        btrfs_subvol: str | None = None,
        add_opts: str | None = None,
        del_opts: str | None = None,
        mount: str | None = None,
        swap: str | None = None,
        backup: bool = False,
        update: bool = False,
        no_fstab: bool = False,
    ) -> CommandResult:
        """Create boot entry.

        ``mount`` format: ``what:where:fstype:options``.
        ``swap`` format: ``what:options``.

        Example:
            ```python
            entry.create(title='System Snapshot', root_lv='vg00/lvol0-snap', backup=True).assert_ok()
            ```
        """
        options: BoomOptions = {}

        # Set required title
        if not title and not self.title:
            logger.error('Title is required for creating a boot entry')
            return CommandResult(
                command='boom entry create', rc=1, stderr='Title is required for creating a boot entry'
            )

        options['--title'] = title or self.title
        if profile_id or self.profile_id:
            options['--profile'] = profile_id or self.profile_id

        self._set_kernel_options(options=options, version=version, linux=linux, initramfs=initramfs)
        self._set_device_options(options=options, root_device=root_device, root_lv=root_lv)
        self._set_boot_options(
            options=options,
            add_opts=add_opts,
            del_opts=del_opts,
            backup=backup,
            update=update,
            no_fstab=no_fstab,
            mount=mount,
            swap=swap,
        )

        # Handle BTRFS subvolume
        subvol_to_use = None
        if btrfs_subvol:
            subvol_to_use = btrfs_subvol
        elif self.btrfs_subvol_path:
            subvol_to_use = self.btrfs_subvol_path
        elif self.btrfs_subvol_id is not None and self.btrfs_subvol_id >= 0:
            subvol_to_use = str(self.btrfs_subvol_id)

        if subvol_to_use:
            options['--btrfs-subvol'] = subvol_to_use

        result = self.run_command(
            command=self.COMMAND,
            subcommand='create',
            options=options,
        )

        if result.succeeded:
            # Extract new boot_id from output
            for line in result.stdout.splitlines():
                m = re.search(r'boot_id\s+(\w+)', line)
                if m:
                    self.boot_id = m.group(1)
                    self._load_data()
                    break
            else:
                logger.warning('Could not parse boot_id from create output')
        return result

    def delete(self) -> CommandResult:
        """Delete boot entry."""
        if not self.boot_id:
            logger.error('Boot ID required for deletion')
            return CommandResult(command='boom entry delete', rc=1, stderr='Boot ID required for deletion')

        options: BoomOptions = {'--boot-id': self.boot_id}

        return self.run_command(command=self.COMMAND, subcommand='delete', options=options)

    def clone(
        self,
        *,
        title: str | None = None,
        version: str | None = None,
        profile_id: str | None = None,
        root_device: str | None = None,
        root_lv: str | None = None,
        linux: str | None = None,
        initramfs: str | None = None,
        btrfs_subvol: str | None = None,
        add_opts: str | None = None,
        del_opts: str | None = None,
        mount: str | None = None,
        swap: str | None = None,
        backup: bool = False,
        update: bool = False,
        no_fstab: bool = False,
    ) -> BoomEntry | None:
        """Clone this boot entry with optional overrides.

        ``mount`` format: ``what:where:fstype:options``.
        ``swap`` format: ``what:options``.

        Example:
            ```python
            new_entry = entry.clone(title='System Snapshot 2', root_lv='vg00/lvol0-snap2')
            ```
        """
        if not self.boot_id:
            logger.error('Original boot entry ID required for cloning')
            return None

        options: BoomOptions = {
            '--boot-id': self.boot_id,
        }

        if title:
            options['--title'] = title
        if profile_id:
            options['--profile'] = profile_id
        if btrfs_subvol:
            options['--btrfs-subvol'] = btrfs_subvol

        # If no explicit root_device provided, check if the entry's root device
        # uses UUID= format and resolve it to a device path. Boom clone does not
        # accept UUID= format for --root-device.
        if not root_device and self.root_device and self.root_device.startswith('UUID='):
            root_device = self._resolve_uuid_device(self.root_device)
            if not root_device:
                logger.error(f'Cannot clone: failed to resolve UUID root device {self.root_device}')
                return None

        self._set_kernel_options(options=options, version=version, linux=linux, initramfs=initramfs)
        self._set_device_options(options=options, root_device=root_device, root_lv=root_lv)
        self._set_boot_options(
            options=options,
            add_opts=add_opts,
            del_opts=del_opts,
            backup=backup,
            update=update,
            no_fstab=no_fstab,
            mount=mount,
            swap=swap,
        )

        result = self.run_command(
            command=self.COMMAND,
            subcommand='clone',
            options=options,
        )

        if not result.succeeded:
            return None

        # Extract new boot_id from output
        for line in result.stdout.splitlines():
            # Parse output like "Created entry with boot_id abc123:"
            m = re.search(r'boot_id\s+\w+\s+as\s+boot_id\s+(\w+)', line)
            if m:
                # Only the first 7 characters of os_id_full are used as ID
                entry = BoomEntry(boot_id=m.group(1))
                entry.refresh_report()
                return entry
        logger.warning('Could not parse boot_id from clone output')
        return None

    def show(self) -> CommandResult:
        """Show boot entry configuration."""
        options: BoomOptions = {}
        if self.boot_id:
            options = {'--boot-id': self.boot_id}

        return self.run_command(command=self.COMMAND, subcommand='show', options=options)

    def list_items(
        self,
        boot_id: str | None = None,
        profile_id: str | None = None,
        version: str | None = None,
        title: str | None = None,
        root_device: str | None = None,
        root_lv: str | None = None,
        options: BoomOptions | None = None,
    ) -> CommandResult:
        """List boot entries matching the given filter criteria."""
        # Build filter options
        if not options:
            options = {}

        if boot_id:
            options['--boot-id'] = boot_id
        if profile_id:
            options['--profile'] = profile_id
        if version:
            options['--version'] = version
        if title:
            options['--title'] = title
        if root_device:
            options['--root-device'] = root_device
        if root_lv:
            options['--root-lv'] = root_lv

        return self.run_command(command=self.COMMAND, subcommand='list', options=options)

clone(*, title=None, version=None, profile_id=None, root_device=None, root_lv=None, linux=None, initramfs=None, btrfs_subvol=None, add_opts=None, del_opts=None, mount=None, swap=None, backup=False, update=False, no_fstab=False)

Clone this boot entry with optional overrides.

mount format: what:where:fstype:options. swap format: what:options.

Example
new_entry = entry.clone(title='System Snapshot 2', root_lv='vg00/lvol0-snap2')
Source code in sts_libs/src/sts/boom/entry.py
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
def clone(
    self,
    *,
    title: str | None = None,
    version: str | None = None,
    profile_id: str | None = None,
    root_device: str | None = None,
    root_lv: str | None = None,
    linux: str | None = None,
    initramfs: str | None = None,
    btrfs_subvol: str | None = None,
    add_opts: str | None = None,
    del_opts: str | None = None,
    mount: str | None = None,
    swap: str | None = None,
    backup: bool = False,
    update: bool = False,
    no_fstab: bool = False,
) -> BoomEntry | None:
    """Clone this boot entry with optional overrides.

    ``mount`` format: ``what:where:fstype:options``.
    ``swap`` format: ``what:options``.

    Example:
        ```python
        new_entry = entry.clone(title='System Snapshot 2', root_lv='vg00/lvol0-snap2')
        ```
    """
    if not self.boot_id:
        logger.error('Original boot entry ID required for cloning')
        return None

    options: BoomOptions = {
        '--boot-id': self.boot_id,
    }

    if title:
        options['--title'] = title
    if profile_id:
        options['--profile'] = profile_id
    if btrfs_subvol:
        options['--btrfs-subvol'] = btrfs_subvol

    # If no explicit root_device provided, check if the entry's root device
    # uses UUID= format and resolve it to a device path. Boom clone does not
    # accept UUID= format for --root-device.
    if not root_device and self.root_device and self.root_device.startswith('UUID='):
        root_device = self._resolve_uuid_device(self.root_device)
        if not root_device:
            logger.error(f'Cannot clone: failed to resolve UUID root device {self.root_device}')
            return None

    self._set_kernel_options(options=options, version=version, linux=linux, initramfs=initramfs)
    self._set_device_options(options=options, root_device=root_device, root_lv=root_lv)
    self._set_boot_options(
        options=options,
        add_opts=add_opts,
        del_opts=del_opts,
        backup=backup,
        update=update,
        no_fstab=no_fstab,
        mount=mount,
        swap=swap,
    )

    result = self.run_command(
        command=self.COMMAND,
        subcommand='clone',
        options=options,
    )

    if not result.succeeded:
        return None

    # Extract new boot_id from output
    for line in result.stdout.splitlines():
        # Parse output like "Created entry with boot_id abc123:"
        m = re.search(r'boot_id\s+\w+\s+as\s+boot_id\s+(\w+)', line)
        if m:
            # Only the first 7 characters of os_id_full are used as ID
            entry = BoomEntry(boot_id=m.group(1))
            entry.refresh_report()
            return entry
    logger.warning('Could not parse boot_id from clone output')
    return None

create(*, title=None, version=None, profile_id=None, root_device=None, root_lv=None, linux=None, initramfs=None, btrfs_subvol=None, add_opts=None, del_opts=None, mount=None, swap=None, backup=False, update=False, no_fstab=False)

Create boot entry.

mount format: what:where:fstype:options. swap format: what:options.

Example
entry.create(title='System Snapshot', root_lv='vg00/lvol0-snap', backup=True).assert_ok()
Source code in sts_libs/src/sts/boom/entry.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
def create(
    self,
    *,
    title: str | None = None,
    version: str | None = None,
    profile_id: str | None = None,
    root_device: str | None = None,
    root_lv: str | None = None,
    linux: str | None = None,
    initramfs: str | None = None,
    btrfs_subvol: str | None = None,
    add_opts: str | None = None,
    del_opts: str | None = None,
    mount: str | None = None,
    swap: str | None = None,
    backup: bool = False,
    update: bool = False,
    no_fstab: bool = False,
) -> CommandResult:
    """Create boot entry.

    ``mount`` format: ``what:where:fstype:options``.
    ``swap`` format: ``what:options``.

    Example:
        ```python
        entry.create(title='System Snapshot', root_lv='vg00/lvol0-snap', backup=True).assert_ok()
        ```
    """
    options: BoomOptions = {}

    # Set required title
    if not title and not self.title:
        logger.error('Title is required for creating a boot entry')
        return CommandResult(
            command='boom entry create', rc=1, stderr='Title is required for creating a boot entry'
        )

    options['--title'] = title or self.title
    if profile_id or self.profile_id:
        options['--profile'] = profile_id or self.profile_id

    self._set_kernel_options(options=options, version=version, linux=linux, initramfs=initramfs)
    self._set_device_options(options=options, root_device=root_device, root_lv=root_lv)
    self._set_boot_options(
        options=options,
        add_opts=add_opts,
        del_opts=del_opts,
        backup=backup,
        update=update,
        no_fstab=no_fstab,
        mount=mount,
        swap=swap,
    )

    # Handle BTRFS subvolume
    subvol_to_use = None
    if btrfs_subvol:
        subvol_to_use = btrfs_subvol
    elif self.btrfs_subvol_path:
        subvol_to_use = self.btrfs_subvol_path
    elif self.btrfs_subvol_id is not None and self.btrfs_subvol_id >= 0:
        subvol_to_use = str(self.btrfs_subvol_id)

    if subvol_to_use:
        options['--btrfs-subvol'] = subvol_to_use

    result = self.run_command(
        command=self.COMMAND,
        subcommand='create',
        options=options,
    )

    if result.succeeded:
        # Extract new boot_id from output
        for line in result.stdout.splitlines():
            m = re.search(r'boot_id\s+(\w+)', line)
            if m:
                self.boot_id = m.group(1)
                self._load_data()
                break
        else:
            logger.warning('Could not parse boot_id from create output')
    return result

delete()

Delete boot entry.

Source code in sts_libs/src/sts/boom/entry.py
228
229
230
231
232
233
234
235
236
def delete(self) -> CommandResult:
    """Delete boot entry."""
    if not self.boot_id:
        logger.error('Boot ID required for deletion')
        return CommandResult(command='boom entry delete', rc=1, stderr='Boot ID required for deletion')

    options: BoomOptions = {'--boot-id': self.boot_id}

    return self.run_command(command=self.COMMAND, subcommand='delete', options=options)

list_items(boot_id=None, profile_id=None, version=None, title=None, root_device=None, root_lv=None, options=None)

List boot entries matching the given filter criteria.

Source code in sts_libs/src/sts/boom/entry.py
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
def list_items(
    self,
    boot_id: str | None = None,
    profile_id: str | None = None,
    version: str | None = None,
    title: str | None = None,
    root_device: str | None = None,
    root_lv: str | None = None,
    options: BoomOptions | None = None,
) -> CommandResult:
    """List boot entries matching the given filter criteria."""
    # Build filter options
    if not options:
        options = {}

    if boot_id:
        options['--boot-id'] = boot_id
    if profile_id:
        options['--profile'] = profile_id
    if version:
        options['--version'] = version
    if title:
        options['--title'] = title
    if root_device:
        options['--root-device'] = root_device
    if root_lv:
        options['--root-lv'] = root_lv

    return self.run_command(command=self.COMMAND, subcommand='list', options=options)

refresh_report()

Refresh entry data from the system.

Source code in sts_libs/src/sts/boom/entry.py
51
52
53
54
55
56
def refresh_report(self) -> bool:
    """Refresh entry data from the system."""
    if not self._load_data():
        logger.warning('No identifiers available for entry refresh')
        return False
    return True

show()

Show boot entry configuration.

Source code in sts_libs/src/sts/boom/entry.py
325
326
327
328
329
330
331
def show(self) -> CommandResult:
    """Show boot entry configuration."""
    options: BoomOptions = {}
    if self.boot_id:
        options = {'--boot-id': self.boot_id}

    return self.run_command(command=self.COMMAND, subcommand='show', options=options)

sts.boom.profile

Boom OS profile management.

BoomProfile pydantic-model

Bases: BoomBase

Boom OS profile representation.

Show JSON schema:
{
  "$defs": {
    "BoomConfig": {
      "additionalProperties": false,
      "description": "Boom configuration.",
      "properties": {
        "debug": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Debug"
        },
        "boot_dir": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Boot Dir"
        },
        "verbose": {
          "default": 0,
          "title": "Verbose",
          "type": "integer"
        }
      },
      "title": "BoomConfig",
      "type": "object"
    }
  },
  "description": "Boom OS profile representation.",
  "properties": {
    "config": {
      "$ref": "#/$defs/BoomConfig"
    },
    "os_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Os Id"
    },
    "profile_osname": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Osname"
    },
    "profile_osshortname": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Osshortname"
    },
    "profile_osversion": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Osversion"
    },
    "profile_osversion_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Osversion Id"
    },
    "profile_unamepattern": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Unamepattern"
    },
    "profile_kernelpattern": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Kernelpattern"
    },
    "profile_initrdpattern": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Initrdpattern"
    },
    "profile_lvm2opts": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Lvm2Opts"
    },
    "profile_btrfsopts": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Btrfsopts"
    },
    "profile_options": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Options"
    },
    "profile_profilepath": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Profile Profilepath"
    }
  },
  "title": "BoomProfile",
  "type": "object"
}

Config:

  • populate_by_name: True
  • extra: ignore

Fields:

  • config (BoomConfig)
  • os_id (str | None)
  • name (str | None)
  • short_name (str | None)
  • version (str | None)
  • version_id (str | None)
  • uname_pattern (str | None)
  • kernel_pattern (str | None)
  • initrd_pattern (str | None)
  • lvm_opts (str | None)
  • btrfs_opts (str | None)
  • options (str | None)
  • profile_path (str | None)
Source code in sts_libs/src/sts/boom/profile.py
 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
class BoomProfile(BoomBase):
    """Boom OS profile representation."""

    model_config = ConfigDict(populate_by_name=True, extra='ignore')

    COMMAND: ClassVar[str] = 'profile'
    JSON_KEY: ClassVar[str] = 'OsProfiles'
    ID_FIELD: ClassVar[str] = 'os_id'
    RAW_ID_KEY: ClassVar[str] = 'profile_osid'
    ID_FILTER_FLAG: ClassVar[str] = '--profile'
    OPTIONS_FIELDS: ClassVar[str] = '+profile_all'

    os_id: str | None = None
    name: str | None = Field(default=None, alias='profile_osname')
    short_name: str | None = Field(default=None, alias='profile_osshortname')
    version: str | None = Field(default=None, alias='profile_osversion')
    version_id: str | None = Field(default=None, alias='profile_osversion_id')
    uname_pattern: str | None = Field(default=None, alias='profile_unamepattern')
    kernel_pattern: str | None = Field(default=None, alias='profile_kernelpattern')
    initrd_pattern: str | None = Field(default=None, alias='profile_initrdpattern')
    lvm_opts: str | None = Field(default=None, alias='profile_lvm2opts')
    btrfs_opts: str | None = Field(default=None, alias='profile_btrfsopts')
    options: str | None = Field(default=None, alias='profile_options')
    profile_path: str | None = Field(default=None, alias='profile_profilepath')

    def refresh_report(self) -> bool:
        """Refresh profile data from the system."""
        if self._load_data():
            return True
        logger.warning('There was a problem loading profile data!')
        return False

    @staticmethod
    def _set_options(
        *,
        options_dict: BoomOptions,
        version: str | None = None,
        version_id: str | None = None,
        uname_pattern: str | None = None,
        kernel_pattern: str | None = None,
        initrd_pattern: str | None = None,
        lvm_opts: str | None = None,
        btrfs_opts: str | None = None,
        from_host: bool = False,
        os_release: str | None = None,
    ) -> None:
        """Helper function to set command options."""
        if version:
            options_dict['--os-version'] = version
        if version_id:
            options_dict['--os-version-id'] = version_id
        if uname_pattern:
            options_dict['--uname-pattern'] = uname_pattern
        if kernel_pattern:
            options_dict['--kernel-pattern'] = kernel_pattern
        if initrd_pattern:
            options_dict['--initramfs-pattern'] = initrd_pattern
        if lvm_opts:
            options_dict['--lvm-opts'] = lvm_opts
        if btrfs_opts:
            options_dict['--btrfs-opts'] = btrfs_opts
        if from_host:
            options_dict['--from-host'] = None
        if os_release:
            options_dict['--os-release'] = os_release

    def create(
        self,
        *,
        name: str | None = None,
        short_name: str | None = None,
        version: str | None = None,
        version_id: str | None = None,
        uname_pattern: str | None = None,
        from_host: bool = False,
        os_release: str | None = None,
        kernel_pattern: str | None = None,
        initrd_pattern: str | None = None,
        lvm_opts: str | None = None,
        btrfs_opts: str | None = None,
        options: str | None = None,
    ) -> CommandResult:
        """Create OS profile.

        ``uname_pattern`` is required unless ``from_host`` is set, in which case
        OS identity is derived from the running host. ``os_release`` overrides
        the default ``/etc/os-release`` path.

        Example:
            ```python
            profile.create(
                name='Fedora',
                short_name='fedora',
                version='36',
                version_id='36',
                uname_pattern='fc36',
            ).assert_ok()
            ```
        """
        options_dict: BoomOptions = {}

        # Set parameters
        if name:
            options_dict['--name'] = name
        if short_name:
            options_dict['--short-name'] = short_name
        if options:
            options_dict['--os-options'] = options

        self._set_options(
            options_dict=options_dict,
            version=version,
            version_id=version_id,
            uname_pattern=uname_pattern,
            from_host=from_host,
            os_release=os_release,
            kernel_pattern=kernel_pattern,
            initrd_pattern=initrd_pattern,
            lvm_opts=lvm_opts,
            btrfs_opts=btrfs_opts,
        )

        result = self.run_command(
            command=self.COMMAND,
            subcommand='create',
            options=options_dict,
        )

        if result.succeeded:
            # Extract os_id from output
            for line in result.stdout.splitlines():
                if match := re.match(r'\s*OS ID:\s*"([^"]+)"', line):
                    # Only the first 7 characters of os_id_full are used as ID
                    self.os_id = match.group(1)[:7]
                    if not self._load_data():
                        logger.warning('Could not load profile data after create')
                    break
            else:
                logger.warning('Could not parse os_id from create output')
        return result

    def delete(self) -> CommandResult:
        """Delete OS profile."""
        if not self.os_id:
            logger.error('OS ID required for deletion')
            return CommandResult(command='boom profile delete', rc=1, stderr='OS ID required for deletion')

        options: BoomOptions = {'--profile': self.os_id}

        return self.run_command(command=self.COMMAND, subcommand='delete', options=options)

    def clone(
        self,
        name: str | None = None,
        short_name: str | None = None,
        version: str | None = None,
        version_id: str | None = None,
        uname_pattern: str | None = None,
        kernel_pattern: str | None = None,
        initrd_pattern: str | None = None,
        lvm_opts: str | None = None,
        btrfs_opts: str | None = None,
        options: str | None = None,
    ) -> BoomProfile | None:
        """Clone this OS profile with optional overrides.

        Example:
            ```python
            new_profile = profile.clone(version='37', version_id='37', uname_pattern='fc37')
            ```
        """
        if not self.os_id:
            logger.error('Original OS profile ID required for cloning')
            return None

        options_dict: BoomOptions = {
            '--profile': self.os_id,
        }

        # Set optional parameters
        if name:
            options_dict['--name'] = name
        if short_name:
            options_dict['--short-name'] = short_name
        if options:
            options_dict['--os-options'] = options

        self._set_options(
            options_dict=options_dict,
            version=version,
            version_id=version_id,
            uname_pattern=uname_pattern,
            kernel_pattern=kernel_pattern,
            initrd_pattern=initrd_pattern,
            lvm_opts=lvm_opts,
            btrfs_opts=btrfs_opts,
        )

        result = self.run_command(
            command=self.COMMAND,
            subcommand='clone',
            options=options_dict,
        )

        if not result.succeeded:
            return None
        # Extract new os_id from output
        for line in result.stdout.splitlines():
            if match := re.match(r'\s*OS ID:\s*"([^"]+)"', line):
                # Only the first 7 characters of os_id_full are used as ID
                profile = BoomProfile(os_id=match.group(1)[:7])
                profile.refresh_report()
                return profile

        logger.warning('Could not parse os_id from clone output')
        return None

    def show(self) -> CommandResult:
        """Show OS profile configuration."""
        options: BoomOptions = {}
        if self.os_id:
            options = {'--profile': self.os_id}

        return self.run_command(command=self.COMMAND, subcommand='show', options=options)

    def list_items(
        self,
        os_id: str | None = None,
        name: str | None = None,
        short_name: str | None = None,
        version: str | None = None,
        version_id: str | None = None,
        options: BoomOptions | None = None,
    ) -> CommandResult:
        """List OS profiles matching the given filter criteria."""
        # Build filter options
        if not options:
            options = {}

        if os_id:
            options['--profile'] = os_id
        if name:
            options['--name'] = name
        if short_name:
            options['--short-name'] = short_name
        if version:
            options['--os-version'] = version
        if version_id:
            options['--os-version-id'] = version_id

        return self.run_command(command=self.COMMAND, subcommand='list', options=options)

clone(name=None, short_name=None, version=None, version_id=None, uname_pattern=None, kernel_pattern=None, initrd_pattern=None, lvm_opts=None, btrfs_opts=None, options=None)

Clone this OS profile with optional overrides.

Example
new_profile = profile.clone(version='37', version_id='37', uname_pattern='fc37')
Source code in sts_libs/src/sts/boom/profile.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
def clone(
    self,
    name: str | None = None,
    short_name: str | None = None,
    version: str | None = None,
    version_id: str | None = None,
    uname_pattern: str | None = None,
    kernel_pattern: str | None = None,
    initrd_pattern: str | None = None,
    lvm_opts: str | None = None,
    btrfs_opts: str | None = None,
    options: str | None = None,
) -> BoomProfile | None:
    """Clone this OS profile with optional overrides.

    Example:
        ```python
        new_profile = profile.clone(version='37', version_id='37', uname_pattern='fc37')
        ```
    """
    if not self.os_id:
        logger.error('Original OS profile ID required for cloning')
        return None

    options_dict: BoomOptions = {
        '--profile': self.os_id,
    }

    # Set optional parameters
    if name:
        options_dict['--name'] = name
    if short_name:
        options_dict['--short-name'] = short_name
    if options:
        options_dict['--os-options'] = options

    self._set_options(
        options_dict=options_dict,
        version=version,
        version_id=version_id,
        uname_pattern=uname_pattern,
        kernel_pattern=kernel_pattern,
        initrd_pattern=initrd_pattern,
        lvm_opts=lvm_opts,
        btrfs_opts=btrfs_opts,
    )

    result = self.run_command(
        command=self.COMMAND,
        subcommand='clone',
        options=options_dict,
    )

    if not result.succeeded:
        return None
    # Extract new os_id from output
    for line in result.stdout.splitlines():
        if match := re.match(r'\s*OS ID:\s*"([^"]+)"', line):
            # Only the first 7 characters of os_id_full are used as ID
            profile = BoomProfile(os_id=match.group(1)[:7])
            profile.refresh_report()
            return profile

    logger.warning('Could not parse os_id from clone output')
    return None

create(*, name=None, short_name=None, version=None, version_id=None, uname_pattern=None, from_host=False, os_release=None, kernel_pattern=None, initrd_pattern=None, lvm_opts=None, btrfs_opts=None, options=None)

Create OS profile.

uname_pattern is required unless from_host is set, in which case OS identity is derived from the running host. os_release overrides the default /etc/os-release path.

Example
profile.create(
    name='Fedora',
    short_name='fedora',
    version='36',
    version_id='36',
    uname_pattern='fc36',
).assert_ok()
Source code in sts_libs/src/sts/boom/profile.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
def create(
    self,
    *,
    name: str | None = None,
    short_name: str | None = None,
    version: str | None = None,
    version_id: str | None = None,
    uname_pattern: str | None = None,
    from_host: bool = False,
    os_release: str | None = None,
    kernel_pattern: str | None = None,
    initrd_pattern: str | None = None,
    lvm_opts: str | None = None,
    btrfs_opts: str | None = None,
    options: str | None = None,
) -> CommandResult:
    """Create OS profile.

    ``uname_pattern`` is required unless ``from_host`` is set, in which case
    OS identity is derived from the running host. ``os_release`` overrides
    the default ``/etc/os-release`` path.

    Example:
        ```python
        profile.create(
            name='Fedora',
            short_name='fedora',
            version='36',
            version_id='36',
            uname_pattern='fc36',
        ).assert_ok()
        ```
    """
    options_dict: BoomOptions = {}

    # Set parameters
    if name:
        options_dict['--name'] = name
    if short_name:
        options_dict['--short-name'] = short_name
    if options:
        options_dict['--os-options'] = options

    self._set_options(
        options_dict=options_dict,
        version=version,
        version_id=version_id,
        uname_pattern=uname_pattern,
        from_host=from_host,
        os_release=os_release,
        kernel_pattern=kernel_pattern,
        initrd_pattern=initrd_pattern,
        lvm_opts=lvm_opts,
        btrfs_opts=btrfs_opts,
    )

    result = self.run_command(
        command=self.COMMAND,
        subcommand='create',
        options=options_dict,
    )

    if result.succeeded:
        # Extract os_id from output
        for line in result.stdout.splitlines():
            if match := re.match(r'\s*OS ID:\s*"([^"]+)"', line):
                # Only the first 7 characters of os_id_full are used as ID
                self.os_id = match.group(1)[:7]
                if not self._load_data():
                    logger.warning('Could not load profile data after create')
                break
        else:
            logger.warning('Could not parse os_id from create output')
    return result

delete()

Delete OS profile.

Source code in sts_libs/src/sts/boom/profile.py
164
165
166
167
168
169
170
171
172
def delete(self) -> CommandResult:
    """Delete OS profile."""
    if not self.os_id:
        logger.error('OS ID required for deletion')
        return CommandResult(command='boom profile delete', rc=1, stderr='OS ID required for deletion')

    options: BoomOptions = {'--profile': self.os_id}

    return self.run_command(command=self.COMMAND, subcommand='delete', options=options)

list_items(os_id=None, name=None, short_name=None, version=None, version_id=None, options=None)

List OS profiles matching the given filter criteria.

Source code in sts_libs/src/sts/boom/profile.py
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
def list_items(
    self,
    os_id: str | None = None,
    name: str | None = None,
    short_name: str | None = None,
    version: str | None = None,
    version_id: str | None = None,
    options: BoomOptions | None = None,
) -> CommandResult:
    """List OS profiles matching the given filter criteria."""
    # Build filter options
    if not options:
        options = {}

    if os_id:
        options['--profile'] = os_id
    if name:
        options['--name'] = name
    if short_name:
        options['--short-name'] = short_name
    if version:
        options['--os-version'] = version
    if version_id:
        options['--os-version-id'] = version_id

    return self.run_command(command=self.COMMAND, subcommand='list', options=options)

refresh_report()

Refresh profile data from the system.

Source code in sts_libs/src/sts/boom/profile.py
48
49
50
51
52
53
def refresh_report(self) -> bool:
    """Refresh profile data from the system."""
    if self._load_data():
        return True
    logger.warning('There was a problem loading profile data!')
    return False

show()

Show OS profile configuration.

Source code in sts_libs/src/sts/boom/profile.py
240
241
242
243
244
245
246
def show(self) -> CommandResult:
    """Show OS profile configuration."""
    options: BoomOptions = {}
    if self.os_id:
        options = {'--profile': self.os_id}

    return self.run_command(command=self.COMMAND, subcommand='show', options=options)

sts.boom.host

Boom host profile management.

BoomHost pydantic-model

Bases: BoomBase

Boom host profile representation.

Show JSON schema:
{
  "$defs": {
    "BoomConfig": {
      "additionalProperties": false,
      "description": "Boom configuration.",
      "properties": {
        "debug": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Debug"
        },
        "boot_dir": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Boot Dir"
        },
        "verbose": {
          "default": 0,
          "title": "Verbose",
          "type": "integer"
        }
      },
      "title": "BoomConfig",
      "type": "object"
    }
  },
  "description": "Boom host profile representation.",
  "properties": {
    "config": {
      "$ref": "#/$defs/BoomConfig"
    },
    "host_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Id"
    },
    "host_hostname": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Hostname"
    },
    "short_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Short Name"
    },
    "host_osid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Osid"
    },
    "host_machineid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Machineid"
    },
    "host_kernelpattern": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Kernelpattern"
    },
    "host_initrdpattern": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Initrdpattern"
    },
    "host_lvm2opts": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Lvm2Opts"
    },
    "host_btrfsopts": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Btrfsopts"
    },
    "host_options": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Options"
    },
    "host_hostprofilepath": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Hostprofilepath"
    },
    "host_label": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Host Label"
    }
  },
  "title": "BoomHost",
  "type": "object"
}

Config:

  • populate_by_name: True
  • extra: ignore

Fields:

  • config (BoomConfig)
  • host_id (str | None)
  • name (str | None)
  • short_name (str | None)
  • profile_id (str | None)
  • machine_id (str | None)
  • kernel_pattern (str | None)
  • initramfs_pattern (str | None)
  • lvm_opts (str | None)
  • btrfs_opts (str | None)
  • options (str | None)
  • host_profile_path (str | None)
  • host_label (str | None)
Source code in sts_libs/src/sts/boom/host.py
 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
class BoomHost(BoomBase):
    """Boom host profile representation."""

    model_config = ConfigDict(populate_by_name=True, extra='ignore')

    COMMAND: ClassVar[str] = 'host'
    JSON_KEY: ClassVar[str] = 'HostProfiles'
    ID_FIELD: ClassVar[str] = 'host_id'
    RAW_ID_KEY: ClassVar[str] = 'host_hostid'
    ID_FILTER_FLAG: ClassVar[str] = '--host-profile'
    OPTIONS_FIELDS: ClassVar[str] = '+host_all'

    host_id: str | None = None
    name: str | None = Field(default=None, alias='host_hostname')
    short_name: str | None = None
    profile_id: str | None = Field(default=None, alias='host_osid')
    machine_id: str | None = Field(default=None, alias='host_machineid')
    kernel_pattern: str | None = Field(default=None, alias='host_kernelpattern')
    initramfs_pattern: str | None = Field(default=None, alias='host_initrdpattern')
    lvm_opts: str | None = Field(default=None, alias='host_lvm2opts')
    btrfs_opts: str | None = Field(default=None, alias='host_btrfsopts')
    options: str | None = Field(default=None, alias='host_options')
    host_profile_path: str | None = Field(default=None, alias='host_hostprofilepath')
    host_label: str | None = Field(default=None, alias='host_label')

    def refresh_report(self) -> bool:
        """Refresh host profile data from the system."""
        if self._load_data():
            return True
        logger.warning('No identifiers available for host profile refresh')
        return False

    @staticmethod
    def _set_options(
        options_dict: BoomOptions,
        profile_id: str | None = None,
        machine_id: str | None = None,
        kernel_pattern: str | None = None,
        initramfs_pattern: str | None = None,
        lvm_opts: str | None = None,
        btrfs_opts: str | None = None,
        options: str | None = None,
        label: str | None = None,
    ) -> None:
        """Helper function to set command options."""
        if profile_id:
            options_dict['--profile'] = profile_id
        if machine_id:
            options_dict['--machine-id'] = machine_id
        if kernel_pattern:
            options_dict['--kernel-pattern'] = kernel_pattern
        if initramfs_pattern:
            options_dict['--initramfs-pattern'] = initramfs_pattern
        if lvm_opts:
            options_dict['--lvm-opts'] = lvm_opts
        if btrfs_opts:
            options_dict['--btrfs-opts'] = btrfs_opts
        if options:
            options_dict['--os-options'] = options
        if label:
            options_dict['--label'] = label

    def create(
        self,
        name: str | None = None,
        short_name: str | None = None,
        profile_id: str | None = None,
        machine_id: str | None = None,
        kernel_pattern: str | None = None,
        initramfs_pattern: str | None = None,
        lvm_opts: str | None = None,
        btrfs_opts: str | None = None,
        options: str | None = None,
    ) -> CommandResult:
        """Create host profile.

        Example:
            ```python
            host.create(
                name='webserver', profile_id='3fc389b', machine_id='611f38fd887d41dea7eb3403b2730a76'
            ).assert_ok()
            ```
        """
        options_dict: BoomOptions = {}

        # Set parameters
        if name or self.name:
            options_dict['--name'] = name or self.name
        if short_name or self.short_name:
            options_dict['--short-name'] = short_name or self.short_name

        self._set_options(
            options_dict,
            profile_id=profile_id or self.profile_id,
            machine_id=machine_id or self.machine_id,
            kernel_pattern=kernel_pattern or self.kernel_pattern,
            initramfs_pattern=initramfs_pattern or self.initramfs_pattern,
            lvm_opts=lvm_opts or self.lvm_opts,
            btrfs_opts=btrfs_opts or self.btrfs_opts,
            options=options or self.options,
        )

        result = self.run_command(
            command=self.COMMAND,
            subcommand='create',
            options=options_dict,
        )

        if result.succeeded:
            # Extract host_id from output
            for line in result.stdout.splitlines():
                if match := re.match(r'\s*Host ID:\s*"([^"]+)"', line):
                    # Only the first 7 characters of full host id are used as ID
                    self.host_id = match.group(1)[:7]
                    if not self._load_data():
                        logger.warning('Could not load host data after create')
                    break
        return result

    def delete(self) -> CommandResult:
        """Delete host profile."""
        if not self.host_id:
            logger.error('Host ID required for deletion')
            return CommandResult(command='boom host delete', rc=1, stderr='Host ID required for deletion')

        options: BoomOptions = {'--host-profile': self.host_id}

        return self.run_command(command=self.COMMAND, subcommand='delete', options=options)

    def clone(
        self,
        name: str | None = None,
        short_name: str | None = None,
        profile_id: str | None = None,
        machine_id: str | None = None,
        kernel_pattern: str | None = None,
        initramfs_pattern: str | None = None,
        lvm_opts: str | None = None,
        btrfs_opts: str | None = None,
        options: str | None = None,
        label: str | None = None,
    ) -> BoomHost | None:
        """Clone this host profile with optional overrides.

        Example:
            ```python
            new_host = host.clone(name='webserver2', machine_id='722f38fd887d41dea7eb3403b2730a77')
            ```
        """
        if not self.host_id:
            logger.error('Original host profile ID required for cloning')
            return None

        options_dict: BoomOptions = {
            '--host-profile': self.host_id,
        }

        # Set optional parameters
        if name:
            options_dict['--name'] = name
        if short_name:
            options_dict['--short-name'] = short_name

        self._set_options(
            options_dict,
            profile_id=profile_id,
            machine_id=machine_id,
            kernel_pattern=kernel_pattern,
            initramfs_pattern=initramfs_pattern,
            lvm_opts=lvm_opts,
            btrfs_opts=btrfs_opts,
            options=options,
            label=label,
        )

        result = self.run_command(
            command=self.COMMAND,
            subcommand='clone',
            options=options_dict,
        )

        if not result.succeeded:
            return None
        # Extract new host_id from output
        for line in result.stdout.splitlines():
            if match := re.match(r'\s*Host ID:\s*"([^"]+)"', line):
                # Only the first 7 characters of os_id_full are used as ID
                host = BoomHost(host_id=match.group(1)[:7])
                host.refresh_report()
                return host
        return None

    def edit(
        self,
        name: str | None = None,
        short_name: str | None = None,
        profile_id: str | None = None,
        machine_id: str | None = None,
        kernel_pattern: str | None = None,
        initramfs_pattern: str | None = None,
        lvm_opts: str | None = None,
        btrfs_opts: str | None = None,
        options: str | None = None,
    ) -> CommandResult:
        """Edit host profile.

        Example:
            ```python
            host.edit(name='webserver-updated', options='root=/dev/vg00/lvol0 ro quiet').assert_ok()
            ```
        """
        if not self.host_id:
            logger.error('Host ID required for edit operation')
            return CommandResult(command='boom host edit', rc=1, stderr='Host ID required for edit operation')

        options_dict: BoomOptions = {
            '--host-profile': self.host_id,
        }

        # Set optional parameters
        if name:
            options_dict['--name'] = name
        if short_name:
            options_dict['--short-name'] = short_name

        self._set_options(
            options_dict,
            profile_id=profile_id or self.profile_id,
            machine_id=machine_id or self.machine_id,
            kernel_pattern=kernel_pattern or self.kernel_pattern,
            initramfs_pattern=initramfs_pattern or self.initramfs_pattern,
            lvm_opts=lvm_opts or self.lvm_opts,
            btrfs_opts=btrfs_opts or self.btrfs_opts,
            options=options or self.options,
        )

        result = self.run_command(
            command=self.COMMAND,
            subcommand='edit',
            options=options_dict,
        )

        if result.succeeded:
            # Reload host profile data
            self._load_data()
        return result

    def show(self) -> CommandResult:
        """Show host profile configuration."""
        options: BoomOptions = {}
        if self.host_id:
            options = {'--host-profile': self.host_id}

        return self.run_command(command=self.COMMAND, subcommand='show', options=options)

    def list_items(
        self,
        host_id: str | None = None,
        name: str | None = None,
        short_name: str | None = None,
        profile_id: str | None = None,
        machine_id: str | None = None,
        options: BoomOptions | None = None,
    ) -> CommandResult:
        """List host profiles matching the given filter criteria."""
        # Build filter options
        if not options:
            options = {}

        if host_id:
            options['--host-profile'] = host_id
        if name:
            options['--name'] = name
        if short_name:
            options['--short-name'] = short_name
        if profile_id:
            options['--profile'] = profile_id
        if machine_id:
            options['--machine-id'] = machine_id

        return self.run_command(command=self.COMMAND, subcommand='list', options=options)

clone(name=None, short_name=None, profile_id=None, machine_id=None, kernel_pattern=None, initramfs_pattern=None, lvm_opts=None, btrfs_opts=None, options=None, label=None)

Clone this host profile with optional overrides.

Example
new_host = host.clone(name='webserver2', machine_id='722f38fd887d41dea7eb3403b2730a77')
Source code in sts_libs/src/sts/boom/host.py
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def clone(
    self,
    name: str | None = None,
    short_name: str | None = None,
    profile_id: str | None = None,
    machine_id: str | None = None,
    kernel_pattern: str | None = None,
    initramfs_pattern: str | None = None,
    lvm_opts: str | None = None,
    btrfs_opts: str | None = None,
    options: str | None = None,
    label: str | None = None,
) -> BoomHost | None:
    """Clone this host profile with optional overrides.

    Example:
        ```python
        new_host = host.clone(name='webserver2', machine_id='722f38fd887d41dea7eb3403b2730a77')
        ```
    """
    if not self.host_id:
        logger.error('Original host profile ID required for cloning')
        return None

    options_dict: BoomOptions = {
        '--host-profile': self.host_id,
    }

    # Set optional parameters
    if name:
        options_dict['--name'] = name
    if short_name:
        options_dict['--short-name'] = short_name

    self._set_options(
        options_dict,
        profile_id=profile_id,
        machine_id=machine_id,
        kernel_pattern=kernel_pattern,
        initramfs_pattern=initramfs_pattern,
        lvm_opts=lvm_opts,
        btrfs_opts=btrfs_opts,
        options=options,
        label=label,
    )

    result = self.run_command(
        command=self.COMMAND,
        subcommand='clone',
        options=options_dict,
    )

    if not result.succeeded:
        return None
    # Extract new host_id from output
    for line in result.stdout.splitlines():
        if match := re.match(r'\s*Host ID:\s*"([^"]+)"', line):
            # Only the first 7 characters of os_id_full are used as ID
            host = BoomHost(host_id=match.group(1)[:7])
            host.refresh_report()
            return host
    return None

create(name=None, short_name=None, profile_id=None, machine_id=None, kernel_pattern=None, initramfs_pattern=None, lvm_opts=None, btrfs_opts=None, options=None)

Create host profile.

Example
host.create(
    name='webserver', profile_id='3fc389b', machine_id='611f38fd887d41dea7eb3403b2730a76'
).assert_ok()
Source code in sts_libs/src/sts/boom/host.py
 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def create(
    self,
    name: str | None = None,
    short_name: str | None = None,
    profile_id: str | None = None,
    machine_id: str | None = None,
    kernel_pattern: str | None = None,
    initramfs_pattern: str | None = None,
    lvm_opts: str | None = None,
    btrfs_opts: str | None = None,
    options: str | None = None,
) -> CommandResult:
    """Create host profile.

    Example:
        ```python
        host.create(
            name='webserver', profile_id='3fc389b', machine_id='611f38fd887d41dea7eb3403b2730a76'
        ).assert_ok()
        ```
    """
    options_dict: BoomOptions = {}

    # Set parameters
    if name or self.name:
        options_dict['--name'] = name or self.name
    if short_name or self.short_name:
        options_dict['--short-name'] = short_name or self.short_name

    self._set_options(
        options_dict,
        profile_id=profile_id or self.profile_id,
        machine_id=machine_id or self.machine_id,
        kernel_pattern=kernel_pattern or self.kernel_pattern,
        initramfs_pattern=initramfs_pattern or self.initramfs_pattern,
        lvm_opts=lvm_opts or self.lvm_opts,
        btrfs_opts=btrfs_opts or self.btrfs_opts,
        options=options or self.options,
    )

    result = self.run_command(
        command=self.COMMAND,
        subcommand='create',
        options=options_dict,
    )

    if result.succeeded:
        # Extract host_id from output
        for line in result.stdout.splitlines():
            if match := re.match(r'\s*Host ID:\s*"([^"]+)"', line):
                # Only the first 7 characters of full host id are used as ID
                self.host_id = match.group(1)[:7]
                if not self._load_data():
                    logger.warning('Could not load host data after create')
                break
    return result

delete()

Delete host profile.

Source code in sts_libs/src/sts/boom/host.py
142
143
144
145
146
147
148
149
150
def delete(self) -> CommandResult:
    """Delete host profile."""
    if not self.host_id:
        logger.error('Host ID required for deletion')
        return CommandResult(command='boom host delete', rc=1, stderr='Host ID required for deletion')

    options: BoomOptions = {'--host-profile': self.host_id}

    return self.run_command(command=self.COMMAND, subcommand='delete', options=options)

edit(name=None, short_name=None, profile_id=None, machine_id=None, kernel_pattern=None, initramfs_pattern=None, lvm_opts=None, btrfs_opts=None, options=None)

Edit host profile.

Example
host.edit(name='webserver-updated', options='root=/dev/vg00/lvol0 ro quiet').assert_ok()
Source code in sts_libs/src/sts/boom/host.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
def edit(
    self,
    name: str | None = None,
    short_name: str | None = None,
    profile_id: str | None = None,
    machine_id: str | None = None,
    kernel_pattern: str | None = None,
    initramfs_pattern: str | None = None,
    lvm_opts: str | None = None,
    btrfs_opts: str | None = None,
    options: str | None = None,
) -> CommandResult:
    """Edit host profile.

    Example:
        ```python
        host.edit(name='webserver-updated', options='root=/dev/vg00/lvol0 ro quiet').assert_ok()
        ```
    """
    if not self.host_id:
        logger.error('Host ID required for edit operation')
        return CommandResult(command='boom host edit', rc=1, stderr='Host ID required for edit operation')

    options_dict: BoomOptions = {
        '--host-profile': self.host_id,
    }

    # Set optional parameters
    if name:
        options_dict['--name'] = name
    if short_name:
        options_dict['--short-name'] = short_name

    self._set_options(
        options_dict,
        profile_id=profile_id or self.profile_id,
        machine_id=machine_id or self.machine_id,
        kernel_pattern=kernel_pattern or self.kernel_pattern,
        initramfs_pattern=initramfs_pattern or self.initramfs_pattern,
        lvm_opts=lvm_opts or self.lvm_opts,
        btrfs_opts=btrfs_opts or self.btrfs_opts,
        options=options or self.options,
    )

    result = self.run_command(
        command=self.COMMAND,
        subcommand='edit',
        options=options_dict,
    )

    if result.succeeded:
        # Reload host profile data
        self._load_data()
    return result

list_items(host_id=None, name=None, short_name=None, profile_id=None, machine_id=None, options=None)

List host profiles matching the given filter criteria.

Source code in sts_libs/src/sts/boom/host.py
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
def list_items(
    self,
    host_id: str | None = None,
    name: str | None = None,
    short_name: str | None = None,
    profile_id: str | None = None,
    machine_id: str | None = None,
    options: BoomOptions | None = None,
) -> CommandResult:
    """List host profiles matching the given filter criteria."""
    # Build filter options
    if not options:
        options = {}

    if host_id:
        options['--host-profile'] = host_id
    if name:
        options['--name'] = name
    if short_name:
        options['--short-name'] = short_name
    if profile_id:
        options['--profile'] = profile_id
    if machine_id:
        options['--machine-id'] = machine_id

    return self.run_command(command=self.COMMAND, subcommand='list', options=options)

refresh_report()

Refresh host profile data from the system.

Source code in sts_libs/src/sts/boom/host.py
48
49
50
51
52
53
def refresh_report(self) -> bool:
    """Refresh host profile data from the system."""
    if self._load_data():
        return True
    logger.warning('No identifiers available for host profile refresh')
    return False

show()

Show host profile configuration.

Source code in sts_libs/src/sts/boom/host.py
270
271
272
273
274
275
276
def show(self) -> CommandResult:
    """Show host profile configuration."""
    options: BoomOptions = {}
    if self.host_id:
        options = {'--host-profile': self.host_id}

    return self.run_command(command=self.COMMAND, subcommand='show', options=options)