-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: simple apisix sdk Signed-off-by: Ling Samuel (WSL) <[email protected]> * rollback changes * fmt code Signed-off-by: Ling Samuel (WSL) <[email protected]> * rollback types changes * simple rename Signed-off-by: Ling Samuel (WSL) <[email protected]> * generic client * fix service types Signed-off-by: Ling Samuel (WSL) <[email protected]> * remove v2 version admin API Signed-off-by: Ling Samuel (WSL) <[email protected]> * feat: add route api Signed-off-by: Ling Samuel (WSL) <[email protected]> * remove upstream api Signed-off-by: Ling Samuel (WSL) <[email protected]> --------- Signed-off-by: Ling Samuel (WSL) <[email protected]>
- Loading branch information
1 parent
c593db6
commit 0245e46
Showing
18 changed files
with
876 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package apisix | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/api7/adc/pkg/api/apisix/types" | ||
) | ||
|
||
type Cluster interface { | ||
Route() Route | ||
Service() Service | ||
} | ||
|
||
type Route interface { | ||
Get(ctx context.Context, name string) (*types.Route, error) | ||
List(ctx context.Context) ([]*types.Route, error) | ||
Create(ctx context.Context, ups *types.Route) (*types.Route, error) | ||
Delete(ctx context.Context, name string) error | ||
Update(ctx context.Context, ups *types.Route) (*types.Route, error) | ||
} | ||
|
||
type Service interface { | ||
Get(ctx context.Context, name string) (*types.Service, error) | ||
List(ctx context.Context) ([]*types.Service, error) | ||
Create(ctx context.Context, ups *types.Service) (*types.Service, error) | ||
Delete(ctx context.Context, name string) error | ||
Update(ctx context.Context, ups *types.Service) (*types.Service, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
package apisix | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"strings" | ||
"time" | ||
|
||
"go.uber.org/multierr" | ||
) | ||
|
||
var ( | ||
ErrNotFound = fmt.Errorf("not found") | ||
ErrStillInUse = errors.New("still in use") // We should use force mode | ||
ErrFunctionDisabled = errors.New("function disabled") | ||
) | ||
|
||
type Client struct { | ||
baseURL string | ||
adminKey string | ||
|
||
cli *http.Client | ||
} | ||
|
||
func newClient(baseURL, adminKey string) *Client { | ||
return &Client{ | ||
baseURL: baseURL, | ||
adminKey: adminKey, | ||
cli: &http.Client{ | ||
Timeout: 5 * time.Second, | ||
}, | ||
} | ||
} | ||
|
||
func (c *Client) setAdminKey(req *http.Request) { | ||
if c.adminKey != "" { | ||
req.Header.Set("X-API-Key", c.adminKey) | ||
} | ||
} | ||
|
||
func (c *Client) do(req *http.Request) (*http.Response, error) { | ||
c.setAdminKey(req) | ||
return c.cli.Do(req) | ||
} | ||
|
||
func (c *Client) isFunctionDisabled(body string) bool { | ||
return strings.Contains(body, "is disabled") | ||
} | ||
|
||
func (c *Client) getResource(ctx context.Context, url string) (*item, error) { | ||
var res getResponse | ||
err := makeGetRequest(c, ctx, url, &res) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &res, nil | ||
} | ||
|
||
func (c *Client) listResource(ctx context.Context, url string) (items, error) { | ||
var res listResponse | ||
|
||
err := makeGetRequest(c, ctx, url, &res) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return res.List, nil | ||
} | ||
|
||
func (c *Client) createResource(ctx context.Context, url string, body []byte) (*item, error) { | ||
var cr createResponse | ||
err := makePutRequest(c, ctx, url, body, &cr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &cr, nil | ||
} | ||
|
||
func (c *Client) updateResource(ctx context.Context, url string, body []byte) (*item, error) { | ||
var ur updateResponse | ||
|
||
err := makePutRequest(c, ctx, url, body, &ur) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &ur, nil | ||
} | ||
|
||
func (c *Client) deleteResource(ctx context.Context, url string) error { | ||
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, url, nil) | ||
if err != nil { | ||
return err | ||
} | ||
resp, err := c.do(req) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusNotFound { | ||
message := readBody(resp.Body) | ||
if c.isFunctionDisabled(message) { | ||
return ErrFunctionDisabled | ||
} | ||
err = multierr.Append(err, fmt.Errorf("unexpected status code %d", resp.StatusCode)) | ||
err = multierr.Append(err, fmt.Errorf("error message: %s", message)) | ||
if strings.Contains(message, "still using") { | ||
return ErrStillInUse | ||
} | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func readBody(r io.ReadCloser) string { | ||
defer r.Close() | ||
|
||
data, err := io.ReadAll(r) | ||
if err != nil { | ||
return "" | ||
} | ||
return string(data) | ||
} | ||
|
||
// getSchema returns the schema of APISIX object. | ||
func (c *Client) getSchema(ctx context.Context, url string) (string, error) { | ||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) | ||
if err != nil { | ||
return "", err | ||
} | ||
resp, err := c.do(req) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
defer resp.Body.Close() | ||
if resp.StatusCode != http.StatusOK { | ||
if resp.StatusCode == http.StatusNotFound { | ||
return "", ErrNotFound | ||
} else { | ||
err = multierr.Append(err, fmt.Errorf("unexpected status code %d", resp.StatusCode)) | ||
err = multierr.Append(err, fmt.Errorf("error message: %s", readBody(resp.Body))) | ||
} | ||
return "", err | ||
} | ||
|
||
return readBody(resp.Body), nil | ||
} | ||
|
||
// getList returns a list of string. | ||
func (c *Client) getList(ctx context.Context, url string) ([]string, error) { | ||
var listResp map[string]interface{} | ||
err := makeGetRequest(c, ctx, url, &listResp) | ||
if err != nil { | ||
return nil, err | ||
} | ||
res := make([]string, 0, len(listResp)) | ||
|
||
for name := range listResp { | ||
res = append(res, name) | ||
} | ||
return res, nil | ||
} | ||
|
||
func makeGetRequest[T any](c *Client, ctx context.Context, url string, result *T) error { | ||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) | ||
if err != nil { | ||
return err | ||
} | ||
resp, err := c.do(req) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer resp.Body.Close() | ||
if resp.StatusCode != http.StatusOK { | ||
body := readBody(resp.Body) | ||
if c.isFunctionDisabled(body) { | ||
return ErrFunctionDisabled | ||
} | ||
err = multierr.Append(err, fmt.Errorf("unexpected status code %d", resp.StatusCode)) | ||
err = multierr.Append(err, fmt.Errorf("error message: %s", body)) | ||
return err | ||
} | ||
|
||
dec := json.NewDecoder(resp.Body) | ||
if err := dec.Decode(result); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func makePutRequest[T any](c *Client, ctx context.Context, url string, body []byte, result *T) error { | ||
req, err := http.NewRequestWithContext(ctx, http.MethodPut, url, bytes.NewReader(body)) | ||
if err != nil { | ||
return err | ||
} | ||
resp, err := c.do(req) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { | ||
body := readBody(resp.Body) | ||
if c.isFunctionDisabled(body) { | ||
return ErrFunctionDisabled | ||
} | ||
err = multierr.Append(err, fmt.Errorf("unexpected status code %d", resp.StatusCode)) | ||
err = multierr.Append(err, fmt.Errorf("error message: %s", body)) | ||
return err | ||
} | ||
dec := json.NewDecoder(resp.Body) | ||
if err := dec.Decode(result); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.