diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 000000000..3b4a67a60
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+# For any changes, ensure owners approvals
+* @microsoft/azurelinux-trident
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 000000000..b86ceb8ba
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,100 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL Advanced"
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+ schedule:
+ - cron: '43 9 * * 0'
+
+jobs:
+ analyze:
+ name: Analyze (${{ matrix.language }})
+ # Runner size impacts CodeQL analysis time. To learn more, please see:
+ # - https://gh.io/recommended-hardware-resources-for-running-codeql
+ # - https://gh.io/supported-runners-and-hardware-resources
+ # - https://gh.io/using-larger-runners (GitHub.com only)
+ # Consider using larger runners or machines with greater resources for possible analysis time improvements.
+ runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
+ permissions:
+ # required for all workflows
+ security-events: write
+
+ # required to fetch internal or private CodeQL packs
+ packages: read
+
+ # only required for workflows in private repositories
+ actions: read
+ contents: read
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - language: go
+ build-mode: autobuild
+ - language: python
+ build-mode: none
+ # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
+ # Use `c-cpp` to analyze code written in C, C++ or both
+ # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
+ # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
+ # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
+ # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
+ # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
+ # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ # Add any setup steps before running the `github/codeql-action/init` action.
+ # This includes steps like installing compilers or runtimes (`actions/setup-node`
+ # or others). This is typically only required for manual builds.
+ # - name: Setup runtime (example)
+ # uses: actions/setup-example@v1
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: ${{ matrix.language }}
+ build-mode: ${{ matrix.build-mode }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+
+ # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
+
+ # If the analyze step fails for one of the languages you are analyzing with
+ # "We were unable to automatically build your code", modify the matrix above
+ # to set the build mode to "manual" for that language. Then modify this step
+ # to build your code.
+ # âšī¸ Command-line programs to run using the OS shell.
+ # đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+ - if: matrix.build-mode == 'manual'
+ shell: bash
+ run: |
+ echo 'If you are using a "manual" build mode for one or more of the' \
+ 'languages you are analyzing, replace this with the commands to build' \
+ 'your code, for example:'
+ echo ' make bootstrap'
+ echo ' make release'
+ exit 1
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.pipelines/templates/MockOB.yml b/.pipelines/templates/MockOB.yml
new file mode 100644
index 000000000..a656b3d7a
--- /dev/null
+++ b/.pipelines/templates/MockOB.yml
@@ -0,0 +1,114 @@
+parameters:
+ - name: stages
+ type: stageList
+ default: []
+
+stages:
+ - ${{ each stage in parameters.stages }}:
+ - stage: ${{ stage.stage }}
+ ${{ if ne(stage.displayName, '') }}:
+ displayName: ${{ stage.displayName }}
+
+ ${{ if ne(join(stage.dependsOn, ','), '') }}:
+ dependsOn: ${{ stage.dependsOn }}
+
+ ${{ if ne(stage.condition, '') }}:
+ condition: ${{ stage.condition }}
+
+ ${{ if ne(stage.variables, '') }}:
+ variables: ${{ stage.variables }}
+
+ ${{ if ne(stage.isSkippable, '') }}:
+ isSkippable: ${{ stage.isSkippable }}
+
+ ${{ if ne(stage.lockBehavior, '') }}:
+ lockBehavior: ${{ stage.lockBehavior }}
+
+ jobs:
+ - ${{ each job in stage.jobs }}:
+ - job: ${{ job.job }}
+ ${{ if ne(job.displayName, '') }}:
+ displayName: ${{ job.displayName }}
+
+ ${{ if and(ne(job.timeoutInMinutes, ''), gt(2880, job.timeoutInMinutes)) }}:
+ timeoutInMinutes: ${{ job.timeoutInMinutes }}
+ ${{ else }}:
+ timeoutInMinutes: 1440
+
+ ${{ if ne(job.condition, '') }}:
+ condition: ${{ job.condition }}
+
+ ${{ if ne(job.strategy, '') }}:
+ strategy: ${{ job.strategy }}
+
+ ${{ if ne(join(job.dependsOn, ','), '') }}:
+ dependsOn: ${{ job.dependsOn }}
+
+ variables:
+ - ${{ if ne(job.variables, '') }}:
+ - ${{ each v in job.variables }}:
+ - ${{ if ne(v.key, '') }}:
+ - name: ${{ v.key }}
+ value: ${{ v.value }}
+ - ${{ else }}:
+ - ${{ insert }}: ${{ v }}
+ - name: ob_customArtifactName
+ value: ${{ coalesce(variables.ob_artifactBaseName, format('drop_{0}_{1}', stage.stage, job.job)) }}${{ coalesce(variables.ob_artifactSuffix, '') }}
+
+ pool:
+ name: ${{ coalesce(job.pool.name, 'trident-azl3-1es-pool-westus2') }}
+
+ ${{ if ne(job.pool.hostArchitecture, '') }}:
+ HostArchitecture: ${{ job.pool.hostArchitecture }}
+
+ LinuxHostVersion:
+ vmBuild: true
+ distribution: mariner
+ Host: linux
+
+ steps:
+ - ${{ if eq(variables.ob_outputDirectory, '' ) }}:
+ - ${{ job.job }}
+ - "Variable ob_outputDirectory is not defined. Please check https://aka.ms/obpipelines/artifacts": error
+
+ - checkout: self
+ fetchDepth: 1
+ submodules: recursive
+ path: s
+
+ - bash: |
+ set -eux
+ mkdir -p "${{ variables.ob_outputDirectory }}"
+ displayName: "Create output directory"
+
+ - ${{ each step in job.steps }}:
+ - ${{ if ne(step.task, '') }}:
+ task: ${{ step.task }}
+ ${{ if ne(step.displayName, '') }}:
+ displayName: ${{ step.displayName }}
+ ${{ if ne(step.inputs, '') }}:
+ inputs: ${{ step.inputs }}
+ ${{ if ne(step.condition, '') }}:
+ condition: ${{ step.condition }}
+ ${{ if ne(step.env, '') }}:
+ env: ${{ step.env }}
+ ${{ if ne(step.retryCountOnTaskFailure, '') }}:
+ retryCountOnTaskFailure: ${{ step.retryCountOnTaskFailure }}
+ ${{ if ne(step.continueOnError, '') }}:
+ continueOnError: ${{ step.continueOnError }}
+ ${{ if ne(step.target, '') }}:
+ target: ${{ step.target }}
+ ${{ if ne(step.enabled, '') }}:
+ enabled: ${{ step.enabled }}
+ ${{ if ne(step.name, '') }}:
+ name: ${{ step.name }}
+ ${{ if ne(step.timeoutInMinutes, '') }}:
+ timeoutInMinutes: ${{ step.timeoutInMinutes }}
+
+ # - bash: |
+ # # ACTUAL:
+ # # ${{ convertToJson(step) }}
+
+ - publish: ${{ variables.ob_outputDirectory }}
+ artifact: ${{ variables.ob_customArtifactName }}
+ condition: always()
diff --git a/.pipelines/templates/e2e-template.yml b/.pipelines/templates/e2e-template.yml
index 21120c67d..0b9faa364 100644
--- a/.pipelines/templates/e2e-template.yml
+++ b/.pipelines/templates/e2e-template.yml
@@ -77,10 +77,23 @@ stages:
# Build tools (Go stuff)
- template: stages/building_tools/building-tools.yml
- # Makefile validation, only for CI and PR-E2E
- - ${{ if or(eq(parameters.stageType, 'ci'), eq(parameters.stageType, 'pr-e2e'), eq(parameters.stageType, 'pr-e2e-azure')) }}:
+ # Makefile validation, only for CI
+ - ${{ if eq(parameters.stageType, 'ci') }}:
- template: stages/validate_makefile/dev-build.yml
+ # Build FT base Image, only in CI
+ - ${{ if eq(parameters.stageType, 'ci') }}:
+ # Build Trident installer ISO (host)
+ - template: stages/build_image/build-image.yml
+ parameters:
+ imageName: trident-functest
+ dependsOnTrident: false
+ baseimgBuildType: ${{ parameters.baseimgBuildType }}
+ baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
+ micBuildType: ${{ parameters.micBuildType }}
+ micVersion: ${{ parameters.micVersion }}
+ clones: 1
+
# Build Trident container image
- template: stages/build_docker_image/trident-container.yml
parameters:
@@ -88,79 +101,90 @@ stages:
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
# Build Trident installer ISO (host)
- - template: stages/build_image/trident-testimg.yml
+ - template: stages/build_image/build-image.yml
parameters:
- imageName: build/trident-installer-testimage.iso
- outputArtifactName: trident-installer-testimage
+ imageName: trident-installer
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
micBuildType: ${{ parameters.micBuildType }}
micVersion: ${{ parameters.micVersion }}
+ clones: 1
# Build Trident split (stage and finalize separated) installer ISO (host)
- - template: stages/build_image/trident-testimg.yml
+ - template: stages/build_image/build-image.yml
parameters:
- imageName: build/trident-split-installer-testimage.iso
- outputArtifactName: trident-split-installer-testimage
+ imageName: trident-split-installer
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
micBuildType: ${{ parameters.micBuildType }}
micVersion: ${{ parameters.micVersion }}
+ clones: 1
# Build Trident installer ISO (container)
- - template: stages/build_image/trident-testimg.yml
+ - template: stages/build_image/build-image.yml
parameters:
- imageName: build/trident-container-installer-testimage.iso
- outputArtifactName: trident-container-installer-testimage
+ imageName: trident-container-installer
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
runtimeEnv: "container"
micBuildType: ${{ parameters.micBuildType }}
micVersion: ${{ parameters.micVersion }}
+ clones: 1
# Build Trident test image (regular)
- - template: stages/build_image/trident-testimg.yml
+ - template: stages/build_image/build-image.yml
parameters:
- imageName: build/trident-testimage.cosi
- outputArtifactName: trident-testimage
+ imageName: trident-testimage
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
- mkcosiTemplate: "regular"
micBuildType: ${{ parameters.micBuildType }}
micVersion: ${{ parameters.micVersion }}
# Build Trident test image (container)
- - template: stages/build_image/trident-testimg.yml
+ - template: stages/build_image/build-image.yml
parameters:
- imageName: build/trident-container-testimage.cosi
- outputArtifactName: trident-container-testimage
+ imageName: trident-container-testimage
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
runtimeEnv: "container"
- mkcosiTemplate: "regular"
micBuildType: ${{ parameters.micBuildType }}
micVersion: ${{ parameters.micVersion }}
# Build Trident test image for verity (host)
- - template: stages/build_image/trident-testimg.yml
+ - template: stages/build_image/build-image.yml
parameters:
- imageName: build/trident-verity-testimage.cosi
- outputArtifactName: trident-verity-testimage
+ imageName: trident-verity-testimage
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
- mkcosiTemplate: "verity"
micBuildType: ${{ parameters.micBuildType }}
micVersion: ${{ parameters.micVersion }}
# Build Trident test image for verity (container)
- - template: stages/build_image/trident-testimg.yml
+ - template: stages/build_image/build-image.yml
+ parameters:
+ imageName: trident-container-verity-testimage
+ baseimgBuildType: ${{ parameters.baseimgBuildType }}
+ baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
+ runtimeEnv: "container"
+ micBuildType: ${{ parameters.micBuildType }}
+ micVersion: ${{ parameters.micVersion }}
+
+ # Build Trident test image for usr-verity (host)
+ - template: stages/build_image/build-image.yml
parameters:
- imageName: build/trident-container-verity-testimage.cosi
- outputArtifactName: trident-container-verity-testimage
+ imageName: trident-usrverity-testimage
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
+ micBuildType: ${{ parameters.micBuildType }}
+ micVersion: ${{ parameters.micVersion }}
+
+ # Build Trident test image for usr-verity (container)
+ - template: stages/build_image/build-image.yml
+ parameters:
+ imageName: trident-container-usrverity-testimage
runtimeEnv: "container"
- mkcosiTemplate: "verity"
+ baseimgBuildType: ${{ parameters.baseimgBuildType }}
+ baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
micBuildType: ${{ parameters.micBuildType }}
micVersion: ${{ parameters.micVersion }}
@@ -263,6 +287,8 @@ stages:
- ${{ if eq(parameters.stageType, 'ci') }}:
# Functional Testing
- template: stages/testing_functional/functional-testing.yml
+ parameters:
+ downloadPrebuiltImage: false
# VM Testing (host, post_merge)
- template: stages/testing_vm/netlaunch-testing.yml
@@ -281,7 +307,7 @@ stages:
# Functional Testing (short version)
- template: stages/testing_functional/functional-testing.yml
parameters:
- buildPurpose: "validation"
+ rerunTests: false
# VM Testing (host, pullrequest)
- template: stages/testing_vm/netlaunch-testing.yml
diff --git a/.pipelines/templates/stages/build_docker_image/trident-container.yml b/.pipelines/templates/stages/build_docker_image/trident-container.yml
index 710036ee4..40cc7ae13 100644
--- a/.pipelines/templates/stages/build_docker_image/trident-container.yml
+++ b/.pipelines/templates/stages/build_docker_image/trident-container.yml
@@ -28,6 +28,8 @@ stages:
ob_artifactBaseName: "trident-docker-image"
steps:
+ - template: ../common_tasks/avoid-pypi-usage.yml
+
- script: |
set -eux
mkdir -p bin/RPMS
diff --git a/.pipelines/templates/stages/build_image/trident-testimg.yml b/.pipelines/templates/stages/build_image/build-image.yml
similarity index 62%
rename from .pipelines/templates/stages/build_image/trident-testimg.yml
rename to .pipelines/templates/stages/build_image/build-image.yml
index 833cd05e5..205474fa9 100644
--- a/.pipelines/templates/stages/build_image/trident-testimg.yml
+++ b/.pipelines/templates/stages/build_image/build-image.yml
@@ -2,9 +2,6 @@ parameters:
- name: imageName
type: string
- - name: outputArtifactName
- type: string
-
- name: baseimgBuildType
displayName: Base Image build type
type: string
@@ -27,21 +24,13 @@ parameters:
- host
- container
- - name: mkcosiTemplate
- type: string
- default: "none"
- values:
- - none
- - regular
- - verity
-
- name: micBuildType
displayName: MIC Build Type
type: string
values:
- - dev
- - preview
- - release
+ - dev
+ - preview
+ - release
default: release
- name: micVersion
@@ -49,12 +38,20 @@ parameters:
type: string
default: "*.*.*"
+ - name: clones
+ displayName: "Number of clones to generate"
+ type: number
+ default: 2
+
+ - name: dependsOnTrident
+ type: boolean
+ default: true
stages:
- - stage: TridentTestImg_${{ replace(parameters.outputArtifactName, '-', '_') }}
- displayName: Build ${{ parameters.outputArtifactName }}
+ - stage: TridentTestImg_${{ replace(parameters.imageName, '-', '_') }}
+ displayName: Build ${{ parameters.imageName }}
dependsOn:
- - ${{ if eq(parameters.runtimeEnv, 'host') }}:
+ - ${{ if and(eq(parameters.runtimeEnv, 'host'), parameters.dependsOnTrident) }}:
- GetTridentBinaries_rpms
- ${{ else }}: []
@@ -66,15 +63,12 @@ stages:
type: linux
variables:
- ob_outputDirectory: $(Pipeline.Workspace)/s/test-images/output
- ob_artifactBaseName: ${{ parameters.outputArtifactName }}
+ ob_outputDirectory: $(Pipeline.Workspace)/s/output
+ ob_artifactBaseName: ${{ parameters.imageName }}
BASEIMG_AZURE_LINUX_VERSION: "3.0"
steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
+ - template: ../common_tasks/avoid-pypi-usage.yml
- task: DownloadPipelineArtifact@2
inputs:
@@ -82,21 +76,19 @@ stages:
artifactName: trident-binaries
targetPath: "$(Build.ArtifactStagingDirectory)/trident"
displayName: Download Trident RPMs
- condition: eq('${{ parameters.runtimeEnv }}', 'host')
+ condition: and(eq('${{ parameters.runtimeEnv }}', 'host'), eq('${{ parameters.dependsOnTrident }}', true))
- template: ../common_tasks/find-base-image-version.yml
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
- - template: .pipelines/templates/trident-testimg-template.yml@test-images
+ - template: .pipelines/templates/build-image.yml@test-images
parameters:
- target: ${{ parameters.imageName }}
- outputDirectory: ${{ variables.ob_outputDirectory }}
- testImagesRepo: test-images
- micBuildType: ${{ parameters.micBuildType }}
- micVersion: ${{ parameters.micVersion }}
+ imageName: ${{ parameters.imageName }}
+ clones: ${{ parameters.clones }}
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseimgVersion: $(baseimgVersion)
- baseimgAzureLinuxVersion: ${{ variables.BASEIMG_AZURE_LINUX_VERSION }}
- downloadTrident: false
+ azureLinuxVersion: ${{ variables.BASEIMG_AZURE_LINUX_VERSION }}
+ micBuildType: ${{ parameters.micBuildType }}
+ micVersion: ${{ parameters.micVersion }}
diff --git a/.pipelines/templates/stages/building_tools/building-tools.yml b/.pipelines/templates/stages/building_tools/building-tools.yml
index 2bc80fbc0..ff5e6c694 100644
--- a/.pipelines/templates/stages/building_tools/building-tools.yml
+++ b/.pipelines/templates/stages/building_tools/building-tools.yml
@@ -37,10 +37,7 @@ stages:
ob_artifactBaseName: go-tools
steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
+ - template: ../common_tasks/avoid-pypi-usage.yml
- ${{ if eq(parameters.buildNetlaunch, true) }}:
- bash: |
diff --git a/.pipelines/templates/stages/common_tasks/avoid-pypi-usage.yml b/.pipelines/templates/stages/common_tasks/avoid-pypi-usage.yml
new file mode 100644
index 000000000..2059ce9c1
--- /dev/null
+++ b/.pipelines/templates/stages/common_tasks/avoid-pypi-usage.yml
@@ -0,0 +1,7 @@
+steps:
+ - task: PipAuthenticate@1
+ displayName: Provision - Authenticate Pip
+ inputs:
+ artifactFeeds: "mariner/Mariner-Pypi-Feed"
+
+ - template: common/sfi-enforce-isolation-with-etc-hosts.yaml@platform-pipelines
diff --git a/.pipelines/templates/stages/common_tasks/build-osmodifier.yml b/.pipelines/templates/stages/common_tasks/build-osmodifier.yml
index 8a087ee7a..0da3f8d3b 100644
--- a/.pipelines/templates/stages/common_tasks/build-osmodifier.yml
+++ b/.pipelines/templates/stages/common_tasks/build-osmodifier.yml
@@ -1,4 +1,18 @@
steps:
+ - bash: |
+ set -ex
+ if command -v tdnf; then
+ # Use msft-golang since it has latest versions supported
+ sudo tdnf remove golang -y
+ sudo tdnf install msft-golang -y
+ else
+ sudo snap install --classic go
+ fi
+
+ # Verify installation
+ go version
+ displayName: "Install golang to build Image Customizer"
+ retryCountOnTaskFailure: 3
- bash: |
set -ex
git submodule init
diff --git a/.pipelines/templates/stages/common_tasks/os-info.yml b/.pipelines/templates/stages/common_tasks/os-info.yml
new file mode 100644
index 000000000..629770f61
--- /dev/null
+++ b/.pipelines/templates/stages/common_tasks/os-info.yml
@@ -0,0 +1,30 @@
+steps:
+ - script: |
+ echo "OS RELEASE:"
+ cat /etc/os-release
+ echo "KERNEL RELEASE:"
+ uname -r
+
+ echo ""
+ echo "Installed packages:"
+ echo "====================="
+ if command -v rpm; then
+ echo "Installed RPMs:"
+ rpm -qa
+ fi
+
+ if command -v dpkg; then
+ echo "Installed DEBs:"
+ dpkg -l
+ fi
+
+ displayName: os-release
+ - script: |
+ echo "CPU Info:"
+ echo "N proc: $(nproc)"
+ lscpu
+ echo "Memory:"
+ free -h
+ echo "Disk space:"
+ df -h
+ displayName: system-info
diff --git a/.pipelines/templates/stages/download_artifacts/get-artifacts.yml b/.pipelines/templates/stages/download_artifacts/get-artifacts.yml
index 7dd7f3361..761d8c975 100644
--- a/.pipelines/templates/stages/download_artifacts/get-artifacts.yml
+++ b/.pipelines/templates/stages/download_artifacts/get-artifacts.yml
@@ -195,14 +195,14 @@ stages:
targetPath: "$(System.ArtifactsDirectory)/container/"
- job: TridentContainerInstallerTestimage
- displayName: Download trident-container-installer-testimage
+ displayName: Download trident-container-installer
timeoutInMinutes: 10
pool:
type: linux
variables:
ob_outputDirectory: $(Build.SourcesDirectory)/build
- ob_artifactBaseName: "trident-container-installer-testimage"
+ ob_artifactBaseName: "trident-container-installer"
steps:
- task: DownloadPipelineArtifact@2
@@ -264,17 +264,40 @@ stages:
artifactName: $(ob_artifactBaseName)
targetPath: $(ob_outputDirectory)
+ - job: TridentContainerUsrVerityTestimage
+ displayName: "Download trident-container-usrverity-testimage"
+ timeoutInMinutes: 10
+ pool:
+ type: linux
+
+ variables:
+ ob_outputDirectory: $(Build.SourcesDirectory)/build
+ ob_artifactBaseName: "trident-container-usrverity-testimage"
+
+ steps:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ source: specific
+ project: "ECF"
+ definition: ${{ parameters.definition }}
+ runVersion: ${{ parameters.runVersion }}
+ branchName: "refs/heads/${{ parameters.branch }}"
+ runId: ${{ parameters.tridentPipelineRunId }}
+ allowFailedBuilds: ${{ parameters.allowFailedBuilds }}
+ artifactName: $(ob_artifactBaseName)
+ targetPath: $(ob_outputDirectory)
+
# Host images:
- ${{ if eq(parameters.hostImages, true) }}:
- job: TridentInstallerTestimage
- displayName: Download trident-installer-testimage
+ displayName: Download trident-installer
timeoutInMinutes: 10
pool:
type: linux
variables:
ob_outputDirectory: $(Build.SourcesDirectory)/build
- ob_artifactBaseName: "trident-installer-testimage"
+ ob_artifactBaseName: "trident-installer"
steps:
- task: DownloadPipelineArtifact@2
@@ -291,14 +314,14 @@ stages:
targetPath: $(ob_outputDirectory)
- job: TridentSplitInstallerTestimage
- displayName: Download trident-split-installer-testimage
+ displayName: Download trident-split-installer
timeoutInMinutes: 10
pool:
type: linux
variables:
ob_outputDirectory: $(Build.SourcesDirectory)/build
- ob_artifactBaseName: "trident-split-installer-testimage"
+ ob_artifactBaseName: "trident-split-installer"
steps:
- task: DownloadPipelineArtifact@2
@@ -359,3 +382,26 @@ stages:
allowFailedBuilds: ${{ parameters.allowFailedBuilds }}
artifactName: $(ob_artifactBaseName)
targetPath: $(ob_outputDirectory)
+
+ - job: TridentUsrVerityTestimage
+ displayName: "Download trident-usrverity-testimage"
+ timeoutInMinutes: 10
+ pool:
+ type: linux
+
+ variables:
+ ob_outputDirectory: $(Build.SourcesDirectory)/build
+ ob_artifactBaseName: "trident-usrverity-testimage"
+
+ steps:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ source: specific
+ project: "ECF"
+ definition: ${{ parameters.definition }}
+ runVersion: ${{ parameters.runVersion }}
+ branchName: "refs/heads/${{ parameters.branch }}"
+ runId: ${{ parameters.tridentPipelineRunId }}
+ allowFailedBuilds: ${{ parameters.allowFailedBuilds }}
+ artifactName: $(ob_artifactBaseName)
+ targetPath: $(ob_outputDirectory)
diff --git a/.pipelines/templates/stages/publishing/publish.yml b/.pipelines/templates/stages/publishing/publish.yml
index 5ecf9d894..1899d3303 100644
--- a/.pipelines/templates/stages/publishing/publish.yml
+++ b/.pipelines/templates/stages/publishing/publish.yml
@@ -26,6 +26,7 @@ stages:
- DeploymentTesting_container
- FunctionalTesting
- BaremetalDeploymentTesting_host
+ - BaremetalDeploymentTesting_container
- ServicingTesting
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main') )
diff --git a/.pipelines/templates/stages/testing_baremetal/baremetal-testing.yml b/.pipelines/templates/stages/testing_baremetal/baremetal-testing.yml
index 903916dc2..cc60ed21e 100644
--- a/.pipelines/templates/stages/testing_baremetal/baremetal-testing.yml
+++ b/.pipelines/templates/stages/testing_baremetal/baremetal-testing.yml
@@ -40,13 +40,15 @@ stages:
- BuildingTools
- ${{ if eq(parameters.runtimeEnv, 'container') }}:
- BuildTridentContainerImage
- - TridentTestImg_trident_container_installer_testimage
+ - TridentTestImg_trident_container_installer
- TridentTestImg_trident_container_testimage
- TridentTestImg_trident_container_verity_testimage
+ - TridentTestImg_trident_container_usrverity_testimage
- ${{ else }}:
- TridentTestImg_trident_verity_testimage
- - TridentTestImg_trident_installer_testimage
+ - TridentTestImg_trident_installer
- TridentTestImg_trident_testimage
+ - TridentTestImg_trident_usrverity_testimage
jobs:
- template: ../testing_common/get-tests.yml
@@ -83,6 +85,7 @@ stages:
- name: BAREMETAL_LAB_CANARY_IP
value: "10.8.6.1"
+ # Sourced from the matrix
- name: TRIDENT_CONFIGURATION_NAME
value: $(configuration)
@@ -106,9 +109,9 @@ stages:
- name: INSTALLER_ISO_NAME
${{ if eq(parameters.runtimeEnv, 'container') }}:
- value: "trident-container-installer-testimage"
+ value: "trident-container-installer"
${{ else }}:
- value: "trident-installer-testimage"
+ value: "trident-installer"
- name: IMAGE_NAME
${{ if eq(parameters.runtimeEnv, 'container') }}:
@@ -122,6 +125,12 @@ stages:
${{ else }}:
value: "trident-verity-testimage"
+ - name: USRVERITY_IMAGE_NAME
+ ${{ if eq(parameters.runtimeEnv, 'container') }}:
+ value: "trident-container-usrverity-testimage"
+ ${{ else }}:
+ value: "trident-usrverity-testimage"
+
- group: baremetal_controller
steps:
@@ -165,6 +174,7 @@ stages:
installerISO: ${{ variables.INSTALLER_ISO_NAME }}
tridentTestImage: ${{ variables.IMAGE_NAME }}
tridentTestImageVerity: ${{ variables.VERITY_IMAGE_NAME }}
+ tridentTestImageUsrVerity: ${{ variables.USRVERITY_IMAGE_NAME }}
${{ if eq(parameters.runtimeEnv, 'container') }}:
downloadTridentContainer: true
@@ -264,6 +274,17 @@ stages:
displayName: "Output serial log"
condition: always()
+ - bash: |
+ set -eux
+ ./bin/storm-trident helper boot-metrics \
+ "$(Build.SourcesDirectory)/e2e_tests/helpers/key" \
+ "${{ variables.BAREMETAL_OAM_IP }}" \
+ "testing-user" \
+ "${{ parameters.runtimeEnv }}" \
+ --metrics-file $(TRIDENT_SOURCE_DIR)/trident-clean-install-metrics.jsonl \
+ --metrics-operation install
+ displayName: "Create boot metrics for booting into runtime OS"
+
- template: ../testing_common/trident-metrics.yml
parameters:
tridentSourceDirectory: $(TRIDENT_SOURCE_DIR)
diff --git a/.pipelines/templates/stages/testing_baremetal/update_host_config.py b/.pipelines/templates/stages/testing_baremetal/update_host_config.py
index 7dbf00be5..8e2ce5f0b 100755
--- a/.pipelines/templates/stages/testing_baremetal/update_host_config.py
+++ b/.pipelines/templates/stages/testing_baremetal/update_host_config.py
@@ -9,54 +9,118 @@
def update_trident_host_config(
- host_configuration: str,
- oam_ip: str,
+ *,
+ host_configuration: dict,
interface_name: str,
- oam_gateway: Optional[str] = None,
- oam_mac: Optional[str] = None,
+ interface_ip: str,
+ interface_mac: Optional[str] = None,
+ network_gateway: Optional[str] = None,
use_dhcp: bool = False,
):
logging.info("Updating host config section of trident.yaml")
- logging.info("oam_ip: %s", oam_ip)
- logging.info("oam_gateway: %s", oam_gateway)
os = host_configuration.setdefault("os", {})
- network = os.setdefault("network", {})
- ethernets = network.setdefault("ethernets", {})
- # Ensure that all interface dhcp4 settings are consistent
- for ethernet in ethernets:
- if "dhcp4" in ethernets[ethernet]:
- ethernets[ethernet]["dhcp4"] = use_dhcp
-
- eno_interface = ethernets.setdefault(interface_name, {})
+ main_interface = {
+ "addresses": [f"{interface_ip}/23"],
+ "dhcp4": use_dhcp,
+ "set-name": interface_name,
+ }
# Temporary fix for #8837.
- if oam_mac:
- eno_interface["match"] = {"macaddress": oam_mac}
-
- eno_interface.setdefault("addresses", []).append(oam_ip + "/23")
- eno_interface["dhcp4"] = use_dhcp
- if oam_gateway:
- eno_interface.setdefault("routes", []).append(
- {"to": "0.0.0.0/0", "via": oam_gateway}
+ if interface_mac:
+ main_interface["match"] = {"macaddress": interface_mac}
+
+ if network_gateway:
+ main_interface.setdefault("routes", []).append(
+ {"to": "0.0.0.0/0", "via": network_gateway}
)
+ # Override network to only preserve the eno interface.
+ os["network"] = {
+ "version": 2,
+ "ethernets": {
+ interface_name: main_interface,
+ },
+ }
+
+ # Name of the wait online service for this interface
+ wait_online_service = f"systemd-networkd-wait-online@{interface_name}.service"
+
+ # Enable systemd-networkd-wait-online service for the interface.
+ enable_services = os.setdefault("services", {}).setdefault("enable", [])
+ if wait_online_service not in enable_services:
+ enable_services.append(wait_online_service)
+
+ # Add an override for the trident service to wait for the network
+ # interface to be online before starting.
+ os.setdefault("additionalFiles", []).append(
+ {
+ "destination": "/etc/systemd/system/trident.service.d/override.conf",
+ "content": "[Unit]\n"
+ f"Requires={wait_online_service}\n"
+ f"After={wait_online_service}\n",
+ }
+ )
+
logging.info("Updating os disks device in trident.yaml")
- disks = host_configuration.get("storage", {}).get("disks", [])
+ disks = host_configuration.get("storage").get("disks")
for disk in disks:
if disk["id"] == "os":
disk["device"] = "/dev/sda"
elif disk["id"] == "disk2":
disk["device"] = "/dev/sdb"
- internal_params = host_configuration.setdefault("internalParams", {})
- internal_params["waitForSystemdNetworkd"] = True
+ # If this is root verity, we need to set an internal param to be able to
+ # configure the network.
+ if is_root_verity(host_configuration):
+ logging.info(
+ "Detected root verity configuration, setting 'writableEtcOverlayHooks' internal param."
+ )
+ host_configuration.setdefault("internalParams", {})[
+ "writableEtcOverlayHooks"
+ ] = True
logging.info(
"Final trident_yaml content post all the updates: %s", host_configuration
)
+def is_root_verity(host_configuration: dict) -> bool:
+ """
+ Check if the host configuration is using root verity.
+ """
+
+ verity_config = host_configuration.get("storage", {}).get("verity", [])
+ if len(verity_config) == 0:
+ return False
+
+ if len(verity_config) > 1:
+ raise ValueError("Multiple verity configurations found, expected only one.")
+
+ verity = verity_config[0]
+ verity_id = verity.get("id")
+
+ filesystems = host_configuration.get("storage", {}).get("filesystems", [])
+ verity_filesystem = None
+ for fs in filesystems:
+ if fs.get("deviceId") == verity_id:
+ verity_filesystem = fs
+ break
+
+ if verity_filesystem is None:
+ return False
+
+ mount_point = verity_filesystem.get("mountPoint")
+ if mount_point is None:
+ return False
+ if isinstance(mount_point, str):
+ return mount_point == "/"
+ if isinstance(mount_point, dict):
+ return mount_point.get("path") == "/"
+
+ return False
+
+
def main():
logging.basicConfig(
level=logging.INFO,
@@ -84,20 +148,28 @@ def main():
"--oam-mac", default=None, help="MAC address of the OAM interface."
)
parser.add_argument("--use-dhcp", default=False, help="Configure DHCP.")
+ parser.add_argument(
+ "-o",
+ "--output",
+ default=None,
+ help="Output file path. Defaults to editing the input file.",
+ )
args = parser.parse_args()
with open(args.trident_yaml) as f:
trident_yaml_content = yaml.safe_load(f)
update_trident_host_config(
- trident_yaml_content,
- args.oam_ip,
- args.interface_name,
- args.oam_gateway,
- args.oam_mac,
- args.use_dhcp,
+ host_configuration=trident_yaml_content,
+ interface_name=args.interface_name,
+ interface_ip=args.oam_ip,
+ interface_mac=args.oam_mac,
+ network_gateway=args.oam_gateway,
+ use_dhcp=args.use_dhcp,
)
- with open(args.trident_yaml, "w") as f:
+
+ output_path = args.output or args.trident_yaml
+ with open(output_path, "w") as f:
yaml.dump(trident_yaml_content, f, default_flow_style=False)
diff --git a/.pipelines/templates/stages/testing_common/download-test-images.yml b/.pipelines/templates/stages/testing_common/download-test-images.yml
index 08f0a8edb..a5e5e8107 100644
--- a/.pipelines/templates/stages/testing_common/download-test-images.yml
+++ b/.pipelines/templates/stages/testing_common/download-test-images.yml
@@ -2,13 +2,13 @@ parameters:
- name: installerISO
displayName: "Image used for the installer, source of Trident (container vs host)"
type: string
- default: trident-installer-testimage
+ default: trident-installer
# Test selection is at runtime, and template parameters cannot be validated against runtime variables.
# So, do validation in task below rather than specifying this here:
# values:
- # - trident-installer-testimage
- # - trident-split-installer-testimage
- # - trident-container-installer-testimage
+ # - trident-installer
+ # - trident-split-installer
+ # - trident-container-installer
- name: tridentTestImage
displayName: "Image used the runtime OS, source of Trident (container vs host)"
@@ -26,6 +26,14 @@ parameters:
- trident-verity-testimage
- trident-container-verity-testimage
+ - name: tridentTestImageUsrVerity
+ displayName: "Image used the verity runtime OS, source of Trident (container vs host)"
+ type: string
+ default: trident-usrverity-testimage
+ values:
+ - trident-usrverity-testimage
+ - trident-container-usrverity-testimage
+
- name: downloadTridentContainer
displayName: "Download Trident container"
type: boolean
@@ -51,6 +59,10 @@ parameters:
type: string
default: "$(System.ArtifactsDirectory)/verity-testimage"
+ - name: testImageDirUsrVerity
+ type: string
+ default: "$(System.ArtifactsDirectory)/usrverity-testimage"
+
steps:
- bash: |
set -eux
@@ -59,11 +71,11 @@ steps:
# So, do validation here.
#
case "${{ parameters.installerISO }}" in
- trident-installer-testimage|trident-split-installer-testimage|trident-container-installer-testimage)
+ trident-installer|trident-split-installer|trident-container-installer)
# Valid image_type, do nothing
;;
*)
- echo "installerISO should be either 'trident-installer-testimage', 'trident-split-installer-testimage', or 'trident-container-installer-testimage'."
+ echo "installerISO should be either 'trident-installer', 'trident-split-installer', or 'trident-container-installer'."
exit 1
;;
esac
@@ -100,6 +112,13 @@ steps:
artifactName: "${{ parameters.tridentTestImageVerity }}"
targetPath: "${{ parameters.testImageDirVerity }}"
+ - task: DownloadPipelineArtifact@2
+ displayName: "Download ${{ parameters.tridentTestImageUsrVerity }}"
+ inputs:
+ buildType: current
+ artifactName: "${{ parameters.tridentTestImageUsrVerity }}"
+ targetPath: "${{ parameters.testImageDirUsrVerity }}"
+
- task: DownloadPipelineArtifact@2
displayName: "Download go-tools"
inputs:
@@ -113,6 +132,14 @@ steps:
targetPath: "${{ parameters.toolsDirectory }}"
- bash: |
+ # Debug log
+ echo "REGULAR IMAGES:"
+ ls -alh "${{ parameters.testImageDir }}"
+
+ echo ""
+ echo "VERITY IMAGES:"
+ ls -alh "${{ parameters.testImageDirVerity }}"
+
set -eux
# Set tools to be executable
@@ -120,18 +147,17 @@ steps:
chmod +x ${{ parameters.toolsDirectory }}/mkcosi
chmod +x ${{ parameters.toolsDirectory }}/storm-trident
- # Create the target directory
- mkdir -p "${{ parameters.targetDirectory }}"
-
- # If testImageDir is not an empty string, rename the Trident test images
- if [ -n "${{ parameters.testImageDir }}" ]; then
- mv "${{ parameters.testImageDir }}/${{ parameters.tridentTestImage }}.cosi" "${{ parameters.targetDirectory }}/regular.cosi"
- fi
-
- # If testImageDirVerity is not an empty string, rename the Trident verity test images
- if [ -n "${{ parameters.testImageDirVerity }}" ]; then
- mv "${{ parameters.testImageDirVerity }}/${{ parameters.tridentTestImageVerity }}.cosi" "${{ parameters.targetDirectory }}/verity.cosi"
- fi
+ # Call helper to copy and rename images!
+ ${{ parameters.toolsDirectory }}/storm-trident \
+ helper prepare-images -a -- \
+ "${{ parameters.testImageDir }}" \
+ "${{ parameters.testImageDirVerity }}" \
+ "${{ parameters.testImageDirUsrVerity }}" \
+ "${{ parameters.tridentTestImage }}" \
+ "${{ parameters.tridentTestImageVerity }}" \
+ "${{ parameters.tridentTestImageUsrVerity }}" \
+ "${{ parameters.targetDirectory }}" \
+ -v 4
# List tools in the target directory
ls -lh "${{ parameters.toolsDirectory }}"
diff --git a/.pipelines/templates/stages/testing_common/e2e-ab-update-stage-finalize-test-run.yml b/.pipelines/templates/stages/testing_common/e2e-ab-update-stage-finalize-test-run.yml
index 71d801870..9a16a1788 100644
--- a/.pipelines/templates/stages/testing_common/e2e-ab-update-stage-finalize-test-run.yml
+++ b/.pipelines/templates/stages/testing_common/e2e-ab-update-stage-finalize-test-run.yml
@@ -53,31 +53,21 @@ parameters:
default: 4000
steps:
- - bash: |
- set -eux
- "$(Build.SourcesDirectory)/.pipelines/templates/stages/testing_common/scripts/transfer-update-os-image.sh" \
- "${{ parameters.sshKeyPath }}" \
- "${{ parameters.userName }}" \
- "${{ parameters.hostIp }}" \
- "${{ parameters.artifactsDirectory }}" \
- "$(destinationDirectory)" \
- "$(version)" \
- "$(verityRequired)"
- displayName: "Transfer updated OS image to the host for A/B update testing"
- condition: and(succeeded(), ne(variables['abActiveVolume'], 'null'))
-
- bash: |
set -eux
# If there is a netlisten process, kill it so there is no port clash in the instance
if pgrep netlisten > /dev/null; then pkill netlisten; fi
- ./bin/netlisten -m $(Build.SourcesDirectory)/trident-stage-update-metrics.jsonl -p ${{ parameters.netlistenPort }} > ./stage-ab-update-deployment.log 2>&1 &
+
+ ./bin/netlisten -m $(Build.SourcesDirectory)/trident-stage-update-metrics.jsonl \
+ -p ${{ parameters.netlistenPort }} \
+ -s "${{ parameters.artifactsDirectory }}" > ./stage-ab-update-deployment.log 2>&1 &
+
echo "Running script to stage A/B update..."
./bin/storm-trident helper ab-update \
"${{ parameters.sshKeyPath }}" \
"${{ parameters.hostIp }}" \
"${{ parameters.userName }}" \
"${{ parameters.runtimeEnv }}" \
- --destination-directory $(destinationDirectory) \
--trident-config $(tridentConfigFile) \
--version $(version) \
--stage-ab-update
@@ -123,14 +113,16 @@ steps:
set -eux
# If there is a netlisten process, kill it so there is no port clash in the instance
if pgrep netlisten > /dev/null; then pkill netlisten; fi
- ./bin/netlisten -m $(Build.SourcesDirectory)/trident-finalize-update-metrics.jsonl -p ${{ parameters.netlistenPort }} > ./finalize-ab-update.log 2>&1 &
+ ./bin/netlisten -m $(Build.SourcesDirectory)/trident-finalize-update-metrics.jsonl \
+ -p ${{ parameters.netlistenPort }} \
+ -s "${{ parameters.artifactsDirectory }}" > ./finalize-ab-update.log 2>&1 &
+
echo "Running script to finalize A/B update..."
./bin/storm-trident helper ab-update \
"${{ parameters.sshKeyPath }}" \
"${{ parameters.hostIp }}" \
"${{ parameters.userName }}" \
"${{ parameters.runtimeEnv }}" \
- --destination-directory $(destinationDirectory) \
--trident-config $(tridentConfigFile) \
--version $(version) \
--finalize-ab-update
@@ -160,6 +152,18 @@ steps:
displayName: "đ¤ Check SSH connection after booting into runtime OS B"
condition: and(succeeded(), ne(variables['abActiveVolume'], 'null'))
+ - bash: |
+ set -eux
+ ./bin/storm-trident helper boot-metrics \
+ "${{ parameters.sshKeyPath }}" \
+ "${{ parameters.hostIp }}" \
+ "${{ parameters.userName }}" \
+ "${{ parameters.runtimeEnv }}" \
+ --metrics-file $(Build.SourcesDirectory)/trident-finalize-update-metrics.jsonl \
+ --metrics-operation update1
+ displayName: "Create boot metrics for booting into runtime OS B"
+ condition: and(succeeded(), ne(variables['abActiveVolume'], 'null'))
+
- template: ../testing_common/trident-metrics.yml
parameters:
tridentSourceDirectory: $(Build.SourcesDirectory)
diff --git a/.pipelines/templates/stages/testing_common/e2e-test-run.yml b/.pipelines/templates/stages/testing_common/e2e-test-run.yml
index 3273765d2..42edc1809 100644
--- a/.pipelines/templates/stages/testing_common/e2e-test-run.yml
+++ b/.pipelines/templates/stages/testing_common/e2e-test-run.yml
@@ -75,25 +75,6 @@ steps:
workingDirectory: $(Build.SourcesDirectory)/e2e_tests
displayName: "Check if Trident config requires A/B update testing"
- # Check if Trident config uses verity. If yes, we need to copy the verity COSI
- # to a writable directory /run on the VM. Otherwise, copy the regular COSI to
- # /abupdate.
- - bash: |
- set -eu
- verityRequired=$(sudo yq e '.storage.verity != null' "${{ parameters.tridentConfigPath }}/trident-config.yaml")
- if [ "$verityRequired" == "true" ]; then
- echo "Trident config requires verity runtime OS images"
- echo "##vso[task.setvariable variable=verityRequired]true"
- echo "##vso[task.setvariable variable=destinationDirectory]/run"
- else
- echo "Trident config does not require verity runtime OS images"
- echo "##vso[task.setvariable variable=verityRequired]false"
- echo "##vso[task.setvariable variable=destinationDirectory]/abupdate"
- fi
- workingDirectory: $(Build.SourcesDirectory)/e2e_tests
- displayName: "Check if Trident config requires verity runtime OS images"
- condition: and(succeeded(), ne(variables['abActiveVolume'], 'null'))
-
- bash: |
$(Build.SourcesDirectory)/bin/storm-trident helper check-ssh \
"${{ parameters.sshKeyPath }}" \
@@ -123,20 +104,6 @@ steps:
testRunTitle: ${{ parameters.deploymentEnvironment }}_trident_e2e_tests_${{ parameters.tridentConfigurationName }}_clean_install_$(System.JobAttempt)
displayName: "Publish test results for clean install of runtime OS"
- - bash: |
- set -eux
- chmod +x $(Build.SourcesDirectory)/.pipelines/templates/stages/testing_common/scripts/transfer-update-os-image.sh
- "$(Build.SourcesDirectory)/.pipelines/templates/stages/testing_common/scripts/transfer-update-os-image.sh" \
- "${{ parameters.sshKeyPath }}" \
- "${{ parameters.userName }}" \
- "${{ parameters.hostIp }}" \
- "${{ parameters.artifactsDirectory }}" \
- "$(destinationDirectory)" \
- "$(version)" \
- "$(verityRequired)"
- displayName: "Transfer update OS image to the host for A/B update testing"
- condition: and(succeeded(), ne(variables['abActiveVolume'], 'null'))
-
# If current config requires A/B update testing, execute script to ssh into the host, update
# images in the custom Trident config, and re-run Trident to both stage and finalize A/B update.
- bash: |
@@ -144,6 +111,7 @@ steps:
./bin/netlisten --force-color \
-m $(Build.SourcesDirectory)/trident-ab-update-metrics-runtime-os-B.jsonl \
--full-logstream ./logstream-full.log \
+ -s "${{ parameters.artifactsDirectory }}" \
-p ${{ parameters.netlistenPort }} > ./stage-finalize-ab-update-runtime-os-B.log 2>&1 &
echo "Running script to stage and finalize A/B update..."
@@ -152,7 +120,6 @@ steps:
"${{ parameters.hostIp }}" \
"${{ parameters.userName }}" \
"${{ parameters.runtimeEnv }}" \
- --destination-directory $(destinationDirectory) \
--trident-config $(tridentConfigFile) \
--version $(version) \
--stage-ab-update \
@@ -179,6 +146,18 @@ steps:
deploymentLogPath: $(Build.SourcesDirectory)/logstream-full.log
displayName: "đ [TRACE] Display A/B update deployment logs for runtime OS B"
+ - bash: |
+ set -eux
+ ./bin/storm-trident helper boot-metrics \
+ "${{ parameters.sshKeyPath }}" \
+ "${{ parameters.hostIp }}" \
+ "${{ parameters.userName }}" \
+ "${{ parameters.runtimeEnv }}" \
+ --metrics-file $(Build.SourcesDirectory)/trident-ab-update-metrics-runtime-os-B.jsonl \
+ --metrics-operation update1
+ displayName: "Create boot metrics for booting into runtime OS B"
+ condition: and(succeeded(), ne(variables['abActiveVolume'], 'null'))
+
- template: ../testing_common/trident-metrics.yml
parameters:
tridentSourceDirectory: $(Build.SourcesDirectory)
@@ -217,19 +196,6 @@ steps:
testRunTitle: ${{ parameters.deploymentEnvironment }}_trident_e2e_tests_${{ parameters.tridentConfigurationName }}_ab_update_B_$(System.JobAttempt)
displayName: "Publish test results for A/B update into runtime OS B"
- - bash: |
- set -eux
- "$(Build.SourcesDirectory)/.pipelines/templates/stages/testing_common/scripts/transfer-update-os-image.sh" \
- "${{ parameters.sshKeyPath }}" \
- "${{ parameters.userName }}" \
- "${{ parameters.hostIp }}" \
- "${{ parameters.artifactsDirectory }}" \
- "$(destinationDirectory)" \
- "$(version)" \
- "$(verityRequired)"
- displayName: "Transfer update OS image to the host for A/B update testing"
- condition: and(succeeded(), ne(variables['abActiveVolume'], 'null'))
-
- bash: |
set -eux
# If there is a netlisten process, kill it so there is no port clash in the instance
@@ -238,6 +204,7 @@ steps:
./bin/netlisten --force-color \
-m $(Build.SourcesDirectory)/trident-ab-update-metrics-runtime-os-A.jsonl \
--full-logstream ./logstream-full.log \
+ -s "${{ parameters.artifactsDirectory }}" \
-p ${{ parameters.netlistenPort }} > ./stage-finalize-ab-update-runtime-os-A.log 2>&1 &
echo "Running script to stage and finalize A/B update..."
@@ -246,7 +213,6 @@ steps:
"${{ parameters.hostIp }}" \
"${{ parameters.userName }}" \
"${{ parameters.runtimeEnv }}" \
- --destination-directory $(destinationDirectory) \
--trident-config $(tridentConfigFile) \
--version $(version) \
--stage-ab-update \
@@ -273,6 +239,18 @@ steps:
deploymentLogPath: $(Build.SourcesDirectory)/logstream-full.log
displayName: "đ [TRACE] Display A/B update deployment logs for runtime OS A"
+ - bash: |
+ set -eux
+ ./bin/storm-trident helper boot-metrics \
+ "${{ parameters.sshKeyPath }}" \
+ "${{ parameters.hostIp }}" \
+ "${{ parameters.userName }}" \
+ "${{ parameters.runtimeEnv }}" \
+ --metrics-file $(Build.SourcesDirectory)/trident-ab-update-metrics-runtime-os-A.jsonl \
+ --metrics-operation update2
+ displayName: "Create boot metrics for booting into runtime OS A"
+ condition: and(succeeded(), ne(variables['abActiveVolume'], 'null'))
+
- template: ../testing_common/trident-metrics.yml
parameters:
tridentSourceDirectory: $(Build.SourcesDirectory)
@@ -336,3 +314,4 @@ steps:
tridentSourceDirectory: $(Build.SourcesDirectory)
tridentConfigPath: ${{ parameters.tridentConfigPath }}
deploymentEnvironment: ${{ parameters.deploymentEnvironment }}
+ tridentConfigurationName: ${{ parameters.tridentConfigurationName }}
diff --git a/.pipelines/templates/stages/testing_common/get-tests.yml b/.pipelines/templates/stages/testing_common/get-tests.yml
index 349e2b62c..8f7bc15c5 100644
--- a/.pipelines/templates/stages/testing_common/get-tests.yml
+++ b/.pipelines/templates/stages/testing_common/get-tests.yml
@@ -35,17 +35,13 @@ jobs:
ob_artifactBaseName: select_tests_${{ parameters.deploymentEnvironment }}_${{ parameters.runtimeEnv }}_$(System.JobAttempt)
steps:
+ - template: ../common_tasks/avoid-pypi-usage.yml
- bash: |
- set -eux
- matrix=$(
- python3 ./e2e_tests/helpers/read_target_configurations.py \
- --configurations ./e2e_tests/target-configurations.yaml \
- --env ${{ parameters.deploymentEnvironment }} \
- --runtimeEnv ${{ parameters.runtimeEnv }} \
- --purpose ${{ parameters.buildPurpose }} \
- )
-
- set +x
- echo "##vso[task.setvariable variable=matrixConfigurations;isOutput=true]$matrix"
+ python3 ./e2e_tests/helpers/read_target_configurations.py \
+ --configurations ./e2e_tests/target-configurations.yaml \
+ --env ${{ parameters.deploymentEnvironment }} \
+ --runtimeEnv ${{ parameters.runtimeEnv }} \
+ --purpose ${{ parameters.buildPurpose }} \
+ --matrix-name matrixConfigurations
name: setConfigurations
displayName: Matrix of Trident configurations for E2E Tests
diff --git a/.pipelines/templates/stages/testing_common/scripts/transfer-update-os-image.sh b/.pipelines/templates/stages/testing_common/scripts/transfer-update-os-image.sh
deleted file mode 100644
index 6f8df0d13..000000000
--- a/.pipelines/templates/stages/testing_common/scripts/transfer-update-os-image.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-# transfer-update-os-image.sh
-
-set -eux
-
-# Arguments
-SSH_KEY_PATH=$1
-USER_NAME=$2
-HOST_IP=$3
-ARTIFACTS_DIR=$4
-DESTINATION_DIR=$5
-VERSION=$6
-VERITY_REQUIRED=$7
-
-# Define path to the COSI file
-COSI_FILE="$ARTIFACTS_DIR/regular.cosi"
-# Define path to the update COSI file, i.e. with randomized FS UUID required for A/B update testing
-UPDATE_COSI_FILE="$ARTIFACTS_DIR/regular-update.cosi"
-# Define path to the COSI file on the host
-HOST_COSI_FILE="$DESTINATION_DIR/regular_v$VERSION.cosi"
-
-# If needed, change the name/path of the COSI file based on verityRequired parameter
-if [ "$VERITY_REQUIRED" = "true" ]; then
- echo "Transferring verity COSI file onto the host"
- COSI_FILE="$ARTIFACTS_DIR/verity.cosi"
- UPDATE_COSI_FILE="$ARTIFACTS_DIR/verity-update.cosi"
- HOST_COSI_FILE="$DESTINATION_DIR/verity_v$VERSION.cosi"
-
- # Before transferring the COSI file, randomize the FS UUID
- ./bin/mkcosi randomize-fs-uuid "$COSI_FILE" "$UPDATE_COSI_FILE" /boot
-else
- echo "Transferring regular COSI file onto the host"
- # Create destination directory on the host
- ssh -o StrictHostKeyChecking=no -i "$SSH_KEY_PATH" "$USER_NAME"@"$HOST_IP" "sudo mkdir -p '$DESTINATION_DIR'"
-
- ./bin/mkcosi randomize-fs-uuid "$COSI_FILE" "$UPDATE_COSI_FILE" /
-fi
-
-# Prepare destination directory on the host
-ssh -o StrictHostKeyChecking=no -i "$SSH_KEY_PATH" "$USER_NAME"@"$HOST_IP" "sudo chown '$USER_NAME:$USER_NAME' '$DESTINATION_DIR' && sudo chmod 755 '$DESTINATION_DIR'"
-
-# SCP the file onto the host
-scp -o StrictHostKeyChecking=no -i "$SSH_KEY_PATH" "$UPDATE_COSI_FILE" "$USER_NAME"@"$HOST_IP":"$HOST_COSI_FILE"
-echo "Transferred COSI file to the host"
diff --git a/.pipelines/templates/stages/testing_common/trident-rebuild.yml b/.pipelines/templates/stages/testing_common/trident-rebuild.yml
index 247089fdc..466fd4dc1 100644
--- a/.pipelines/templates/stages/testing_common/trident-rebuild.yml
+++ b/.pipelines/templates/stages/testing_common/trident-rebuild.yml
@@ -31,11 +31,19 @@ parameters:
- bareMetal
- virtualMachine
+ - name: tridentConfigurationName
+ type: string
+
steps:
- bash: |
set -eu
+
+ # For some reason the file is owned by root, so sudo is needed to read it.
raidExists=$(sudo yq e '.storage.raid != null' "${{ parameters.tridentConfigPath }}/trident-config.yaml")
- if [ "$raidExists" == "true" ]; then
+ usrVerity=$(sudo yq e '.storage.verity[0].name == "usr"' "${{ parameters.tridentConfigPath }}/trident-config.yaml")
+
+ # TODO (12277): Support for UKI + Rebuild
+ if [ "$raidExists" == "true" ] && [ "$usrVerity" != "true" ]; then
echo "Trident config requires Rebuild testing"
echo "##vso[task.setvariable variable=TEST_REBUILD_RAID]True"
else
@@ -70,23 +78,6 @@ steps:
displayName: "Replace the test disk with a new disk"
condition: and(succeeded(),eq(variables['TEST_REBUILD_RAID'], 'True'))
- - bash: |
- set -eux
- echo "Dump the VM before boot order change."
- until sudo virsh dumpxml virtdeploy-vm-0; do
- sudo virsh list
- sleep 0.1
- done
- echo "Changing the boot order of the VM to boot from sda."
- python3 $(Build.SourcesDirectory)/.pipelines/templates/stages/testing_vm/update-vm-bootorder.py
- echo "Dump the VM after boot order change."
- until sudo virsh dumpxml virtdeploy-vm-0; do
- sudo virsh list
- sleep 0.1
- done
- displayName: "Change boot order"
- condition: and(succeeded(),eq(variables['TEST_REBUILD_RAID'], 'True'))
-
- bash: |
set -eux
diff --git a/.pipelines/templates/stages/testing_functional/functional-testing.yml b/.pipelines/templates/stages/testing_functional/functional-testing.yml
index a70f21b3c..fa3b95858 100644
--- a/.pipelines/templates/stages/testing_functional/functional-testing.yml
+++ b/.pipelines/templates/stages/testing_functional/functional-testing.yml
@@ -1,27 +1,30 @@
parameters:
- - name: testingRun
- displayName: "Download prebuilt test artifacts"
+ - name: downloadPrebuiltImage
+ displayName: "Download prebuilt base image"
type: boolean
- default: false
+ default: true
- - name: buildPurpose
+ - name: rerunTests
+ displayName: "Rerun functional tests on the same VM"
+ type: boolean
+ default: true
+
+ - name: functestImageArtifact
type: string
- default: "post_merge"
- values:
- - post_merge
- - validation
+ default: "trident-functest"
+
+ - name: functestImageArtifactPipeline
+ type: number
+ default: 3371 # trident-ci
+ displayName: Where to download prebuilt image from
stages:
- stage: FunctionalTesting
displayName: Functional Testing
dependsOn:
- - ${{ if eq(parameters.testingRun, true) }}:
- - DownloadTestingElements
- - ${{ else }}:
- - BuildingTools
- - TridentTestImg_trident_installer_testimage
- - TridentTestImg_trident_testimage
- - TridentTestImg_trident_verity_testimage
+ - ${{ if eq(parameters.downloadPrebuiltImage, false) }}:
+ - TridentTestImg_trident_functest
+ - ${{ else }}: []
jobs:
- job: FunctionalTests
@@ -34,7 +37,7 @@ stages:
variables:
ob_outputDirectory: $(Build.SourcesDirectory)/build
- argusToolkitSourceDirectory: $(Build.SourcesDirectory)/argus-toolkit
+ baseImageDirectory: "$(Build.SourcesDirectory)/artifacts"
steps:
- checkout: argus-toolkit
@@ -44,11 +47,27 @@ stages:
- template: ../common_tasks/cargo-auth.yml
- # Download all test images for host
- - template: ../testing_common/download-test-images.yml
-
- template: ../testing_vm/netlaunch-prep.yml
+ - ${{ if eq(parameters.downloadPrebuiltImage, false) }}:
+ - task: DownloadPipelineArtifact@2
+ displayName: "Download FT Image from current build"
+ inputs:
+ buildType: current
+ artifactName: "${{ parameters.functestImageArtifact }}"
+ targetPath: "${{ variables.baseImageDirectory }}"
+ - ${{ else }}:
+ - task: DownloadPipelineArtifact@2
+ displayName: "Download FT Image from latest build of ${{ parameters.functestImageArtifactPipeline}}"
+ inputs:
+ buildType: specific
+ project: "ECF"
+ definition: ${{ parameters.functestImageArtifactPipeline}}
+ buildVersionToDownload: latestFromBranch
+ branchName: "refs/heads/main"
+ artifactName: "${{ parameters.functestImageArtifact }}"
+ targetPath: "${{ variables.baseImageDirectory }}"
+
- bash: |
set -eux
@@ -58,6 +77,8 @@ stages:
displayName: Install dependencies
retryCountOnTaskFailure: 3
+ - template: ../common_tasks/build-osmodifier.yml
+
- bash: |
set -eux
@@ -78,7 +99,7 @@ stages:
# rebuilding the test binaries and invoking pytest. The regular
# target is meant for local use and does extra setup not required
# here.
- sg libvirt "make functional-test-core INSTALLER_ISO_PATH=./artifacts/iso/trident-installer-testimage.iso ARGUS_TOOLKIT_PATH=argus-toolkit"
+ sg libvirt "make functional-test-core ARGUS_TOOLKIT_PATH=argus-toolkit"
displayName: Execute Functional Tests
- template: ../common_tasks/coverage.yml
@@ -97,6 +118,6 @@ stages:
- bash: |
set -eux
- sg libvirt "make patch-functional-test INSTALLER_ISO_PATH=$(System.ArtifactsDirectory)/trident-installer-testimg.iso ARGUS_TOOLKIT_PATH=argus-toolkit"
- condition: and(succeeded(), eq('${{ parameters.buildPurpose }}', 'post_merge'))
+ sg libvirt "make patch-functional-test ARGUS_TOOLKIT_PATH=argus-toolkit"
+ condition: and(succeeded(), eq('${{ parameters.rerunTests }}', 'true'))
displayName: Rerun Functional Tests
diff --git a/.pipelines/templates/stages/testing_servicing/build-image.yml b/.pipelines/templates/stages/testing_servicing/build-image.yml
index 2d0dfa9e8..d9a62072d 100644
--- a/.pipelines/templates/stages/testing_servicing/build-image.yml
+++ b/.pipelines/templates/stages/testing_servicing/build-image.yml
@@ -63,10 +63,7 @@ jobs:
ob_artifactBaseName: "image-${{ parameters.label }}"
steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
+ - template: ../common_tasks/avoid-pypi-usage.yml
- task: DownloadPipelineArtifact@2
inputs:
diff --git a/.pipelines/templates/stages/testing_servicing/generate-ssh-keys.yml b/.pipelines/templates/stages/testing_servicing/generate-ssh-keys.yml
index 63df1c68d..12f1da76c 100644
--- a/.pipelines/templates/stages/testing_servicing/generate-ssh-keys.yml
+++ b/.pipelines/templates/stages/testing_servicing/generate-ssh-keys.yml
@@ -10,10 +10,7 @@ jobs:
ob_artifactBaseName: "ssh-keys"
steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
+ - template: ../common_tasks/avoid-pypi-usage.yml
- bash: |
set -eux
diff --git a/.pipelines/templates/stages/testing_servicing/testing-template.yml b/.pipelines/templates/stages/testing_servicing/testing-template.yml
index d0d137c65..85a1ec801 100644
--- a/.pipelines/templates/stages/testing_servicing/testing-template.yml
+++ b/.pipelines/templates/stages/testing_servicing/testing-template.yml
@@ -45,36 +45,6 @@ parameters:
default: "trident-ubuntu-1es-pool-eastus2"
jobs:
- - ${{ if eq(parameters.platform, 'azure') }}:
- - job: PublishAzureImage
- displayName: Publish Azure Image
- timeoutInMinutes: 20
- pool:
- type: linux
- name: ${{ parameters.pool }}
- hostArchitecture: amd64
- variables:
- ob_outputDirectory: $(Build.SourcesDirectory)/logs
- steps:
- - task: DownloadPipelineArtifact@2
- inputs:
- buildType: current
- artifactName: image-${{ parameters.platform }}-base
- targetPath: "$(Build.ArtifactStagingDirectory)/"
- displayName: Download Base Image
- - bash: |
- set -eux
- az login --identity
- ./scripts/loop-update/publish-sig-image.sh
- displayName: Publish Base Image
- env:
- SUBSCRIPTION: 04cdc145-a4f9-42d4-9868-c46d23d0c63f # CoreOS_Mariner_BMP_Staging
- IMAGE_DEFINITION: "trident-vm-verity-testimage-$(System.DefinitionId)"
- ARTIFACTS: $(Build.ArtifactStagingDirectory)
- STORAGE_ACCOUNT: "azlinuxbmpstagingeastus2"
- RESOURCE_GROUP: "azlinux_bmp_staging_eastus2"
- AZCOPY_AUTO_LOGIN_TYPE: "MSI"
-
- job: UpdateTesting_${{ parameters.flavor }}
displayName: Update Testing - ${{ parameters.flavor }}
timeoutInMinutes: ${{ parameters.updateCheckTimeoutInMinutes }}
@@ -84,17 +54,17 @@ jobs:
hostArchitecture: amd64
strategy:
parallel: ${{ parameters.workers }}
- dependsOn:
- - ${{ if eq(parameters.platform, 'azure') }}:
- - PublishAzureImage
variables:
tridentSourceDirectory: $(Build.SourcesDirectory)
ob_outputDirectory: $(tridentSourceDirectory)/deployment_logs_${{ parameters.flavor }}
ob_artifactBaseName: "update-testing-${{ parameters.flavor }}-$(System.JobPositionInPhase)"
- IMAGE_DEFINITION: "trident-vm-verity-testimage-$(System.DefinitionId)"
+ IMAGE_DEFINITION: "trident-vm-grub-verity-testimage-$(System.DefinitionId)"
TEST_RESOURCE_GROUP: trident-vm-servicing-validation-$(Build.BuildId)-$(System.JobPositionInPhase)
SUBSCRIPTION: 04cdc145-a4f9-42d4-9868-c46d23d0c63f # CoreOS_Mariner_BMP_Staging
+ STORAGE_ACCOUNT: "azlinuxbmpstagingeastus2"
+ RESOURCE_GROUP: "azlinux_bmp_staging_eastus2"
+ SUBNET_ID: /subscriptions/04cdc145-a4f9-42d4-9868-c46d23d0c63f/resourceGroups/trident-vm_servicing-azure-vnet/providers/Microsoft.Network/virtualNetworks/poolpeeringvnet/subnets/default
steps:
- bash: |
@@ -102,6 +72,14 @@ jobs:
echo "##vso[task.setvariable variable=TEST_RESOURCE_GROUP;]trident-vm-servicing-validation-$(Build.BuildId)-$(printf '%03d' $(System.JobPositionInPhase))"
displayName: "Set variables"
+ - ${{ if eq(parameters.platform, 'azure') }}:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ buildType: current
+ artifactName: image-${{ parameters.platform }}-base
+ targetPath: "$(Build.ArtifactStagingDirectory)/"
+ displayName: Download Base Image
+
- ${{ if eq(parameters.platform, 'qemu') }}:
- task: DownloadPipelineArtifact@2
inputs:
@@ -152,72 +130,49 @@ jobs:
- bash: |
set -eux
- if [ "$TEST_PLATFORM" == "azure" ]; then
+
+ SUDO="sudo"
+ if [ "${{ parameters.platform }}" == "azure" ]; then
az login --identity
+ SUDO=""
fi
- ./scripts/loop-update/deploy-vm.sh
- displayName: "Deploy VM"
- env:
- VERBOSE: ${{ parameters.verboseLogging }}
- ARTIFACTS: $(Build.ArtifactStagingDirectory)
- OUTPUT: $(ob_outputDirectory)
- TEST_RESOURCE_GROUP: $(TEST_RESOURCE_GROUP)
- IMAGE_DEFINITION: $(IMAGE_DEFINITION)
- TEST_PLATFORM: ${{ parameters.platform }}
- SUBSCRIPTION: $(SUBSCRIPTION)
- SECURE_BOOT: ${{ ne(parameters.flavor, 'uki') }}
- VALIDATION_SUBNET_ID: /subscriptions/04cdc145-a4f9-42d4-9868-c46d23d0c63f/resourceGroups/trident-vm_servicing-azure-vnet/providers/Microsoft.Network/virtualNetworks/poolpeeringvnet/subnets/default
- timeoutInMinutes: 5
- - bash: ./scripts/loop-update/check-deployment.sh
- displayName: "Check that Trident can adopt the deployment"
- env:
- TEST_PLATFORM: ${{ parameters.platform }}
+ FLAGS=""
+ if [ "${{ parameters.verboseLogging }}" == "True" ]; then
+ FLAGS="$FLAGS --verbose"
+ fi
+ if [ "${{ parameters.flavor }}" != "uki" ]; then
+ FLAGS="$FLAGS --secure-boot"
+ fi
- - bash: ./scripts/loop-update/loop-update.sh
+ $SUDO ./bin/storm-trident run servicing $FLAGS \
+ --artifacts-dir $(Build.ArtifactStagingDirectory) \
+ --output-path $(ob_outputDirectory) \
+ --subscription $(SUBSCRIPTION) \
+ --image-definition $(IMAGE_DEFINITION) \
+ --storage-account $(STORAGE_ACCOUNT) \
+ --storage-account-resource-group $(RESOURCE_GROUP) \
+ --test-resource-group $(TEST_RESOURCE_GROUP) \
+ --platform ${{ parameters.platform }} \
+ --subnet-id $(SUBNET_ID) \
+ --ssh-private-key-path $HOME/.ssh/id_rsa \
+ --ssh-public-key-path $HOME/.ssh/id_rsa.pub \
+ --retry-count ${{ parameters.updateIterationCount }} \
+ --rollback-retry-count ${{ parameters.updateIterationCount }} \
+ --build-id $(Build.BuildId) \
+ --force-cleanup
+
+ set +x
+ echo "##vso[task.setvariable variable=STORM_SCENARIO_FINISHED;]true"
+
+ displayName: "Servicing test"
env:
- ARTIFACTS: $(Build.ArtifactStagingDirectory)
- OUTPUT: $(ob_outputDirectory)
- VERBOSE: ${{ parameters.verboseLogging }}
- RETRY_COUNT: ${{ parameters.updateIterationCount }}
- EXPECTED_VOLUME: "volume-b"
- ROLLBACK: "false"
- TEST_RESOURCE_GROUP: $(TEST_RESOURCE_GROUP)
- TEST_PLATFORM: ${{ parameters.platform }}
- displayName: "Check that Trident can perform A/B update"
- condition: succeeded()
-
- # E2E rollback test: Trigger an A/B update back into runtime OS A, then cause a rollback
- # by triggering an artificial reboot. Then, check that the firmware performed a rollback
- # into B correctly. Finally, trigger two A/B updates, the first one using the same Host
- # Configuration, and validate that they succeed. Rollback testing will only be run when
- # the rollbackTesting parameter is true. The scaling test logic will set it to false.
-
- # TODO: reenable as part of https://dev.azure.com/mariner-org/ECF/_workitems/edit/10624
- - ${{ if ne(parameters.flavor, 'uki') }}:
- - bash: ./scripts/loop-update/loop-update.sh
- env:
- ARTIFACTS: $(Build.ArtifactStagingDirectory)
- OUTPUT: $(ob_outputDirectory)
- VERBOSE: ${{ parameters.verboseLogging }}
- RETRY_COUNT: 3
- EXPECTED_VOLUME: "volume-b"
- ROLLBACK: "true"
- TEST_RESOURCE_GROUP: $(TEST_RESOURCE_GROUP)
- TEST_PLATFORM: ${{ parameters.platform }}
- displayName: "Check that Trident can roll back and perform A/B update after"
- condition: and(succeeded(), eq(${{ parameters.rollbackTesting }}, true))
-
- # TODO add more e2e tests here (Task 8813)
-
+ AZCOPY_AUTO_LOGIN_TYPE: "MSI"
+
- bash: |
set -eux
- ./scripts/loop-update/fetch-logs.sh $(ob_outputDirectory)/
- ./scripts/loop-update/cleanup-vm.sh
-
- if [ "$TEST_PLATFORM" == "qemu" ]; then
- mkdir -p $(ob_outputDirectory)
+ if [ "${{ parameters.platform }}" == "qemu" ]; then
sudo zstd -T0 $(Build.ArtifactStagingDirectory)/booted.qcow2
sudo mv $(Build.ArtifactStagingDirectory)/booted.qcow2.zst $(ob_outputDirectory)/
fi
@@ -225,21 +180,42 @@ jobs:
# https://learn.microsoft.com/en-us/azure/virtual-machines/linux/download-vhd?tabs=azure-cli
# for Azure images
workingDirectory: $(tridentSourceDirectory)
- env:
- TEST_RESOURCE_GROUP: $(TEST_RESOURCE_GROUP)
- TEST_PLATFORM: ${{ parameters.platform }}
- SUBSCRIPTION: $(SUBSCRIPTION)
condition: failed()
displayName: "Publish logs and OS disk on failure"
timeoutInMinutes: 5
- - bash: |
- set -eux
- ./scripts/loop-update/cleanup-vm.sh
- displayName: "Cleanup VM"
- workingDirectory: $(tridentSourceDirectory)
- condition: always()
- env:
- TEST_RESOURCE_GROUP: $(TEST_RESOURCE_GROUP)
- TEST_PLATFORM: ${{ parameters.platform }}
- SUBSCRIPTION: $(SUBSCRIPTION)
+ - ${{ if eq(parameters.platform, 'azure') }}:
+ - bash: |
+ set -ex
+
+ # If platform is azure AND the test failed to finish, run cleanup to
+ # ensure there are no azure resources left behind
+ if [ "${STORM_SCENARIO_FINISHED}" != "true" ]; then
+ az login --identity
+
+ FLAGS=""
+ if [ "${{ parameters.verboseLogging }}" == "True" ]; then
+ FLAGS="$FLAGS --verbose"
+ fi
+
+ ./bin/storm-trident run servicing $FLAGS \
+ --artifacts-dir $(Build.ArtifactStagingDirectory) \
+ --output-path $(ob_outputDirectory) \
+ --subscription $(SUBSCRIPTION) \
+ --image-definition $(IMAGE_DEFINITION) \
+ --storage-account $(STORAGE_ACCOUNT) \
+ --storage-account-resource-group $(RESOURCE_GROUP) \
+ --test-resource-group $(TEST_RESOURCE_GROUP) \
+ --platform ${{ parameters.platform }} \
+ --subnet-id $(SUBNET_ID) \
+ --ssh-private-key-path $HOME/.ssh/id_rsa \
+ --ssh-public-key-path $HOME/.ssh/id_rsa.pub \
+ --retry-count ${{ parameters.updateIterationCount }} \
+ --rollback-retry-count ${{ parameters.updateIterationCount }} \
+ --build-id $(Build.BuildId) \
+ --test-case-to-run cleanup-vm
+ fi
+
+ displayName: "Cleanup even if timeout"
+ timeoutInMinutes: 20
+ condition: always()
diff --git a/.pipelines/templates/stages/testing_servicing/vm-testing.yml b/.pipelines/templates/stages/testing_servicing/vm-testing.yml
index 510493456..6b2c2d954 100644
--- a/.pipelines/templates/stages/testing_servicing/vm-testing.yml
+++ b/.pipelines/templates/stages/testing_servicing/vm-testing.yml
@@ -96,7 +96,7 @@ stages:
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
label: "qemu-base"
- makeTarget: "build/trident-vm-verity-testimage.qcow2"
+ makeTarget: "build/trident-vm-grub-verity-testimage.qcow2"
baseimgType: qemu_guest
baseimgAzlVersion: ${{ parameters.baseimgAzlVersion }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
@@ -108,7 +108,7 @@ stages:
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
label: "qemu-update-a"
- makeTarget: "build/trident-vm-verity-testimage.cosi"
+ makeTarget: "build/trident-vm-grub-verity-testimage.cosi"
baseimgType: qemu_guest
baseimgAzlVersion: ${{ parameters.baseimgAzlVersion }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
@@ -120,7 +120,7 @@ stages:
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
label: "qemu-update-b"
- makeTarget: "build/trident-vm-verity-testimage.cosi"
+ makeTarget: "build/trident-vm-grub-verity-testimage.cosi"
baseimgType: qemu_guest
baseimgAzlVersion: ${{ parameters.baseimgAzlVersion }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
@@ -140,7 +140,7 @@ stages:
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
label: "azure-base"
- makeTarget: "build/trident-vm-verity-azure-testimage.vhd"
+ makeTarget: "build/trident-vm-grub-verity-azure-testimage.vhd"
baseimgType: core_selinux
baseimgAzlVersion: ${{ parameters.baseimgAzlVersion }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
@@ -151,7 +151,7 @@ stages:
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
label: "azure-update-a"
- makeTarget: "build/trident-vm-verity-azure-testimage.cosi"
+ makeTarget: "build/trident-vm-grub-verity-azure-testimage.cosi"
baseimgType: core_selinux
baseimgAzlVersion: ${{ parameters.baseimgAzlVersion }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
@@ -162,7 +162,7 @@ stages:
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
label: "azure-update-b"
- makeTarget: "build/trident-vm-verity-azure-testimage.cosi"
+ makeTarget: "build/trident-vm-grub-verity-azure-testimage.cosi"
baseimgType: core_selinux
baseimgAzlVersion: ${{ parameters.baseimgAzlVersion }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
@@ -181,7 +181,7 @@ stages:
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
label: "uki-base"
- makeTarget: "build/trident-vm-verity-uki-testimage.qcow2"
+ makeTarget: "build/trident-vm-usr-verity-testimage.qcow2"
baseimgType: qemu_guest
baseimgAzlVersion: ${{ parameters.baseimgAzlVersion }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
@@ -193,7 +193,7 @@ stages:
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
label: "uki-update-a"
- makeTarget: "build/trident-vm-verity-uki-testimage.cosi"
+ makeTarget: "build/trident-vm-usr-verity-testimage.cosi"
baseimgType: qemu_guest
baseimgAzlVersion: ${{ parameters.baseimgAzlVersion }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
@@ -205,7 +205,7 @@ stages:
parameters:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
label: "uki-update-b"
- makeTarget: "build/trident-vm-verity-uki-testimage.cosi"
+ makeTarget: "build/trident-vm-usr-verity-testimage.cosi"
baseimgType: qemu_guest
baseimgAzlVersion: ${{ parameters.baseimgAzlVersion }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
diff --git a/.pipelines/templates/stages/testing_vm/netlaunch-prep.yml b/.pipelines/templates/stages/testing_vm/netlaunch-prep.yml
index 0a86d0715..affd3d04e 100644
--- a/.pipelines/templates/stages/testing_vm/netlaunch-prep.yml
+++ b/.pipelines/templates/stages/testing_vm/netlaunch-prep.yml
@@ -58,6 +58,8 @@ steps:
python3-bcrypt \
python3-jinja2 \
zstd
+
+ sudo pip3 install virt-firmware
displayName: Install virt-deploy dependencies
retryCountOnTaskFailure: 3
@@ -71,4 +73,23 @@ steps:
cat << EOF > ~/.config/libvirt/libvirt.conf
uri_default = "qemu:///system"
EOF
+
+ sudo mkdir -p /etc/systemd/system/docker.socket.d
+ echo "[Socket]
+ SocketMode=0666" | sudo tee /etc/systemd/system/docker.socket.d/mode.conf > /dev/null
+
+ sudo mkdir -p /etc/systemd/system/libvirtd.socket.d
+ echo "[Socket]
+ SocketMode=0666" | sudo tee /etc/systemd/system/libvirtd.socket.d/mode.conf > /dev/null
+
+ sudo systemctl daemon-reload
+
+ sudo systemctl stop docker.service
+ sudo systemctl restart docker.socket
+ sudo systemctl start docker.service
+
+ sudo systemctl stop libvirtd.service
+ sudo systemctl restart libvirtd.socket
+ sudo systemctl start libvirtd.service
+
displayName: "Configure virt-deploy"
diff --git a/.pipelines/templates/stages/testing_vm/netlaunch-testing.yml b/.pipelines/templates/stages/testing_vm/netlaunch-testing.yml
index f95287084..a32db6c12 100644
--- a/.pipelines/templates/stages/testing_vm/netlaunch-testing.yml
+++ b/.pipelines/templates/stages/testing_vm/netlaunch-testing.yml
@@ -23,33 +23,38 @@ parameters:
- container
stages:
+ - stage: DefineTests_VM_${{ parameters.runtimeEnv }}
+ displayName: Test List for VM:${{ parameters.runtimeEnv }}
+ jobs:
+ - template: ../testing_common/get-tests.yml
+ parameters:
+ buildPurpose: ${{ parameters.buildPurpose }}
+ deploymentEnvironment: virtualMachine
+ runtimeEnv: ${{ parameters.runtimeEnv }}
+
- stage: DeploymentTesting_${{ parameters.runtimeEnv }}
displayName: Deployment VM ${{ parameters.runtimeEnv }} Testing
dependsOn:
+ - DefineTests_VM_${{ parameters.runtimeEnv }}
- ${{ if eq(parameters.testingRun, true) }}:
- DownloadTestingElements
- ${{ else }}:
- BuildingTools
- ${{ if eq(parameters.runtimeEnv, 'container') }}:
- BuildTridentContainerImage
- - TridentTestImg_trident_container_installer_testimage
+ - TridentTestImg_trident_container_installer
- TridentTestImg_trident_container_testimage
- TridentTestImg_trident_container_verity_testimage
+ - TridentTestImg_trident_container_usrverity_testimage
- ${{ else }}:
- - TridentTestImg_trident_split_installer_testimage
- - TridentTestImg_trident_installer_testimage
+ - TridentTestImg_trident_split_installer
+ - TridentTestImg_trident_installer
- TridentTestImg_trident_testimage
- TridentTestImg_trident_verity_testimage
+ - TridentTestImg_trident_usrverity_testimage
jobs:
- - template: ../testing_common/get-tests.yml
- parameters:
- buildPurpose: ${{ parameters.buildPurpose }}
- deploymentEnvironment: virtualMachine
- runtimeEnv: ${{ parameters.runtimeEnv }}
-
- job: Testing
- dependsOn: DefineTests
timeoutInMinutes: 50
pool:
type: linux
@@ -57,24 +62,28 @@ stages:
hostArchitecture: amd64
strategy:
- matrix: $[ dependencies.DefineTests.outputs['setConfigurations.matrixConfigurations'] ]
+ matrix: $[ stageDependencies.DefineTests_VM_${{ parameters.runtimeEnv }}.DefineTests.outputs['setConfigurations.matrixConfigurations'] ]
variables:
+ # Sourced from the matrix
tridentConfigurationName: $(configuration)
+
tridentConfigPath: $(tridentSourceDirectory)/e2e_tests/trident_configurations/$(tridentConfigurationName)
tridentSourceDirectory: $(Build.SourcesDirectory)
argusToolkitSourceDirectory: $(Build.SourcesDirectory)/argus-toolkit
${{ if eq(parameters.runtimeEnv, 'container') }}:
- installerISOName: trident-container-installer-testimage
+ installerISOName: trident-container-installer
testImageName: trident-container-testimage
verityTestImageName: trident-container-verity-testimage
+ usrVerityTestImageName: trident-container-usrverity-testimage
downloadTridentContainer: true
${{ else }}:
- installerISOName: trident-installer-testimage
+ installerISOName: trident-installer
testImageName: trident-testimage
verityTestImageName: trident-verity-testimage
+ usrVerityTestImageName: trident-usrverity-testimage
downloadTridentContainer: false
ob_outputDirectory: $(tridentSourceDirectory)/deployment_logs
@@ -85,7 +94,7 @@ stages:
steps:
- bash: |
if [ ${{ variables['tridentConfigurationName'] }} == 'split' ]; then
- splitInstallerIsoName="trident-split-installer-testimage"
+ splitInstallerIsoName="trident-split-installer"
echo "setting variable.installerISOName to $splitInstallerIsoName"
echo "##vso[task.setvariable variable=installerISOName]$splitInstallerIsoName"
fi
@@ -101,6 +110,7 @@ stages:
tridentTestImage: ${{ variables.testImageName }}
tridentTestImageVerity: ${{ variables.verityTestImageName }}
downloadTridentContainer: ${{ variables.downloadTridentContainer }}
+ tridentTestImageUsrVerity: ${{ variables.usrVerityTestImageName }}
- template: netlaunch-prep.yml
@@ -112,8 +122,7 @@ stages:
- bash: |
set -eux
- sg libvirt "./virt-deploy create --mem 12 --disks 32,32"
- sg libvirt "./virt-deploy run"
+ ./virt-deploy create --mem 12 --disks 32,32
workingDirectory: $(argusToolkitSourceDirectory)
displayName: "Creating virt-deploy VM"
@@ -147,7 +156,7 @@ stages:
--port ${{variables.netlaunchPort}} 2>&1 | tee ./clean-install-deployment.log
workingDirectory: $(tridentSourceDirectory)
displayName: "đ Run netlaunch for testing"
- timeoutInMinutes: 15
+ timeoutInMinutes: 20
- template: ../testing_common/display-deployment-logs.yml
parameters:
@@ -195,6 +204,18 @@ stages:
condition: eq('${{ parameters.runtimeEnv }}', 'container')
displayName: "đ Display Container logs"
+ - bash: |
+ set -eux
+ HOST_IP=$(jq -r '.virtualmachines[0].ip' $(argusToolkitSourceDirectory)/virt-deploy-metadata.json)
+ ./bin/storm-trident helper boot-metrics \
+ "$(tridentSourceDirectory)/e2e_tests/helpers/key" \
+ "$HOST_IP" \
+ "testing-user" \
+ "${{ parameters.runtimeEnv }}" \
+ --metrics-file $(tridentSourceDirectory)/trident-clean-install-metrics.jsonl \
+ --metrics-operation install
+ displayName: "Create boot metrics for booting into runtime OS"
+
- template: ../testing_common/trident-metrics.yml
parameters:
tridentSourceDirectory: $(tridentSourceDirectory)
diff --git a/.pipelines/templates/stages/testing_vm/update-vm-bootorder.py b/.pipelines/templates/stages/testing_vm/update-vm-bootorder.py
deleted file mode 100755
index 1800d5982..000000000
--- a/.pipelines/templates/stages/testing_vm/update-vm-bootorder.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python3
-
-import os
-import subprocess
-import xml.etree.ElementTree as ET
-
-VM_NAME = "virtdeploy-vm-0"
-XML_FILE = f"/tmp/{VM_NAME}.xml"
-
-
-def run_command(command):
- result = subprocess.run(command, shell=True, capture_output=True, text=True)
- if result.returncode != 0:
- raise RuntimeError(f"Command '{command}' failed with error: {result.stderr}")
- return result.stdout
-
-
-# Dump the current XML configuration to a temporary file
-run_command(f"sudo virsh dumpxml {VM_NAME} > {XML_FILE}")
-
-# Parse the XML file
-tree = ET.parse(XML_FILE)
-root = tree.getroot()
-
-# Remove the line from the cdrom device
-for disk in root.findall("./devices/disk"):
- if disk.get("device") == "cdrom":
- boot = disk.find("boot")
- if boot is not None and boot.get("order") == "1":
- disk.remove(boot)
-
-# Add to the sda device
-for disk in root.findall("./devices/disk"):
- source = disk.find("source")
- if (
- disk.get("device") == "disk"
- and source is not None
- and source.get("file")
- == "/var/lib/libvirt/images/virtdeploy-pool/virtdeploy-vm-0-0-volume.qcow2"
- ):
- boot = ET.Element("boot", order="1")
- disk.append(boot)
-
-# Write the updated XML back to the file
-tree.write(XML_FILE)
-
-# Define the updated XML configuration
-run_command(f"sudo virsh define {XML_FILE}")
-
-# Cleanup
-os.remove(XML_FILE)
-
-print(f"Boot order updated successfully for VM: {VM_NAME}")
diff --git a/.pipelines/templates/stages/trident_rpms/build-source.yml b/.pipelines/templates/stages/trident_rpms/build-source.yml
index 8701e0985..da3d990ea 100644
--- a/.pipelines/templates/stages/trident_rpms/build-source.yml
+++ b/.pipelines/templates/stages/trident_rpms/build-source.yml
@@ -1,4 +1,8 @@
parameters:
+ - name: publishToDevFeed
+ type: boolean
+ default: false
+
- name: tridentArtifactName
type: string
@@ -38,11 +42,7 @@ stages:
value: "$(Build.SourcesDirectory)/trident/out"
steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
-
+ - template: ../common_tasks/avoid-pypi-usage.yml
- template: check.yml
- job: TestTrident
@@ -55,35 +55,14 @@ stages:
value: "$(Build.SourcesDirectory)/trident/out"
steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
-
+ - template: ../common_tasks/avoid-pypi-usage.yml
# need newer rust for cargo-nextest, use rustup.yml to install
- template: ../common_tasks/rustup.yml
- template: ../common_tasks/cargo-auth.yml
- template: unit-test.yml
-
- - job: Coverage
- displayName: Evaluate Unit Test Code Coverage
- condition: eq(${{ parameters.codeCoverage }}, true)
- pool:
- type: linux
-
- variables:
- ob_outputDirectory: "$(Build.SourcesDirectory)/trident/out"
-
- steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
-
- - template: ../common_tasks/cargo-auth.yml
- - template: ../common_tasks/coverage.yml
parameters:
- codeCoverageBaseline: 70 # Unit tests
+ codeCoverage: ${{ parameters.codeCoverage }}
+ unitTestCoverageBaseline: 70 # Unit tests
- job: BuildTrident
displayName: Build Trident 3.0 RPMs
@@ -100,11 +79,8 @@ stages:
buildType: auto
steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
-
+ - template: ../common_tasks/os-info.yml
+ - template: ../common_tasks/avoid-pypi-usage.yml
- template: ../common_tasks/cargo-auth.yml
- template: ../common_tasks/build-osmodifier.yml
- template: release.yml
@@ -112,6 +88,8 @@ stages:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImagePipelineBuildId }}
previewContainerPipeline: "[AMD64-6-OneBranch]-Prod-BuildImages"
+ - ${{ if eq(parameters.publishToDevFeed, true) }}:
+ - template: publish-dev.yml
- job: BuildTridentARM64
displayName: Build Trident 3.0 RPMs for ARM64
@@ -130,11 +108,7 @@ stages:
buildType: auto
steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
-
+ - template: ../common_tasks/avoid-pypi-usage.yml
- template: ../common_tasks/cargo-auth.yml
- template: ../common_tasks/build-osmodifier.yml
- template: release.yml
@@ -142,28 +116,3 @@ stages:
baseimgBuildType: ${{ parameters.baseimgBuildType }}
baseImagePipelineBuildId: ${{ parameters.baseImageArm64PipelineBuildId }}
previewContainerPipeline: "[ARM64-6-OneBranch]-Prod-BuildImages"
-
- - job: BuildTrident2
- displayName: Build Trident 2.0 RPMs
- pool:
- type: linux
-
- variables:
- - name: ob_artifactBaseName
- value: ${{ parameters.tridentArtifactName }}2
- - name: ob_outputDirectory
- value: "$(Build.SourcesDirectory)/out"
- - template: common/setup-registries-vars-template.yaml@platform-pipelines
- parameters:
- buildType: auto
-
- steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
-
- - template: ../common_tasks/rustup.yml
- - template: ../common_tasks/cargo-auth.yml
- - template: ../common_tasks/build-osmodifier.yml
- - template: release2.yml
diff --git a/.pipelines/templates/stages/trident_rpms/check.yml b/.pipelines/templates/stages/trident_rpms/check.yml
index 7c4e95e23..6ad8a39e8 100644
--- a/.pipelines/templates/stages/trident_rpms/check.yml
+++ b/.pipelines/templates/stages/trident_rpms/check.yml
@@ -5,11 +5,7 @@ steps:
- template: ../common_tasks/rustup.yml
- template: ../common_tasks/cargo-auth.yml
-
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
+ - template: ../common_tasks/avoid-pypi-usage.yml
- script: |
set -eux
diff --git a/.pipelines/templates/stages/trident_rpms/publish-dev.yml b/.pipelines/templates/stages/trident_rpms/publish-dev.yml
new file mode 100644
index 000000000..4ba7d3c26
--- /dev/null
+++ b/.pipelines/templates/stages/trident_rpms/publish-dev.yml
@@ -0,0 +1,47 @@
+parameters:
+ - name: "feed"
+ type: string
+ default: TridentDev
+ values: [TridentDev]
+ - name: "packageName"
+ type: string
+ default: rpms-pr
+ values: [rpms-pr]
+
+steps:
+ - script: echo $(Build.BuildNumber)
+ displayName: "Print Trident Version"
+
+ - script: |
+ set -eux
+
+ alreadyPublished=$(./scripts/get-packages.py --debug \
+ --feed '${{ parameters.feed }}' \
+ --package '${{ parameters.packageName }}' \
+ --version '$(Build.BuildNumber)' \
+ --action=exists)
+
+ # Save variable to know if package needs to be published
+ set +x
+ echo "##vso[task.setvariable variable=isVersionInFeed;]$alreadyPublished"
+ displayName: "Check if package version has already been published in the feed."
+ workingDirectory: $(Build.SourcesDirectory)
+ env:
+ AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)
+
+ - script: |
+ mkdir -p $(Build.SourcesDirectory)/staging_dir
+ cp $(ob_outputDirectory)/*.rpm $(Build.SourcesDirectory)/staging_dir
+ ls $(Build.SourcesDirectory)/staging_dir
+ displayName: Copy RPMs into Staging Directory
+
+ - task: UniversalPackages@0
+ displayName: "Publish RPMs Universal Package"
+ condition: and(succeeded(), eq(variables.isVersionInFeed, false))
+ inputs:
+ command: publish
+ vstsFeedPublish: "ECF/${{ parameters.feed }}"
+ vstsFeedPackagePublish: "${{ parameters.packageName }}"
+ publishDirectory: "$(Build.SourcesDirectory)/staging_dir"
+ versionPublish: $(Build.BuildNumber)
+ versionOption: custom
diff --git a/.pipelines/templates/stages/trident_rpms/release2.yml b/.pipelines/templates/stages/trident_rpms/release2.yml
deleted file mode 100644
index 0731cb57a..000000000
--- a/.pipelines/templates/stages/trident_rpms/release2.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-parameters:
- - name: minimumSystemdVersion
- type: string
- default: '254'
-
-steps:
- - script: |
- set -eux
- TRIDENT_VERSION=$(python3 ./scripts/get-version.py "$(Build.BuildNumber)" --commit)
- echo "##vso[task.setvariable variable=trident_version]$TRIDENT_VERSION"
- displayName: "Setting Trident version"
-
- - task: onebranch.pipeline.version@1
- displayName: "Set build number"
- inputs:
- system: "Custom"
- customVersion: $(trident_version)
-
- - task: CopyFiles@2
- inputs:
- sourceFolder: "./artifacts"
- targetFolder: "/usr/src/mariner/SOURCES"
- contents: "*"
- displayName: Copy EMU to SOURCES
-
- - task: CopyFiles@2
- inputs:
- sourceFolder: "./"
- targetFolder: "/usr/src/mariner/SOURCES"
- contents: "trident-selinuxpolicies.cil"
- displayName: Copy Trident selinux policy to SOURCES
-
- - script: sudo tdnf install -y protobuf protobuf-c openssl-devel clang-devel rust p7zip p7zip-plugins zstd moby-buildx
- displayName: Install native dependencies
- retryCountOnTaskFailure: 3
-
- - script: |
- set -eux
- full_version=$(trident_version)
-
- # Separate into version and prerelease identifier
- # for the RPM build.
- version=$(echo $full_version | cut -d'-' -f1)
- prerelease=$(echo $full_version | cut -d'-' -f2-)
-
- # Edit the trident.spec file to not require 3.0 dependencies
- sed -i 's/systemd >= 255/systemd >= ${{ parameters.minimumSystemdVersion }}/g' trident.spec
- sed -i 's/Requires:[[:blank:]]*systemd-udev//g' trident.spec
-
- rpmbuild -bb --build-in-place trident.spec \
- --define="trident_version $full_version" \
- --define="rpm_ver $version" \
- --define="rpm_rel $prerelease"
- displayName: Build 2.0 RPMs
-
- - task: CopyFiles@2
- inputs:
- sourceFolder: "/usr/src/mariner/RPMS/x86_64"
- targetFolder: "$(ob_outputDirectory)"
- displayName: Copy RPM file to output
diff --git a/.pipelines/templates/stages/trident_rpms/trident-stage.yml b/.pipelines/templates/stages/trident_rpms/trident-stage.yml
index 0de43cd8a..9f8bc562d 100644
--- a/.pipelines/templates/stages/trident_rpms/trident-stage.yml
+++ b/.pipelines/templates/stages/trident_rpms/trident-stage.yml
@@ -43,6 +43,8 @@ stages:
- ${{ if or(parameters.forceTridentRebuild, eq(parameters.stageType, 'pr'), eq(parameters.stageType, 'pr-e2e'), eq(parameters.stageType, 'ci'), eq(parameters.stageType, 'pr-e2e-azure')) }}:
- template: build-source.yml
parameters:
+ ${{ if eq(parameters.stageType, 'pr') }}:
+ publishToDevFeed: true
tridentArtifactName: ${{ parameters.tridentArtifactName }}
codeCoverage: ${{ parameters.codeCoverage }}
baseimgBuildType: ${{ parameters.baseimgBuildType }}
diff --git a/.pipelines/templates/stages/trident_rpms/unit-test.yml b/.pipelines/templates/stages/trident_rpms/unit-test.yml
index 3e546949a..917133c45 100644
--- a/.pipelines/templates/stages/trident_rpms/unit-test.yml
+++ b/.pipelines/templates/stages/trident_rpms/unit-test.yml
@@ -1,3 +1,11 @@
+parameters:
+ - name: codeCoverage
+ type: boolean
+ default: true
+
+ - name: unitTestCoverageBaseline
+ type: number
+
steps:
- script: sudo tdnf install -y protobuf protobuf-c openssl-devel clang-devel rust
displayName: Install native dependencies
@@ -5,14 +13,41 @@ steps:
- script: |
set -eux
- cargo install cargo-nextest --locked --version 0.9.85
+ cargo install cargo-nextest --locked --version 0.9.97
+ cargo install cargo-llvm-cov --locked --version 0.6.16
+
# Exclude pytest_gen as Mariner Rust is currently failing to build it. See
# for more details: https://dev.azure.com/mariner-org/ECF/_workitems/edit/6517
- cargo nextest run --workspace --exclude pytest_gen --profile ci
- displayName: Test Debug
+ cargo llvm-cov nextest --remap-path-prefix --lcov --output-path target/lcov.info --workspace --exclude pytest_gen --profile ci
+ displayName: Run Unit Tests
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testResultsFormat: "JUnit"
testResultsFiles: "./target/nextest/ci/trident_unit_tests.xml"
+
+ - task: PublishCodeCoverageResults@2
+ condition: and(succeededOrFailed(), eq(${{ parameters.codeCoverage }}, true))
+ inputs:
+ summaryFileLocation: "./target/lcov.info"
+
+ - bash: |
+ set -eux
+ cargo llvm-cov report \
+ --ignore-filename-regex 'docbuilder' \
+ --summary-only --json > ./target/coverage.json
+
+ MEASURED_COVERAGE="$(jq '.data[0].totals.lines.percent' ./target/coverage.json)"
+ BASELINE="${{ parameters.unitTestCoverageBaseline }}"
+
+ if (( $(echo "$MEASURED_COVERAGE < $BASELINE" | bc -l) )); then
+ set +x
+ echo "##vso[task.logissue type=error]Code coverage ($MEASURED_COVERAGE) is below baseline ($BASELINE)"
+ set -x
+ exit 1
+ else
+ echo "Code coverage ($MEASURED_COVERAGE) meets or exceeds baseline ($BASELINE)"
+ fi
+ displayName: Assert code coverage is above baseline
+ condition: and(succeededOrFailed(), eq(${{ parameters.codeCoverage }}, true))
diff --git a/.pipelines/templates/stages/trident_usb_iso/trident-usb-iso.yml b/.pipelines/templates/stages/trident_usb_iso/trident-usb-iso.yml
index 16cc77e86..f3067f8a9 100644
--- a/.pipelines/templates/stages/trident_usb_iso/trident-usb-iso.yml
+++ b/.pipelines/templates/stages/trident_usb_iso/trident-usb-iso.yml
@@ -55,10 +55,7 @@ stages:
fetchDepth: 1
path: s/test-images
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
+ - template: ../common_tasks/avoid-pypi-usage.yml
- task: DownloadPipelineArtifact@2
inputs:
diff --git a/.pipelines/templates/stages/validate_makefile/dev-build.yml b/.pipelines/templates/stages/validate_makefile/dev-build.yml
index 1c1e7b752..3f9db059a 100644
--- a/.pipelines/templates/stages/validate_makefile/dev-build.yml
+++ b/.pipelines/templates/stages/validate_makefile/dev-build.yml
@@ -15,11 +15,7 @@ stages:
ob_outputDirectory: $(Build.SourcesDirectory)/build
steps:
- - task: PipAuthenticate@1
- displayName: Provision - Authenticate Pip
- inputs:
- artifactFeeds: 'mariner/Mariner-Pypi-Feed'
-
+ - template: ../common_tasks/avoid-pypi-usage.yml
- template: ../common_tasks/build-osmodifier.yml
- script: |
diff --git a/.pipelines/trident-pr-e2e.yml b/.pipelines/trident-pr-e2e.yml
index a1aeb09c6..a781a9a90 100644
--- a/.pipelines/trident-pr-e2e.yml
+++ b/.pipelines/trident-pr-e2e.yml
@@ -12,10 +12,10 @@ trigger: none
resources:
repositories:
- - repository: templates
- type: git
- name: OneBranch.Pipelines/GovernedTemplates
- ref: refs/heads/main
+ # - repository: templates
+ # type: git
+ # name: OneBranch.Pipelines/GovernedTemplates
+ # ref: refs/heads/main
- repository: argus-toolkit
type: git
@@ -44,24 +44,28 @@ resources:
variables:
- group: bot # added for access to dom0 RPMs
+# Preserving old OneBranch Pipelines template for reference.
+# extends:
+# template: v2/OneBranch.NonOfficial.CrossPlat.yml@templates # https://aka.ms/obpipelines/templates
+# parameters:
+# globalSdl: # https://aka.ms/obpipelines/sdl
+# # tsa:
+# # enabled: true # SDL results of non-official builds aren't uploaded to TSA by default.
+# credscan:
+# suppressionsFile: $(Build.SourcesDirectory)\.config\CredScanSuppressions.json
+# policheck:
+# break: true # always break the build on policheck issues. You can disable it by setting to 'false'
+# # suppression:
+# # suppressionFile: $(Build.SourcesDirectory)\.gdn\global.gdnsuppress
+# cg:
+# alertWarningLevel: Medium
+# featureFlags:
+# runOnHost: true
+# EnableCDPxPAT: false
+
extends:
- template: v2/OneBranch.NonOfficial.CrossPlat.yml@templates # https://aka.ms/obpipelines/templates
+ template: templates/MockOB.yml
parameters:
- globalSdl: # https://aka.ms/obpipelines/sdl
- # tsa:
- # enabled: true # SDL results of non-official builds aren't uploaded to TSA by default.
- credscan:
- suppressionsFile: $(Build.SourcesDirectory)\.config\CredScanSuppressions.json
- policheck:
- break: true # always break the build on policheck issues. You can disable it by setting to 'false'
- # suppression:
- # suppressionFile: $(Build.SourcesDirectory)\.gdn\global.gdnsuppress
- cg:
- alertWarningLevel: Medium
- featureFlags:
- runOnHost: true
- EnableCDPxPAT: false
-
stages:
- template: templates/pipeline-selector.yml
parameters:
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 4a9f2a999..e44a7dd52 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,6 +1,6 @@
{
"editor.formatOnSave": true,
- "rust-analyzer.checkOnSave.command": "clippy",
+ "rust-analyzer.check.command": "clippy",
"rust-analyzer.cargo.features": "all",
"black-formatter.args": [],
"[python]": {
@@ -17,5 +17,5 @@
"editor.insertSpaces": true,
"editor.tabSize": 2,
"prettier.tabWidth": 2,
- }
+ },
}
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index d6c4ab6c2..c62aedf48 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -454,6 +454,15 @@ dependencies = [
"libc",
]
+[[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+dependencies = [
+ "cfg-if",
+]
+
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
@@ -548,7 +557,9 @@ dependencies = [
"serde_yaml",
"setsail",
"strum",
+ "svg",
"tera",
+ "textwrap",
"trident",
"trident_api",
]
@@ -707,6 +718,16 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
+[[package]]
+name = "flate2"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
[[package]]
name = "fnv"
version = "1.0.7"
@@ -856,6 +877,17 @@ dependencies = [
"walkdir",
]
+[[package]]
+name = "goblin"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daa0a64d21a7eb230583b4c5f4e23b7e4e57974f96620f42a7e75e08ae66d745"
+dependencies = [
+ "log",
+ "plain",
+ "scroll",
+]
+
[[package]]
name = "h2"
version = "0.4.7"
@@ -928,6 +960,12 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
[[package]]
name = "home"
version = "0.5.9"
@@ -1632,6 +1670,8 @@ dependencies = [
"duct",
"enumflags2",
"glob",
+ "goblin",
+ "hex",
"hostname",
"indoc",
"inventory",
@@ -1847,6 +1887,12 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+[[package]]
+name = "plain"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
+
[[package]]
name = "ppv-lite86"
version = "0.2.20"
@@ -1885,6 +1931,31 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "procfs"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f"
+dependencies = [
+ "bitflags",
+ "chrono",
+ "flate2",
+ "hex",
+ "procfs-core",
+ "rustix",
+]
+
+[[package]]
+name = "procfs-core"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
+dependencies = [
+ "bitflags",
+ "chrono",
+ "hex",
+]
+
[[package]]
name = "prost"
version = "0.13.4"
@@ -2244,6 +2315,26 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+[[package]]
+name = "scroll"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
+dependencies = [
+ "scroll_derive",
+]
+
+[[package]]
+name = "scroll_derive"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "security-framework"
version = "2.11.1"
@@ -2462,6 +2553,12 @@ dependencies = [
"syn",
]
+[[package]]
+name = "smawk"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
+
[[package]]
name = "socket2"
version = "0.5.8"
@@ -2531,6 +2628,12 @@ dependencies = [
"syn",
]
+[[package]]
+name = "svg"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94afda9cd163c04f6bee8b4bf2501c91548deae308373c436f36aeff3cf3c4a3"
+
[[package]]
name = "syn"
version = "2.0.90"
@@ -2674,6 +2777,17 @@ dependencies = [
"windows-sys 0.48.0",
]
+[[package]]
+name = "textwrap"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
+dependencies = [
+ "smawk",
+ "unicode-linebreak",
+ "unicode-width",
+]
+
[[package]]
name = "thiserror"
version = "1.0.69"
@@ -2961,6 +3075,7 @@ dependencies = [
"netplan-types",
"nix",
"osutils",
+ "procfs",
"prost",
"pytest",
"pytest_gen",
@@ -3093,12 +3208,24 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+[[package]]
+name = "unicode-linebreak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
+
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+[[package]]
+name = "unicode-width"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
+
[[package]]
name = "unicode-xid"
version = "0.2.6"
diff --git a/Cargo.toml b/Cargo.toml
index 747f2e350..e84727e96 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,6 +26,7 @@ nix = { version = "0.29.0", default-features = false, features = [
"fs",
"user",
] }
+procfs = "0.17.0"
rayon = "1.10"
regex = "1.11.1"
reqwest = { version = "0.12.9", default-features = false, features = [
diff --git a/Dockerfile.azl2 b/Dockerfile.azl2
deleted file mode 100644
index a5955355f..000000000
--- a/Dockerfile.azl2
+++ /dev/null
@@ -1,23 +0,0 @@
-FROM mcr.microsoft.com/cbl-mariner/base/rust:1
-
-RUN tdnf install -y rpmdevtools openssl-devel clang-devel protobuf-devel
-
-WORKDIR /work
-
-COPY trident.spec .
-COPY systemd ./systemd
-COPY bin/trident ./target/release/trident
-COPY artifacts/osmodifier /usr/src/mariner/SOURCES/osmodifier
-COPY trident-selinuxpolicies.cil /usr/src/mariner/SOURCES/trident-selinuxpolicies.cil
-
-ARG TRIDENT_VERSION=dev-build
-ARG RPM_VER=0.1.0
-ARG RPM_REL=1
-
-RUN \
- sed -i "s/cargo build/#cargo build/g" trident.spec && \
- rpmbuild -bb --build-in-place trident.spec \
- --define="trident_version $TRIDENT_VERSION" \
- --define="rpm_ver $RPM_VER" \
- --define="rpm_rel $RPM_REL" && \
- tar -czvf trident-rpms.tar.gz -C /usr/src/mariner ./RPMS
diff --git a/Dockerfile.azl3 b/Dockerfile.azl3
index ec6f476bc..1ca3dd430 100644
--- a/Dockerfile.azl3
+++ b/Dockerfile.azl3
@@ -1,6 +1,8 @@
+### This file is primarily used to build Trident RPMs for local testing.
+
FROM mcr.microsoft.com/azurelinux/base/core:3.0
-RUN tdnf install -y rpmdevtools openssl-devel clang-devel protobuf-devel rust sed
+RUN tdnf install -y rpmdevtools openssl-devel clang-devel protobuf-devel rust sed selinux-policy-devel
WORKDIR /work
@@ -8,7 +10,10 @@ COPY trident.spec .
COPY systemd ./systemd
COPY bin/trident ./target/release/trident
COPY artifacts/osmodifier /usr/src/azl/SOURCES/osmodifier
-COPY trident-selinuxpolicies.cil /usr/src/azl/SOURCES/trident-selinuxpolicies.cil
+COPY selinux-policy-trident/trident.te /usr/src/azl/SOURCES/trident.te
+COPY selinux-policy-trident/trident.fc /usr/src/azl/SOURCES/trident.fc
+COPY selinux-policy-trident/trident.if /usr/src/azl/SOURCES/trident.if
+COPY packaging/static-pcrlock-files/ /usr/src/azl/SOURCES/static-pcrlock-files/
ARG TRIDENT_VERSION=dev-build
ARG RPM_VER=0.1.0
diff --git a/Dockerfile.full b/Dockerfile.full
index 1969c0eb1..37109074d 100644
--- a/Dockerfile.full
+++ b/Dockerfile.full
@@ -1,13 +1,18 @@
+### This file is used in pipelines to build Trident RPMs.
+
FROM mcr.microsoft.com/azurelinux/base/core:3.0
-RUN tdnf install -y rpmdevtools openssl-devel clang-devel protobuf-devel rust sed ca-certificates perl build-essential
+RUN tdnf install -y rpmdevtools openssl-devel clang-devel protobuf-devel rust sed ca-certificates perl build-essential selinux-policy-devel
WORKDIR /work
COPY trident.spec .
COPY systemd ./systemd
COPY artifacts/osmodifier /usr/src/azl/SOURCES/osmodifier
-COPY trident-selinuxpolicies.cil /usr/src/azl/SOURCES/trident-selinuxpolicies.cil
+COPY selinux-policy-trident/trident.te /usr/src/azl/SOURCES/trident.te
+COPY selinux-policy-trident/trident.fc /usr/src/azl/SOURCES/trident.fc
+COPY selinux-policy-trident/trident.if /usr/src/azl/SOURCES/trident.if
+COPY packaging/static-pcrlock-files/ /usr/src/azl/SOURCES/static-pcrlock-files/
COPY .cargo/config.toml ./.cargo/config.toml
COPY build.rs .
@@ -29,7 +34,10 @@ ARG RPM_REL=1
# This entry needs to exist in the config.toml file to allow cargo to use the
# token from the environment variable.
-# RUN printf '[registry]\nglobal-credential-providers = ["cargo:token"]\n' >> ./.cargo/config.toml
+ARG CARGO_REGISTRIES_FROM_ENV=false
+RUN if [ "$CARGO_REGISTRIES_FROM_ENV" = "true" ]; then \
+ printf '[registry]\nglobal-credential-providers = ["cargo:token"]\n' >> ./.cargo/config.toml; \
+fi
RUN --mount=type=secret,id=registry_token \
export CARGO_REGISTRIES_BMP_PUBLICPACKAGES_TOKEN=$(cat /run/secrets/registry_token) && \
diff --git a/Dockerfile.runtime b/Dockerfile.runtime
index 6c39e20ae..f385cdb38 100644
--- a/Dockerfile.runtime
+++ b/Dockerfile.runtime
@@ -1,3 +1,5 @@
+### This file is used to build a container image with Trident inside.
+
FROM mcr.microsoft.com/azurelinux/base/core:3.0
RUN tdnf -y install \
@@ -21,6 +23,8 @@ RUN \
--mount=type=bind,source=./bin/RPMS,target=/trident \
tdnf install -y \
/trident/x86_64/trident-0*.rpm && \
+ tdnf install -y \
+ /trident/x86_64/trident-static-pcrlock-files-0*.rpm && \
tdnf clean all
ENV DOCKER_ENVIRONMENT=true
diff --git a/Makefile b/Makefile
index 16bcbbeee..0efb851a6 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ NETLAUNCH_CONFIG ?= input/netlaunch.yaml
OVERRIDE_RUST_FEED ?= true
.PHONY: all
-all: format check test build-api-docs bin/trident-rpms-azl2.tar.gz bin/trident-rpms-azl3.tar.gz docker-build build-functional-test coverage validate-configs generate-mermaid-diagrams
+all: format check test build-api-docs bin/trident-rpms.tar.gz docker-build build-functional-test coverage validate-configs generate-mermaid-diagrams
.PHONY: check
check:
@@ -62,10 +62,16 @@ check-sh:
fi
@echo "NOTICE: Created local .cargo/config file."
-.PHONY: build
-build: .cargo/config
+.PHONY: version-vars
+version-vars:
$(eval TRIDENT_CARGO_VERSION := $(shell python3 ./scripts/get-version.py "$(shell date +%Y%m%d).99"))
$(eval GIT_COMMIT := $(shell git rev-parse --short HEAD)$(shell git diff --quiet || echo '.dirty'))
+ $(eval LOCAL_BUILD_TRIDENT_VERSION=$(TRIDENT_CARGO_VERSION)-dev.$(GIT_COMMIT))
+ @echo "TRIDENT_CARGO_VERSION=$(TRIDENT_CARGO_VERSION)"
+ @echo "GIT_COMMIT=$(GIT_COMMIT)"
+
+.PHONY: build
+build: .cargo/config version-vars
@OPENSSL_STATIC=1 \
OPENSSL_LIB_DIR=$(shell dirname `whereis libssl.a | cut -d" " -f2`) \
OPENSSL_INCLUDE_DIR=/usr/include/openssl \
@@ -117,22 +123,30 @@ bin/trident: build
@mkdir -p bin
@cp -u target/release/trident bin/
-bin/trident-rpms-azl2.tar.gz: Dockerfile.azl2 systemd/*.service trident.spec artifacts/osmodifier bin/trident
- @docker build --quiet -t trident/trident-build:latest \
- --build-arg TRIDENT_VERSION="$(TRIDENT_CARGO_VERSION)-dev.$(GIT_COMMIT)" \
- --build-arg RPM_VER="$(TRIDENT_CARGO_VERSION)" \
- --build-arg RPM_REL="dev.$(GIT_COMMIT)" \
- -f Dockerfile.azl2 \
- .
+# This will do a proper build on azl3, exactly as the pipelines would, with the custom registry and all.
+bin/trident-rpms-azl3.tar.gz: Dockerfile.full systemd/*.service trident.spec artifacts/osmodifier selinux-policy-trident/* version-vars
+ $(eval CARGO_REGISTRIES_BMP_PUBLICPACKAGES_TOKEN := $(shell az account get-access-token --query "join(' ', ['Bearer', accessToken])" --output tsv))
+
+ @export CARGO_REGISTRIES_BMP_PUBLICPACKAGES_TOKEN="$(CARGO_REGISTRIES_BMP_PUBLICPACKAGES_TOKEN)" &&\
+ docker build -t trident/trident-build:latest \
+ --secret id=registry_token,env=CARGO_REGISTRIES_BMP_PUBLICPACKAGES_TOKEN \
+ --build-arg CARGO_REGISTRIES_FROM_ENV="true" \
+ --build-arg TRIDENT_VERSION="$(LOCAL_BUILD_TRIDENT_VERSION)" \
+ --build-arg RPM_VER="$(TRIDENT_CARGO_VERSION)" \
+ --build-arg RPM_REL="dev.$(GIT_COMMIT)" \
+ -f Dockerfile.full \
+ .
+ @mkdir -p bin/
@id=$$(docker create trident/trident-build:latest) && \
- docker cp -q $$id:/work/trident-rpms.tar.gz $@ && \
+ docker cp -q $$id:/work/trident-rpms.tar.gz $@ || \
docker rm -v $$id
- @rm -rf bin/RPMS/x86_64
+ @rm -rf bin/RPMS/
@tar xf $@ -C bin/
-bin/trident-rpms-azl3.tar.gz: Dockerfile.azl3 systemd/*.service trident.spec artifacts/osmodifier bin/trident
+# This one does a fast trick-build where we build locally and inject the binary into the container to add it to the RPM.
+bin/trident-rpms.tar.gz: Dockerfile.azl3 systemd/*.service trident.spec artifacts/osmodifier bin/trident selinux-policy-trident/*
@docker build -t trident/trident-build:latest \
- --build-arg TRIDENT_VERSION="$(TRIDENT_CARGO_VERSION)-dev.$(GIT_COMMIT)" \
+ --build-arg TRIDENT_VERSION="$(LOCAL_BUILD_TRIDENT_VERSION)" \
--build-arg RPM_VER="$(TRIDENT_CARGO_VERSION)" \
--build-arg RPM_REL="dev.$(GIT_COMMIT)" \
-f Dockerfile.azl3 \
@@ -141,14 +155,25 @@ bin/trident-rpms-azl3.tar.gz: Dockerfile.azl3 systemd/*.service trident.spec art
@id=$$(docker create trident/trident-build:latest) && \
docker cp -q $$id:/work/trident-rpms.tar.gz $@ || \
docker rm -v $$id
- @rm -rf bin/RPMS/x86_64
+ @rm -rf bin/RPMS/
@tar xf $@ -C bin/
-bin/trident-rpms.tar.gz: bin/trident-rpms-azl3.tar.gz
- cp $< $@
+STEAMBOAT_RPMS_DIR ?= /tmp/mariner/uki/out/RPMS
+
+.PHONY: copy-rpms-to-steamboat
+copy-rpms-to-steamboat: bin/trident-rpms-azl3.tar.gz
+ @echo "Cleaning up old Trident RPMs in Steamboat..."
+ @rm -f $(STEAMBOAT_RPMS_DIR)/trident-*
+ @echo "Copying Trident RPMs to Steamboat..."
+ @mkdir -p $(STEAMBOAT_RPMS_DIR)
+ @find bin/RPMS -type f -name 'trident-*.rpm' -exec cp {} $(STEAMBOAT_RPMS_DIR) \;
+ @echo "Trident RPMs copied to Steamboat directory: $(STEAMBOAT_RPMS_DIR)"
+ @ls -alh $(STEAMBOAT_RPMS_DIR)/trident-*.rpm
+
+# Grabs bin/trident-rpms.tar.gz from the local build directory and builds a Docker image with it.
.PHONY: docker-build
-docker-build: Dockerfile.runtime bin/trident-rpms-azl3.tar.gz
+docker-build: Dockerfile.runtime bin/trident-rpms.tar.gz
@docker build --quiet -f Dockerfile.runtime -t trident/trident:latest .
artifacts/test-image/trident-container.tar.gz: docker-build
@@ -193,6 +218,7 @@ TRIDENT_API_HC_EXAMPLE_FILE := docs/Reference/Host-Configuration/Sample-Host-Con
TRIDENT_API_HC_EXAMPLE_YAML := docs/Reference/Host-Configuration/sample-host-configuration.yaml
TRIDENT_API_HC_STORAGE_RULES_FILES := docs/Reference/Host-Configuration/Storage-Rules.md
TRIDENT_API_CLI_DOC := docs/Reference/Trident-CLI.md
+TRIDENT_ARCH_INSTALL_SVG := docs/resources/trident-install.svg
target/trident-api-docs:
mkdir -p target/trident-api-docs
@@ -224,6 +250,9 @@ build-api-docs: build-api-schema docbuilder
$(DOCBUILDER_BIN) trident-cli -o $(TRIDENT_API_CLI_DOC)
@echo Wrote CLI docs to $(TRIDENT_API_CLI_DOC)
+ $(DOCBUILDER_BIN) trident-arch install > $(TRIDENT_ARCH_INSTALL_SVG)
+ @echo Wrote install diagram to $(TRIDENT_ARCH_INSTALL_SVG)
+
# This target is meant to be used by CI to ensure that the API schema is up to date.
@@ -269,28 +298,45 @@ build-functional-test-cc: .cargo/config
cargo build --target-dir $(TRIDENT_COVERAGE_TARGET) --lib --tests --features functional-test --all
.PHONY: functional-test
-functional-test: bin/trident-mos.iso bin/trident artifacts/osmodifier artifacts/test-image/regular.cosi bin/netlaunch
+functional-test: artifacts/trident-functest.qcow2
cp $(PLATFORM_TESTS_PATH)/tools/marinerhci_test_tools/node_interface.py functional_tests/
cp $(PLATFORM_TESTS_PATH)/tools/marinerhci_test_tools/ssh_node.py functional_tests/
- cp bin/trident artifacts/test-image/
- cp artifacts/osmodifier artifacts/test-image/
$(MAKE) functional-test-core
# A target for pipelines that skips all setup and building steps that are not
# required in the pipeline environment.
.PHONY: functional-test-core
-functional-test-core: build-functional-test-cc generate-functional-test-manifest
-# Check if INSTALLER_ISO_PATH is set, if not, check if the installer iso is present in the bin directory
-ifndef INSTALLER_ISO_PATH
-ifeq ($(wildcard bin/trident-mos.iso),)
- $(error INSTALLER_ISO_PATH is not set and bin/trident-mos.iso is not present in the bin directory)
-endif
-endif
- python3 -u -m pytest functional_tests/test_setup.py functional_tests/$(FILTER) --keep-duplicates -v -o junit_logging=all --junitxml $(FUNCTIONAL_TEST_JUNIT_XML) ${FUNCTIONAL_TEST_EXTRA_PARAMS} --keep-environment --test-dir $(FUNCTIONAL_TEST_DIR) --build-output $(BUILD_OUTPUT) --force-upload
+functional-test-core: artifacts/osmodifier build-functional-test-cc generate-functional-test-manifest artifacts/trident-functest.qcow2
+ python3 -u -m \
+ pytest --color=yes \
+ --log-level=INFO \
+ --force-upload \
+ functional_tests/test_setup.py \
+ functional_tests/$(FILTER) \
+ --keep-duplicates \
+ -v \
+ -o junit_logging=all \
+ --junitxml $(FUNCTIONAL_TEST_JUNIT_XML) \
+ ${FUNCTIONAL_TEST_EXTRA_PARAMS} \
+ --keep-environment \
+ --test-dir $(FUNCTIONAL_TEST_DIR) \
+ --build-output $(BUILD_OUTPUT)
.PHONY: patch-functional-test
-patch-functional-test: build-functional-test-cc generate-functional-test-manifest
- ARGUS_TOOLKIT_PATH=$(ARGUS_TOOLKIT_PATH) python3 -u -m pytest functional_tests/$(FILTER) -v -o junit_logging=all --junitxml $(FUNCTIONAL_TEST_JUNIT_XML) ${FUNCTIONAL_TEST_EXTRA_PARAMS} --keep-environment --test-dir $(FUNCTIONAL_TEST_DIR) --build-output $(BUILD_OUTPUT) --reuse-environment
+patch-functional-test: artifacts/osmodifier build-functional-test-cc generate-functional-test-manifest
+ python3 -u -m \
+ pytest --color=yes \
+ --log-level=INFO \
+ --force-upload \
+ functional_tests/$(FILTER) \
+ -v \
+ -o junit_logging=all \
+ --junitxml $(FUNCTIONAL_TEST_JUNIT_XML) \
+ ${FUNCTIONAL_TEST_EXTRA_PARAMS} \
+ --keep-environment \
+ --test-dir $(FUNCTIONAL_TEST_DIR) \
+ --build-output $(BUILD_OUTPUT) \
+ --reuse-environment
.PHONY: generate-functional-test-manifest
generate-functional-test-manifest: .cargo/config
@@ -299,10 +345,10 @@ generate-functional-test-manifest: .cargo/config
.PHONY: validate-configs
validate-configs: bin/trident
- $(eval DETECTED_HC_FILES := $(shell grep -R 'storage:' . --include '*.yaml' --exclude-dir=trident-mos --exclude-dir=target --exclude-dir=dev --exclude-dir=azure-linux-image-tools -l))
+ $(eval DETECTED_HC_FILES := $(shell grep -R 'storage:' . --include '*.yaml' --exclude-dir=trident-mos --exclude-dir=target --exclude-dir=dev --exclude-dir=azure-linux-image-tools --exclude-dir=docbuilder -l))
@for file in $(DETECTED_HC_FILES); do \
echo "Validating $$file"; \
- $< validate $$file || exit 1; \
+ $< validate $$file -v info || exit 1; \
done
.PHONY: generate-mermaid-diagrams
@@ -339,8 +385,8 @@ bin/mkcosi: tools/cmd/mkcosi/* tools/go.sum tools/pkg/* tools/cmd/mkcosi/**/*
bin/storm-trident: $(shell find storm -type f) tools/go.sum
@mkdir -p bin
- cd storm && go generate suites/trident/e2e/discover.go
- cd storm && go build -o ../bin/storm-trident ./cmd/storm-trident/main.go
+ cd tools && go generate storm/e2e/discover.go
+ cd tools && go build -o ../bin/storm-trident ./cmd/storm-trident/main.go
.PHONY: validate
validate: $(TRIDENT_CONFIG) bin/trident
@@ -374,12 +420,12 @@ run-netlaunch: $(NETLAUNCH_CONFIG) $(TRIDENT_CONFIG) $(NETLAUNCH_ISO) bin/netlau
run-netlaunch-container-images: \
validate \
$(NETLAUNCH_CONFIG) \
- artifacts/trident-container-installer-testimage.iso \
+ artifacts/trident-container-installer.iso \
artifacts/test-image/trident-container.tar.gz \
$(TRIDENT_CONFIG) \
bin/netlaunch
@bin/netlaunch \
- --iso artifacts/trident-container-installer-testimage.iso \
+ --iso artifacts/trident-container-installer.iso \
$(if $(NETLAUNCH_PORT),--port $(NETLAUNCH_PORT)) \
--config $(NETLAUNCH_CONFIG) \
--trident $(TRIDENT_CONFIG) \
@@ -412,6 +458,30 @@ run-netlaunch-sample: build-api-docs
yq '.os.users += [{"name": "$(shell whoami)", "sshPublicKeys": ["$(shell cat ~/.ssh/id_rsa.pub)"], "sshMode": "key-only", "secondaryGroups": ["wheel"]}] | (.. | select(tag == "!!str")) |= sub("file:///trident_cdrom/data", "http://NETLAUNCH_HOST_ADDRESS/files") | del(.storage.encryption.recoveryKeyUrl) | (.storage.filesystems[] | select(has("source")) | .source).sha256 = "ignored" | .storage.verityFilesystems[].dataImage.sha256 = "ignored" | .storage.verityFilesystems[].hashImage.sha256 = "ignored"' docs/Reference/Host-Configuration/Samples/$(HOST_CONFIG) > $(TMP)
TRIDENT_CONFIG=$(TMP) make run-netlaunch
+# Downloads the latest Trident functional test image from the Azure DevOps pipeline.
+artifacts/trident-functest.qcow2:
+ $(eval BRANCH ?= main)
+ $(eval RUN_ID ?= $(shell az pipelines runs list \
+ --org "https://dev.azure.com/mariner-org" \
+ --project "ECF" \
+ --pipeline-ids 3371 \
+ --branch $(BRANCH) \
+ --query-order QueueTimeDesc \
+ --result succeeded \
+ --reason triggered \
+ --top 1 \
+ --query '[0].id'))
+ @echo PIPELINE RUN ID: $(RUN_ID)
+
+ mkdir -p artifacts
+ rm -f $@
+ az pipelines runs artifact download \
+ --org 'https://dev.azure.com/mariner-org' \
+ --project "ECF" \
+ --run-id $(RUN_ID) \
+ --path artifacts/ \
+ --artifact-name 'trident-functest'
+
# Downloads regular, verity, and container COSI images from the latest successful
# pipeline run. The images are downloaded to ./artifacts/test-image.
.PHONY: download-runtime-images
@@ -428,6 +498,12 @@ download-runtime-images:
--top 1 \
--query '[0].id'))
@echo PIPELINE RUN ID: $(RUN_ID)
+
+# Clean & create artifacts dir
+ rm -rf ./artifacts/test-image
+ mkdir -p ./artifacts/test-image
+
+# Get regular image
$(eval DOWNLOAD_DIR := $(shell mktemp -d))
az pipelines runs artifact download \
--org 'https://dev.azure.com/mariner-org' \
@@ -436,15 +512,28 @@ download-runtime-images:
--path $(DOWNLOAD_DIR) \
--artifact-name 'trident-testimage'
-# Clean & create artifacts dir
- rm -rf ./artifacts/test-image
- mkdir -p ./artifacts/test-image
-# Move regular COSI image
- mv $(DOWNLOAD_DIR)/*.cosi ./artifacts/test-image/regular.cosi
+# Move COSI images
+ mv $(DOWNLOAD_DIR)/*_0.cosi ./artifacts/test-image/regular.cosi
+ mv $(DOWNLOAD_DIR)/*_1.cosi ./artifacts/test-image/regular_v2.cosi
+# Clean temp dir
+ rm -rf $(DOWNLOAD_DIR)
+
+# Get usr-verity image
+ $(eval DOWNLOAD_DIR := $(shell mktemp -d))
+ az pipelines runs artifact download \
+ --org 'https://dev.azure.com/mariner-org' \
+ --project "ECF" \
+ --run-id $(RUN_ID) \
+ --path $(DOWNLOAD_DIR) \
+ --artifact-name 'trident-usrverity-testimage'
+
+# Move COSI images
+ mv $(DOWNLOAD_DIR)/*_0.cosi ./artifacts/test-image/usrverity.cosi
+ mv $(DOWNLOAD_DIR)/*_1.cosi ./artifacts/test-image/usrverity_v2.cosi
# Clean temp dir
rm -rf $(DOWNLOAD_DIR)
-# Get verity image
+# Get root-verity image
$(eval DOWNLOAD_DIR := $(shell mktemp -d))
az pipelines runs artifact download \
--org 'https://dev.azure.com/mariner-org' \
@@ -453,8 +542,9 @@ download-runtime-images:
--path $(DOWNLOAD_DIR) \
--artifact-name 'trident-verity-testimage'
-# Move verity COSI image
- mv $(DOWNLOAD_DIR)/*.cosi ./artifacts/test-image/verity.cosi
+# Move COSI images
+ mv $(DOWNLOAD_DIR)/*_0.cosi ./artifacts/test-image/verity.cosi
+ mv $(DOWNLOAD_DIR)/*_1.cosi ./artifacts/test-image/verity_v2.cosi
# Clean temp dir
rm -rf $(DOWNLOAD_DIR)
@@ -467,8 +557,9 @@ download-runtime-images:
--path $(DOWNLOAD_DIR) \
--artifact-name 'trident-container-testimage'
-# Move container COSI image
- mv $(DOWNLOAD_DIR)/*.cosi ./artifacts/test-image/container.cosi
+# Move COSI images
+ mv $(DOWNLOAD_DIR)/*_0.cosi ./artifacts/test-image/container.cosi
+ mv $(DOWNLOAD_DIR)/*_1.cosi ./artifacts/test-image/container_v2.cosi
# Clean temp dir
rm -rf $(DOWNLOAD_DIR)
@@ -497,7 +588,7 @@ endif
--project "ECF" \
--run-id $(RUN_ID) \
--path artifacts/ \
- --artifact-name 'trident-installer-testimage'
+ --artifact-name 'trident-installer'
.PHONY: download-trident-container-installer-iso
download-trident-container-installer-iso:
@@ -519,11 +610,11 @@ download-trident-container-installer-iso:
--project "ECF" \
--run-id $(RUN_ID) \
--path artifacts/ \
- --artifact-name 'trident-container-installer-testimage'
+ --artifact-name 'trident-container-installer'
-artifacts/trident-container-installer-testimage.iso:
+artifacts/trident-container-installer.iso:
$(MAKE) download-trident-container-installer-iso; \
- ls -l artifacts/trident-container-installer-testimage.iso
+ ls -l artifacts/trident-container-installer.iso
# Copies locally built runtime images from ../test-images/build to ./artifacts/test-image.
# Expects that both the regular and verity Trident test images have been built.
@@ -597,7 +688,7 @@ artifacts/imagecustomizer:
@chmod +x artifacts/imagecustomizer
@touch artifacts/imagecustomizer
-bin/trident-mos.iso: artifacts/baremetal.vhdx artifacts/imagecustomizer systemd/trident-install.service trident-mos/iso.yaml trident-mos/files/* trident-mos/post-install.sh
+bin/trident-mos.iso: artifacts/baremetal.vhdx artifacts/imagecustomizer systemd/trident-install.service trident-mos/iso.yaml trident-mos/files/* trident-mos/post-install.sh selinux-policy-trident/*
@mkdir -p bin
BUILD_DIR=`mktemp -d` && \
trap 'sudo rm -rf $$BUILD_DIR' EXIT; \
diff --git a/azure-linux-image-tools b/azure-linux-image-tools
index c60e9422d..e52c4572c 160000
--- a/azure-linux-image-tools
+++ b/azure-linux-image-tools
@@ -1 +1 @@
-Subproject commit c60e9422d312c0a8af1844d3e954dcf4858da644
+Subproject commit e52c4572cf1b8d98738a2ba40d17006752b7d0e4
diff --git a/azurepipelines-coverage.yml b/azurepipelines-coverage.yml
new file mode 100644
index 000000000..716200487
--- /dev/null
+++ b/azurepipelines-coverage.yml
@@ -0,0 +1,5 @@
+coverage:
+ status: # Code coverage status will be posted to pull requests based on targets defined below.
+ comments: on # Off by default. When on, details about coverage for each file changed will be posted as a pull request comment.
+ diff: # diff coverage is code coverage only for the lines changed in a pull request.
+ target: 50% # set this to a desired %. Default is 50%
\ No newline at end of file
diff --git a/dev-docs/diagrams/overall-testing-on-baremetal.mmd b/dev-docs/diagrams/overall-testing-on-baremetal.mmd
index f685424ac..e27ef239e 100644
--- a/dev-docs/diagrams/overall-testing-on-baremetal.mmd
+++ b/dev-docs/diagrams/overall-testing-on-baremetal.mmd
@@ -16,7 +16,7 @@ F0 --> D["Strategy Matrix"]
subgraph Job to execute the test - trident_baremetal_tests
D --> E[Loop for each test from the list of E2E Tests]
E --> G[Run E2E Test]
- subgraph Seperate step for each test in Strategy Matrix
+ subgraph Separate step for each test in Strategy Matrix
G --> H[Checkout Repositories]
H --> I[Install prerequisites for BM Host communication - baremetal-prep.yml]
I --> J[Create SSH key and install prerequisites required for the E2E tests - trident-prep.yml]
diff --git a/dev-docs/prerequisites.md b/dev-docs/prerequisites.md
index 5d696272e..f44bede76 100644
--- a/dev-docs/prerequisites.md
+++ b/dev-docs/prerequisites.md
@@ -28,6 +28,7 @@
- Install `build-essential`, `pkg-config`, `libssl-dev`, `libclang-dev`, and
`protobuf-compiler`. E.g. `sudo apt install build-essential pkg-config
libssl-dev libclang-dev protobuf-compiler`.
+- Install the `virt-firmware` Python package: `sudo pip3 install virt-firmware`.
- Clone the [Trident
repository](https://mariner-org@dev.azure.com/mariner-org/ECF/_git/trident):
`git clone https://mariner-org@dev.azure.com/mariner-org/ECF/_git/trident`.
diff --git a/dev-docs/specs/Composable-OS-Image.md b/dev-docs/specs/Composable-OS-Image.md
index 19f4a759d..dbd5202ed 100644
--- a/dev-docs/specs/Composable-OS-Image.md
+++ b/dev-docs/specs/Composable-OS-Image.md
@@ -2,9 +2,10 @@
## Revision Summary
-| Revision | Date | Comment |
-| -------- | ---------- | ---------------- |
-| 1.0 | 2024-10-09 | Initial version. |
+| Revision | Spec Date |
+| ------------------- | ---------- |
+| [1.1](#revision-11) | TBD |
+| [1.0](#revision-10) | 2024-10-09 |
## Table of Contents
@@ -21,15 +22,22 @@
- [Metadata JSON File](#metadata-json-file)
- [Schema](#schema)
- [Root Object](#root-object)
- - [`Image` Object](#image-object)
+ - [`Filesystem` Object](#filesystem-object)
- [`VerityConfig` Object](#verityconfig-object)
- [`ImageFile` Object](#imagefile-object)
- [`OsArchitecture` Enum](#osarchitecture-enum)
- [`OsPackage` Object](#ospackage-object)
+ - [`Bootloader` Object](#bootloader-object)
+ - [`BootloaderType` Enum](#bootloadertype-enum)
+ - [`SystemDBoot` Object](#systemdboot-object)
+ - [`SystemDBootEntry` Object](#systemdbootentry-object)
+ - [`SystemDBootEntryType` Enum](#systemdbootentrytype-enum)
- [Samples](#samples)
- [Simple Image](#simple-image)
- - [Verity Image](#verity-image)
- - [Packages](#packages)
+ - [Verity Image with UKI](#verity-image-with-uki)
+ - [Changelog](#changelog)
+ - [Revision 1.1](#revision-11)
+ - [Revision 1.0](#revision-10)
- [FAQ and Notes](#faq-and-notes)
## Background
@@ -134,71 +142,68 @@ tarball. The metadata file MUST be a valid JSON file.
The metadata file MUST contain a JSON object with the following fields:
-| Field | Type | Required | Description |
-| ------------ | -------------------------------------- | -------- | ------------------------------------------------------ |
-| `version` | string `MAJOR.MINOR` | Yes | The version of the metadata schema. |
-| `osArch` | [OsArchitecture](#osarchitecture-enum) | Yes | The architecture of the OS. |
-| `osRelease` | string | Yes | The contents of `/etc/os-release` verbatim. |
-| `images` | [Image](#image-object)[] | Yes | Metadata of partition images that contain filesystems. |
-| `osPackages` | [OsPackage](#ospackage-object)[] | No | The list of packages installed in the OS. |
-| `id` | UUID (string, case insensitive) | No | A unique identifier for the COSI file. |
-
-To allow for future extensions, the object MAY contain other fields, but Trident
-MUST ignore them. The object SHOULD NOT contain any extra fields that will not
-be used by Trident.
-
-##### `Image` Object
-
-| Field | Type | Required | Description |
-| ------------ | ------------------------------------ | -------- | ----------------------------------------- |
-| `image` | [ImageFile](#imagefile-object) | Yes | Details of the image file in the tarball. |
-| `mountPoint` | string | Yes | The mount point of the partition. |
-| `fsType` | string | Yes | The filesystem type of the partition. [1] |
-| `fsUuid` | string | Yes | The UUID of the filesystem. [2] |
-| `partType` | UUID (string, case insensitive) | Yes | The GPT partition type. [3] [4] [5] |
-| `verity` | [VerityConfig](#verityconfig-object) | No | The verity metadata of the partition. |
+| Field | Type | Added in | Required | Description |
+| ------------ | -------------------------------------- | -------- | --------------- | ------------------------------------------------ |
+| `version` | string `MAJOR.MINOR` | 1.0 | Yes (since 1.0) | The version of the metadata schema. |
+| `osArch` | [OsArchitecture](#osarchitecture-enum) | 1.0 | Yes (since 1.0) | The architecture of the OS. |
+| `osRelease` | string | 1.0 | Yes (since 1.0) | The contents of `/etc/os-release` verbatim. |
+| `images` | [Filesystem](#filesystem-object)[] | 1.0 | Yes (since 1.0) | Filesystem metadata. |
+| `osPackages` | [OsPackage](#ospackage-object)[] | 1.0 | Yes (since 1.1) | The list of packages installed in the OS. |
+| `bootloader` | [Bootloader](#bootloader-object) | 1.1 | Yes (since 1.1) | Information about the bootloader used by the OS. |
+| `id` | UUID (string, case insensitive) | 1.0 | No | A unique identifier for the COSI file. |
+
+If the object contains other fields, readers MUST ignore them. A writer SHOULD
+NOT add any other files to the object.
+
+##### `Filesystem` Object
+
+This object carries information about a filesystem and the partition it comes
+from in a virtual disk.
+
+| Field | Type | Added in | Required | Description |
+| ------------ | ------------------------------------ | -------- | ---------------- | ----------------------------------------- |
+| `image` | [ImageFile](#imagefile-object) | 1.0 | Yes (since 1.0) | Details of the image file in the tarball. |
+| `mountPoint` | string | 1.0 | Yes (since 1.0) | The mount point of the filesystem. |
+| `fsType` | string | 1.0 | Yes (since 1.0) | The filesystem's type. [1] |
+| `fsUuid` | string | 1.0 | Yes (since 1.0) | The UUID of the filesystem. [2] |
+| `partType` | UUID (string, case insensitive) | 1.0 | Yes (since 1.0) | The GPT partition type. [3] [4] [5] |
+| `verity` | [VerityConfig](#verityconfig-object) | 1.0 | Conditionally[6] | The verity metadata of the filesystem. |
_Notes:_
-- **[1]** It MUST use the name recognized by the kernel. For example, `ext4` for ext4 filesystems,
- `vfat` for FAT32 filesystems, etc.
-
-- **[2]** It MUST be unique across all filesystems in the COSI tarball. Additionally, volumes in an
- A/B volume pair MUST have unique filesystem UUIDs.
+- **[1]** It MUST use the name recognized by the kernel. For example, `ext4` for
+ ext4 filesystems, `vfat` for FAT32 filesystems, etc.
+- **[2]** It MUST be unique across all filesystems in the COSI tarball.
+ Additionally, volumes in an A/B volume pair MUST have unique filesystem UUIDs.
- **[3]** It MUST be a UUID defined by the [Discoverable Partition Specification
- (DPS)](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/) when
- the applicable type exists in the DPS. Other partition types MAY be used for types not defined
- in DPS (e.g. Windows partitions).
-
-- **[4]** The EFI Sytem Partition (ESP) MUST be identified with the UUID established by the DPS:
- `c12a7328-f81f-11d2-ba4b-00a0c93ec93b`.
-
-- **[5]** Should default to `0fc63daf-8483-4772-8e79-3d69d8477de4` (Generic Linux Data) if the
- partition type cannot be determined.
+ (DPS)](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/)
+ when the applicable type exists in the DPS. Other partition types MAY be
+ used for types not defined in DPS (e.g. Windows partitions).
+- **[4]** The EFI Sytem Partition (ESP) MUST be identified with the UUID
+ established by the DPS: `c12a7328-f81f-11d2-ba4b-00a0c93ec93b`.
+- **[5]** Should default to `0fc63daf-8483-4772-8e79-3d69d8477de4` (Generic
+ Linux Data) if the partition type cannot be determined.
+- **[6]** The `verity` field MUST be specified if the OS is configured to open this
+ filesystem with `dm-verity`. Otherwise, it MUST be omitted OR set to `null`.
##### `VerityConfig` Object
The `VerityConfig` object contains information required to set up a verity
-device on top of a data partition.
+device on top of a data device.
-| Field | Type | Required | Description |
-| ---------- | ------------------------------ | -------- | -------------------------------------------------------- |
-| `image` | [ImageFile](#imagefile-object) | Yes | Details of the hash partition image file in the tarball. |
-| `roothash` | string | Yes | Verity root hash. |
+| Field | Type | Added in | Required | Description |
+| ---------- | ------------------------------ | -------- | --------------- | -------------------------------------------------------- |
+| `image` | [ImageFile](#imagefile-object) | 1.0 | Yes (since 1.0) | Details of the hash partition image file in the tarball. |
+| `roothash` | string | 1.0 | Yes (since 1.0) | Verity root hash. |
##### `ImageFile` Object
-| Field | Type | Required | Description |
-| ------------------ | ------ | -------- | ----------------------------------------------------------------------------------------- |
-| `path` | string | Yes | Absolute path of the compressed image file inside the tarball. MUST start with `images/`. |
-| `compressedSize` | number | Yes | Size of the compressed image in bytes. |
-| `uncompressedSize` | number | Yes | Size of the raw uncompressed image in bytes. |
-| `sha384` | string | No[5] | SHA-384 hash of the compressed hash image. |
-
-_Notes:_
-
-- **[5]** The `sha384` field is optional, but it is RECOMMENDED to include it
- for integrity verification.
+| Field | Type | Added in | Required | Description |
+| ------------------ | ------ | -------- | --------------- | ----------------------------------------------------------------------------------------- |
+| `path` | string | 1.0 | Yes (since 1.0) | Absolute path of the compressed image file inside the tarball. MUST start with `images/`. |
+| `compressedSize` | number | 1.0 | Yes (since 1.0) | Size of the compressed image in bytes. |
+| `uncompressedSize` | number | 1.0 | Yes (since 1.0) | Size of the raw uncompressed image in bytes. |
+| `sha384` | string | 1.0 | Yes (since 1.1) | SHA-384 hash of the compressed hash image. |
##### `OsArchitecture` Enum
@@ -216,19 +221,15 @@ The `osArch` field is case-insensitive.
##### `OsPackage` Object
-When present, the `osPackages` field in the root object MUST contain an array of
-`OsPackage` objects. Each object represents a package installed in the OS.
-
-The field is strictly optional, but recommended. Trident MAY use this field to
-figure out if the new OS is compatible with the Host Configuration by, for
-example, identifying missing dependencies.
+The `osPackages` field in the root object MUST contain an array of `OsPackage`
+objects. Each object represents a package installed in the OS.
-| Field | Type | Required | Description |
-| --------- | ------ | -------- | ------------------------------------- |
-| `name` | string | Yes | The name of the package. |
-| `version` | string | Yes | The version of the package installed. |
-| `release` | string | No | The release of the package. |
-| `arch` | string | No | The architecture of the package. |
+| Field | Type | Added in | Required | Description |
+| --------- | ------ | -------- | --------------- | ------------------------------------- |
+| `name` | string | 1.0 | Yes (since 1.0) | The name of the package. |
+| `version` | string | 1.0 | Yes (since 1.0) | The version of the package installed. |
+| `release` | string | 1.0 | Yes (since 1.1) | The release of the package. |
+| `arch` | string | 1.0 | Yes (since 1.1) | The architecture of the package. |
A suggested way to obtain this information is by running:
@@ -236,13 +237,65 @@ A suggested way to obtain this information is by running:
rpm -qa --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n"
```
+##### `Bootloader` Object
+
+| Field | Type | Added in | Required | Description |
+| ------------- | ---------------------------------------- | -------- | -------------------------------- | --------------------------- |
+| `type` | [`BootloaderType`](#bootloadertype-enum) | 1.1 | Yes (since 1.1) | The type of the bootloader. |
+| `systemdBoot` | [`SystemDBoot`](#systemdboot-object) | 1.1 | When `type` == `systemd-boot`[7] | systemd-boot configuration. |
+
+_Notes:_
+
+- **[7]** The `systemd-boot` field is required if the `type` field is set to
+ `systemd-boot`. It MUST be omitted OR set to `null` if the `type`
+ field is set to any other value.
+
+##### `BootloaderType` Enum
+
+A string that represents the primary bootloader used in the contained OS. These
+are the valid values for the `type` field in the `bootloader` object:
+
+| Value | Description |
+| -------------- | --------------------------------------------------- |
+| `systemd-boot` | The system is using systemd-boot as the bootloader. |
+| `grub` | The system is using GRUB as the bootloader. |
+
+##### `SystemDBoot` Object
+
+This object contains metadata about how systemd-boot is configured in the OS.
+
+| Field | Type | Added in | Required | Description |
+| --------- | ------------------------------------------------ | -------- | --------------- | ------------------------------------------------------------------------------------ |
+| `entries` | [`SystemDBootEntry`](#systemdbootentry-object)[] | 1.1 | Yes (since 1.1) | The contents of the `loader/entries/*.conf` files in the systemd-boot EFI partition. |
+
+##### `SystemDBootEntry` Object
+
+This object contains metadata about a specific systemd-boot entry.
+
+| Field | Type | Added in | Required | Description |
+| --------- | ---------------------------------------------------- | -------- | --------------- | ------------------------------------------------------ |
+| `type` | [`SystemDBootEntryType`](#systemdbootentrytype-enum) | 1.1 | Yes (since 1.1) | The type of the entry. |
+| `path` | string | 1.1 | Yes (since 1.1) | Absolute path (from the root FS) to the UKI or config. |
+| `cmdline` | string | 1.1 | Yes (since 1.1) | The kernel command line. |
+| `kernel` | string | 1.1 | Yes (since 1.1) | Kernel release as a string. |
+
+##### `SystemDBootEntryType` Enum
+
+A string that represents the type of the systemd-boot entry.
+
+| Value | Description |
+| ---------------- | ------------------------------------------------------------------ |
+| `uki-standalone` | The entry is a bare UKI file in the ESP. |
+| `uki-config` | The entry is a config file with a UKI. |
+| `config` | The entry is a config file with a kernel, initrd and command line. |
+
#### Samples
##### Simple Image
```json
{
- "version": "1.0",
+ "version": "1.1",
"images": [
{
"image": {
@@ -271,15 +324,39 @@ rpm -qa --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n"
"verity": null
}
],
- "osRelease": "NAME=\"Microsoft Azure Linux\"\nVERSION=\"3.0.20240824\"\nID=azurelinux\nVERSION_ID=\"3.0\"\nPRETTY_NAME=\"Microsoft Azure Linux 3.0\"\nANSI_COLOR=\"1;34\"\nHOME_URL=\"https://aka.ms/azurelinux\"\nBUG_REPORT_URL=\"https://aka.ms/azurelinux\"\nSUPPORT_URL=\"https://aka.ms/azurelinux\"\n"
+ "osRelease": "NAME=\"Microsoft Azure Linux\"\nVERSION=\"3.0.20240824\"\nID=azurelinux\nVERSION_ID=\"3.0\"\nPRETTY_NAME=\"Microsoft Azure Linux 3.0\"\nANSI_COLOR=\"1;34\"\nHOME_URL=\"https://aka.ms/azurelinux\"\nBUG_REPORT_URL=\"https://aka.ms/azurelinux\"\nSUPPORT_URL=\"https://aka.ms/azurelinux\"\n",
+ "bootloader": {
+ "type": "grub"
+ },
+ "osPackages": [
+ {
+ "name": "bash",
+ "version": "5.1.8",
+ "release": "1.azl3",
+ "arch": "x86_64"
+ },
+ {
+ "name": "coreutils",
+ "version": "8.32",
+ "release": "1.azl3",
+ "arch": "x86_64"
+ },
+ {
+ "name": "systemd",
+ "version": "255",
+ "release": "20.azl3",
+ "arch": "x86_64"
+ },
+ // More packages...
+ ]
}
```
-##### Verity Image
+##### Verity Image with UKI
```json
{
- "version": "1.0",
+ "version": "1.1",
"images": [
{
"image": {
@@ -304,37 +381,45 @@ rpm -qa --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n"
},
// More images...
],
- "osRelease": "NAME=\"Microsoft Azure Linux\"\nVERSION=\"3.0.20240824\"\nID=azurelinux\nVERSION_ID=\"3.0\"\nPRETTY_NAME=\"Microsoft Azure Linux 3.0\"\nANSI_COLOR=\"1;34\"\nHOME_URL=\"https://aka.ms/azurelinux\"\nBUG_REPORT_URL=\"https://aka.ms/azurelinux\"\nSUPPORT_URL=\"https://aka.ms/azurelinux\"\n"
-}
-```
-
-##### Packages
-
-```json
-{
- "version": "1.0",
- "images": [
- // Images...
- ],
- "osRelease": "",
+ "osRelease": "NAME=\"Microsoft Azure Linux\"\nVERSION=\"3.0.20240824\"\nID=azurelinux\nVERSION_ID=\"3.0\"\nPRETTY_NAME=\"Microsoft Azure Linux 3.0\"\nANSI_COLOR=\"1;34\"\nHOME_URL=\"https://aka.ms/azurelinux\"\nBUG_REPORT_URL=\"https://aka.ms/azurelinux\"\nSUPPORT_URL=\"https://aka.ms/azurelinux\"\n",
+ "bootloader": {
+ "type": "systemd-boot",
+ "systemdBoot": {
+ "entries": [
+ {
+ "type": "uki-standalone",
+ "path": "/boot/efi/EFI/Linux/azurelinux-uki.efi",
+ "cmdline": "root=/dev/disk/by-partuuid/88d2fa9b-7a32-450a-a9f8-aa9c3de79298 ro",
+ "kernel": "6.6.78.1-3.azl3"
+ }
+ ]
+ }
+ },
"osPackages": [
- {
- "name": "bash",
- "version": "5.1.8"
- },
- {
- "name": "coreutils",
- "version": "8.32"
- },
{
"name": "systemd",
- "version": "255"
+ "version": "255",
+ "release": "20.azl3",
+ "arch": "x86_64"
},
// More packages...
]
}
```
+## Changelog
+
+### Revision 1.1
+
+- Added `bootloader` field to the root object.
+- Root field `osPackages` is now required.
+- Field `sha384` in `ImageFile` object is now required.
+- Fields `release` and `arch` in `OsPackage` object are now required.
+
+### Revision 1.0
+
+- Initial revision
+
## FAQ and Notes
**Why tar?**
diff --git a/dev-docs/testing.md b/dev-docs/testing.md
index d3122132d..46331d6da 100644
--- a/dev-docs/testing.md
+++ b/dev-docs/testing.md
@@ -22,7 +22,7 @@ more details in the following sections.
- [Deploy Baremetal Environment - baremetal-deploy.yml](#deploy-baremetal-environment---baremetal-deployyml)
- [Run End-to-End Tests on the BM Host - e2e-test-run.yml](#run-end-to-end-tests-on-the-bm-host---e2e-test-runyml)
- [Update trident.yaml to reflect the OAM IP, HTTP server and SSH Key Details - baremetal-update-trident-host-config.yml](#update-tridentyaml-to-reflect-the-oam-ip-http-server-and-ssh-key-details---baremetal-update-trident-host-configyml)
- - [Boot baremetal lab machine - .pipelines/stages/testing\_baremetal/deploy\_on\_bm.py](#boot-baremetal-lab-machine---pipelinesstagestesting_baremetaldeploy_on_bmpy)
+ - [Boot baremetal lab machine - .pipelines/templates/stages/testing\_baremetal/deploy\_on\_bm.py](#boot-baremetal-lab-machine---pipelinestemplatesstagestesting_baremetaldeploy_on_bmpy)
## Unit Tests
@@ -89,9 +89,9 @@ Functional tests should:
Functional tests are structured as follows:
- `/functional_tests`: Contains the functional test code, leveraging `pytest`
- and common SSH interface from `platform-tests` repo. `pytest` creates the test VM
- using is Fixtures concept and while currently only a single VM is created to
- run all the tests, this could be easily extended to support seperate VMs for
+ and common SSH interface from `platform-tests` repo. `pytest` fixtures create
+ the test VM using virt-deploy. Currently, only one VM is created to run all
+ the tests, but this could be easily extended to support separate VMs for
different tests. Most of the time, no changes will be required to this layer
while developing functional tests.
- `/functional_tests/trident-setup.yaml`: Contains the initial host
@@ -139,10 +139,9 @@ deployment. The tests are started on the deployed OS through SSH connection.
In the functional test environment, tests are run on top of block device
/dev/sda. As a result, any changes made by the testing logic should **not**
-modify this block device. E.g., this block device should not be reformatted to
-a clean filesystem, be mounted/unmounted, etc. On the other hand, **/dev/sdb**
-is available for any modifications that are needed for functional testing
-purposes.
+modify this block device. E.g., this block device should not be reformatted to a
+clean filesystem, be mounted/unmounted, etc. On the other hand, **/dev/sdb** is
+available for any modifications that are needed for functional testing purposes.
### Functional Test Building and Execution
@@ -156,12 +155,9 @@ targets:
- `make functional-test`: This will build the tests locally with code coverage
profile (using internal `build-functional-test-cc` target), a new
- `virt-deploy` VM will be created and deployed using `netlaunch`. Afterwards,
+ `virt-deploy` VM will be created using a prebuilt qcow image. Afterwards,
tests will be uploaded into the VM, executed and code coverage will be
- downloaded for later viewing. To note, this will also execute all UTs. If you
- want to iterate on the tests without recreating the VM, but do want to
- redeploy the OS, you can: `make functional-test
- FUNCTIONAL_TEST_EXTRA_PARAMS="--reuse-environment --redeploy"`.
+ downloaded for later viewing.
- `make patch-functional-test`: This will build the tests locally with code
coverage profile (using internal `build-functional-test-cc` target), upload
@@ -169,17 +165,16 @@ targets:
code coverage for later viewing. This is useful when you want to iterate on
the tests and don't want to wait for the VM to be deployed again. It is
important to note that only tests that have changed will be re-uploaded. This
- is determined based on `cargo build` output. To note, this will also execute
- all UTs.
-
-To execute the functional tests, ensure that `platform-tests` and `argus-toolkit` of
-recent version are checked out side by side with the `trident` repo.
-Additionally, the following dependencies are required for the Ubuntu based
-pipelines, so you might need to install them on your development machine as well
-(note that this set is different per Ubuntu version and is provided just as an
-illustration of what works for [pipelines](.pipelines/netlaunch-testing.yml), so
-if you are on 22.04 or newer, you might not need to for example reinstall
-`python3-openssl`):
+ is determined based on `cargo build` output.
+
+To execute the functional tests, ensure that `platform-tests` and
+`argus-toolkit` of recent version are checked out side by side with the
+`trident` repo. Additionally, the following dependencies are required for the
+Ubuntu based pipelines, so you might need to install them on your development
+machine as well (note that this set is different per Ubuntu version and is
+provided just as an illustration of what works for
+[pipelines](.pipelines/netlaunch-testing.yml), so if you are on 22.04 or newer,
+you might not need to for example reinstall `python3-openssl`):
```bash
sudo apt install -y protobuf-compiler clang-7 bc
@@ -215,11 +210,11 @@ aggregated with the locally produced coverage results.
### Additional Notes
-`functional-test` target depends on `platform-tests` and `argus-toolkit` repos to be
-checked out side by side with the `trident` repo. This is because `platform-tests`
-repo contains the common logic to execute test logic over SSH connection and
-`argus-toolkit` repo contains the `netlaunch` and `virt-deploy` binaries, along
-with logic to generate the OS deployment ISO.
+`functional-test` target depends on `platform-tests` and `argus-toolkit` repos
+to be checked out side by side with the `trident` repo. This is because
+`platform-tests` repo contains the common logic to execute test logic over SSH
+connection and `argus-toolkit` repo contains the `netlaunch` and `virt-deploy`
+binaries, along with logic to generate the OS deployment ISO.
Both `functional-test` and `patch-functional-test` targets leverage `pytest`. To
get more detailed logs or do any changes to the `pytest` logic, you can modify
@@ -240,15 +235,16 @@ code.
### Selective Test Execution
-The functional test `make` targets support the variable `FILTER`. This is meant to
-be used to filter the tests that are executed. For example, if you want to execute
-only the tests from a certain rust crate, you can do:
+The functional test `make` targets support the variable `FILTER`. This is meant
+to be used to filter the tests that are executed. For example, if you want to
+execute only the tests from a certain rust crate, you can do:
```bash
make functional-test FILTER=ft.json::
```
-You can narrow down the filter by adding the modules, up to each individual test.
+You can narrow down the filter by adding the modules, up to each individual
+test.
```bash
make functional-test FILTER=ft.json::::::
@@ -294,11 +290,13 @@ End to end tests should:
#### Install prerequisites for BM Host communication - baremetal-prep.yml
-
+
#### Create prerequisites required for the E2E tests - trident-prep.yml
-
+
#### Deploy Baremetal Environment - baremetal-deploy.yml
@@ -310,7 +308,8 @@ End to end tests should:
#### Update trident.yaml to reflect the OAM IP, HTTP server and SSH Key Details - baremetal-update-trident-host-config.yml
-
+
#### Boot baremetal lab machine - .pipelines/templates/stages/testing_baremetal/deploy_on_bm.py
diff --git a/dev-docs/validating-container.md b/dev-docs/validating-container.md
index 884a94970..7975ff5e2 100644
--- a/dev-docs/validating-container.md
+++ b/dev-docs/validating-container.md
@@ -100,7 +100,6 @@ validating an image running Trident from a container.
```bash
./virt-deploy create --mem 11
- ./virt-deploy run
```
Note that at least 11GB of RAM is necessary to run Trident in a container,
diff --git a/docbuilder/Cargo.toml b/docbuilder/Cargo.toml
index a05165e83..5d811450b 100644
--- a/docbuilder/Cargo.toml
+++ b/docbuilder/Cargo.toml
@@ -20,7 +20,9 @@ serde = { version = "1.0.215", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9.34"
strum = "0.26.3"
+svg = "0.18.0"
tera = { version = "1.20.0" }
+textwrap = "0.16.2"
setsail = { path = "../setsail" }
diff --git a/docbuilder/src/main.rs b/docbuilder/src/main.rs
index cb9c653e8..bdb5ed57a 100644
--- a/docbuilder/src/main.rs
+++ b/docbuilder/src/main.rs
@@ -1,7 +1,7 @@
use std::path::PathBuf;
use anyhow::{Context, Error};
-use clap::{Args, Parser, Subcommand};
+use clap::{Args, Parser, Subcommand, ValueEnum};
use log::info;
use crate::schema_renderer::SchemaDocSettings;
@@ -10,6 +10,7 @@ mod host_config;
mod markdown;
mod schema_renderer;
mod setsail;
+mod trident_arch;
mod trident_cli;
#[derive(Parser, Debug)]
@@ -28,6 +29,9 @@ enum Commands {
/// Output documentation for Trident's CLI
TridentCli(TridentCliOpts),
+
+ /// Output a Trident arch diagram
+ TridentArch(TridentArchOpts),
}
#[derive(Args, Debug)]
@@ -48,12 +52,31 @@ struct TridentCliOpts {
output: Option,
}
-#[derive(Parser, Debug)]
+#[derive(Args, Debug)]
struct HostConfigCli {
#[clap(subcommand)]
command: HostConfigCommands,
}
+#[derive(Args, Debug)]
+struct TridentArchOpts {
+ /// Optional output file
+ ///
+ /// If not specified, will print to stdout.
+ #[clap(short, long)]
+ output: Option,
+
+ /// Arch diagram to output
+ selected: TridentArchSelection,
+}
+
+#[derive(Debug, ValueEnum, Clone, Copy)]
+#[clap(rename_all = "kebab-case")]
+enum TridentArchSelection {
+ Install,
+ Update,
+}
+
#[derive(Subcommand, Debug)]
enum HostConfigCommands {
/// Build markdown docs for Host Configuration
@@ -145,6 +168,9 @@ fn main() -> Result<(), Error> {
Commands::TridentCli(opts) => {
build_tricent_cli_docs(opts).context("Failed to build CLI docs")
}
+ Commands::TridentArch(opts) => {
+ build_trident_arch_diagram(opts).context("Failed to build arch diagram")
+ }
}
}
@@ -208,3 +234,25 @@ fn build_tricent_cli_docs(opts: TridentCliOpts) -> Result<(), Error> {
Ok(())
}
+
+fn build_trident_arch_diagram(opts: TridentArchOpts) -> Result<(), Error> {
+ info!("Building trident arch diagram");
+
+ let diagram = trident_arch::build_arch_diagram(opts.selected)
+ .context("Failed to build trident arch diagram")?;
+
+ if let Some(output) = opts.output {
+ let parent = output.parent().context("Failed to get parent directory")?;
+ std::fs::create_dir_all(parent).context(format!(
+ "Failed to create parent directory {}",
+ parent.display()
+ ))?;
+
+ std::fs::write(&output, diagram)
+ .context(format!("Failed to write to file {}", output.display()))?;
+ } else {
+ println!("{}", diagram);
+ }
+
+ Ok(())
+}
diff --git a/docbuilder/src/trident_arch/diagrams/install.yaml b/docbuilder/src/trident_arch/diagrams/install.yaml
new file mode 100644
index 000000000..43ca0c7ee
--- /dev/null
+++ b/docbuilder/src/trident_arch/diagrams/install.yaml
@@ -0,0 +1,135 @@
+legends:
+ verb:
+ friendly: Trident Invocation Verb
+ background: "#b03e00"
+ border: "#5a1f00"
+ operation:
+ friendly: Operation
+ background: "#023c57"
+ border: "#042433"
+ subsystem:
+ friendly: Subsystem
+ background: "#4EA72E"
+ border: "#1C440D"
+ step:
+ friendly: Step
+ background: "#A02B93"
+ border: "#410C3B"
+ hook:
+ friendly: Script Hook
+ background: "#FF5757"
+ border: "#C00000"
+ system:
+ friendly: System Action
+ background: "#9c2403"
+ border: "#4d1101"
+ storage:
+ friendly: Storage Configuration
+ background: "#01523c"
+ border: "#00241a"
+ mount:
+ friendly: Mount
+ background: "#324a02"
+ border: "#1b2901"
+root:
+ - name: install
+ legend: verb
+ children:
+ - name: Static Validation
+ comment: "Context-free validation of Host Config"
+ - name: Safety Check
+ - name: Stage
+ legend: operation
+ children:
+ - name: Load COSI
+ - name: "Pre-servicing Script Hook"
+ legend: hook
+ - name: "Dynamic Validation"
+ legend: step
+ - name: Prepare
+ legend: step
+ children:
+ - name: MOS Config
+ legend: subsystem
+ comment: "Changes to current OS"
+ - name: Hooks
+ legend: subsystem
+ comment: Stage addtl. files & scripts
+ - name: Block Device Creation
+ legend: storage
+ children:
+ - name: Close pre-existing devices
+ children:
+ - name: Close verity
+ - name: Close Encrypted Volumes
+ - name: Close RAID
+ - name: Create partitions
+ - name: Create RAID
+ - name: Create Encrypted Volumes
+ - name: Block Device Initialization
+ legend: storage
+ children:
+ - name: Deploy Images
+ - name: Create Filesystems
+ - name: Create swap
+ - name: Open dm-verity devices
+ - name: New OS Mount
+ legend: mount
+ children:
+ - name: Provision
+ legend: step
+ children:
+ - name: Boot
+ legend: subsystem
+ comment: ESP Deployment
+ - name: Hooks
+ legend: subsystem
+ children:
+ - name: "Post-provision Script Hook"
+ legend: hook
+ - name: |
+ Configure
+ (chroot)
+ legend: step
+ children:
+ - name: Storage
+ legend: subsystem
+ comment: "Regenerate fstab, crypttab, mdadm.conf"
+ - name: Boot
+ legend: subsystem
+ comment: "Update grub config when in use"
+ - name: Network
+ legend: subsystem
+ comment: "Write network config"
+ - name: OS Config
+ legend: subsystem
+ comment: Enact OS config changes
+ - name: Hooks
+ legend: subsystem
+ children:
+ - name: Post-configure Script Hook
+ legend: hook
+ - name: Initrd
+ legend: subsystem
+ comment: "Regenerate initrd when not UKI"
+ - name: SELinux
+ legend: subsystem
+ comment: "Relabel filesystems when enabled"
+ - name: "Finalize"
+ legend: operation
+ children:
+ - name: "Boot Entry Configuration"
+ children:
+ - name: Insert/Update Boot Entry
+ comment: "Label depends on active volume"
+ - name: "Set Boot Order"
+ comment: "New entry is first"
+ - name: "Set NextBoot"
+ - name: Trigger Reboot
+ - name: ""
+ legend: system
+ - name: "commit"
+ legend: verb
+ children:
+ - name: "Success/Rollback Detection"
+ comment: "Update is finalized on success"
diff --git a/docbuilder/src/trident_arch/mod.rs b/docbuilder/src/trident_arch/mod.rs
new file mode 100644
index 000000000..f36a6ca29
--- /dev/null
+++ b/docbuilder/src/trident_arch/mod.rs
@@ -0,0 +1,37 @@
+use std::path::PathBuf;
+
+use anyhow::{Context, Error, Ok};
+
+use crate::TridentArchSelection;
+
+mod nodes;
+mod render;
+
+use nodes::Diagram;
+
+fn get_diagram_base(selected: TridentArchSelection) -> Result {
+ let file = match selected {
+ TridentArchSelection::Install => "install.yaml",
+ TridentArchSelection::Update => "update.yaml",
+ };
+
+ let full_path = PathBuf::from(file!())
+ .parent()
+ .context("Failed to get parent directory")?
+ .join("diagrams")
+ .join(file);
+
+ let yaml = std::fs::read_to_string(&full_path)
+ .with_context(|| format!("Failed to read diagram file: {:?}", full_path))?;
+
+ serde_yaml::from_str(&yaml)
+ .with_context(|| format!("Failed to parse YAML for diagram '{:?}'", selected))
+}
+
+pub(super) fn build_arch_diagram(selected: TridentArchSelection) -> Result {
+ let diag = get_diagram_base(selected).context("Failed to get diagram base")?;
+
+ let svg = render::render(diag).context("Failed to render diagram")?;
+
+ Ok(svg.to_string())
+}
diff --git a/docbuilder/src/trident_arch/nodes.rs b/docbuilder/src/trident_arch/nodes.rs
new file mode 100644
index 000000000..4be450560
--- /dev/null
+++ b/docbuilder/src/trident_arch/nodes.rs
@@ -0,0 +1,75 @@
+use serde::{de::Visitor, Deserialize, Deserializer};
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub(super) struct Diagram {
+ #[serde(default, deserialize_with = "deserialize_legends")]
+ pub legends: Vec