mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
83f287d1f6
Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
191 lines
5.5 KiB
Go
191 lines
5.5 KiB
Go
//go:build search
|
|
// +build search
|
|
|
|
package client
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
"gopkg.in/yaml.v2"
|
|
|
|
zerr "zotregistry.io/zot/errors"
|
|
"zotregistry.io/zot/pkg/api/constants"
|
|
)
|
|
|
|
const (
|
|
StatusOnline = "online"
|
|
StatusOffline = "offline"
|
|
StatusUnknown = "unknown"
|
|
)
|
|
|
|
func NewServerStatusCommand() *cobra.Command {
|
|
serverInfoCmd := &cobra.Command{
|
|
Use: "status",
|
|
Short: "Information about the server configuration and build information",
|
|
Long: `Information about the server configuration and build information`,
|
|
Args: cobra.NoArgs,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
searchConfig, err := GetSearchConfigFromFlags(cmd, NewSearchService())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return GetServerStatus(searchConfig)
|
|
},
|
|
}
|
|
|
|
serverInfoCmd.PersistentFlags().String(URLFlag, "",
|
|
"Specify zot server URL if config-name is not mentioned")
|
|
serverInfoCmd.PersistentFlags().StringP(ConfigFlag, "c", "",
|
|
"Specify the registry configuration to use for connection")
|
|
serverInfoCmd.PersistentFlags().StringP(UserFlag, "u", "",
|
|
`User Credentials of zot server in "username:password" format`)
|
|
serverInfoCmd.Flags().StringP(OutputFormatFlag, "f", "text", "Specify the output format [text|json|yaml]")
|
|
|
|
return serverInfoCmd
|
|
}
|
|
|
|
func GetServerStatus(config SearchConfig) error {
|
|
ctx := context.Background()
|
|
username, password := getUsernameAndPassword(config.User)
|
|
|
|
checkAPISupportEndpoint, err := combineServerAndEndpointURL(config.ServURL, constants.RoutePrefix+"/")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = makeGETRequest(ctx, checkAPISupportEndpoint, username, password, config.VerifyTLS, config.Debug,
|
|
nil, config.ResultWriter)
|
|
if err != nil {
|
|
serverInfo := ServerInfo{}
|
|
|
|
switch {
|
|
case errors.Is(err, zerr.ErrUnauthorizedAccess):
|
|
serverInfo.Status = StatusUnknown
|
|
serverInfo.ErrorMsg = fmt.Sprintf("unauthorised access, %s", getCredentialsSuggestion(username))
|
|
case errors.Is(err, zerr.ErrBadHTTPStatusCode), errors.Is(err, zerr.ErrURLNotFound):
|
|
serverInfo.Status = StatusOffline
|
|
serverInfo.ErrorMsg = fmt.Sprintf("%s: request at %s failed", zerr.ErrAPINotSupported.Error(),
|
|
checkAPISupportEndpoint)
|
|
default:
|
|
serverInfo.Status = StatusOffline
|
|
serverInfo.ErrorMsg = err.Error()
|
|
}
|
|
|
|
return PrintServerInfo(serverInfo, config)
|
|
}
|
|
|
|
mgmtEndpoint, err := combineServerAndEndpointURL(config.ServURL, fmt.Sprintf("%s%s",
|
|
constants.RoutePrefix, constants.ExtMgmt))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
serverInfo := ServerInfo{}
|
|
|
|
_, err = makeGETRequest(ctx, mgmtEndpoint, username, password, config.VerifyTLS, config.Debug,
|
|
&serverInfo, config.ResultWriter)
|
|
|
|
switch {
|
|
case err == nil:
|
|
serverInfo.Status = StatusOnline
|
|
case errors.Is(err, zerr.ErrURLNotFound):
|
|
serverInfo.Status = StatusOnline
|
|
serverInfo.ErrorMsg = fmt.Sprintf("%s%s endpoint is not available", constants.RoutePrefix, constants.ExtMgmt)
|
|
case errors.Is(err, zerr.ErrUnauthorizedAccess):
|
|
serverInfo.Status = StatusOnline
|
|
serverInfo.ErrorMsg = fmt.Sprintf("unauthorised access, %s", getCredentialsSuggestion(username))
|
|
case errors.Is(err, zerr.ErrBadHTTPStatusCode):
|
|
serverInfo.Status = StatusOnline
|
|
serverInfo.ErrorMsg = fmt.Sprintf("%s: request at %s failed", zerr.ErrAPINotSupported.Error(),
|
|
checkAPISupportEndpoint)
|
|
default:
|
|
serverInfo.Status = StatusOffline
|
|
serverInfo.ErrorMsg = err.Error()
|
|
}
|
|
|
|
return PrintServerInfo(serverInfo, config)
|
|
}
|
|
|
|
func getCredentialsSuggestion(username string) string {
|
|
if username == "" {
|
|
return "endpoint requires valid user credentials (add the flag '--user [user]:[password]')"
|
|
}
|
|
|
|
return "given credentials are invalid"
|
|
}
|
|
|
|
func PrintServerInfo(serverInfo ServerInfo, config SearchConfig) error {
|
|
outputResult, err := serverInfo.ToStringFormat(config.OutputFormat)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Fprintln(config.ResultWriter, outputResult)
|
|
|
|
return nil
|
|
}
|
|
|
|
type ServerInfo struct {
|
|
Status string `json:"status,omitempty" mapstructure:"status"`
|
|
ErrorMsg string `json:"error,omitempty" mapstructure:"error"`
|
|
DistSpecVersion string `json:"distSpecVersion,omitempty" mapstructure:"distSpecVersion"`
|
|
Commit string `json:"commit,omitempty" mapstructure:"commit"`
|
|
BinaryType string `json:"binaryType,omitempty" mapstructure:"binaryType"`
|
|
ReleaseTag string `json:"releaseTag,omitempty" mapstructure:"releaseTag"`
|
|
}
|
|
|
|
func (si *ServerInfo) ToStringFormat(format string) (string, error) {
|
|
switch format {
|
|
case "text", "":
|
|
return si.ToText()
|
|
case "json":
|
|
return si.ToJSON()
|
|
case "yaml", "yml":
|
|
return si.ToYAML()
|
|
default:
|
|
return "", zerr.ErrFormatNotSupported
|
|
}
|
|
}
|
|
|
|
func (si *ServerInfo) ToText() (string, error) {
|
|
flagsList := strings.Split(strings.Trim(si.BinaryType, "-"), "-")
|
|
flags := strings.Join(flagsList, ", ")
|
|
|
|
var output string
|
|
|
|
if si.ErrorMsg != "" {
|
|
serverStatus := fmt.Sprintf("Server Status: %s\n"+
|
|
"Error: %s", si.Status, si.ErrorMsg)
|
|
|
|
output = serverStatus
|
|
} else {
|
|
serverStatus := fmt.Sprintf("Server Status: %s", si.Status)
|
|
serverInfo := fmt.Sprintf("Server Version: %s\n"+
|
|
"Dist Spec Version: %s\n"+
|
|
"Built with: %s",
|
|
si.ReleaseTag, si.DistSpecVersion, flags,
|
|
)
|
|
|
|
output = serverStatus + "\n" + serverInfo
|
|
}
|
|
|
|
return output, nil
|
|
}
|
|
|
|
func (si *ServerInfo) ToJSON() (string, error) {
|
|
blob, err := json.MarshalIndent(*si, "", " ")
|
|
|
|
return string(blob), err
|
|
}
|
|
|
|
func (si *ServerInfo) ToYAML() (string, error) {
|
|
body, err := yaml.Marshal(*si)
|
|
|
|
return string(body), err
|
|
}
|