mirror of
https://github.com/project-zot/zot.git
synced 2025-02-17 23:45:36 -05:00
feat(userprefs): update documentation and list extensions endpoint (#1456)
Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
parent
970997f3a8
commit
2b8479f7f2
11 changed files with 182 additions and 56 deletions
|
@ -7249,11 +7249,12 @@ func TestDistSpecExtensions(t *testing.T) {
|
||||||
err = json.Unmarshal(resp.Body(), &extensionList)
|
err = json.Unmarshal(resp.Body(), &extensionList)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(extensionList.Extensions), ShouldEqual, 1)
|
So(len(extensionList.Extensions), ShouldEqual, 1)
|
||||||
So(len(extensionList.Extensions[0].Endpoints), ShouldEqual, 1)
|
So(len(extensionList.Extensions[0].Endpoints), ShouldEqual, 2)
|
||||||
So(extensionList.Extensions[0].Name, ShouldEqual, "_zot")
|
So(extensionList.Extensions[0].Name, ShouldEqual, "_zot")
|
||||||
So(extensionList.Extensions[0].URL, ShouldContainSubstring, "_zot.md")
|
So(extensionList.Extensions[0].URL, ShouldContainSubstring, "_zot.md")
|
||||||
So(extensionList.Extensions[0].Description, ShouldNotBeEmpty)
|
So(extensionList.Extensions[0].Description, ShouldNotBeEmpty)
|
||||||
So(extensionList.Extensions[0].Endpoints[0], ShouldEqual, constants.FullSearchPrefix)
|
So(extensionList.Extensions[0].Endpoints, ShouldContain, constants.FullSearchPrefix)
|
||||||
|
So(extensionList.Extensions[0].Endpoints, ShouldContain, constants.FullUserPreferencesPrefix)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("start zot server with search and mgmt extensions", t, func(c C) {
|
Convey("start zot server with search and mgmt extensions", t, func(c C) {
|
||||||
|
@ -7297,17 +7298,14 @@ func TestDistSpecExtensions(t *testing.T) {
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
err = json.Unmarshal(resp.Body(), &extensionList)
|
err = json.Unmarshal(resp.Body(), &extensionList)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(extensionList.Extensions), ShouldEqual, 2)
|
So(len(extensionList.Extensions), ShouldEqual, 1)
|
||||||
So(len(extensionList.Extensions[0].Endpoints), ShouldEqual, 1)
|
So(len(extensionList.Extensions[0].Endpoints), ShouldEqual, 3)
|
||||||
So(len(extensionList.Extensions[1].Endpoints), ShouldEqual, 1)
|
|
||||||
So(extensionList.Extensions[0].Name, ShouldEqual, "_zot")
|
So(extensionList.Extensions[0].Name, ShouldEqual, "_zot")
|
||||||
So(extensionList.Extensions[0].URL, ShouldContainSubstring, "_zot.md")
|
So(extensionList.Extensions[0].URL, ShouldContainSubstring, "_zot.md")
|
||||||
So(extensionList.Extensions[0].Description, ShouldNotBeEmpty)
|
So(extensionList.Extensions[0].Description, ShouldNotBeEmpty)
|
||||||
So(extensionList.Extensions[0].Endpoints[0], ShouldEqual, constants.FullSearchPrefix)
|
So(extensionList.Extensions[0].Endpoints, ShouldContain, constants.FullSearchPrefix)
|
||||||
So(extensionList.Extensions[1].Name, ShouldEqual, "_zot")
|
So(extensionList.Extensions[0].Endpoints, ShouldContain, constants.FullUserPreferencesPrefix)
|
||||||
So(extensionList.Extensions[1].URL, ShouldContainSubstring, "_zot.md")
|
So(extensionList.Extensions[0].Endpoints, ShouldContain, constants.FullMgmtPrefix)
|
||||||
So(extensionList.Extensions[1].Description, ShouldNotBeEmpty)
|
|
||||||
So(extensionList.Extensions[1].Endpoints[0], ShouldEqual, constants.FullMgmtPrefix)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("start minimal zot server", t, func(c C) {
|
Convey("start minimal zot server", t, func(c C) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ Component | Endpoint | Description
|
||||||
--- | --- | ---
|
--- | --- | ---
|
||||||
[`search`](search/search.md) | `/v2/_zot/ext/search` | efficient and enhanced registry search capabilities using graphQL backend
|
[`search`](search/search.md) | `/v2/_zot/ext/search` | efficient and enhanced registry search capabilities using graphQL backend
|
||||||
[`mgmt`](mgmt.md) | `/v2/_zot/ext/mgmt` | config management
|
[`mgmt`](mgmt.md) | `/v2/_zot/ext/mgmt` | config management
|
||||||
|
[`userprefs`](userprefs.md) | `/v2/_zot/ext/userprefs` | change user preferences
|
||||||
|
|
||||||
|
|
||||||
# References
|
# References
|
||||||
|
|
|
@ -40,6 +40,10 @@ type StrippedConfig struct {
|
||||||
} `json:"http" mapstructure:"http"`
|
} `json:"http" mapstructure:"http"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsBuiltWithMGMTExtension() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (auth Auth) MarshalJSON() ([]byte, error) {
|
func (auth Auth) MarshalJSON() ([]byte, error) {
|
||||||
type localAuth Auth
|
type localAuth Auth
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,10 @@ import (
|
||||||
"zotregistry.io/zot/pkg/log"
|
"zotregistry.io/zot/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func IsBuiltWithMGMTExtension() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func SetupMgmtRoutes(config *config.Config, router *mux.Router, log log.Logger) {
|
func SetupMgmtRoutes(config *config.Config, router *mux.Router, log log.Logger) {
|
||||||
log.Warn().Msg("skipping setting up mgmt routes because given zot binary doesn't include this feature," +
|
log.Warn().Msg("skipping setting up mgmt routes because given zot binary doesn't include this feature," +
|
||||||
"please build a binary that does so")
|
"please build a binary that does so")
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
|
|
||||||
gqlHandler "github.com/99designs/gqlgen/graphql/handler"
|
gqlHandler "github.com/99designs/gqlgen/graphql/handler"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
|
|
||||||
|
|
||||||
"zotregistry.io/zot/pkg/api/config"
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
"zotregistry.io/zot/pkg/api/constants"
|
"zotregistry.io/zot/pkg/api/constants"
|
||||||
|
@ -34,6 +33,10 @@ const (
|
||||||
done
|
done
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func IsBuiltWithSearchExtension() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func GetCVEInfo(config *config.Config, storeController storage.StoreController,
|
func GetCVEInfo(config *config.Config, storeController storage.StoreController,
|
||||||
repoDB repodb.RepoDB, log log.Logger,
|
repoDB repodb.RepoDB, log log.Logger,
|
||||||
) CveInfo {
|
) CveInfo {
|
||||||
|
@ -199,42 +202,3 @@ func SearchACHeadersHandler() mux.MiddlewareFunc {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExtension(name, url, description string, endpoints []string) distext.Extension {
|
|
||||||
return distext.Extension{
|
|
||||||
Name: name,
|
|
||||||
URL: url,
|
|
||||||
Description: description,
|
|
||||||
Endpoints: endpoints,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetExtensions(config *config.Config) distext.ExtensionList {
|
|
||||||
extensionList := distext.ExtensionList{}
|
|
||||||
|
|
||||||
extensions := make([]distext.Extension, 0)
|
|
||||||
|
|
||||||
if config.Extensions != nil && config.Extensions.Search != nil {
|
|
||||||
endpoints := []string{constants.FullSearchPrefix}
|
|
||||||
searchExt := getExtension("_zot",
|
|
||||||
"https://github.com/project-zot/zot/blob/"+config.ReleaseTag+"/pkg/extensions/_zot.md",
|
|
||||||
"zot registry extensions",
|
|
||||||
endpoints)
|
|
||||||
|
|
||||||
extensions = append(extensions, searchExt)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Extensions != nil && config.Extensions.Mgmt != nil {
|
|
||||||
endpoints := []string{constants.FullMgmtPrefix}
|
|
||||||
mgmtExt := getExtension("_zot",
|
|
||||||
"https://github.com/project-zot/zot/blob/"+config.ReleaseTag+"/pkg/extensions/_zot.md",
|
|
||||||
"zot registry extensions",
|
|
||||||
endpoints)
|
|
||||||
|
|
||||||
extensions = append(extensions, mgmtExt)
|
|
||||||
}
|
|
||||||
|
|
||||||
extensionList.Extensions = extensions
|
|
||||||
|
|
||||||
return extensionList
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ package extensions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
|
|
||||||
|
|
||||||
"zotregistry.io/zot/pkg/api/config"
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
"zotregistry.io/zot/pkg/log"
|
"zotregistry.io/zot/pkg/log"
|
||||||
|
@ -22,6 +21,10 @@ func GetCVEInfo(config *config.Config, storeController storage.StoreController,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsBuiltWithSearchExtension() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// EnableSearchExtension ...
|
// EnableSearchExtension ...
|
||||||
func EnableSearchExtension(config *config.Config, storeController storage.StoreController,
|
func EnableSearchExtension(config *config.Config, storeController storage.StoreController,
|
||||||
repoDB repodb.RepoDB, scheduler *scheduler.Scheduler, cveInfo CveInfo, log log.Logger,
|
repoDB repodb.RepoDB, scheduler *scheduler.Scheduler, cveInfo CveInfo, log log.Logger,
|
||||||
|
@ -37,8 +40,3 @@ func SetupSearchRoutes(config *config.Config, router *mux.Router, storeControlle
|
||||||
log.Warn().Msg("skipping setting up search routes because given zot binary doesn't include this feature," +
|
log.Warn().Msg("skipping setting up search routes because given zot binary doesn't include this feature," +
|
||||||
"please build a binary that does so")
|
"please build a binary that does so")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions...
|
|
||||||
func GetExtensions(config *config.Config) distext.ExtensionList {
|
|
||||||
return distext.ExtensionList{}
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,6 +24,10 @@ const (
|
||||||
ToggleRepoStarAction = "toggleStar"
|
ToggleRepoStarAction = "toggleStar"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func IsBuiltWithUserPrefsExtension() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func SetupUserPreferencesRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
func SetupUserPreferencesRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||||
repoDB repodb.RepoDB, cveInfo CveInfo, log log.Logger,
|
repoDB repodb.RepoDB, cveInfo CveInfo, log log.Logger,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -12,6 +12,10 @@ import (
|
||||||
"zotregistry.io/zot/pkg/storage"
|
"zotregistry.io/zot/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func IsBuiltWithUserPrefsExtension() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func SetupUserPreferencesRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
func SetupUserPreferencesRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||||
repoDB repodb.RepoDB, cveInfo CveInfo, log log.Logger,
|
repoDB repodb.RepoDB, cveInfo CveInfo, log log.Logger,
|
||||||
) {
|
) {
|
||||||
|
|
42
pkg/extensions/get_extensions.go
Normal file
42
pkg/extensions/get_extensions.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package extensions
|
||||||
|
|
||||||
|
import (
|
||||||
|
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
|
||||||
|
|
||||||
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
|
"zotregistry.io/zot/pkg/api/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetExtensions(config *config.Config) distext.ExtensionList {
|
||||||
|
extensionList := distext.ExtensionList{}
|
||||||
|
|
||||||
|
endpoints := []string{}
|
||||||
|
extensions := []distext.Extension{}
|
||||||
|
|
||||||
|
if config.Extensions != nil && config.Extensions.Search != nil {
|
||||||
|
if IsBuiltWithSearchExtension() {
|
||||||
|
endpoints = append(endpoints, constants.FullSearchPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsBuiltWithUserPrefsExtension() {
|
||||||
|
endpoints = append(endpoints, constants.FullUserPreferencesPrefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsBuiltWithMGMTExtension() && config.Extensions != nil && config.Extensions.Mgmt != nil {
|
||||||
|
endpoints = append(endpoints, constants.FullMgmtPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(endpoints) > 0 {
|
||||||
|
extensions = append(extensions, distext.Extension{
|
||||||
|
Name: "_zot",
|
||||||
|
URL: "https://github.com/project-zot/zot/blob/" + config.ReleaseTag + "/pkg/extensions/_zot.md",
|
||||||
|
Description: "zot registry extensions",
|
||||||
|
Endpoints: endpoints,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionList.Extensions = extensions
|
||||||
|
|
||||||
|
return extensionList
|
||||||
|
}
|
76
pkg/extensions/get_extensions_disabled_test.go
Normal file
76
pkg/extensions/get_extensions_disabled_test.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
//go:build !search && !mgmt && !userprefs
|
||||||
|
|
||||||
|
package extensions_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
"gopkg.in/resty.v1"
|
||||||
|
|
||||||
|
"zotregistry.io/zot/pkg/api"
|
||||||
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
|
"zotregistry.io/zot/pkg/api/constants"
|
||||||
|
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||||
|
"zotregistry.io/zot/pkg/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetExensionsDisabled(t *testing.T) {
|
||||||
|
Convey("start zot server with extensions but no extensions built", t, func(c C) {
|
||||||
|
conf := config.New()
|
||||||
|
port := test.GetFreePort()
|
||||||
|
baseURL := test.GetBaseURL(port)
|
||||||
|
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
|
||||||
|
defaultVal := true
|
||||||
|
|
||||||
|
searchConfig := &extconf.SearchConfig{
|
||||||
|
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
||||||
|
}
|
||||||
|
|
||||||
|
mgmtConfg := &extconf.MgmtConfig{
|
||||||
|
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: searchConfig,
|
||||||
|
Mgmt: mgmtConfg,
|
||||||
|
}
|
||||||
|
|
||||||
|
logFile, err := os.CreateTemp("", "zot-log*.txt")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
conf.Log.Output = logFile.Name()
|
||||||
|
defer os.Remove(logFile.Name()) // clean up
|
||||||
|
|
||||||
|
ctlr := makeController(conf, t.TempDir(), "")
|
||||||
|
|
||||||
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
cm.StartAndWait(port)
|
||||||
|
defer cm.StopServer()
|
||||||
|
|
||||||
|
var extensionList distext.ExtensionList
|
||||||
|
|
||||||
|
resp, err := resty.R().Get(baseURL + constants.RoutePrefix + constants.ExtOciDiscoverPrefix)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
|
err = json.Unmarshal(resp.Body(), &extensionList)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(len(extensionList.Extensions), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeController(conf *config.Config, dir string, copyTestDataDest string) *api.Controller {
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
|
||||||
|
if copyTestDataDest != "" {
|
||||||
|
test.CopyTestFiles(copyTestDataDest, dir)
|
||||||
|
}
|
||||||
|
ctlr.Config.Storage.RootDirectory = dir
|
||||||
|
|
||||||
|
return ctlr
|
||||||
|
}
|
31
pkg/extensions/userprefs.md
Normal file
31
pkg/extensions/userprefs.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# `userprefs`
|
||||||
|
|
||||||
|
`userprefs` component provides an endpoint for adding user preferences for repos. It is available only to authentificated users. Unauthentificated users will be denied access.
|
||||||
|
|
||||||
|
| Supported queries | Input | Output | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| [Toggle repo star](#toggle-repo-star) | None | None | Sets the repo starred property to true if it is false, and to false if it is true |
|
||||||
|
| [Toggle repo bookmark](#toggle-repo-bookmark) | None | None | Sets the repo bookmarked property to true if it is false, and to false if it is true |
|
||||||
|
|
||||||
|
## General usage
|
||||||
|
The userprefs endpoint accepts as a query parameter what `action` to perform and then all other required parameters for the specified action.
|
||||||
|
|
||||||
|
## Toggle repo star
|
||||||
|
| Action | Parameter | Parameter Type | Parameter Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| toggleStar | repo | string | The repo name which should be starred |
|
||||||
|
|
||||||
|
A request to togle a star on a repo would look like this:
|
||||||
|
```
|
||||||
|
(PUT) http://localhost:8080/v2/_zot/ext/userprefs?action=toggleStar&repo=repoName
|
||||||
|
```
|
||||||
|
|
||||||
|
## Toggle repo bookmark
|
||||||
|
| Action | Parameter | Parameter Type | Parameter Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| toggleBookmark | repo | string | The repo name which should be bookmarked |
|
||||||
|
|
||||||
|
A request to togle a bookmark on a repo would look like this:
|
||||||
|
```
|
||||||
|
(PUT) http://localhost:8080/v2/_zot/ext/userprefs?action=toggleBookmark&repo=repoName
|
||||||
|
```
|
Loading…
Add table
Reference in a new issue