Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image history #42

Merged
merged 23 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions docs/imagecustomizer/api/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,42 +43,44 @@ The top level type for the YAML file is the [config](./configuration/config.md)

10. Write the `/etc/image-customizer-release` file.

11. If the bootloader [resetType](./configuration/bootloader.md#resettype-string) is set
11. Write the image history file.

12. If the bootloader [resetType](./configuration/bootloader.md#resettype-string) is set
to `hard-reset`, then reset the boot-loader.

If the bootloader [resetType](./configuration/bootloader.md#resettype-string) is not
set, then append the
[extraCommandLine](./configuration/kernelcommandline.md#extracommandline-string)
value to the existing `grub.cfg` file.

12. Update the SELinux mode. [mode](./configuration/selinux.md#mode-string)
13. Update the SELinux mode. [mode](./configuration/selinux.md#mode-string)

13. If ([overlays](./configuration/os.md#overlays-overlay)) are specified, then add the
14. If ([overlays](./configuration/os.md#overlays-overlay)) are specified, then add the
overlay driver and update the fstab file with the overlay mount information.

14. If a ([verity](./configuration/storage.md#verity-verity)) device is specified, then
15. If a ([verity](./configuration/storage.md#verity-verity)) device is specified, then
add the dm-verity dracut driver and update the grub config.

15. Regenerate the initramfs file (if needed).
16. Regenerate the initramfs file (if needed).

16. Run ([postCustomization](./configuration/scripts.md#postcustomization-script)) scripts.
17. Run ([postCustomization](./configuration/scripts.md#postcustomization-script)) scripts.

17. Restore the `/etc/resolv.conf` file.
18. Restore the `/etc/resolv.conf` file.

18. If SELinux is enabled, call `setfiles`.
19. If SELinux is enabled, call `setfiles`.

19. Run finalize image scripts. ([finalizeCustomization](./configuration/scripts.md#finalizecustomization-script))
20. Run finalize image scripts. ([finalizeCustomization](./configuration/scripts.md#finalizecustomization-script))

20. If [--shrink-filesystems](./cli.md#shrink-filesystems) is specified, then shrink
21. If [--shrink-filesystems](./cli.md#shrink-filesystems) is specified, then shrink
the file systems.

21. If a ([verity](./configuration/storage.md#verity-verity)) device is specified, then
22. If a ([verity](./configuration/storage.md#verity-verity)) device is specified, then
create the hash tree and update the grub config.

22. If the output format is set to `iso`, copy additional iso media files.
23. If the output format is set to `iso`, copy additional iso media files.
([iso](./configuration/iso.md))

23. If [--output-pxe-artifacts-dir](./cli.md#output-pxe-artifacts-dir) is specified,
24. If [--output-pxe-artifacts-dir](./cli.md#output-pxe-artifacts-dir) is specified,
then export the ISO image contents to the specified folder.

## /etc/resolv.conf
Expand Down Expand Up @@ -206,6 +208,7 @@ os:
- [overlays](./configuration/os.md#overlays-overlay) ([overlay type](./configuration/overlay.md))
- [uki](./configuration/os.md#uki-uki) ([uki type](./configuration/uki.md))
- [kernels](./configuration/uki.md#kernels)
- [imageHistory](./configuration/imagehistory.md)
amritakohli marked this conversation as resolved.
Show resolved Hide resolved
- [scripts](./configuration/config.md#scripts-scripts) ([scripts type](./configuration/scripts.md))
- [postCustomization](./configuration/scripts.md#postcustomization-script) ([script type](./configuration/script.md))
- [path](./configuration/script.md#script-path)
Expand Down
11 changes: 11 additions & 0 deletions docs/imagecustomizer/api/configuration/os.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,14 @@ os:
enable:
- sshd
```
## imageHistory [string]
Options for configuring image history.
Set value to `none` to disable.

```yaml
os:
imageHistory: none
```
10 changes: 6 additions & 4 deletions toolkit/tools/imagecustomizerapi/additionalfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,20 @@ type AdditionalFileList []AdditionalFile

type AdditionalFile struct {
// The destination file path in the target OS that the file will be copied to.
Destination string `yaml:"destination"`
Destination string `yaml:"destination" json:"destination,omitempty"`

// The source file path of the file that will copied.
// Mutally exclusive with 'contents'.
Source string `yaml:"source"`
Source string `yaml:"source" json:"source,omitempty"`

// A string that will be used as the contents of the file.
// Mutally exclusive with 'source'.
Content *string `yaml:"content"`
Content *string `yaml:"content" json:"content,omitempty"`

// The file permissions to set on the file.
Permissions *FilePermissions `yaml:"permissions"`
Permissions *FilePermissions `yaml:"permissions" json:"permissions,omitempty"`

SHA256Hash string `json:"sha256hash,omitempty"`
}

func (l AdditionalFileList) IsValid() (err error) {
Expand Down
2 changes: 1 addition & 1 deletion toolkit/tools/imagecustomizerapi/bootloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

type BootLoader struct {
ResetType ResetBootLoaderType `yaml:"resetType"`
ResetType ResetBootLoaderType `yaml:"resetType" json:"resetType,omitempty"`
}

func (b *BootLoader) IsValid() error {
Expand Down
12 changes: 6 additions & 6 deletions toolkit/tools/imagecustomizerapi/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (
)

type Config struct {
Storage Storage `yaml:"storage"`
Iso *Iso `yaml:"iso"`
Pxe *Pxe `yaml:"pxe"`
OS *OS `yaml:"os"`
Scripts Scripts `yaml:"scripts"`
PreviewFeatures []string `yaml:"previewFeatures"`
Storage Storage `yaml:"storage" json:"storage,omitempty"`
Iso *Iso `yaml:"iso" json:"iso,omitempty"`
Pxe *Pxe `yaml:"pxe" json:"pxe,omitempty"`
OS *OS `yaml:"os" json:"os,omitempty"`
Scripts Scripts `yaml:"scripts" json:"scripts,omitempty"`
PreviewFeatures []string `yaml:"previewFeatures" json:"previewFeatures,omitempty"`
}

func (c *Config) IsValid() (err error) {
Expand Down
12 changes: 7 additions & 5 deletions toolkit/tools/imagecustomizerapi/dirconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,24 @@ type DirConfigList []DirConfig

type DirConfig struct {
// The path to the source directory that will be copied (can be relative or absolute path).
Source string `yaml:"source"`
Source string `yaml:"source" json:"source,omitempty"`

// The absolute path in the target OS that the directory will be copied to.
Destination string `yaml:"destination"`
Destination string `yaml:"destination" json:"destination,omitempty"`

// The permissions to set on all of the new directories being created on the target OS (including the top-level directory).
// Note: If this value is not specified in the config, the permissions for these directories will be set to 0755.
NewDirPermissions *FilePermissions `yaml:"newDirPermissions"`
NewDirPermissions *FilePermissions `yaml:"newDirPermissions" json:"newDirPermissions,omitempty"`

// The permissions to set on the directories being copied that already do exist on the target OS (including the top-level directory).
// Note: If this value is not specified in the config, the permissions for this field will be the same as that of the pre-existing directory.
MergedDirPermissions *FilePermissions `yaml:"mergedDirPermissions"`
MergedDirPermissions *FilePermissions `yaml:"mergedDirPermissions" json:"mergedDirPermissions,omitempty"`

// The permissions to set on the children file of the directory.
// Note: If this value is not specified in the config, the permissions for these directories will be set to 0755.
ChildFilePermissions *FilePermissions `yaml:"childFilePermissions"`
ChildFilePermissions *FilePermissions `yaml:"childFilePermissions" json:"childFilePermissions,omitempty"`

SHA256HashMap map[string]string `json:"sha256hashmap,omitempty"`
}

func (l *DirConfigList) IsValid() (err error) {
Expand Down
6 changes: 3 additions & 3 deletions toolkit/tools/imagecustomizerapi/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ const (

type Disk struct {
// The type of partition table to use (e.g. mbr, gpt)
PartitionTableType PartitionTableType `yaml:"partitionTableType"`
PartitionTableType PartitionTableType `yaml:"partitionTableType" json:"partitionTableType,omitempty"`

// The virtual size of the disk.
// Note: This value is filled in by IsValid().
MaxSize *DiskSize `yaml:"maxSize"`
MaxSize *DiskSize `yaml:"maxSize" json:"maxSize,omitempty"`

// The partitions to allocate on the disk.
Partitions []Partition `yaml:"partitions"`
Partitions []Partition `yaml:"partitions" json:"partitions,omitempty"`
}

func (d *Disk) IsValid() error {
Expand Down
38 changes: 38 additions & 0 deletions toolkit/tools/imagecustomizerapi/disksize.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package imagecustomizerapi

import (
"encoding/json"
"fmt"
"regexp"
"strconv"
Expand Down Expand Up @@ -31,6 +32,26 @@ func (s *DiskSize) UnmarshalYAML(value *yaml.Node) error {
return fmt.Errorf("failed to parse disk size:\n%w", err)
}

return parseAndSetDiskSize(stringValue, s)
}

func (s DiskSize) MarshalJSON() ([]byte, error) {
return json.Marshal(s.String())
}

func (s *DiskSize) UnmarshalJSON(data []byte) error {
var err error

var stringValue string
err = json.Unmarshal(data, &stringValue)
if err != nil {
return fmt.Errorf("failed to parse disk size:\n%w", err)
}

return parseAndSetDiskSize(stringValue, s)
}

func parseAndSetDiskSize(stringValue string, s *DiskSize) error {
diskSize, err := parseDiskSize(stringValue)
if err != nil {
return fmt.Errorf("%w:\nexpected format: <NUM>(K|M|G|T) (e.g. 100M, 1G)", err)
Expand Down Expand Up @@ -98,3 +119,20 @@ func parseDiskSize(diskSizeString string) (DiskSize, error) {

return DiskSize(num), nil
}

// String returns the string representation of DiskSize in the most appropriate unit
// such that it matches the input format.
func (s DiskSize) String() string {
switch {
case s%diskutils.TiB == 0:
return fmt.Sprintf("%dT", s/diskutils.TiB)
case s%diskutils.GiB == 0:
return fmt.Sprintf("%dG", s/diskutils.GiB)
case s%diskutils.MiB == 0:
return fmt.Sprintf("%dM", s/diskutils.MiB)
case s%diskutils.KiB == 0:
return fmt.Sprintf("%dK", s/diskutils.KiB)
default:
return fmt.Sprintf("%d", s)
}
}
8 changes: 4 additions & 4 deletions toolkit/tools/imagecustomizerapi/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import (
// FileSystem holds the file system information for a partition.
type FileSystem struct {
// DeviceId is the ID of the source partition.
DeviceId string `yaml:"deviceId"`
DeviceId string `yaml:"deviceId" json:"deviceId,omitempty"`
// FileSystemType is the type of file system to use on the partition.
Type FileSystemType `yaml:"type"`
Type FileSystemType `yaml:"type" json:"type,omitempty"`
// MountPoint contains the mount settings.
MountPoint *MountPoint `yaml:"mountPoint"`
MountPoint *MountPoint `yaml:"mountPoint" json:"mountPoint,omitempty"`

// If 'DeviceId' points at a verity device, this value is the 'Id' of the data partition.
// Otherwise, it is the same as 'DeviceId'.
// Value is filled in by Storage.IsValid().
PartitionId string
PartitionId string `json:"-"`
}

// IsValid returns an error if the MountPoint is not valid
Expand Down
26 changes: 26 additions & 0 deletions toolkit/tools/imagecustomizerapi/imagehistory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package imagecustomizerapi

import (
"fmt"
)

type ImageHistory string

const (
ImageHistoryDefault ImageHistory = ""
ImageHistoryNone ImageHistory = "none"
)

func (t ImageHistory) IsValid() error {
switch t {
case ImageHistoryDefault, ImageHistoryNone:
// All good.
return nil

default:
return fmt.Errorf("invalid imageHistory value (%s)", t)
}
}
4 changes: 2 additions & 2 deletions toolkit/tools/imagecustomizerapi/iso.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (

// Iso defines how the generated iso media should be configured.
type Iso struct {
KernelCommandLine KernelCommandLine `yaml:"kernelCommandLine"`
AdditionalFiles AdditionalFileList `yaml:"additionalFiles"`
KernelCommandLine KernelCommandLine `yaml:"kernelCommandLine" json:"kernelCommandLine,omitempty"`
AdditionalFiles AdditionalFileList `yaml:"additionalFiles" json:"additionalFiles,omitempty"`
}

func (i *Iso) IsValid() error {
Expand Down
2 changes: 1 addition & 1 deletion toolkit/tools/imagecustomizerapi/kernelcommandline.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

type KernelCommandLine struct {
// Extra kernel command line args.
ExtraCommandLine []string `yaml:"extraCommandLine"`
ExtraCommandLine []string `yaml:"extraCommandLine" json:"extraCommandLine,omitempty"`
}

func (k *KernelCommandLine) IsValid() error {
Expand Down
6 changes: 3 additions & 3 deletions toolkit/tools/imagecustomizerapi/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
)

type Module struct {
Name string `yaml:"name"`
LoadMode ModuleLoadMode `yaml:"loadMode"`
Options map[string]string `yaml:"options"`
Name string `yaml:"name" json:"name,omitempty"`
LoadMode ModuleLoadMode `yaml:"loadMode" json:"loadMode,omitempty"`
Options map[string]string `yaml:"options" json:"options,omitempty"`
}

type ModuleList []Module
Expand Down
6 changes: 3 additions & 3 deletions toolkit/tools/imagecustomizerapi/mountpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (
// MountPoint holds the mounting information for each partition.
type MountPoint struct {
// The ID type to use for the source in the /etc/fstab file.
IdType MountIdentifierType `yaml:"idType"`
IdType MountIdentifierType `yaml:"idType" json:"idType,omitempty"`
// The additional options for the mount.
Options string `yaml:"options"`
Options string `yaml:"options" json:"options,omitempty"`
// The target directory path of the mount.
Path string `yaml:"path"`
Path string `yaml:"path" json:"path,omitempty"`
}

// UnmarshalYAML enables MountPoint to handle both a shorthand path and a structured object.
Expand Down
30 changes: 18 additions & 12 deletions toolkit/tools/imagecustomizerapi/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,19 @@ import (

// OS defines how each system present on the image is supposed to be configured.
type OS struct {
Hostname string `yaml:"hostname"`
Packages Packages `yaml:"packages"`
SELinux SELinux `yaml:"selinux"`
KernelCommandLine KernelCommandLine `yaml:"kernelCommandLine"`
AdditionalFiles AdditionalFileList `yaml:"additionalFiles"`
AdditionalDirs DirConfigList `yaml:"additionalDirs"`
Users []User `yaml:"users"`
Services Services `yaml:"services"`
Modules ModuleList `yaml:"modules"`
Overlays *[]Overlay `yaml:"overlays"`
BootLoader BootLoader `yaml:"bootloader"`
Uki *Uki `yaml:"uki"`
Hostname string `yaml:"hostname" json:"hostname,omitempty"`
Packages Packages `yaml:"packages" json:"packages,omitempty"`
SELinux SELinux `yaml:"selinux" json:"selinux,omitempty"`
KernelCommandLine KernelCommandLine `yaml:"kernelCommandLine" json:"kernelCommandLine,omitempty"`
AdditionalFiles AdditionalFileList `yaml:"additionalFiles" json:"additionalFiles,omitempty"`
AdditionalDirs DirConfigList `yaml:"additionalDirs" json:"additionalDirs,omitempty"`
Users []User `yaml:"users" json:"users,omitempty"`
Services Services `yaml:"services" json:"services,omitempty"`
Modules ModuleList `yaml:"modules" json:"modules,omitempty"`
Overlays *[]Overlay `yaml:"overlays" json:"overlays,omitempty"`
BootLoader BootLoader `yaml:"bootloader" json:"bootloader,omitempty"`
Uki *Uki `yaml:"uki" json:"uki,omitempty"`
ImageHistory ImageHistory `yaml:"imageHistory" json:"imageHistory,omitempty"`
}

func (s *OS) IsValid() error {
Expand All @@ -39,6 +40,11 @@ func (s *OS) IsValid() error {
}
}

err = s.ImageHistory.IsValid()
if err != nil {
return fmt.Errorf("invalid imageHistory:\n%w", err)
}

err = s.SELinux.IsValid()
if err != nil {
return fmt.Errorf("invalid selinux:\n%w", err)
Expand Down
14 changes: 7 additions & 7 deletions toolkit/tools/imagecustomizerapi/overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import (
)

type Overlay struct {
LowerDirs []string `yaml:"lowerDirs"`
UpperDir string `yaml:"upperDir"`
WorkDir string `yaml:"workDir"`
MountPoint string `yaml:"mountPoint"`
IsInitrdOverlay bool `yaml:"isInitrdOverlay"`
MountDependencies []string `yaml:"mountDependencies"`
MountOptions string `yaml:"mountOptions"`
LowerDirs []string `yaml:"lowerDirs" json:"lowerDirs,omitempty"`
UpperDir string `yaml:"upperDir" json:"upperDir,omitempty"`
WorkDir string `yaml:"workDir" json:"workDir,omitempty"`
MountPoint string `yaml:"mountPoint" json:"mountPoint,omitempty"`
IsInitrdOverlay bool `yaml:"isInitrdOverlay" json:"isInitrdOverlay,omitempty"`
MountDependencies []string `yaml:"mountDependencies" json:"mountDependencies,omitempty"`
MountOptions string `yaml:"mountOptions" json:"mountOptions,omitempty"`
}

func (o *Overlay) IsValid() error {
Expand Down
Loading
Loading