-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathrepository_parameters.go
152 lines (132 loc) · 5.84 KB
/
repository_parameters.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package handler
import (
"fmt"
"net/http"
"sync"
"time"
"github.com/content-services/content-sources-backend/pkg/api"
"github.com/content-services/content-sources-backend/pkg/config"
"github.com/content-services/content-sources-backend/pkg/dao"
ce "github.com/content-services/content-sources-backend/pkg/errors"
"github.com/content-services/content-sources-backend/pkg/rbac"
"github.com/content-services/yummy/pkg/yum"
"github.com/labstack/echo/v4"
)
const RequestTimeout = time.Second * 3
type RepositoryParameterHandler struct {
dao dao.DaoRegistry
}
func RegisterRepositoryParameterRoutes(engine *echo.Group, dao *dao.DaoRegistry) {
rph := RepositoryParameterHandler{dao: *dao}
addRepoRoute(engine, http.MethodGet, "/repository_parameters/", rph.listParameters, rbac.RbacVerbRead)
addRepoRoute(engine, http.MethodPost, "/repository_parameters/external_gpg_key/", rph.fetchGpgKey, rbac.RbacVerbWrite)
addRepoRoute(engine, http.MethodPost, "/repository_parameters/validate/", rph.validate, rbac.RbacVerbWrite)
}
// FetchGpgKeys godoc
// @Summary Fetch gpgkey from URL
// @ID fetchGpgKey
// @Description Fetch a gpgkey from a remote repo.
// @Tags gpgKey
// @Accept json
// @Produce json
// @Param body body api.FetchGPGKeyRequest true "request body"
// @Success 200 {object} api.FetchGPGKeyResponse
// @Failure 400 {object} ce.ErrorResponse
// @Failure 401 {object} ce.ErrorResponse
// @Failure 404 {object} ce.ErrorResponse
// @Failure 415 {object} ce.ErrorResponse
// @Failure 500 {object} ce.ErrorResponse
// @Router /repository_parameters/external_gpg_key/ [post]
func (rh *RepositoryParameterHandler) fetchGpgKey(c echo.Context) error {
var gpgKeyParams api.FetchGPGKeyRequest
if err := c.Bind(&gpgKeyParams); err != nil {
return ce.NewErrorResponse(http.StatusBadRequest, "Error binding parameters", err.Error())
}
transport := http.Transport{ResponseHeaderTimeout: RequestTimeout}
client := http.Client{Timeout: RequestTimeout, Transport: &transport}
gpgKey, _, err := yum.FetchGPGKey(c.Request().Context(), gpgKeyParams.URL, &client)
if err != nil {
httpError := ce.NewErrorResponse(http.StatusNotAcceptable, "", "Received response was not a valid GPG Key")
return httpError
}
return c.JSON(http.StatusOK, api.FetchGPGKeyResponse{
GpgKey: *gpgKey,
})
}
// ListRepositoryParameters godoc
// @Summary List Repository Parameters
// @ID listRepositoryParameters
// @Description List repository parameters.
// @Tags repositories
// @Accept json
// @Produce json
// @Success 200 {object} api.RepositoryParameterResponse
// @Failure 400 {object} ce.ErrorResponse
// @Failure 401 {object} ce.ErrorResponse
// @Router /repository_parameters/ [get]
func (rh *RepositoryParameterHandler) listParameters(c echo.Context) error {
return c.JSON(200, api.RepositoryParameterResponse{
DistributionVersions: config.DistributionVersions[:],
DistributionArches: config.DistributionArches[:],
})
}
// ValidateRepositoryParameters godoc
// @summary Validate parameters prior to creating a repository
// @Description This validates the parameters before creating a repository. It provides a way to ensure the accuracy and validity of the provided parameters, including a check for the presence of remote yum metadata. Users can perform necessary checks before proceeding with the creation of a repository.
// @ID validateRepositoryParameters
// @Tags repositories
// @Accept json
// @Produce json
// @Param body body []api.RepositoryValidationRequest true "request body"
// @Success 200 {object} []api.RepositoryValidationResponse
// @Failure 400 {object} ce.ErrorResponse
// @Failure 401 {object} ce.ErrorResponse
// @Failure 404 {object} ce.ErrorResponse
// @Failure 415 {object} ce.ErrorResponse
// @Failure 500 {object} ce.ErrorResponse
// @Router /repository_parameters/validate/ [post]
func (rph *RepositoryParameterHandler) validate(c echo.Context) error {
_, orgID := getAccountIdOrgId(c)
var validationParams []api.RepositoryValidationRequest
if err := c.Bind(&validationParams); err != nil {
return ce.NewErrorResponse(http.StatusBadRequest, "Error binding parameters", err.Error())
}
repoCount := len(validationParams)
if BulkCreateLimit < repoCount {
limitErrMsg := fmt.Sprintf("Cannot validate more than %d repositories at once.", BulkCreateLimit)
return ce.NewErrorResponse(http.StatusRequestEntityTooLarge, "", limitErrMsg)
}
// Create arrays to hold results and errors
validationResponse := make([]api.RepositoryValidationResponse, repoCount)
errors := make([]error, repoCount)
excludedUUIDs := []string{}
for i := 0; i < repoCount; i++ {
if validationParams[i].UUID != nil {
excludedUUIDs = append(excludedUUIDs, *validationParams[i].UUID)
}
}
// Use go routine here to reduce the api call time length.
// Each url validation can take seconds to fail in case of a timeout.
// This makes the call roughly take the amount of time as a single timeout at worst.
var wg sync.WaitGroup
wg.Add(len(validationParams))
for i := 0; i < len(validationParams); i++ {
go func(slot int, validationParam api.RepositoryValidationRequest) {
defer wg.Done()
response, err := rph.dao.RepositoryConfig.ValidateParameters(c.Request().Context(), orgID, validationParam, excludedUUIDs)
if err == nil {
validationResponse[slot] = response
} else {
errors[slot] = err
}
}(i, validationParams[i])
}
wg.Wait()
// Check for any errors and return the first one. Errors are fatal, not errors retrieving metadata.
for i := 0; i < len(errors); i++ {
if errors[i] != nil {
return ce.NewErrorResponse(ce.HttpCodeForDaoError(errors[i]), "Error validating repository", errors[i].Error())
}
}
return c.JSON(http.StatusOK, validationResponse)
}