Add registry ping API

Signed-off-by: cd1989 <chende@caicloud.io>
This commit is contained in:
cd1989 2019-04-03 19:20:31 +08:00
parent bfc41addb0
commit f71a110bec
6 changed files with 116 additions and 3 deletions

View File

@ -2160,6 +2160,33 @@ paths:
$ref: '#/responses/UnsupportedMediaType'
'500':
description: Unexpected internal errors.
/registries/ping:
post:
summary: Ping status of a registry.
description: |
This endpoint checks status of a registry, the registry can be given by ID or URL (together with credential)
parameters:
- name: registry
in: body
description: Registry to ping.
required: true
schema:
$ref: '#/definitions/Registry'
tags:
- Products
responses:
'200':
description: Registry is healthy.
'400':
description: No proper registry information provided.
'401':
description: User need to log in first.
'404':
description: Registry not found (when registry is provided by ID).
'415':
$ref: '#/responses/UnsupportedMediaType'
'500':
description: Unexpected internal errors.
'/registries/{id}':
put:
summary: Update a given registry.

View File

@ -124,6 +124,7 @@ func init() {
beego.Router("/api/repositories/*/signatures", &RepositoryAPI{}, "get:GetSignatures")
beego.Router("/api/repositories/top", &RepositoryAPI{}, "get:GetTopRepos")
beego.Router("/api/registries", &RegistryAPI{}, "get:List;post:Post")
beego.Router("/api/registries/ping", &RegistryAPI{}, "post:Ping")
beego.Router("/api/registries/:id([0-9]+)", &RegistryAPI{}, "get:Get;put:Put;delete:Delete")
beego.Router("/api/systeminfo", &SystemInfoAPI{}, "get:GetGeneralInfo")
beego.Router("/api/systeminfo/volumes", &SystemInfoAPI{}, "get:GetVolumeInfo")
@ -1175,6 +1176,12 @@ func (a testapi) RegistryCreate(authInfo usrInfo, registry *model.Registry) (int
return code, err
}
func (a testapi) RegistryPing(authInfo usrInfo, registry *model.Registry) (int, error) {
_sling := sling.New().Base(a.basePath).Post("/api/registries/ping").BodyJSON(registry)
code, _, err := request(_sling, jsonAcceptHeader, authInfo)
return code, err
}
func (a testapi) RegistryDelete(authInfo usrInfo, registryID int64) (int, error) {
_sling := sling.New().Base(a.basePath).Delete(fmt.Sprintf("/api/registries/%d", registryID))
code, _, err := request(_sling, jsonAcceptHeader, authInfo)

View File

@ -40,6 +40,44 @@ func (t *RegistryAPI) Prepare() {
t.policyCtl = ng.PolicyCtl
}
// Ping checks health status of a registry
func (t *RegistryAPI) Ping() {
r := &model.Registry{}
t.DecodeJSONReqAndValidate(r)
var err error
id := r.ID
if id != 0 {
r, err = t.manager.Get(id)
if err != nil {
log.Errorf("failed to get registry %s: %v", r.Name, err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
return
}
if r == nil {
t.CustomAbort(http.StatusNotFound, fmt.Sprintf("Registry %d not found", id))
return
}
}
if len(r.URL) == 0 || r.Credential == nil {
t.CustomAbort(http.StatusBadRequest, "URL or credential emptry")
return
}
status, err := registry.CheckHealthStatus(r)
if err != nil {
t.CustomAbort(http.StatusInternalServerError, fmt.Sprintf("Ping registry %s error: %v", r.URL, err))
return
}
if status != registry.Healthy {
t.CustomAbort(http.StatusBadRequest, fmt.Sprintf("Ping registry %d failed", r.ID))
}
return
}
// Get gets a registry by id.
func (t *RegistryAPI) Get() {
id := t.GetIDFromURL()

View File

@ -117,6 +117,45 @@ func (suite *RegistrySuite) TestPost() {
assert.Equal(http.StatusForbidden, code)
}
func (suite *RegistrySuite) TestPing() {
assert := assert.New(suite.T())
code, err := suite.testAPI.RegistryPing(*admin, &model.Registry{
ID: suite.defaultRegistry.ID,
})
assert.Nil(err)
assert.Equal(http.StatusInternalServerError, code)
code, err = suite.testAPI.RegistryPing(*admin, &model.Registry{
ID: -1,
})
assert.Nil(err)
assert.Equal(http.StatusNotFound, code)
code, err = suite.testAPI.RegistryPing(*admin, &model.Registry{
URL: "http://foo.bar",
})
assert.Nil(err)
assert.Equal(http.StatusBadRequest, code)
code, err = suite.testAPI.RegistryPing(*admin, &model.Registry{
URL: "http://foo.bar",
Credential: &model.Credential{
Type: model.CredentialTypeBasic,
AccessKey: "admin",
AccessSecret: "Harbor12345",
},
})
assert.Nil(err)
assert.NotEqual(http.StatusBadRequest, code)
code, err = suite.testAPI.RegistryPing(*testUser, &model.Registry{
ID: suite.defaultRegistry.ID,
})
assert.Nil(err)
assert.Equal(http.StatusForbidden, code)
}
func (suite *RegistrySuite) TestRegistryPut() {
assert := assert.New(suite.T())

View File

@ -132,6 +132,7 @@ func initRouters() {
beego.Router("/api/registries", &api.RegistryAPI{}, "get:List;post:Post")
beego.Router("/api/registries/:id([0-9]+)", &api.RegistryAPI{}, "get:Get;put:Put;delete:Delete")
beego.Router("/api/registries/ping", &api.RegistryAPI{}, "post:Ping")
// we use "0" as the ID of the local Harbor registry, so don't add "([0-9]+)" in the path
beego.Router("/api/registries/:id/info", &api.RegistryAPI{}, "get:GetInfo")

View File

@ -183,7 +183,7 @@ func (m *DefaultManager) HealthCheck() error {
errCount := 0
for _, r := range registries {
status, err := healthStatus(r)
status, err := CheckHealthStatus(r)
if err != nil {
log.Warningf("Check health status for %s error: %v", r.URL, err)
}
@ -202,7 +202,8 @@ func (m *DefaultManager) HealthCheck() error {
return nil
}
func healthStatus(r *model.Registry) (HealthStatus, error) {
// CheckHealthStatus checks status of a given registry
func CheckHealthStatus(r *model.Registry) (HealthStatus, error) {
// TODO(ChenDe): Support other credential type like OAuth, for the moment, only basic auth is supported.
if r.Credential.Type != model.CredentialTypeBasic {
return Unknown, fmt.Errorf("unknown credential type '%s', only '%s' supported yet", r.Credential.Type, model.CredentialTypeBasic)
@ -210,7 +211,7 @@ func healthStatus(r *model.Registry) (HealthStatus, error) {
// TODO(ChenDe): Support health check for other kinds of registry
if r.Type != model.RegistryTypeHarbor {
return Unknown, fmt.Errorf("unknown registry type '%s'", model.RegistryTypeHarbor)
return Unknown, fmt.Errorf("unknown registry type '%s'", r.Type)
}
transport := util.GetHTTPTransport(r.Insecure)