mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
ui: initial commit
Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com> (cherry picked from commit d557da0baba819b7cd7e6b5941528776e125ac6d)
This commit is contained in:
parent
f3faae0e09
commit
97f1fc0f98
10 changed files with 134 additions and 16 deletions
18
Makefile
18
Makefile
|
@ -45,7 +45,7 @@ build-metadata:
|
|||
go list -tags $(EXTENSIONS) -f '{{ join .GoFiles "\n" }}' ./... | sort -u
|
||||
|
||||
.PHONY: binary
|
||||
binary: modcheck swagger create-name build-metadata
|
||||
binary: modcheck swagger create-name build-metadata ui
|
||||
env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH) -buildmode=pie -tags $(EXTENSIONS),containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.io/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.io/zot/pkg/api/config.BinaryType=$(extended-name) -X zotregistry.io/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zot
|
||||
|
||||
.PHONY: binary-debug
|
||||
|
@ -134,7 +134,7 @@ $(GOLINTER):
|
|||
$(GOLINTER) version
|
||||
|
||||
.PHONY: check
|
||||
check: ./golangcilint.yaml $(GOLINTER)
|
||||
check: ./golangcilint.yaml $(GOLINTER) ui
|
||||
$(GOLINTER) --config ./golangcilint.yaml run --enable-all --out-format=colored-line-number --build-tags containers_image_openpgp ./...
|
||||
$(GOLINTER) --config ./golangcilint.yaml run --enable-all --out-format=colored-line-number --build-tags $(EXTENSIONS),containers_image_openpgp ./...
|
||||
$(GOLINTER) --config ./golangcilint.yaml run --enable-all --out-format=colored-line-number --build-tags dev,containers_image_openpgp ./...
|
||||
|
@ -187,6 +187,7 @@ clean:
|
|||
rm -rf hack
|
||||
rm -rf test/data/zot-test
|
||||
rm -rf test/data/zot-cve-test
|
||||
rm -rf pkg/extensions/build
|
||||
|
||||
.PHONY: run
|
||||
run: binary test
|
||||
|
@ -323,3 +324,16 @@ fuzz-all:
|
|||
.PHONY: anonymous-push-pull
|
||||
anonymous-push-pull: binary check-skopeo $(BATS)
|
||||
$(BATS) --trace --print-output-on-failure test/blackbox/anonymous_policiy.bats
|
||||
|
||||
.PHONY: ui
|
||||
ui:
|
||||
pwd=$$(pwd);\
|
||||
tdir=$$(mktemp -d);\
|
||||
cd $$tdir;\
|
||||
git clone https://github.com/project-zot/zui.git;\
|
||||
cd zui;\
|
||||
npm install;\
|
||||
npm run build;\
|
||||
cd $$pwd;\
|
||||
rm -rf ./pkg/extensions/build;\
|
||||
cp -R $$tdir/zui/build ./pkg/extensions/;
|
||||
|
|
23
examples/config-ui.json
Normal file
23
examples/config-ui.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
"http": {
|
||||
"address": "127.0.0.1",
|
||||
"port": "8080"
|
||||
},
|
||||
"log": {
|
||||
"level": "debug"
|
||||
},
|
||||
"extensions": {
|
||||
"search": {
|
||||
"cve": {
|
||||
"updateInterval": "2h"
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"enable": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,7 +58,8 @@ func allowedMethods(method string) []string {
|
|||
|
||||
// nolint: contextcheck
|
||||
func (rh *RouteHandler) SetupRoutes() {
|
||||
rh.c.Router.Use(AuthHandler(rh.c))
|
||||
prefixedRouter := rh.c.Router.PathPrefix(constants.RoutePrefix).Subrouter()
|
||||
prefixedRouter.Use(AuthHandler(rh.c))
|
||||
// authz is being enabled if AccessControl is specified
|
||||
// if Authn is not present AccessControl will have only default policies
|
||||
if rh.c.Config.AccessControl != nil && !isBearerAuthEnabled(rh.c.Config) {
|
||||
|
@ -68,11 +69,10 @@ func (rh *RouteHandler) SetupRoutes() {
|
|||
rh.c.Log.Info().Msg("default policy only access control is being enabled")
|
||||
}
|
||||
|
||||
rh.c.Router.Use(AuthzHandler(rh.c))
|
||||
prefixedRouter.Use(AuthzHandler(rh.c))
|
||||
}
|
||||
|
||||
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#endpoints
|
||||
prefixedRouter := rh.c.Router.PathPrefix(constants.RoutePrefix).Subrouter()
|
||||
{
|
||||
prefixedRouter.HandleFunc(fmt.Sprintf("/{name:%s}/tags/list", NameRegexp.String()),
|
||||
rh.ListTags).Methods(allowedMethods("GET")...)
|
||||
|
@ -113,7 +113,10 @@ func (rh *RouteHandler) SetupRoutes() {
|
|||
constants.ArtifactSpecRoutePrefix, NameRegexp.String()), rh.GetReferrers).Methods("GET")
|
||||
|
||||
// swagger swagger "/swagger/v2/index.html"
|
||||
rh.c.Router.PathPrefix("/swagger/v2/").Methods("GET").Handler(httpSwagger.WrapHandler)
|
||||
swgRouter := rh.c.Router.PathPrefix("/swagger/v2/").Subrouter()
|
||||
swgRouter.Use(AuthHandler(rh.c))
|
||||
swgRouter.Methods("GET").Handler(httpSwagger.WrapHandler)
|
||||
|
||||
// Setup Extensions Routes
|
||||
if rh.c.Config != nil {
|
||||
if rh.c.Config.Extensions == nil {
|
||||
|
@ -121,8 +124,9 @@ func (rh *RouteHandler) SetupRoutes() {
|
|||
prefixedRouter.HandleFunc("/metrics", rh.GetMetrics).Methods("GET")
|
||||
} else {
|
||||
// extended build
|
||||
ext.SetupMetricsRoutes(rh.c.Config, rh.c.Router, rh.c.StoreController, rh.c.Log)
|
||||
ext.SetupSearchRoutes(rh.c.Config, rh.c.Router, rh.c.StoreController, rh.c.Log)
|
||||
ext.SetupMetricsRoutes(rh.c.Config, rh.c.Router, rh.c.StoreController, AuthHandler(rh.c), rh.c.Log)
|
||||
ext.SetupSearchRoutes(rh.c.Config, rh.c.Router, rh.c.StoreController, AuthHandler(rh.c), rh.c.Log)
|
||||
ext.SetupUIRoutes(rh.c.Config, rh.c.Router, rh.c.StoreController, rh.c.Log)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ type ExtensionConfig struct {
|
|||
Metrics *MetricsConfig
|
||||
Scrub *ScrubConfig
|
||||
Lint *LintConfig
|
||||
UI *UIConfig
|
||||
}
|
||||
|
||||
type LintConfig struct {
|
||||
|
@ -41,3 +42,7 @@ type PrometheusConfig struct {
|
|||
type ScrubConfig struct {
|
||||
Interval time.Duration
|
||||
}
|
||||
|
||||
type UIConfig struct {
|
||||
Enable *bool
|
||||
}
|
||||
|
|
18
pkg/extensions/extension-ui-disabled.go
Normal file
18
pkg/extensions/extension-ui-disabled.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
//go:build !search && !ui_base
|
||||
// +build !search,!ui_base
|
||||
|
||||
package extensions
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
)
|
||||
|
||||
func SetupUIRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||
log log.Logger,
|
||||
) {
|
||||
log.Warn().Msg("skipping setting up ui routes because given zot binary doesn't include this feature," +
|
||||
"please build a binary that does so")
|
||||
}
|
52
pkg/extensions/extension-ui.go
Normal file
52
pkg/extensions/extension-ui.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
//go:build search || ui_base
|
||||
// +build search ui_base
|
||||
|
||||
package extensions
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
)
|
||||
|
||||
// content is our static web server content.
|
||||
//go:embed build/*
|
||||
var content embed.FS
|
||||
|
||||
func SetupUIRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||
l log.Logger,
|
||||
) {
|
||||
// fork a new zerolog child to avoid data race
|
||||
log := log.Logger{Logger: l.With().Caller().Timestamp().Logger()}
|
||||
|
||||
if config.Extensions.UI != nil {
|
||||
fsub, _ := fs.Sub(content, "build")
|
||||
|
||||
router.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
buf, _ := content.ReadFile("build/index.html")
|
||||
|
||||
_, err := w.Write(buf)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("unable to serve index.html")
|
||||
}
|
||||
})
|
||||
|
||||
router.HandleFunc("/home", func(w http.ResponseWriter, r *http.Request) {
|
||||
buf, _ := content.ReadFile("build/index.html")
|
||||
|
||||
_, err := w.Write(buf)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("unable to serve index.html")
|
||||
}
|
||||
})
|
||||
|
||||
router.PathPrefix("/").Handler(http.FileServer(http.FS(fsub)))
|
||||
log.Info().Msg("setting up ui routes")
|
||||
}
|
||||
}
|
|
@ -26,14 +26,14 @@ func EnableMetricsExtension(config *config.Config, log log.Logger, rootDir strin
|
|||
}
|
||||
|
||||
func SetupMetricsRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||
l log.Logger,
|
||||
authFunc mux.MiddlewareFunc, l log.Logger,
|
||||
) {
|
||||
// fork a new zerolog child to avoid data race
|
||||
log := log.Logger{Logger: l.With().Caller().Timestamp().Logger()}
|
||||
log.Info().Msg("setting up metrics routes")
|
||||
|
||||
if config.Extensions.Metrics != nil && *config.Extensions.Metrics.Enable {
|
||||
router.PathPrefix(config.Extensions.Metrics.Prometheus.Path).
|
||||
Handler(promhttp.Handler())
|
||||
extRouter := router.PathPrefix(config.Extensions.Metrics.Prometheus.Path).Handler(promhttp.Handler()).Subrouter()
|
||||
extRouter.Use(authFunc)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ func EnableMetricsExtension(config *config.Config, log log.Logger, rootDir strin
|
|||
|
||||
// SetupMetricsRoutes ...
|
||||
func SetupMetricsRoutes(conf *config.Config, router *mux.Router,
|
||||
storeController storage.StoreController, log log.Logger,
|
||||
storeController storage.StoreController, authFunc mux.MiddlewareFunc, log log.Logger,
|
||||
) {
|
||||
log.Warn().Msg("skipping setting up metrics routes because given zot binary doesn't include this feature," +
|
||||
"please build a binary that does so")
|
||||
|
|
|
@ -56,7 +56,7 @@ func downloadTrivyDB(dbDir string, log log.Logger, updateInterval time.Duration)
|
|||
}
|
||||
|
||||
func SetupSearchRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||
l log.Logger,
|
||||
authFunc mux.MiddlewareFunc, l log.Logger,
|
||||
) {
|
||||
// fork a new zerolog child to avoid data race
|
||||
log := log.Logger{Logger: l.With().Caller().Timestamp().Logger()}
|
||||
|
@ -71,8 +71,10 @@ func SetupSearchRoutes(config *config.Config, router *mux.Router, storeControlle
|
|||
resConfig = search.GetResolverConfig(log, storeController, false)
|
||||
}
|
||||
|
||||
graphqlPrefix := router.PathPrefix(constants.ExtSearchPrefix).Methods("OPTIONS", "GET", "POST")
|
||||
graphqlPrefix.Handler(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig)))
|
||||
extRouter := router.PathPrefix(constants.ExtSearchPrefix).Subrouter()
|
||||
extRouter.Use(authFunc)
|
||||
extRouter.Methods("GET", "POST", "OPTIONS").
|
||||
Handler(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ func EnableSearchExtension(config *config.Config, log log.Logger, rootDir string
|
|||
|
||||
// SetupSearchRoutes ...
|
||||
func SetupSearchRoutes(conf *config.Config, router *mux.Router,
|
||||
storeController storage.StoreController, log log.Logger,
|
||||
storeController storage.StoreController, authFunc mux.MiddlewareFunc, log log.Logger,
|
||||
) {
|
||||
log.Warn().Msg("skipping setting up search routes because given zot binary doesn't include this feature," +
|
||||
"please build a binary that does so")
|
||||
|
|
Loading…
Reference in a new issue