mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
feat(ui): package zui within zot binary (#1161)
(cherry picked from commit d557da0baba819b7cd7e6b5941528776e125ac6d) build(ui): fix stacker builds (cherry picked from commit ba25daf02b4a9bc7ee1cb6f84b7a6b096ca7d61f) build(ui): various fixes - Fix metrics endpoint - Fix unit tests unit tests - Make the ui build optional in the makefile before the linter lint runs in the golangci-lint workflow - Do not attempt to include UI routes if search is enabled - Fix authorization for search endpoint fix: use zot tag in ui make target (cherry picked from commit 2a6882fa23f06b2d68c6c299773a6ff50bf90e78) Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com> Signed-off-by: Catalin Hofnar <catalin.hofnar@gmail.com> Signed-off-by: Andrei Aaron <aaaron@luxoft.com> Co-authored-by: Ramkumar Chinchani <rchincha@cisco.com>
This commit is contained in:
parent
d12836e69c
commit
c0aaca8ed1
16 changed files with 189 additions and 37 deletions
15
.github/workflows/ci-cd.yml
vendored
15
.github/workflows/ci-cd.yml
vendored
|
@ -41,6 +41,19 @@ jobs:
|
|||
go-version: 1.19.x
|
||||
- name: Check out source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Push release tag to zui
|
||||
if: github.event_name == 'release' && github.event.action == 'published' && matrix.os == 'linux' && matrix.arch == 'amd64'
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
token: ${{ secrets.ZUI_TOKEN }}
|
||||
repo: zui
|
||||
owner: project-zot
|
||||
tag: ${{ github.event.release.tag_name }}
|
||||
name: ${{ github.event.release.name }}
|
||||
body: ${{ github.event.release.body }}
|
||||
commit: main
|
||||
|
||||
- name: Cache go dependencies
|
||||
id: cache-go-dependencies
|
||||
uses: actions/cache@v3
|
||||
|
@ -105,7 +118,7 @@ jobs:
|
|||
make OS=$OS ARCH=$ARCH
|
||||
sudo env "PATH=$PATH" make privileged-test
|
||||
else
|
||||
make OS=$OS ARCH=$ARCH binary binary-minimal binary-debug cli bench exporter-minimal
|
||||
make OS=$OS ARCH=$ARCH binary binary-minimal binary-debug binary-ui cli bench exporter-minimal
|
||||
fi
|
||||
env:
|
||||
S3MOCK_ENDPOINT: localhost:4566
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -11,6 +11,9 @@
|
|||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Output of the UI build
|
||||
pkg/extensions/build/
|
||||
|
||||
# Tooling used for blackbox testing
|
||||
hack/
|
||||
.stacker/
|
||||
|
|
44
Makefile
44
Makefile
|
@ -32,7 +32,7 @@ hyphen:= -
|
|||
extended-name:=
|
||||
|
||||
.PHONY: all
|
||||
all: modcheck swagger binary binary-minimal binary-debug cli bench exporter-minimal verify-config test covhtml check check-gh-actions
|
||||
all: modcheck swagger binary binary-minimal binary-debug binary-ui cli bench exporter-minimal verify-config test covhtml check check-gh-actions
|
||||
|
||||
.PHONY: modcheck
|
||||
modcheck:
|
||||
|
@ -45,7 +45,7 @@ ifdef EXTENSIONS
|
|||
endif
|
||||
|
||||
.PHONY: build-metadata
|
||||
build-metadata:
|
||||
build-metadata: $(if $(findstring ui,$(EXTENSIONS)), ui)
|
||||
echo "Imports: \n"
|
||||
go list -tags $(EXTENSIONS) -f '{{ join .Imports "\n" }}' ./... | sort -u
|
||||
echo "\n Files: \n"
|
||||
|
@ -57,13 +57,19 @@ binary-minimal: modcheck build-metadata
|
|||
env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH)-minimal -buildmode=pie -tags containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.io/zot/pkg/api/config.ReleaseTag=${RELEASE_TAG} -X zotregistry.io/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.io/zot/pkg/api/config.BinaryType=minimal -X zotregistry.io/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zot
|
||||
|
||||
.PHONY: binary
|
||||
binary: $(if $(findstring ui,$(EXTENSIONS)), ui)
|
||||
binary: modcheck create-name build-metadata
|
||||
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.ReleaseTag=${RELEASE_TAG} -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
|
||||
binary-debug: $(if $(findstring ui,$(EXTENSIONS)), ui)
|
||||
binary-debug: modcheck swagger create-name build-metadata
|
||||
env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH)-debug -buildmode=pie -tags $(EXTENSIONS),debug,containers_image_openpgp -v -gcflags all='-N -l' -ldflags "-X zotregistry.io/zot/pkg/api/config.ReleaseTag=${RELEASE_TAG} -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}" ./cmd/zot
|
||||
|
||||
.PHONY: binary-ui
|
||||
binary-ui: modcheck create-name build-metadata ui
|
||||
env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH)-ui -buildmode=pie -tags $(EXTENSIONS),ui,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: cli
|
||||
cli: modcheck create-name build-metadata
|
||||
env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zli-$(OS)-$(ARCH) -buildmode=pie -tags $(EXTENSIONS),search,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/zli
|
||||
|
@ -78,6 +84,7 @@ exporter-minimal: modcheck build-metadata
|
|||
env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zxp-$(OS)-$(ARCH) -buildmode=pie -tags containers_image_openpgp -v -trimpath ./cmd/zxp
|
||||
|
||||
.PHONY: test
|
||||
test: $(if $(findstring ui,$(EXTENSIONS)), ui)
|
||||
test: check-skopeo $(TESTDATA) $(NOTATION) $(ORAS)
|
||||
go test -failfast -tags $(EXTENSIONS),containers_image_openpgp -v -trimpath -race -timeout 15m -cover -coverpkg ./... -coverprofile=coverage-extended.txt -covermode=atomic ./...
|
||||
go test -failfast -tags containers_image_openpgp -v -trimpath -race -cover -coverpkg ./... -coverprofile=coverage-minimal.txt -covermode=atomic ./...
|
||||
|
@ -87,6 +94,7 @@ test: check-skopeo $(TESTDATA) $(NOTATION) $(ORAS)
|
|||
go test -failfast -tags stress,$(EXTENSIONS),containers_image_openpgp -v -trimpath -race -timeout 15m ./pkg/cli/stress_test.go
|
||||
|
||||
.PHONY: privileged-test
|
||||
privileged-test: $(if $(findstring ui,$(EXTENSIONS)), ui)
|
||||
privileged-test: check-skopeo $(TESTDATA) $(NOTATION)
|
||||
go test -failfast -tags needprivileges,$(EXTENSIONS),containers_image_openpgp -v -trimpath -race -timeout 15m -cover -coverpkg ./... -coverprofile=coverage-dev-needprivileges.txt -covermode=atomic ./pkg/storage/... ./pkg/cli/... -run ^TestElevatedPrivileges
|
||||
|
||||
|
@ -151,12 +159,16 @@ $(GOLINTER):
|
|||
$(GOLINTER) version
|
||||
|
||||
.PHONY: check
|
||||
check: $(if $(findstring ui,$(EXTENSIONS)), ui)
|
||||
check: ./golangcilint.yaml $(GOLINTER)
|
||||
mkdir -p pkg/extensions/build; touch pkg/extensions/build/.empty
|
||||
$(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 $(EXTENSIONS),containers_image_openpgp,ui,debug ./...
|
||||
$(GOLINTER) --config ./golangcilint.yaml run --enable-all --out-format=colored-line-number --build-tags dev,containers_image_openpgp ./...
|
||||
$(GOLINTER) --config ./golangcilint.yaml run --enable-all --out-format=colored-line-number --build-tags dev,$(EXTENSIONS),containers_image_openpgp ./...
|
||||
$(GOLINTER) --config ./golangcilint.yaml run --enable-all --out-format=colored-line-number --build-tags stress,$(EXTENSIONS),containers_image_openpgp ./...
|
||||
rm pkg/extensions/build/.empty
|
||||
|
||||
swagger/docs.go:
|
||||
swag -v || go install github.com/swaggo/swag/cmd/swag@1.6.3
|
||||
|
@ -204,6 +216,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
|
||||
|
@ -262,12 +275,12 @@ run-container:
|
|||
|
||||
.PHONY: binary-stacker
|
||||
binary-stacker:
|
||||
${STACKER} build \
|
||||
${STACKER} --debug build \
|
||||
-f build/stacker.yaml \
|
||||
--substitute COMMIT=$(PWD) \
|
||||
--substitute OS=$(OS) \
|
||||
--substitute ARCH=$(ARCH) \
|
||||
--substitute PWD=$(PWD)
|
||||
--substitute PWD=$$PWD \
|
||||
--substitute COMMIT=$$COMMIT \
|
||||
--substitute ARCH=$$ARCH \
|
||||
--substitute OS=$$OS
|
||||
|
||||
.PHONY: image
|
||||
image:
|
||||
|
@ -369,3 +382,20 @@ $(COSIGN):
|
|||
mkdir -p $(TOOLSDIR)/bin
|
||||
curl -fsSL https://github.com/sigstore/cosign/releases/download/v1.13.0/cosign-linux-amd64 -o $@; \
|
||||
chmod +x $@
|
||||
|
||||
.PHONY: ui
|
||||
ui:
|
||||
pwd=$$(pwd);\
|
||||
tdir=$$(mktemp -d);\
|
||||
cd $$tdir;\
|
||||
if [ -z $(RELEASE_UI) ]; then\
|
||||
git clone https://github.com/project-zot/zui.git;\
|
||||
else\
|
||||
git clone --depth 1 --branch $(RELEASE_TAG) https://github.com/project-zot/zui.git;\
|
||||
fi;\
|
||||
cd zui;\
|
||||
npm install;\
|
||||
npm run build;\
|
||||
cd $$pwd;\
|
||||
rm -rf ./pkg/extensions/build;\
|
||||
cp -R $$tdir/zui/build ./pkg/extensions/;
|
||||
|
|
|
@ -45,7 +45,7 @@ build:
|
|||
arch: ${{ARCH}}
|
||||
from:
|
||||
type: docker
|
||||
url: docker://gcr.io/distroless/base:latest-${{ARCH}}
|
||||
url: docker://zothub.io/c3/base:jammy
|
||||
overlay_dirs:
|
||||
- source: ../.build/${{REPO_NAME}}/binary
|
||||
dest: /usr/local/bin
|
||||
|
|
23
examples/config-ui.json
Normal file
23
examples/config-ui.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"distSpecVersion": "1.1.0-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
"http": {
|
||||
"address": "0.0.0.0",
|
||||
"port": "8080"
|
||||
},
|
||||
"log": {
|
||||
"level": "debug"
|
||||
},
|
||||
"extensions": {
|
||||
"search": {
|
||||
"cve": {
|
||||
"updateInterval": "2h"
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"enable": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,7 +58,8 @@ func allowedMethods(method string) []string {
|
|||
}
|
||||
|
||||
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", zreg.NameRegexp.String()),
|
||||
rh.ListTags).Methods(allowedMethods("GET")...)
|
||||
|
@ -116,7 +116,7 @@ func (rh *RouteHandler) SetupRoutes() {
|
|||
constants.ArtifactSpecRoutePrefix, zreg.NameRegexp.String()), rh.GetOrasReferrers).Methods("GET")
|
||||
|
||||
// swagger
|
||||
debug.SetupSwaggerRoutes(rh.c.Config, rh.c.Router, rh.c.Log)
|
||||
debug.SetupSwaggerRoutes(rh.c.Config, rh.c.Router, AuthHandler(rh.c), rh.c.Log)
|
||||
|
||||
// Setup Extensions Routes
|
||||
if rh.c.Config != nil {
|
||||
|
@ -125,9 +125,10 @@ 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.RepoDB, rh.c.CveInfo, rh.c.Log)
|
||||
gqlPlayground.SetupGQLPlaygroundRoutes(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, prefixedRouter, rh.c.StoreController, rh.c.RepoDB, rh.c.CveInfo, rh.c.Log)
|
||||
ext.SetupUIRoutes(rh.c.Config, rh.c.Router, rh.c.StoreController, rh.c.Log)
|
||||
gqlPlayground.SetupGQLPlaygroundRoutes(rh.c.Config, prefixedRouter, rh.c.StoreController, rh.c.Log)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,7 +107,8 @@ func TestServeExtensions(t *testing.T) {
|
|||
WaitTillServerReady(baseURL)
|
||||
data, err := os.ReadFile(logFile.Name())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(data), ShouldContainSubstring, "\"Extensions\":{\"Search\":null,\"Sync\":null,\"Metrics\":null,\"Scrub\":null,\"Lint\":null") //nolint:lll // gofumpt conflicts with lll
|
||||
So(string(data), ShouldContainSubstring,
|
||||
"\"Extensions\":{\"Search\":null,\"Sync\":null,\"Metrics\":null,\"Scrub\":null,\"Lint\":null,\"UI\":null") //nolint:lll // gofumpt conflicts with lll
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -148,7 +149,7 @@ func testWithMetricsEnabled(cfgContentFormat string) {
|
|||
data, err := os.ReadFile(logFile.Name())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(data), ShouldContainSubstring,
|
||||
"\"Extensions\":{\"Search\":null,\"Sync\":null,\"Metrics\":{\"Enable\":true,\"Prometheus\":{\"Path\":\"/metrics\"}},\"Scrub\":null,\"Lint\":null}") //nolint:lll // gofumpt conflicts with lll
|
||||
"\"Metrics\":{\"Enable\":true,\"Prometheus\":{\"Path\":\"/metrics\"}}")
|
||||
}
|
||||
|
||||
func TestServeMetricsExtension(t *testing.T) {
|
||||
|
@ -272,7 +273,7 @@ func TestServeMetricsExtension(t *testing.T) {
|
|||
data, err := os.ReadFile(logFile.Name())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(data), ShouldContainSubstring,
|
||||
"\"Extensions\":{\"Search\":null,\"Sync\":null,\"Metrics\":{\"Enable\":false,\"Prometheus\":{\"Path\":\"/metrics\"}},\"Scrub\":null,\"Lint\":null}}") //nolint:lll // gofumpt conflicts with lll
|
||||
"\"Metrics\":{\"Enable\":false,\"Prometheus\":{\"Path\":\"/metrics\"}}") //nolint:lll // gofumpt conflicts with lll
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -472,8 +473,7 @@ func TestServeScrubExtension(t *testing.T) {
|
|||
defer os.Remove(logPath) // clean up
|
||||
// Even if in config we specified scrub interval=1h, the minimum interval is 2h
|
||||
dataStr := string(data)
|
||||
So(dataStr, ShouldContainSubstring,
|
||||
"\"Extensions\":{\"Search\":null,\"Sync\":null,\"Metrics\":null,\"Scrub\":{\"Enable\":true,\"Interval\":3600000000000},\"Lint\":null") //nolint:lll // gofumpt conflicts with lll
|
||||
So(dataStr, ShouldContainSubstring, "\"Scrub\":{\"Enable\":true,\"Interval\":3600000000000}")
|
||||
So(dataStr, ShouldContainSubstring,
|
||||
"Scrub interval set to too-short interval < 2h, changing scrub duration to 2 hours and continuing.")
|
||||
})
|
||||
|
@ -536,8 +536,7 @@ func TestServeScrubExtension(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
defer os.Remove(logPath) // clean up
|
||||
dataStr := string(data)
|
||||
So(dataStr, ShouldContainSubstring,
|
||||
"\"Extensions\":{\"Search\":null,\"Sync\":null,\"Metrics\":null,\"Scrub\":{\"Enable\":false,\"Interval\":86400000000000},\"Lint\":null}") //nolint:lll // gofumpt conflicts with lll
|
||||
So(dataStr, ShouldContainSubstring, "\"Scrub\":{\"Enable\":false,\"Interval\":86400000000000}")
|
||||
So(dataStr, ShouldContainSubstring, "Scrub config not provided, skipping scrub")
|
||||
So(dataStr, ShouldNotContainSubstring,
|
||||
"Scrub interval set to too-short interval < 2h, changing scrub duration to 2 hours and continuing.")
|
||||
|
@ -639,7 +638,8 @@ func TestServeSearchEnabled(t *testing.T) {
|
|||
// to avoid data race when multiple go routines write to trivy DB instance.
|
||||
defer os.Remove(logPath) // clean up
|
||||
|
||||
substring := "\"Extensions\":{\"Search\":{\"Enable\":true,\"CVE\":null},\"Sync\":null,\"Metrics\":null,\"Scrub\":null,\"Lint\":null}" //nolint:lll // gofumpt conflicts with lll
|
||||
substring := `"Extensions":{"Search":{"Enable":true,"CVE":null}`
|
||||
|
||||
found, err := readLogFileAndSearchString(logPath, substring, readLogFileTimeout)
|
||||
So(found, ShouldBeTrue)
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -680,7 +680,8 @@ func TestServeSearchEnabledCVE(t *testing.T) {
|
|||
// to avoid data race when multiple go routines write to trivy DB instance.
|
||||
WaitTillTrivyDBDownloadStarted(tempDir)
|
||||
|
||||
substring := "\"Extensions\":{\"Search\":{\"Enable\":true,\"CVE\":{\"UpdateInterval\":3600000000000,\"Trivy\":null}},\"Sync\":null,\"Metrics\":null,\"Scrub\":null,\"Lint\":null}" //nolint:lll // gofumpt conflicts with lll
|
||||
substring := "\"Search\":{\"Enable\":true,\"CVE\":{\"UpdateInterval\":3600000000000,\"Trivy\":null}}"
|
||||
|
||||
found, err := readLogFileAndSearchString(logPath, substring, readLogFileTimeout)
|
||||
So(found, ShouldBeTrue)
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -726,7 +727,7 @@ func TestServeSearchEnabledNoCVE(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
defer os.Remove(logPath) // clean up
|
||||
|
||||
substring := "\"Extensions\":{\"Search\":{\"Enable\":true,\"CVE\":null},\"Sync\":null,\"Metrics\":null,\"Scrub\":null,\"Lint\":null}" //nolint:lll // gofumpt conflicts with lll
|
||||
substring := `"Extensions":{"Search":{"Enable":true,"CVE":null}` //nolint:lll // gofumpt conflicts with lll
|
||||
found, err := readLogFileAndSearchString(logPath, substring, readLogFileTimeout)
|
||||
So(found, ShouldBeTrue)
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -768,7 +769,7 @@ func TestServeSearchDisabled(t *testing.T) {
|
|||
defer os.Remove(logPath) // clean up
|
||||
dataStr := string(data)
|
||||
So(dataStr, ShouldContainSubstring,
|
||||
"\"Extensions\":{\"Search\":{\"Enable\":false,\"CVE\":{\"UpdateInterval\":10800000000000,\"Trivy\":null}},\"Sync\":null,\"Metrics\":null,\"Scrub\":null,\"Lint\":null}") //nolint:lll // gofumpt conflicts with lll
|
||||
"\"Search\":{\"Enable\":false,\"CVE\":{\"UpdateInterval\":10800000000000,\"Trivy\":null}")
|
||||
So(dataStr, ShouldContainSubstring, "CVE config not provided, skipping CVE update")
|
||||
So(dataStr, ShouldNotContainSubstring,
|
||||
"CVE update interval set to too-short interval < 2h, changing update duration to 2 hours and continuing.")
|
||||
|
|
|
@ -33,7 +33,7 @@ func SetupGQLPlaygroundRoutes(conf *config.Config, router *mux.Router,
|
|||
}
|
||||
|
||||
//nolint:lll
|
||||
router.PathPrefix(constants.RoutePrefix + debugCst.GQLPlaygroundEndpoint).HandlerFunc(func(writer http.ResponseWriter, req *http.Request) {
|
||||
router.PathPrefix(debugCst.GQLPlaygroundEndpoint).HandlerFunc(func(writer http.ResponseWriter, req *http.Request) {
|
||||
writer.Header().Add("Content-Type", "text/html")
|
||||
|
||||
proto := ""
|
||||
|
|
|
@ -17,9 +17,12 @@ import (
|
|||
_ "zotregistry.io/zot/swagger"
|
||||
)
|
||||
|
||||
func SetupSwaggerRoutes(conf *config.Config, router *mux.Router, log log.Logger,
|
||||
func SetupSwaggerRoutes(conf *config.Config, router *mux.Router, authFunc mux.MiddlewareFunc,
|
||||
log log.Logger,
|
||||
) {
|
||||
log.Info().Msg("setting up swagger route")
|
||||
// swagger swagger "/swagger/v2/index.html"
|
||||
router.PathPrefix("/swagger/v2/").Methods("GET").Handler(httpSwagger.WrapHandler)
|
||||
swgRouter := router.PathPrefix("/swagger/v2/").Subrouter()
|
||||
swgRouter.Use(authFunc)
|
||||
swgRouter.Methods("GET").Handler(httpSwagger.WrapHandler)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ import (
|
|||
_ "zotregistry.io/zot/swagger"
|
||||
)
|
||||
|
||||
func SetupSwaggerRoutes(conf *config.Config, router *mux.Router, log log.Logger,
|
||||
func SetupSwaggerRoutes(conf *config.Config, router *mux.Router, authFunc mux.MiddlewareFunc,
|
||||
log log.Logger,
|
||||
) {
|
||||
// swagger swagger "/swagger/v2/index.html"
|
||||
log.Warn().Msg("skipping enabling swagger because given zot binary " +
|
||||
|
|
|
@ -17,6 +17,7 @@ type ExtensionConfig struct {
|
|||
Metrics *MetricsConfig
|
||||
Scrub *ScrubConfig
|
||||
Lint *LintConfig
|
||||
UI *UIConfig
|
||||
}
|
||||
|
||||
type LintConfig struct {
|
||||
|
@ -52,3 +53,7 @@ type ScrubConfig struct {
|
|||
BaseConfig `mapstructure:",squash"`
|
||||
Interval time.Duration
|
||||
}
|
||||
|
||||
type UIConfig struct {
|
||||
BaseConfig `mapstructure:",squash"`
|
||||
}
|
||||
|
|
19
pkg/extensions/extension-ui-disabled.go
Normal file
19
pkg/extensions/extension-ui-disabled.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
//go:build !search || !ui
|
||||
// +build !search !ui
|
||||
|
||||
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")
|
||||
}
|
51
pkg/extensions/extension-ui.go
Normal file
51
pkg/extensions/extension-ui.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
//go:build search && ui
|
||||
// +build search,ui
|
||||
|
||||
package extensions
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
)
|
||||
|
||||
// content is our static web server content.
|
||||
//
|
||||
//go:embed build/*
|
||||
var content embed.FS
|
||||
|
||||
type uiHandler struct {
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (uih uiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
buf, _ := content.ReadFile("build/index.html")
|
||||
|
||||
_, err := w.Write(buf)
|
||||
if err != nil {
|
||||
uih.log.Error().Err(err).Msg("unable to serve index.html")
|
||||
}
|
||||
}
|
||||
|
||||
func SetupUIRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||
log log.Logger,
|
||||
) {
|
||||
if config.Extensions.UI != nil {
|
||||
fsub, _ := fs.Sub(content, "build")
|
||||
uih := uiHandler{log: log}
|
||||
|
||||
router.PathPrefix("/login").Handler(uih)
|
||||
router.PathPrefix("/home").Handler(uih)
|
||||
router.PathPrefix("/explore").Handler(uih)
|
||||
router.PathPrefix("/image").Handler(uih)
|
||||
router.PathPrefix("/").Handler(http.FileServer(http.FS(fsub)))
|
||||
|
||||
log.Info().Msg("setting up ui routes")
|
||||
}
|
||||
}
|
|
@ -27,12 +27,13 @@ func EnableMetricsExtension(config *config.Config, log log.Logger, rootDir strin
|
|||
}
|
||||
|
||||
func SetupMetricsRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||
log log.Logger,
|
||||
authFunc mux.MiddlewareFunc, log log.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).Subrouter()
|
||||
extRouter.Use(authFunc)
|
||||
extRouter.Methods("GET").Handler(promhttp.Handler())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,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")
|
||||
|
|
|
@ -84,8 +84,9 @@ func SetupSearchRoutes(config *config.Config, router *mux.Router, storeControlle
|
|||
if config.Extensions.Search != nil && *config.Extensions.Search.Enable {
|
||||
resConfig := search.GetResolverConfig(log, storeController, repoDB, cveInfo)
|
||||
|
||||
graphqlPrefix := router.PathPrefix(constants.FullSearchPrefix).Methods("OPTIONS", "GET", "POST")
|
||||
graphqlPrefix.Handler(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig)))
|
||||
extRouter := router.PathPrefix(constants.ExtSearchPrefix).Subrouter()
|
||||
extRouter.Methods("GET", "POST", "OPTIONS").
|
||||
Handler(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue