rpmmd: add ssl fields to RepoConfig
rpmmd now contains three repo config structs. RepoConfig is for use throughout osbuild-composer. repository is for reading from our internal json repository files before creating a RepoConfig. dnfRepoConfig is is for use within rpmmd and it matches what dnf-json expects from a repo. Repos now contain support for rhsm. In order to connect to rhel's cdn, dnf must pass an sslcacert, sslcakey, and sslclientcert. When a repo is used for fetching metadata or depsolving it is checked for rhsm secrets. If secrets are needed they are retrieved from the host system. Packages requiring rhsm are marked as requiring "org.osbuild.rhsm" secrets.
This commit is contained in:
parent
8750dc467b
commit
d19ffb4eb9
1 changed files with 143 additions and 16 deletions
|
|
@ -6,22 +6,48 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RepoConfig struct {
|
type repository struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
BaseURL string `json:"baseurl,omitempty"`
|
||||||
|
Metalink string `json:"metalink,omitempty"`
|
||||||
|
MirrorList string `json:"mirrorlist,omitempty"`
|
||||||
|
GPGKey string `json:"gpgkey,omitempty"`
|
||||||
|
RHSM bool `json:"rhsm,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type dnfRepoConfig struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
BaseURL string `json:"baseurl,omitempty"`
|
BaseURL string `json:"baseurl,omitempty"`
|
||||||
Metalink string `json:"metalink,omitempty"`
|
Metalink string `json:"metalink,omitempty"`
|
||||||
MirrorList string `json:"mirrorlist,omitempty"`
|
MirrorList string `json:"mirrorlist,omitempty"`
|
||||||
GPGKey string `json:"gpgkey,omitempty"`
|
GPGKey string `json:"gpgkey,omitempty"`
|
||||||
IgnoreSSL bool `json:"ignoressl"`
|
IgnoreSSL bool `json:"ignoressl"`
|
||||||
|
SSLCACert string `json:"sslcacert,omitempty"`
|
||||||
|
SSLClientKey string `json:"sslclientkey,omitempty"`
|
||||||
|
SSLClientCert string `json:"sslclientcert,omitempty"`
|
||||||
MetadataExpire string `json:"metadata_expire,omitempty"`
|
MetadataExpire string `json:"metadata_expire,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RepoConfig struct {
|
||||||
|
Id string
|
||||||
|
BaseURL string
|
||||||
|
Metalink string
|
||||||
|
MirrorList string
|
||||||
|
GPGKey string
|
||||||
|
IgnoreSSL bool
|
||||||
|
MetadataExpire string
|
||||||
|
RHSM bool
|
||||||
|
}
|
||||||
|
|
||||||
type PackageList []Package
|
type PackageList []Package
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
|
|
@ -72,6 +98,7 @@ type PackageSpec struct {
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
RemoteLocation string `json:"remote_location,omitempty"`
|
RemoteLocation string `json:"remote_location,omitempty"`
|
||||||
Checksum string `json:"checksum,omitempty"`
|
Checksum string `json:"checksum,omitempty"`
|
||||||
|
Secrets string `json:"secrets,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PackageSource struct {
|
type PackageSource struct {
|
||||||
|
|
@ -125,6 +152,35 @@ func (re *RepositoryError) Error() string {
|
||||||
return re.msg
|
return re.msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RHSMSecrets struct {
|
||||||
|
SSLCACert string `json:"sslcacert,omitempty"`
|
||||||
|
SSLClientKey string `json:"sslclientkey,omitempty"`
|
||||||
|
SSLClientCert string `json:"sslclientcert,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var rhsmSecrets RHSMSecrets
|
||||||
|
|
||||||
|
func getRHSMSecrets() (RHSMSecrets, error) {
|
||||||
|
if rhsmSecrets == (RHSMSecrets{}) {
|
||||||
|
keys, err := filepath.Glob("/etc/pki/entitlement/*-key.pem")
|
||||||
|
if err != nil {
|
||||||
|
return rhsmSecrets, &RepositoryError{fmt.Sprintf("unable to find client key in /etc/pki/entitlement/: %v", err)}
|
||||||
|
}
|
||||||
|
for _, key := range keys {
|
||||||
|
cert := strings.TrimSuffix(key, "-key.pem") + ".pem"
|
||||||
|
if _, err := os.Stat(cert); err == nil {
|
||||||
|
rhsmSecrets = RHSMSecrets{
|
||||||
|
SSLCACert: "/etc/rhsm/ca/redhat-uep.pem",
|
||||||
|
SSLClientKey: key,
|
||||||
|
SSLClientCert: cert,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rhsmSecrets, nil
|
||||||
|
}
|
||||||
|
|
||||||
func LoadRepositories(confPaths []string, distro string) (map[string][]RepoConfig, error) {
|
func LoadRepositories(confPaths []string, distro string) (map[string][]RepoConfig, error) {
|
||||||
var f *os.File
|
var f *os.File
|
||||||
var err error
|
var err error
|
||||||
|
|
@ -143,14 +199,29 @@ func LoadRepositories(confPaths []string, distro string) (map[string][]RepoConfi
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
var repos map[string][]RepoConfig
|
var reposMap map[string][]repository
|
||||||
|
repoConfigs := make(map[string][]RepoConfig)
|
||||||
|
|
||||||
err = json.NewDecoder(f).Decode(&repos)
|
err = json.NewDecoder(f).Decode(&reposMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return repos, nil
|
for arch, repos := range reposMap {
|
||||||
|
for _, repo := range repos {
|
||||||
|
config := RepoConfig{
|
||||||
|
Id: repo.Id,
|
||||||
|
BaseURL: repo.BaseURL,
|
||||||
|
Metalink: repo.Metalink,
|
||||||
|
MirrorList: repo.MirrorList,
|
||||||
|
GPGKey: repo.GPGKey,
|
||||||
|
RHSM: repo.RHSM,
|
||||||
|
}
|
||||||
|
|
||||||
|
repoConfigs[arch] = append(repoConfigs[arch], config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return repoConfigs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDNF(command string, arguments interface{}, result interface{}) error {
|
func runDNF(command string, arguments interface{}, result interface{}) error {
|
||||||
|
|
@ -223,18 +294,52 @@ func NewRPMMD(cacheDir string) RPMMD {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo RepoConfig) toDNFRepoConfig() (dnfRepoConfig, error) {
|
||||||
|
id := uuid.New().String()
|
||||||
|
dnfRepo := dnfRepoConfig{
|
||||||
|
Id: id,
|
||||||
|
BaseURL: repo.BaseURL,
|
||||||
|
Metalink: repo.Metalink,
|
||||||
|
MirrorList: repo.MirrorList,
|
||||||
|
GPGKey: repo.GPGKey,
|
||||||
|
IgnoreSSL: repo.IgnoreSSL,
|
||||||
|
MetadataExpire: repo.MetadataExpire,
|
||||||
|
}
|
||||||
|
if repo.RHSM {
|
||||||
|
secrets, err := getRHSMSecrets()
|
||||||
|
if err != nil {
|
||||||
|
return dnfRepoConfig{}, err
|
||||||
|
}
|
||||||
|
dnfRepo.SSLCACert = secrets.SSLCACert
|
||||||
|
dnfRepo.SSLClientKey = secrets.SSLClientKey
|
||||||
|
dnfRepo.SSLClientCert = secrets.SSLClientCert
|
||||||
|
}
|
||||||
|
return dnfRepo, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *rpmmdImpl) FetchMetadata(repos []RepoConfig, modulePlatformID string, arch string) (PackageList, map[string]string, error) {
|
func (r *rpmmdImpl) FetchMetadata(repos []RepoConfig, modulePlatformID string, arch string) (PackageList, map[string]string, error) {
|
||||||
|
var dnfRepoConfigs []dnfRepoConfig
|
||||||
|
for _, repo := range repos {
|
||||||
|
dnfRepo, err := repo.toDNFRepoConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
dnfRepoConfigs = append(dnfRepoConfigs, dnfRepo)
|
||||||
|
}
|
||||||
|
|
||||||
var arguments = struct {
|
var arguments = struct {
|
||||||
Repos []RepoConfig `json:"repos"`
|
Repos []dnfRepoConfig `json:"repos"`
|
||||||
CacheDir string `json:"cachedir"`
|
CacheDir string `json:"cachedir"`
|
||||||
ModulePlatformID string `json:"module_platform_id"`
|
ModulePlatformID string `json:"module_platform_id"`
|
||||||
Arch string `json:"arch"`
|
Arch string `json:"arch"`
|
||||||
}{repos, r.CacheDir, modulePlatformID, arch}
|
}{dnfRepoConfigs, r.CacheDir, modulePlatformID, arch}
|
||||||
var reply struct {
|
var reply struct {
|
||||||
Checksums map[string]string `json:"checksums"`
|
Checksums map[string]string `json:"checksums"`
|
||||||
Packages PackageList `json:"packages"`
|
Packages PackageList `json:"packages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
err := runDNF("dump", arguments, &reply)
|
err := runDNF("dump", arguments, &reply)
|
||||||
|
|
||||||
sort.Slice(reply.Packages, func(i, j int) bool {
|
sort.Slice(reply.Packages, func(i, j int) bool {
|
||||||
return reply.Packages[i].Name < reply.Packages[j].Name
|
return reply.Packages[i].Name < reply.Packages[j].Name
|
||||||
})
|
})
|
||||||
|
|
@ -242,19 +347,41 @@ func (r *rpmmdImpl) FetchMetadata(repos []RepoConfig, modulePlatformID string, a
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rpmmdImpl) Depsolve(specs, excludeSpecs []string, repos []RepoConfig, modulePlatformID, arch string) ([]PackageSpec, map[string]string, error) {
|
func (r *rpmmdImpl) Depsolve(specs, excludeSpecs []string, repos []RepoConfig, modulePlatformID, arch string) ([]PackageSpec, map[string]string, error) {
|
||||||
|
repoMap := make(map[string]RepoConfig)
|
||||||
|
var dnfRepoConfigs []dnfRepoConfig
|
||||||
|
|
||||||
|
for _, repo := range repos {
|
||||||
|
id := repo.Id
|
||||||
|
repoMap[id] = repo
|
||||||
|
|
||||||
|
dnfRepo, err := repo.toDNFRepoConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
dnfRepoConfigs = append(dnfRepoConfigs, dnfRepo)
|
||||||
|
}
|
||||||
|
|
||||||
var arguments = struct {
|
var arguments = struct {
|
||||||
PackageSpecs []string `json:"package-specs"`
|
PackageSpecs []string `json:"package-specs"`
|
||||||
ExcludSpecs []string `json:"exclude-specs"`
|
ExcludSpecs []string `json:"exclude-specs"`
|
||||||
Repos []RepoConfig `json:"repos"`
|
Repos []dnfRepoConfig `json:"repos"`
|
||||||
CacheDir string `json:"cachedir"`
|
CacheDir string `json:"cachedir"`
|
||||||
ModulePlatformID string `json:"module_platform_id"`
|
ModulePlatformID string `json:"module_platform_id"`
|
||||||
Arch string `json:"arch"`
|
Arch string `json:"arch"`
|
||||||
}{specs, excludeSpecs, repos, r.CacheDir, modulePlatformID, arch}
|
}{specs, excludeSpecs, dnfRepoConfigs, r.CacheDir, modulePlatformID, arch}
|
||||||
var reply struct {
|
var reply struct {
|
||||||
Checksums map[string]string `json:"checksums"`
|
Checksums map[string]string `json:"checksums"`
|
||||||
Dependencies []PackageSpec `json:"dependencies"`
|
Dependencies []PackageSpec `json:"dependencies"`
|
||||||
}
|
}
|
||||||
err := runDNF("depsolve", arguments, &reply)
|
err := runDNF("depsolve", arguments, &reply)
|
||||||
|
|
||||||
|
for i, pack := range reply.Dependencies {
|
||||||
|
id := pack.RepoID
|
||||||
|
if repoMap[id].RHSM {
|
||||||
|
reply.Dependencies[i].Secrets = "org.osbuild.rhsm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return reply.Dependencies, reply.Checksums, err
|
return reply.Dependencies, reply.Checksums, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue