add apis for switch the notification language (#5088)

add apis for switch the notification lanaguae

Signed-off-by: wanjunlei <wanjunlei@kubesphere.io>
This commit is contained in:
wanjunlei
2022-07-22 17:46:57 +08:00
committed by GitHub
parent bc23969bfa
commit 1f2f6157d7
6 changed files with 208 additions and 59 deletions

View File

@@ -506,6 +506,7 @@ func (s *APIServer) waitForResourceSync(ctx context.Context) error {
notificationv2beta1.ResourcesPluralReceiver,
},
{Group: "notification.kubesphere.io", Version: "v2beta2"}: {
notificationv2beta2.ResourcesPluralNotificationManager,
notificationv2beta2.ResourcesPluralConfig,
notificationv2beta2.ResourcesPluralReceiver,
notificationv2beta2.ResourcesPluralRouter,

View File

@@ -16,6 +16,8 @@
package v2beta2
import (
"io/ioutil"
"github.com/emicklei/go-restful"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/kubernetes"
@@ -118,6 +120,27 @@ func (h *handler) UpdateResource(req *restful.Request, resp *restful.Response) {
handleResponse(req, resp, updated, err)
}
func (h *handler) PatchResource(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user")
resource := req.PathParameter("resources")
name := req.PathParameter("name")
if !h.operator.IsKnownResource(resource, nmoperator.V2beta2, "") {
api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s", resource))
return
}
data, err := ioutil.ReadAll(req.Request.Body)
if err != nil {
api.HandleBadRequest(resp, req, err)
return
}
patched, err := h.operator.Patch(user, resource, name, data)
handleResponse(req, resp, patched, err)
}
func (h *handler) DeleteResource(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user")

View File

@@ -69,7 +69,7 @@ func AddToContainer(
To(h.ListResource).
Doc("list the notification resources").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, routers, silences, configmaps")).
Param(ws.PathParameter("resources", "known values include notificationmanagers, configs, receivers, secrets, routers, silences, configmaps")).
Param(ws.QueryParameter(query.ParameterName, "name used for filtering").Required(false)).
Param(ws.QueryParameter(query.ParameterLabelSelector, "label selector used for filtering").Required(false)).
Param(ws.QueryParameter("type", "config or receiver type, known values include dingtalk, email, feishu, slack, webhook, wechat").Required(false)).
@@ -83,7 +83,7 @@ func AddToContainer(
To(h.GetResource).
Doc("get the specified notification resources").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, routers, silences, configmaps")).
Param(ws.PathParameter("resources", "known values include notificationmanagers, configs, receivers, secrets, routers, silences, configmaps")).
Param(ws.PathParameter(query.ParameterName, "the name of the resource")).
Param(ws.QueryParameter("type", "config or receiver type, known values include dingtalk, feishu, email, slack, webhook, wechat").Required(false)).
Returns(http.StatusOK, api.StatusOK, nil))
@@ -92,14 +92,22 @@ func AddToContainer(
To(h.CreateResource).
Doc("create a notification resources").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, routers, silences, configmaps")).
Param(ws.PathParameter("resources", "known values include notificationmanagers, configs, receivers, secrets, routers, silences, configmaps")).
Returns(http.StatusOK, api.StatusOK, nil))
ws.Route(ws.PUT("/{resources}/{name}").
To(h.UpdateResource).
Doc("update the specified notification resources").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, routers, silences, configmaps")).
Param(ws.PathParameter("resources", "known values include notificationmanagers, configs, receivers, secrets, routers, silences, configmaps")).
Param(ws.PathParameter(query.ParameterName, "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, nil))
ws.Route(ws.PATCH("/{resources}/{name}").
To(h.PatchResource).
Doc("patch the specified notification resources").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resources", "known values include notificationmanagers, configs, receivers, secrets, routers, silences, configmaps")).
Param(ws.PathParameter(query.ParameterName, "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, nil))
@@ -154,6 +162,15 @@ func AddToContainer(
Param(ws.PathParameter(query.ParameterName, "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, nil))
ws.Route(ws.PATCH("/users/{user}/{resources}/{name}").
To(h.PatchResource).
Doc("Patch the specified notification resources").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("user", "user name")).
Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, silences, configmaps")).
Param(ws.PathParameter(query.ParameterName, "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, nil))
ws.Route(ws.DELETE("/users/{user}/{resources}/{name}").
To(h.DeleteResource).
Doc("delete the specified notification resources").

View File

@@ -25,6 +25,8 @@ import (
"net/http"
"reflect"
"k8s.io/apimachinery/pkg/types"
"github.com/emicklei/go-restful"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
@@ -66,6 +68,7 @@ type Operator interface {
Create(user, resource string, obj runtime.Object) (runtime.Object, error)
Delete(user, resource, name string) error
Update(user, resource, name string, obj runtime.Object) (runtime.Object, error)
Patch(user, resource, name string, data []byte) (runtime.Object, error)
Verify(request *restful.Request, response *restful.Response)
@@ -120,29 +123,15 @@ func (o *operator) List(user, resource, subresource string, q *query.Query) (*ap
func (o *operator) list(user, resource, version, subresource string, q *query.Query) (*api.ListResult, error) {
if user != "" && resource == v2beta2.ResourcesPluralRouter {
return nil, errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "",
fmt.Errorf("tenant can not list router"))
}
if len(q.LabelSelector) > 0 {
q.LabelSelector = q.LabelSelector + ","
}
filter := ""
// If user is nil, it will list all global object.
if user == "" {
if isConfig(o.GetObject(resource, version)) {
filter = "type=default"
} else {
filter = "type=global"
if user != "" {
if resource == v2beta2.ResourcesPluralRouter ||
resource == v2beta2.ResourcesPluralNotificationManager {
return nil, errors.NewForbidden(v2beta2.Resource(resource), "",
fmt.Errorf("tenant can not list %s", resource))
}
} else {
// If the user is not nil, only return the object belong to this user.
filter = "type=tenant,user=" + user
}
q.LabelSelector = q.LabelSelector + filter
q.LabelSelector = o.generateLabelSelector(q, user, resource, version)
ns := ""
if resource == Secret || resource == ConfigMap {
@@ -155,7 +144,8 @@ func (o *operator) list(user, resource, version, subresource string, q *query.Qu
return nil, err
}
if subresource == "" || resource == Secret {
if subresource == "" ||
(resource != v2beta2.ResourcesPluralConfig && resource != v2beta2.ResourcesPluralReceiver) {
return res, nil
}
@@ -174,6 +164,34 @@ func (o *operator) list(user, resource, version, subresource string, q *query.Qu
return results, nil
}
func (o *operator) generateLabelSelector(q *query.Query, user, resource, version string) string {
if resource == v2beta2.ResourcesPluralNotificationManager {
return q.LabelSelector
}
labelSelector := q.LabelSelector
if len(labelSelector) > 0 {
labelSelector = q.LabelSelector + ","
}
filter := ""
// If user is nil, it will list all global object.
if user == "" {
if isConfig(o.GetObject(resource, version)) {
filter = "type=default"
} else {
filter = "type=global"
}
} else {
// If the user is not nil, only return the object belong to this user.
filter = "type=tenant,user=" + user
}
labelSelector = labelSelector + filter
return labelSelector
}
// GetV2beta1 get the specified object of version v2beta1, if you want to get a global object, the user must be nil.
// If you want to get a tenant object, the user must equal to the tenant specified in labels of the object.
func (o *operator) GetV2beta1(user, resource, name, subresource string) (runtime.Object, error) {
@@ -188,9 +206,12 @@ func (o *operator) Get(user, resource, name, subresource string) (runtime.Object
func (o *operator) get(user, resource, version, name, subresource string) (runtime.Object, error) {
if user != "" && resource == v2beta2.ResourcesPluralRouter {
return nil, errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "",
fmt.Errorf("tenant can not get router"))
if user != "" {
if resource == v2beta2.ResourcesPluralRouter ||
resource == v2beta2.ResourcesPluralNotificationManager {
return nil, errors.NewForbidden(v2beta2.Resource(resource), "",
fmt.Errorf("tenant can not get %s", resource))
}
}
ns := ""
@@ -209,7 +230,8 @@ func (o *operator) get(user, resource, version, name, subresource string) (runti
return nil, err
}
if subresource == "" || resource == Secret || resource == ConfigMap {
if subresource == "" ||
(resource != v2beta2.ResourcesPluralConfig && resource != v2beta2.ResourcesPluralReceiver) {
return obj, nil
}
@@ -239,16 +261,21 @@ func (o *operator) Create(user, resource string, obj runtime.Object) (runtime.Ob
func (o *operator) create(user, resource, version string, obj runtime.Object) (runtime.Object, error) {
if user != "" {
if resource == v2beta2.ResourcesPluralRouter ||
resource == v2beta2.ResourcesPluralNotificationManager {
return nil, errors.NewForbidden(v2beta2.Resource(resource), "",
fmt.Errorf("tenant can not create %s", resource))
}
}
if err := appendLabel(user, resource, obj); err != nil {
return nil, err
}
if user != "" && resource == v2beta2.ResourcesPluralRouter {
return nil, errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "",
fmt.Errorf("tenant can not create router"))
}
switch resource {
case v2beta2.ResourcesPluralNotificationManager:
return o.ksClient.NotificationV2beta2().NotificationManagers().Create(context.Background(), obj.(*v2beta2.NotificationManager), v1.CreateOptions{})
case v2beta2.ResourcesPluralConfig:
if version == V2beta1 {
return o.ksClient.NotificationV2beta1().Configs().Create(context.Background(), obj.(*v2beta1.Config), v1.CreateOptions{})
@@ -288,22 +315,22 @@ func (o *operator) Delete(user, resource, name string) error {
func (o *operator) delete(user, resource, name string) error {
if user != "" && resource == v2beta2.ResourcesPluralRouter {
return errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "",
fmt.Errorf("tenant can not delete router"))
}
if obj, err := o.Get(user, resource, name, ""); err != nil {
klog.Error(err)
return err
} else {
if err := authorizer(user, obj); err != nil {
klog.Error(err)
return err
if user != "" {
if resource == v2beta2.ResourcesPluralRouter ||
resource == v2beta2.ResourcesPluralNotificationManager {
return errors.NewForbidden(v2beta2.Resource(resource), "",
fmt.Errorf("tenant can not delete %s", resource))
}
}
if _, err := o.Get(user, resource, name, ""); err != nil {
klog.Error(err)
return err
}
switch resource {
case v2beta2.ResourcesPluralNotificationManager:
return o.ksClient.NotificationV2beta2().NotificationManagers().Delete(context.Background(), name, v1.DeleteOptions{})
case v2beta2.ResourcesPluralConfig:
return o.ksClient.NotificationV2beta2().Configs().Delete(context.Background(), name, v1.DeleteOptions{})
case v2beta2.ResourcesPluralReceiver:
@@ -335,26 +362,36 @@ func (o *operator) Update(user, resource, name string, obj runtime.Object) (runt
func (o *operator) update(user, resource, version, name string, obj runtime.Object) (runtime.Object, error) {
if user != "" && resource == v2beta2.ResourcesPluralRouter {
return nil, errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "",
fmt.Errorf("tenant can not update router"))
if user != "" {
if resource == v2beta2.ResourcesPluralRouter ||
resource == v2beta2.ResourcesPluralNotificationManager {
return nil, errors.NewForbidden(v2beta2.Resource(resource), "",
fmt.Errorf("tenant can not update %s", resource))
}
}
accessor, err := meta.Accessor(obj)
if err != nil {
return nil, err
}
if accessor.GetName() != name {
return nil, fmt.Errorf("incorrcet parameter, resource name is not equal to the name in body")
}
_, err = o.Get(user, resource, name, "")
if err != nil {
klog.Error(err)
return nil, err
}
if err := appendLabel(user, resource, obj); err != nil {
return nil, err
}
if old, err := o.Get(user, resource, name, ""); err != nil {
klog.Error(err)
return nil, err
} else {
if err := authorizer(user, old); err != nil {
klog.Error(err)
return nil, err
}
}
switch resource {
case v2beta2.ResourcesPluralNotificationManager:
return o.ksClient.NotificationV2beta2().NotificationManagers().Update(context.Background(), obj.(*v2beta2.NotificationManager), v1.UpdateOptions{})
case v2beta2.ResourcesPluralConfig:
if version == V2beta1 {
return o.ksClient.NotificationV2beta1().Configs().Update(context.Background(), obj.(*v2beta1.Config), v1.UpdateOptions{})
@@ -380,9 +417,49 @@ func (o *operator) update(user, resource, version, name string, obj runtime.Obje
}
}
// Patch an object, only a global object will be patched if the user is nil.
// If the user is not nil, a tenant object whose tenant label matches the user will be patched.
func (o *operator) Patch(user, resource, name string, data []byte) (runtime.Object, error) {
if user != "" {
if resource == v2beta2.ResourcesPluralRouter ||
resource == v2beta2.ResourcesPluralNotificationManager {
return nil, errors.NewForbidden(v2beta2.Resource(resource), "",
fmt.Errorf("tenant can not update %s", resource))
}
}
_, err := o.Get(user, resource, name, "")
if err != nil {
klog.Error(err)
return nil, err
}
switch resource {
case v2beta2.ResourcesPluralNotificationManager:
return o.ksClient.NotificationV2beta2().NotificationManagers().Patch(context.Background(), name, types.MergePatchType, data, v1.PatchOptions{})
case v2beta2.ResourcesPluralConfig:
return o.ksClient.NotificationV2beta2().Configs().Patch(context.Background(), name, types.MergePatchType, data, v1.PatchOptions{})
case v2beta2.ResourcesPluralReceiver:
return o.ksClient.NotificationV2beta2().Receivers().Patch(context.Background(), name, types.MergePatchType, data, v1.PatchOptions{})
case v2beta2.ResourcesPluralRouter:
return o.ksClient.NotificationV2beta2().Routers().Patch(context.Background(), name, types.MergePatchType, data, v1.PatchOptions{})
case v2beta2.ResourcesPluralSilence:
return o.ksClient.NotificationV2beta2().Silences().Patch(context.Background(), name, types.MergePatchType, data, v1.PatchOptions{})
case Secret:
return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Patch(context.Background(), name, types.MergePatchType, data, v1.PatchOptions{})
case ConfigMap:
return o.k8sClient.CoreV1().ConfigMaps(constants.NotificationSecretNamespace).Patch(context.Background(), name, types.MergePatchType, data, v1.PatchOptions{})
default:
return nil, errors.NewInternalError(nil)
}
}
func (o *operator) GetObject(resource, version string) runtime.Object {
switch resource {
case v2beta2.ResourcesPluralNotificationManager:
return &v2beta2.NotificationManager{}
case v2beta2.ResourcesPluralConfig:
if version == V2beta1 {
return &v2beta1.Config{}
@@ -542,6 +619,11 @@ func isConfig(obj runtime.Object) bool {
// Is the object is a global object.
func isGlobal(obj runtime.Object) bool {
if _, ok := obj.(*v2beta2.NotificationManager); ok {
return true
}
accessor, err := meta.Accessor(obj)
if err != nil {
klog.Errorln(err)

View File

@@ -28,6 +28,31 @@ import (
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type notificationmanagerGetter struct {
ksInformer ksinformers.SharedInformerFactory
}
func NewNotificationManagerGetter(informer ksinformers.SharedInformerFactory) v1alpha3.Interface {
return &notificationmanagerGetter{ksInformer: informer}
}
func (g *notificationmanagerGetter) Get(_, name string) (runtime.Object, error) {
return g.ksInformer.Notification().V2beta2().NotificationManagers().Lister().Get(name)
}
func (g *notificationmanagerGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
objs, err := g.ksInformer.Notification().V2beta2().NotificationManagers().Lister().List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, obj := range objs {
result = append(result, obj)
}
return v1alpha3.DefaultList(result, query, compare, filter), nil
}
type configGetter struct {
ksInformer ksinformers.SharedInformerFactory
}

View File

@@ -143,6 +143,7 @@ func NewResourceGetter(factory informers.InformerFactory, cache cache.Cache) *Re
clusterResourceGetters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralClusterRole)] = clusterrole.New(factory.KubernetesSharedInformerFactory())
clusterResourceGetters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralClusterRoleBinding)] = clusterrolebinding.New(factory.KubernetesSharedInformerFactory())
clusterResourceGetters[clusterv1alpha1.SchemeGroupVersion.WithResource(clusterv1alpha1.ResourcesPluralCluster)] = cluster.New(factory.KubeSphereSharedInformerFactory())
clusterResourceGetters[notificationv2beta2.SchemeGroupVersion.WithResource(notificationv2beta2.ResourcesPluralNotificationManager)] = notification.NewNotificationManagerGetter(factory.KubeSphereSharedInformerFactory())
clusterResourceGetters[notificationv2beta2.SchemeGroupVersion.WithResource(notificationv2beta2.ResourcesPluralConfig)] = notification.NewNotificationConfigGetter(factory.KubeSphereSharedInformerFactory())
clusterResourceGetters[notificationv2beta2.SchemeGroupVersion.WithResource(notificationv2beta2.ResourcesPluralReceiver)] = notification.NewNotificationReceiverGetter(factory.KubeSphereSharedInformerFactory())
clusterResourceGetters[notificationv2beta2.SchemeGroupVersion.WithResource(notificationv2beta2.ResourcesPluralRouter)] = notification.NewNotificationRouterGetter(factory.KubeSphereSharedInformerFactory())