harbor/src/core/api/internal.go

111 lines
3.5 KiB
Go

// Copyright 2018 Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"context"
o "github.com/beego/beego/v2/client/orm"
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/controller/quota"
"github.com/goharbor/harbor/src/controller/user"
"github.com/goharbor/harbor/src/core/auth"
"github.com/goharbor/harbor/src/lib/config"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/lib/orm"
)
// InternalAPI handles request of harbor admin...
type InternalAPI struct {
BaseController
}
// Prepare validates the URL and parms
func (ia *InternalAPI) Prepare() {
ia.BaseController.Prepare()
if !ia.SecurityCtx.IsAuthenticated() {
ia.SendUnAuthorizedError(errors.New("UnAuthorized"))
return
}
if !ia.SecurityCtx.IsSysAdmin() {
ia.SendForbiddenError(errors.New(ia.SecurityCtx.GetUsername()))
return
}
}
// RenameAdmin we don't provide flexibility in this API, as this is a workaround.
func (ia *InternalAPI) RenameAdmin() {
ctx := ia.Ctx.Request.Context()
if !auth.IsSuperUser(ctx, ia.SecurityCtx.GetUsername()) {
log.Errorf("User %s is not super user, not allow to rename admin.", ia.SecurityCtx.GetUsername())
ia.SendForbiddenError(errors.New(ia.SecurityCtx.GetUsername()))
return
}
newName := common.NewHarborAdminName
if err := user.Ctl.UpdateProfile(ctx, &models.User{
UserID: 1,
Username: newName,
}, "username"); err != nil {
log.Errorf("Failed to change admin's username, error: %v", err)
ia.SendInternalServerError(errors.New("failed to rename admin user"))
return
}
log.Debugf("The super user has been renamed to: %s", newName)
if err := ia.DestroySession(); err != nil {
log.Errorf("failed to destroy session for admin user, error: %v", err)
return
}
}
// SyncQuota ...
func (ia *InternalAPI) SyncQuota() {
if !config.QuotaPerProjectEnable(orm.Context()) {
ia.SendError(errors.ForbiddenError(nil).WithMessage("quota per project is deactivated"))
return
}
ctx := orm.Context()
cur := config.ReadOnly(ctx)
cfgMgr := config.GetCfgManager(ctx)
if !cur {
cfgMgr.Set(ctx, common.ReadOnly, true)
err := cfgMgr.Save(ctx)
if err != nil {
log.Warningf("failed to save context into config manager, error: %v", err)
}
}
// For api call, to avoid the timeout, it should be asynchronous
go func() {
defer func() {
ctx := orm.Context()
cfgMgr.Set(ctx, common.ReadOnly, cur)
err := cfgMgr.Save(ctx)
if err != nil {
log.Warningf("failed to save context into config manager asynchronously, error: %v", err)
}
}()
log.Info("start to sync quota(API), the system will be set to ReadOnly and back it normal once it done.")
ctx := orm.NewContext(context.TODO(), o.NewOrm())
err := quota.RefreshForProjects(ctx)
if err != nil {
log.Errorf("fail to sync quota(API), but with error: %v, please try to do it again.", err)
return
}
log.Info("success to sync quota(API).")
}()
}