feat: [AH-1146]: add support for RPM artifact details (#3697)

* feat: [AH-1063]: RPM client setup details (#3726)

* add credentials
* feat: [AH-1063]: RPM client setup details
* fix lint issues
* fix lint issue
* refactoring
* refactoring
* fix tests
* fix rebase issues
* feat: [AH-1146]: add support for RPM artifact details
This commit is contained in:
Tudor Macari 2025-04-24 05:21:14 +00:00 committed by Harness
parent b8653351a4
commit c3a70ca12e
25 changed files with 963 additions and 492 deletions

View File

@ -135,6 +135,8 @@ import (
"github.com/harness/gitness/pubsub"
registryevents "github.com/harness/gitness/registry/app/events"
"github.com/harness/gitness/registry/app/pkg/docker"
rpmutils "github.com/harness/gitness/registry/app/utils/rpm"
registryindex "github.com/harness/gitness/registry/services/index"
registrywebhooks "github.com/harness/gitness/registry/services/webhook"
"github.com/harness/gitness/ssh"
"github.com/harness/gitness/store/database/dbtx"
@ -292,6 +294,8 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
registrywebhooks.WireSet,
gitspacedeleteevents.WireSet,
gitspacedeleteeventservice.WireSet,
registryindex.WireSet,
rpmutils.WireSet,
)
return &cliserver.System{}, nil
}

View File

@ -129,7 +129,7 @@ import (
npm2 "github.com/harness/gitness/registry/app/api/controller/pkg/npm"
nuget2 "github.com/harness/gitness/registry/app/api/controller/pkg/nuget"
python2 "github.com/harness/gitness/registry/app/api/controller/pkg/python"
rpm2 "github.com/harness/gitness/registry/app/api/controller/pkg/rpm"
rpm3 "github.com/harness/gitness/registry/app/api/controller/pkg/rpm"
"github.com/harness/gitness/registry/app/api/router"
events12 "github.com/harness/gitness/registry/app/events"
"github.com/harness/gitness/registry/app/pkg"
@ -141,9 +141,11 @@ import (
"github.com/harness/gitness/registry/app/pkg/npm"
"github.com/harness/gitness/registry/app/pkg/nuget"
"github.com/harness/gitness/registry/app/pkg/python"
"github.com/harness/gitness/registry/app/pkg/rpm"
rpm2 "github.com/harness/gitness/registry/app/pkg/rpm"
database2 "github.com/harness/gitness/registry/app/store/database"
"github.com/harness/gitness/registry/app/utils/rpm"
"github.com/harness/gitness/registry/gc"
"github.com/harness/gitness/registry/services/index"
webhook3 "github.com/harness/gitness/registry/services/webhook"
"github.com/harness/gitness/ssh"
"github.com/harness/gitness/store/database/dbtx"
@ -523,7 +525,9 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
if err != nil {
return nil, err
}
apiHandler := router.APIHandlerProvider(registryRepository, upstreamProxyConfigRepository, fileManager, tagRepository, manifestRepository, cleanupPolicyRepository, imageRepository, storageDriver, spaceFinder, transactor, authenticator, provider, authorizer, auditService, artifactRepository, webhooksRepository, webhooksExecutionRepository, service2, spacePathStore, reporter10, downloadStatRepository)
registryHelper := rpm.LocalRegistryHelperProvider(fileManager, artifactRepository)
indexService := index.ProvideService(registryHelper)
apiHandler := router.APIHandlerProvider(registryRepository, upstreamProxyConfigRepository, fileManager, tagRepository, manifestRepository, cleanupPolicyRepository, imageRepository, storageDriver, spaceFinder, transactor, authenticator, provider, authorizer, auditService, artifactRepository, webhooksRepository, webhooksExecutionRepository, service2, spacePathStore, reporter10, downloadStatRepository, indexService)
mavenDBStore := maven.DBStoreProvider(registryRepository, imageRepository, artifactRepository, spaceStore, bandwidthStatRepository, downloadStatRepository, nodesRepository, upstreamProxyConfigRepository)
mavenLocalRegistry := maven.LocalRegistryProvider(mavenDBStore, transactor, fileManager)
mavenController := maven.ProvideProxyController(mavenLocalRegistry, secretService, spaceFinder)
@ -551,10 +555,9 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
npmProxy := npm.ProxyProvider(upstreamProxyConfigRepository, registryRepository, imageRepository, artifactRepository, fileManager, transactor, provider, spaceFinder, secretService, npmLocalRegistryHelper)
npmController := npm2.ControllerProvider(upstreamProxyConfigRepository, registryRepository, imageRepository, artifactRepository, fileManager, transactor, downloadStatRepository, provider, npmLocalRegistry, npmProxy)
npmHandler := api2.NewNPMHandlerProvider(npmController, packagesHandler)
rpmLocalRegistryHelper := rpm.LocalRegistryHelperProvider(fileManager, artifactRepository)
rpmLocalRegistry := rpm.LocalRegistryProvider(localBase, fileManager, upstreamProxyConfigRepository, transactor, registryRepository, imageRepository, artifactRepository, provider, rpmLocalRegistryHelper)
rpmProxy := rpm.ProxyProvider(upstreamProxyConfigRepository, registryRepository, imageRepository, artifactRepository, fileManager, transactor, provider)
rpmController := rpm2.ControllerProvider(upstreamProxyConfigRepository, registryRepository, imageRepository, artifactRepository, fileManager, transactor, provider, rpmLocalRegistry, rpmProxy)
rpmLocalRegistry := rpm2.LocalRegistryProvider(localBase, fileManager, upstreamProxyConfigRepository, transactor, registryRepository, imageRepository, artifactRepository, provider, indexService)
rpmProxy := rpm2.ProxyProvider(upstreamProxyConfigRepository, registryRepository, imageRepository, artifactRepository, fileManager, transactor, provider)
rpmController := rpm3.ControllerProvider(upstreamProxyConfigRepository, registryRepository, imageRepository, artifactRepository, fileManager, transactor, provider, rpmLocalRegistry, rpmProxy)
rpmHandler := api2.NewRpmHandlerProvider(rpmController, packagesHandler)
handler4 := router.PackageHandlerProvider(packagesHandler, mavenHandler, genericHandler, pythonHandler, nugetHandler, npmHandler, rpmHandler)
appRouter := router.AppRouterProvider(registryOCIHandler, apiHandler, handler2, handler3, handler4)

View File

@ -128,6 +128,8 @@ func toPackageType(packageTypeStr string) (artifactapi.PackageType, error) {
return artifactapi.PackageTypePYTHON, nil
case string(artifactapi.PackageTypeNPM):
return artifactapi.PackageTypeNPM, nil
case string(artifactapi.PackageTypeRPM):
return artifactapi.PackageTypeRPM, nil
default:
return "", errors.New("invalid package type")
}
@ -234,15 +236,18 @@ func GetArtifactFilesMetadata(
filePathPrefix := "/" + artifactName + "/" + version + "/"
filename := strings.Replace(file.Path, filePathPrefix, "", 1)
var downloadCommand string
if artifactapi.PackageTypeGENERIC == packageType ||
artifactapi.PackageTypePYTHON == packageType || artifactapi.PackageTypeNPM == packageType {
//nolint:exhaustive
switch packageType {
case artifactapi.PackageTypeGENERIC, artifactapi.PackageTypePYTHON, artifactapi.PackageTypeNPM:
downloadCommand = GetGenericArtifactFileDownloadCommand(registryURL, artifactName, version, filename)
} else if artifactapi.PackageTypeMAVEN == packageType {
case artifactapi.PackageTypeMAVEN:
artifactName = strings.ReplaceAll(artifactName, ".", "/")
artifactName = strings.ReplaceAll(artifactName, ":", "/")
filePathPrefix = "/" + artifactName + "/" + version + "/"
filename = strings.Replace(file.Path, filePathPrefix, "", 1)
downloadCommand = GetMavenArtifactFileDownloadCommand(registryURL, artifactName, version, filename)
case artifactapi.PackageTypeRPM:
downloadCommand = GetRPMArtifactFileDownloadCommand(registryURL, filename)
}
files = append(files, artifactapi.FileDetail{
Checksums: getCheckSums(file),
@ -536,6 +541,42 @@ func GetNPMArtifactDetail(
return *artifactDetail
}
func GetRPMArtifactDetail(
image *types.Image, artifact *types.Artifact,
metadata map[string]interface{},
downloadCount int64,
) artifactapi.ArtifactDetail {
createdAt := GetTimeInMs(artifact.CreatedAt)
modifiedAt := GetTimeInMs(artifact.UpdatedAt)
size, ok := metadata["size"].(float64)
if !ok {
log.Error().Msg("failed to get size from RPM metadata")
}
fileMetadata, ok := metadata["file_metadata"].(map[string]interface{})
if ok {
delete(fileMetadata, "files")
delete(fileMetadata, "changelogs")
}
totalSize := strconv.FormatInt(int64(size), 10)
artifactDetail := &artifactapi.ArtifactDetail{
CreatedAt: &createdAt,
ModifiedAt: &modifiedAt,
Name: &image.Name,
Version: artifact.Version,
DownloadCount: &downloadCount,
Size: &totalSize,
}
err := artifactDetail.FromRpmArtifactDetailConfig(artifactapi.RpmArtifactDetailConfig{
Metadata: &metadata,
})
if err != nil {
log.Error().Err(err).Msgf("Error setting the artifact details for artifact: [%s/%s].", image.Name, artifact.Version)
return artifactapi.ArtifactDetail{}
}
return *artifactDetail
}
func GetArtifactSummary(artifact types.ImageMetadata) *artifactapi.ArtifactSummaryResponseJSONResponse {
createdAt := GetTimeInMs(artifact.CreatedAt)
modifiedAt := GetTimeInMs(artifact.ModifiedAt)

View File

@ -23,6 +23,7 @@ import (
registryevents "github.com/harness/gitness/registry/app/events"
"github.com/harness/gitness/registry/app/pkg/filemanager"
"github.com/harness/gitness/registry/app/store"
"github.com/harness/gitness/registry/services/index"
"github.com/harness/gitness/registry/services/webhook"
"github.com/harness/gitness/store/database/dbtx"
)
@ -51,6 +52,7 @@ type APIController struct {
WebhookService webhook.ServiceInterface
ArtifactEventReporter registryevents.Reporter
DownloadStatRepository store.DownloadStatRepository
RegistryIndexService index.Service
}
func NewAPIController(
@ -76,6 +78,7 @@ func NewAPIController(
webhookService webhook.ServiceInterface,
artifactEventReporter registryevents.Reporter,
downloadStatRepository store.DownloadStatRepository,
registryIndexService index.Service,
) *APIController {
return &APIController{
fileManager: fileManager,
@ -100,5 +103,6 @@ func NewAPIController(
WebhookService: webhookService,
ArtifactEventReporter: artifactEventReporter,
DownloadStatRepository: downloadStatRepository,
RegistryIndexService: registryIndexService,
}
}

View File

@ -263,6 +263,7 @@ func TestCreateRegistry(t *testing.T) {
nil, // webhookService.
eventReporter,
nil, // downloadStatRepository.
nil, // registryIndexService - not needed for this test.
)
},
},
@ -332,6 +333,7 @@ func TestCreateRegistry(t *testing.T) {
mockRegistryMetadataHelper,
nil, // webhookService.
eventReporter,
nil, //
nil, // downloadStatRepository.
)
},

View File

@ -120,7 +120,12 @@ func (c *APIController) DeleteArtifactVersion(ctx context.Context, r artifact.De
case artifact.PackageTypeNUGET:
err = fmt.Errorf("delete version not supported for nuget")
case artifact.PackageTypeRPM:
err = fmt.Errorf("delete version not supported for rpm")
err = c.deleteVersion(ctx, regInfo, artifactName, versionName)
if err != nil {
break
}
err = c.RegistryIndexService.RegenerateRpmRepoData(ctx, regInfo.RegistryID,
regInfo.RootIdentifierID, regInfo.RootIdentifier)
default:
err = fmt.Errorf("unsupported package type: %s", regInfo.PackageType)
}

View File

@ -155,6 +155,17 @@ func (c *APIController) GetArtifactDetails(
}, nil
}
artifactDetails = GetNPMArtifactDetail(img, art, result, downloadCount)
case artifact.PackageTypeRPM:
var result map[string]interface{}
err := json.Unmarshal(art.Metadata, &result)
if err != nil {
return artifact.GetArtifactDetails500JSONResponse{
InternalServerErrorJSONResponse: artifact.InternalServerErrorJSONResponse(
*GetErrorResponse(http.StatusInternalServerError, err.Error()),
),
}, nil
}
artifactDetails = GetRPMArtifactDetail(img, art, result, downloadCount)
case artifact.PackageTypeDOCKER:
case artifact.PackageTypeHELM:
default:

View File

@ -23,6 +23,8 @@ import (
apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/api/request"
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
"github.com/harness/gitness/registry/app/api/utils"
"github.com/harness/gitness/registry/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
@ -99,24 +101,15 @@ func (c *APIController) GetArtifactFiles(
registryURL := c.URLProvider.RegistryURL(ctx,
reqInfo.RootIdentifier, strings.ToLower(string(registry.PackageType)), reqInfo.RegistryIdentifier)
filePathPrefix := "/" + img.Name + "/" + art.Version + "%"
if artifact.PackageTypeMAVEN == registry.PackageType {
artifactName := strings.ReplaceAll(img.Name, ".", "/")
artifactName = strings.ReplaceAll(artifactName, ":", "/")
filePathPrefix = "/" + artifactName + "/" + art.Version + "%"
}
fileMetadataList, err := c.fileManager.GetFilesMetadata(ctx, filePathPrefix, img.RegistryID,
reqInfo.sortByField, reqInfo.sortByOrder, reqInfo.limit, reqInfo.offset, reqInfo.searchTerm)
filePathPrefix, err := utils.GetFilePath(registry.PackageType, img.Name, art.Version)
if err != nil {
log.Error().Msgf("Failed to fetch files for artifact, err: %v", err.Error())
return artifact.GetArtifactFiles500JSONResponse{
InternalServerErrorJSONResponse: artifact.InternalServerErrorJSONResponse(
*GetErrorResponse(http.StatusInternalServerError,
fmt.Sprintf("Failed to fetch files for artifact with name: [%s]", art.Version)),
),
}, nil
return failedToFetchFilesResponse(err, art)
}
filePathPattern := filePathPrefix + "%"
fileMetadataList, err := c.fileManager.GetFilesMetadata(ctx, filePathPattern, img.RegistryID,
reqInfo.sortByField, reqInfo.sortByOrder, reqInfo.limit, reqInfo.offset, reqInfo.searchTerm)
if err != nil {
return failedToFetchFilesResponse(err, art)
}
count, err := c.fileManager.CountFilesByPath(ctx, filePathPrefix, img.RegistryID)
@ -133,7 +126,8 @@ func (c *APIController) GetArtifactFiles(
//nolint:exhaustive
switch registry.PackageType {
case artifact.PackageTypeGENERIC, artifact.PackageTypeMAVEN, artifact.PackageTypePYTHON, artifact.PackageTypeNPM:
case artifact.PackageTypeGENERIC, artifact.PackageTypeMAVEN, artifact.PackageTypePYTHON,
artifact.PackageTypeNPM, artifact.PackageTypeRPM:
return artifact.GetArtifactFiles200JSONResponse{
FileDetailResponseJSONResponse: *GetAllArtifactFilesResponse(
fileMetadataList, count, reqInfo.pageNumber, reqInfo.limit, registryURL, img.Name, art.Version,
@ -147,3 +141,13 @@ func (c *APIController) GetArtifactFiles(
}, nil
}
}
func failedToFetchFilesResponse(err error, art *types.Artifact) (artifact.GetArtifactFilesResponseObject, error) {
log.Error().Msgf("Failed to fetch files for artifact, err: %v", err.Error())
return artifact.GetArtifactFiles500JSONResponse{
InternalServerErrorJSONResponse: artifact.InternalServerErrorJSONResponse(
*GetErrorResponse(http.StatusInternalServerError,
fmt.Sprintf("Failed to fetch files for artifact with name: [%s]", art.Version)),
),
}, nil
}

View File

@ -109,6 +109,8 @@ func (c *APIController) GenerateClientSetupDetails(
loginPasswordLabel := "Password: *see step 2*"
blankString := ""
switch packageType {
case string(artifact.PackageTypeRPM):
return c.generateRpmClientSetupDetail(ctx, image, tag, registryRef, username)
case string(artifact.PackageTypeMAVEN):
return c.generateMavenClientSetupDetail(ctx, image, tag, registryRef, username, registryType)
case string(artifact.PackageTypeHELM):
@ -782,6 +784,208 @@ func (c *APIController) generateMavenClientSetupDetail(
}
}
func (c *APIController) generateRpmClientSetupDetail(
ctx context.Context,
artifactName *artifact.ArtifactParam,
version *artifact.VersionParam,
registryRef string,
username string,
) *artifact.ClientSetupDetailsResponseJSONResponse {
staticStepType := artifact.ClientSetupStepTypeStatic
generateTokenStepType := artifact.ClientSetupStepTypeGenerateToken
// Authentication section
section1 := artifact.ClientSetupSection{
Header: utils.StringPtr("1. Configure Authentication"),
}
_ = section1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
Steps: &[]artifact.ClientSetupStep{
{
Header: utils.StringPtr("Generate an identity token for authentication"),
Type: &generateTokenStepType,
},
},
})
yumSection1 := artifact.ClientSetupSection{
Header: utils.StringPtr("2. Install a RPM Package"),
}
_ = yumSection1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
Steps: &[]artifact.ClientSetupStep{
{
Header: utils.StringPtr("Create or edit the .repo file."),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
Value: utils.StringPtr("sudo vi /etc/yum.repos.d/harness-<REGISTRY_NAME>.repo"),
},
},
},
{
Header: utils.StringPtr("Add the following content:"),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
Value: utils.StringPtr("[harness-<REGISTRY_NAME>]\n" +
"name=harness-<REGISTRY_NAME>\n" +
"baseurl=<REGISTRY_URL>\n" +
"enabled=1\n" +
"gpgcheck=0\n" +
"username=<USERNAME>\n" +
"password=*see step 2*\n"),
},
},
},
{
Header: utils.StringPtr("Clear the YUM cache."),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
Value: utils.StringPtr("sudo yum clean all"),
},
},
},
{
Header: utils.StringPtr("Install package."),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
Value: utils.StringPtr("sudo yum install <ARTIFACT_NAME>"),
},
},
},
},
})
yumSection2 := artifact.ClientSetupSection{
Header: utils.StringPtr("3. Upload RPM Package"),
}
_ = yumSection2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
Steps: &[]artifact.ClientSetupStep{
{
Header: utils.StringPtr("To upload a RPM artifact run the following cURL with your package file:"),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
//nolint:lll
Value: utils.StringPtr("curl --location --request PUT '<REGISTRY_URL>/' \\\n--form 'file=@\"<FILE_PATH>\"' \\\n--header 'x-api-key: <API_KEY>'"),
},
},
},
},
})
dnfSection1 := artifact.ClientSetupSection{
Header: utils.StringPtr("2. Install a RPM Package"),
}
_ = dnfSection1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
Steps: &[]artifact.ClientSetupStep{
{
Header: utils.StringPtr("Create or edit the .repo file."),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
Value: utils.StringPtr("sudo vi /etc/yum.repos.d/harness-<REGISTRY_NAME>.repo"),
},
},
},
{
Header: utils.StringPtr("Add the following content:"),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
Value: utils.StringPtr("[harness-<REGISTRY_NAME>]\n" +
"name=harness-<REGISTRY_NAME>\n" +
"baseurl=<REGISTRY_URL>\n" +
"enabled=1\n" +
"gpgcheck=0\n"),
},
},
},
{
Header: utils.StringPtr("Clear the DNF cache."),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
Value: utils.StringPtr("sudo dnf clean all"),
},
},
},
{
Header: utils.StringPtr("Install package."),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
Value: utils.StringPtr("sudo dnf install <ARTIFACT_NAME>"),
},
},
},
},
})
dnfSection2 := artifact.ClientSetupSection{
Header: utils.StringPtr("3. Upload RPM Package"),
}
_ = dnfSection2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{
Steps: &[]artifact.ClientSetupStep{
{
Header: utils.StringPtr("To upload a RPM artifact run the following cURL with your package file:"),
Type: &staticStepType,
Commands: &[]artifact.ClientSetupStepCommand{
{
//nolint:lll
Value: utils.StringPtr("curl --location --request PUT '<REGISTRY_URL>/' \\\n--form 'file=@\"<FILE_PATH>\"' \\\n--header 'x-api-key: <API_KEY>'"),
},
},
},
},
})
section2 := artifact.ClientSetupSection{}
config := artifact.TabSetupStepConfig{
Tabs: &[]artifact.TabSetupStep{
{
Header: utils.StringPtr("YUM"),
Sections: &[]artifact.ClientSetupSection{
yumSection1,
yumSection2,
},
},
{
Header: utils.StringPtr("DNF"),
Sections: &[]artifact.ClientSetupSection{
dnfSection1,
dnfSection2,
},
},
},
}
_ = section2.FromTabSetupStepConfig(config)
clientSetupDetails := artifact.ClientSetupDetails{
MainHeader: "RPM Client Setup",
SecHeader: "Follow these instructions to install/upload RPM packages.",
Sections: []artifact.ClientSetupSection{
section1,
section2,
},
}
registryURL := c.URLProvider.PackageURL(ctx, registryRef, "rpm")
//nolint:lll
c.replacePlaceholders(ctx, &clientSetupDetails.Sections, username, registryRef, artifactName, version, registryURL,
"", "")
return &artifact.ClientSetupDetailsResponseJSONResponse{
Data: clientSetupDetails,
Status: artifact.StatusSUCCESS,
}
}
func (c *APIController) generatePythonClientSetupDetail(
ctx context.Context,
registryRef string,

View File

@ -117,6 +117,7 @@ var validPackageTypes = []string{
string(a.PackageTypeMAVEN),
string(a.PackageTypePYTHON),
string(a.PackageTypeNPM),
string(a.PackageTypeRPM),
}
var validUpstreamSources = []string{
@ -376,6 +377,8 @@ func GetPullCommand(
return GetPythonDownloadCommand(image, tag)
case string(a.PackageTypeNPM):
return GetNPMDownloadCommand(image, tag)
case string(a.PackageTypeRPM):
return GetRPMDownloadCommand(image, tag)
default:
return ""
}
@ -392,6 +395,22 @@ func GetHelmPullCommand(image string, tag string, registryURL string) string {
return "helm pull oci://" + GetRepoURLWithoutProtocol(registryURL) + "/" + image + " --version " + tag
}
func GetRPMDownloadCommand(artifact, version string) string {
downloadCommand := "yum install <ARTIFACT>-<VERSION>"
// Replace the placeholders with the actual values
replacements := map[string]string{
"<ARTIFACT>": artifact,
"<VERSION>": version,
}
for placeholder, value := range replacements {
downloadCommand = strings.ReplaceAll(downloadCommand, placeholder, value)
}
return downloadCommand
}
func GetNPMDownloadCommand(artifact, version string) string {
downloadCommand := "npm install <ARTIFACT>@<VERSION> "
@ -443,6 +462,21 @@ func GetGenericArtifactFileDownloadCommand(regURL, artifact, version, filename s
return downloadCommand
}
func GetRPMArtifactFileDownloadCommand(regURL, filename string) string {
downloadCommand := "curl --location '<HOSTNAME>/package<FILENAME>' --header 'x-api-key: <API_KEY>'" +
" -J -O"
replacements := map[string]string{
"<HOSTNAME>": regURL,
"<FILENAME>": filename,
}
for placeholder, value := range replacements {
downloadCommand = strings.ReplaceAll(downloadCommand, placeholder, value)
}
return downloadCommand
}
func GetMavenArtifactFileDownloadCommand(regURL, artifact, version, filename string) string {
downloadCommand := "curl --location '<HOSTNAME>/<ARTIFACT>/<VERSION>/<FILENAME>'" +
" --header 'x-api-key: <IDENTITY_TOKEN>' -O"

View File

@ -2249,6 +2249,7 @@ components:
MAVEN: "#/components/schemas/MavenArtifactDetailConfig"
PYTHON: "#/components/schemas/PythonArtifactDetailConfig"
NPM: "#/components/schemas/NpmArtifactDetailConfig"
RPM: "#/components/schemas/RpmArtifactDetailConfig"
oneOf:
- $ref: "#/components/schemas/DockerArtifactDetailConfig"
- $ref: "#/components/schemas/HelmArtifactDetailConfig"
@ -2256,6 +2257,7 @@ components:
- $ref: "#/components/schemas/MavenArtifactDetailConfig"
- $ref: "#/components/schemas/PythonArtifactDetailConfig"
- $ref: "#/components/schemas/NpmArtifactDetailConfig"
- $ref: "#/components/schemas/RpmArtifactDetailConfig"
required:
- imageName
- version
@ -2296,6 +2298,13 @@ components:
metadata:
type: object
additionalProperties: true
RpmArtifactDetailConfig:
type: object
description: Config for RPM artifact details
properties:
metadata:
type: object
additionalProperties: true
HelmArtifactDetailConfig:
type: object
description: Config for helm artifact details

View File

@ -7021,114 +7021,114 @@ func (sh *strictHandler) GetAllRegistries(w http.ResponseWriter, r *http.Request
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"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",
"SDQQAQA=",
"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",
"LHss44Rke8XdkafPT/8fAAD//8d9dIJLEQEA",
}
// GetSwagger returns the content of the embedded swagger specification file

View File

@ -697,6 +697,11 @@ type ReplicationRuleRequestDestinationType string
// ReplicationRuleRequestSourceType defines model for ReplicationRuleRequest.SourceType.
type ReplicationRuleRequestSourceType string
// RpmArtifactDetailConfig Config for RPM artifact details
type RpmArtifactDetailConfig struct {
Metadata *map[string]interface{} `json:"metadata,omitempty"`
}
// SectionType refers to client setup section type
type SectionType string
@ -1612,6 +1617,36 @@ func (t *ArtifactDetail) MergeNpmArtifactDetailConfig(v NpmArtifactDetailConfig)
return err
}
// AsRpmArtifactDetailConfig returns the union data inside the ArtifactDetail as a RpmArtifactDetailConfig
func (t ArtifactDetail) AsRpmArtifactDetailConfig() (RpmArtifactDetailConfig, error) {
var body RpmArtifactDetailConfig
err := json.Unmarshal(t.union, &body)
return body, err
}
// FromRpmArtifactDetailConfig overwrites any union data inside the ArtifactDetail as the provided RpmArtifactDetailConfig
func (t *ArtifactDetail) FromRpmArtifactDetailConfig(v RpmArtifactDetailConfig) error {
t.PackageType = "RPM"
b, err := json.Marshal(v)
t.union = b
return err
}
// MergeRpmArtifactDetailConfig performs a merge with any union data inside the ArtifactDetail, using the provided RpmArtifactDetailConfig
func (t *ArtifactDetail) MergeRpmArtifactDetailConfig(v RpmArtifactDetailConfig) error {
t.PackageType = "RPM"
b, err := json.Marshal(v)
if err != nil {
return err
}
merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
func (t ArtifactDetail) Discriminator() (string, error) {
var discriminator struct {
Discriminator string `json:"packageType"`
@ -1638,6 +1673,8 @@ func (t ArtifactDetail) ValueByDiscriminator() (interface{}, error) {
return t.AsNpmArtifactDetailConfig()
case "PYTHON":
return t.AsPythonArtifactDetailConfig()
case "RPM":
return t.AsRpmArtifactDetailConfig()
default:
return nil, errors.New("unknown discriminator value: " + discriminator)
}

View File

@ -32,6 +32,7 @@ import (
registryevents "github.com/harness/gitness/registry/app/events"
"github.com/harness/gitness/registry/app/pkg/filemanager"
"github.com/harness/gitness/registry/app/store"
"github.com/harness/gitness/registry/services/index"
registrywebhook "github.com/harness/gitness/registry/services/webhook"
"github.com/harness/gitness/store/database/dbtx"
@ -77,6 +78,7 @@ func NewAPIHandler(
spacePathStore corestore.SpacePathStore,
artifactEventReporter registryevents.Reporter,
downloadStatRepository store.DownloadStatRepository,
registryIndexService index.Service,
) APIHandler {
r := chi.NewRouter()
r.Use(audit.Middleware())
@ -106,6 +108,7 @@ func NewAPIHandler(
&webhookService,
artifactEventReporter,
downloadStatRepository,
registryIndexService,
)
handler := artifact.NewStrictHandler(apiController, []artifact.StrictMiddlewareFunc{})

View File

@ -29,7 +29,7 @@ import (
hoci "github.com/harness/gitness/registry/app/api/handler/oci"
"github.com/harness/gitness/registry/app/api/handler/packages"
"github.com/harness/gitness/registry/app/api/handler/python"
rpm "github.com/harness/gitness/registry/app/api/handler/rpm"
"github.com/harness/gitness/registry/app/api/handler/rpm"
generic2 "github.com/harness/gitness/registry/app/api/router/generic"
"github.com/harness/gitness/registry/app/api/router/harness"
mavenRouter "github.com/harness/gitness/registry/app/api/router/maven"
@ -39,6 +39,7 @@ import (
registryevents "github.com/harness/gitness/registry/app/events"
"github.com/harness/gitness/registry/app/pkg/filemanager"
"github.com/harness/gitness/registry/app/store"
"github.com/harness/gitness/registry/services/index"
registrywebhook "github.com/harness/gitness/registry/services/webhook"
"github.com/harness/gitness/store/database/dbtx"
@ -77,6 +78,7 @@ func APIHandlerProvider(
spacePathStore corestore.SpacePathStore,
artifactEventReporter *registryevents.Reporter,
downloadStatRepository store.DownloadStatRepository,
registryIndexService index.Service,
) harness.APIHandler {
return harness.NewAPIHandler(
repoDao,
@ -101,6 +103,7 @@ func APIHandlerProvider(
spacePathStore,
*artifactEventReporter,
downloadStatRepository,
registryIndexService,
)
}

View File

@ -39,9 +39,17 @@ func GetGenericFilePath(imageName string, version string) string {
return filePathPrefix
}
func GetRpmFilePath(imageName string, version string) string {
lastDotIndex := strings.LastIndex(version, ".")
rpmVersion := version[:lastDotIndex]
rpmArch := version[lastDotIndex+1:]
return "/" + imageName + "/" + rpmVersion + "/" + rpmArch
}
func GetFilePath(
packageType artifact.PackageType,
imageName string, version string) (string, error) {
imageName string, version string,
) (string, error) {
switch packageType {
case artifact.PackageTypeDOCKER:
return "", fmt.Errorf("docker package type not supported")
@ -58,7 +66,7 @@ func GetFilePath(
case artifact.PackageTypeNUGET:
return "", fmt.Errorf("nuget package type not supported")
case artifact.PackageTypeRPM:
return "", fmt.Errorf("rpm package type not supported")
return GetRpmFilePath(imageName, version), nil
default:
return "", fmt.Errorf("unsupported package type: %s", packageType)
}

View File

@ -31,6 +31,8 @@ import (
rpmtype "github.com/harness/gitness/registry/app/pkg/types/rpm"
"github.com/harness/gitness/registry/app/storage"
"github.com/harness/gitness/registry/app/store"
rpmutil "github.com/harness/gitness/registry/app/utils/rpm"
"github.com/harness/gitness/registry/services/index"
"github.com/harness/gitness/store/database/dbtx"
"github.com/rs/zerolog/log"
@ -40,15 +42,15 @@ var _ pkg.Artifact = (*localRegistry)(nil)
var _ Registry = (*localRegistry)(nil)
type localRegistry struct {
localBase base.LocalBase
fileManager filemanager.FileManager
proxyStore store.UpstreamProxyConfigRepository
tx dbtx.Transactor
registryDao store.RegistryRepository
imageDao store.ImageRepository
artifactDao store.ArtifactRepository
urlProvider urlprovider.Provider
localRegistryHelper LocalRegistryHelper
localBase base.LocalBase
fileManager filemanager.FileManager
proxyStore store.UpstreamProxyConfigRepository
tx dbtx.Transactor
registryDao store.RegistryRepository
imageDao store.ImageRepository
artifactDao store.ArtifactRepository
urlProvider urlprovider.Provider
registryIndexService index.Service
}
type LocalRegistry interface {
@ -64,18 +66,18 @@ func NewLocalRegistry(
imageDao store.ImageRepository,
artifactDao store.ArtifactRepository,
urlProvider urlprovider.Provider,
localRegistryHelper LocalRegistryHelper,
registryIndexService index.Service,
) LocalRegistry {
return &localRegistry{
localBase: localBase,
fileManager: fileManager,
proxyStore: proxyStore,
tx: tx,
registryDao: registryDao,
imageDao: imageDao,
artifactDao: artifactDao,
urlProvider: urlProvider,
localRegistryHelper: localRegistryHelper,
localBase: localBase,
fileManager: fileManager,
proxyStore: proxyStore,
tx: tx,
registryDao: registryDao,
imageDao: imageDao,
artifactDao: artifactDao,
urlProvider: urlProvider,
registryIndexService: registryIndexService,
}
}
@ -103,7 +105,7 @@ func (c *localRegistry) UploadPackageFile(
}
defer r.Close()
p, err := parsePackage(r)
p, err := rpmutil.ParsePackage(r)
if err != nil {
log.Printf("failded to parse rpm package: %v", err)
return nil, "", err
@ -129,7 +131,7 @@ func (c *localRegistry) UploadPackageFile(
}
//TODO: make it async / atomic operation, implement artifact status (sync successful, sync failed..... statuses)
err = c.localRegistryHelper.BuildRegistryFiles(ctx, info)
err = c.registryIndexService.RegenerateRpmRepoData(ctx, info.RegistryID, info.RootParentID, info.RootIdentifier)
if err != nil {
return nil, "", err
}
@ -152,7 +154,7 @@ func (c *localRegistry) GetRepoData(
}
fileReader, _, redirectURL, err := c.fileManager.DownloadFile(
ctx, "/"+RepoDataPrefix+fileName, info.RegistryID, info.RegIdentifier, info.RootIdentifier,
ctx, "/"+rpmutil.RepoDataPrefix+fileName, info.RegistryID, info.RegIdentifier, info.RootIdentifier,
)
if err != nil {
return responseHeaders, nil, nil, "", err

View File

@ -1,316 +0,0 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rpm
import (
"bytes"
"compress/gzip"
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"net/url"
"time"
rpmmetadata "github.com/harness/gitness/registry/app/metadata/rpm"
"github.com/harness/gitness/registry/app/pkg/filemanager"
rpmtype "github.com/harness/gitness/registry/app/pkg/types/rpm"
"github.com/harness/gitness/registry/app/store"
)
const artifactBatchLimit = 50
type LocalRegistryHelper interface {
BuildRegistryFiles(ctx context.Context, info rpmtype.ArtifactInfo) error
}
type localRegistryHelper struct {
fileManager filemanager.FileManager
artifactDao store.ArtifactRepository
}
func NewLocalRegistryHelper(
fileManager filemanager.FileManager,
artifactDao store.ArtifactRepository,
) LocalRegistryHelper {
return &localRegistryHelper{
fileManager: fileManager,
artifactDao: artifactDao,
}
}
func (l *localRegistryHelper) BuildRegistryFiles(ctx context.Context, info rpmtype.ArtifactInfo) error {
lastArtifactID := int64(0)
var packageInfos []*packageInfo
for {
artifacts, err := l.artifactDao.GetAllArtifactsByRepo(ctx, info.RegistryID, artifactBatchLimit, lastArtifactID)
if err != nil {
return err
}
for _, a := range *artifacts {
metadata := rpmmetadata.RpmMetadata{}
err := json.Unmarshal(a.Metadata, &metadata)
if err != nil {
return err
}
packageInfos = append(packageInfos, &packageInfo{
Name: a.Name,
Sha256: metadata.GetFiles()[0].Sha256,
Size: metadata.GetFiles()[0].Size,
VersionMetadata: &metadata.VersionMetadata,
FileMetadata: &metadata.FileMetadata,
})
if a.ID > lastArtifactID {
lastArtifactID = a.ID
}
}
if len(*artifacts) < artifactBatchLimit {
break
}
}
primary, err := l.buildPrimary(ctx, packageInfos, info)
if err != nil {
return err
}
fileLists, err := l.buildFileLists(ctx, packageInfos, info)
if err != nil {
return err
}
other, err := l.buildOther(ctx, packageInfos, info)
if err != nil {
return err
}
return l.buildRepomd(ctx, []*repoData{
primary,
fileLists,
other,
}, info)
}
func (l *localRegistryHelper) buildPrimary(
ctx context.Context,
pds []*packageInfo,
info rpmtype.ArtifactInfo,
) (*repoData, error) {
packages := make([]*primaryPackage, 0, len(pds))
for _, pd := range pds {
files := make([]*rpmmetadata.File, 0, 3)
for _, f := range pd.FileMetadata.Files {
if f.IsExecutable {
files = append(files, f)
}
}
packageVersion := fmt.Sprintf("%s-%s", pd.FileMetadata.Version, pd.FileMetadata.Release)
packages = append(packages, &primaryPackage{
Type: "rpm",
Name: pd.Name,
Architecture: pd.FileMetadata.Architecture,
Version: primaryVersion{
Epoch: pd.FileMetadata.Epoch,
Version: pd.FileMetadata.Version,
Release: pd.FileMetadata.Release,
},
Checksum: primaryChecksum{
Type: "sha256",
Checksum: pd.Sha256,
Pkgid: "YES",
},
Summary: pd.VersionMetadata.Summary,
Description: pd.VersionMetadata.Description,
Packager: pd.FileMetadata.Packager,
URL: pd.VersionMetadata.ProjectURL,
Time: primaryTimes{
File: pd.FileMetadata.FileTime,
Build: pd.FileMetadata.BuildTime,
},
Size: primarySizes{
Package: pd.Size,
Installed: pd.FileMetadata.InstalledSize,
Archive: pd.FileMetadata.ArchiveSize,
},
Location: PrimaryLocation{
Href: fmt.Sprintf("package/%s/%s/%s/%s",
url.PathEscape(pd.Name),
url.PathEscape(packageVersion),
url.PathEscape(pd.FileMetadata.Architecture),
url.PathEscape(fmt.Sprintf("%s-%s.%s.rpm", pd.Name, packageVersion, pd.FileMetadata.Architecture))),
},
Format: primaryFormat{
License: pd.VersionMetadata.License,
Vendor: pd.FileMetadata.Vendor,
Group: pd.FileMetadata.Group,
Buildhost: pd.FileMetadata.BuildHost,
Sourcerpm: pd.FileMetadata.SourceRpm,
Provides: primaryEntryList{
Entries: pd.FileMetadata.Provides,
},
Requires: primaryEntryList{
Entries: pd.FileMetadata.Requires,
},
Conflicts: primaryEntryList{
Entries: pd.FileMetadata.Conflicts,
},
Obsoletes: primaryEntryList{
Entries: pd.FileMetadata.Obsoletes,
},
Files: files,
},
})
}
return l.addDataAsFileToRepo(ctx, "primary", &primaryMetadata{
Xmlns: "http://linux.duke.edu/metadata/common",
XmlnsRpm: "http://linux.duke.edu/metadata/rpm",
PackageCount: len(pds),
Packages: packages,
}, info)
}
func (l *localRegistryHelper) buildOther(
ctx context.Context,
pds []*packageInfo,
info rpmtype.ArtifactInfo,
) (*repoData, error) {
packages := make([]*otherPackage, 0, len(pds))
for _, pd := range pds {
packages = append(packages, &otherPackage{
Pkgid: pd.Sha256,
Name: pd.Name,
Architecture: pd.FileMetadata.Architecture,
Version: otherVersion{
Epoch: pd.FileMetadata.Epoch,
Version: pd.FileMetadata.Version,
Release: pd.FileMetadata.Release,
},
Changelogs: pd.FileMetadata.Changelogs,
})
}
return l.addDataAsFileToRepo(ctx, "other", &otherdata{
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pds),
Packages: packages,
}, info)
}
func (l *localRegistryHelper) buildFileLists(
ctx context.Context,
pds []*packageInfo,
info rpmtype.ArtifactInfo,
) (*repoData, error) { //nolint:dupl
packages := make([]*fileListPackage, 0, len(pds))
for _, pd := range pds {
packages = append(packages, &fileListPackage{
Pkgid: pd.Sha256,
Name: pd.Name,
Architecture: pd.FileMetadata.Architecture,
Version: fileListVersion{
Epoch: pd.FileMetadata.Epoch,
Version: pd.FileMetadata.Version,
Release: pd.FileMetadata.Release,
},
Files: pd.FileMetadata.Files,
})
}
return l.addDataAsFileToRepo(ctx, "filelists", &filelists{
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pds),
Packages: packages,
}, info)
}
func (l *localRegistryHelper) buildRepomd(
ctx context.Context,
data []*repoData,
info rpmtype.ArtifactInfo,
) error {
var buf bytes.Buffer
buf.WriteString(xml.Header)
if err := xml.NewEncoder(&buf).Encode(&repomd{
Xmlns: "http://linux.duke.edu/metadata/repo",
XmlnsRpm: "http://linux.duke.edu/metadata/rpm",
Data: data,
}); err != nil {
return err
}
repomdContent, _ := CreateHashedBufferFromReader(&buf)
defer repomdContent.Close()
_, err := l.fileManager.UploadFile(ctx, RepoDataPrefix+RepoMdFile, info.RegistryID,
info.RootParentID, info.RootIdentifier, repomdContent, repomdContent, RepoMdFile)
if err != nil {
return err
}
return nil
}
func (l *localRegistryHelper) addDataAsFileToRepo(
ctx context.Context,
filetype string,
obj any,
info rpmtype.ArtifactInfo,
) (*repoData, error) {
content, _ := NewHashedBuffer()
defer content.Close()
gzw := gzip.NewWriter(content)
wc := &writtenCounter{}
h := sha256.New()
w := io.MultiWriter(gzw, wc, h)
_, _ = w.Write([]byte(xml.Header))
if err := xml.NewEncoder(w).Encode(obj); err != nil {
return nil, err
}
if err := gzw.Close(); err != nil {
return nil, err
}
filename := filetype + ".xml.gz"
_, err := l.fileManager.UploadFile(ctx, RepoDataPrefix+filename, info.RegistryID,
info.RootParentID, info.RootIdentifier, content, content, filename)
if err != nil {
return nil, err
}
_, _, hashSHA256, _ := content.Sums()
return &repoData{
Type: filetype,
Checksum: repoChecksum{
Type: "sha256",
Value: hex.EncodeToString(hashSHA256),
},
OpenChecksum: repoChecksum{
Type: "sha256",
Value: hex.EncodeToString(h.Sum(nil)),
},
Location: repoLocation{
Href: "repodata/" + filename,
},
Timestamp: time.Now().Unix(),
Size: content.Size(),
OpenSize: wc.Written(),
}, nil
}

View File

@ -19,6 +19,7 @@ import (
"github.com/harness/gitness/registry/app/pkg/base"
"github.com/harness/gitness/registry/app/pkg/filemanager"
"github.com/harness/gitness/registry/app/store"
"github.com/harness/gitness/registry/services/index"
"github.com/harness/gitness/store/database/dbtx"
"github.com/google/wire"
@ -33,10 +34,10 @@ func LocalRegistryProvider(
imageDao store.ImageRepository,
artifactDao store.ArtifactRepository,
urlProvider urlprovider.Provider,
helper LocalRegistryHelper,
registryIndexService index.Service,
) LocalRegistry {
registry := NewLocalRegistry(localBase, fileManager, proxyStore, tx, registryDao, imageDao, artifactDao,
urlProvider, helper)
urlProvider, registryIndexService)
base.Register(registry)
return registry
}
@ -55,11 +56,4 @@ func ProxyProvider(
return proxy
}
func LocalRegistryHelperProvider(
fileManager filemanager.FileManager,
artifactDao store.ArtifactRepository,
) LocalRegistryHelper {
return NewLocalRegistryHelper(fileManager, artifactDao)
}
var WireSet = wire.NewSet(LocalRegistryProvider, ProxyProvider, LocalRegistryHelperProvider)
var WireSet = wire.NewSet(LocalRegistryProvider, ProxyProvider)

View File

@ -17,20 +17,29 @@ package rpm
//nolint:gosec
import (
"bytes"
"compress/gzip"
"context"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding"
"encoding/hex"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"hash"
"io"
"math"
"net/url"
"os"
"strings"
"time"
rpmmetadata "github.com/harness/gitness/registry/app/metadata/rpm"
"github.com/harness/gitness/registry/app/pkg/filemanager"
"github.com/harness/gitness/registry/app/store"
"github.com/harness/gitness/registry/validation"
"github.com/sassoftware/go-rpmutils"
@ -52,7 +61,8 @@ const (
RepoMdFile = "repomd.xml"
RepoDataPrefix = "repodata/"
DefaultMemorySize = 32 * 1024 * 1024
DefaultMemorySize = 32 * 1024 * 1024
artifactBatchLimit = 50
)
var (
@ -60,7 +70,306 @@ var (
ErrWriteAfterRead = errors.New("write is unsupported after a read operation")
)
func parsePackage(r io.Reader) (*rpmPackage, error) {
type RegistryHelper interface {
BuildRegistryFiles(ctx context.Context, registryID int64, rootParentID int64, rootIdentifier string) error
}
type registryHelper struct {
fileManager filemanager.FileManager
artifactDao store.ArtifactRepository
}
func NewRegistryHelper(
fileManager filemanager.FileManager,
artifactDao store.ArtifactRepository,
) RegistryHelper {
return &registryHelper{
fileManager: fileManager,
artifactDao: artifactDao,
}
}
func (l *registryHelper) BuildRegistryFiles(
ctx context.Context,
registryID int64,
rootParentID int64,
rootIdentifier string,
) error {
lastArtifactID := int64(0)
var packageInfos []*packageInfo
for {
artifacts, err := l.artifactDao.GetAllArtifactsByRepo(ctx, registryID, artifactBatchLimit, lastArtifactID)
if err != nil {
return err
}
for _, a := range *artifacts {
metadata := rpmmetadata.RpmMetadata{}
err := json.Unmarshal(a.Metadata, &metadata)
if err != nil {
return err
}
packageInfos = append(packageInfos, &packageInfo{
Name: a.Name,
Sha256: metadata.GetFiles()[0].Sha256,
Size: metadata.GetFiles()[0].Size,
VersionMetadata: &metadata.VersionMetadata,
FileMetadata: &metadata.FileMetadata,
})
if a.ID > lastArtifactID {
lastArtifactID = a.ID
}
}
if len(*artifacts) < artifactBatchLimit {
break
}
}
primary, err := l.buildPrimary(ctx, packageInfos, registryID, rootParentID, rootIdentifier)
if err != nil {
return err
}
fileLists, err := l.buildFileLists(ctx, packageInfos, registryID, rootParentID, rootIdentifier)
if err != nil {
return err
}
other, err := l.buildOther(ctx, packageInfos, registryID, rootParentID, rootIdentifier)
if err != nil {
return err
}
return l.buildRepomd(ctx, []*repoData{
primary,
fileLists,
other,
}, registryID, rootParentID, rootIdentifier)
}
func (l *registryHelper) buildPrimary(
ctx context.Context,
pds []*packageInfo,
registryID int64,
rootParentID int64,
rootIdentifier string,
) (*repoData, error) {
packages := make([]*primaryPackage, 0, len(pds))
for _, pd := range pds {
files := make([]*rpmmetadata.File, 0, 3)
for _, f := range pd.FileMetadata.Files {
if f.IsExecutable {
files = append(files, f)
}
}
packageVersion := fmt.Sprintf("%s-%s", pd.FileMetadata.Version, pd.FileMetadata.Release)
packages = append(packages, &primaryPackage{
Type: "rpm",
Name: pd.Name,
Architecture: pd.FileMetadata.Architecture,
Version: primaryVersion{
Epoch: pd.FileMetadata.Epoch,
Version: pd.FileMetadata.Version,
Release: pd.FileMetadata.Release,
},
Checksum: primaryChecksum{
Type: "sha256",
Checksum: pd.Sha256,
Pkgid: "YES",
},
Summary: pd.VersionMetadata.Summary,
Description: pd.VersionMetadata.Description,
Packager: pd.FileMetadata.Packager,
URL: pd.VersionMetadata.ProjectURL,
Time: primaryTimes{
File: pd.FileMetadata.FileTime,
Build: pd.FileMetadata.BuildTime,
},
Size: primarySizes{
Package: pd.Size,
Installed: pd.FileMetadata.InstalledSize,
Archive: pd.FileMetadata.ArchiveSize,
},
Location: PrimaryLocation{
Href: fmt.Sprintf("package/%s/%s/%s/%s",
url.PathEscape(pd.Name),
url.PathEscape(packageVersion),
url.PathEscape(pd.FileMetadata.Architecture),
url.PathEscape(fmt.Sprintf("%s-%s.%s.rpm", pd.Name, packageVersion, pd.FileMetadata.Architecture))),
},
Format: primaryFormat{
License: pd.VersionMetadata.License,
Vendor: pd.FileMetadata.Vendor,
Group: pd.FileMetadata.Group,
Buildhost: pd.FileMetadata.BuildHost,
Sourcerpm: pd.FileMetadata.SourceRpm,
Provides: primaryEntryList{
Entries: pd.FileMetadata.Provides,
},
Requires: primaryEntryList{
Entries: pd.FileMetadata.Requires,
},
Conflicts: primaryEntryList{
Entries: pd.FileMetadata.Conflicts,
},
Obsoletes: primaryEntryList{
Entries: pd.FileMetadata.Obsoletes,
},
Files: files,
},
})
}
primaryData := &primaryMetadata{
Xmlns: "http://linux.duke.edu/metadata/common",
XmlnsRpm: "http://linux.duke.edu/metadata/rpm",
PackageCount: len(pds),
Packages: packages,
}
return l.addDataAsFileToRepo(ctx, "primary", primaryData, registryID, rootParentID, rootIdentifier)
}
func (l *registryHelper) buildOther(
ctx context.Context,
pds []*packageInfo,
registryID int64,
rootParentID int64,
rootIdentifier string,
) (*repoData, error) {
packages := make([]*otherPackage, 0, len(pds))
for _, pd := range pds {
packages = append(packages, &otherPackage{
Pkgid: pd.Sha256,
Name: pd.Name,
Architecture: pd.FileMetadata.Architecture,
Version: otherVersion{
Epoch: pd.FileMetadata.Epoch,
Version: pd.FileMetadata.Version,
Release: pd.FileMetadata.Release,
},
Changelogs: pd.FileMetadata.Changelogs,
})
}
otherData := &otherdata{
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pds),
Packages: packages,
}
return l.addDataAsFileToRepo(ctx, "other", otherData, registryID, rootParentID, rootIdentifier)
}
func (l *registryHelper) buildFileLists(
ctx context.Context,
pds []*packageInfo,
registryID int64,
rootParentID int64,
rootIdentifier string,
) (*repoData, error) { //nolint:dupl
packages := make([]*fileListPackage, 0, len(pds))
for _, pd := range pds {
packages = append(packages, &fileListPackage{
Pkgid: pd.Sha256,
Name: pd.Name,
Architecture: pd.FileMetadata.Architecture,
Version: fileListVersion{
Epoch: pd.FileMetadata.Epoch,
Version: pd.FileMetadata.Version,
Release: pd.FileMetadata.Release,
},
Files: pd.FileMetadata.Files,
})
}
fileLists := &filelists{
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pds),
Packages: packages,
}
return l.addDataAsFileToRepo(ctx, "filelists", fileLists, registryID, rootParentID, rootIdentifier)
}
func (l *registryHelper) buildRepomd(
ctx context.Context,
data []*repoData,
registryID int64,
rootParentID int64,
rootIdentifier string,
) error {
var buf bytes.Buffer
buf.WriteString(xml.Header)
if err := xml.NewEncoder(&buf).Encode(&repomd{
Xmlns: "http://linux.duke.edu/metadata/repo",
XmlnsRpm: "http://linux.duke.edu/metadata/rpm",
Data: data,
}); err != nil {
return err
}
repomdContent, _ := CreateHashedBufferFromReader(&buf)
defer repomdContent.Close()
_, err := l.fileManager.UploadFile(ctx, RepoDataPrefix+RepoMdFile, registryID,
rootParentID, rootIdentifier, repomdContent, repomdContent, RepoMdFile)
if err != nil {
return err
}
return nil
}
func (l *registryHelper) addDataAsFileToRepo(
ctx context.Context,
filetype string,
obj any,
registryID int64,
rootParentID int64,
rootIdentifier string,
) (*repoData, error) {
content, _ := NewHashedBuffer()
defer content.Close()
gzw := gzip.NewWriter(content)
wc := &writtenCounter{}
h := sha256.New()
w := io.MultiWriter(gzw, wc, h)
_, _ = w.Write([]byte(xml.Header))
if err := xml.NewEncoder(w).Encode(obj); err != nil {
return nil, err
}
if err := gzw.Close(); err != nil {
return nil, err
}
filename := filetype + ".xml.gz"
_, err := l.fileManager.UploadFile(ctx, RepoDataPrefix+filename, registryID,
rootParentID, rootIdentifier, content, content, filename)
if err != nil {
return nil, err
}
_, _, hashSHA256, _ := content.Sums()
return &repoData{
Type: filetype,
Checksum: repoChecksum{
Type: "sha256",
Value: hex.EncodeToString(hashSHA256),
},
OpenChecksum: repoChecksum{
Type: "sha256",
Value: hex.EncodeToString(h.Sum(nil)),
},
Location: repoLocation{
Href: "repodata/" + filename,
},
Timestamp: time.Now().Unix(),
Size: content.Size(),
OpenSize: wc.Written(),
}, nil
}
func ParsePackage(r io.Reader) (*Package, error) {
rpm, err := rpmutils.ReadRpm(r)
if err != nil {
return nil, err
@ -76,7 +385,7 @@ func parsePackage(r io.Reader) (*rpmPackage, error) {
version = fmt.Sprintf("%s-%s", nevra.Epoch, version)
}
p := &rpmPackage{
p := &Package{
Name: nevra.Name,
Version: version,
VersionMetadata: &rpmmetadata.VersionMetadata{

View File

@ -165,7 +165,7 @@ type packageInfo struct {
FileMetadata *rpmmetadata.FileMetadata
}
type rpmPackage struct {
type Package struct {
Name string
Version string
VersionMetadata *rpmmetadata.VersionMetadata

View File

@ -0,0 +1,31 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rpm
import (
"github.com/harness/gitness/registry/app/pkg/filemanager"
"github.com/harness/gitness/registry/app/store"
"github.com/google/wire"
)
func LocalRegistryHelperProvider(
fileManager filemanager.FileManager,
artifactDao store.ArtifactRepository,
) RegistryHelper {
return NewRegistryHelper(fileManager, artifactDao)
}
var WireSet = wire.NewSet(LocalRegistryHelperProvider)

View File

@ -0,0 +1,47 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package index
import (
"context"
"github.com/harness/gitness/registry/app/utils/rpm"
)
type Service interface {
RegenerateRpmRepoData(ctx context.Context, registryID int64, rootParentID int64, rootIdentifier string) error
}
type service struct {
rpmRegistryHelper rpm.RegistryHelper
}
func (s *service) RegenerateRpmRepoData(
ctx context.Context,
registryID int64,
rootParentID int64,
rootIdentifier string,
) error {
// TODO: integrate with distributed lock
return s.rpmRegistryHelper.BuildRegistryFiles(ctx, registryID, rootParentID, rootIdentifier)
}
func NewService(
rpmRegistryHelper rpm.RegistryHelper,
) Service {
return &service{
rpmRegistryHelper: rpmRegistryHelper,
}
}

View File

@ -0,0 +1,32 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package index
import (
"github.com/harness/gitness/registry/app/utils/rpm"
"github.com/google/wire"
)
// WireSet provides a wire set for this package.
var WireSet = wire.NewSet(
ProvideService,
)
func ProvideService(
rpmRegistryHelper rpm.RegistryHelper,
) Service {
return NewService(rpmRegistryHelper)
}

View File

@ -20,7 +20,7 @@ import (
gitnesswebhook "github.com/harness/gitness/app/services/webhook"
)
// Service interface for webhook operations.
// ServiceInterface interface for webhook operations.
type ServiceInterface interface {
ReTriggerWebhookExecution(ctx context.Context, webhookExecutionID int64) (*gitnesswebhook.TriggerResult, error)
}