blob: f99946ae6c2fbef6656e2feef575bcdbb56d3f43 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 service
import (
"context"
"encoding/json"
"github.com/apache/servicecomb-service-center/pkg/log"
"github.com/apache/servicecomb-service-center/pkg/util"
apt "github.com/apache/servicecomb-service-center/server/core"
"github.com/apache/servicecomb-service-center/server/core/backend"
pb "github.com/apache/servicecomb-service-center/server/core/proto"
"github.com/apache/servicecomb-service-center/server/plugin"
"github.com/apache/servicecomb-service-center/server/plugin/quota"
"github.com/apache/servicecomb-service-center/server/plugin/registry"
scerr "github.com/apache/servicecomb-service-center/server/scerror"
serviceUtil "github.com/apache/servicecomb-service-center/server/service/util"
)
func (s *MicroServiceService) AddTags(ctx context.Context, in *pb.AddServiceTagsRequest) (*pb.AddServiceTagsResponse, error) {
remoteIP := util.GetIPFromContext(ctx)
err := Validate(in)
if err != nil {
log.Errorf(err, "add service[%s]'s tags %v failed, operator: %s", in.ServiceId, in.Tags, remoteIP)
return &pb.AddServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, err.Error()),
}, nil
}
domainProject := util.ParseDomainProject(ctx)
// service id存在性校验
if !serviceUtil.ServiceExist(ctx, domainProject, in.ServiceId) {
log.Errorf(nil, "add service[%s]'s tags %v failed, service does not exist, operator: %s",
in.ServiceId, in.Tags, remoteIP)
return &pb.AddServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrServiceNotExists, "Service does not exist."),
}, nil
}
addTags := in.Tags
res := quota.NewApplyQuotaResource(quota.TagQuotaType, domainProject, in.ServiceId, int64(len(addTags)))
rst := plugin.Plugins().Quota().Apply4Quotas(ctx, res)
errQuota := rst.Err
if errQuota != nil {
log.Errorf(errQuota, "add service[%s]'s tags %v failed, operator: %s", in.ServiceId, addTags, remoteIP)
response := &pb.AddServiceTagsResponse{
Response: pb.CreateResponseWithSCErr(errQuota),
}
if errQuota.InternalError() {
return response, errQuota
}
return response, nil
}
dataTags, err := serviceUtil.GetTagsUtils(ctx, domainProject, in.ServiceId)
if err != nil {
log.Errorf(err, "add service[%s]'s tags %v failed, get existed tag failed, operator: %s",
in.ServiceId, addTags, remoteIP)
return &pb.AddServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrInternal, err.Error()),
}, err
}
for key, value := range dataTags {
if _, ok := addTags[key]; ok {
continue
}
addTags[key] = value
}
dataTags = addTags
checkErr := serviceUtil.AddTagIntoETCD(ctx, domainProject, in.ServiceId, dataTags)
if checkErr != nil {
log.Errorf(checkErr, "add service[%s]'s tags %v failed, operator: %s", in.ServiceId, in.Tags, remoteIP)
resp := &pb.AddServiceTagsResponse{
Response: pb.CreateResponseWithSCErr(checkErr),
}
if checkErr.InternalError() {
return resp, checkErr
}
return resp, nil
}
log.Infof("add service[%s]'s tags %v successfully, operator: %s", in.ServiceId, in.Tags, remoteIP)
return &pb.AddServiceTagsResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "Add service tags successfully."),
}, nil
}
func (s *MicroServiceService) UpdateTag(ctx context.Context, in *pb.UpdateServiceTagRequest) (*pb.UpdateServiceTagResponse, error) {
remoteIP := util.GetIPFromContext(ctx)
tagFlag := util.StringJoin([]string{in.Key, in.Value}, "/")
err := Validate(in)
if err != nil {
log.Errorf(err, "update service[%s]'s tag[%s] failed, operator: %s", in.ServiceId, tagFlag, remoteIP)
return &pb.UpdateServiceTagResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, err.Error()),
}, nil
}
domainProject := util.ParseDomainProject(ctx)
if !serviceUtil.ServiceExist(ctx, domainProject, in.ServiceId) {
log.Errorf(err, "update service[%s]'s tag[%s] failed, service does not exist, operator: %s",
in.ServiceId, tagFlag, remoteIP)
return &pb.UpdateServiceTagResponse{
Response: pb.CreateResponse(scerr.ErrServiceNotExists, "Service does not exist."),
}, nil
}
tags, err := serviceUtil.GetTagsUtils(ctx, domainProject, in.ServiceId)
if err != nil {
log.Errorf(err, "update service[%s]'s tag[%s] failed, get tag failed, operator: %s",
in.ServiceId, tagFlag, remoteIP)
return &pb.UpdateServiceTagResponse{
Response: pb.CreateResponse(scerr.ErrInternal, err.Error()),
}, err
}
//check tag 是否存在
if _, ok := tags[in.Key]; !ok {
log.Errorf(nil, "update service[%s]'s tag[%s] failed, tag does not exist, operator: %s",
in.ServiceId, tagFlag, remoteIP)
return &pb.UpdateServiceTagResponse{
Response: pb.CreateResponse(scerr.ErrTagNotExists, "Tag does not exist, please add one first."),
}, nil
}
copyTags := make(map[string]string, len(tags))
for k, v := range tags {
copyTags[k] = v
}
copyTags[in.Key] = in.Value
checkErr := serviceUtil.AddTagIntoETCD(ctx, domainProject, in.ServiceId, copyTags)
if checkErr != nil {
log.Errorf(checkErr, "update service[%s]'s tag[%s] failed, operator: %s", in.ServiceId, tagFlag, remoteIP)
resp := &pb.UpdateServiceTagResponse{
Response: pb.CreateResponseWithSCErr(checkErr),
}
if checkErr.InternalError() {
return resp, checkErr
}
return resp, nil
}
log.Infof("update service[%s]'s tag[%s] successfully, operator: %s", in.ServiceId, tagFlag, remoteIP)
return &pb.UpdateServiceTagResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "Update service tag success."),
}, nil
}
func (s *MicroServiceService) DeleteTags(ctx context.Context, in *pb.DeleteServiceTagsRequest) (*pb.DeleteServiceTagsResponse, error) {
remoteIP := util.GetIPFromContext(ctx)
err := Validate(in)
if err != nil {
log.Errorf(err, "delete service[%s]'s tags %v failed, operator: %s", in.ServiceId, in.Keys, remoteIP)
return &pb.DeleteServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, err.Error()),
}, nil
}
domainProject := util.ParseDomainProject(ctx)
if !serviceUtil.ServiceExist(ctx, domainProject, in.ServiceId) {
log.Errorf(nil, "delete service[%s]'s tags %v failed, service does not exist, operator: %s",
in.ServiceId, in.Keys, remoteIP)
return &pb.DeleteServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrServiceNotExists, "Service does not exist."),
}, nil
}
tags, err := serviceUtil.GetTagsUtils(ctx, domainProject, in.ServiceId)
if err != nil {
log.Errorf(err, "delete service[%s]'s tags %v failed, get service tags failed, operator: %s",
in.ServiceId, in.Keys, remoteIP)
return &pb.DeleteServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrInternal, err.Error()),
}, err
}
copyTags := make(map[string]string, len(tags))
for k, v := range tags {
copyTags[k] = v
}
for _, key := range in.Keys {
if _, ok := copyTags[key]; !ok {
log.Errorf(nil, "delete service[%s]'s tags %v failed, tag[%s] does not exist, operator: %s",
in.ServiceId, in.Keys, key, remoteIP)
return &pb.DeleteServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrTagNotExists, "Delete tags failed for this key "+key+" does not exist."),
}, nil
}
delete(copyTags, key)
}
// tags 可能size == 0
data, err := json.Marshal(copyTags)
if err != nil {
log.Errorf(err, "delete service[%s]'s tags %v failed, marshall service tags failed, operator: %s",
in.ServiceId, in.Keys, remoteIP)
return &pb.DeleteServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrInternal, err.Error()),
}, err
}
key := apt.GenerateServiceTagKey(domainProject, in.ServiceId)
resp, err := backend.Registry().TxnWithCmp(ctx,
[]registry.PluginOp{registry.OpPut(registry.WithStrKey(key), registry.WithValue(data))},
[]registry.CompareOp{registry.OpCmp(
registry.CmpVer(util.StringToBytesWithNoCopy(apt.GenerateServiceKey(domainProject, in.ServiceId))),
registry.CmpNotEqual, 0)},
nil)
if err != nil {
log.Errorf(err, "delete service[%s]'s tags %v failed, operator: %s",
in.ServiceId, in.Keys, remoteIP)
return &pb.DeleteServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrUnavailableBackend, err.Error()),
}, err
}
if !resp.Succeeded {
log.Errorf(err, "delete service[%s]'s tags %v failed, service does not exist, operator: %s",
in.ServiceId, in.Keys, remoteIP)
return &pb.DeleteServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrServiceNotExists, "Service does not exist."),
}, nil
}
log.Infof("delete service[%s]'s tags %v successfully, operator: %s", in.ServiceId, in.Keys, remoteIP)
return &pb.DeleteServiceTagsResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "Delete service tags successfully."),
}, nil
}
func (s *MicroServiceService) GetTags(ctx context.Context, in *pb.GetServiceTagsRequest) (*pb.GetServiceTagsResponse, error) {
err := Validate(in)
if err != nil {
log.Errorf(err, "get service[%s]'s tags failed", in.ServiceId)
return &pb.GetServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, err.Error()),
}, nil
}
domainProject := util.ParseDomainProject(ctx)
if !serviceUtil.ServiceExist(ctx, domainProject, in.ServiceId) {
log.Errorf(err, "get service[%s]'s tags failed, service does not exist", in.ServiceId)
return &pb.GetServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrServiceNotExists, "Service does not exist."),
}, nil
}
tags, err := serviceUtil.GetTagsUtils(ctx, domainProject, in.ServiceId)
if err != nil {
log.Errorf(err, "get service[%s]'s tags failed, get tags failed", in.ServiceId)
return &pb.GetServiceTagsResponse{
Response: pb.CreateResponse(scerr.ErrInternal, err.Error()),
}, err
}
return &pb.GetServiceTagsResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "Get service tags successfully."),
Tags: tags,
}, nil
}