diff --git a/pkg/dnfjson/dnfjson.go b/pkg/dnfjson/dnfjson.go index f92d5a7262..8f51cf00b1 100644 --- a/pkg/dnfjson/dnfjson.go +++ b/pkg/dnfjson/dnfjson.go @@ -160,6 +160,7 @@ type Solver struct { type DepsolveResult struct { Packages []rpmmd.PackageSpec Repos []rpmmd.RepoConfig + Modules []rpmmd.ModuleConfig SBOM *sbom.Document Solver string } @@ -231,7 +232,7 @@ func (s *Solver) Depsolve(pkgSets []rpmmd.PackageSet, sbomType sbom.StandardType return nil, fmt.Errorf("decoding depsolve result failed: %w", err) } - packages, repos := result.toRPMMD(rhsmMap) + packages, repos, modules := result.toRPMMD(rhsmMap) var sbomDoc *sbom.Document if sbomType != sbom.StandardTypeNone { @@ -243,6 +244,7 @@ func (s *Solver) Depsolve(pkgSets []rpmmd.PackageSet, sbomType sbom.StandardType return &DepsolveResult{ Packages: packages, + Modules: modules, Repos: repos, SBOM: sbomDoc, Solver: result.Solver, @@ -415,6 +417,17 @@ type repoConfig struct { repoHash string } +type moduleConfigModule struct { + Data string `json:"data"` + Path string `json:"path"` +} + +type moduleConfig struct { + Name string `json:"name"` + ModuleFile moduleConfigModule `json:"module-file"` + FailsafeFile moduleConfigModule `json:"failsafe-file"` +} + // use the hash calculated by the `rpmmd.RepoConfig.Hash()` // function rather than re-implementing the same code func (r *repoConfig) Hash() string { @@ -454,9 +467,10 @@ func (s *Solver) makeDepsolveRequest(pkgSets []rpmmd.PackageSet, sbomType sbom.S transactions := make([]transactionArgs, len(pkgSets)) for dsIdx, pkgSet := range pkgSets { transactions[dsIdx] = transactionArgs{ - PackageSpecs: pkgSet.Include, - ExcludeSpecs: pkgSet.Exclude, - InstallWeakDeps: pkgSet.InstallWeakDeps, + PackageSpecs: pkgSet.Include, + ExcludeSpecs: pkgSet.Exclude, + ModuleEnableSpecs: pkgSet.EnabledModules, + InstallWeakDeps: pkgSet.InstallWeakDeps, } for _, jobRepo := range pkgSet.Repositories { @@ -568,9 +582,10 @@ func (s *Solver) makeSearchRequest(repos []rpmmd.RepoConfig, packages []string) // convert internal a list of PackageSpecs and map of repoConfig to the rpmmd // equivalents and attach key and subscription information based on the // repository configs. -func (result depsolveResult) toRPMMD(rhsm map[string]bool) ([]rpmmd.PackageSpec, []rpmmd.RepoConfig) { +func (result depsolveResult) toRPMMD(rhsm map[string]bool) ([]rpmmd.PackageSpec, []rpmmd.RepoConfig, []rpmmd.ModuleConfig) { pkgs := result.Packages repos := result.Repos + modules := result.Modules rpmDependencies := make([]rpmmd.PackageSpec, len(pkgs)) for i, dep := range pkgs { repo, ok := repos[dep.RepoID] @@ -624,7 +639,23 @@ func (result depsolveResult) toRPMMD(rhsm map[string]bool) ([]rpmmd.PackageSpec, SSLClientCert: repo.SSLClientCert, }) } - return rpmDependencies, repoConfigs + + var moduleConfigs []rpmmd.ModuleConfig + for moduleName := range modules { + module := modules[moduleName] + + moduleConfigs = append(moduleConfigs, rpmmd.ModuleConfig{ + Name: moduleName, + + ModuleFilePath: module.ModuleFile.Path, + ModuleFileData: module.ModuleFile.Data, + + FailsafeFilePath: module.FailsafeFile.Path, + FailsafeFileData: module.FailsafeFile.Data, + }) + } + + return rpmDependencies, repoConfigs, moduleConfigs } // Request command and arguments for dnf-json @@ -712,6 +743,9 @@ type transactionArgs struct { // Packages to exclude from results ExcludeSpecs []string `json:"exclude-specs"` + // Modules to enable + ModuleEnableSpecs []string `json:"module-enable-specs"` + // IDs of repositories to use for this depsolve RepoIDs []string `json:"repo-ids"` @@ -722,8 +756,9 @@ type transactionArgs struct { type packageSpecs []PackageSpec type depsolveResult struct { - Packages packageSpecs `json:"packages"` - Repos map[string]repoConfig `json:"repos"` + Packages packageSpecs `json:"packages"` + Repos map[string]repoConfig `json:"repos"` + Modules map[string]moduleConfig `json:"modules"` // (optional) contains the solver used, e.g. "dnf5" Solver string `json:"solver,omitempty"` diff --git a/pkg/manifest/anaconda_installer.go b/pkg/manifest/anaconda_installer.go index bb82f5556d..d8bfd3edab 100644 --- a/pkg/manifest/anaconda_installer.go +++ b/pkg/manifest/anaconda_installer.go @@ -196,7 +196,7 @@ func (p *AnacondaInstaller) getPackageSpecs() []rpmmd.PackageSpec { return p.packageSpecs } -func (p *AnacondaInstaller) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig) { +func (p *AnacondaInstaller) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig, _ []rpmmd.ModuleConfig) { if len(p.packageSpecs) > 0 { panic("double call to serializeStart()") } diff --git a/pkg/manifest/anaconda_installer_iso_tree.go b/pkg/manifest/anaconda_installer_iso_tree.go index 65d6fa2bff..e8b80ed1ed 100644 --- a/pkg/manifest/anaconda_installer_iso_tree.go +++ b/pkg/manifest/anaconda_installer_iso_tree.go @@ -146,7 +146,7 @@ func (p *AnacondaInstallerISOTree) getBuildPackages(_ Distro) []string { return packages } -func (p *AnacondaInstallerISOTree) serializeStart(_ []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec, _ []rpmmd.RepoConfig) { +func (p *AnacondaInstallerISOTree) serializeStart(_ []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec, _ []rpmmd.RepoConfig, _ []rpmmd.ModuleConfig) { if p.ostreeCommitSpec != nil || p.containerSpec != nil { panic("double call to serializeStart()") } diff --git a/pkg/manifest/anaconda_installer_iso_tree_test.go b/pkg/manifest/anaconda_installer_iso_tree_test.go index 511ae63bff..bd176943db 100644 --- a/pkg/manifest/anaconda_installer_iso_tree_test.go +++ b/pkg/manifest/anaconda_installer_iso_tree_test.go @@ -266,11 +266,11 @@ func TestAnacondaISOTreePayloadsBad(t *testing.T) { assert.PanicsWithValue( "pipeline supports at most one ostree commit", - func() { pipeline.serializeStart(nil, nil, make([]ostree.CommitSpec, 2), nil) }, + func() { pipeline.serializeStart(nil, nil, make([]ostree.CommitSpec, 2), nil, nil) }, ) assert.PanicsWithValue( "pipeline supports at most one container", - func() { pipeline.serializeStart(nil, make([]container.Spec, 2), nil, nil) }, + func() { pipeline.serializeStart(nil, make([]container.Spec, 2), nil, nil, nil) }, ) } @@ -290,7 +290,7 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { t.Run("plain", func(t *testing.T) { pipeline := newTestAnacondaISOTree() pipeline.OSPipeline = osPayload - pipeline.serializeStart(nil, nil, nil, nil) + pipeline.serializeStart(nil, nil, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, payloadStages, @@ -303,7 +303,7 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { pipeline := newTestAnacondaISOTree() pipeline.OSPipeline = osPayload pipeline.Kickstart = &kickstart.Options{Path: testKsPath} - pipeline.serializeStart(nil, nil, nil, nil) + pipeline.serializeStart(nil, nil, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.kickstart"), @@ -316,7 +316,7 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { pipeline.OSPipeline = osPayload pipeline.Kickstart = &kickstart.Options{Path: testKsPath} pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, nil, nil) + pipeline.serializeStart(nil, nil, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux", "org.osbuild.kickstart"), @@ -328,7 +328,7 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { pipeline.OSPipeline = osPayload pipeline.Kickstart = &kickstart.Options{Path: testKsPath, Unattended: true} pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, nil, nil) + pipeline.serializeStart(nil, nil, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux", "org.osbuild.kickstart"), @@ -345,7 +345,7 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { SudoNopasswd: []string{`%wheel`, `%sudo`}, } pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, nil, nil) + pipeline.serializeStart(nil, nil, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux", "org.osbuild.kickstart"), @@ -365,7 +365,7 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { }, } pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, nil, nil) + pipeline.serializeStart(nil, nil, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux", "org.osbuild.kickstart"), @@ -385,7 +385,7 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { }, } pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, nil, nil) + pipeline.serializeStart(nil, nil, nil, nil, nil) assert.Panics(t, func() { pipeline.serialize() }) }) @@ -401,7 +401,7 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { }, } pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, nil, nil) + pipeline.serializeStart(nil, nil, nil, nil, nil) assert.Panics(t, func() { pipeline.serialize() }) }) } @@ -428,7 +428,7 @@ func TestAnacondaISOTreeSerializeWithOSTree(t *testing.T) { t.Run("plain", func(t *testing.T) { pipeline := newTestAnacondaISOTree() pipeline.Kickstart = &kickstart.Options{Path: testKsPath, OSTree: &kickstart.OSTree{}} - pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil) + pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, payloadStages, @@ -440,7 +440,7 @@ func TestAnacondaISOTreeSerializeWithOSTree(t *testing.T) { pipeline := newTestAnacondaISOTree() pipeline.Kickstart = &kickstart.Options{Path: testKsPath, OSTree: &kickstart.OSTree{}} pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil) + pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux"), variantStages)) @@ -450,7 +450,7 @@ func TestAnacondaISOTreeSerializeWithOSTree(t *testing.T) { pipeline := newTestAnacondaISOTree() pipeline.Kickstart = &kickstart.Options{Path: testKsPath, Unattended: true, OSTree: &kickstart.OSTree{}} pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil) + pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux"), variantStages)) @@ -466,7 +466,7 @@ func TestAnacondaISOTreeSerializeWithOSTree(t *testing.T) { OSTree: &kickstart.OSTree{}, } pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil) + pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux"), variantStages)) @@ -485,7 +485,7 @@ func TestAnacondaISOTreeSerializeWithOSTree(t *testing.T) { OSTree: &kickstart.OSTree{}, } pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil) + pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux"), variantStages)) @@ -504,7 +504,7 @@ func TestAnacondaISOTreeSerializeWithOSTree(t *testing.T) { OSTree: &kickstart.OSTree{}, } pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil) + pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil, nil) assert.Panics(t, func() { pipeline.serialize() }) }) @@ -521,7 +521,7 @@ func TestAnacondaISOTreeSerializeWithOSTree(t *testing.T) { OSTree: &kickstart.OSTree{}, } pipeline.ISOLinux = true - pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil) + pipeline.serializeStart(nil, nil, []ostree.CommitSpec{ostreeCommit}, nil, nil) assert.Panics(t, func() { pipeline.serialize() }) }) } @@ -552,7 +552,7 @@ func TestAnacondaISOTreeSerializeWithContainer(t *testing.T) { t.Run("kspath", func(t *testing.T) { pipeline := newTestAnacondaISOTree() pipeline.Kickstart = &kickstart.Options{Path: testKsPath} - pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil) + pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, payloadStages, @@ -564,7 +564,7 @@ func TestAnacondaISOTreeSerializeWithContainer(t *testing.T) { pipeline := newTestAnacondaISOTree() pipeline.Kickstart = &kickstart.Options{Path: testKsPath} pipeline.ISOLinux = true - pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil) + pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux"), variantStages)) @@ -577,7 +577,7 @@ func TestAnacondaISOTreeSerializeWithContainer(t *testing.T) { Unattended: true, KernelOptionsAppend: []string{"kernel.opt=1", "debug"}, } - pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil) + pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() kickstartSt := findStage("org.osbuild.kickstart", sp.Stages) @@ -589,7 +589,7 @@ func TestAnacondaISOTreeSerializeWithContainer(t *testing.T) { t.Run("network-on-boot", func(t *testing.T) { pipeline := newTestAnacondaISOTree() pipeline.Kickstart = &kickstart.Options{Path: testKsPath, NetworkOnBoot: true} - pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil) + pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() kickstartSt := findStage("org.osbuild.kickstart", sp.Stages) @@ -609,7 +609,7 @@ func TestAnacondaISOTreeSerializeWithContainer(t *testing.T) { }, } pipeline.ISOLinux = true - pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil) + pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() assert.NoError(t, checkISOTreeStages(sp.Stages, append(payloadStages, "org.osbuild.isolinux"), variantStages)) @@ -620,7 +620,7 @@ func TestAnacondaISOTreeSerializeWithContainer(t *testing.T) { pipeline := newTestAnacondaISOTree() pipeline.Kickstart = &kickstart.Options{Path: testKsPath} pipeline.PayloadRemoveSignatures = true - pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil) + pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() skopeoStage := findStage("org.osbuild.skopeo", sp.Stages) @@ -651,7 +651,7 @@ restorecon -rvF /etc/sudoers.d func stagesFrom(pipeline Pipeline) []*osbuild.Stage { containerPayload := makeFakeContainerPayload() - pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil) + pipeline.serializeStart(nil, []container.Spec{containerPayload}, nil, nil, nil) sp := pipeline.serialize() pipeline.serializeEnd() return sp.Stages diff --git a/pkg/manifest/anaconda_installer_test.go b/pkg/manifest/anaconda_installer_test.go index aaa3ebbb7f..5d4d9195e2 100644 --- a/pkg/manifest/anaconda_installer_test.go +++ b/pkg/manifest/anaconda_installer_test.go @@ -105,7 +105,7 @@ func TestAnacondaInstallerModules(t *testing.T) { installerPipeline.UseLegacyAnacondaConfig = legacy installerPipeline.AdditionalAnacondaModules = tc.enable installerPipeline.DisabledAnacondaModules = tc.disable - installerPipeline.serializeStart(pkgs, nil, nil, nil) + installerPipeline.serializeStart(pkgs, nil, nil, nil, nil) pipeline := installerPipeline.serialize() require := require.New(t) diff --git a/pkg/manifest/build.go b/pkg/manifest/build.go index 715771ba8a..cca837fe0c 100644 --- a/pkg/manifest/build.go +++ b/pkg/manifest/build.go @@ -99,7 +99,7 @@ func (p *BuildrootFromPackages) getPackageSpecs() []rpmmd.PackageSpec { return p.packageSpecs } -func (p *BuildrootFromPackages) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig) { +func (p *BuildrootFromPackages) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig, _ []rpmmd.ModuleConfig) { if len(p.packageSpecs) > 0 { panic("double call to serializeStart()") } @@ -199,7 +199,7 @@ func (p *BuildrootFromContainer) getContainerSpecs() []container.Spec { return p.containerSpecs } -func (p *BuildrootFromContainer) serializeStart(_ []rpmmd.PackageSpec, containerSpecs []container.Spec, _ []ostree.CommitSpec, _ []rpmmd.RepoConfig) { +func (p *BuildrootFromContainer) serializeStart(_ []rpmmd.PackageSpec, containerSpecs []container.Spec, _ []ostree.CommitSpec, _ []rpmmd.RepoConfig, _ []rpmmd.ModuleConfig) { if len(p.containerSpecs) > 0 { panic("double call to serializeStart()") } diff --git a/pkg/manifest/build_test.go b/pkg/manifest/build_test.go index eb1da5680a..5e832ce0c9 100644 --- a/pkg/manifest/build_test.go +++ b/pkg/manifest/build_test.go @@ -109,7 +109,7 @@ func TestNewBuildFromContainerSpecs(t *testing.T) { } // containerSpecs is "nil" until serializeStart populates it require.Nil(t, build.getContainerSpecs()) - build.serializeStart(nil, fakeContainerSpecs, nil, nil) + build.serializeStart(nil, fakeContainerSpecs, nil, nil, nil) assert.Equal(t, build.getContainerSpecs(), fakeContainerSpecs) osbuildPipeline := build.serialize() diff --git a/pkg/manifest/commit_server_tree.go b/pkg/manifest/commit_server_tree.go index 8f9c8669f0..498f9dba71 100644 --- a/pkg/manifest/commit_server_tree.go +++ b/pkg/manifest/commit_server_tree.go @@ -80,7 +80,7 @@ func (p *OSTreeCommitServer) getPackageSpecs() []rpmmd.PackageSpec { return p.packageSpecs } -func (p *OSTreeCommitServer) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig) { +func (p *OSTreeCommitServer) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig, _ []rpmmd.ModuleConfig) { if len(p.packageSpecs) > 0 { panic("double call to serializeStart()") } diff --git a/pkg/manifest/coreos_installer.go b/pkg/manifest/coreos_installer.go index 0978e80346..799491dc08 100644 --- a/pkg/manifest/coreos_installer.go +++ b/pkg/manifest/coreos_installer.go @@ -136,7 +136,7 @@ func (p *CoreOSInstaller) getPackageSpecs() []rpmmd.PackageSpec { return p.packageSpecs } -func (p *CoreOSInstaller) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig) { +func (p *CoreOSInstaller) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig, _ []rpmmd.ModuleConfig) { if len(p.packageSpecs) > 0 { panic("double call to serializeStart()") } diff --git a/pkg/manifest/empty.go b/pkg/manifest/empty.go index 05c60cb4e1..c0e76abc90 100644 --- a/pkg/manifest/empty.go +++ b/pkg/manifest/empty.go @@ -65,7 +65,7 @@ func (p *ContentTest) getOSTreeCommits() []ostree.CommitSpec { return p.commitSpecs } -func (p *ContentTest) serializeStart(pkgs []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig) { +func (p *ContentTest) serializeStart(pkgs []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig, _ []rpmmd.ModuleConfig) { if p.serializing { panic("double call to serializeStart()") } diff --git a/pkg/manifest/manifest.go b/pkg/manifest/manifest.go index 1ae10c5a0f..825313fe98 100644 --- a/pkg/manifest/manifest.go +++ b/pkg/manifest/manifest.go @@ -145,7 +145,7 @@ func (m Manifest) Serialize(packageSets map[string][]rpmmd.PackageSpec, containe inline := make([]string, 0) containers := make([]container.Spec, 0) for _, pipeline := range m.pipelines { - pipeline.serializeStart(packageSets[pipeline.Name()], containerSpecs[pipeline.Name()], ostreeCommits[pipeline.Name()], rpmRepos[pipeline.Name()]) + pipeline.serializeStart(packageSets[pipeline.Name()], containerSpecs[pipeline.Name()], ostreeCommits[pipeline.Name()], rpmRepos[pipeline.Name()], nil) } for _, pipeline := range m.pipelines { commits = append(commits, pipeline.getOSTreeCommits()...) diff --git a/pkg/manifest/os.go b/pkg/manifest/os.go index 6192128bd1..0ac2f7aee1 100644 --- a/pkg/manifest/os.go +++ b/pkg/manifest/os.go @@ -178,6 +178,7 @@ type OS struct { // content-related fields repos []rpmmd.RepoConfig + modules []rpmmd.ModuleConfig packageSpecs []rpmmd.PackageSpec containerSpecs []container.Spec ostreeParentSpec *ostree.CommitSpec @@ -376,13 +377,15 @@ func (p *OS) getContainerSpecs() []container.Spec { return p.containerSpecs } -func (p *OS) serializeStart(packages []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig) { +func (p *OS) serializeStart(packages []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec, rpmRepos []rpmmd.RepoConfig, modules []rpmmd.ModuleConfig) { if len(p.packageSpecs) > 0 { panic("double call to serializeStart()") } p.packageSpecs = packages p.containerSpecs = containers + p.modules = modules + if len(commits) > 0 { if len(commits) > 1 { panic("pipeline supports at most one ostree commit") @@ -404,6 +407,7 @@ func (p *OS) serializeEnd() { p.kernelVer = "" p.packageSpecs = nil p.containerSpecs = nil + p.modules = nil p.ostreeParentSpec = nil } diff --git a/pkg/manifest/os_test.go b/pkg/manifest/os_test.go index dddb9aeada..40ca9b4644 100644 --- a/pkg/manifest/os_test.go +++ b/pkg/manifest/os_test.go @@ -34,7 +34,7 @@ func NewTestOS() *OS { packages := []rpmmd.PackageSpec{ {Name: "pkg1", Checksum: "sha1:c02524e2bd19490f2a7167958f792262754c5f46"}, } - os.serializeStart(packages, nil, nil, repos) + os.serializeStart(packages, nil, nil, repos, nil) return os } diff --git a/pkg/manifest/ostree_deployment.go b/pkg/manifest/ostree_deployment.go index a6886013eb..f823889794 100644 --- a/pkg/manifest/ostree_deployment.go +++ b/pkg/manifest/ostree_deployment.go @@ -161,7 +161,7 @@ func (p *OSTreeDeployment) getContainerSources() []container.SourceSpec { } } -func (p *OSTreeDeployment) serializeStart(_ []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec, _ []rpmmd.RepoConfig) { +func (p *OSTreeDeployment) serializeStart(_ []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec, _ []rpmmd.RepoConfig, _ []rpmmd.ModuleConfig) { if p.ostreeSpec != nil || p.containerSpec != nil { panic("double call to serializeStart()") } diff --git a/pkg/manifest/pipeline.go b/pkg/manifest/pipeline.go index a9325693e6..fc93709a88 100644 --- a/pkg/manifest/pipeline.go +++ b/pkg/manifest/pipeline.go @@ -53,7 +53,7 @@ type Pipeline interface { // its full Spec. See the ostree package for more details. getOSTreeCommitSources() []ostree.SourceSpec - serializeStart([]rpmmd.PackageSpec, []container.Spec, []ostree.CommitSpec, []rpmmd.RepoConfig) + serializeStart([]rpmmd.PackageSpec, []container.Spec, []ostree.CommitSpec, []rpmmd.RepoConfig, []rpmmd.ModuleConfig) serializeEnd() serialize() osbuild.Pipeline @@ -166,7 +166,7 @@ func NewBase(name string, build Build) Base { // serializeStart must be called exactly once before each call // to serialize(). -func (p Base) serializeStart([]rpmmd.PackageSpec, []container.Spec, []ostree.CommitSpec, []rpmmd.RepoConfig) { +func (p Base) serializeStart([]rpmmd.PackageSpec, []container.Spec, []ostree.CommitSpec, []rpmmd.RepoConfig, []rpmmd.ModuleConfig) { } // serializeEnd must be called exactly once after each call to diff --git a/pkg/manifest/raw_bootc.go b/pkg/manifest/raw_bootc.go index dce79bba76..09b3afaeba 100644 --- a/pkg/manifest/raw_bootc.go +++ b/pkg/manifest/raw_bootc.go @@ -71,7 +71,7 @@ func (p *RawBootcImage) getContainerSpecs() []container.Spec { return p.containerSpecs } -func (p *RawBootcImage) serializeStart(_ []rpmmd.PackageSpec, containerSpecs []container.Spec, _ []ostree.CommitSpec, _ []rpmmd.RepoConfig) { +func (p *RawBootcImage) serializeStart(_ []rpmmd.PackageSpec, containerSpecs []container.Spec, _ []ostree.CommitSpec, _ []rpmmd.RepoConfig, _ []rpmmd.ModuleConfig) { if len(p.containerSpecs) > 0 { panic("double call to serializeStart()") } diff --git a/pkg/manifest/raw_bootc_export_test.go b/pkg/manifest/raw_bootc_export_test.go index 2e87203c8a..c0976b2abf 100644 --- a/pkg/manifest/raw_bootc_export_test.go +++ b/pkg/manifest/raw_bootc_export_test.go @@ -16,5 +16,5 @@ func (rbc *RawBootcImage) Serialize() osbuild.Pipeline { } func (rbc *RawBootcImage) SerializeStart(a []rpmmd.PackageSpec, b []container.Spec, c []ostree.CommitSpec, r []rpmmd.RepoConfig) { - rbc.serializeStart(a, b, c, r) + rbc.serializeStart(a, b, c, r, nil) } diff --git a/pkg/rpmmd/repository.go b/pkg/rpmmd/repository.go index e897a0a56b..86d1a4c67a 100644 --- a/pkg/rpmmd/repository.go +++ b/pkg/rpmmd/repository.go @@ -57,6 +57,19 @@ type RepoConfig struct { SSLClientCert string `json:"sslclientcert,omitempty"` } +// A module config contains the configuration file for the module to put +// in `/etc/dnf/modules.d/{Name}` and the failsafe file to put in +// `/var/lib/dnf/modulefailsafe`. +type ModuleConfig struct { + Name string + + ModuleFilePath string + ModuleFileData string + + FailsafeFilePath string + FailsafeFileData string +} + // Hash calculates an ID string that uniquely represents a repository // configuration. The Name and ImageTypeTags fields are not considered in the // calculation. @@ -137,12 +150,15 @@ func (pkg Package) ToPackageInfo() PackageInfo { // The inputs to depsolve, a set of packages to include and a set of packages // to exclude. The Repositories are used when depsolving this package set in -// addition to the base repositories. +// addition to the base repositories. When modules are passed they are enabled +// before the rest of the depsolve as well. Note that we only expose enabled +// modules and not installation modules. type PackageSet struct { Include []string Exclude []string Repositories []RepoConfig InstallWeakDeps bool + EnabledModules []string } // Append the Include and Exclude package list from another PackageSet and