Merge pull request #11360 from ninjadq/rever_chart_api_change

Rever chart api change
This commit is contained in:
Qian Deng 2020-04-01 18:58:57 +08:00 committed by GitHub
commit b1284da96b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 104 additions and 105 deletions

View File

@ -9,7 +9,6 @@ import (
"strings"
"github.com/ghodss/yaml"
"github.com/goharbor/harbor/src/common/api"
commonhttp "github.com/goharbor/harbor/src/common/http"
"github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/replication"
@ -70,7 +69,7 @@ func (c *Controller) DeleteChartVersion(namespace, chartName, version string) er
return errors.New("invalid chart for deleting")
}
url := fmt.Sprintf("/api/%s/chartrepo/%s/charts/%s/%s", api.APIVersion, namespace, chartName, version)
url := fmt.Sprintf("/api/chartrepo/%s/charts/%s/%s", namespace, chartName, version)
req, _ := http.NewRequest(http.MethodDelete, url, nil)
w := httptest.NewRecorder()

View File

@ -10,7 +10,6 @@ import (
"testing"
"github.com/ghodss/yaml"
"github.com/goharbor/harbor/src/common/api"
htesting "github.com/goharbor/harbor/src/testing"
helm_repo "k8s.io/helm/pkg/repo"
)
@ -37,7 +36,7 @@ func TestStartMockServers(t *testing.T) {
// Test /health
func TestGetHealthOfBaseHandler(t *testing.T) {
content, err := httpClient.GetContent(fmt.Sprintf("%s/api/%s/chartrepo/health", frontServer.URL, api.APIVersion))
content, err := httpClient.GetContent(fmt.Sprintf("%s/api/chartrepo/health", frontServer.URL))
if err != nil {
t.Fatal(err)
}

View File

@ -4,7 +4,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/goharbor/harbor/src/controller/event/metadata"
"io/ioutil"
"log"
"net/http"
@ -16,9 +15,9 @@ import (
"time"
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/api"
commonhttp "github.com/goharbor/harbor/src/common/http"
hlog "github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/controller/event/metadata"
n_event "github.com/goharbor/harbor/src/pkg/notifier/event"
"github.com/goharbor/harbor/src/replication"
rep_event "github.com/goharbor/harbor/src/replication/event"
@ -27,15 +26,11 @@ import (
const (
agentHarbor = "HARBOR"
contentLengthHeader = "Content-Length"
)
var (
defaultRepo = "library"
chartRepoAPIPrefix = fmt.Sprintf("/api/%s/chartrepo", api.APIVersion)
rootUploadingEndpoint = fmt.Sprintf("/api/%s/chartrepo/charts", api.APIVersion)
chartRepoHealthEndpoint = fmt.Sprintf("/api/%s/chartrepo/health", api.APIVersion)
chartRepoPrefix = "/chartrepo"
defaultRepo = "library"
rootUploadingEndpoint = "/api/chartrepo/charts"
rootIndexEndpoint = "/chartrepo/index.yaml"
chartRepoHealthEndpoint = "/api/chartrepo/health"
)
// ProxyEngine is used to proxy the related traffics
@ -229,19 +224,19 @@ func rewriteURLPath(req *http.Request) {
// Root uploading endpoint
if incomingURLPath == rootUploadingEndpoint {
req.URL.Path = strings.Replace(incomingURLPath, fmt.Sprintf("%s/chartrepo", api.APIVersion), defaultRepo, 1)
req.URL.Path = strings.Replace(incomingURLPath, "chartrepo", defaultRepo, 1)
return
}
// Repository endpoints
if strings.HasPrefix(incomingURLPath, chartRepoPrefix) {
if strings.HasPrefix(incomingURLPath, "/chartrepo") {
req.URL.Path = strings.TrimPrefix(incomingURLPath, "/chartrepo")
return
}
// API endpoints
if strings.HasPrefix(incomingURLPath, chartRepoAPIPrefix) {
req.URL.Path = strings.Replace(incomingURLPath, fmt.Sprintf("/%s/chartrepo", api.APIVersion), "", 1)
if strings.HasPrefix(incomingURLPath, "/api/chartrepo") {
req.URL.Path = strings.Replace(incomingURLPath, "/chartrepo", "", 1)
return
}
}

View File

@ -1,16 +1,13 @@
package chartserver
import (
"fmt"
"net/http"
"testing"
"github.com/goharbor/harbor/src/common/api"
)
// Test the URL rewrite function
func TestURLRewrite(t *testing.T) {
req, err := createRequest(http.MethodGet, fmt.Sprintf("/api/%s/chartrepo/health", api.APIVersion))
req, err := createRequest(http.MethodGet, "/api/chartrepo/health")
if err != nil {
t.Fatal(err)
}
@ -19,7 +16,7 @@ func TestURLRewrite(t *testing.T) {
t.Fatalf("Expect url format %s but got %s", "/health", req.URL.Path)
}
req, err = createRequest(http.MethodGet, fmt.Sprintf("/api/%s/chartrepo/library/charts", api.APIVersion))
req, err = createRequest(http.MethodGet, "/api/chartrepo/library/charts")
if err != nil {
t.Fatal(err)
}
@ -28,7 +25,7 @@ func TestURLRewrite(t *testing.T) {
t.Fatalf("Expect url format %s but got %s", "/api/library/charts", req.URL.Path)
}
req, err = createRequest(http.MethodPost, fmt.Sprintf("/api/%s/chartrepo/charts", api.APIVersion))
req, err = createRequest(http.MethodPost, "/api/chartrepo/charts")
if err != nil {
t.Fatal(err)
}

View File

@ -5,7 +5,6 @@ import (
"context"
"errors"
"fmt"
"github.com/goharbor/harbor/src/controller/event/metadata"
"io"
"io/ioutil"
"mime/multipart"
@ -17,9 +16,10 @@ import (
"strings"
"time"
"github.com/goharbor/harbor/src/controller/event/metadata"
"github.com/goharbor/harbor/src/chartserver"
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/api"
"github.com/goharbor/harbor/src/common/rbac"
hlog "github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/config"
@ -33,9 +33,13 @@ import (
)
const (
namespaceParam = ":repo"
nameParam = ":name"
filenameParam = ":filename"
namespaceParam = ":repo"
nameParam = ":name"
filenameParam = ":filename"
defaultRepo = "library"
rootUploadingEndpoint = "/api/chartrepo/charts"
rootIndexEndpoint = "/chartrepo/index.yaml"
chartRepoHealthEndpoint = "/api/chartrepo/health"
accessLevelPublic = iota
accessLevelRead
@ -51,13 +55,6 @@ const (
chartPackageFileExtension = "tgz"
)
var (
defaultRepo = "library"
rootUploadingEndpoint = fmt.Sprintf("/api/%s/chartrepo/charts", api.APIVersion)
chartRepoHealthEndpoint = fmt.Sprintf("/api/%s/chartrepo/health", api.APIVersion)
rootIndexEndpoint = "/chartrepo/index.yaml"
)
// chartController is a singleton instance
var chartController *chartserver.Controller
@ -116,7 +113,7 @@ func (cra *ChartRepositoryAPI) requireAccess(action rbac.Action, subresource ...
return cra.RequireProjectAccess(cra.namespace, action, subresource...)
}
// GetHealthStatus handles GET /chartrepo/health
// GetHealthStatus handles GET /api/chartrepo/health
func (cra *ChartRepositoryAPI) GetHealthStatus() {
// Check access
if !cra.SecurityCtx.IsAuthenticated() {
@ -606,7 +603,7 @@ func initializeChartController() (*chartserver.Controller, error) {
return nil, errors.New("Endpoint URL of chart storage server is malformed")
}
chartVersionURL := fmt.Sprintf(`^/api/%s/chartrepo/(?P<namespace>[^?#]+)/charts/(?P<name>[^?#]+)/(?P<version>[^?#]+)/?$`, api.APIVersion)
chartVersionURL := fmt.Sprintf(`^/api/chartrepo/(?P<namespace>[^?#]+)/charts/(?P<name>[^?#]+)/(?P<version>[^?#]+)/?$`)
skipper := middleware.NegativeSkipper(middleware.MethodAndPathSkipper(http.MethodDelete, regexp.MustCompile(chartVersionURL)))
controller, err := chartserver.NewController(url, orm.Middleware(), quota.UploadChartVersionMiddleware(), quota.RefreshForProjectMiddleware(skipper))

View File

@ -2,13 +2,11 @@ package api
import (
"errors"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/goharbor/harbor/src/chartserver"
"github.com/goharbor/harbor/src/common/api"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/core/promgr/metamgr"
)
@ -19,7 +17,7 @@ var (
)
func TestIsMultipartFormData(t *testing.T) {
req, err := createRequest(http.MethodPost, fmt.Sprintf("/api/%s/chartrepo/charts", api.APIVersion))
req, err := createRequest(http.MethodPost, "/api/chartrepo/charts")
if err != nil {
t.Fatal(err)
}
@ -57,7 +55,7 @@ func TestPrepareEnv(t *testing.T) {
func TestGetHealthStatus(t *testing.T) {
status := make(map[string]interface{})
err := handleAndParse(&testingRequest{
url: fmt.Sprintf("/api/%s/chartrepo/health", api.APIVersion),
url: "/api/chartrepo/health",
method: http.MethodGet,
credential: sysAdmin,
}, &status)
@ -111,7 +109,7 @@ func TestDownloadChart(t *testing.T) {
func TesListCharts(t *testing.T) {
charts := make([]*chartserver.ChartInfo, 0)
err := handleAndParse(&testingRequest{
url: fmt.Sprintf("/api/%s/chartrepo/library/charts", api.APIVersion),
url: "/api/chartrepo/library/charts",
method: http.MethodGet,
credential: projAdmin,
}, &charts)
@ -129,7 +127,7 @@ func TesListCharts(t *testing.T) {
func TestListChartVersions(t *testing.T) {
chartVersions := make(chartserver.ChartVersions, 0)
err := handleAndParse(&testingRequest{
url: fmt.Sprintf("/api/%s/chartrepo/library/charts/harbor", api.APIVersion),
url: "/api/chartrepo/library/charts/harbor",
method: http.MethodGet,
credential: projAdmin,
}, &chartVersions)
@ -147,7 +145,7 @@ func TestListChartVersions(t *testing.T) {
func TestGetChartVersion(t *testing.T) {
chartV := &chartserver.ChartVersionDetails{}
err := handleAndParse(&testingRequest{
url: fmt.Sprintf("/api/%s/chartrepo/library/charts/harbor/0.2.0", api.APIVersion),
url: "/api/chartrepo/library/charts/harbor/0.2.0",
method: http.MethodGet,
credential: projAdmin,
}, chartV)
@ -169,7 +167,7 @@ func TestGetChartVersion(t *testing.T) {
func TestDeleteChartVersion(t *testing.T) {
runCodeCheckingCases(t, &codeCheckingCase{
request: &testingRequest{
url: fmt.Sprintf("/api/%s/chartrepo/library/charts/harbor/0.2.1", api.APIVersion),
url: "/api/chartrepo/library/charts/harbor/0.2.1",
method: http.MethodDelete,
credential: projAdmin,
},
@ -181,7 +179,7 @@ func TestDeleteChartVersion(t *testing.T) {
func TestDeleteChart(t *testing.T) {
runCodeCheckingCases(t, &codeCheckingCase{
request: &testingRequest{
url: fmt.Sprintf("/api/%s/chartrepo/library/charts/harbor", api.APIVersion),
url: "/api/chartrepo/library/charts/harbor",
method: http.MethodDelete,
credential: projAdmin,
},

View File

@ -19,7 +19,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/goharbor/harbor/src/server/middleware/security"
"io/ioutil"
"log"
"net/http"
@ -29,6 +28,8 @@ import (
"strconv"
"strings"
"github.com/goharbor/harbor/src/server/middleware/security"
"github.com/astaxie/beego"
"github.com/dghubble/sling"
"github.com/goharbor/harbor/src/common/api"
@ -166,15 +167,15 @@ func init() {
beego.Router("/api/projects/:pid([0-9]+)/immutabletagrules/:id([0-9]+)", &ImmutableTagRuleAPI{})
// Charts are controlled under projects
chartRepositoryAPIType := &ChartRepositoryAPI{}
beego.Router("/api/"+api.APIVersion+"/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus")
beego.Router("/api/"+api.APIVersion+"/chartrepo/:repo/charts", chartRepositoryAPIType, "get:ListCharts")
beego.Router("/api/"+api.APIVersion+"/chartrepo/:repo/charts/:name", chartRepositoryAPIType, "get:ListChartVersions")
beego.Router("/api/"+api.APIVersion+"/chartrepo/:repo/charts/:name", chartRepositoryAPIType, "delete:DeleteChart")
beego.Router("/api/"+api.APIVersion+"/chartrepo/:repo/charts/:name/:version", chartRepositoryAPIType, "get:GetChartVersion")
beego.Router("/api/"+api.APIVersion+"/chartrepo/:repo/charts/:name/:version", chartRepositoryAPIType, "delete:DeleteChartVersion")
beego.Router("/api/"+api.APIVersion+"/chartrepo/:repo/charts", chartRepositoryAPIType, "post:UploadChartVersion")
beego.Router("/api/"+api.APIVersion+"/chartrepo/:repo/prov", chartRepositoryAPIType, "post:UploadChartProvFile")
beego.Router("/api/"+api.APIVersion+"/chartrepo/charts", chartRepositoryAPIType, "post:UploadChartVersion")
beego.Router("/api/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus")
beego.Router("/api/chartrepo/:repo/charts", chartRepositoryAPIType, "get:ListCharts")
beego.Router("/api/chartrepo/:repo/charts/:name", chartRepositoryAPIType, "get:ListChartVersions")
beego.Router("/api/chartrepo/:repo/charts/:name", chartRepositoryAPIType, "delete:DeleteChart")
beego.Router("/api/chartrepo/:repo/charts/:name/:version", chartRepositoryAPIType, "get:GetChartVersion")
beego.Router("/api/chartrepo/:repo/charts/:name/:version", chartRepositoryAPIType, "delete:DeleteChartVersion")
beego.Router("/api/chartrepo/:repo/charts", chartRepositoryAPIType, "post:UploadChartVersion")
beego.Router("/api/chartrepo/:repo/prov", chartRepositoryAPIType, "post:UploadChartProvFile")
beego.Router("/api/chartrepo/charts", chartRepositoryAPIType, "post:UploadChartVersion")
// Repository services
beego.Router("/chartrepo/:repo/index.yaml", chartRepositoryAPIType, "get:GetIndexByRepo")

View File

@ -18,11 +18,10 @@ import (
"fmt"
"github.com/goharbor/harbor/src/chartserver"
"github.com/goharbor/harbor/src/common/api"
)
func (c *client) ListAllCharts(project, repository string) ([]*chartserver.ChartVersion, error) {
url := c.buildURL(fmt.Sprintf("/api/%s/chartrepo/%s/charts/%s", api.APIVersion, project, repository))
url := c.buildURL(fmt.Sprintf("/api/chartrepo/%s/charts/%s", project, repository))
var charts []*chartserver.ChartVersion
if err := c.httpclient.Get(url, &charts); err != nil {
return nil, err
@ -31,11 +30,11 @@ func (c *client) ListAllCharts(project, repository string) ([]*chartserver.Chart
}
func (c *client) DeleteChart(project, repository, version string) error {
url := c.buildURL(fmt.Sprintf("/api/%s/chartrepo/%s/charts/%s/%s", api.APIVersion, project, repository, version))
url := c.buildURL(fmt.Sprintf("/api/chartrepo/%s/charts/%s/%s", project, repository, version))
return c.httpclient.Delete(url)
}
func (c *client) DeleteChartRepository(project, repository string) error {
url := c.buildURL(fmt.Sprintf("/api/%s/chartrepo/%s/charts/%s", api.APIVersion, project, repository))
url := c.buildURL(fmt.Sprintf("/api/chartrepo/%s/charts/%s", project, repository))
return c.httpclient.Delete(url)
}

View File

@ -46,7 +46,7 @@ import { ListChartVersionRoComponent } from "./list-chart-version-ro/list-chart-
import { IServiceConfig, SERVICE_CONFIG } from "../../lib/entities/service.config";
import { ErrorHandler } from "../../lib/utils/error-handler";
import { HarborLibraryModule } from "../../lib/harbor-library.module";
import { CURRENT_BASE_HREF } from "../../lib/utils/utils";
import { CURRENT_BASE_HREF, V1_BASE_HREF } from "../../lib/utils/utils";
const uiLibConfig: IServiceConfig = {
enablei18Support: true,
@ -67,8 +67,9 @@ const uiLibConfig: IServiceConfig = {
configurationEndpoint: CURRENT_BASE_HREF + "/configurations",
scanJobEndpoint: CURRENT_BASE_HREF + "/jobs/scan",
labelEndpoint: CURRENT_BASE_HREF + "/labels",
helmChartEndpoint: CURRENT_BASE_HREF + "/chartrepo",
helmChartEndpoint: V1_BASE_HREF + "/chartrepo",
downloadChartEndpoint: "/chartrepo",
helmChartLabelEndpoint: CURRENT_BASE_HREF + "/chartrepo",
gcEndpoint: CURRENT_BASE_HREF + "/system/gc",
ScanAllEndpoint: CURRENT_BASE_HREF + "/system/scanAll",
quotaUrl: CURRENT_BASE_HREF + "/quotas"

View File

@ -229,6 +229,8 @@ export interface IServiceConfig {
*/
downloadChartEndpoint?: string;
helmChartLabelEndpoint?: string;
gcEndpoint?: string;
ScanAllEndpoint?: string;

View File

@ -34,7 +34,7 @@ import {
ErrorHandler,
DefaultErrorHandler
} from './utils/error-handler';
import { DEFAULT_LANG_COOKIE_KEY, DEFAULT_SUPPORTING_LANGS, DEFAULT_LANG, CURRENT_BASE_HREF } from './utils/utils';
import { DEFAULT_LANG_COOKIE_KEY, DEFAULT_SUPPORTING_LANGS, DEFAULT_LANG, CURRENT_BASE_HREF, V1_BASE_HREF } from './utils/utils';
import { OperationService } from './components/operation/operation.service';
import { GcHistoryComponent } from "./components/config/gc/gc-history/gc-history.component";
import { GcComponent } from "./components/config/gc/gc.component";
@ -97,7 +97,8 @@ export const DefaultServiceConfig: IServiceConfig = {
configurationEndpoint: CURRENT_BASE_HREF + "/configurations",
scanJobEndpoint: CURRENT_BASE_HREF + "/jobs/scan",
labelEndpoint: CURRENT_BASE_HREF + "/labels",
helmChartEndpoint: CURRENT_BASE_HREF + "/chartrepo",
helmChartEndpoint: V1_BASE_HREF + "/chartrepo",
helmChartLabelEndpoint: CURRENT_BASE_HREF + "/chartrepo",
downloadChartEndpoint: "/chartrepo",
gcEndpoint: CURRENT_BASE_HREF + "/system/gc",
ScanAllEndpoint: CURRENT_BASE_HREF + "/system/scanAll"

View File

@ -6,7 +6,7 @@ import { RequestQueryParams } from "./RequestQueryParams";
import { Label } from "./interface";
import { IServiceConfig, SERVICE_CONFIG } from "../entities/service.config";
import { buildHttpRequestOptions, CURRENT_BASE_HREF, HTTP_JSON_OPTIONS } from "../utils/utils";
import { buildHttpRequestOptions, CURRENT_BASE_HREF, V1_BASE_HREF, HTTP_JSON_OPTIONS } from "../utils/utils";
import { Observable, throwError as observableThrowError } from "rxjs";
export abstract class LabelService {
@ -72,6 +72,7 @@ export abstract class LabelService {
export class LabelDefaultService extends LabelService {
labelUrl: string;
chartUrl: string;
chartLabelUrl: string;
constructor(
@Inject(SERVICE_CONFIG) config: IServiceConfig,
@ -79,7 +80,8 @@ export class LabelDefaultService extends LabelService {
) {
super();
this.labelUrl = config.labelEndpoint ? config.labelEndpoint : CURRENT_BASE_HREF + "/labels";
this.chartUrl = config.helmChartEndpoint ? config.helmChartEndpoint : CURRENT_BASE_HREF + "/chartrepo";
this.chartUrl = config.helmChartEndpoint ? config.helmChartEndpoint : V1_BASE_HREF + "/chartrepo";
this.chartLabelUrl = config.helmChartLabelEndpoint ? config.helmChartLabelEndpoint : CURRENT_BASE_HREF + "/chartrepo";
}
@ -208,7 +210,7 @@ export class LabelDefaultService extends LabelService {
chartName: string,
version: string
): Observable<Label[]> {
return this.http.get<Label[]>(`${this.chartUrl}/${projectName}/charts/${chartName}/${version}/labels`);
return this.http.get<Label[]>(`${this.chartLabelUrl}/${projectName}/charts/${chartName}/${version}/labels`);
}
markChartLabel(
@ -217,7 +219,7 @@ export class LabelDefaultService extends LabelService {
version: string,
label: Label,
): Observable<any> {
return this.http.post(`${this.chartUrl}/${projectName}/charts/${chartName}/${version}/labels`,
return this.http.post(`${this.chartLabelUrl}/${projectName}/charts/${chartName}/${version}/labels`,
JSON.stringify(label), HTTP_JSON_OPTIONS);
}
@ -227,7 +229,7 @@ export class LabelDefaultService extends LabelService {
version: string,
label: Label,
): Observable<any> {
return this.http.delete(`${this.chartUrl}/${projectName}/charts/${chartName}/${version}/labels/${label.id}`, HTTP_JSON_OPTIONS);
return this.http.delete(`${this.chartLabelUrl}/${projectName}/charts/${chartName}/${version}/labels/${label.id}`, HTTP_JSON_OPTIONS);
}
}

View File

@ -13,6 +13,12 @@ enum APILevels {
V1 = '',
V2 = '/v2.0'
}
/**
* v1 base href
*/
export const V1_BASE_HREF = '/api' + APILevels.V1;
/**
* Current base href
*/

View File

@ -17,14 +17,14 @@ package harbor
import (
"bytes"
"fmt"
"github.com/goharbor/harbor/src/replication/filter"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"strings"
"github.com/goharbor/harbor/src/common/api"
"github.com/goharbor/harbor/src/replication/filter"
common_http "github.com/goharbor/harbor/src/common/http"
"github.com/goharbor/harbor/src/replication/model"
)
@ -54,7 +54,7 @@ func (a *adapter) FetchCharts(filters []*model.Filter) ([]*model.Resource, error
resources := []*model.Resource{}
for _, project := range projects {
url := fmt.Sprintf("%s/api/%s/chartrepo/%s/charts", a.getURL(), api.APIVersion, project.Name)
url := fmt.Sprintf("%s/api/chartrepo/%s/charts", a.getURL(), project.Name)
repositories := []*model.Repository{}
if err := a.client.Get(url, &repositories); err != nil {
return nil, err
@ -72,7 +72,7 @@ func (a *adapter) FetchCharts(filters []*model.Filter) ([]*model.Resource, error
for _, repository := range repositories {
name := strings.SplitN(repository.Name, "/", 2)[1]
url := fmt.Sprintf("%s/api/%s/chartrepo/%s/charts/%s", a.getURL(), api.APIVersion, project.Name, name)
url := fmt.Sprintf("%s/api/chartrepo/%s/charts/%s", a.getURL(), project.Name, name)
versions := []*chartVersion{}
if err := a.client.Get(url, &versions); err != nil {
return nil, err
@ -133,7 +133,7 @@ func (a *adapter) getChartInfo(name, version string) (*chartVersionDetail, error
if err != nil {
return nil, err
}
url := fmt.Sprintf("%s/api/%s/chartrepo/%s/charts/%s/%s", a.url, api.APIVersion, project, name, version)
url := fmt.Sprintf("%s/api/chartrepo/%s/charts/%s/%s", a.url, project, name, version)
info := &chartVersionDetail{}
if err = a.client.Get(url, info); err != nil {
return nil, err
@ -193,7 +193,7 @@ func (a *adapter) UploadChart(name, version string, chart io.Reader) error {
}
w.Close()
url := fmt.Sprintf("%s/api/%s/chartrepo/%s/charts", a.url, api.APIVersion, project)
url := fmt.Sprintf("%s/api/chartrepo/%s/charts", a.url, project)
req, err := http.NewRequest(http.MethodPost, url, buf)
if err != nil {
@ -224,7 +224,7 @@ func (a *adapter) DeleteChart(name, version string) error {
if err != nil {
return err
}
url := fmt.Sprintf("%s/api/%s/chartrepo/%s/charts/%s/%s", a.url, api.APIVersion, project, name, version)
url := fmt.Sprintf("%s/api/chartrepo/%s/charts/%s/%s", a.url, project, name, version)
return a.client.Delete(url)
}

View File

@ -42,7 +42,7 @@ func TestFetchCharts(t *testing.T) {
},
{
Method: http.MethodGet,
Pattern: fmt.Sprintf("/api/%s/chartrepo/library/charts/harbor", api.APIVersion),
Pattern: "/api/chartrepo/library/charts/harbor",
Handler: func(w http.ResponseWriter, r *http.Request) {
data := `[{
"name": "harbor",
@ -56,7 +56,7 @@ func TestFetchCharts(t *testing.T) {
},
{
Method: http.MethodGet,
Pattern: fmt.Sprintf("/api/%s/chartrepo/library/charts", api.APIVersion),
Pattern: "/api/chartrepo/library/charts",
Handler: func(w http.ResponseWriter, r *http.Request) {
data := `[{
"name": "harbor"
@ -102,7 +102,7 @@ func TestFetchCharts(t *testing.T) {
func TestChartExist(t *testing.T) {
server := test.NewServer(&test.RequestHandlerMapping{
Method: http.MethodGet,
Pattern: fmt.Sprintf("/api/%s/chartrepo/library/charts/harbor/1.0", api.APIVersion),
Pattern: "/api/chartrepo/library/charts/harbor/1.0",
Handler: func(w http.ResponseWriter, r *http.Request) {
data := `{
"metadata": {
@ -127,7 +127,7 @@ func TestDownloadChart(t *testing.T) {
server := test.NewServer([]*test.RequestHandlerMapping{
{
Method: http.MethodGet,
Pattern: fmt.Sprintf("/api/%s/chartrepo/library/charts/harbor/1.0", api.APIVersion),
Pattern: "/api/chartrepo/library/charts/harbor/1.0",
Handler: func(w http.ResponseWriter, r *http.Request) {
data := `{
"metadata": {
@ -158,7 +158,7 @@ func TestDownloadChart(t *testing.T) {
func TestUploadChart(t *testing.T) {
server := test.NewServer(&test.RequestHandlerMapping{
Method: http.MethodPost,
Pattern: fmt.Sprintf("/api/%s/chartrepo/library/charts", api.APIVersion),
Pattern: "/api/chartrepo/library/charts",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
},
@ -176,7 +176,7 @@ func TestUploadChart(t *testing.T) {
func TestDeleteChart(t *testing.T) {
server := test.NewServer(&test.RequestHandlerMapping{
Method: http.MethodDelete,
Pattern: fmt.Sprintf("/api/%s/chartrepo/library/charts/harbor/1.0", api.APIVersion),
Pattern: "/api/chartrepo/library/charts/harbor/1.0",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
},

View File

@ -20,7 +20,6 @@ import (
"regexp"
"strconv"
"github.com/goharbor/harbor/src/common/api"
"github.com/goharbor/harbor/src/lib"
"github.com/goharbor/harbor/src/pkg/types"
"github.com/goharbor/harbor/src/server/middleware"
@ -30,7 +29,7 @@ import (
// UploadChartVersionMiddleware middleware to request count resources for the project
func UploadChartVersionMiddleware() func(http.Handler) http.Handler {
chartsURL := fmt.Sprintf(`^/api/%s/chartrepo/(?P<namespace>[^?#]+)/charts/?$`, api.APIVersion)
chartsURL := `^/api/chartrepo/(?P<namespace>[^?#]+)/charts/?$`
skipper := middleware.NegativeSkipper(middleware.MethodAndPathSkipper(http.MethodPost, regexp.MustCompile(chartsURL)))
return RequestMiddleware(RequestConfig{

View File

@ -58,6 +58,7 @@ func Test_projectReferenceObject(t *testing.T) {
{"/api/v2.0/projects/library/repositories", args{req("/api/v2.0/projects/library/repositories")}, "project", "1", false},
{"/api/v2.0/projects/demo", args{req("/api/v2.0/projects/demo")}, "", "", true},
{"/api/v2.0/library", args{req("/api/v2.0/library")}, "", "", true},
{"/api/chartrepo/library/charts", args{req("/api/chartrepo/library/charts")}, "project", "1", false},
{"/v2/library/photon/manifests/2.0", args{req("/v2/library/photon/manifests/2.0")}, "project", "1", false},
{"/v2", args{req("/v2")}, "", "", true},
}

View File

@ -38,6 +38,7 @@ func (o *oidcCli) Generate(req *http.Request) security.Context {
if path != "/service/token" &&
!strings.HasPrefix(path, "/v2") &&
!strings.HasPrefix(path, "/chartrepo/") &&
!strings.HasPrefix(path, "/api/chartrepo/") &&
!strings.HasPrefix(path, fmt.Sprintf("/api/%s/chartrepo/", api.APIVersion)) {
return nil
}

View File

@ -31,8 +31,9 @@ func ParseProjectName(r *http.Request) string {
var projectName string
prefixes := []string{
fmt.Sprintf("/api/%s/projects/", api.APIVersion), // v2.0 management APIs
fmt.Sprintf("/api/%s/chartrepo/", api.APIVersion), // chartmuseum APIs
fmt.Sprintf("/api/%s/projects/", api.APIVersion), // v2.0 management APIs
"/api/chartrepo/", // chartmuseum APIs
fmt.Sprintf("/api/%s/chartrepo/", api.APIVersion), // chartmuseum Label APIs
}
for _, prefix := range prefixes {

View File

@ -56,6 +56,15 @@ func registerRoutes() {
beego.Router("/chartrepo/:repo/index.yaml", chartRepositoryAPIType, "get:GetIndexByRepo")
beego.Router("/chartrepo/index.yaml", chartRepositoryAPIType, "get:GetIndex")
beego.Router("/chartrepo/:repo/charts/:filename", chartRepositoryAPIType, "get:DownloadChart")
beego.Router("/api/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus")
beego.Router("/api/chartrepo/:repo/charts", chartRepositoryAPIType, "get:ListCharts")
beego.Router("/api/chartrepo/:repo/charts/:name", chartRepositoryAPIType, "get:ListChartVersions")
beego.Router("/api/chartrepo/:repo/charts/:name", chartRepositoryAPIType, "delete:DeleteChart")
beego.Router("/api/chartrepo/:repo/charts/:name/:version", chartRepositoryAPIType, "get:GetChartVersion")
beego.Router("/api/chartrepo/:repo/charts/:name/:version", chartRepositoryAPIType, "delete:DeleteChartVersion")
beego.Router("/api/chartrepo/:repo/charts", chartRepositoryAPIType, "post:UploadChartVersion")
beego.Router("/api/chartrepo/:repo/prov", chartRepositoryAPIType, "post:UploadChartProvFile")
beego.Router("/api/chartrepo/charts", chartRepositoryAPIType, "post:UploadChartVersion")
}
// Error pages

View File

@ -110,18 +110,6 @@ func registerLegacyRoutes() {
// APIs for chart repository
if config.WithChartMuseum() {
// Charts are controlled under projects
chartRepositoryAPIType := &api.ChartRepositoryAPI{}
beego.Router("/api/"+version+"/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus")
beego.Router("/api/"+version+"/chartrepo/:repo/charts", chartRepositoryAPIType, "get:ListCharts")
beego.Router("/api/"+version+"/chartrepo/:repo/charts/:name", chartRepositoryAPIType, "get:ListChartVersions")
beego.Router("/api/"+version+"/chartrepo/:repo/charts/:name", chartRepositoryAPIType, "delete:DeleteChart")
beego.Router("/api/"+version+"/chartrepo/:repo/charts/:name/:version", chartRepositoryAPIType, "get:GetChartVersion")
beego.Router("/api/"+version+"/chartrepo/:repo/charts/:name/:version", chartRepositoryAPIType, "delete:DeleteChartVersion")
beego.Router("/api/"+version+"/chartrepo/:repo/charts", chartRepositoryAPIType, "post:UploadChartVersion")
beego.Router("/api/"+version+"/chartrepo/:repo/prov", chartRepositoryAPIType, "post:UploadChartProvFile")
beego.Router("/api/"+version+"/chartrepo/charts", chartRepositoryAPIType, "post:UploadChartVersion")
// Labels for chart
chartLabelAPIType := &api.ChartLabelAPI{}
beego.Router("/api/"+version+"/chartrepo/:repo/charts/:name/:version/labels", chartLabelAPIType, "get:GetLabels;post:MarkLabel")

View File

@ -2,7 +2,7 @@ from __future__ import absolute_import
import unittest
from testutils import ADMIN_CLIENT
from testutils import ADMIN_CLIENT, CHART_API_CLIENT
from testutils import TEARDOWN
from library.user import User
from library.project import Project
@ -27,7 +27,7 @@ class TestProjects(unittest.TestCase):
@unittest.skipIf(TEARDOWN == False, "Test data won't be erased.")
def test_ClearData(self):
#1. Delete chart file;
self.chart.delete_chart_with_version(TestProjects.project_chart_name, TestProjects.CHART_NAME, TestProjects.VERSION, **ADMIN_CLIENT)
self.chart.delete_chart_with_version(TestProjects.project_chart_name, TestProjects.CHART_NAME, TestProjects.VERSION, **CHART_API_CLIENT)
#2. Delete project(PA);
self.project.delete_project(TestProjects.project_chart_id, **TestProjects.USER_CHART_CLIENT)
@ -50,8 +50,8 @@ class TestProjects(unittest.TestCase):
3. Delete user(UA).
"""
url = ADMIN_CLIENT["endpoint"]
user_chart_password = "Aa123456"
chart_api_url = CHART_API_CLIENT['endpoint']
user_chart_password = 'Aa123456'
TestProjects.CHART_NAME = 'mariadb'
TestProjects.VERSION = '4.3.1'
@ -60,14 +60,16 @@ class TestProjects(unittest.TestCase):
TestProjects.USER_CHART_CLIENT=dict(endpoint = url, username = user_chart_name, password = user_chart_password)
TestProjects.API_CHART_CLIENT=dict(endpoint = chart_api_url, username = user_chart_name, password = user_chart_password)
#2. Create a new project(PA) by user(UA);
TestProjects.project_chart_id, TestProjects.project_chart_name = self.project.create_project(metadata = {"public": "false"}, **TestProjects.USER_CHART_CLIENT)
#3. Upload a chart file to project(PA);
self.chart.upload_chart(TestProjects.project_chart_name, r'./tests/apitests/python/mariadb-{}.tgz'.format(TestProjects.VERSION), **TestProjects.USER_CHART_CLIENT)
self.chart.upload_chart(TestProjects.project_chart_name, r'./tests/apitests/python/mariadb-{}.tgz'.format(TestProjects.VERSION), **TestProjects.API_CHART_CLIENT)
#4. Chart file should be exist in project(PA).
self.chart.chart_should_exist(TestProjects.project_chart_name, TestProjects.CHART_NAME, **TestProjects.USER_CHART_CLIENT)
self.chart.chart_should_exist(TestProjects.project_chart_name, TestProjects.CHART_NAME, **TestProjects.API_CHART_CLIENT)
if __name__ == '__main__':
unittest.main()

View File

@ -14,6 +14,7 @@ admin_pwd = "Harbor12345"
harbor_server = os.environ["HARBOR_HOST"]
#CLIENT=dict(endpoint="https://"+harbor_server+"/api")
ADMIN_CLIENT=dict(endpoint = os.environ.get("HARBOR_HOST_SCHEMA", "https")+ "://"+harbor_server+"/api/v2.0", username = admin_user, password = admin_pwd)
CHART_API_CLIENT=dict(endpoint = os.environ.get("HARBOR_HOST_SCHEMA", "https")+ "://"+harbor_server+"/api", username = admin_user, password = admin_pwd)
USER_ROLE=dict(admin=0,normal=1)
TEARDOWN = os.environ.get('TEARDOWN', 'true').lower() in ('true', 'yes')