Skip to content

Commit

Permalink
feat: support global rules for Manager API (#1057)
Browse files Browse the repository at this point in the history
* feat: support global rules
  • Loading branch information
nic-chen authored Dec 28, 2020
1 parent b194c61 commit 822aa6d
Show file tree
Hide file tree
Showing 8 changed files with 781 additions and 8 deletions.
6 changes: 6 additions & 0 deletions api/internal/core/entity/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,12 @@ type Script struct {
Script interface{} `json:"script,omitempty"`
}

// swagger:model GlobalPlugins
type GlobalPlugins struct {
ID interface{} `json:"id"`
Plugins map[string]interface{} `json:"plugins,omitempty"`
}

type ServerInfo struct {
BaseInfo
LastReportTime int64 `json:"last_report_time,omitempty"`
Expand Down
24 changes: 22 additions & 2 deletions api/internal/core/store/storehub.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
HubKeySsl HubKey = "ssl"
HubKeyUpstream HubKey = "upstream"
HubKeyScript HubKey = "script"
HubKeyGlobalRule HubKey = "global_rule"
HubKeyServerInfo HubKey = `server_info`
)

Expand All @@ -42,8 +43,15 @@ var (
)

func InitStore(key HubKey, opt GenericStoreOption) error {
if key == HubKeyConsumer || key == HubKeyRoute ||
key == HubKeyService || key == HubKeySsl || key == HubKeyUpstream {
hubsNeedCheck := map[HubKey]bool{
HubKeyConsumer: true,
HubKeyRoute: true,
HubKeySsl: true,
HubKeyService: true,
HubKeyUpstream: true,
HubKeyGlobalRule: true,
}
if _, ok := hubsNeedCheck[key]; ok {
validator, err := NewAPISIXJsonSchemaValidator("main." + string(key))
if err != nil {
return err
Expand Down Expand Up @@ -145,6 +153,18 @@ func InitStores() error {
return err
}

err = InitStore(HubKeyGlobalRule, GenericStoreOption{
BasePath: "/apisix/global_rules",
ObjType: reflect.TypeOf(entity.GlobalPlugins{}),
KeyFunc: func(obj interface{}) string {
r := obj.(*entity.GlobalPlugins)
return utils.InterfaceToString(r.ID)
},
})
if err != nil {
return err
}

err = InitStore(HubKeyServerInfo, GenericStoreOption{
BasePath: "/apisix/data_plane/server_info",
ObjType: reflect.TypeOf(entity.ServerInfo{}),
Expand Down
11 changes: 6 additions & 5 deletions api/internal/filter/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ import (
)

var resources = map[string]string{
"routes": "route",
"upstreams": "upstream",
"services": "service",
"consumers": "consumer",
"ssl": "ssl",
"routes": "route",
"upstreams": "upstream",
"services": "service",
"consumers": "consumer",
"ssl": "ssl",
"global_rules": "global_rule",
}

const (
Expand Down
175 changes: 175 additions & 0 deletions api/internal/handler/global_rule/global_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* 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 global_rule

import (
"encoding/json"
"reflect"

"github.com/gin-gonic/gin"
"github.com/shiningrush/droplet"
"github.com/shiningrush/droplet/wrapper"
wgin "github.com/shiningrush/droplet/wrapper/gin"

"github.com/apisix/manager-api/internal/core/entity"
"github.com/apisix/manager-api/internal/core/store"
"github.com/apisix/manager-api/internal/handler"
"github.com/apisix/manager-api/internal/utils"
"github.com/apisix/manager-api/internal/utils/consts"
)

type Handler struct {
globalRuleStore store.Interface
}

func NewHandler() (handler.RouteRegister, error) {
return &Handler{
globalRuleStore: store.GetStore(store.HubKeyGlobalRule),
}, nil
}

func (h *Handler) ApplyRoute(r *gin.Engine) {
// global plugins
r.GET("/apisix/admin/global_rules/:id", wgin.Wraps(h.Get,
wrapper.InputType(reflect.TypeOf(GetInput{}))))
r.GET("/apisix/admin/global_rules", wgin.Wraps(h.List,
wrapper.InputType(reflect.TypeOf(ListInput{}))))
r.PUT("/apisix/admin/global_rules/:id", wgin.Wraps(h.Set,
wrapper.InputType(reflect.TypeOf(entity.GlobalPlugins{}))))
r.PUT("/apisix/admin/global_rules", wgin.Wraps(h.Set,
wrapper.InputType(reflect.TypeOf(entity.GlobalPlugins{}))))

r.PATCH("/apisix/admin/global_rules/:id", consts.ErrorWrapper(Patch))
r.PATCH("/apisix/admin/global_rules/:id/*path", consts.ErrorWrapper(Patch))

r.DELETE("/apisix/admin/global_rules/:id", wgin.Wraps(h.BatchDelete,
wrapper.InputType(reflect.TypeOf(BatchDeleteInput{}))))
}

type GetInput struct {
ID string `auto_read:"id,path" validate:"required"`
}

func (h *Handler) Get(c droplet.Context) (interface{}, error) {
input := c.Input().(*GetInput)

r, err := h.globalRuleStore.Get(input.ID)
if err != nil {
return handler.SpecCodeResponse(err), err
}
return r, nil
}

type ListInput struct {
store.Pagination
}

// swagger:operation GET /apisix/admin/global_rules getGlobalRuleList
//
// Return the global rule list according to the specified page number and page size.
//
// ---
// produces:
// - application/json
// parameters:
// - name: page
// in: query
// description: page number
// required: false
// type: integer
// - name: page_size
// in: query
// description: page size
// required: false
// type: integer
// responses:
// '0':
// description: list response
// schema:
// type: array
// items:
// "$ref": "#/definitions/GlobalPlugins"
// default:
// description: unexpected error
// schema:
// "$ref": "#/definitions/ApiError"
func (h *Handler) List(c droplet.Context) (interface{}, error) {
input := c.Input().(*ListInput)

ret, err := h.globalRuleStore.List(store.ListInput{
PageSize: input.PageSize,
PageNumber: input.PageNumber,
})
if err != nil {
return nil, err
}

return ret, nil
}

func (h *Handler) Set(c droplet.Context) (interface{}, error) {
input := c.Input().(*entity.GlobalPlugins)

if err := h.globalRuleStore.Create(c.Context(), input); err != nil {
return handler.SpecCodeResponse(err), err
}

return nil, nil
}

func Patch(c *gin.Context) (interface{}, error) {
reqBody, _ := c.GetRawData()
ID := c.Param("id")
subPath := c.Param("path")

routeStore := store.GetStore(store.HubKeyGlobalRule)
stored, err := routeStore.Get(ID)
if err != nil {
return handler.SpecCodeResponse(err), err
}

res, err := utils.MergePatch(stored, subPath, reqBody)
if err != nil {
return handler.SpecCodeResponse(err), err
}

var globalRule entity.GlobalPlugins
err = json.Unmarshal(res, &globalRule)
if err != nil {
return handler.SpecCodeResponse(err), err
}

if err := routeStore.Update(c, &globalRule, false); err != nil {
return handler.SpecCodeResponse(err), err
}

return nil, nil
}

type BatchDeleteInput struct {
ID string `auto_read:"id,path"`
}

func (h *Handler) BatchDelete(c droplet.Context) (interface{}, error) {
input := c.Input().(*BatchDeleteInput)

if err := h.globalRuleStore.BatchDelete(c.Context(), []string{input.ID}); err != nil {
return handler.SpecCodeResponse(err), err
}

return nil, nil
}
Loading

0 comments on commit 822aa6d

Please sign in to comment.