distro: set the repository checksum dynamically
Instead of having a static repository checksum, set it dynamically from the metadata that osbuild-composer last saw. This is implemented in dnf-json, which returns the checksums for each repository on every call. This enables the use of repositories that change over time, such as fedora-updates. Note that the osbuild pipeline will break when such a repository changes. This is intentional: pipelines have to be reproducible.
This commit is contained in:
parent
75218ad2d9
commit
d3a0b788a2
20 changed files with 184 additions and 95 deletions
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro"
|
||||
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
@ -36,7 +37,25 @@ func main() {
|
|||
panic("unknown distro: " + distroArg)
|
||||
}
|
||||
|
||||
pipeline, err := d.Pipeline(blueprint, format)
|
||||
packages := make([]string, len(blueprint.Packages))
|
||||
for i, pkg := range blueprint.Packages {
|
||||
packages[i] = pkg.Name
|
||||
// If a package has version "*" the package name suffix must be equal to "-*-*.*"
|
||||
// Using just "-*" would find any other package containing the package name
|
||||
if pkg.Version != "" && pkg.Version != "*" {
|
||||
packages[i] += "-" + pkg.Version
|
||||
} else if pkg.Version == "*" {
|
||||
packages[i] += "-*-*.*"
|
||||
}
|
||||
}
|
||||
|
||||
rpmmd := rpmmd.NewRPMMD()
|
||||
_, checksums, err := rpmmd.Depsolve(packages, d.Repositories())
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
pipeline, err := d.Pipeline(blueprint, checksums, format)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
|
|
|||
41
dnf-json
41
dnf-json
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import datetime
|
||||
import dnf
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ def dnfrepo(desc, parent_conf=None):
|
|||
elif "metalink" in desc:
|
||||
repo.metalink = desc["metalink"]
|
||||
elif "mirrorlist" in desc:
|
||||
repo.metalink = desc["mirrorlist"]
|
||||
repo.mirrorlist = desc["mirrorlist"]
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
|
@ -46,6 +47,30 @@ def exit_with_dnf_error(kind: str, reason: str):
|
|||
sys.exit(DNF_ERROR_EXIT_CODE)
|
||||
|
||||
|
||||
def repo_checksums(base):
|
||||
checksums = {}
|
||||
for repo in base.repos.iter_enabled():
|
||||
# Uses the same algorithm as libdnf to find cache dir:
|
||||
# https://github.com/rpm-software-management/libdnf/blob/master/libdnf/repo/Repo.cpp#L1288
|
||||
if repo.metalink:
|
||||
url = repo.metalink
|
||||
elif repo.mirrorlist:
|
||||
url = repo.mirrorlist
|
||||
elif repo.baseurl:
|
||||
url = repo.baseurl[0]
|
||||
else:
|
||||
assert False
|
||||
|
||||
digest = hashlib.sha256(url.encode()).hexdigest()[:16]
|
||||
|
||||
with open(f"{base.conf.cachedir}/{repo.id}-{digest}/repodata/repomd.xml", "rb") as f:
|
||||
repomd = f.read()
|
||||
|
||||
checksums[repo.id] = "sha256:" + hashlib.sha256(repomd).hexdigest()
|
||||
|
||||
return checksums
|
||||
|
||||
|
||||
call = json.load(sys.stdin)
|
||||
command = call["command"]
|
||||
arguments = call.get("arguments", {})
|
||||
|
|
@ -66,7 +91,10 @@ if command == "dump":
|
|||
"buildtime": timestamp_to_rfc3339(package.buildtime),
|
||||
"license": package.license
|
||||
})
|
||||
json.dump(packages, sys.stdout)
|
||||
json.dump({
|
||||
"checksums": repo_checksums(base),
|
||||
"packages": packages
|
||||
}, sys.stdout)
|
||||
|
||||
elif command == "depsolve":
|
||||
base = create_base(arguments.get("repos", {}))
|
||||
|
|
@ -82,13 +110,16 @@ elif command == "depsolve":
|
|||
except dnf.exceptions.DepsolveError as e:
|
||||
exit_with_dnf_error("DepsolveError", f"There was a problem depsolving {arguments['package-specs']}: {e}")
|
||||
|
||||
packages = []
|
||||
dependencies = []
|
||||
for package in base.transaction.install_set:
|
||||
packages.append({
|
||||
dependencies.append({
|
||||
"name": package.name,
|
||||
"epoch": package.epoch,
|
||||
"version": package.version,
|
||||
"release": package.release,
|
||||
"arch": package.arch
|
||||
})
|
||||
json.dump(packages, sys.stdout)
|
||||
json.dump({
|
||||
"checksums": repo_checksums(base),
|
||||
"dependencies": dependencies
|
||||
}, sys.stdout)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ type Distro interface {
|
|||
// Returns an osbuild pipeline that generates an image in the given
|
||||
// output format with all packages and customizations specified in the
|
||||
// given blueprint.
|
||||
Pipeline(b *blueprint.Blueprint, outputFormat string) (*pipeline.Pipeline, error)
|
||||
Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputFormat string) (*pipeline.Pipeline, error)
|
||||
|
||||
// Returns a osbuild runner that can be used on this distro.
|
||||
Runner() string
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ func TestDistro_Pipeline(t *testing.T) {
|
|||
type compose struct {
|
||||
Distro string `json:"distro"`
|
||||
OutputFormat string `json:"output-format"`
|
||||
Checksums map[string]string `json:"checksums"`
|
||||
Blueprint *blueprint.Blueprint `json:"blueprint"`
|
||||
}
|
||||
var tt struct {
|
||||
|
|
@ -45,7 +46,7 @@ func TestDistro_Pipeline(t *testing.T) {
|
|||
t.Errorf("unknown distro: %v", tt.Compose.Distro)
|
||||
return
|
||||
}
|
||||
got, err := d.Pipeline(tt.Compose.Blueprint, tt.Compose.OutputFormat)
|
||||
got, err := d.Pipeline(tt.Compose.Blueprint, tt.Compose.Checksums, tt.Compose.OutputFormat)
|
||||
if (err != nil) != (tt.Pipeline == nil) {
|
||||
t.Errorf("distro.Pipeline() error = %v", err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -221,7 +221,6 @@ func (r *Fedora30) Repositories() []rpmmd.RepoConfig {
|
|||
Id: "fedora",
|
||||
Name: "Fedora 30",
|
||||
Metalink: "https://mirrors.fedoraproject.org/metalink?repo=fedora-30&arch=x86_64",
|
||||
Checksum: "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97",
|
||||
GPGKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBFturGcBEACv0xBo91V2n0uEC2vh69ywCiSyvUgN/AQH8EZpCVtM7NyjKgKm
|
||||
|
|
@ -271,17 +270,17 @@ func (r *Fedora30) FilenameFromType(outputFormat string) (string, string, error)
|
|||
return "", "", errors.New("invalid output format: " + outputFormat)
|
||||
}
|
||||
|
||||
func (r *Fedora30) Pipeline(b *blueprint.Blueprint, outputFormat string) (*pipeline.Pipeline, error) {
|
||||
func (r *Fedora30) Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputFormat string) (*pipeline.Pipeline, error) {
|
||||
output, exists := r.outputs[outputFormat]
|
||||
if !exists {
|
||||
return nil, errors.New("invalid output format: " + outputFormat)
|
||||
}
|
||||
|
||||
p := &pipeline.Pipeline{}
|
||||
p.SetBuild(r.buildPipeline(), "org.osbuild.fedora30")
|
||||
p.SetBuild(r.buildPipeline(checksums), "org.osbuild.fedora30")
|
||||
|
||||
packages := append(output.Packages, b.GetPackages()...)
|
||||
p.AddStage(pipeline.NewDNFStage(r.dnfStageOptions(packages, output.ExcludedPackages)))
|
||||
p.AddStage(pipeline.NewDNFStage(r.dnfStageOptions(checksums, packages, output.ExcludedPackages)))
|
||||
p.AddStage(pipeline.NewFixBLSStage())
|
||||
|
||||
// TODO support setting all languages and install corresponding langpack-* package
|
||||
|
|
@ -347,7 +346,7 @@ func (r *Fedora30) Runner() string {
|
|||
return "org.osbuild.fedora30"
|
||||
}
|
||||
|
||||
func (r *Fedora30) buildPipeline() *pipeline.Pipeline {
|
||||
func (r *Fedora30) buildPipeline(checksums map[string]string) *pipeline.Pipeline {
|
||||
packages := []string{
|
||||
"dnf",
|
||||
"e2fsprogs",
|
||||
|
|
@ -358,11 +357,11 @@ func (r *Fedora30) buildPipeline() *pipeline.Pipeline {
|
|||
"tar",
|
||||
}
|
||||
p := &pipeline.Pipeline{}
|
||||
p.AddStage(pipeline.NewDNFStage(r.dnfStageOptions(packages, nil)))
|
||||
p.AddStage(pipeline.NewDNFStage(r.dnfStageOptions(checksums, packages, nil)))
|
||||
return p
|
||||
}
|
||||
|
||||
func (r *Fedora30) dnfStageOptions(packages, excludedPackages []string) *pipeline.DNFStageOptions {
|
||||
func (r *Fedora30) dnfStageOptions(checksums map[string]string, packages, excludedPackages []string) *pipeline.DNFStageOptions {
|
||||
options := &pipeline.DNFStageOptions{
|
||||
ReleaseVersion: "30",
|
||||
BaseArchitecture: "x86_64",
|
||||
|
|
@ -372,8 +371,8 @@ func (r *Fedora30) dnfStageOptions(packages, excludedPackages []string) *pipelin
|
|||
BaseURL: repo.BaseURL,
|
||||
MetaLink: repo.Metalink,
|
||||
MirrorList: repo.MirrorList,
|
||||
Checksum: repo.Checksum,
|
||||
GPGKey: repo.GPGKey,
|
||||
Checksum: checksums[repo.Id],
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -269,13 +269,11 @@ func (r *RHEL82) Repositories() []rpmmd.RepoConfig {
|
|||
Id: "baseos",
|
||||
Name: "BaseOS",
|
||||
BaseURL: "http://download-ipv4.eng.brq.redhat.com/rhel-8/nightly/RHEL-8/RHEL-8.2.0-20191125.n.1/compose/BaseOS/x86_64/os",
|
||||
Checksum: "sha256:30b905ab1538243de69e019573443b2a1e4edad7c1f7d32aa5a4fb014ff98060",
|
||||
},
|
||||
{
|
||||
Id: "appstream",
|
||||
Name: "AppStream",
|
||||
BaseURL: "http://download-ipv4.eng.brq.redhat.com/rhel-8/nightly/RHEL-8/RHEL-8.2.0-20191125.n.1/compose/AppStream/x86_64/os",
|
||||
Checksum: "sha256:afd86d5b664ec87e209c5ff3cf011bcc6a40578394191c1d889b4ead17a072ae",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -296,17 +294,17 @@ func (r *RHEL82) FilenameFromType(outputFormat string) (string, string, error) {
|
|||
return "", "", errors.New("invalid output format: " + outputFormat)
|
||||
}
|
||||
|
||||
func (r *RHEL82) Pipeline(b *blueprint.Blueprint, outputFormat string) (*pipeline.Pipeline, error) {
|
||||
func (r *RHEL82) Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputFormat string) (*pipeline.Pipeline, error) {
|
||||
output, exists := r.outputs[outputFormat]
|
||||
if !exists {
|
||||
return nil, errors.New("invalid output format: " + outputFormat)
|
||||
}
|
||||
|
||||
p := &pipeline.Pipeline{}
|
||||
p.SetBuild(r.buildPipeline(), "org.osbuild.rhel82")
|
||||
p.SetBuild(r.buildPipeline(checksums), "org.osbuild.rhel82")
|
||||
|
||||
packages := append(output.Packages, b.GetPackages()...)
|
||||
p.AddStage(pipeline.NewDNFStage(r.dnfStageOptions(packages, output.ExcludedPackages)))
|
||||
p.AddStage(pipeline.NewDNFStage(r.dnfStageOptions(checksums, packages, output.ExcludedPackages)))
|
||||
p.AddStage(pipeline.NewFixBLSStage())
|
||||
|
||||
if output.IncludeFSTab {
|
||||
|
|
@ -377,7 +375,7 @@ func (r *RHEL82) Runner() string {
|
|||
return "org.osbuild.rhel82"
|
||||
}
|
||||
|
||||
func (r *RHEL82) buildPipeline() *pipeline.Pipeline {
|
||||
func (r *RHEL82) buildPipeline(checksums map[string]string) *pipeline.Pipeline {
|
||||
packages := []string{
|
||||
"dnf",
|
||||
"dracut-config-generic",
|
||||
|
|
@ -392,11 +390,11 @@ func (r *RHEL82) buildPipeline() *pipeline.Pipeline {
|
|||
"xfsprogs",
|
||||
}
|
||||
p := &pipeline.Pipeline{}
|
||||
p.AddStage(pipeline.NewDNFStage(r.dnfStageOptions(packages, nil)))
|
||||
p.AddStage(pipeline.NewDNFStage(r.dnfStageOptions(checksums, packages, nil)))
|
||||
return p
|
||||
}
|
||||
|
||||
func (r *RHEL82) dnfStageOptions(packages, excludedPackages []string) *pipeline.DNFStageOptions {
|
||||
func (r *RHEL82) dnfStageOptions(checksums map[string]string, packages, excludedPackages []string) *pipeline.DNFStageOptions {
|
||||
options := &pipeline.DNFStageOptions{
|
||||
ReleaseVersion: "8",
|
||||
BaseArchitecture: "x86_64",
|
||||
|
|
@ -407,7 +405,7 @@ func (r *RHEL82) dnfStageOptions(packages, excludedPackages []string) *pipeline.
|
|||
BaseURL: repo.BaseURL,
|
||||
MetaLink: repo.Metalink,
|
||||
MirrorList: repo.MirrorList,
|
||||
Checksum: repo.Checksum,
|
||||
Checksum: checksums[repo.Id],
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func (d *TestDistro) FilenameFromType(outputFormat string) (string, string, erro
|
|||
return "", "", errors.New("invalid output format: " + outputFormat)
|
||||
}
|
||||
|
||||
func (d *TestDistro) Pipeline(b *blueprint.Blueprint, outputFormat string) (*pipeline.Pipeline, error) {
|
||||
func (d *TestDistro) Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputFormat string) (*pipeline.Pipeline, error) {
|
||||
return nil, errors.New("invalid output format: " + outputFormat)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,13 +43,13 @@ func TestCreate(t *testing.T) {
|
|||
store := store.New(nil, distro.New("fedora-30"))
|
||||
api := jobqueue.New(nil, store)
|
||||
|
||||
err := store.PushCompose(id, &blueprint.Blueprint{}, "tar", nil)
|
||||
err := store.PushCompose(id, &blueprint.Blueprint{}, map[string]string{"fedora": "test:foo"}, "tar", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error pushing compose: %v", err)
|
||||
}
|
||||
|
||||
test.TestRoute(t, api, false, "POST", "/job-queue/v1/jobs", `{}`, http.StatusCreated,
|
||||
`{"id":"ffffffff-ffff-ffff-ffff-ffffffffffff","output_type":"tar","pipeline":{"build":{"pipeline":{"stages":[{"name":"org.osbuild.dnf","options":{"repos":[{"metalink":"https://mirrors.fedoraproject.org/metalink?repo=fedora-30\u0026arch=x86_64","gpgkey":"-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFturGcBEACv0xBo91V2n0uEC2vh69ywCiSyvUgN/AQH8EZpCVtM7NyjKgKm\nbbY4G3R0M3ir1xXmvUDvK0493/qOiFrjkplvzXFTGpPTi0ypqGgxc5d0ohRA1M75\nL+0AIlXoOgHQ358/c4uO8X0JAA1NYxCkAW1KSJgFJ3RjukrfqSHWthS1d4o8fhHy\nKJKEnirE5hHqB50dafXrBfgZdaOs3C6ppRIePFe2o4vUEapMTCHFw0woQR8Ah4/R\nn7Z9G9Ln+0Cinmy0nbIDiZJ+pgLAXCOWBfDUzcOjDGKvcpoZharA07c0q1/5ojzO\n4F0Fh4g/BUmtrASwHfcIbjHyCSr1j/3Iz883iy07gJY5Yhiuaqmp0o0f9fgHkG53\n2xCU1owmACqaIBNQMukvXRDtB2GJMuKa/asTZDP6R5re+iXs7+s9ohcRRAKGyAyc\nYKIQKcaA+6M8T7/G+TPHZX6HJWqJJiYB+EC2ERblpvq9TPlLguEWcmvjbVc31nyq\nSDoO3ncFWKFmVsbQPTbP+pKUmlLfJwtb5XqxNR5GEXSwVv4I7IqBmJz1MmRafnBZ\ng0FJUtH668GnldO20XbnSVBr820F5SISMXVwCXDXEvGwwiB8Lt8PvqzXnGIFDAu3\nDlQI5sxSqpPVWSyw08ppKT2Tpmy8adiBotLfaCFl2VTHwOae48X2dMPBvQARAQAB\ntDFGZWRvcmEgKDMwKSA8ZmVkb3JhLTMwLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJbbqxnAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRDvPBEfz8ZZudTnD/9170LL3nyTVUCFmBjT9wZ4gYnpwtKVPa/pKnxbbS+Bmmac\ng9TrT9pZbqOHrNJLiZ3Zx1Hp+8uxr3Lo6kbYwImLhkOEDrf4aP17HfQ6VYFbQZI8\nf79OFxWJ7si9+3gfzeh9UYFEqOQfzIjLWFyfnas0OnV/P+RMQ1Zr+vPRqO7AR2va\nN9wg+Xl7157dhXPCGYnGMNSoxCbpRs0JNlzvJMuAea5nTTznRaJZtK/xKsqLn51D\nK07k9MHVFXakOH8QtMCUglbwfTfIpO5YRq5imxlWbqsYWVQy1WGJFyW6hWC0+RcJ\nOx5zGtOfi4/dN+xJ+ibnbyvy/il7Qm+vyFhCYqIPyS5m2UVJUuao3eApE38k78/o\n8aQOTnFQZ+U1Sw+6woFTxjqRQBXlQm2+7Bt3bqGATg4sXXWPbmwdL87Ic+mxn/ml\nSMfQux/5k6iAu1kQhwkO2YJn9eII6HIPkW+2m5N1JsUyJQe4cbtZE5Yh3TRA0dm7\n+zoBRfCXkOW4krchbgww/ptVmzMMP7GINJdROrJnsGl5FVeid9qHzV7aZycWSma7\nCxBYB1J8HCbty5NjtD6XMYRrMLxXugvX6Q4NPPH+2NKjzX4SIDejS6JjgrP3KA3O\npMuo7ZHMfveBngv8yP+ZD/1sS6l+dfExvdaJdOdgFCnp4p3gPbw5+Lv70HrMjA==\n=BfZ/\n-----END PGP PUBLIC KEY BLOCK-----\n","checksum":"sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"}],"packages":["dnf","e2fsprogs","policycoreutils","qemu-img","systemd","grub2-pc","tar"],"releasever":"30","basearch":"x86_64"}}]},"runner":"org.osbuild.fedora30"},"stages":[{"name":"org.osbuild.dnf","options":{"repos":[{"metalink":"https://mirrors.fedoraproject.org/metalink?repo=fedora-30\u0026arch=x86_64","gpgkey":"-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFturGcBEACv0xBo91V2n0uEC2vh69ywCiSyvUgN/AQH8EZpCVtM7NyjKgKm\nbbY4G3R0M3ir1xXmvUDvK0493/qOiFrjkplvzXFTGpPTi0ypqGgxc5d0ohRA1M75\nL+0AIlXoOgHQ358/c4uO8X0JAA1NYxCkAW1KSJgFJ3RjukrfqSHWthS1d4o8fhHy\nKJKEnirE5hHqB50dafXrBfgZdaOs3C6ppRIePFe2o4vUEapMTCHFw0woQR8Ah4/R\nn7Z9G9Ln+0Cinmy0nbIDiZJ+pgLAXCOWBfDUzcOjDGKvcpoZharA07c0q1/5ojzO\n4F0Fh4g/BUmtrASwHfcIbjHyCSr1j/3Iz883iy07gJY5Yhiuaqmp0o0f9fgHkG53\n2xCU1owmACqaIBNQMukvXRDtB2GJMuKa/asTZDP6R5re+iXs7+s9ohcRRAKGyAyc\nYKIQKcaA+6M8T7/G+TPHZX6HJWqJJiYB+EC2ERblpvq9TPlLguEWcmvjbVc31nyq\nSDoO3ncFWKFmVsbQPTbP+pKUmlLfJwtb5XqxNR5GEXSwVv4I7IqBmJz1MmRafnBZ\ng0FJUtH668GnldO20XbnSVBr820F5SISMXVwCXDXEvGwwiB8Lt8PvqzXnGIFDAu3\nDlQI5sxSqpPVWSyw08ppKT2Tpmy8adiBotLfaCFl2VTHwOae48X2dMPBvQARAQAB\ntDFGZWRvcmEgKDMwKSA8ZmVkb3JhLTMwLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJbbqxnAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRDvPBEfz8ZZudTnD/9170LL3nyTVUCFmBjT9wZ4gYnpwtKVPa/pKnxbbS+Bmmac\ng9TrT9pZbqOHrNJLiZ3Zx1Hp+8uxr3Lo6kbYwImLhkOEDrf4aP17HfQ6VYFbQZI8\nf79OFxWJ7si9+3gfzeh9UYFEqOQfzIjLWFyfnas0OnV/P+RMQ1Zr+vPRqO7AR2va\nN9wg+Xl7157dhXPCGYnGMNSoxCbpRs0JNlzvJMuAea5nTTznRaJZtK/xKsqLn51D\nK07k9MHVFXakOH8QtMCUglbwfTfIpO5YRq5imxlWbqsYWVQy1WGJFyW6hWC0+RcJ\nOx5zGtOfi4/dN+xJ+ibnbyvy/il7Qm+vyFhCYqIPyS5m2UVJUuao3eApE38k78/o\n8aQOTnFQZ+U1Sw+6woFTxjqRQBXlQm2+7Bt3bqGATg4sXXWPbmwdL87Ic+mxn/ml\nSMfQux/5k6iAu1kQhwkO2YJn9eII6HIPkW+2m5N1JsUyJQe4cbtZE5Yh3TRA0dm7\n+zoBRfCXkOW4krchbgww/ptVmzMMP7GINJdROrJnsGl5FVeid9qHzV7aZycWSma7\nCxBYB1J8HCbty5NjtD6XMYRrMLxXugvX6Q4NPPH+2NKjzX4SIDejS6JjgrP3KA3O\npMuo7ZHMfveBngv8yP+ZD/1sS6l+dfExvdaJdOdgFCnp4p3gPbw5+Lv70HrMjA==\n=BfZ/\n-----END PGP PUBLIC KEY BLOCK-----\n","checksum":"sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"}],"packages":["policycoreutils","selinux-policy-targeted","kernel","firewalld","chrony","langpacks-en"],"exclude_packages":["dracut-config-rescue"],"releasever":"30","basearch":"x86_64"}},{"name":"org.osbuild.fix-bls","options":{}},{"name":"org.osbuild.locale","options":{"language":"en_US"}},{"name":"org.osbuild.grub2","options":{"root_fs_uuid":"76a22bf4-f153-4541-b6c7-0332c0dfaeac","boot_fs_uuid":"00000000-0000-0000-0000-000000000000","kernel_opts":"ro biosdevname=0 net.ifnames=0"}},{"name":"org.osbuild.selinux","options":{"file_contexts":"etc/selinux/targeted/contexts/files/file_contexts"}}],"assembler":{"name":"org.osbuild.tar","options":{"filename":"root.tar.xz"}}},"targets":[]}`, "created", "uuid")
|
||||
`{"id":"ffffffff-ffff-ffff-ffff-ffffffffffff","output_type":"tar","pipeline":{"build":{"pipeline":{"stages":[{"name":"org.osbuild.dnf","options":{"repos":[{"metalink":"https://mirrors.fedoraproject.org/metalink?repo=fedora-30\u0026arch=x86_64","gpgkey":"-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFturGcBEACv0xBo91V2n0uEC2vh69ywCiSyvUgN/AQH8EZpCVtM7NyjKgKm\nbbY4G3R0M3ir1xXmvUDvK0493/qOiFrjkplvzXFTGpPTi0ypqGgxc5d0ohRA1M75\nL+0AIlXoOgHQ358/c4uO8X0JAA1NYxCkAW1KSJgFJ3RjukrfqSHWthS1d4o8fhHy\nKJKEnirE5hHqB50dafXrBfgZdaOs3C6ppRIePFe2o4vUEapMTCHFw0woQR8Ah4/R\nn7Z9G9Ln+0Cinmy0nbIDiZJ+pgLAXCOWBfDUzcOjDGKvcpoZharA07c0q1/5ojzO\n4F0Fh4g/BUmtrASwHfcIbjHyCSr1j/3Iz883iy07gJY5Yhiuaqmp0o0f9fgHkG53\n2xCU1owmACqaIBNQMukvXRDtB2GJMuKa/asTZDP6R5re+iXs7+s9ohcRRAKGyAyc\nYKIQKcaA+6M8T7/G+TPHZX6HJWqJJiYB+EC2ERblpvq9TPlLguEWcmvjbVc31nyq\nSDoO3ncFWKFmVsbQPTbP+pKUmlLfJwtb5XqxNR5GEXSwVv4I7IqBmJz1MmRafnBZ\ng0FJUtH668GnldO20XbnSVBr820F5SISMXVwCXDXEvGwwiB8Lt8PvqzXnGIFDAu3\nDlQI5sxSqpPVWSyw08ppKT2Tpmy8adiBotLfaCFl2VTHwOae48X2dMPBvQARAQAB\ntDFGZWRvcmEgKDMwKSA8ZmVkb3JhLTMwLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJbbqxnAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRDvPBEfz8ZZudTnD/9170LL3nyTVUCFmBjT9wZ4gYnpwtKVPa/pKnxbbS+Bmmac\ng9TrT9pZbqOHrNJLiZ3Zx1Hp+8uxr3Lo6kbYwImLhkOEDrf4aP17HfQ6VYFbQZI8\nf79OFxWJ7si9+3gfzeh9UYFEqOQfzIjLWFyfnas0OnV/P+RMQ1Zr+vPRqO7AR2va\nN9wg+Xl7157dhXPCGYnGMNSoxCbpRs0JNlzvJMuAea5nTTznRaJZtK/xKsqLn51D\nK07k9MHVFXakOH8QtMCUglbwfTfIpO5YRq5imxlWbqsYWVQy1WGJFyW6hWC0+RcJ\nOx5zGtOfi4/dN+xJ+ibnbyvy/il7Qm+vyFhCYqIPyS5m2UVJUuao3eApE38k78/o\n8aQOTnFQZ+U1Sw+6woFTxjqRQBXlQm2+7Bt3bqGATg4sXXWPbmwdL87Ic+mxn/ml\nSMfQux/5k6iAu1kQhwkO2YJn9eII6HIPkW+2m5N1JsUyJQe4cbtZE5Yh3TRA0dm7\n+zoBRfCXkOW4krchbgww/ptVmzMMP7GINJdROrJnsGl5FVeid9qHzV7aZycWSma7\nCxBYB1J8HCbty5NjtD6XMYRrMLxXugvX6Q4NPPH+2NKjzX4SIDejS6JjgrP3KA3O\npMuo7ZHMfveBngv8yP+ZD/1sS6l+dfExvdaJdOdgFCnp4p3gPbw5+Lv70HrMjA==\n=BfZ/\n-----END PGP PUBLIC KEY BLOCK-----\n","checksum":"test:foo"}],"packages":["dnf","e2fsprogs","policycoreutils","qemu-img","systemd","grub2-pc","tar"],"releasever":"30","basearch":"x86_64"}}]},"runner":"org.osbuild.fedora30"},"stages":[{"name":"org.osbuild.dnf","options":{"repos":[{"metalink":"https://mirrors.fedoraproject.org/metalink?repo=fedora-30\u0026arch=x86_64","gpgkey":"-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFturGcBEACv0xBo91V2n0uEC2vh69ywCiSyvUgN/AQH8EZpCVtM7NyjKgKm\nbbY4G3R0M3ir1xXmvUDvK0493/qOiFrjkplvzXFTGpPTi0ypqGgxc5d0ohRA1M75\nL+0AIlXoOgHQ358/c4uO8X0JAA1NYxCkAW1KSJgFJ3RjukrfqSHWthS1d4o8fhHy\nKJKEnirE5hHqB50dafXrBfgZdaOs3C6ppRIePFe2o4vUEapMTCHFw0woQR8Ah4/R\nn7Z9G9Ln+0Cinmy0nbIDiZJ+pgLAXCOWBfDUzcOjDGKvcpoZharA07c0q1/5ojzO\n4F0Fh4g/BUmtrASwHfcIbjHyCSr1j/3Iz883iy07gJY5Yhiuaqmp0o0f9fgHkG53\n2xCU1owmACqaIBNQMukvXRDtB2GJMuKa/asTZDP6R5re+iXs7+s9ohcRRAKGyAyc\nYKIQKcaA+6M8T7/G+TPHZX6HJWqJJiYB+EC2ERblpvq9TPlLguEWcmvjbVc31nyq\nSDoO3ncFWKFmVsbQPTbP+pKUmlLfJwtb5XqxNR5GEXSwVv4I7IqBmJz1MmRafnBZ\ng0FJUtH668GnldO20XbnSVBr820F5SISMXVwCXDXEvGwwiB8Lt8PvqzXnGIFDAu3\nDlQI5sxSqpPVWSyw08ppKT2Tpmy8adiBotLfaCFl2VTHwOae48X2dMPBvQARAQAB\ntDFGZWRvcmEgKDMwKSA8ZmVkb3JhLTMwLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJbbqxnAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRDvPBEfz8ZZudTnD/9170LL3nyTVUCFmBjT9wZ4gYnpwtKVPa/pKnxbbS+Bmmac\ng9TrT9pZbqOHrNJLiZ3Zx1Hp+8uxr3Lo6kbYwImLhkOEDrf4aP17HfQ6VYFbQZI8\nf79OFxWJ7si9+3gfzeh9UYFEqOQfzIjLWFyfnas0OnV/P+RMQ1Zr+vPRqO7AR2va\nN9wg+Xl7157dhXPCGYnGMNSoxCbpRs0JNlzvJMuAea5nTTznRaJZtK/xKsqLn51D\nK07k9MHVFXakOH8QtMCUglbwfTfIpO5YRq5imxlWbqsYWVQy1WGJFyW6hWC0+RcJ\nOx5zGtOfi4/dN+xJ+ibnbyvy/il7Qm+vyFhCYqIPyS5m2UVJUuao3eApE38k78/o\n8aQOTnFQZ+U1Sw+6woFTxjqRQBXlQm2+7Bt3bqGATg4sXXWPbmwdL87Ic+mxn/ml\nSMfQux/5k6iAu1kQhwkO2YJn9eII6HIPkW+2m5N1JsUyJQe4cbtZE5Yh3TRA0dm7\n+zoBRfCXkOW4krchbgww/ptVmzMMP7GINJdROrJnsGl5FVeid9qHzV7aZycWSma7\nCxBYB1J8HCbty5NjtD6XMYRrMLxXugvX6Q4NPPH+2NKjzX4SIDejS6JjgrP3KA3O\npMuo7ZHMfveBngv8yP+ZD/1sS6l+dfExvdaJdOdgFCnp4p3gPbw5+Lv70HrMjA==\n=BfZ/\n-----END PGP PUBLIC KEY BLOCK-----\n","checksum":"test:foo"}],"packages":["policycoreutils","selinux-policy-targeted","kernel","firewalld","chrony","langpacks-en"],"exclude_packages":["dracut-config-rescue"],"releasever":"30","basearch":"x86_64"}},{"name":"org.osbuild.fix-bls","options":{}},{"name":"org.osbuild.locale","options":{"language":"en_US"}},{"name":"org.osbuild.grub2","options":{"root_fs_uuid":"76a22bf4-f153-4541-b6c7-0332c0dfaeac","boot_fs_uuid":"00000000-0000-0000-0000-000000000000","kernel_opts":"ro biosdevname=0 net.ifnames=0"}},{"name":"org.osbuild.selinux","options":{"file_contexts":"etc/selinux/targeted/contexts/files/file_contexts"}}],"assembler":{"name":"org.osbuild.tar","options":{"filename":"root.tar.xz"}}},"targets":[]}`, "created", "uuid")
|
||||
}
|
||||
|
||||
func testUpdateTransition(t *testing.T, from, to string, expectedStatus int) {
|
||||
|
|
@ -58,7 +58,7 @@ func testUpdateTransition(t *testing.T, from, to string, expectedStatus int) {
|
|||
api := jobqueue.New(nil, store)
|
||||
|
||||
if from != "VOID" {
|
||||
err := store.PushCompose(id, &blueprint.Blueprint{}, "tar", nil)
|
||||
err := store.PushCompose(id, &blueprint.Blueprint{}, map[string]string{"fedora": "test:foo"}, "tar", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error pushing compose: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,10 +178,12 @@ func BaseFixture() Fixture {
|
|||
return Fixture{
|
||||
fetchPackageList{
|
||||
generatePackageList(),
|
||||
map[string]string{"base": "sha256:f34848ca92665c342abd5816c9e3eda0e82180671195362bcd0080544a3bc2ac"},
|
||||
nil,
|
||||
},
|
||||
depsolve{
|
||||
createBaseDepsolveFixture(),
|
||||
map[string]string{"base": "sha256:f34848ca92665c342abd5816c9e3eda0e82180671195362bcd0080544a3bc2ac"},
|
||||
nil,
|
||||
},
|
||||
createBaseStoreFixture(),
|
||||
|
|
@ -192,10 +194,12 @@ func NoComposesFixture() Fixture {
|
|||
return Fixture{
|
||||
fetchPackageList{
|
||||
generatePackageList(),
|
||||
map[string]string{"base": "sha256:f34848ca92665c342abd5816c9e3eda0e82180671195362bcd0080544a3bc2ac"},
|
||||
nil,
|
||||
},
|
||||
depsolve{
|
||||
createBaseDepsolveFixture(),
|
||||
map[string]string{"base": "sha256:f34848ca92665c342abd5816c9e3eda0e82180671195362bcd0080544a3bc2ac"},
|
||||
nil,
|
||||
},
|
||||
createStoreWithoutComposesFixture(),
|
||||
|
|
@ -206,9 +210,11 @@ func NonExistingPackage() Fixture {
|
|||
return Fixture{
|
||||
fetchPackageList{
|
||||
generatePackageList(),
|
||||
map[string]string{"base": "sha256:f34848ca92665c342abd5816c9e3eda0e82180671195362bcd0080544a3bc2ac"},
|
||||
nil,
|
||||
},
|
||||
depsolve{
|
||||
nil,
|
||||
nil,
|
||||
&rpmmd.DNFError{
|
||||
Kind: "MarkingErrors",
|
||||
|
|
@ -223,9 +229,11 @@ func BadDepsolve() Fixture {
|
|||
return Fixture{
|
||||
fetchPackageList{
|
||||
generatePackageList(),
|
||||
map[string]string{"base": "sha256:f34848ca92665c342abd5816c9e3eda0e82180671195362bcd0080544a3bc2ac"},
|
||||
nil,
|
||||
},
|
||||
depsolve{
|
||||
nil,
|
||||
nil,
|
||||
&rpmmd.DNFError{
|
||||
Kind: "DepsolveError",
|
||||
|
|
@ -240,12 +248,14 @@ func BadFetch() Fixture {
|
|||
return Fixture{
|
||||
fetchPackageList{
|
||||
ret: nil,
|
||||
checksums: nil,
|
||||
err: &rpmmd.DNFError{
|
||||
Kind: "FetchError",
|
||||
Reason: "There was a problem when fetching packages.",
|
||||
},
|
||||
},
|
||||
depsolve{
|
||||
nil,
|
||||
nil,
|
||||
&rpmmd.DNFError{
|
||||
Kind: "DepsolveError",
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@ import (
|
|||
|
||||
type fetchPackageList struct {
|
||||
ret rpmmd.PackageList
|
||||
checksums map[string]string
|
||||
err error
|
||||
}
|
||||
type depsolve struct {
|
||||
ret []rpmmd.PackageSpec
|
||||
checksums map[string]string
|
||||
err error
|
||||
}
|
||||
|
||||
|
|
@ -28,10 +30,10 @@ func NewRPMMDMock(fixture Fixture) rpmmd.RPMMD {
|
|||
return &rpmmdMock{Fixture: fixture}
|
||||
}
|
||||
|
||||
func (r *rpmmdMock) FetchPackageList(repos []rpmmd.RepoConfig) (rpmmd.PackageList, error) {
|
||||
return r.Fixture.fetchPackageList.ret, r.Fixture.fetchPackageList.err
|
||||
func (r *rpmmdMock) FetchPackageList(repos []rpmmd.RepoConfig) (rpmmd.PackageList, map[string]string, error) {
|
||||
return r.Fixture.fetchPackageList.ret, r.Fixture.fetchPackageList.checksums, r.Fixture.fetchPackageList.err
|
||||
}
|
||||
|
||||
func (r *rpmmdMock) Depsolve(specs []string, repos []rpmmd.RepoConfig) ([]rpmmd.PackageSpec, error) {
|
||||
return r.Fixture.depsolve.ret, r.Fixture.depsolve.err
|
||||
func (r *rpmmdMock) Depsolve(specs []string, repos []rpmmd.RepoConfig) ([]rpmmd.PackageSpec, map[string]string, error) {
|
||||
return r.Fixture.depsolve.ret, r.Fixture.fetchPackageList.checksums, r.Fixture.depsolve.err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ type RepoConfig struct {
|
|||
BaseURL string `json:"baseurl,omitempty"`
|
||||
Metalink string `json:"metalink,omitempty"`
|
||||
MirrorList string `json:"mirrorlist,omitempty"`
|
||||
Checksum string `json:"checksum,omitempty"`
|
||||
GPGKey string `json:"gpgkey,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -93,8 +92,8 @@ type PackageInfo struct {
|
|||
}
|
||||
|
||||
type RPMMD interface {
|
||||
FetchPackageList(repos []RepoConfig) (PackageList, error)
|
||||
Depsolve(specs []string, repos []RepoConfig) ([]PackageSpec, error)
|
||||
FetchPackageList(repos []RepoConfig) (PackageList, map[string]string, error)
|
||||
Depsolve(specs []string, repos []RepoConfig) ([]PackageSpec, map[string]string, error)
|
||||
}
|
||||
|
||||
type DNFError struct {
|
||||
|
|
@ -172,26 +171,32 @@ func NewRPMMD() RPMMD {
|
|||
return &rpmmdImpl{}
|
||||
}
|
||||
|
||||
func (*rpmmdImpl) FetchPackageList(repos []RepoConfig) (PackageList, error) {
|
||||
func (*rpmmdImpl) FetchPackageList(repos []RepoConfig) (PackageList, map[string]string, error) {
|
||||
var arguments = struct {
|
||||
Repos []RepoConfig `json:"repos"`
|
||||
}{repos}
|
||||
var packages PackageList
|
||||
err := runDNF("dump", arguments, &packages)
|
||||
sort.Slice(packages, func(i, j int) bool {
|
||||
return packages[i].Name < packages[j].Name
|
||||
var reply struct {
|
||||
Checksums map[string]string `json:"checksums"`
|
||||
Packages PackageList `json:"packages"`
|
||||
}
|
||||
err := runDNF("dump", arguments, &reply)
|
||||
sort.Slice(reply.Packages, func(i, j int) bool {
|
||||
return reply.Packages[i].Name < reply.Packages[j].Name
|
||||
})
|
||||
return packages, err
|
||||
return reply.Packages, reply.Checksums, err
|
||||
}
|
||||
|
||||
func (*rpmmdImpl) Depsolve(specs []string, repos []RepoConfig) ([]PackageSpec, error) {
|
||||
func (*rpmmdImpl) Depsolve(specs []string, repos []RepoConfig) ([]PackageSpec, map[string]string, error) {
|
||||
var arguments = struct {
|
||||
PackageSpecs []string `json:"package-specs"`
|
||||
Repos []RepoConfig `json:"repos"`
|
||||
}{specs, repos}
|
||||
var dependencies []PackageSpec
|
||||
err := runDNF("depsolve", arguments, &dependencies)
|
||||
return dependencies, err
|
||||
var reply struct {
|
||||
Checksums map[string]string `json:"checksums"`
|
||||
Dependencies []PackageSpec `json:"dependencies"`
|
||||
}
|
||||
err := runDNF("depsolve", arguments, &reply)
|
||||
return reply.Dependencies, reply.Checksums, err
|
||||
}
|
||||
|
||||
func (packages PackageList) Search(globPatterns ...string) (PackageList, error) {
|
||||
|
|
@ -247,6 +252,6 @@ func (packages PackageList) ToPackageInfos() []PackageInfo {
|
|||
}
|
||||
|
||||
func (pkg *PackageInfo) FillDependencies(rpmmd RPMMD, repos []RepoConfig) (err error) {
|
||||
pkg.Dependencies, err = rpmmd.Depsolve([]string{pkg.Name}, repos)
|
||||
pkg.Dependencies, _, err = rpmmd.Depsolve([]string{pkg.Name}, repos)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -415,7 +415,7 @@ func (s *Store) DeleteBlueprintFromWorkspace(name string) {
|
|||
})
|
||||
}
|
||||
|
||||
func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, composeType string, uploadTarget *target.Target) error {
|
||||
func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, checksums map[string]string, composeType string, uploadTarget *target.Target) error {
|
||||
targets := []*target.Target{}
|
||||
|
||||
if s.stateDir != nil {
|
||||
|
|
@ -430,7 +430,7 @@ func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, compos
|
|||
targets = append(targets, uploadTarget)
|
||||
}
|
||||
|
||||
pipeline, err := s.distro.Pipeline(bp, composeType)
|
||||
pipeline, err := s.distro.Pipeline(bp, checksums, composeType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -610,7 +610,7 @@ func (api *API) projectsDepsolveHandler(writer http.ResponseWriter, request *htt
|
|||
|
||||
names := strings.Split(params.ByName("projects"), ",")
|
||||
|
||||
packages, err := api.rpmmd.Depsolve(names, api.distro.Repositories())
|
||||
packages, _, err := api.rpmmd.Depsolve(names, api.distro.Repositories())
|
||||
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
|
|
@ -792,27 +792,7 @@ func (api *API) blueprintsDepsolveHandler(writer http.ResponseWriter, request *h
|
|||
return
|
||||
}
|
||||
|
||||
specs := make([]string, len(blueprint.Packages))
|
||||
for i, pkg := range blueprint.Packages {
|
||||
specs[i] = pkg.Name
|
||||
// If a package has version "*" the package name suffix must be equal to "-*-*.*"
|
||||
// Using just "-*" would find any other package containing the package name
|
||||
if pkg.Version != "" && pkg.Version != "*" {
|
||||
specs[i] += "-" + pkg.Version
|
||||
} else if pkg.Version == "*" {
|
||||
specs[i] += "-*-*.*"
|
||||
}
|
||||
}
|
||||
|
||||
var repos []rpmmd.RepoConfig
|
||||
for _, repo := range api.distro.Repositories() {
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
for _, source := range api.store.GetAllSources() {
|
||||
repos = append(repos, source.RepoConfig())
|
||||
}
|
||||
|
||||
dependencies, err := api.rpmmd.Depsolve(specs, repos)
|
||||
dependencies, _, err := api.depsolveBlueprint(blueprint)
|
||||
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
|
|
@ -866,36 +846,24 @@ func (api *API) blueprintsFreezeHandler(writer http.ResponseWriter, request *htt
|
|||
}
|
||||
blueprint, _ := api.store.GetBlueprint(name)
|
||||
if blueprint == nil {
|
||||
err := responseError{
|
||||
rerr := responseError{
|
||||
ID: "UnknownBlueprint",
|
||||
Msg: fmt.Sprintf("%s: blueprint_not_found", name),
|
||||
}
|
||||
errors = append(errors, err)
|
||||
return
|
||||
errors = append(errors, rerr)
|
||||
break
|
||||
}
|
||||
|
||||
specs := make([]string, len(blueprint.Packages))
|
||||
for i, pkg := range blueprint.Packages {
|
||||
specs[i] = pkg.Name
|
||||
// If a package has version "*" the package name suffix must be equal to "-*-*.*"
|
||||
// Using just "-*" would find any other package containing the package name
|
||||
if pkg.Version != "" && pkg.Version != "*" {
|
||||
specs[i] += "-" + pkg.Version
|
||||
} else if pkg.Version == "*" {
|
||||
specs[i] += "-*-*.*"
|
||||
dependencies, _, err := api.depsolveBlueprint(blueprint)
|
||||
if err != nil {
|
||||
rerr := responseError{
|
||||
ID: "BlueprintsError",
|
||||
Msg: fmt.Sprintf("%s: %s", name, err.Error()),
|
||||
}
|
||||
errors = append(errors, rerr)
|
||||
break
|
||||
}
|
||||
|
||||
var repos []rpmmd.RepoConfig
|
||||
for _, repo := range api.distro.Repositories() {
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
for _, source := range api.store.GetAllSources() {
|
||||
repos = append(repos, source.RepoConfig())
|
||||
}
|
||||
|
||||
dependencies, _ := api.rpmmd.Depsolve(specs, repos)
|
||||
|
||||
for pkgIndex, pkg := range blueprint.Packages {
|
||||
i := sort.Search(len(dependencies), func(i int) bool {
|
||||
return dependencies[i].Name >= pkg.Name
|
||||
|
|
@ -1243,7 +1211,17 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
|
|||
bp := api.store.GetBlueprintCommitted(cr.BlueprintName)
|
||||
|
||||
if bp != nil {
|
||||
err := api.store.PushCompose(reply.BuildID, bp, cr.ComposeType, uploadTarget)
|
||||
_, checksums, err := api.depsolveBlueprint(bp)
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: "DepsolveError",
|
||||
Msg: err.Error(),
|
||||
}
|
||||
statusResponseError(writer, http.StatusInternalServerError, errors)
|
||||
return
|
||||
}
|
||||
|
||||
err = api.store.PushCompose(reply.BuildID, bp, checksums, cr.ComposeType, uploadTarget)
|
||||
|
||||
// TODO: we should probably do some kind of blueprint validation in future
|
||||
// for now, let's just 500 and bail out
|
||||
|
|
@ -1630,7 +1608,32 @@ func (api *API) fetchPackageList() (rpmmd.PackageList, error) {
|
|||
repos = append(repos, source.RepoConfig())
|
||||
}
|
||||
|
||||
return api.rpmmd.FetchPackageList(repos)
|
||||
packages, _, err := api.rpmmd.FetchPackageList(repos)
|
||||
return packages, err
|
||||
}
|
||||
|
||||
func (api *API) depsolveBlueprint(bp *blueprint.Blueprint) ([]rpmmd.PackageSpec, map[string]string, error) {
|
||||
specs := make([]string, len(bp.Packages))
|
||||
for i, pkg := range bp.Packages {
|
||||
specs[i] = pkg.Name
|
||||
// If a package has version "*" the package name suffix must be equal to "-*-*.*"
|
||||
// Using just "-*" would find any other package containing the package name
|
||||
if pkg.Version != "" && pkg.Version != "*" {
|
||||
specs[i] += "-" + pkg.Version
|
||||
} else if pkg.Version == "*" {
|
||||
specs[i] += "-*-*.*"
|
||||
}
|
||||
}
|
||||
|
||||
var repos []rpmmd.RepoConfig
|
||||
for _, repo := range api.distro.Repositories() {
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
for _, source := range api.store.GetAllSources() {
|
||||
repos = append(repos, source.RepoConfig())
|
||||
}
|
||||
|
||||
return api.rpmmd.Depsolve(specs, repos)
|
||||
}
|
||||
|
||||
func (api *API) uploadsScheduleHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
"compose": {
|
||||
"distro": "fedora-30",
|
||||
"arch": "x86_64",
|
||||
"checksums": {
|
||||
"fedora": "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"
|
||||
},
|
||||
"filename": "image.raw.xz",
|
||||
"output-format": "ami",
|
||||
"blueprint": {}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
"compose": {
|
||||
"distro": "fedora-30",
|
||||
"arch": "x86_64",
|
||||
"checksums": {
|
||||
"fedora": "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"
|
||||
},
|
||||
"output-format": "partitioned-disk",
|
||||
"filename": "disk.img",
|
||||
"blueprint": {}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
"compose": {
|
||||
"distro": "fedora-30",
|
||||
"arch": "x86_64",
|
||||
"checksums": {
|
||||
"fedora": "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"
|
||||
},
|
||||
"output-format": "ext4-filesystem",
|
||||
"filename": "filesystem.img",
|
||||
"blueprint": {}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
"compose": {
|
||||
"distro": "fedora-30",
|
||||
"arch": "x86_64",
|
||||
"checksums": {
|
||||
"fedora": "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"
|
||||
},
|
||||
"output-format": "openstack",
|
||||
"filename": "image.qcow2",
|
||||
"blueprint": {}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
"compose": {
|
||||
"distro": "fedora-30",
|
||||
"arch": "x86_64",
|
||||
"checksums": {
|
||||
"fedora": "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"
|
||||
},
|
||||
"output-format": "qcow2",
|
||||
"filename": "image.qcow2",
|
||||
"blueprint": {}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
"compose": {
|
||||
"distro": "fedora-30",
|
||||
"arch": "x86_64",
|
||||
"checksums": {
|
||||
"fedora": "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"
|
||||
},
|
||||
"output-format": "vhd",
|
||||
"filename": "image.vhd",
|
||||
"blueprint": {}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
"compose": {
|
||||
"distro": "fedora-30",
|
||||
"arch": "x86_64",
|
||||
"checksums": {
|
||||
"fedora": "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"
|
||||
},
|
||||
"output-format": "vmdk",
|
||||
"filename": "disk.vmdk",
|
||||
"blueprint": {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue