Add api to get namespaces of registry

To query the namespace of the registry according to its ID.

Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
wang yan 2019-04-11 23:13:51 +08:00
parent 68342c68bc
commit 117c36d52c
5 changed files with 154 additions and 7 deletions

View File

@ -2291,6 +2291,39 @@ paths:
description: Registry not found
'500':
description: Unexpected internal errors.
/registries/{id}/namespace:
get:
summary: List namespaces of registry
description: |
This endpoint let user list namespaces of registry according to query.
parameters:
- name: id
in: query
type: integer
required: true
description: The registry ID.
- name: name
in: query
type: string
required: false
description: The name of namespace.
tags:
- Products
responses:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Namespace'
'401':
description: User need to login first.
'404':
description: No registry found.
'403':
description: User has no privilege for the operation.
'500':
description: Unexpected internal errors.
/internal/syncregistry:
post:
summary: Sync repositories from registry to DB.
@ -4965,4 +4998,14 @@ definitions:
description: The start time
end_time:
type: string
description: The end time
description: The end time
Namespace:
type: object
description: The namespace of registry
properties:
name:
type: string
description: The name of namespace
metadata:
type: object
description: The metadata of namespace

View File

@ -321,6 +321,60 @@ func (t *RegistryAPI) GetInfo() {
t.WriteJSONData(process(info))
}
// GetNamespace get the namespace of a registry
func (t *RegistryAPI) GetNamespace() {
var registry *model.Registry
var err error
id, err := t.GetInt64FromPath(":id")
if err != nil || id < 0 {
t.HandleBadRequest(fmt.Sprintf("invalid registry ID %s", t.GetString(":id")))
return
}
if id > 0 {
registry, err = t.manager.Get(id)
if err != nil {
t.HandleInternalServerError(fmt.Sprintf("failed to get registry %d: %v", id, err))
return
}
} else if id == 0 {
registry = event.GetLocalRegistry()
}
if registry == nil {
t.HandleNotFound(fmt.Sprintf("registry %d not found", id))
return
}
if !adapter.HasFactory(registry.Type) {
t.HandleInternalServerError(fmt.Sprintf("no adapter factory found for %s", registry.Type))
return
}
regFactory, err := adapter.GetFactory(registry.Type)
if err != nil {
t.HandleInternalServerError(fmt.Sprintf("fail to get adapter factory %s", registry.Type))
return
}
regAdapter, err := regFactory(registry)
if err != nil {
t.HandleInternalServerError(fmt.Sprintf("fail to get adapter %s", registry.Type))
return
}
query := &model.NamespaceQuery{
Name: t.GetString("name"),
}
npResults, err := regAdapter.ListNamespaces(query)
if err != nil {
t.HandleInternalServerError(fmt.Sprintf("fail to list namespaces %s %v", registry.Type, err))
return
}
t.Data["json"] = npResults
t.ServeJSON()
}
// merge "SupportedResourceTypes" into "SupportedResourceFilters" for UI to render easier
func process(info *model.RegistryInfo) *model.RegistryInfo {
if info == nil {

View File

@ -135,6 +135,7 @@ func initRouters() {
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")
beego.Router("/api/registries/:id/namespace", &api.RegistryAPI{}, "get:GetNamespace")
beego.Router("/v2/*", &controllers.RegistryProxy{}, "*:Handle")

View File

@ -125,10 +125,24 @@ func (a *adapter) Info() (*model.RegistryInfo, error) {
return info, nil
}
// TODO implement the function
func (a *adapter) ListNamespaces(*model.NamespaceQuery) ([]*model.Namespace, error) {
return nil, nil
func (a *adapter) ListNamespaces(npQuery *model.NamespaceQuery) ([]*model.Namespace, error) {
var nps []*model.Namespace
projects, err := a.getProjects(npQuery.Name)
if err != nil {
return nil, err
}
for _, pro := range projects {
nps = append(nps, &model.Namespace{
Name: pro.Name,
Metadata: pro.Metadata,
})
}
return nps, nil
}
func (a *adapter) ConvertResourceMetadata(metadata *model.ResourceMetadata, namespace *model.Namespace) (*model.ResourceMetadata, error) {
if metadata == nil {
return nil, errors.New("the metadata cannot be null")
@ -237,13 +251,21 @@ type project struct {
Metadata map[string]interface{} `json:"metadata"`
}
func (a *adapter) getProject(name string) (*project, error) {
// TODO need an API to exact match project by name
func (a *adapter) getProjects(name string) ([]*project, error) {
projects := []*project{}
url := fmt.Sprintf("%s/api/projects?name=%s&page=1&page_size=1000", a.coreServiceURL, name)
if err := a.client.Get(url, &projects); err != nil {
return nil, err
}
return projects, nil
}
func (a *adapter) getProject(name string) (*project, error) {
// TODO need an API to exact match project by name
projects, err := a.getProjects(name)
if err != nil {
return nil, err
}
for _, pro := range projects {
if pro.Name == name {

View File

@ -72,7 +72,34 @@ func TestInfo(t *testing.T) {
}
func TestListNamespaces(t *testing.T) {
// TODO
// project exists
server := test.NewServer(&test.RequestHandlerMapping{
Method: http.MethodGet,
Pattern: "/api/projects",
Handler: func(w http.ResponseWriter, r *http.Request) {
data := `[{
"name": "library",
"metadata": {"public":true}
},{
"name": "library1",
"metadata": {"public":true}
}]`
w.Write([]byte(data))
},
})
defer server.Close()
registry := &model.Registry{
URL: server.URL,
}
adapter := newAdapter(registry)
npQuery := &model.NamespaceQuery{
Name: "lib",
}
namespace, err := adapter.ListNamespaces(npQuery)
require.Nil(t, err)
assert.Equal(t, 2, len(namespace))
assert.Equal(t, "library", namespace[0].Name)
assert.True(t, namespace[0].Metadata["public"].(bool))
}
func TestPrepareForPush(t *testing.T) {