Skip to content

Commit 4ab529d

Browse files
feat(cli): add command to interogate the server version and other details
Signed-off-by: Laurentiu Niculae <[email protected]>
1 parent 4e4ea17 commit 4ab529d

File tree

13 files changed

+201
-14
lines changed

13 files changed

+201
-14
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ exporter-minimal: modcheck build-metadata
123123
.PHONY: test
124124
test: $(if $(findstring ui,$(BUILD_LABELS)), ui)
125125
test: check-skopeo $(TESTDATA) $(ORAS)
126-
go test -failfast -tags $(BUILD_LABELS),containers_image_openpgp -v -trimpath -race -timeout 15m -cover -coverpkg ./... -coverprofile=coverage-extended.txt -covermode=atomic ./...
126+
go test -failfast -tags $(BUILD_LABELS),containers_image_openpgp -v -trimpath -race -timeout 15m -cover -coverpkg ./... -coverprofile=coverage-extended.txt -covermode=atomic ./... -ldflags "-X zotregistry.io/zot/pkg/api/config.ReleaseTag=1.1.1 -X zotregistry.io/zot/pkg/api/config.BinaryType=test,build,tags"
127127
rm -rf /tmp/getter*; rm -rf /tmp/trivy*
128128
go test -failfast -tags containers_image_openpgp -v -trimpath -race -cover -coverpkg ./... -coverprofile=coverage-minimal.txt -covermode=atomic ./...
129129
rm -rf /tmp/getter*; rm -rf /tmp/trivy*

errors/errors.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ var (
7878
ErrUnauthorizedAccess = errors.New("auth: unauthorized access. check credentials")
7979
ErrCannotResetConfigKey = errors.New("cli: cannot reset given config key")
8080
ErrConfigNotFound = errors.New("cli: config with the given name does not exist")
81-
ErrNoURLProvided = errors.New("cli: no URL provided in argument or via config")
81+
ErrNoURLProvided = errors.New("cli: no URL provided by flag or via config")
8282
ErrIllegalConfigKey = errors.New("cli: given config key is not allowed")
8383
ErrScanNotSupported = errors.New("search: scanning of image media type not supported")
8484
ErrCLITimeout = errors.New("cli: Query timed out while waiting for results")
@@ -155,4 +155,5 @@ var (
155155
ErrGQLEndpointNotFound = errors.New("cli: the server doesn't have a gql endpoint")
156156
ErrGQLQueryNotSupported = errors.New("cli: query is not supported or has different arguments")
157157
ErrBadHTTPStatusCode = errors.New("cli: the response doesn't contain the expected status code")
158+
ErrFormatNotSupported = errors.New("cli: the given output format is not supported")
158159
)

pkg/api/config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ func (c *Config) AreUserPrefsEnabled() bool {
326326
}
327327

328328
func (c *Config) IsMgmtEnabled() bool {
329-
return c.IsSearchEnabled() && c.IsUIEnabled()
329+
return c.IsSearchEnabled()
330330
}
331331

332332
func (c *Config) IsImageTrustEnabled() bool {

pkg/api/controller_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8538,17 +8538,17 @@ func TestDistSpecExtensions(t *testing.T) {
85388538
So(err, ShouldBeNil)
85398539
t.Log(extensionList.Extensions)
85408540
So(len(extensionList.Extensions), ShouldEqual, 1)
8541-
So(len(extensionList.Extensions[0].Endpoints), ShouldEqual, 1)
8541+
So(len(extensionList.Extensions[0].Endpoints), ShouldEqual, 2)
85428542
So(extensionList.Extensions[0].Name, ShouldEqual, constants.BaseExtension)
85438543
So(extensionList.Extensions[0].URL, ShouldContainSubstring, "_zot.md")
85448544
So(extensionList.Extensions[0].Description, ShouldNotBeEmpty)
85458545
// Verify the endpoints below are enabled by search
85468546
So(extensionList.Extensions[0].Endpoints, ShouldContain, constants.FullSearchPrefix)
8547+
So(extensionList.Extensions[0].Endpoints, ShouldContain, constants.FullMgmt)
85478548
// Verify the endpoints below are not enabled since trust is not enabled
85488549
So(extensionList.Extensions[0].Endpoints, ShouldNotContain, constants.FullCosign)
85498550
So(extensionList.Extensions[0].Endpoints, ShouldNotContain, constants.FullNotation)
85508551
// Verify the endpoints below are not enabled since the UI is not enabled
8551-
So(extensionList.Extensions[0].Endpoints, ShouldNotContain, constants.FullMgmt)
85528552
So(extensionList.Extensions[0].Endpoints, ShouldNotContain, constants.FullUserPrefs)
85538553
})
85548554

pkg/cli/cli.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ func enableCli(rootCmd *cobra.Command) {
1313
rootCmd.AddCommand(NewCVESCommand(NewSearchService()))
1414
rootCmd.AddCommand(NewRepoCommand(NewSearchService()))
1515
rootCmd.AddCommand(NewSearchCommand(NewSearchService()))
16+
rootCmd.AddCommand(NewServerInfoCommand())
1617
}

pkg/cli/discover.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,11 @@ func CheckExtEndPointQuery(config searchConfig, requiredQueries ...GQLQuery) err
199199
searchEndPoint, _ := combineServerAndEndpointURL(*config.servURL, constants.FullSearchPrefix)
200200

201201
schemaQuery := `
202-
{
203-
__schema() {
204-
queryType {
205-
fields {
206-
name
202+
{
203+
__schema() {
204+
queryType {
205+
fields {
206+
name
207207
args {
208208
name
209209
}

pkg/cli/extensions_test.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ func TestServeMgmtExtension(t *testing.T) {
837837
So(found, ShouldBeTrue)
838838
})
839839

840-
Convey("Mgmt disabled - UI unconfigured", t, func(c C) {
840+
Convey("Mgmt disabled - Search unconfigured", t, func(c C) {
841841
content := `{
842842
"storage": {
843843
"rootDirectory": "%s"
@@ -851,9 +851,6 @@ func TestServeMgmtExtension(t *testing.T) {
851851
"output": "%s"
852852
},
853853
"extensions": {
854-
"search": {
855-
"enable": true
856-
}
857854
}
858855
}`
859856

pkg/cli/server_info_cmd.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//go:build search
2+
// +build search
3+
4+
package cli
5+
6+
import (
7+
"context"
8+
"encoding/json"
9+
"fmt"
10+
"strings"
11+
12+
"github.com/spf13/cobra"
13+
"gopkg.in/yaml.v2"
14+
15+
zerr "zotregistry.io/zot/errors"
16+
"zotregistry.io/zot/pkg/api/constants"
17+
"zotregistry.io/zot/pkg/cli/cmdflags"
18+
)
19+
20+
func NewServerInfoCommand() *cobra.Command {
21+
serverInfoCmd := &cobra.Command{
22+
Use: "server-info",
23+
Short: "Information about the server configuration and build information",
24+
Long: `Information about the server configuration and build information`,
25+
Args: cobra.NoArgs,
26+
RunE: func(cmd *cobra.Command, args []string) error {
27+
searchConfig, err := GetSearchConfigFromFlags(cmd, NewSearchService())
28+
if err != nil {
29+
return err
30+
}
31+
32+
return GetServerInfo(searchConfig)
33+
},
34+
}
35+
36+
serverInfoCmd.Flags().String(cmdflags.OutputFormatFlag, "text", "Specify the output format [text|json|yaml]")
37+
38+
return serverInfoCmd
39+
}
40+
41+
func GetServerInfo(config searchConfig) error {
42+
username, password := getUsernameAndPassword(*config.user)
43+
ctx := context.Background()
44+
45+
mgmtEndpoint, err := combineServerAndEndpointURL(*config.servURL, fmt.Sprintf("%s%s",
46+
constants.RoutePrefix, constants.ExtMgmt))
47+
if err != nil {
48+
return err
49+
}
50+
51+
serverInfo := ServerInfo{}
52+
53+
_, err = makeGETRequest(ctx, mgmtEndpoint, username, password, *config.verifyTLS, *config.debug,
54+
&serverInfo, config.resultWriter)
55+
if err != nil {
56+
return err
57+
}
58+
59+
outputResult, err := serverInfo.ToStringFormat(*config.outputFormat)
60+
if err != nil {
61+
return err
62+
}
63+
64+
fmt.Fprintln(config.resultWriter, outputResult)
65+
66+
return nil
67+
}
68+
69+
type ServerInfo struct {
70+
DistSpecVersion string `json:"distSpecVersion" mapstructure:"distSpecVersion"`
71+
Commit string `json:"commit" mapstructure:"commit"`
72+
BinaryType string `json:"binaryType" mapstructure:"binaryType"`
73+
ReleaseTag string `json:"releaseTag" mapstructure:"releaseTag"`
74+
}
75+
76+
func (si *ServerInfo) ToStringFormat(format string) (string, error) {
77+
switch format {
78+
case "text", "":
79+
return si.ToText()
80+
case "json":
81+
return si.ToJSON()
82+
case "yaml", "yml":
83+
return si.ToYAML()
84+
default:
85+
return "", zerr.ErrFormatNotSupported
86+
}
87+
}
88+
89+
func (si *ServerInfo) ToText() (string, error) {
90+
flagsList := strings.Split(strings.Trim(si.BinaryType, "-"), "-")
91+
flags := strings.Join(flagsList, ", ")
92+
93+
return fmt.Sprintf("Server Version: %s\n"+
94+
"Dist Spec Version: %s\n"+
95+
"Built with: %s",
96+
si.ReleaseTag, si.DistSpecVersion, flags,
97+
),
98+
nil
99+
}
100+
101+
func (si *ServerInfo) ToJSON() (string, error) {
102+
blob, err := json.MarshalIndent(*si, "", " ")
103+
104+
return string(blob), err
105+
}
106+
107+
func (si *ServerInfo) ToYAML() (string, error) {
108+
body, err := yaml.Marshal(*si)
109+
110+
return string(body), err
111+
}

pkg/cli/server_info_cmd_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//go:build search
2+
// +build search
3+
4+
package cli //nolint:testpackage
5+
6+
import (
7+
"bytes"
8+
"fmt"
9+
"os"
10+
"regexp"
11+
"strings"
12+
"testing"
13+
14+
. "github.com/smartystreets/goconvey/convey"
15+
16+
"zotregistry.io/zot/pkg/api"
17+
"zotregistry.io/zot/pkg/api/config"
18+
extconf "zotregistry.io/zot/pkg/extensions/config"
19+
"zotregistry.io/zot/pkg/test"
20+
)
21+
22+
func TestServerInfoCommand(t *testing.T) {
23+
Convey("ServerInfoCommand", t, func() {
24+
port := test.GetFreePort()
25+
baseURL := test.GetBaseURL(port)
26+
conf := config.New()
27+
conf.HTTP.Port = port
28+
conf.Storage.GC = false
29+
defaultVal := true
30+
conf.Extensions = &extconf.ExtensionConfig{
31+
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
32+
}
33+
34+
ctlr := api.NewController(conf)
35+
ctlr.Config.Storage.RootDirectory = t.TempDir()
36+
cm := test.NewControllerManager(ctlr)
37+
38+
cm.StartAndWait(conf.HTTP.Port)
39+
defer cm.StopServer()
40+
41+
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"server-info-test","url":"%s","showspinner":false}]}`,
42+
baseURL))
43+
defer os.Remove(configPath)
44+
45+
args := []string{"server-info", "--config", "server-info-test"}
46+
cmd := NewCliRootCmd()
47+
buff := bytes.NewBufferString("")
48+
cmd.SetOut(buff)
49+
cmd.SetErr(buff)
50+
cmd.SetArgs(args)
51+
err := cmd.Execute()
52+
So(err, ShouldBeNil)
53+
space := regexp.MustCompile(`\s+`)
54+
str := space.ReplaceAllString(buff.String(), " ")
55+
actual := strings.TrimSpace(str)
56+
So(actual, ShouldContainSubstring, config.ReleaseTag)
57+
So(actual, ShouldContainSubstring, config.BinaryType)
58+
})
59+
}

pkg/extensions/extension_mgmt.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ type Auth struct {
4343

4444
type StrippedConfig struct {
4545
DistSpecVersion string `json:"distSpecVersion" mapstructure:"distSpecVersion"`
46+
Commit string `json:"commit" mapstructure:"commit"`
47+
ReleaseTag string `json:"releaseTag" mapstructure:"releaseTag"`
4648
BinaryType string `json:"binaryType" mapstructure:"binaryType"`
4749
HTTP struct {
4850
Auth *Auth `json:"auth,omitempty" mapstructure:"auth"`

0 commit comments

Comments
 (0)