diff --git a/.gitignore b/.gitignore index 20992c591..d79e11032 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,8 @@ src/ui_ng/typings/ **/*yarn-error.log.* .idea/ .DS_Store +.project +.vscode/ **/node_modules **/ssl/ **/proxy.config.json diff --git a/src/adminserver/api/monitor.go b/src/adminserver/api/monitor.go new file mode 100644 index 000000000..fa37f325d --- /dev/null +++ b/src/adminserver/api/monitor.go @@ -0,0 +1,14 @@ +package api + +import ( + "net/http" + "github.com/vmware/harbor/src/common/utils/log" +) + +// Ping monitor the server status +func Ping(w http.ResponseWriter, r *http.Request) { + if err := writeJSON(w, "Pong"); err != nil { + log.Errorf("Failed to write response: %v", err) + return + } +} diff --git a/src/adminserver/api/monitor_test.go b/src/adminserver/api/monitor_test.go new file mode 100644 index 000000000..d7536ce52 --- /dev/null +++ b/src/adminserver/api/monitor_test.go @@ -0,0 +1,16 @@ +package api +import( + "testing" + "net/http/httptest" + "net/http" + "github.com/stretchr/testify/assert" + "io/ioutil" +) + +func TestPing(t *testing.T) { + w := httptest.NewRecorder() + Ping(w, nil) + assert.Equal(t, http.StatusOK, w.Code) + result, _:= ioutil.ReadAll(w.Body) + assert.Equal(t, "\"Pong\"", string(result)) +} diff --git a/src/adminserver/handlers/handler.go b/src/adminserver/handlers/handler.go index 014893dff..b071f40f4 100644 --- a/src/adminserver/handlers/handler.go +++ b/src/adminserver/handlers/handler.go @@ -31,7 +31,10 @@ func NewHandler() http.Handler { "uiSecret": os.Getenv("UI_SECRET"), "jobserviceSecret": os.Getenv("JOBSERVICE_SECRET"), } - h = newAuthHandler(auth.NewSecretAuthenticator(secrets), h) + insecureAPIs := map[string]bool{ + "/api/ping":true, + } + h = newAuthHandler(auth.NewSecretAuthenticator(secrets), h, insecureAPIs) h = gorilla_handlers.LoggingHandler(os.Stdout, h) return h } @@ -39,12 +42,14 @@ func NewHandler() http.Handler { type authHandler struct { authenticator auth.Authenticator handler http.Handler + insecureAPIs map[string]bool } -func newAuthHandler(authenticator auth.Authenticator, handler http.Handler) http.Handler { +func newAuthHandler(authenticator auth.Authenticator, handler http.Handler, insecureAPIs map[string]bool) http.Handler { return &authHandler{ authenticator: authenticator, handler: handler, + insecureAPIs: insecureAPIs, } } @@ -56,6 +61,12 @@ func (a *authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + if a.insecureAPIs !=nil && a.insecureAPIs[r.URL.Path] { + if a.handler != nil { + a.handler.ServeHTTP(w, r) + } + return + } valid, err := a.authenticator.Authenticate(r) if err != nil { log.Errorf("failed to authenticate request: %v", err) diff --git a/src/adminserver/handlers/handlers_test.go b/src/adminserver/handlers/handlers_test.go index 2ccd46d9e..af273bb88 100644 --- a/src/adminserver/handlers/handlers_test.go +++ b/src/adminserver/handlers/handlers_test.go @@ -45,28 +45,40 @@ func TestNewAuthHandler(t *testing.T) { cases := []struct { authenticator auth.Authenticator handler http.Handler + insecureAPIs map[string]bool responseCode int + requestURL string }{ - {nil, nil, http.StatusOK}, + {nil, nil, nil, http.StatusOK,"http://localhost/good"}, {&fakeAuthenticator{ authenticated: false, err: nil, - }, nil, http.StatusUnauthorized}, + }, nil, nil, http.StatusUnauthorized,"http://localhost/hello"}, {&fakeAuthenticator{ authenticated: false, err: errors.New("error"), - }, nil, http.StatusInternalServerError}, + }, nil, nil, http.StatusInternalServerError,"http://localhost/hello"}, {&fakeAuthenticator{ authenticated: true, err: nil, - }, &fakeHandler{http.StatusNotFound}, http.StatusNotFound}, + }, &fakeHandler{http.StatusNotFound}, nil, http.StatusNotFound,"http://localhost/notexsit"}, + {&fakeAuthenticator{ + authenticated: false, + err: nil, + }, &fakeHandler{http.StatusOK},map[string]bool{"/api/ping":true,},http.StatusOK,"http://localhost/api/ping"}, } for _, c := range cases { - handler := newAuthHandler(c.authenticator, c.handler) + handler := newAuthHandler(c.authenticator, c.handler, c.insecureAPIs) w := httptest.NewRecorder() - handler.ServeHTTP(w, nil) + r := httptest.NewRequest("GET",c.requestURL,nil) + handler.ServeHTTP(w, r) assert.Equal(t, c.responseCode, w.Code, "unexpected response code") } + handler := NewHandler() + w := httptest.NewRecorder() + r := httptest.NewRequest("GET","http://localhost/api/ping",nil) + handler.ServeHTTP(w,r) + } diff --git a/src/adminserver/handlers/router.go b/src/adminserver/handlers/router.go index 93c3bc5be..df11e8ac2 100644 --- a/src/adminserver/handlers/router.go +++ b/src/adminserver/handlers/router.go @@ -27,5 +27,6 @@ func newRouter() http.Handler { r.HandleFunc("/api/configurations", api.UpdateCfgs).Methods("PUT") r.HandleFunc("/api/configurations/reset", api.ResetCfgs).Methods("POST") r.HandleFunc("/api/systeminfo/capacity", api.Capacity).Methods("GET") + r.HandleFunc("/api/ping", api.Ping).Methods("GET") return r } diff --git a/src/ui/api/harborapi_test.go b/src/ui/api/harborapi_test.go index f108aed23..df8538b86 100644 --- a/src/ui/api/harborapi_test.go +++ b/src/ui/api/harborapi_test.go @@ -138,7 +138,7 @@ func init() { beego.Router("/api/replications", &ReplicationAPI{}) beego.Router("/api/labels", &LabelAPI{}, "post:Post;get:List") beego.Router("/api/labels/:id([0-9]+", &LabelAPI{}, "get:Get;put:Put;delete:Delete") - + beego.Router("/api/ping", &SystemInfoAPI{}, "get:Ping") _ = updateInitPassword(1, "Harbor12345") if err := core.Init(); err != nil { @@ -991,6 +991,11 @@ func (a testapi) GetGeneralInfo() (int, []byte, error) { return request(_sling, jsonAcceptHeader) } +func (a testapi) Ping() (int, []byte, error) { + _sling := sling.New().Get(a.basePath).Path("/api/ping") + return request(_sling, jsonAcceptHeader) +} + //Get system cert func (a testapi) CertGet(authInfo usrInfo) (int, []byte, error) { _sling := sling.New().Get(a.basePath) diff --git a/src/ui/api/systeminfo.go b/src/ui/api/systeminfo.go index 18e37013b..4974ffdbd 100644 --- a/src/ui/api/systeminfo.go +++ b/src/ui/api/systeminfo.go @@ -247,3 +247,9 @@ func getClairVulnStatus() *models.ClairVulnerabilityStatus { res.Details = details return res } + +// Ping ping the harbor UI service. +func (sia *SystemInfoAPI) Ping() { + sia.Data["json"] = "Pong" + sia.ServeJSON() +} diff --git a/src/ui/api/systeminfo_test.go b/src/ui/api/systeminfo_test.go index 2f3bfce5a..edcc8c157 100644 --- a/src/ui/api/systeminfo_test.go +++ b/src/ui/api/systeminfo_test.go @@ -91,3 +91,10 @@ func TestGetCert(t *testing.T) { } CommonDelUser() } +func TestPing(t *testing.T) { + apiTest := newHarborAPI() + code, _, err := apiTest.Ping() + assert := assert.New(t) + assert.Nil(err, fmt.Sprintf("Unexpected Error: %v", err)) + assert.Equal(200, code, fmt.Sprintf("Unexpected status code: %d", code)) +} diff --git a/src/ui/router.go b/src/ui/router.go index d6a722d6a..59a0b6288 100644 --- a/src/ui/router.go +++ b/src/ui/router.go @@ -60,6 +60,7 @@ func initRouters() { } // API + beego.Router("/api/ping", &api.SystemInfoAPI{}, "get:Ping") beego.Router("/api/search", &api.SearchAPI{}) beego.Router("/api/projects/", &api.ProjectAPI{}, "get:List;post:Post") beego.Router("/api/projects/:id([0-9]+)/logs", &api.ProjectAPI{}, "get:Logs") @@ -114,6 +115,7 @@ func initRouters() { beego.Router("/service/token", &token.Handler{}) beego.Router("/registryproxy/*", &controllers.RegistryProxy{}, "*:Handle") + //Error pages beego.ErrorController(&controllers.ErrorController{})