Skip to content

Commit

Permalink
Beskar-yum: Add a sync handler that accepts a URL with credentials
Browse files Browse the repository at this point in the history
Credentials can be configured in repository properies in mirror urls,
but these are presisted to the database. This new handler only sets the
provided url in memory before performing the sync.
  • Loading branch information
ikaneshiro committed Jan 12, 2024
1 parent 05dc3a1 commit 8528704
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 5 deletions.
16 changes: 16 additions & 0 deletions integration/beskar_yum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,22 @@ var _ = Describe("Beskar YUM Plugin", func() {
Expect(status.EndTime).ToNot(BeEmpty())
})

It("Sync Repository With URL", func() {
err := beskarYUMClient().SyncRepositoryWithURL(context.Background(), repositoryAPIName, repo.AuthMirrorURL, true)
Expect(err).To(BeNil())
})

It("Sync Status", func() {
status, err := beskarYUMClient().GetRepositorySyncStatus(context.Background(), repositoryAPIName)
Expect(err).To(BeNil())
Expect(status.Syncing).To(BeFalse())
Expect(status.SyncError).To(BeEmpty())
Expect(status.SyncedPackages).To(Equal(len(repo.Files)))
Expect(status.TotalPackages).To(Equal(len(repo.Files)))
Expect(status.StartTime).ToNot(BeEmpty())
Expect(status.EndTime).ToNot(BeEmpty())
})

It("Access Repository Artifacts", func() {
for filename := range repo.Files {
info, ok := repo.Files[filename]
Expand Down
25 changes: 25 additions & 0 deletions integration/main_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
_ "embed"
"fmt"
"net/http"
"net/url"
"os"
"os/exec"
"syscall"
Expand Down Expand Up @@ -38,6 +39,17 @@ func TestSubstrateIntegration(t *testing.T) {
RunSpecs(t, "Beskar Integration Test Suite")
}

func auth(username, password string, h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
u, p, ok := r.BasicAuth()
if !ok || username != u || password != p {
http.Error(w, "401 unauthorized", http.StatusUnauthorized)
}

h.ServeHTTP(w, r)
})
}

var _ = SynchronizedBeforeSuite(
// NOTE: This runs *only* on process #1 when run in parallel
func() []byte {
Expand All @@ -61,6 +73,19 @@ var _ = SynchronizedBeforeSuite(
fs := http.FileServer(http.Dir(repo.LocalPath))
pathPrefix := fmt.Sprintf("/%s/", name)
mux.Handle(pathPrefix, http.StripPrefix(pathPrefix, fs))

if repo.AuthMirrorURL != "" {
u, err := url.Parse(repo.AuthMirrorURL)
if err != nil {
continue
}

username := u.User.Username()
password, _ := u.User.Password()

pathPrefix := fmt.Sprintf("/auth/%s/", name)
mux.Handle(pathPrefix, auth(username, password, http.StripPrefix(pathPrefix, fs)))
}
}
}

Expand Down
11 changes: 6 additions & 5 deletions integration/pkg/repoconfig/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ type File struct {
}

type Repository struct {
URL string `yaml:"url"`
LocalPath string `yaml:"local-path"`
MirrorURL string `yaml:"mirror-url"`
GPGKey string `yaml:"gpgkey"`
Files map[string]File `yaml:"files"`
URL string `yaml:"url"`
LocalPath string `yaml:"local-path"`
MirrorURL string `yaml:"mirror-url"`
AuthMirrorURL string `yaml:"auth-mirror-url"`
GPGKey string `yaml:"gpgkey"`
Files map[string]File `yaml:"files"`
}

type Repositories map[string]Repository
Expand Down
1 change: 1 addition & 0 deletions integration/testdata/repoconfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ vault-rocky-8.3-ha-debug:
local-path: testdata/vault-rocky-8.3-ha-debug
url: http://127.0.0.1:8080/vault-rocky-8.3-ha-debug/Packages
mirror-url: http://127.0.0.1:8080/vault-rocky-8.3-ha-debug
auth-mirror-url: http://test:[email protected]:8080/auth/vault-rocky-8.3-ha-debug
gpgkey: |
-----BEGIN PGP PUBLIC KEY BLOCK-----
Expand Down
7 changes: 7 additions & 0 deletions internal/plugins/yum/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ func (p *Plugin) SyncRepository(ctx context.Context, repository string, wait boo
return p.repositoryManager.Get(ctx, repository).SyncRepository(ctx, wait)
}

func (p *Plugin) SyncRepositoryWithURL(ctx context.Context, repository, url string, wait bool) (err error) {
if err := checkRepository(repository); err != nil {
return err
}
return p.repositoryManager.Get(ctx, repository).SyncRepositoryWithURL(ctx, url, wait)
}

func (p *Plugin) GetRepositorySyncStatus(ctx context.Context, repository string) (syncStatus *apiv1.SyncStatus, err error) {
if err := checkRepository(repository); err != nil {
return nil, err
Expand Down
33 changes: 33 additions & 0 deletions internal/plugins/yum/pkg/yumrepository/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,39 @@ func (h *Handler) SyncRepository(_ context.Context, wait bool) (err error) {
return nil
}

func (h *Handler) SyncRepositoryWithURL(_ context.Context, url string, wait bool) (err error) {
if !h.Started() {
return werror.Wrap(gcode.ErrUnavailable, err)
} else if !h.getMirror() {
return werror.Wrap(gcode.ErrFailedPrecondition, errors.New("repository not setup as a mirror"))
} else if err := h.setMirrorURLs([]string{url}); err != nil {
return werror.Wrap(gcode.ErrInternal, err)
} else if h.delete.Load() {
return werror.Wrap(gcode.ErrAlreadyExists, fmt.Errorf("repository %s is being deleted", h.Repository))
} else if h.syncing.Swap(true) {
return werror.Wrap(gcode.ErrAlreadyExists, errors.New("a repository sync is already running"))
}

var waitErrCh chan error

if wait {
waitErrCh = make(chan error, 1)
}

select {
case h.syncCh <- waitErrCh:
if waitErrCh != nil {
if err := <-waitErrCh; err != nil {
return werror.Wrap(gcode.ErrInternal, fmt.Errorf("synchronization failed: %w", err))
}
}
default:
return werror.Wrap(gcode.ErrUnavailable, errors.New("something goes wrong"))
}

return nil
}

func (h *Handler) GetRepositorySyncStatus(context.Context) (syncStatus *apiv1.SyncStatus, err error) {
reposync := h.getReposync()
return &apiv1.SyncStatus{
Expand Down
5 changes: 5 additions & 0 deletions pkg/plugins/yum/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ type YUM interface { //nolint:interfacebloat
//kun:success statusCode=200
SyncRepository(ctx context.Context, repository string, wait bool) (err error)

// Sync YUM repository with an upstream repository using a specified URL.
//kun:op GET /repository/sync:url
//kun:success statusCode=200
SyncRepositoryWithURL(ctx context.Context, repository, mirrorURL string, wait bool) (err error)

// Get YUM repository sync status.
//kun:op GET /repository/sync:status
//kun:success statusCode=200
Expand Down
39 changes: 39 additions & 0 deletions pkg/plugins/yum/api/v1/endpoint.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions pkg/plugins/yum/api/v1/http.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions pkg/plugins/yum/api/v1/http_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions pkg/plugins/yum/api/v1/oas2.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8528704

Please sign in to comment.