提交 5e39b7c7 编写于 作者: W wanjunlei

add tenant-level apis for notification secret

Signed-off-by: Nwanjunlei <wanjunlei@yunify.com>
上级 d4a8f9bf
...@@ -128,7 +128,6 @@ const ( ...@@ -128,7 +128,6 @@ const (
NotificationTag = "Notification" NotificationTag = "Notification"
NotificationSecretNamespace = "kubesphere-monitoring-federated" NotificationSecretNamespace = "kubesphere-monitoring-federated"
NotificationManagedLabel = "notification-manager/managed"
) )
var ( var (
......
...@@ -222,7 +222,7 @@ func (c *Controller) reconcile(obj interface{}) error { ...@@ -222,7 +222,7 @@ func (c *Controller) reconcile(obj interface{}) error {
// Only reconcile the secret which created by notification manager. // Only reconcile the secret which created by notification manager.
if secret, ok := obj.(*corev1.Secret); ok { if secret, ok := obj.(*corev1.Secret); ok {
if secret.Namespace != constants.NotificationSecretNamespace || secret.Labels[constants.NotificationManagedLabel] != "true" { if secret.Namespace != constants.NotificationSecretNamespace {
klog.V(8).Infof("No need to reconcile secret %s/%s", accessor.GetNamespace(), accessor.GetName()) klog.V(8).Infof("No need to reconcile secret %s/%s", accessor.GetNamespace(), accessor.GetName())
return nil return nil
} }
......
...@@ -47,7 +47,6 @@ var ( ...@@ -47,7 +47,6 @@ var (
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Namespace: constants.NotificationSecretNamespace, Namespace: constants.NotificationSecretNamespace,
Labels: map[string]string{constants.NotificationManagedLabel: "true"},
}, },
} }
......
...@@ -18,7 +18,6 @@ package v2 ...@@ -18,7 +18,6 @@ package v2
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/klog" "k8s.io/klog"
...@@ -44,36 +43,6 @@ func newNotificationHandler( ...@@ -44,36 +43,6 @@ func newNotificationHandler(
} }
} }
func (h *handler) ListSecret(req *restful.Request, resp *restful.Response) {
q := query.ParseQueryParameter(req)
objs, err := h.operator.ListSecret(q)
handleResponse(req, resp, objs, err)
}
func (h *handler) GetSecret(req *restful.Request, resp *restful.Response) {
obj, err := h.operator.GetSecret(req.PathParameter("secret"))
handleResponse(req, resp, obj, err)
}
func (h *handler) CreateOrUpdateSecret(req *restful.Request, resp *restful.Response) {
var obj corev1.Secret
err := req.ReadEntity(&obj)
if err != nil {
api.HandleBadRequest(resp, req, err)
return
}
created, err := h.operator.CreateOrUpdateSecret(&obj)
handleResponse(req, resp, created, err)
}
func (h *handler) DeleteSecret(req *restful.Request, resp *restful.Response) {
err := h.operator.DeleteSecret(req.PathParameter("secret"))
handleResponse(req, resp, servererr.None, err)
}
func (h *handler) ListResource(req *restful.Request, resp *restful.Response) { func (h *handler) ListResource(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user") user := req.PathParameter("user")
...@@ -128,6 +97,7 @@ func (h *handler) UpdateResource(req *restful.Request, resp *restful.Response) { ...@@ -128,6 +97,7 @@ func (h *handler) UpdateResource(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user") user := req.PathParameter("user")
resource := req.PathParameter("resources") resource := req.PathParameter("resources")
name := req.PathParameter("name")
if !h.operator.IsKnownResource(resource) { if !h.operator.IsKnownResource(resource) {
api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s", resource)) api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s", resource))
...@@ -140,7 +110,7 @@ func (h *handler) UpdateResource(req *restful.Request, resp *restful.Response) { ...@@ -140,7 +110,7 @@ func (h *handler) UpdateResource(req *restful.Request, resp *restful.Response) {
return return
} }
updated, err := h.operator.Update(user, resource, obj) updated, err := h.operator.Update(user, resource, name, obj)
handleResponse(req, resp, updated, err) handleResponse(req, resp, updated, err)
} }
......
...@@ -21,7 +21,6 @@ package v2 ...@@ -21,7 +21,6 @@ package v2
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
openapi "github.com/emicklei/go-restful-openapi" openapi "github.com/emicklei/go-restful-openapi"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/api" "kubesphere.io/kubesphere/pkg/api"
...@@ -50,52 +49,12 @@ func AddToContainer( ...@@ -50,52 +49,12 @@ func AddToContainer(
ws := runtime.NewWebService(GroupVersion) ws := runtime.NewWebService(GroupVersion)
h := newNotificationHandler(informers, k8sClient, ksClient) h := newNotificationHandler(informers, k8sClient, ksClient)
// apis for secrets // apis for global notification config, receiver, and secret
ws.Route(ws.GET("/secrets").
To(h.ListSecret).
Doc("list the secrets").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
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(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")).
Param(ws.QueryParameter(query.ParameterLimit, "limit").Required(false)).
Param(ws.QueryParameter(query.ParameterAscending, "sort parameters, e.g. ascending=false").Required(false).DefaultValue("ascending=false")).
Param(ws.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime")).
Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{}}))
ws.Route(ws.GET("/secrets/{secret}").
To(h.GetSecret).
Doc("get the secret").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("secret", "secret name")).
Returns(http.StatusOK, api.StatusOK, []v1.Secret{}))
ws.Route(ws.POST("/secrets").
To(h.CreateOrUpdateSecret).
Doc("create a secret").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Returns(http.StatusOK, api.StatusOK, []v1.Secret{}))
ws.Route(ws.PUT("/secrets/{secret}").
To(h.CreateOrUpdateSecret).
Doc("update the secret").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("secret", "secret name")).
Returns(http.StatusOK, api.StatusOK, []v1.Secret{}))
ws.Route(ws.DELETE("/secrets/{secret}").
To(h.DeleteSecret).
Doc("delete the secret").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("secret", "secret name")).
Returns(http.StatusOK, api.StatusOK, errors.None))
// apis for global notification config and receiver
ws.Route(ws.GET("/{resources}"). ws.Route(ws.GET("/{resources}").
To(h.ListResource). To(h.ListResource).
Doc("list the notification configs or receivers"). Doc("list the notification configs or receivers").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers")). Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers, secrets")).
Param(ws.QueryParameter(query.ParameterName, "name used for filtering").Required(false)). 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(query.ParameterLabelSelector, "label selector used for filtering").Required(false)).
Param(ws.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). Param(ws.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")).
...@@ -108,7 +67,7 @@ func AddToContainer( ...@@ -108,7 +67,7 @@ func AddToContainer(
To(h.GetResource). To(h.GetResource).
Doc("get the specified notification config or receiver"). Doc("get the specified notification config or receiver").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers")). Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers, secrets")).
Param(ws.PathParameter("name", "the name of the resource")). Param(ws.PathParameter("name", "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, nil)) Returns(http.StatusOK, api.StatusOK, nil))
...@@ -116,14 +75,14 @@ func AddToContainer( ...@@ -116,14 +75,14 @@ func AddToContainer(
To(h.CreateResource). To(h.CreateResource).
Doc("create a notification config or receiver"). Doc("create a notification config or receiver").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resource", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers")). Param(ws.PathParameter("resource", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers, secrets")).
Returns(http.StatusOK, api.StatusOK, nil)) Returns(http.StatusOK, api.StatusOK, nil))
ws.Route(ws.PUT("/{resources}/{name}"). ws.Route(ws.PUT("/{resources}/{name}").
To(h.UpdateResource). To(h.UpdateResource).
Doc("update the specified notification config or receiver"). Doc("update the specified notification config or receiver").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers")). Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers, secrets")).
Param(ws.PathParameter("name", "the name of the resource")). Param(ws.PathParameter("name", "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, nil)) Returns(http.StatusOK, api.StatusOK, nil))
...@@ -131,7 +90,7 @@ func AddToContainer( ...@@ -131,7 +90,7 @@ func AddToContainer(
To(h.DeleteResource). To(h.DeleteResource).
Doc("delete the specified notification config or receiver"). Doc("delete the specified notification config or receiver").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers")). Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers, secrets")).
Param(ws.PathParameter("name", "the name of the resource")). Param(ws.PathParameter("name", "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, errors.None)) Returns(http.StatusOK, api.StatusOK, errors.None))
...@@ -141,7 +100,7 @@ func AddToContainer( ...@@ -141,7 +100,7 @@ func AddToContainer(
Doc("list the notification configs or receivers"). Doc("list the notification configs or receivers").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("user", "user name")). Param(ws.PathParameter("user", "user name")).
Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers")). Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers, secrets")).
Param(ws.QueryParameter(query.ParameterName, "name used for filtering").Required(false)). 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(query.ParameterLabelSelector, "label selector used for filtering").Required(false)).
Param(ws.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). Param(ws.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")).
...@@ -155,7 +114,7 @@ func AddToContainer( ...@@ -155,7 +114,7 @@ func AddToContainer(
Doc("get the specified notification config or receiver"). Doc("get the specified notification config or receiver").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("user", "user name")). Param(ws.PathParameter("user", "user name")).
Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers")). Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers, secrets")).
Param(ws.PathParameter("name", "the name of the resource")). Param(ws.PathParameter("name", "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, nil)) Returns(http.StatusOK, api.StatusOK, nil))
...@@ -171,7 +130,7 @@ func AddToContainer( ...@@ -171,7 +130,7 @@ func AddToContainer(
Doc("update the specified notification config or receiver"). Doc("update the specified notification config or receiver").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("user", "user name")). Param(ws.PathParameter("user", "user name")).
Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers")). Param(ws.PathParameter("resources", "notification configs or receivers, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers, secrets")).
Param(ws.PathParameter("name", "the name of the resource")). Param(ws.PathParameter("name", "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, nil)) Returns(http.StatusOK, api.StatusOK, nil))
...@@ -180,7 +139,7 @@ func AddToContainer( ...@@ -180,7 +139,7 @@ func AddToContainer(
Doc("delete the specified notification config or receiver"). Doc("delete the specified notification config or receiver").
Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}).
Param(ws.PathParameter("user", "user name")). Param(ws.PathParameter("user", "user name")).
Param(ws.PathParameter("resources", "notification config or receiver, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers")). Param(ws.PathParameter("resources", "notification config or receiver, known values include dingtalkconfigs, dingtalkreceivers, emailconfigs. emailreceivers, slackconfigs, slackreceivers, webhookconfigs, webhookreceivers, wechatconfigs, wechatreceivers, secrets")).
Param(ws.PathParameter("name", "the name of the resource")). Param(ws.PathParameter("name", "the name of the resource")).
Returns(http.StatusOK, api.StatusOK, errors.None)) Returns(http.StatusOK, api.StatusOK, errors.None))
......
...@@ -24,12 +24,7 @@ type Operator interface { ...@@ -24,12 +24,7 @@ type Operator interface {
Get(user, resource, name string) (runtime.Object, error) Get(user, resource, name string) (runtime.Object, error)
Create(user, resource string, obj runtime.Object) (runtime.Object, error) Create(user, resource string, obj runtime.Object) (runtime.Object, error)
Delete(user, resource, name string) error Delete(user, resource, name string) error
Update(user, resource string, obj runtime.Object) (runtime.Object, error) Update(user, resource, name string, obj runtime.Object) (runtime.Object, error)
ListSecret(query *query.Query) (*api.ListResult, error)
GetSecret(name string) (interface{}, error)
CreateOrUpdateSecret(obj *corev1.Secret) (*corev1.Secret, error)
DeleteSecret(name string) error
GetObject(resource string) runtime.Object GetObject(resource string) runtime.Object
IsKnownResource(resource string) bool IsKnownResource(resource string) bool
...@@ -59,21 +54,32 @@ func NewOperator( ...@@ -59,21 +54,32 @@ func NewOperator(
// If the user is not nil, only tenant objects whose tenant label matches the user will be returned. // If the user is not nil, only tenant objects whose tenant label matches the user will be returned.
func (o *operator) List(user, resource string, q *query.Query) (*api.ListResult, error) { func (o *operator) List(user, resource string, q *query.Query) (*api.ListResult, error) {
if len(q.LabelSelector) > 0 {
q.LabelSelector = q.LabelSelector + ","
}
filter := ""
// If user is nil, it will list all global object. // If user is nil, it will list all global object.
if user == "" { if user == "" {
appendGlobalLabel(resource, q) if isConfig(o.GetObject(resource)) {
filter = "type=default"
} else {
filter = "type=global"
}
} else { } else {
// If the user is not nil, only return the object belong to this user. // If the user is not nil, only return the object belong to this user.
appendTenantLabel(user, q) filter = "type=tenant,user=" + user
} }
return o.resourceGetter.List(resource, "", q) q.LabelSelector = q.LabelSelector + filter
return o.resourceGetter.List(resource, constants.NotificationSecretNamespace, q)
} }
// Get the specified object, if you want to get a global object, the user must be nil. // Get the specified object, 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. // If you want to get a tenant object, the user must equal to the tenant specified in labels of the object.
func (o *operator) Get(user, resource, name string) (runtime.Object, error) { func (o *operator) Get(user, resource, name string) (runtime.Object, error) {
obj, err := o.resourceGetter.Get(resource, "", name) obj, err := o.resourceGetter.Get(resource, constants.NotificationSecretNamespace, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -89,7 +95,7 @@ func (o *operator) Get(user, resource, name string) (runtime.Object, error) { ...@@ -89,7 +95,7 @@ func (o *operator) Get(user, resource, name string) (runtime.Object, error) {
// A tenant object will be created if the user is not nil. // A tenant object will be created if the user is not nil.
func (o *operator) Create(user, resource string, obj runtime.Object) (runtime.Object, error) { func (o *operator) Create(user, resource string, obj runtime.Object) (runtime.Object, error) {
if err := authorizer(user, obj); err != nil { if err := appendLabel(user, obj); err != nil {
return nil, err return nil, err
} }
...@@ -114,6 +120,8 @@ func (o *operator) Create(user, resource string, obj runtime.Object) (runtime.Ob ...@@ -114,6 +120,8 @@ func (o *operator) Create(user, resource string, obj runtime.Object) (runtime.Ob
return o.ksClient.NotificationV2().WechatConfigs().Create(context.Background(), obj.(*v2.WechatConfig), v1.CreateOptions{}) return o.ksClient.NotificationV2().WechatConfigs().Create(context.Background(), obj.(*v2.WechatConfig), v1.CreateOptions{})
case v2.ResourcesPluralWechatReceiver: case v2.ResourcesPluralWechatReceiver:
return o.ksClient.NotificationV2().WechatReceivers().Create(context.Background(), obj.(*v2.WechatReceiver), v1.CreateOptions{}) return o.ksClient.NotificationV2().WechatReceivers().Create(context.Background(), obj.(*v2.WechatReceiver), v1.CreateOptions{})
case "secrets":
return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Create(context.Background(), obj.(*corev1.Secret), v1.CreateOptions{})
default: default:
return nil, errors.NewInternalError(nil) return nil, errors.NewInternalError(nil)
} }
...@@ -152,6 +160,8 @@ func (o *operator) Delete(user, resource, name string) error { ...@@ -152,6 +160,8 @@ func (o *operator) Delete(user, resource, name string) error {
return o.ksClient.NotificationV2().WechatConfigs().Delete(context.Background(), name, v1.DeleteOptions{}) return o.ksClient.NotificationV2().WechatConfigs().Delete(context.Background(), name, v1.DeleteOptions{})
case v2.ResourcesPluralWechatReceiver: case v2.ResourcesPluralWechatReceiver:
return o.ksClient.NotificationV2().WechatReceivers().Delete(context.Background(), name, v1.DeleteOptions{}) return o.ksClient.NotificationV2().WechatReceivers().Delete(context.Background(), name, v1.DeleteOptions{})
case "secrets":
return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Delete(context.Background(), name, v1.DeleteOptions{})
default: default:
return errors.NewInternalError(nil) return errors.NewInternalError(nil)
} }
...@@ -159,17 +169,16 @@ func (o *operator) Delete(user, resource, name string) error { ...@@ -159,17 +169,16 @@ func (o *operator) Delete(user, resource, name string) error {
// Update an object, only a global object will be updated if the user is nil. // Update an object, only a global object will be updated if the user is nil.
// If the user is not nil, a tenant object whose tenant label matches the user will be updated. // If the user is not nil, a tenant object whose tenant label matches the user will be updated.
func (o *operator) Update(user, resource string, obj runtime.Object) (runtime.Object, error) { func (o *operator) Update(user, resource, name string, obj runtime.Object) (runtime.Object, error) {
name, err := getName(obj) if err := appendLabel(user, obj); err != nil {
if err != nil {
return nil, err return nil, err
} }
if _, err := o.Get(user, resource, name); err != nil { if old, err := o.Get(user, resource, name); err != nil {
return nil, err return nil, err
} else { } else {
if err := authorizer(user, obj); err != nil { if err := authorizer(user, old); err != nil {
return nil, err return nil, err
} }
} }
...@@ -195,54 +204,13 @@ func (o *operator) Update(user, resource string, obj runtime.Object) (runtime.Ob ...@@ -195,54 +204,13 @@ func (o *operator) Update(user, resource string, obj runtime.Object) (runtime.Ob
return o.ksClient.NotificationV2().WechatConfigs().Update(context.Background(), obj.(*v2.WechatConfig), v1.UpdateOptions{}) return o.ksClient.NotificationV2().WechatConfigs().Update(context.Background(), obj.(*v2.WechatConfig), v1.UpdateOptions{})
case v2.ResourcesPluralWechatReceiver: case v2.ResourcesPluralWechatReceiver:
return o.ksClient.NotificationV2().WechatReceivers().Update(context.Background(), obj.(*v2.WechatReceiver), v1.UpdateOptions{}) return o.ksClient.NotificationV2().WechatReceivers().Update(context.Background(), obj.(*v2.WechatReceiver), v1.UpdateOptions{})
case "secrets":
return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Update(context.Background(), obj.(*corev1.Secret), v1.UpdateOptions{})
default: default:
return nil, errors.NewInternalError(nil) return nil, errors.NewInternalError(nil)
} }
} }
func (o *operator) ListSecret(q *query.Query) (*api.ListResult, error) {
appendManagedLabel(q)
return o.resourceGetter.List("secrets", constants.NotificationSecretNamespace, q)
}
func (o *operator) GetSecret(name string) (interface{}, error) {
obj, err := o.resourceGetter.Get("secrets", constants.NotificationSecretNamespace, name)
if err != nil {
return nil, err
}
if !isManagedByNotification(obj.(*corev1.Secret)) {
return nil, errors.NewForbidden(v2.Resource(obj.GetObjectKind().GroupVersionKind().GroupKind().Kind), "",
fmt.Errorf("secret '%s' is not managed by notification", name))
}
return obj, nil
}
func (o *operator) CreateOrUpdateSecret(obj *corev1.Secret) (*corev1.Secret, error) {
obj.Namespace = constants.NotificationSecretNamespace
if obj.Labels == nil {
obj.Labels = make(map[string]string)
}
obj.Labels[constants.NotificationManagedLabel] = "true"
if obj.ResourceVersion == "" {
return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Create(context.Background(), obj, v1.CreateOptions{})
} else {
return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Update(context.Background(), obj, v1.UpdateOptions{})
}
}
func (o *operator) DeleteSecret(name string) error {
if _, err := o.GetSecret(name); err != nil {
return err
}
return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Delete(context.Background(), name, v1.DeleteOptions{})
}
func (o *operator) GetObject(resource string) runtime.Object { func (o *operator) GetObject(resource string) runtime.Object {
switch resource { switch resource {
...@@ -266,6 +234,8 @@ func (o *operator) GetObject(resource string) runtime.Object { ...@@ -266,6 +234,8 @@ func (o *operator) GetObject(resource string) runtime.Object {
return &v2.WechatConfig{} return &v2.WechatConfig{}
case v2.ResourcesPluralWechatReceiver: case v2.ResourcesPluralWechatReceiver:
return &v2.WechatReceiver{} return &v2.WechatReceiver{}
case "secrets":
return &corev1.Secret{}
default: default:
return nil return nil
} }
...@@ -333,48 +303,30 @@ func isGlobal(obj runtime.Object) bool { ...@@ -333,48 +303,30 @@ func isGlobal(obj runtime.Object) bool {
} }
} }
func appendTenantLabel(user string, q *query.Query) { func appendLabel(user string, obj runtime.Object) error {
if len(q.LabelSelector) > 0 {
q.LabelSelector = q.LabelSelector + ","
}
q.LabelSelector = q.LabelSelector + "type=tenant,user=" + user
}
func appendGlobalLabel(resource string, q *query.Query) {
if len(q.LabelSelector) > 0 { accessor, err := meta.Accessor(obj)
q.LabelSelector = q.LabelSelector + "," if err != nil {
} klog.Errorln(err)
return err
switch resource {
case v2.ResourcesPluralDingTalkConfig, v2.ResourcesPluralEmailConfig,
v2.ResourcesPluralSlackConfig, v2.ResourcesPluralWebhookConfig, v2.ResourcesPluralWechatConfig:
q.LabelSelector = q.LabelSelector + "type=default"
case v2.ResourcesPluralDingTalkReceiver, v2.ResourcesPluralEmailReceiver,
v2.ResourcesPluralSlackReceiver, v2.ResourcesPluralWebhookReceiver, v2.ResourcesPluralWechatReceiver:
q.LabelSelector = q.LabelSelector + "type=global"
} }
}
func appendManagedLabel(q *query.Query) { labels := accessor.GetLabels()
if labels == nil {
if len(q.LabelSelector) > 0 { labels = make(map[string]string)
q.LabelSelector = q.LabelSelector + ","
} }
q.LabelSelector = q.LabelSelector + constants.NotificationManagedLabel + "=" + "true"
}
func isManagedByNotification(secret *corev1.Secret) bool {
return secret.Labels[constants.NotificationManagedLabel] == "true"
}
func getName(obj runtime.Object) (string, error) { if user == "" {
if isConfig(obj) {
accessor, err := meta.Accessor(obj) labels["type"] = "default"
if err != nil { } else {
return "", err labels["type"] = "global"
}
} else {
labels["type"] = "tenant"
labels["user"] = user
} }
return accessor.GetName(), nil accessor.SetLabels(labels)
return nil
} }
...@@ -31,7 +31,7 @@ import ( ...@@ -31,7 +31,7 @@ import (
"testing" "testing"
) )
func TestOperator_ListSecret(t *testing.T) { func TestOperator_List(t *testing.T) {
o := prepare() o := prepare()
tests := []struct { tests := []struct {
result *api.ListResult result *api.ListResult
...@@ -46,7 +46,7 @@ func TestOperator_ListSecret(t *testing.T) { ...@@ -46,7 +46,7 @@ func TestOperator_ListSecret(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
result, err := o.ListSecret(&query.Query{ result, err := o.List("", "secrets", &query.Query{
SortBy: query.FieldName, SortBy: query.FieldName,
Ascending: true, Ascending: true,
}) })
...@@ -64,7 +64,7 @@ func TestOperator_ListSecret(t *testing.T) { ...@@ -64,7 +64,7 @@ func TestOperator_ListSecret(t *testing.T) {
} }
} }
func TestOperator_GetSecret(t *testing.T) { func TestOperator_Get(t *testing.T) {
o := prepare() o := prepare()
tests := []struct { tests := []struct {
result *corev1.Secret result *corev1.Secret
...@@ -83,7 +83,7 @@ func TestOperator_GetSecret(t *testing.T) { ...@@ -83,7 +83,7 @@ func TestOperator_GetSecret(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
result, err := o.GetSecret(test.name) result, err := o.Get("", "secrets", test.name)
if err != nil { if err != nil {
if !reflect.DeepEqual(err, test.expectError) { if !reflect.DeepEqual(err, test.expectError) {
...@@ -98,7 +98,7 @@ func TestOperator_GetSecret(t *testing.T) { ...@@ -98,7 +98,7 @@ func TestOperator_GetSecret(t *testing.T) {
} }
} }
func TestOperator_CreateOrUpdateSecret(t *testing.T) { func TestOperator_Create(t *testing.T) {
o := prepare() o := prepare()
tests := []struct { tests := []struct {
result *corev1.Secret result *corev1.Secret
...@@ -110,12 +110,17 @@ func TestOperator_CreateOrUpdateSecret(t *testing.T) { ...@@ -110,12 +110,17 @@ func TestOperator_CreateOrUpdateSecret(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "test", Name: "test",
Namespace: constants.NotificationSecretNamespace, Namespace: constants.NotificationSecretNamespace,
Labels: map[string]string{constants.NotificationManagedLabel: "true"}, Labels: map[string]string{
"type": "global",
},
}, },
}, },
secret: &corev1.Secret{ secret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "test", Name: "test",
Labels: map[string]string{
"type": "global",
},
}, },
}, },
expectError: nil, expectError: nil,
...@@ -123,7 +128,7 @@ func TestOperator_CreateOrUpdateSecret(t *testing.T) { ...@@ -123,7 +128,7 @@ func TestOperator_CreateOrUpdateSecret(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
result, err := o.CreateOrUpdateSecret(test.secret) result, err := o.Create("", "secrets", test.secret)
if err != nil { if err != nil {
if !reflect.DeepEqual(err, test.expectError) { if !reflect.DeepEqual(err, test.expectError) {
...@@ -138,7 +143,7 @@ func TestOperator_CreateOrUpdateSecret(t *testing.T) { ...@@ -138,7 +143,7 @@ func TestOperator_CreateOrUpdateSecret(t *testing.T) {
} }
} }
func TestOperator_DeleteSecret(t *testing.T) { func TestOperator_Delete(t *testing.T) {
o := prepare() o := prepare()
tests := []struct { tests := []struct {
name string name string
...@@ -151,7 +156,7 @@ func TestOperator_DeleteSecret(t *testing.T) { ...@@ -151,7 +156,7 @@ func TestOperator_DeleteSecret(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
err := o.DeleteSecret(test.name) err := o.Delete("", "secrets", test.name)
if err != nil { if err != nil {
if test.expectError != nil && test.expectError.Error() == err.Error() { if test.expectError != nil && test.expectError.Error() == err.Error() {
continue continue
...@@ -169,7 +174,9 @@ var ( ...@@ -169,7 +174,9 @@ var (
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo1", Name: "foo1",
Namespace: constants.NotificationSecretNamespace, Namespace: constants.NotificationSecretNamespace,
Labels: map[string]string{constants.NotificationManagedLabel: "true"}, Labels: map[string]string{
"type": "global",
},
}, },
} }
...@@ -177,7 +184,9 @@ var ( ...@@ -177,7 +184,9 @@ var (
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo2", Name: "foo2",
Namespace: constants.NotificationSecretNamespace, Namespace: constants.NotificationSecretNamespace,
Labels: map[string]string{constants.NotificationManagedLabel: "true"}, Labels: map[string]string{
"type": "global",
},
}, },
} }
...@@ -185,7 +194,9 @@ var ( ...@@ -185,7 +194,9 @@ var (
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo3", Name: "foo3",
Namespace: constants.NotificationSecretNamespace, Namespace: constants.NotificationSecretNamespace,
Labels: map[string]string{constants.NotificationManagedLabel: "true"}, Labels: map[string]string{
"type": "global",
},
}, },
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册