Skip to content
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
3 changes: 3 additions & 0 deletions docs/user/reference/config/config-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ All config files share the same schema — there is no distinction between a "ro
| `components` | map of objects | Component (package) definitions | [Components](components.md) |
| `component-groups` | map of objects | Named groups of components with shared defaults | [Component Groups](component-groups.md) |
| `images` | map of objects | Image definitions (VMs, containers) | [Images](images.md) |
| `test-suites` | map of objects | Named test suite definitions referenced by images | [Test Suites](test-suites.md) |
| `tools` | object | Configuration for external tools used by azldev | [Tools](tools.md) |
| `default-package-config` | object | Project-wide default applied to all binary packages | [Package Groups — Resolution Order](package-groups.md#resolution-order) |
| `package-groups` | map of objects | Named groups of binary packages with shared config | [Package Groups](package-groups.md) |

## Includes

Expand Down
72 changes: 70 additions & 2 deletions docs/user/reference/config/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ The `[images]` section defines system images (VMs, containers, etc.) that azldev
|-------|----------|------|----------|-------------|
| Description | `description` | string | No | Human-readable description of the image |
| Definition | `definition` | [ImageDefinition](#image-definition) | No | Specifies the image definition format, file path, and optional profile |
| Capabilities | `capabilities` | [ImageCapabilities](#image-capabilities) | No | Describes features and properties of this image |
| Tests | `tests` | [ImageTests](#image-tests) | No | Test configuration for this image |
| Publish | `publish` | [ImagePublish](#image-publish) | No | Publishing settings for this image |

## Image Definition

Expand All @@ -19,24 +22,59 @@ The `definition` field tells azldev where to find the image definition file and
| Path | `path` | string | No | Path to the image definition file, relative to the config file |
| Profile | `profile` | string | No | Build profile to use when building the image (format-specific) |

## Image Capabilities

The `capabilities` subtable describes what the image supports. All fields are optional booleans using tri-state semantics: `true` (explicitly enabled), `false` (explicitly disabled), or omitted (unspecified / inherit from defaults).

| Field | TOML Key | Type | Default | Description |
|-------|----------|------|---------|-------------|
| Machine Bootable | `machine-bootable` | bool | unset | Whether the image can be booted on a machine (bare metal or VM) |
| Container | `container` | bool | unset | Whether the image can be run on an OCI container host |
| Systemd | `systemd` | bool | unset | Whether the image runs systemd as its init system |
| Runtime Package Management | `runtime-package-management` | bool | unset | Whether the image supports installing/removing packages at runtime (e.g., via dnf/tdnf) |

## Image Tests

The `tests` subtable links an image to one or more test suites defined in the top-level [`[test-suites]`](test-suites.md) section.

| Field | TOML Key | Type | Required | Description |
|-------|----------|------|----------|-------------|
| Test Suites | `test-suites` | array of inline tables | No | List of test suite references. Each entry must have a `name` field matching a key in `[test-suites]`. |

## Image Publish

The `publish` subtable configures where an image is published. Unlike packages (which target a single channel), images may be published to multiple channels simultaneously.

| Field | TOML Key | Type | Required | Description |
|-------|----------|------|----------|-------------|
| Channels | `channels` | string array | No | List of publish channels for this image |

> **Note:** Each image name must be unique across all config files. Defining the same image name in two files produces an error.

## Examples

### VM image using Kiwi
### VM image with capabilities

```toml
[images.vm-base]
description = "VM Base Image"
definition = { type = "kiwi", path = "vm-base/vm-base.kiwi" }

[images.vm-base.capabilities]
machine-bootable = true
systemd = true
runtime-package-management = true
```

### Container image
### Container image with capabilities

```toml
[images.container-base]
description = "Container Base Image"
definition = { type = "kiwi", path = "container-base/container-base.kiwi" }

[images.container-base.capabilities]
container = true
```

### Image with a build profile
Expand All @@ -47,7 +85,37 @@ description = "Azure-optimized VM image"
definition = { type = "kiwi", path = "vm-azure/vm-azure.kiwi", profile = "azure" }
```

### Image with test suite references

```toml
[images.vm-base]
description = "VM Base Image"
definition = { type = "kiwi", path = "vm-base/vm-base.kiwi" }

[images.vm-base.capabilities]
machine-bootable = true
systemd = true

[images.vm-base.tests]
test-suites = [
{ name = "smoke" },
{ name = "integration" },
]
```

### Image with publish channels

```toml
[images.vm-base]
description = "VM Base Image"
definition = { type = "kiwi", path = "vm-base/vm-base.kiwi" }

[images.vm-base.publish]
channels = ["registry-prod", "registry-staging"]
```

## Related Resources

- [Config File Structure](config-file.md) — top-level config file layout
- [Test Suites](test-suites.md) — test suite definitions
- [Tools](tools.md) — Image Customizer tool configuration
43 changes: 43 additions & 0 deletions docs/user/reference/config/test-suites.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Test Suites

The `[test-suites]` section defines named test suites that can be referenced by images. Each test suite is defined under `[test-suites.<name>]`.

## Test Suite Config

| Field | TOML Key | Type | Required | Description |
|-------|----------|------|----------|-------------|
| Description | `description` | string | No | Human-readable description of the test suite |

Test suites are referenced by images through the [`[images.<name>.tests]`](images.md#image-tests) subtable. Each image can reference one or more test suites by name.

> **Note:** Each test suite name must be unique across all config files. Defining the same test suite name in two files produces an error.

## Examples

### Basic test suite definitions

```toml
[test-suites.smoke]
description = "Smoke tests for basic image validation"

[test-suites.integration]
description = "Integration tests for live VM validation"
```

### Referencing test suites from an image

```toml
[test-suites.smoke]
description = "Smoke tests"

[images.vm-base]
description = "VM Base Image"

[images.vm-base.tests]
test-suites = [{ name = "smoke" }]
```

## Related Resources

- [Images](images.md) — image configuration including test references
- [Config File Structure](config-file.md) — top-level config file layout
32 changes: 30 additions & 2 deletions internal/app/azldev/cmds/image/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"

"github.com/microsoft/azure-linux-dev-tools/internal/app/azldev"
"github.com/microsoft/azure-linux-dev-tools/internal/projectconfig"
"github.com/samber/lo"
"github.com/spf13/cobra"
)
Expand All @@ -28,6 +29,26 @@ type ImageListResult struct {
// Description of the image.
Description string `json:"description"`

// Capabilities describes the features and properties of this image.
Capabilities projectconfig.ImageCapabilities `json:"capabilities" table:"-"`

// CapabilitiesSummary is a comma-separated summary of enabled capabilities for table
// display.
CapabilitiesSummary string `json:"-" table:"Capabilities"`

// Tests holds the test configuration for this image, matching the original config
// structure.
Tests projectconfig.ImageTestsConfig `json:"tests" table:"-"`

// TestsSummary is a comma-separated summary of test suite names for table display.
TestsSummary string `json:"-" table:"Tests"`

// Publish holds the publish settings for this image.
Publish projectconfig.ImagePublishConfig `json:"publish" table:"-"`

// PublishSummary is a comma-separated summary of publish channels for table display.
PublishSummary string `json:"-" table:"Publish"`

// Definition contains the image definition details (hidden from table output).
Definition ImageDefinitionResult `json:"definition" table:"-"`
}
Expand Down Expand Up @@ -108,9 +129,16 @@ func ListImages(env *azldev.Env, options *ListImageOptions) ([]ImageListResult,
}

imageConfig := cfg.Images[name]

results = append(results, ImageListResult{
Name: name,
Description: imageConfig.Description,
Name: name,
Description: imageConfig.Description,
Capabilities: imageConfig.Capabilities,
CapabilitiesSummary: strings.Join(imageConfig.Capabilities.EnabledNames(), ", "),
Tests: imageConfig.Tests,
TestsSummary: strings.Join(imageConfig.TestNames(), ", "),
Publish: imageConfig.Publish,
PublishSummary: strings.Join(imageConfig.Publish.Channels, ", "),
Definition: ImageDefinitionResult{
Type: string(imageConfig.Definition.DefinitionType),
Path: imageConfig.Definition.Path,
Expand Down
86 changes: 86 additions & 0 deletions internal/app/azldev/cmds/image/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/microsoft/azure-linux-dev-tools/internal/app/azldev/cmds/image"
"github.com/microsoft/azure-linux-dev-tools/internal/app/azldev/core/testutils"
"github.com/microsoft/azure-linux-dev-tools/internal/projectconfig"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -78,6 +79,91 @@ func TestListImages_AllImages(t *testing.T) {
assert.Equal(t, "Image B description", results[1].Description)
}

func TestListImages_WithCapabilitiesAndTests(t *testing.T) {
testEnv := testutils.NewTestEnv(t)
testEnv.Config.Images = map[string]projectconfig.ImageConfig{
"vm-base": {
Name: "vm-base",
Description: "VM Base Image",
Capabilities: projectconfig.ImageCapabilities{
MachineBootable: lo.ToPtr(true),
Systemd: lo.ToPtr(true),
},
Tests: projectconfig.ImageTestsConfig{
TestSuites: []projectconfig.TestSuiteRef{
{Name: "smoke"},
{Name: "integration"},
},
},
Publish: projectconfig.ImagePublishConfig{
Channels: []string{"registry-prod", "registry-staging"},
},
},
"container-base": {
Name: "container-base",
Description: "Container Base Image",
Capabilities: projectconfig.ImageCapabilities{
Container: lo.ToPtr(true),
},
Tests: projectconfig.ImageTestsConfig{
TestSuites: []projectconfig.TestSuiteRef{
{Name: "smoke"},
},
},
Publish: projectconfig.ImagePublishConfig{
Channels: []string{"registry-prod"},
},
},
"minimal": {
Name: "minimal",
Description: "Minimal image with no capabilities or tests",
},
}

options := &image.ListImageOptions{}

results, err := image.ListImages(testEnv.Env, options)
require.NoError(t, err)
require.Len(t, results, 3)

// Results sorted alphabetically.
assert.Equal(t, "container-base", results[0].Name)
assert.Equal(t, lo.ToPtr(true), results[0].Capabilities.Container)
assert.Nil(t, results[0].Capabilities.MachineBootable)
assert.Equal(t, "container", results[0].CapabilitiesSummary)
assert.Equal(t, projectconfig.ImageTestsConfig{
TestSuites: []projectconfig.TestSuiteRef{{Name: "smoke"}},
}, results[0].Tests)
assert.Equal(t, "smoke", results[0].TestsSummary)
assert.Equal(t, projectconfig.ImagePublishConfig{
Channels: []string{"registry-prod"},
}, results[0].Publish)
assert.Equal(t, "registry-prod", results[0].PublishSummary)

assert.Equal(t, "minimal", results[1].Name)
assert.Nil(t, results[1].Capabilities.MachineBootable)
assert.Nil(t, results[1].Capabilities.Container)
assert.Empty(t, results[1].CapabilitiesSummary)
assert.Empty(t, results[1].Tests.TestSuites)
assert.Empty(t, results[1].TestsSummary)
assert.Empty(t, results[1].Publish.Channels)
assert.Empty(t, results[1].PublishSummary)

assert.Equal(t, "vm-base", results[2].Name)
assert.Equal(t, lo.ToPtr(true), results[2].Capabilities.MachineBootable)
assert.Equal(t, lo.ToPtr(true), results[2].Capabilities.Systemd)
assert.Nil(t, results[2].Capabilities.Container)
assert.Equal(t, "machine-bootable, systemd", results[2].CapabilitiesSummary)
assert.Equal(t, projectconfig.ImageTestsConfig{
TestSuites: []projectconfig.TestSuiteRef{{Name: "smoke"}, {Name: "integration"}},
}, results[2].Tests)
assert.Equal(t, "smoke, integration", results[2].TestsSummary)
assert.Equal(t, projectconfig.ImagePublishConfig{
Channels: []string{"registry-prod", "registry-staging"},
}, results[2].Publish)
assert.Equal(t, "registry-prod, registry-staging", results[2].PublishSummary)
}

func TestListImages_ExactMatch(t *testing.T) {
testEnv := testutils.NewTestEnv(t)
testEnv.Config.Images = map[string]projectconfig.ImageConfig{
Expand Down
3 changes: 3 additions & 0 deletions internal/projectconfig/configfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ type ConfigFile struct {
// to be applied to sets of binary packages.
PackageGroups map[string]PackageGroupConfig `toml:"package-groups,omitempty" validate:"dive" jsonschema:"title=Package groups,description=Definitions of package groups for shared binary package configuration"`

// Definitions of test suites.
TestSuites map[string]TestSuiteConfig `toml:"test-suites,omitempty" validate:"dive" jsonschema:"title=Test Suites,description=Definitions of test suites for this project"`

// Internal fields used to track the origin of the config file; `dir` is the directory
// that the config file's relative paths are based from.
sourcePath string `toml:"-"`
Expand Down
Loading
Loading