mirror of
https://github.com/netbirdio/netbird.git
synced 2026-03-31 06:24:18 -04:00
[misc] Add cloud api spec to public open api with rest client (#5222)
This commit is contained in:
82
shared/management/client/rest/billing.go
Normal file
82
shared/management/client/rest/billing.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// BillingAPI APIs for billing and invoices
|
||||
type BillingAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// GetUsage retrieves current usage statistics for the account
|
||||
// See more: https://docs.netbird.io/api/resources/billing#get-current-usage
|
||||
func (a *BillingAPI) GetUsage(ctx context.Context) (*api.UsageStats, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/billing/usage", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.UsageStats](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// GetSubscription retrieves the current subscription details
|
||||
// See more: https://docs.netbird.io/api/resources/billing#get-current-subscription
|
||||
func (a *BillingAPI) GetSubscription(ctx context.Context) (*api.Subscription, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/billing/subscription", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.Subscription](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// GetInvoices retrieves the account's paid invoices
|
||||
// See more: https://docs.netbird.io/api/resources/billing#list-all-invoices
|
||||
func (a *BillingAPI) GetInvoices(ctx context.Context) ([]api.InvoiceResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/billing/invoices", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.InvoiceResponse](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// GetInvoicePDF retrieves the invoice PDF URL
|
||||
// See more: https://docs.netbird.io/api/resources/billing#get-invoice-pdf
|
||||
func (a *BillingAPI) GetInvoicePDF(ctx context.Context, invoiceID string) (*api.InvoicePDFResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/billing/invoices/"+invoiceID+"/pdf", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.InvoicePDFResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// GetInvoiceCSV retrieves the invoice CSV content
|
||||
// See more: https://docs.netbird.io/api/resources/billing#get-invoice-csv
|
||||
func (a *BillingAPI) GetInvoiceCSV(ctx context.Context, invoiceID string) (string, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/billing/invoices/"+invoiceID+"/csv", nil, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[string](resp)
|
||||
return ret, err
|
||||
}
|
||||
194
shared/management/client/rest/billing_test.go
Normal file
194
shared/management/client/rest/billing_test.go
Normal file
@@ -0,0 +1,194 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var (
|
||||
testUsageStats = api.UsageStats{
|
||||
ActiveUsers: 15,
|
||||
TotalUsers: 20,
|
||||
ActivePeers: 10,
|
||||
TotalPeers: 25,
|
||||
}
|
||||
|
||||
testSubscription = api.Subscription{
|
||||
Active: true,
|
||||
PlanTier: "basic",
|
||||
PriceId: "price_1HhxOp",
|
||||
Currency: "USD",
|
||||
Price: 1000,
|
||||
Provider: "stripe",
|
||||
UpdatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
|
||||
testInvoice = api.InvoiceResponse{
|
||||
Id: "inv_123",
|
||||
PeriodStart: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
PeriodEnd: time.Date(2024, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||
Type: "invoice",
|
||||
}
|
||||
|
||||
testInvoicePDF = api.InvoicePDFResponse{
|
||||
Url: "https://example.com/invoice.pdf",
|
||||
}
|
||||
)
|
||||
|
||||
func TestBilling_GetUsage_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/usage", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testUsageStats)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetUsage(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUsageStats, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBilling_GetUsage_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/usage", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetUsage(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBilling_GetSubscription_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/subscription", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testSubscription)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetSubscription(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testSubscription, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBilling_GetSubscription_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/subscription", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetSubscription(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBilling_GetInvoices_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/invoices", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.InvoiceResponse{testInvoice})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetInvoices(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testInvoice, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestBilling_GetInvoices_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/invoices", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetInvoices(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBilling_GetInvoicePDF_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/invoices/inv_123/pdf", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testInvoicePDF)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetInvoicePDF(context.Background(), "inv_123")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testInvoicePDF, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBilling_GetInvoicePDF_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/invoices/inv_123/pdf", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetInvoicePDF(context.Background(), "inv_123")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBilling_GetInvoiceCSV_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/invoices/inv_123/csv", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal("col1,col2\nval1,val2")
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetInvoiceCSV(context.Background(), "inv_123")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "col1,col2\nval1,val2", ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBilling_GetInvoiceCSV_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/billing/invoices/inv_123/csv", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Billing.GetInvoiceCSV(context.Background(), "inv_123")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
@@ -73,6 +73,38 @@ type Client struct {
|
||||
// Events NetBird Events APIs
|
||||
// see more: https://docs.netbird.io/api/resources/events
|
||||
Events *EventsAPI
|
||||
|
||||
// Billing NetBird Billing APIs for subscriptions, plans, and invoices
|
||||
// see more: https://docs.netbird.io/api/resources/billing
|
||||
Billing *BillingAPI
|
||||
|
||||
// MSP NetBird MSP tenant management APIs
|
||||
// see more: https://docs.netbird.io/api/resources/msp
|
||||
MSP *MSPAPI
|
||||
|
||||
// EDR NetBird EDR integration APIs (Intune, SentinelOne, Falcon, Huntress)
|
||||
// see more: https://docs.netbird.io/api/resources/edr
|
||||
EDR *EDRAPI
|
||||
|
||||
// SCIM NetBird SCIM IDP integration APIs
|
||||
// see more: https://docs.netbird.io/api/resources/scim
|
||||
SCIM *SCIMAPI
|
||||
|
||||
// EventStreaming NetBird Event Streaming integration APIs
|
||||
// see more: https://docs.netbird.io/api/resources/event-streaming
|
||||
EventStreaming *EventStreamingAPI
|
||||
|
||||
// IdentityProviders NetBird Identity Providers APIs
|
||||
// see more: https://docs.netbird.io/api/resources/identity-providers
|
||||
IdentityProviders *IdentityProvidersAPI
|
||||
|
||||
// Ingress NetBird Ingress Peers APIs
|
||||
// see more: https://docs.netbird.io/api/resources/ingress-ports
|
||||
Ingress *IngressAPI
|
||||
|
||||
// Instance NetBird Instance API
|
||||
// see more: https://docs.netbird.io/api/resources/instance
|
||||
Instance *InstanceAPI
|
||||
}
|
||||
|
||||
// New initialize new Client instance using PAT token
|
||||
@@ -120,6 +152,14 @@ func (c *Client) initialize() {
|
||||
c.DNSZones = &DNSZonesAPI{c}
|
||||
c.GeoLocation = &GeoLocationAPI{c}
|
||||
c.Events = &EventsAPI{c}
|
||||
c.Billing = &BillingAPI{c}
|
||||
c.MSP = &MSPAPI{c}
|
||||
c.EDR = &EDRAPI{c}
|
||||
c.SCIM = &SCIMAPI{c}
|
||||
c.EventStreaming = &EventStreamingAPI{c}
|
||||
c.IdentityProviders = &IdentityProvidersAPI{c}
|
||||
c.Ingress = &IngressAPI{c}
|
||||
c.Instance = &InstanceAPI{c}
|
||||
}
|
||||
|
||||
// NewRequest creates and executes new management API request
|
||||
|
||||
307
shared/management/client/rest/edr.go
Normal file
307
shared/management/client/rest/edr.go
Normal file
@@ -0,0 +1,307 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// EDRAPI APIs for EDR integrations (Intune, SentinelOne, Falcon, Huntress)
|
||||
type EDRAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// GetIntuneIntegration retrieves the EDR Intune integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#get-intune-integration
|
||||
func (a *EDRAPI) GetIntuneIntegration(ctx context.Context) (*api.EDRIntuneResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/edr/intune", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRIntuneResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// CreateIntuneIntegration creates a new EDR Intune integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#create-intune-integration
|
||||
func (a *EDRAPI) CreateIntuneIntegration(ctx context.Context, request api.EDRIntuneRequest) (*api.EDRIntuneResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/edr/intune", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRIntuneResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// UpdateIntuneIntegration updates an existing EDR Intune integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#update-intune-integration
|
||||
func (a *EDRAPI) UpdateIntuneIntegration(ctx context.Context, request api.EDRIntuneRequest) (*api.EDRIntuneResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/integrations/edr/intune", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRIntuneResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// DeleteIntuneIntegration deletes the EDR Intune integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#delete-intune-integration
|
||||
func (a *EDRAPI) DeleteIntuneIntegration(ctx context.Context) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/integrations/edr/intune", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSentinelOneIntegration retrieves the EDR SentinelOne integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#get-sentinelone-integration
|
||||
func (a *EDRAPI) GetSentinelOneIntegration(ctx context.Context) (*api.EDRSentinelOneResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/edr/sentinelone", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRSentinelOneResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// CreateSentinelOneIntegration creates a new EDR SentinelOne integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#create-sentinelone-integration
|
||||
func (a *EDRAPI) CreateSentinelOneIntegration(ctx context.Context, request api.EDRSentinelOneRequest) (*api.EDRSentinelOneResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/edr/sentinelone", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRSentinelOneResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// UpdateSentinelOneIntegration updates an existing EDR SentinelOne integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#update-sentinelone-integration
|
||||
func (a *EDRAPI) UpdateSentinelOneIntegration(ctx context.Context, request api.EDRSentinelOneRequest) (*api.EDRSentinelOneResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/integrations/edr/sentinelone", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRSentinelOneResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// DeleteSentinelOneIntegration deletes the EDR SentinelOne integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#delete-sentinelone-integration
|
||||
func (a *EDRAPI) DeleteSentinelOneIntegration(ctx context.Context) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/integrations/edr/sentinelone", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFalconIntegration retrieves the EDR Falcon integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#get-falcon-integration
|
||||
func (a *EDRAPI) GetFalconIntegration(ctx context.Context) (*api.EDRFalconResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/edr/falcon", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRFalconResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// CreateFalconIntegration creates a new EDR Falcon integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#create-falcon-integration
|
||||
func (a *EDRAPI) CreateFalconIntegration(ctx context.Context, request api.EDRFalconRequest) (*api.EDRFalconResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/edr/falcon", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRFalconResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// UpdateFalconIntegration updates an existing EDR Falcon integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#update-falcon-integration
|
||||
func (a *EDRAPI) UpdateFalconIntegration(ctx context.Context, request api.EDRFalconRequest) (*api.EDRFalconResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/integrations/edr/falcon", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRFalconResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// DeleteFalconIntegration deletes the EDR Falcon integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#delete-falcon-integration
|
||||
func (a *EDRAPI) DeleteFalconIntegration(ctx context.Context) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/integrations/edr/falcon", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetHuntressIntegration retrieves the EDR Huntress integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#get-huntress-integration
|
||||
func (a *EDRAPI) GetHuntressIntegration(ctx context.Context) (*api.EDRHuntressResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/edr/huntress", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRHuntressResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// CreateHuntressIntegration creates a new EDR Huntress integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#create-huntress-integration
|
||||
func (a *EDRAPI) CreateHuntressIntegration(ctx context.Context, request api.EDRHuntressRequest) (*api.EDRHuntressResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/edr/huntress", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRHuntressResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// UpdateHuntressIntegration updates an existing EDR Huntress integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#update-huntress-integration
|
||||
func (a *EDRAPI) UpdateHuntressIntegration(ctx context.Context, request api.EDRHuntressRequest) (*api.EDRHuntressResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/integrations/edr/huntress", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.EDRHuntressResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// DeleteHuntressIntegration deletes the EDR Huntress integration
|
||||
// See more: https://docs.netbird.io/api/resources/edr#delete-huntress-integration
|
||||
func (a *EDRAPI) DeleteHuntressIntegration(ctx context.Context) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/integrations/edr/huntress", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BypassPeerCompliance bypasses compliance for a non-compliant peer
|
||||
// See more: https://docs.netbird.io/api/resources/edr#bypass-peer-compliance
|
||||
func (a *EDRAPI) BypassPeerCompliance(ctx context.Context, peerID string) (*api.BypassResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/peers/"+peerID+"/edr/bypass", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.BypassResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// RevokePeerBypass revokes the compliance bypass for a peer
|
||||
// See more: https://docs.netbird.io/api/resources/edr#revoke-peer-bypass
|
||||
func (a *EDRAPI) RevokePeerBypass(ctx context.Context, peerID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/peers/"+peerID+"/edr/bypass", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListBypassedPeers returns all peers that have compliance bypassed
|
||||
// See more: https://docs.netbird.io/api/resources/edr#list-all-bypassed-peers
|
||||
func (a *EDRAPI) ListBypassedPeers(ctx context.Context) ([]api.BypassResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers/edr/bypassed", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.BypassResponse](resp)
|
||||
return ret, err
|
||||
}
|
||||
422
shared/management/client/rest/edr_test.go
Normal file
422
shared/management/client/rest/edr_test.go
Normal file
@@ -0,0 +1,422 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var (
|
||||
testIntuneResponse = api.EDRIntuneResponse{
|
||||
AccountId: "acc-1",
|
||||
ClientId: "client-1",
|
||||
TenantId: "tenant-1",
|
||||
Enabled: true,
|
||||
Id: 1,
|
||||
Groups: []api.Group{},
|
||||
LastSyncedInterval: 24,
|
||||
CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
LastSyncedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
CreatedBy: "user-1",
|
||||
}
|
||||
|
||||
testSentinelOneResponse = api.EDRSentinelOneResponse{
|
||||
AccountId: "acc-1",
|
||||
ApiUrl: "https://sentinelone.example.com",
|
||||
Enabled: true,
|
||||
Id: 2,
|
||||
Groups: []api.Group{},
|
||||
LastSyncedInterval: 24,
|
||||
MatchAttributes: api.SentinelOneMatchAttributes{},
|
||||
CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
LastSyncedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
CreatedBy: "user-1",
|
||||
}
|
||||
|
||||
testFalconResponse = api.EDRFalconResponse{
|
||||
AccountId: "acc-1",
|
||||
CloudId: "us-1",
|
||||
Enabled: true,
|
||||
Id: 3,
|
||||
Groups: []api.Group{},
|
||||
ZtaScoreThreshold: 50,
|
||||
CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
LastSyncedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
CreatedBy: "user-1",
|
||||
}
|
||||
|
||||
testHuntressResponse = api.EDRHuntressResponse{
|
||||
AccountId: "acc-1",
|
||||
Enabled: true,
|
||||
Id: 4,
|
||||
Groups: []api.Group{},
|
||||
LastSyncedInterval: 24,
|
||||
MatchAttributes: api.HuntressMatchAttributes{},
|
||||
CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
LastSyncedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
CreatedBy: "user-1",
|
||||
}
|
||||
|
||||
testBypassResponse = api.BypassResponse{
|
||||
PeerId: "peer-1",
|
||||
}
|
||||
)
|
||||
|
||||
// Intune tests
|
||||
|
||||
func TestEDR_GetIntuneIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/intune", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testIntuneResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.GetIntuneIntegration(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIntuneResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_GetIntuneIntegration_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/intune", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.GetIntuneIntegration(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_CreateIntuneIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/intune", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.EDRIntuneRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "client-1", req.ClientId)
|
||||
retBytes, _ := json.Marshal(testIntuneResponse)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.CreateIntuneIntegration(context.Background(), api.EDRIntuneRequest{
|
||||
ClientId: "client-1",
|
||||
Secret: "secret",
|
||||
TenantId: "tenant-1",
|
||||
Groups: []string{"group-1"},
|
||||
LastSyncedInterval: 24,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIntuneResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_CreateIntuneIntegration_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/intune", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.CreateIntuneIntegration(context.Background(), api.EDRIntuneRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_UpdateIntuneIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/intune", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
retBytes, _ := json.Marshal(testIntuneResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.UpdateIntuneIntegration(context.Background(), api.EDRIntuneRequest{
|
||||
ClientId: "client-1",
|
||||
Secret: "new-secret",
|
||||
TenantId: "tenant-1",
|
||||
Groups: []string{"group-1"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIntuneResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_DeleteIntuneIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/intune", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.EDR.DeleteIntuneIntegration(context.Background())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_DeleteIntuneIntegration_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/intune", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.EDR.DeleteIntuneIntegration(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
// SentinelOne tests
|
||||
|
||||
func TestEDR_GetSentinelOneIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/sentinelone", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testSentinelOneResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.GetSentinelOneIntegration(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testSentinelOneResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_CreateSentinelOneIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/sentinelone", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testSentinelOneResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.CreateSentinelOneIntegration(context.Background(), api.EDRSentinelOneRequest{
|
||||
ApiToken: "token",
|
||||
ApiUrl: "https://sentinelone.example.com",
|
||||
Groups: []string{"group-1"},
|
||||
LastSyncedInterval: 24,
|
||||
MatchAttributes: api.SentinelOneMatchAttributes{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testSentinelOneResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_DeleteSentinelOneIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/sentinelone", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.EDR.DeleteSentinelOneIntegration(context.Background())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// Falcon tests
|
||||
|
||||
func TestEDR_GetFalconIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/falcon", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testFalconResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.GetFalconIntegration(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testFalconResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_CreateFalconIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/falcon", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testFalconResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.CreateFalconIntegration(context.Background(), api.EDRFalconRequest{
|
||||
ClientId: "client-1",
|
||||
Secret: "secret",
|
||||
CloudId: "us-1",
|
||||
Groups: []string{"group-1"},
|
||||
ZtaScoreThreshold: 50,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testFalconResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_DeleteFalconIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/falcon", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.EDR.DeleteFalconIntegration(context.Background())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// Huntress tests
|
||||
|
||||
func TestEDR_GetHuntressIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/huntress", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testHuntressResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.GetHuntressIntegration(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testHuntressResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_CreateHuntressIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/huntress", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testHuntressResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.CreateHuntressIntegration(context.Background(), api.EDRHuntressRequest{
|
||||
ApiKey: "key",
|
||||
ApiSecret: "secret",
|
||||
Groups: []string{"group-1"},
|
||||
LastSyncedInterval: 24,
|
||||
MatchAttributes: api.HuntressMatchAttributes{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testHuntressResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_DeleteHuntressIntegration_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/edr/huntress", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.EDR.DeleteHuntressIntegration(context.Background())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// Peer bypass tests
|
||||
|
||||
func TestEDR_BypassPeerCompliance_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/peer-1/edr/bypass", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testBypassResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.BypassPeerCompliance(context.Background(), "peer-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testBypassResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_BypassPeerCompliance_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/peer-1/edr/bypass", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Bad request", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.BypassPeerCompliance(context.Background(), "peer-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Bad request", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_RevokePeerBypass_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/peer-1/edr/bypass", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.EDR.RevokePeerBypass(context.Background(), "peer-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_RevokePeerBypass_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/peer-1/edr/bypass", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.EDR.RevokePeerBypass(context.Background(), "peer-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_ListBypassedPeers_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/edr/bypassed", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.BypassResponse{testBypassResponse})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.ListBypassedPeers(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testBypassResponse, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestEDR_ListBypassedPeers_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/edr/bypassed", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EDR.ListBypassedPeers(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
92
shared/management/client/rest/event_streaming.go
Normal file
92
shared/management/client/rest/event_streaming.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// EventStreamingAPI APIs for event streaming integrations
|
||||
type EventStreamingAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List retrieves all event streaming integrations
|
||||
// See more: https://docs.netbird.io/api/resources/event-streaming#list-all-event-streaming-integrations
|
||||
func (a *EventStreamingAPI) List(ctx context.Context) ([]api.IntegrationResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/event-streaming", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.IntegrationResponse](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves a specific event streaming integration by ID
|
||||
// See more: https://docs.netbird.io/api/resources/event-streaming#retrieve-an-event-streaming-integration
|
||||
func (a *EventStreamingAPI) Get(ctx context.Context, integrationID int) (*api.IntegrationResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/event-streaming/"+strconv.Itoa(integrationID), nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IntegrationResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create creates a new event streaming integration
|
||||
// See more: https://docs.netbird.io/api/resources/event-streaming#create-an-event-streaming-integration
|
||||
func (a *EventStreamingAPI) Create(ctx context.Context, request api.CreateIntegrationRequest) (*api.IntegrationResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/event-streaming", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IntegrationResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update updates an existing event streaming integration
|
||||
// See more: https://docs.netbird.io/api/resources/event-streaming#update-an-event-streaming-integration
|
||||
func (a *EventStreamingAPI) Update(ctx context.Context, integrationID int, request api.CreateIntegrationRequest) (*api.IntegrationResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/event-streaming/"+strconv.Itoa(integrationID), bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IntegrationResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete deletes an event streaming integration
|
||||
// See more: https://docs.netbird.io/api/resources/event-streaming#delete-an-event-streaming-integration
|
||||
func (a *EventStreamingAPI) Delete(ctx context.Context, integrationID int) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/event-streaming/"+strconv.Itoa(integrationID), nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
194
shared/management/client/rest/event_streaming_test.go
Normal file
194
shared/management/client/rest/event_streaming_test.go
Normal file
@@ -0,0 +1,194 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var (
|
||||
testIntegrationResponse = api.IntegrationResponse{
|
||||
Id: ptr[int64](1),
|
||||
AccountId: ptr("acc-1"),
|
||||
Platform: (*api.IntegrationResponsePlatform)(ptr("datadog")),
|
||||
Enabled: ptr(true),
|
||||
Config: &map[string]string{"api_key": "****"},
|
||||
CreatedAt: ptr(time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
UpdatedAt: ptr(time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
}
|
||||
)
|
||||
|
||||
func TestEventStreaming_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.IntegrationResponse{testIntegrationResponse})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EventStreaming.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testIntegrationResponse, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventStreaming_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EventStreaming.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventStreaming_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming/1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testIntegrationResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EventStreaming.Get(context.Background(), 1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIntegrationResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventStreaming_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming/1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EventStreaming.Get(context.Background(), 1)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventStreaming_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.CreateIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, api.CreateIntegrationRequestPlatformDatadog, req.Platform)
|
||||
assert.Equal(t, true, req.Enabled)
|
||||
retBytes, _ := json.Marshal(testIntegrationResponse)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EventStreaming.Create(context.Background(), api.CreateIntegrationRequest{
|
||||
Platform: api.CreateIntegrationRequestPlatformDatadog,
|
||||
Enabled: true,
|
||||
Config: map[string]string{"api_key": "test-key"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIntegrationResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventStreaming_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EventStreaming.Create(context.Background(), api.CreateIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventStreaming_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming/1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.CreateIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, req.Enabled)
|
||||
retBytes, _ := json.Marshal(testIntegrationResponse)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EventStreaming.Update(context.Background(), 1, api.CreateIntegrationRequest{
|
||||
Platform: api.CreateIntegrationRequestPlatformDatadog,
|
||||
Enabled: false,
|
||||
Config: map[string]string{"api_key": "updated-key"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIntegrationResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventStreaming_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming/1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.EventStreaming.Update(context.Background(), 1, api.CreateIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventStreaming_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming/1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.EventStreaming.Delete(context.Background(), 1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventStreaming_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/event-streaming/1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.EventStreaming.Delete(context.Background(), 1)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
@@ -11,10 +13,79 @@ type EventsAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all events
|
||||
// See more: https://docs.netbird.io/api/resources/events#list-all-events
|
||||
func (a *EventsAPI) List(ctx context.Context) ([]api.Event, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/events", nil, nil)
|
||||
// NetworkTrafficOption options for ListNetworkTrafficEvents API
|
||||
type NetworkTrafficOption func(query map[string]string)
|
||||
|
||||
func NetworkTrafficPage(page int) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["page"] = fmt.Sprintf("%d", page)
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficPageSize(pageSize int) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["page_size"] = fmt.Sprintf("%d", pageSize)
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficUserID(userID string) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["user_id"] = userID
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficReporterID(reporterID string) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["reporter_id"] = reporterID
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficProtocol(protocol int) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["protocol"] = fmt.Sprintf("%d", protocol)
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficType(t api.GetApiEventsNetworkTrafficParamsType) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["type"] = string(t)
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficConnectionType(ct api.GetApiEventsNetworkTrafficParamsConnectionType) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["connection_type"] = string(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficDirection(d api.GetApiEventsNetworkTrafficParamsDirection) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["direction"] = string(d)
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficSearch(search string) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["search"] = search
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficStartDate(t time.Time) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["start_date"] = t.Format(time.RFC3339)
|
||||
}
|
||||
}
|
||||
|
||||
func NetworkTrafficEndDate(t time.Time) NetworkTrafficOption {
|
||||
return func(query map[string]string) {
|
||||
query["end_date"] = t.Format(time.RFC3339)
|
||||
}
|
||||
}
|
||||
|
||||
// ListAuditEvents list all audit events
|
||||
// See more: https://docs.netbird.io/api/resources/events#list-all-audit-events
|
||||
func (a *EventsAPI) ListAuditEvents(ctx context.Context) ([]api.Event, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/events/audit", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -24,3 +95,21 @@ func (a *EventsAPI) List(ctx context.Context) ([]api.Event, error) {
|
||||
ret, err := parseResponse[[]api.Event](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// ListNetworkTrafficEvents list network traffic events
|
||||
// See more: https://docs.netbird.io/api/resources/events#list-network-traffic-events
|
||||
func (a *EventsAPI) ListNetworkTrafficEvents(ctx context.Context, opts ...NetworkTrafficOption) (*api.NetworkTrafficEventsResponse, error) {
|
||||
query := make(map[string]string)
|
||||
for _, o := range opts {
|
||||
o(query)
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/events/network-traffic", nil, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.NetworkTrafficEventsResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
@@ -21,37 +21,76 @@ var (
|
||||
Activity: "AccountCreate",
|
||||
ActivityCode: api.EventActivityCodeAccountCreate,
|
||||
}
|
||||
|
||||
testNetworkTrafficResponse = api.NetworkTrafficEventsResponse{
|
||||
Data: []api.NetworkTrafficEvent{},
|
||||
Page: 1,
|
||||
PageSize: 50,
|
||||
}
|
||||
)
|
||||
|
||||
func TestEvents_List_200(t *testing.T) {
|
||||
func TestEvents_ListAuditEvents_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/events", func(w http.ResponseWriter, r *http.Request) {
|
||||
mux.HandleFunc("/api/events/audit", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Event{testEvent})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Events.List(context.Background())
|
||||
ret, err := c.Events.ListAuditEvents(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testEvent, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvents_List_Err(t *testing.T) {
|
||||
func TestEvents_ListAuditEvents_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/events", func(w http.ResponseWriter, r *http.Request) {
|
||||
mux.HandleFunc("/api/events/audit", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Events.List(context.Background())
|
||||
ret, err := c.Events.ListAuditEvents(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvents_ListNetworkTrafficEvents_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/events/network-traffic", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "1", r.URL.Query().Get("page"))
|
||||
assert.Equal(t, "50", r.URL.Query().Get("page_size"))
|
||||
retBytes, _ := json.Marshal(testNetworkTrafficResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Events.ListNetworkTrafficEvents(context.Background(),
|
||||
rest.NetworkTrafficPage(1),
|
||||
rest.NetworkTrafficPageSize(50),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetworkTrafficResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvents_ListNetworkTrafficEvents_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/events/network-traffic", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Events.ListNetworkTrafficEvents(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvents_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *rest.Client) {
|
||||
// Do something that would trigger any event
|
||||
@@ -62,7 +101,7 @@ func TestEvents_Integration(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
events, err := c.Events.List(context.Background())
|
||||
events, err := c.Events.ListAuditEvents(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, events)
|
||||
})
|
||||
|
||||
92
shared/management/client/rest/identity_providers.go
Normal file
92
shared/management/client/rest/identity_providers.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// IdentityProvidersAPI APIs for Identity Providers, do not use directly
|
||||
type IdentityProvidersAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List all identity providers
|
||||
// See more: https://docs.netbird.io/api/resources/identity-providers#list-all-identity-providers
|
||||
func (a *IdentityProvidersAPI) List(ctx context.Context) ([]api.IdentityProvider, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/identity-providers", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.IdentityProvider](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get identity provider info
|
||||
// See more: https://docs.netbird.io/api/resources/identity-providers#retrieve-an-identity-provider
|
||||
func (a *IdentityProvidersAPI) Get(ctx context.Context, idpID string) (*api.IdentityProvider, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/identity-providers/"+idpID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IdentityProvider](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create new identity provider
|
||||
// See more: https://docs.netbird.io/api/resources/identity-providers#create-an-identity-provider
|
||||
func (a *IdentityProvidersAPI) Create(ctx context.Context, request api.PostApiIdentityProvidersJSONRequestBody) (*api.IdentityProvider, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/identity-providers", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IdentityProvider](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update identity provider
|
||||
// See more: https://docs.netbird.io/api/resources/identity-providers#update-an-identity-provider
|
||||
func (a *IdentityProvidersAPI) Update(ctx context.Context, idpID string, request api.PutApiIdentityProvidersIdpIdJSONRequestBody) (*api.IdentityProvider, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/identity-providers/"+idpID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IdentityProvider](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete identity provider
|
||||
// See more: https://docs.netbird.io/api/resources/identity-providers#delete-an-identity-provider
|
||||
func (a *IdentityProvidersAPI) Delete(ctx context.Context, idpID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/identity-providers/"+idpID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
183
shared/management/client/rest/identity_providers_test.go
Normal file
183
shared/management/client/rest/identity_providers_test.go
Normal file
@@ -0,0 +1,183 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var testIdentityProvider = api.IdentityProvider{
|
||||
ClientId: "test-client-id",
|
||||
Id: ptr("Test"),
|
||||
}
|
||||
|
||||
func TestIdentityProviders_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.IdentityProvider{testIdentityProvider})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.IdentityProviders.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testIdentityProvider, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestIdentityProviders_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.IdentityProviders.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIdentityProviders_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testIdentityProvider)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.IdentityProviders.Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIdentityProvider, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIdentityProviders_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.IdentityProviders.Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIdentityProviders_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiIdentityProvidersJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "new-client-id", req.ClientId)
|
||||
retBytes, _ := json.Marshal(testIdentityProvider)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.IdentityProviders.Create(context.Background(), api.PostApiIdentityProvidersJSONRequestBody{
|
||||
ClientId: "new-client-id",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIdentityProvider, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIdentityProviders_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.IdentityProviders.Create(context.Background(), api.PostApiIdentityProvidersJSONRequestBody{
|
||||
ClientId: "new-client-id",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIdentityProviders_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiIdentityProvidersIdpIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "updated-client-id", req.ClientId)
|
||||
retBytes, _ := json.Marshal(testIdentityProvider)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.IdentityProviders.Update(context.Background(), "Test", api.PutApiIdentityProvidersIdpIdJSONRequestBody{
|
||||
ClientId: "updated-client-id",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIdentityProvider, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIdentityProviders_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.IdentityProviders.Update(context.Background(), "Test", api.PutApiIdentityProvidersIdpIdJSONRequestBody{
|
||||
ClientId: "updated-client-id",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIdentityProviders_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.IdentityProviders.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIdentityProviders_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/identity-providers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.IdentityProviders.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
92
shared/management/client/rest/ingress.go
Normal file
92
shared/management/client/rest/ingress.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// IngressAPI APIs for Ingress Peers, do not use directly
|
||||
type IngressAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List all ingress peers
|
||||
// See more: https://docs.netbird.io/api/resources/ingress#list-all-ingress-peers
|
||||
func (a *IngressAPI) List(ctx context.Context) ([]api.IngressPeer, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/ingress/peers", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.IngressPeer](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get ingress peer info
|
||||
// See more: https://docs.netbird.io/api/resources/ingress#retrieve-an-ingress-peer
|
||||
func (a *IngressAPI) Get(ctx context.Context, ingressPeerID string) (*api.IngressPeer, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/ingress/peers/"+ingressPeerID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IngressPeer](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create new ingress peer
|
||||
// See more: https://docs.netbird.io/api/resources/ingress#create-an-ingress-peer
|
||||
func (a *IngressAPI) Create(ctx context.Context, request api.PostApiIngressPeersJSONRequestBody) (*api.IngressPeer, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/ingress/peers", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IngressPeer](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update ingress peer
|
||||
// See more: https://docs.netbird.io/api/resources/ingress#update-an-ingress-peer
|
||||
func (a *IngressAPI) Update(ctx context.Context, ingressPeerID string, request api.PutApiIngressPeersIngressPeerIdJSONRequestBody) (*api.IngressPeer, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/ingress/peers/"+ingressPeerID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IngressPeer](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete ingress peer
|
||||
// See more: https://docs.netbird.io/api/resources/ingress#delete-an-ingress-peer
|
||||
func (a *IngressAPI) Delete(ctx context.Context, ingressPeerID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/ingress/peers/"+ingressPeerID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
184
shared/management/client/rest/ingress_test.go
Normal file
184
shared/management/client/rest/ingress_test.go
Normal file
@@ -0,0 +1,184 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var testIngressPeer = api.IngressPeer{
|
||||
Connected: true,
|
||||
Enabled: true,
|
||||
Id: "Test",
|
||||
}
|
||||
|
||||
func TestIngress_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.IngressPeer{testIngressPeer})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Ingress.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testIngressPeer, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestIngress_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Ingress.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIngress_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testIngressPeer)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Ingress.Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIngressPeer, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIngress_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Ingress.Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIngress_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiIngressPeersJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "peer-id", req.PeerId)
|
||||
retBytes, _ := json.Marshal(testIngressPeer)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Ingress.Create(context.Background(), api.PostApiIngressPeersJSONRequestBody{
|
||||
PeerId: "peer-id",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIngressPeer, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIngress_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Ingress.Create(context.Background(), api.PostApiIngressPeersJSONRequestBody{
|
||||
PeerId: "peer-id",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIngress_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiIngressPeersIngressPeerIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, req.Enabled)
|
||||
retBytes, _ := json.Marshal(testIngressPeer)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Ingress.Update(context.Background(), "Test", api.PutApiIngressPeersIngressPeerIdJSONRequestBody{
|
||||
Enabled: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIngressPeer, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIngress_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Ingress.Update(context.Background(), "Test", api.PutApiIngressPeersIngressPeerIdJSONRequestBody{
|
||||
Enabled: true,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIngress_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Ingress.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIngress_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/ingress/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Ingress.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
46
shared/management/client/rest/instance.go
Normal file
46
shared/management/client/rest/instance.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// InstanceAPI APIs for Instance status and version, do not use directly
|
||||
type InstanceAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// GetStatus get instance status
|
||||
// See more: https://docs.netbird.io/api/resources/instance#get-instance-status
|
||||
func (a *InstanceAPI) GetStatus(ctx context.Context) (*api.InstanceStatus, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/instance", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.InstanceStatus](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Setup perform initial instance setup
|
||||
// See more: https://docs.netbird.io/api/resources/instance#setup-instance
|
||||
func (a *InstanceAPI) Setup(ctx context.Context, request api.PostApiSetupJSONRequestBody) (*api.SetupResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/setup", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.SetupResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
96
shared/management/client/rest/instance_test.go
Normal file
96
shared/management/client/rest/instance_test.go
Normal file
@@ -0,0 +1,96 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var (
|
||||
testInstanceStatus = api.InstanceStatus{
|
||||
SetupRequired: true,
|
||||
}
|
||||
|
||||
testSetupResponse = api.SetupResponse{
|
||||
Email: "admin@example.com",
|
||||
UserId: "user-123",
|
||||
}
|
||||
)
|
||||
|
||||
func TestInstance_GetStatus_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/instance", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testInstanceStatus)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Instance.GetStatus(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testInstanceStatus, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInstance_GetStatus_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/instance", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Instance.GetStatus(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInstance_Setup_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiSetupJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "admin@example.com", req.Email)
|
||||
retBytes, _ := json.Marshal(testSetupResponse)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Instance.Setup(context.Background(), api.PostApiSetupJSONRequestBody{
|
||||
Email: "admin@example.com",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testSetupResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInstance_Setup_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Instance.Setup(context.Background(), api.PostApiSetupJSONRequestBody{
|
||||
Email: "admin@example.com",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
122
shared/management/client/rest/msp.go
Normal file
122
shared/management/client/rest/msp.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// MSPAPI APIs for MSP tenant management
|
||||
type MSPAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// ListTenants retrieves all MSP tenants
|
||||
// See more: https://docs.netbird.io/api/resources/msp#list-all-tenants
|
||||
func (a *MSPAPI) ListTenants(ctx context.Context) (*api.GetTenantsResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/msp/tenants", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.GetTenantsResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// CreateTenant creates a new MSP tenant
|
||||
// See more: https://docs.netbird.io/api/resources/msp#create-a-tenant
|
||||
func (a *MSPAPI) CreateTenant(ctx context.Context, request api.CreateTenantRequest) (*api.TenantResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/msp/tenants", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.TenantResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// UpdateTenant updates an existing MSP tenant
|
||||
// See more: https://docs.netbird.io/api/resources/msp#update-a-tenant
|
||||
func (a *MSPAPI) UpdateTenant(ctx context.Context, tenantID string, request api.UpdateTenantRequest) (*api.TenantResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/integrations/msp/tenants/"+tenantID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.TenantResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// DeleteTenant deletes an MSP tenant
|
||||
// See more: https://docs.netbird.io/api/resources/msp#delete-a-tenant
|
||||
func (a *MSPAPI) DeleteTenant(ctx context.Context, tenantID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/integrations/msp/tenants/"+tenantID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnlinkTenant unlinks a tenant from the MSP account
|
||||
// See more: https://docs.netbird.io/api/resources/msp#unlink-a-tenant
|
||||
func (a *MSPAPI) UnlinkTenant(ctx context.Context, tenantID, owner string) error {
|
||||
params := map[string]string{"owner": owner}
|
||||
requestBytes, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/msp/tenants/"+tenantID+"/unlink", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyTenantDNS verifies a tenant domain DNS challenge
|
||||
// See more: https://docs.netbird.io/api/resources/msp#verify-tenant-dns
|
||||
func (a *MSPAPI) VerifyTenantDNS(ctx context.Context, tenantID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/msp/tenants/"+tenantID+"/dns", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InviteTenant invites an existing account as a tenant to the MSP account
|
||||
// See more: https://docs.netbird.io/api/resources/msp#invite-a-tenant
|
||||
func (a *MSPAPI) InviteTenant(ctx context.Context, tenantID string) (*api.TenantResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/msp/tenants/"+tenantID+"/invite", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.TenantResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
251
shared/management/client/rest/msp_test.go
Normal file
251
shared/management/client/rest/msp_test.go
Normal file
@@ -0,0 +1,251 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var (
|
||||
testTenant = api.TenantResponse{
|
||||
Id: "tenant-1",
|
||||
Name: "Test Tenant",
|
||||
Domain: "test.example.com",
|
||||
DnsChallenge: "challenge-123",
|
||||
Status: "active",
|
||||
Groups: []api.TenantGroupResponse{},
|
||||
CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
)
|
||||
|
||||
func TestMSP_ListTenants_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.TenantResponse{testTenant})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.MSP.ListTenants(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, *ret, 1)
|
||||
assert.Equal(t, testTenant, (*ret)[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_ListTenants_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.MSP.ListTenants(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_CreateTenant_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.CreateTenantRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test Tenant", req.Name)
|
||||
assert.Equal(t, "test.example.com", req.Domain)
|
||||
retBytes, _ := json.Marshal(testTenant)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.MSP.CreateTenant(context.Background(), api.CreateTenantRequest{
|
||||
Name: "Test Tenant",
|
||||
Domain: "test.example.com",
|
||||
Groups: []api.TenantGroupResponse{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testTenant, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_CreateTenant_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.MSP.CreateTenant(context.Background(), api.CreateTenantRequest{
|
||||
Name: "Test Tenant",
|
||||
Domain: "test.example.com",
|
||||
Groups: []api.TenantGroupResponse{},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_UpdateTenant_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.UpdateTenantRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Updated Tenant", req.Name)
|
||||
retBytes, _ := json.Marshal(testTenant)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.MSP.UpdateTenant(context.Background(), "tenant-1", api.UpdateTenantRequest{
|
||||
Name: "Updated Tenant",
|
||||
Groups: []api.TenantGroupResponse{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testTenant, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_UpdateTenant_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.MSP.UpdateTenant(context.Background(), "tenant-1", api.UpdateTenantRequest{
|
||||
Name: "Updated Tenant",
|
||||
Groups: []api.TenantGroupResponse{},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_DeleteTenant_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.MSP.DeleteTenant(context.Background(), "tenant-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_DeleteTenant_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.MSP.DeleteTenant(context.Background(), "tenant-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_UnlinkTenant_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1/unlink", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.MSP.UnlinkTenant(context.Background(), "tenant-1", "owner-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_UnlinkTenant_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1/unlink", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.MSP.UnlinkTenant(context.Background(), "tenant-1", "owner-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_VerifyTenantDNS_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1/dns", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.MSP.VerifyTenantDNS(context.Background(), "tenant-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_VerifyTenantDNS_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1/dns", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Failed", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.MSP.VerifyTenantDNS(context.Background(), "tenant-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Failed", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_InviteTenant_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1/invite", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testTenant)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.MSP.InviteTenant(context.Background(), "tenant-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testTenant, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMSP_InviteTenant_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/msp/tenants/tenant-1/invite", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.MSP.InviteTenant(context.Background(), "tenant-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
@@ -91,6 +91,20 @@ func (a *NetworksAPI) Delete(ctx context.Context, networkID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListAllRouters list all routers across all networks
|
||||
// See more: https://docs.netbird.io/api/resources/networks#list-all-network-routers
|
||||
func (a *NetworksAPI) ListAllRouters(ctx context.Context) ([]api.NetworkRouter, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/routers", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.NetworkRouter](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// NetworkResourcesAPI APIs for Network Resources, do not use directly
|
||||
type NetworkResourcesAPI struct {
|
||||
c *Client
|
||||
|
||||
@@ -219,6 +219,35 @@ func TestNetworks_Integration(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_ListAllRouters_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/routers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.NetworkRouter{testNetworkRouter})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.ListAllRouters(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testNetworkRouter, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_ListAllRouters_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/routers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.ListAllRouters(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -106,3 +106,173 @@ func (a *PeersAPI) ListAccessiblePeers(ctx context.Context, peerID string) ([]ap
|
||||
ret, err := parseResponse[[]api.Peer](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// CreateTemporaryAccess create temporary access for a peer
|
||||
// See more: https://docs.netbird.io/api/resources/peers#create-temporary-access
|
||||
func (a *PeersAPI) CreateTemporaryAccess(ctx context.Context, peerID string, request api.PostApiPeersPeerIdTemporaryAccessJSONRequestBody) (*api.PeerTemporaryAccessResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/peers/"+peerID+"/temporary-access", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.PeerTemporaryAccessResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// PeerIngressPortsAPI APIs for Peer Ingress Ports, do not use directly
|
||||
type PeerIngressPortsAPI struct {
|
||||
c *Client
|
||||
peerID string
|
||||
}
|
||||
|
||||
// IngressPorts APIs for peer ingress ports
|
||||
func (a *PeersAPI) IngressPorts(peerID string) *PeerIngressPortsAPI {
|
||||
return &PeerIngressPortsAPI{
|
||||
c: a.c,
|
||||
peerID: peerID,
|
||||
}
|
||||
}
|
||||
|
||||
// List list all ingress port allocations for a peer
|
||||
// See more: https://docs.netbird.io/api/resources/peers#list-all-ingress-port-allocations
|
||||
func (a *PeerIngressPortsAPI) List(ctx context.Context) ([]api.IngressPortAllocation, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers/"+a.peerID+"/ingress/ports", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.IngressPortAllocation](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get ingress port allocation info
|
||||
// See more: https://docs.netbird.io/api/resources/peers#retrieve-an-ingress-port-allocation
|
||||
func (a *PeerIngressPortsAPI) Get(ctx context.Context, allocationID string) (*api.IngressPortAllocation, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers/"+a.peerID+"/ingress/ports/"+allocationID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IngressPortAllocation](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create create new ingress port allocation
|
||||
// See more: https://docs.netbird.io/api/resources/peers#create-an-ingress-port-allocation
|
||||
func (a *PeerIngressPortsAPI) Create(ctx context.Context, request api.PostApiPeersPeerIdIngressPortsJSONRequestBody) (*api.IngressPortAllocation, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/peers/"+a.peerID+"/ingress/ports", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IngressPortAllocation](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update ingress port allocation
|
||||
// See more: https://docs.netbird.io/api/resources/peers#update-an-ingress-port-allocation
|
||||
func (a *PeerIngressPortsAPI) Update(ctx context.Context, allocationID string, request api.PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody) (*api.IngressPortAllocation, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/peers/"+a.peerID+"/ingress/ports/"+allocationID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.IngressPortAllocation](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete ingress port allocation
|
||||
// See more: https://docs.netbird.io/api/resources/peers#delete-an-ingress-port-allocation
|
||||
func (a *PeerIngressPortsAPI) Delete(ctx context.Context, allocationID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/peers/"+a.peerID+"/ingress/ports/"+allocationID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PeerJobsAPI APIs for Peer Jobs, do not use directly
|
||||
type PeerJobsAPI struct {
|
||||
c *Client
|
||||
peerID string
|
||||
}
|
||||
|
||||
// Jobs APIs for peer jobs
|
||||
func (a *PeersAPI) Jobs(peerID string) *PeerJobsAPI {
|
||||
return &PeerJobsAPI{
|
||||
c: a.c,
|
||||
peerID: peerID,
|
||||
}
|
||||
}
|
||||
|
||||
// List list all jobs for a peer
|
||||
// See more: https://docs.netbird.io/api/resources/peers#list-all-peer-jobs
|
||||
func (a *PeerJobsAPI) List(ctx context.Context) ([]api.JobResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers/"+a.peerID+"/jobs", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.JobResponse](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get job info
|
||||
// See more: https://docs.netbird.io/api/resources/peers#retrieve-a-peer-job
|
||||
func (a *PeerJobsAPI) Get(ctx context.Context, jobID string) (*api.JobResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers/"+a.peerID+"/jobs/"+jobID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.JobResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create create new job for a peer
|
||||
// See more: https://docs.netbird.io/api/resources/peers#create-a-peer-job
|
||||
func (a *PeerJobsAPI) Create(ctx context.Context, request api.PostApiPeersPeerIdJobsJSONRequestBody) (*api.JobResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/peers/"+a.peerID+"/jobs", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.JobResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
@@ -25,6 +25,21 @@ var (
|
||||
DnsLabel: "test",
|
||||
Id: "Test",
|
||||
}
|
||||
|
||||
testPeerTemporaryAccess = api.PeerTemporaryAccessResponse{
|
||||
Id: "Test",
|
||||
Name: "test-peer",
|
||||
}
|
||||
|
||||
testIngressPortAllocation = api.IngressPortAllocation{
|
||||
Enabled: true,
|
||||
Id: "alloc-1",
|
||||
}
|
||||
|
||||
testJobResponse = api.JobResponse{
|
||||
Id: "job-1",
|
||||
Status: "pending",
|
||||
}
|
||||
)
|
||||
|
||||
func TestPeers_List_200(t *testing.T) {
|
||||
@@ -177,6 +192,264 @@ func TestPeers_ListAccessiblePeers_Err(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_CreateTemporaryAccess_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/temporary-access", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testPeerTemporaryAccess)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.CreateTemporaryAccess(context.Background(), "Test", api.PostApiPeersPeerIdTemporaryAccessJSONRequestBody{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testPeerTemporaryAccess, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_CreateTemporaryAccess_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/temporary-access", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.CreateTemporaryAccess(context.Background(), "Test", api.PostApiPeersPeerIdTemporaryAccessJSONRequestBody{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.IngressPortAllocation{testIngressPortAllocation})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.IngressPorts("Test").List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testIngressPortAllocation, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.IngressPorts("Test").List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports/alloc-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testIngressPortAllocation)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.IngressPorts("Test").Get(context.Background(), "alloc-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIngressPortAllocation, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports/alloc-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.IngressPorts("Test").Get(context.Background(), "alloc-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testIngressPortAllocation)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.IngressPorts("Test").Create(context.Background(), api.PostApiPeersPeerIdIngressPortsJSONRequestBody{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIngressPortAllocation, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.IngressPorts("Test").Create(context.Background(), api.PostApiPeersPeerIdIngressPortsJSONRequestBody{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports/alloc-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
retBytes, _ := json.Marshal(testIngressPortAllocation)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.IngressPorts("Test").Update(context.Background(), "alloc-1", api.PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testIngressPortAllocation, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports/alloc-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.IngressPorts("Test").Update(context.Background(), "alloc-1", api.PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports/alloc-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Peers.IngressPorts("Test").Delete(context.Background(), "alloc-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerIngressPorts_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/ingress/ports/alloc-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Peers.IngressPorts("Test").Delete(context.Background(), "alloc-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerJobs_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/jobs", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.JobResponse{testJobResponse})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Jobs("Test").List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testJobResponse.Id, ret[0].Id)
|
||||
assert.Equal(t, testJobResponse.Status, ret[0].Status)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerJobs_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/jobs", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Jobs("Test").List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerJobs_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/jobs/job-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testJobResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Jobs("Test").Get(context.Background(), "job-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testJobResponse.Id, ret.Id)
|
||||
assert.Equal(t, testJobResponse.Status, ret.Status)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerJobs_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/jobs/job-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Jobs("Test").Get(context.Background(), "job-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerJobs_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/jobs", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testJobResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Jobs("Test").Create(context.Background(), api.PostApiPeersPeerIdJobsJSONRequestBody{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testJobResponse.Id, ret.Id)
|
||||
assert.Equal(t, testJobResponse.Status, ret.Status)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerJobs_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/jobs", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Jobs("Test").Create(context.Background(), api.PostApiPeersPeerIdJobsJSONRequestBody{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *rest.Client) {
|
||||
peers, err := c.Peers.List(context.Background())
|
||||
|
||||
119
shared/management/client/rest/scim.go
Normal file
119
shared/management/client/rest/scim.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// SCIMAPI APIs for SCIM IDP integrations
|
||||
type SCIMAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List retrieves all SCIM IDP integrations
|
||||
// See more: https://docs.netbird.io/api/resources/scim#list-all-scim-integrations
|
||||
func (a *SCIMAPI) List(ctx context.Context) ([]api.ScimIntegration, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/scim-idp", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.ScimIntegration](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves a specific SCIM IDP integration by ID
|
||||
// See more: https://docs.netbird.io/api/resources/scim#retrieve-a-scim-integration
|
||||
func (a *SCIMAPI) Get(ctx context.Context, integrationID string) (*api.ScimIntegration, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/scim-idp/"+integrationID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.ScimIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create creates a new SCIM IDP integration
|
||||
// See more: https://docs.netbird.io/api/resources/scim#create-a-scim-integration
|
||||
func (a *SCIMAPI) Create(ctx context.Context, request api.CreateScimIntegrationRequest) (*api.ScimIntegration, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/scim-idp", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.ScimIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update updates an existing SCIM IDP integration
|
||||
// See more: https://docs.netbird.io/api/resources/scim#update-a-scim-integration
|
||||
func (a *SCIMAPI) Update(ctx context.Context, integrationID string, request api.UpdateScimIntegrationRequest) (*api.ScimIntegration, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/integrations/scim-idp/"+integrationID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.ScimIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete deletes a SCIM IDP integration
|
||||
// See more: https://docs.netbird.io/api/resources/scim#delete-a-scim-integration
|
||||
func (a *SCIMAPI) Delete(ctx context.Context, integrationID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/integrations/scim-idp/"+integrationID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegenerateToken regenerates the SCIM API token for an integration
|
||||
// See more: https://docs.netbird.io/api/resources/scim#regenerate-scim-token
|
||||
func (a *SCIMAPI) RegenerateToken(ctx context.Context, integrationID string) (*api.ScimTokenResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/scim-idp/"+integrationID+"/token", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.ScimTokenResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// GetLogs retrieves synchronization logs for an SCIM IDP integration
|
||||
// See more: https://docs.netbird.io/api/resources/scim#get-scim-sync-logs
|
||||
func (a *SCIMAPI) GetLogs(ctx context.Context, integrationID string) ([]api.IdpIntegrationSyncLog, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/scim-idp/"+integrationID+"/logs", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.IdpIntegrationSyncLog](resp)
|
||||
return ret, err
|
||||
}
|
||||
262
shared/management/client/rest/scim_test.go
Normal file
262
shared/management/client/rest/scim_test.go
Normal file
@@ -0,0 +1,262 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var (
|
||||
testScimIntegration = api.ScimIntegration{
|
||||
Id: 1,
|
||||
AuthToken: "****",
|
||||
Enabled: true,
|
||||
GroupPrefixes: []string{"eng-"},
|
||||
UserGroupPrefixes: []string{"dev-"},
|
||||
Provider: "okta",
|
||||
LastSyncedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
|
||||
testScimToken = api.ScimTokenResponse{
|
||||
AuthToken: "new-token-123",
|
||||
}
|
||||
|
||||
testSyncLog = api.IdpIntegrationSyncLog{
|
||||
Id: 1,
|
||||
Level: "info",
|
||||
Message: "Sync completed",
|
||||
Timestamp: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
)
|
||||
|
||||
func TestSCIM_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.ScimIntegration{testScimIntegration})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testScimIntegration, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testScimIntegration)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.Get(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testScimIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.Get(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.CreateScimIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "okta", req.Provider)
|
||||
assert.Equal(t, "scim-", req.Prefix)
|
||||
retBytes, _ := json.Marshal(testScimIntegration)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.Create(context.Background(), api.CreateScimIntegrationRequest{
|
||||
Provider: "okta",
|
||||
Prefix: "scim-",
|
||||
GroupPrefixes: &[]string{"eng-"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testScimIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.Create(context.Background(), api.CreateScimIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.UpdateScimIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, *req.Enabled)
|
||||
retBytes, _ := json.Marshal(testScimIntegration)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.Update(context.Background(), "int-1", api.UpdateScimIntegrationRequest{
|
||||
Enabled: ptr(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testScimIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.Update(context.Background(), "int-1", api.UpdateScimIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.SCIM.Delete(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.SCIM.Delete(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_RegenerateToken_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1/token", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testScimToken)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.RegenerateToken(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testScimToken, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_RegenerateToken_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1/token", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.RegenerateToken(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_GetLogs_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1/logs", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.IdpIntegrationSyncLog{testSyncLog})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.GetLogs(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testSyncLog, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestSCIM_GetLogs_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/scim-idp/int-1/logs", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SCIM.GetLogs(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
@@ -105,3 +105,145 @@ func (a *UsersAPI) Current(ctx context.Context) (*api.User, error) {
|
||||
ret, err := parseResponse[api.User](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// ListInvites list all user invites
|
||||
// See more: https://docs.netbird.io/api/resources/users#list-all-user-invites
|
||||
func (a *UsersAPI) ListInvites(ctx context.Context) ([]api.UserInvite, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users/invites", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.UserInvite](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// CreateInvite create a user invite
|
||||
// See more: https://docs.netbird.io/api/resources/users#create-a-user-invite
|
||||
func (a *UsersAPI) CreateInvite(ctx context.Context, request api.PostApiUsersInvitesJSONRequestBody) (*api.UserInvite, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users/invites", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.UserInvite](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// DeleteInvite delete a user invite
|
||||
// See more: https://docs.netbird.io/api/resources/users#delete-a-user-invite
|
||||
func (a *UsersAPI) DeleteInvite(ctx context.Context, inviteID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/users/invites/"+inviteID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegenerateInvite regenerate a user invite token
|
||||
// See more: https://docs.netbird.io/api/resources/users#regenerate-a-user-invite
|
||||
func (a *UsersAPI) RegenerateInvite(ctx context.Context, inviteID string, request api.PostApiUsersInvitesInviteIdRegenerateJSONRequestBody) (*api.UserInviteRegenerateResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users/invites/"+inviteID+"/regenerate", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.UserInviteRegenerateResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// GetInviteByToken get a user invite by token
|
||||
// See more: https://docs.netbird.io/api/resources/users#get-a-user-invite-by-token
|
||||
func (a *UsersAPI) GetInviteByToken(ctx context.Context, token string) (*api.UserInviteInfo, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users/invites/"+token, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.UserInviteInfo](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// AcceptInvite accept a user invite
|
||||
// See more: https://docs.netbird.io/api/resources/users#accept-a-user-invite
|
||||
func (a *UsersAPI) AcceptInvite(ctx context.Context, token string, request api.PostApiUsersInvitesTokenAcceptJSONRequestBody) (*api.UserInviteAcceptResponse, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users/invites/"+token+"/accept", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.UserInviteAcceptResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Approve approve a pending user
|
||||
// See more: https://docs.netbird.io/api/resources/users#approve-a-user
|
||||
func (a *UsersAPI) Approve(ctx context.Context, userID string) (*api.User, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users/"+userID+"/approve", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.User](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// ChangePassword change a user's password
|
||||
// See more: https://docs.netbird.io/api/resources/users#change-user-password
|
||||
func (a *UsersAPI) ChangePassword(ctx context.Context, userID string, request api.PutApiUsersUserIdPasswordJSONRequestBody) error {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/users/"+userID+"/password", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reject reject a pending user
|
||||
// See more: https://docs.netbird.io/api/resources/users#reject-a-user
|
||||
func (a *UsersAPI) Reject(ctx context.Context, userID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/users/"+userID+"/reject", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -32,6 +32,23 @@ var (
|
||||
Role: "user",
|
||||
Status: api.UserStatusActive,
|
||||
}
|
||||
|
||||
testUserInvite = api.UserInvite{
|
||||
AutoGroups: []string{"group1"},
|
||||
Id: "invite-1",
|
||||
}
|
||||
|
||||
testUserInviteInfo = api.UserInviteInfo{
|
||||
Email: "invite@test.com",
|
||||
}
|
||||
|
||||
testUserInviteAcceptResponse = api.UserInviteAcceptResponse{
|
||||
Success: true,
|
||||
}
|
||||
|
||||
testUserInviteRegenerateResponse = api.UserInviteRegenerateResponse{
|
||||
InviteToken: "new-token",
|
||||
}
|
||||
)
|
||||
|
||||
func TestUsers_List_200(t *testing.T) {
|
||||
@@ -220,6 +237,269 @@ func TestUsers_Current_Err(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_ListInvites_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.UserInvite{testUserInvite})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.ListInvites(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testUserInvite, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_ListInvites_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.ListInvites(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_CreateInvite_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiUsersInvitesJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "invite@test.com", req.Email)
|
||||
retBytes, _ := json.Marshal(testUserInvite)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.CreateInvite(context.Background(), api.PostApiUsersInvitesJSONRequestBody{
|
||||
Email: "invite@test.com",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUserInvite, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_CreateInvite_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.CreateInvite(context.Background(), api.PostApiUsersInvitesJSONRequestBody{
|
||||
Email: "invite@test.com",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_DeleteInvite_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites/invite-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Users.DeleteInvite(context.Background(), "invite-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_DeleteInvite_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites/invite-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Users.DeleteInvite(context.Background(), "invite-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_RegenerateInvite_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites/invite-1/regenerate", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testUserInviteRegenerateResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.RegenerateInvite(context.Background(), "invite-1", api.PostApiUsersInvitesInviteIdRegenerateJSONRequestBody{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUserInviteRegenerateResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_RegenerateInvite_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites/invite-1/regenerate", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.RegenerateInvite(context.Background(), "invite-1", api.PostApiUsersInvitesInviteIdRegenerateJSONRequestBody{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_GetInviteByToken_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites/some-token", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testUserInviteInfo)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.GetInviteByToken(context.Background(), "some-token")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUserInviteInfo, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_GetInviteByToken_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites/some-token", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.GetInviteByToken(context.Background(), "some-token")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_AcceptInvite_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites/some-token/accept", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testUserInviteAcceptResponse)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.AcceptInvite(context.Background(), "some-token", api.PostApiUsersInvitesTokenAcceptJSONRequestBody{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUserInviteAcceptResponse, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_AcceptInvite_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/invites/some-token/accept", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.AcceptInvite(context.Background(), "some-token", api.PostApiUsersInvitesTokenAcceptJSONRequestBody{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Approve_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test/approve", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testUser)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.Approve(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUser, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Approve_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test/approve", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.Approve(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_ChangePassword_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test/password", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiUsersUserIdPasswordJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Users.ChangePassword(context.Background(), "Test", api.PutApiUsersUserIdPasswordJSONRequestBody{})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_ChangePassword_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test/password", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Users.ChangePassword(context.Background(), "Test", api.PutApiUsersUserIdPasswordJSONRequestBody{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Reject_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test/reject", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Users.Reject(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Reject_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test/reject", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Users.Reject(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *rest.Client) {
|
||||
// rest client PAT is owner's
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,14 @@ const (
|
||||
TokenAuthScopes = "TokenAuth.Scopes"
|
||||
)
|
||||
|
||||
// Defines values for CreateIntegrationRequestPlatform.
|
||||
const (
|
||||
CreateIntegrationRequestPlatformDatadog CreateIntegrationRequestPlatform = "datadog"
|
||||
CreateIntegrationRequestPlatformFirehose CreateIntegrationRequestPlatform = "firehose"
|
||||
CreateIntegrationRequestPlatformGenericHttp CreateIntegrationRequestPlatform = "generic_http"
|
||||
CreateIntegrationRequestPlatformS3 CreateIntegrationRequestPlatform = "s3"
|
||||
)
|
||||
|
||||
// Defines values for DNSRecordType.
|
||||
const (
|
||||
DNSRecordTypeA DNSRecordType = "A"
|
||||
@@ -188,6 +196,20 @@ const (
|
||||
IngressPortAllocationRequestPortRangeProtocolUdp IngressPortAllocationRequestPortRangeProtocol = "udp"
|
||||
)
|
||||
|
||||
// Defines values for IntegrationResponsePlatform.
|
||||
const (
|
||||
IntegrationResponsePlatformDatadog IntegrationResponsePlatform = "datadog"
|
||||
IntegrationResponsePlatformFirehose IntegrationResponsePlatform = "firehose"
|
||||
IntegrationResponsePlatformGenericHttp IntegrationResponsePlatform = "generic_http"
|
||||
IntegrationResponsePlatformS3 IntegrationResponsePlatform = "s3"
|
||||
)
|
||||
|
||||
// Defines values for InvoiceResponseType.
|
||||
const (
|
||||
InvoiceResponseTypeAccount InvoiceResponseType = "account"
|
||||
InvoiceResponseTypeTenants InvoiceResponseType = "tenants"
|
||||
)
|
||||
|
||||
// Defines values for JobResponseStatus.
|
||||
const (
|
||||
JobResponseStatusFailed JobResponseStatus = "failed"
|
||||
@@ -266,6 +288,21 @@ const (
|
||||
ResourceTypeSubnet ResourceType = "subnet"
|
||||
)
|
||||
|
||||
// Defines values for SentinelOneMatchAttributesNetworkStatus.
|
||||
const (
|
||||
SentinelOneMatchAttributesNetworkStatusConnected SentinelOneMatchAttributesNetworkStatus = "connected"
|
||||
SentinelOneMatchAttributesNetworkStatusDisconnected SentinelOneMatchAttributesNetworkStatus = "disconnected"
|
||||
SentinelOneMatchAttributesNetworkStatusQuarantined SentinelOneMatchAttributesNetworkStatus = "quarantined"
|
||||
)
|
||||
|
||||
// Defines values for TenantResponseStatus.
|
||||
const (
|
||||
TenantResponseStatusActive TenantResponseStatus = "active"
|
||||
TenantResponseStatusExisting TenantResponseStatus = "existing"
|
||||
TenantResponseStatusInvited TenantResponseStatus = "invited"
|
||||
TenantResponseStatusPending TenantResponseStatus = "pending"
|
||||
)
|
||||
|
||||
// Defines values for UserStatus.
|
||||
const (
|
||||
UserStatusActive UserStatus = "active"
|
||||
@@ -299,6 +336,12 @@ const (
|
||||
GetApiEventsNetworkTrafficParamsDirectionINGRESS GetApiEventsNetworkTrafficParamsDirection = "INGRESS"
|
||||
)
|
||||
|
||||
// Defines values for PutApiIntegrationsMspTenantsIdInviteJSONBodyValue.
|
||||
const (
|
||||
PutApiIntegrationsMspTenantsIdInviteJSONBodyValueAccept PutApiIntegrationsMspTenantsIdInviteJSONBodyValue = "accept"
|
||||
PutApiIntegrationsMspTenantsIdInviteJSONBodyValueDecline PutApiIntegrationsMspTenantsIdInviteJSONBodyValue = "decline"
|
||||
)
|
||||
|
||||
// AccessiblePeer defines model for AccessiblePeer.
|
||||
type AccessiblePeer struct {
|
||||
// CityName Commonly used English name of the city
|
||||
@@ -490,6 +533,21 @@ type BundleWorkloadResponse struct {
|
||||
Type WorkloadType `json:"type"`
|
||||
}
|
||||
|
||||
// BypassResponse Response for bypassed peer operations.
|
||||
type BypassResponse struct {
|
||||
// PeerId The ID of the bypassed peer.
|
||||
PeerId string `json:"peer_id"`
|
||||
}
|
||||
|
||||
// CheckoutResponse defines model for CheckoutResponse.
|
||||
type CheckoutResponse struct {
|
||||
// SessionId The unique identifier for the checkout session.
|
||||
SessionId string `json:"session_id"`
|
||||
|
||||
// Url URL to redirect the user to the checkout session.
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
// Checks List of objects that perform the actual checks
|
||||
type Checks struct {
|
||||
// GeoLocationCheck Posture check for geo location
|
||||
@@ -532,6 +590,36 @@ type Country struct {
|
||||
// CountryCode 2-letter ISO 3166-1 alpha-2 code that represents the country
|
||||
type CountryCode = string
|
||||
|
||||
// CreateIntegrationRequest Request payload for creating a new event streaming integration. Also used as the structure for the PUT request body, but not all fields are applicable for updates (see PUT operation description).
|
||||
type CreateIntegrationRequest struct {
|
||||
// Config Platform-specific configuration as key-value pairs. For creation, all necessary credentials and settings must be provided. For updates, provide the fields to change or the entire new configuration.
|
||||
Config map[string]string `json:"config"`
|
||||
|
||||
// Enabled Specifies whether the integration is enabled. During creation (POST), this value is sent by the client, but the provided backend manager function `CreateIntegration` does not appear to use it directly, so its effect on creation should be verified. During updates (PUT), this field is used to enable or disable the integration.
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Platform The event streaming platform to integrate with (e.g., "datadog", "s3", "firehose"). This field is used for creation. For updates (PUT), this field, if sent, is ignored by the backend.
|
||||
Platform CreateIntegrationRequestPlatform `json:"platform"`
|
||||
}
|
||||
|
||||
// CreateIntegrationRequestPlatform The event streaming platform to integrate with (e.g., "datadog", "s3", "firehose"). This field is used for creation. For updates (PUT), this field, if sent, is ignored by the backend.
|
||||
type CreateIntegrationRequestPlatform string
|
||||
|
||||
// CreateScimIntegrationRequest Request payload for creating an SCIM IDP integration
|
||||
type CreateScimIntegrationRequest struct {
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// Prefix The connection prefix used for the SCIM provider
|
||||
Prefix string `json:"prefix"`
|
||||
|
||||
// Provider Name of the SCIM identity provider
|
||||
Provider string `json:"provider"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// CreateSetupKeyRequest defines model for CreateSetupKeyRequest.
|
||||
type CreateSetupKeyRequest struct {
|
||||
// AllowExtraDnsLabels Allow extra DNS labels to be added to the peer
|
||||
@@ -556,6 +644,24 @@ type CreateSetupKeyRequest struct {
|
||||
UsageLimit int `json:"usage_limit"`
|
||||
}
|
||||
|
||||
// CreateTenantRequest defines model for CreateTenantRequest.
|
||||
type CreateTenantRequest struct {
|
||||
// Domain The name for the MSP tenant
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Groups MSP users Groups that can access the Tenant and Roles to assume
|
||||
Groups []TenantGroupResponse `json:"groups"`
|
||||
|
||||
// Name The name for the MSP tenant
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// DNSChallengeResponse defines model for DNSChallengeResponse.
|
||||
type DNSChallengeResponse struct {
|
||||
// DnsChallenge The DNS challenge to set in a TXT record
|
||||
DnsChallenge string `json:"dns_challenge"`
|
||||
}
|
||||
|
||||
// DNSRecord defines model for DNSRecord.
|
||||
type DNSRecord struct {
|
||||
// Content DNS record content (IP address for A/AAAA, domain for CNAME)
|
||||
@@ -598,6 +704,234 @@ type DNSSettings struct {
|
||||
DisabledManagementGroups []string `json:"disabled_management_groups"`
|
||||
}
|
||||
|
||||
// EDRFalconRequest Request payload for creating or updating a EDR Falcon integration
|
||||
type EDRFalconRequest struct {
|
||||
// ClientId CrowdStrike API client ID
|
||||
ClientId string `json:"client_id"`
|
||||
|
||||
// CloudId CrowdStrike cloud identifier (e.g., "us-1", "us-2", "eu-1")
|
||||
CloudId string `json:"cloud_id"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// Groups The Groups this integration applies to
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// Secret CrowdStrike API client secret
|
||||
Secret string `json:"secret"`
|
||||
|
||||
// ZtaScoreThreshold The minimum Zero Trust Assessment score required for agent approval (0-100)
|
||||
ZtaScoreThreshold int `json:"zta_score_threshold"`
|
||||
}
|
||||
|
||||
// EDRFalconResponse Represents a Falcon EDR integration
|
||||
type EDRFalconResponse struct {
|
||||
// AccountId The identifier of the account this integration belongs to.
|
||||
AccountId string `json:"account_id"`
|
||||
|
||||
// CloudId CrowdStrike cloud identifier
|
||||
CloudId string `json:"cloud_id"`
|
||||
|
||||
// CreatedAt Timestamp of when the integration was created.
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
// CreatedBy The user id that created the integration
|
||||
CreatedBy string `json:"created_by"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Groups List of groups
|
||||
Groups []Group `json:"groups"`
|
||||
|
||||
// Id The unique numeric identifier for the integration.
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// LastSyncedAt Timestamp of when the integration was last synced.
|
||||
LastSyncedAt time.Time `json:"last_synced_at"`
|
||||
|
||||
// UpdatedAt Timestamp of when the integration was last updated.
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// ZtaScoreThreshold The minimum Zero Trust Assessment score required for agent approval (0-100)
|
||||
ZtaScoreThreshold int `json:"zta_score_threshold"`
|
||||
}
|
||||
|
||||
// EDRHuntressRequest Request payload for creating or updating a EDR Huntress integration
|
||||
type EDRHuntressRequest struct {
|
||||
// ApiKey Huntress API key
|
||||
ApiKey string `json:"api_key"`
|
||||
|
||||
// ApiSecret Huntress API secret
|
||||
ApiSecret string `json:"api_secret"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// Groups The Groups this integrations applies to
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// LastSyncedInterval The devices last sync requirement interval in hours. Minimum value is 24 hours
|
||||
LastSyncedInterval int `json:"last_synced_interval"`
|
||||
|
||||
// MatchAttributes Attribute conditions to match when approving agents
|
||||
MatchAttributes HuntressMatchAttributes `json:"match_attributes"`
|
||||
}
|
||||
|
||||
// EDRHuntressResponse Represents a Huntress EDR integration configuration
|
||||
type EDRHuntressResponse struct {
|
||||
// AccountId The identifier of the account this integration belongs to.
|
||||
AccountId string `json:"account_id"`
|
||||
|
||||
// CreatedAt Timestamp of when the integration was created.
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
// CreatedBy The user id that created the integration
|
||||
CreatedBy string `json:"created_by"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Groups List of groups
|
||||
Groups []Group `json:"groups"`
|
||||
|
||||
// Id The unique numeric identifier for the integration.
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// LastSyncedAt Timestamp of when the integration was last synced.
|
||||
LastSyncedAt time.Time `json:"last_synced_at"`
|
||||
|
||||
// LastSyncedInterval The devices last sync requirement interval in hours.
|
||||
LastSyncedInterval int `json:"last_synced_interval"`
|
||||
|
||||
// MatchAttributes Attribute conditions to match when approving agents
|
||||
MatchAttributes HuntressMatchAttributes `json:"match_attributes"`
|
||||
|
||||
// UpdatedAt Timestamp of when the integration was last updated.
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// EDRIntuneRequest Request payload for creating or updating a EDR Intune integration.
|
||||
type EDRIntuneRequest struct {
|
||||
// ClientId The Azure application client id
|
||||
ClientId string `json:"client_id"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// Groups The Groups this integrations applies to
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// LastSyncedInterval The devices last sync requirement interval in hours. Minimum value is 24 hours.
|
||||
LastSyncedInterval int `json:"last_synced_interval"`
|
||||
|
||||
// Secret The Azure application client secret
|
||||
Secret string `json:"secret"`
|
||||
|
||||
// TenantId The Azure tenant id
|
||||
TenantId string `json:"tenant_id"`
|
||||
}
|
||||
|
||||
// EDRIntuneResponse Represents a Intune EDR integration configuration
|
||||
type EDRIntuneResponse struct {
|
||||
// AccountId The identifier of the account this integration belongs to.
|
||||
AccountId string `json:"account_id"`
|
||||
|
||||
// ClientId The Azure application client id
|
||||
ClientId string `json:"client_id"`
|
||||
|
||||
// CreatedAt Timestamp of when the integration was created.
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
// CreatedBy The user id that created the integration
|
||||
CreatedBy string `json:"created_by"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Groups List of groups
|
||||
Groups []Group `json:"groups"`
|
||||
|
||||
// Id The unique numeric identifier for the integration.
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// LastSyncedAt Timestamp of when the integration was last synced.
|
||||
LastSyncedAt time.Time `json:"last_synced_at"`
|
||||
|
||||
// LastSyncedInterval The devices last sync requirement interval in hours.
|
||||
LastSyncedInterval int `json:"last_synced_interval"`
|
||||
|
||||
// TenantId The Azure tenant id
|
||||
TenantId string `json:"tenant_id"`
|
||||
|
||||
// UpdatedAt Timestamp of when the integration was last updated.
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// EDRSentinelOneRequest Request payload for creating or updating a EDR SentinelOne integration
|
||||
type EDRSentinelOneRequest struct {
|
||||
// ApiToken SentinelOne API token
|
||||
ApiToken string `json:"api_token"`
|
||||
|
||||
// ApiUrl The Base URL of SentinelOne API
|
||||
ApiUrl string `json:"api_url"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// Groups The Groups this integrations applies to
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// LastSyncedInterval The devices last sync requirement interval in hours. Minimum value is 24 hours.
|
||||
LastSyncedInterval int `json:"last_synced_interval"`
|
||||
|
||||
// MatchAttributes Attribute conditions to match when approving agents
|
||||
MatchAttributes SentinelOneMatchAttributes `json:"match_attributes"`
|
||||
}
|
||||
|
||||
// EDRSentinelOneResponse Represents a SentinelOne EDR integration configuration
|
||||
type EDRSentinelOneResponse struct {
|
||||
// AccountId The identifier of the account this integration belongs to.
|
||||
AccountId string `json:"account_id"`
|
||||
|
||||
// ApiUrl The Base URL of SentinelOne API
|
||||
ApiUrl string `json:"api_url"`
|
||||
|
||||
// CreatedAt Timestamp of when the integration was created.
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
// CreatedBy The user id that created the integration
|
||||
CreatedBy string `json:"created_by"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Groups List of groups
|
||||
Groups []Group `json:"groups"`
|
||||
|
||||
// Id The unique numeric identifier for the integration.
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// LastSyncedAt Timestamp of when the integration was last synced.
|
||||
LastSyncedAt time.Time `json:"last_synced_at"`
|
||||
|
||||
// LastSyncedInterval The devices last sync requirement interval in hours.
|
||||
LastSyncedInterval int `json:"last_synced_interval"`
|
||||
|
||||
// MatchAttributes Attribute conditions to match when approving agents
|
||||
MatchAttributes SentinelOneMatchAttributes `json:"match_attributes"`
|
||||
|
||||
// UpdatedAt Timestamp of when the integration was last updated.
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// ErrorResponse Standard error response. Note: The exact structure of this error response is inferred from `util.WriteErrorResponse` and `util.WriteError` usage in the provided Go code, as a specific Go struct for errors was not provided.
|
||||
type ErrorResponse struct {
|
||||
// Message A human-readable error message.
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// Event defines model for Event.
|
||||
type Event struct {
|
||||
// Activity The activity that occurred during the event
|
||||
@@ -643,6 +977,9 @@ type GeoLocationCheck struct {
|
||||
// GeoLocationCheckAction Action to take upon policy match
|
||||
type GeoLocationCheckAction string
|
||||
|
||||
// GetTenantsResponse defines model for GetTenantsResponse.
|
||||
type GetTenantsResponse = []TenantResponse
|
||||
|
||||
// Group defines model for Group.
|
||||
type Group struct {
|
||||
// Id Group ID
|
||||
@@ -699,6 +1036,21 @@ type GroupRequest struct {
|
||||
Resources *[]Resource `json:"resources,omitempty"`
|
||||
}
|
||||
|
||||
// HuntressMatchAttributes Attribute conditions to match when approving agents
|
||||
type HuntressMatchAttributes struct {
|
||||
// DefenderPolicyStatus Policy status of Defender AV for Managed Antivirus.
|
||||
DefenderPolicyStatus *string `json:"defender_policy_status,omitempty"`
|
||||
|
||||
// DefenderStatus Status of Defender AV Managed Antivirus.
|
||||
DefenderStatus *string `json:"defender_status,omitempty"`
|
||||
|
||||
// DefenderSubstatus Sub-status of Defender AV Managed Antivirus.
|
||||
DefenderSubstatus *string `json:"defender_substatus,omitempty"`
|
||||
|
||||
// FirewallStatus Status of agent firewall. Can be one of Disabled, Enabled, Pending Isolation, Isolated, Pending Release.
|
||||
FirewallStatus *string `json:"firewall_status,omitempty"`
|
||||
}
|
||||
|
||||
// IdentityProvider defines model for IdentityProvider.
|
||||
type IdentityProvider struct {
|
||||
// ClientId OAuth2 client ID
|
||||
@@ -738,6 +1090,21 @@ type IdentityProviderRequest struct {
|
||||
// IdentityProviderType Type of identity provider
|
||||
type IdentityProviderType string
|
||||
|
||||
// IdpIntegrationSyncLog Represents a synchronization log entry for an integration
|
||||
type IdpIntegrationSyncLog struct {
|
||||
// Id The unique identifier for the sync log
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// Level The log level
|
||||
Level string `json:"level"`
|
||||
|
||||
// Message Log message
|
||||
Message string `json:"message"`
|
||||
|
||||
// Timestamp Timestamp of when the log was created
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// IngressPeer defines model for IngressPeer.
|
||||
type IngressPeer struct {
|
||||
AvailablePorts AvailablePorts `json:"available_ports"`
|
||||
@@ -892,6 +1259,57 @@ type InstanceVersionInfo struct {
|
||||
ManagementUpdateAvailable bool `json:"management_update_available"`
|
||||
}
|
||||
|
||||
// IntegrationResponse Represents an event streaming integration.
|
||||
type IntegrationResponse struct {
|
||||
// AccountId The identifier of the account this integration belongs to.
|
||||
AccountId *string `json:"account_id,omitempty"`
|
||||
|
||||
// Config Configuration for the integration. Sensitive keys (like API keys, secret keys) are masked with '****' in responses, as indicated by the GetIntegration handler logic.
|
||||
Config *map[string]string `json:"config,omitempty"`
|
||||
|
||||
// CreatedAt Timestamp of when the integration was created.
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||
|
||||
// Enabled Whether the integration is currently active.
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// Id The unique numeric identifier for the integration.
|
||||
Id *int64 `json:"id,omitempty"`
|
||||
|
||||
// Platform The event streaming platform.
|
||||
Platform *IntegrationResponsePlatform `json:"platform,omitempty"`
|
||||
|
||||
// UpdatedAt Timestamp of when the integration was last updated.
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
// IntegrationResponsePlatform The event streaming platform.
|
||||
type IntegrationResponsePlatform string
|
||||
|
||||
// InvoicePDFResponse defines model for InvoicePDFResponse.
|
||||
type InvoicePDFResponse struct {
|
||||
// Url URL to redirect the user to invoice.
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
// InvoiceResponse defines model for InvoiceResponse.
|
||||
type InvoiceResponse struct {
|
||||
// Id The Stripe invoice id
|
||||
Id string `json:"id"`
|
||||
|
||||
// PeriodEnd The end date of the invoice period.
|
||||
PeriodEnd time.Time `json:"period_end"`
|
||||
|
||||
// PeriodStart The start date of the invoice period.
|
||||
PeriodStart time.Time `json:"period_start"`
|
||||
|
||||
// Type The invoice type
|
||||
Type InvoiceResponseType `json:"type"`
|
||||
}
|
||||
|
||||
// InvoiceResponseType The invoice type
|
||||
type InvoiceResponseType string
|
||||
|
||||
// JobRequest defines model for JobRequest.
|
||||
type JobRequest struct {
|
||||
Workload WorkloadRequest `json:"workload"`
|
||||
@@ -1797,6 +2215,15 @@ type PolicyUpdate struct {
|
||||
SourcePostureChecks *[]string `json:"source_posture_checks,omitempty"`
|
||||
}
|
||||
|
||||
// PortalResponse defines model for PortalResponse.
|
||||
type PortalResponse struct {
|
||||
// SessionId The unique identifier for the customer portal session.
|
||||
SessionId string `json:"session_id"`
|
||||
|
||||
// Url URL to redirect the user to the customer portal.
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
// PostureCheck defines model for PostureCheck.
|
||||
type PostureCheck struct {
|
||||
// Checks List of objects that perform the actual checks
|
||||
@@ -1824,6 +2251,21 @@ type PostureCheckUpdate struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Price defines model for Price.
|
||||
type Price struct {
|
||||
// Currency Currency code for this price.
|
||||
Currency string `json:"currency"`
|
||||
|
||||
// Price Price amount in minor units (e.g., cents).
|
||||
Price int `json:"price"`
|
||||
|
||||
// PriceId Unique identifier for the price.
|
||||
PriceId string `json:"price_id"`
|
||||
|
||||
// Unit Unit of measurement for this price (e.g., per user).
|
||||
Unit string `json:"unit"`
|
||||
}
|
||||
|
||||
// Process Describes the operational activity within a peer's system.
|
||||
type Process struct {
|
||||
// LinuxPath Path to the process executable file in a Linux operating system
|
||||
@@ -1841,6 +2283,24 @@ type ProcessCheck struct {
|
||||
Processes []Process `json:"processes"`
|
||||
}
|
||||
|
||||
// Product defines model for Product.
|
||||
type Product struct {
|
||||
// Description Detailed description of the product.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Features List of features provided by the product.
|
||||
Features []string `json:"features"`
|
||||
|
||||
// Free Indicates whether the product is free or not.
|
||||
Free bool `json:"free"`
|
||||
|
||||
// Name Name of the product.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Prices List of prices for the product in different currencies
|
||||
Prices []Price `json:"prices"`
|
||||
}
|
||||
|
||||
// Resource defines model for Resource.
|
||||
type Resource struct {
|
||||
// Id ID of the resource
|
||||
@@ -1950,6 +2410,66 @@ type RulePortRange struct {
|
||||
Start int `json:"start"`
|
||||
}
|
||||
|
||||
// ScimIntegration Represents a SCIM IDP integration
|
||||
type ScimIntegration struct {
|
||||
// AuthToken SCIM API token (full on creation, masked otherwise)
|
||||
AuthToken string `json:"auth_token"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes []string `json:"group_prefixes"`
|
||||
|
||||
// Id The unique identifier for the integration
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// LastSyncedAt Timestamp of when the integration was last synced
|
||||
LastSyncedAt time.Time `json:"last_synced_at"`
|
||||
|
||||
// Provider Name of the SCIM identity provider
|
||||
Provider string `json:"provider"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes []string `json:"user_group_prefixes"`
|
||||
}
|
||||
|
||||
// ScimTokenResponse Response containing the regenerated SCIM token
|
||||
type ScimTokenResponse struct {
|
||||
// AuthToken The newly generated SCIM API token
|
||||
AuthToken string `json:"auth_token"`
|
||||
}
|
||||
|
||||
// SentinelOneMatchAttributes Attribute conditions to match when approving agents
|
||||
type SentinelOneMatchAttributes struct {
|
||||
// ActiveThreats The maximum allowed number of active threats on the agent
|
||||
ActiveThreats *int `json:"active_threats,omitempty"`
|
||||
|
||||
// EncryptedApplications Whether disk encryption is enabled on the agent
|
||||
EncryptedApplications *bool `json:"encrypted_applications,omitempty"`
|
||||
|
||||
// FirewallEnabled Whether the agent firewall is enabled
|
||||
FirewallEnabled *bool `json:"firewall_enabled,omitempty"`
|
||||
|
||||
// Infected Whether the agent is currently flagged as infected
|
||||
Infected *bool `json:"infected,omitempty"`
|
||||
|
||||
// IsActive Whether the agent has been recently active and reporting
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
|
||||
// IsUpToDate Whether the agent is running the latest available version
|
||||
IsUpToDate *bool `json:"is_up_to_date,omitempty"`
|
||||
|
||||
// NetworkStatus The current network connectivity status of the device
|
||||
NetworkStatus *SentinelOneMatchAttributesNetworkStatus `json:"network_status,omitempty"`
|
||||
|
||||
// OperationalState The current operational state of the agent
|
||||
OperationalState *string `json:"operational_state,omitempty"`
|
||||
}
|
||||
|
||||
// SentinelOneMatchAttributesNetworkStatus The current network connectivity status of the device
|
||||
type SentinelOneMatchAttributesNetworkStatus string
|
||||
|
||||
// SetupKey defines model for SetupKey.
|
||||
type SetupKey struct {
|
||||
// AllowExtraDnsLabels Allow extra DNS labels to be added to the peer
|
||||
@@ -2121,6 +2641,117 @@ type SetupResponse struct {
|
||||
UserId string `json:"user_id"`
|
||||
}
|
||||
|
||||
// Subscription defines model for Subscription.
|
||||
type Subscription struct {
|
||||
// Active Indicates whether the subscription is active or not.
|
||||
Active bool `json:"active"`
|
||||
|
||||
// Currency Currency code of the subscription.
|
||||
Currency string `json:"currency"`
|
||||
|
||||
// Features List of features included in the subscription.
|
||||
Features *[]string `json:"features,omitempty"`
|
||||
|
||||
// PlanTier The tier of the plan for the subscription.
|
||||
PlanTier string `json:"plan_tier"`
|
||||
|
||||
// Price Price amount in minor units (e.g., cents).
|
||||
Price int `json:"price"`
|
||||
|
||||
// PriceId Unique identifier for the price of the subscription.
|
||||
PriceId string `json:"price_id"`
|
||||
|
||||
// Provider The provider of the subscription.
|
||||
Provider string `json:"provider"`
|
||||
|
||||
// RemainingTrial The remaining time for the trial period, in seconds.
|
||||
RemainingTrial *int `json:"remaining_trial,omitempty"`
|
||||
|
||||
// UpdatedAt The date and time when the subscription was last updated.
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// TenantGroupResponse defines model for TenantGroupResponse.
|
||||
type TenantGroupResponse struct {
|
||||
// Id The Group ID
|
||||
Id string `json:"id"`
|
||||
|
||||
// Role The Role name
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
// TenantResponse defines model for TenantResponse.
|
||||
type TenantResponse struct {
|
||||
// ActivatedAt The date and time when the tenant was activated.
|
||||
ActivatedAt *time.Time `json:"activated_at,omitempty"`
|
||||
|
||||
// CreatedAt The date and time when the tenant was created.
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
// DnsChallenge The DNS challenge to set in a TXT record
|
||||
DnsChallenge string `json:"dns_challenge"`
|
||||
|
||||
// Domain The tenant account domain
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Groups MSP users Groups that can access the Tenant and Roles to assume
|
||||
Groups []TenantGroupResponse `json:"groups"`
|
||||
|
||||
// Id The updated MSP tenant account ID
|
||||
Id string `json:"id"`
|
||||
|
||||
// InvitedAt The date and time when the existing tenant was invited.
|
||||
InvitedAt *time.Time `json:"invited_at,omitempty"`
|
||||
|
||||
// Name The name for the MSP tenant
|
||||
Name string `json:"name"`
|
||||
|
||||
// Status The status of the tenant
|
||||
Status TenantResponseStatus `json:"status"`
|
||||
|
||||
// UpdatedAt The date and time when the tenant was last updated.
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// TenantResponseStatus The status of the tenant
|
||||
type TenantResponseStatus string
|
||||
|
||||
// UpdateScimIntegrationRequest Request payload for updating an SCIM IDP integration
|
||||
type UpdateScimIntegrationRequest struct {
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateTenantRequest defines model for UpdateTenantRequest.
|
||||
type UpdateTenantRequest struct {
|
||||
// Groups MSP users Groups that can access the Tenant and Roles to assume
|
||||
Groups []TenantGroupResponse `json:"groups"`
|
||||
|
||||
// Name The name for the MSP tenant
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// UsageStats defines model for UsageStats.
|
||||
type UsageStats struct {
|
||||
// ActivePeers Number of active peers.
|
||||
ActivePeers int64 `json:"active_peers"`
|
||||
|
||||
// ActiveUsers Number of active users.
|
||||
ActiveUsers int64 `json:"active_users"`
|
||||
|
||||
// TotalPeers Total number of peers.
|
||||
TotalPeers int64 `json:"total_peers"`
|
||||
|
||||
// TotalUsers Total number of users.
|
||||
TotalUsers int64 `json:"total_users"`
|
||||
}
|
||||
|
||||
// User defines model for User.
|
||||
type User struct {
|
||||
// AutoGroups Group IDs to auto-assign to peers registered by this user
|
||||
@@ -2407,6 +3038,66 @@ type GetApiGroupsParams struct {
|
||||
Name *string `form:"name,omitempty" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
// PostApiIntegrationsBillingAwsMarketplaceActivateJSONBody defines parameters for PostApiIntegrationsBillingAwsMarketplaceActivate.
|
||||
type PostApiIntegrationsBillingAwsMarketplaceActivateJSONBody struct {
|
||||
// PlanTier The plan tier to activate the subscription for.
|
||||
PlanTier string `json:"plan_tier"`
|
||||
}
|
||||
|
||||
// PostApiIntegrationsBillingAwsMarketplaceEnrichJSONBody defines parameters for PostApiIntegrationsBillingAwsMarketplaceEnrich.
|
||||
type PostApiIntegrationsBillingAwsMarketplaceEnrichJSONBody struct {
|
||||
// AwsUserId The AWS user ID.
|
||||
AwsUserId string `json:"aws_user_id"`
|
||||
}
|
||||
|
||||
// PostApiIntegrationsBillingCheckoutJSONBody defines parameters for PostApiIntegrationsBillingCheckout.
|
||||
type PostApiIntegrationsBillingCheckoutJSONBody struct {
|
||||
// BaseURL The base URL for the redirect after checkout.
|
||||
BaseURL string `json:"baseURL"`
|
||||
|
||||
// EnableTrial Enables a 14-day trial for the account.
|
||||
EnableTrial *bool `json:"enableTrial,omitempty"`
|
||||
|
||||
// PriceID The Price ID for checkout.
|
||||
PriceID string `json:"priceID"`
|
||||
}
|
||||
|
||||
// GetApiIntegrationsBillingPortalParams defines parameters for GetApiIntegrationsBillingPortal.
|
||||
type GetApiIntegrationsBillingPortalParams struct {
|
||||
// BaseURL The base URL for the redirect after accessing the portal.
|
||||
BaseURL string `form:"baseURL" json:"baseURL"`
|
||||
}
|
||||
|
||||
// PutApiIntegrationsBillingSubscriptionJSONBody defines parameters for PutApiIntegrationsBillingSubscription.
|
||||
type PutApiIntegrationsBillingSubscriptionJSONBody struct {
|
||||
// PlanTier The plan tier to change the subscription to.
|
||||
PlanTier *string `json:"plan_tier,omitempty"`
|
||||
|
||||
// PriceID The Price ID to change the subscription to.
|
||||
PriceID *string `json:"priceID,omitempty"`
|
||||
}
|
||||
|
||||
// PutApiIntegrationsMspTenantsIdInviteJSONBody defines parameters for PutApiIntegrationsMspTenantsIdInvite.
|
||||
type PutApiIntegrationsMspTenantsIdInviteJSONBody struct {
|
||||
// Value Accept or decline the invitation.
|
||||
Value PutApiIntegrationsMspTenantsIdInviteJSONBodyValue `json:"value"`
|
||||
}
|
||||
|
||||
// PutApiIntegrationsMspTenantsIdInviteJSONBodyValue defines parameters for PutApiIntegrationsMspTenantsIdInvite.
|
||||
type PutApiIntegrationsMspTenantsIdInviteJSONBodyValue string
|
||||
|
||||
// PostApiIntegrationsMspTenantsIdSubscriptionJSONBody defines parameters for PostApiIntegrationsMspTenantsIdSubscription.
|
||||
type PostApiIntegrationsMspTenantsIdSubscriptionJSONBody struct {
|
||||
// PriceID The Price ID to change the subscription to.
|
||||
PriceID string `json:"priceID"`
|
||||
}
|
||||
|
||||
// PostApiIntegrationsMspTenantsIdUnlinkJSONBody defines parameters for PostApiIntegrationsMspTenantsIdUnlink.
|
||||
type PostApiIntegrationsMspTenantsIdUnlinkJSONBody struct {
|
||||
// Owner The new owners user ID.
|
||||
Owner string `json:"owner"`
|
||||
}
|
||||
|
||||
// GetApiPeersParams defines parameters for GetApiPeers.
|
||||
type GetApiPeersParams struct {
|
||||
// Name Filter peers by name
|
||||
@@ -2452,6 +3143,12 @@ type PostApiDnsZonesZoneIdRecordsJSONRequestBody = DNSRecordRequest
|
||||
// PutApiDnsZonesZoneIdRecordsRecordIdJSONRequestBody defines body for PutApiDnsZonesZoneIdRecordsRecordId for application/json ContentType.
|
||||
type PutApiDnsZonesZoneIdRecordsRecordIdJSONRequestBody = DNSRecordRequest
|
||||
|
||||
// CreateIntegrationJSONRequestBody defines body for CreateIntegration for application/json ContentType.
|
||||
type CreateIntegrationJSONRequestBody = CreateIntegrationRequest
|
||||
|
||||
// UpdateIntegrationJSONRequestBody defines body for UpdateIntegration for application/json ContentType.
|
||||
type UpdateIntegrationJSONRequestBody = CreateIntegrationRequest
|
||||
|
||||
// PostApiGroupsJSONRequestBody defines body for PostApiGroups for application/json ContentType.
|
||||
type PostApiGroupsJSONRequestBody = GroupRequest
|
||||
|
||||
@@ -2470,6 +3167,63 @@ type PostApiIngressPeersJSONRequestBody = IngressPeerCreateRequest
|
||||
// PutApiIngressPeersIngressPeerIdJSONRequestBody defines body for PutApiIngressPeersIngressPeerId for application/json ContentType.
|
||||
type PutApiIngressPeersIngressPeerIdJSONRequestBody = IngressPeerUpdateRequest
|
||||
|
||||
// PostApiIntegrationsBillingAwsMarketplaceActivateJSONRequestBody defines body for PostApiIntegrationsBillingAwsMarketplaceActivate for application/json ContentType.
|
||||
type PostApiIntegrationsBillingAwsMarketplaceActivateJSONRequestBody PostApiIntegrationsBillingAwsMarketplaceActivateJSONBody
|
||||
|
||||
// PostApiIntegrationsBillingAwsMarketplaceEnrichJSONRequestBody defines body for PostApiIntegrationsBillingAwsMarketplaceEnrich for application/json ContentType.
|
||||
type PostApiIntegrationsBillingAwsMarketplaceEnrichJSONRequestBody PostApiIntegrationsBillingAwsMarketplaceEnrichJSONBody
|
||||
|
||||
// PostApiIntegrationsBillingCheckoutJSONRequestBody defines body for PostApiIntegrationsBillingCheckout for application/json ContentType.
|
||||
type PostApiIntegrationsBillingCheckoutJSONRequestBody PostApiIntegrationsBillingCheckoutJSONBody
|
||||
|
||||
// PutApiIntegrationsBillingSubscriptionJSONRequestBody defines body for PutApiIntegrationsBillingSubscription for application/json ContentType.
|
||||
type PutApiIntegrationsBillingSubscriptionJSONRequestBody PutApiIntegrationsBillingSubscriptionJSONBody
|
||||
|
||||
// CreateFalconEDRIntegrationJSONRequestBody defines body for CreateFalconEDRIntegration for application/json ContentType.
|
||||
type CreateFalconEDRIntegrationJSONRequestBody = EDRFalconRequest
|
||||
|
||||
// UpdateFalconEDRIntegrationJSONRequestBody defines body for UpdateFalconEDRIntegration for application/json ContentType.
|
||||
type UpdateFalconEDRIntegrationJSONRequestBody = EDRFalconRequest
|
||||
|
||||
// CreateHuntressEDRIntegrationJSONRequestBody defines body for CreateHuntressEDRIntegration for application/json ContentType.
|
||||
type CreateHuntressEDRIntegrationJSONRequestBody = EDRHuntressRequest
|
||||
|
||||
// UpdateHuntressEDRIntegrationJSONRequestBody defines body for UpdateHuntressEDRIntegration for application/json ContentType.
|
||||
type UpdateHuntressEDRIntegrationJSONRequestBody = EDRHuntressRequest
|
||||
|
||||
// CreateEDRIntegrationJSONRequestBody defines body for CreateEDRIntegration for application/json ContentType.
|
||||
type CreateEDRIntegrationJSONRequestBody = EDRIntuneRequest
|
||||
|
||||
// UpdateEDRIntegrationJSONRequestBody defines body for UpdateEDRIntegration for application/json ContentType.
|
||||
type UpdateEDRIntegrationJSONRequestBody = EDRIntuneRequest
|
||||
|
||||
// CreateSentinelOneEDRIntegrationJSONRequestBody defines body for CreateSentinelOneEDRIntegration for application/json ContentType.
|
||||
type CreateSentinelOneEDRIntegrationJSONRequestBody = EDRSentinelOneRequest
|
||||
|
||||
// UpdateSentinelOneEDRIntegrationJSONRequestBody defines body for UpdateSentinelOneEDRIntegration for application/json ContentType.
|
||||
type UpdateSentinelOneEDRIntegrationJSONRequestBody = EDRSentinelOneRequest
|
||||
|
||||
// PostApiIntegrationsMspTenantsJSONRequestBody defines body for PostApiIntegrationsMspTenants for application/json ContentType.
|
||||
type PostApiIntegrationsMspTenantsJSONRequestBody = CreateTenantRequest
|
||||
|
||||
// PutApiIntegrationsMspTenantsIdJSONRequestBody defines body for PutApiIntegrationsMspTenantsId for application/json ContentType.
|
||||
type PutApiIntegrationsMspTenantsIdJSONRequestBody = UpdateTenantRequest
|
||||
|
||||
// PutApiIntegrationsMspTenantsIdInviteJSONRequestBody defines body for PutApiIntegrationsMspTenantsIdInvite for application/json ContentType.
|
||||
type PutApiIntegrationsMspTenantsIdInviteJSONRequestBody PutApiIntegrationsMspTenantsIdInviteJSONBody
|
||||
|
||||
// PostApiIntegrationsMspTenantsIdSubscriptionJSONRequestBody defines body for PostApiIntegrationsMspTenantsIdSubscription for application/json ContentType.
|
||||
type PostApiIntegrationsMspTenantsIdSubscriptionJSONRequestBody PostApiIntegrationsMspTenantsIdSubscriptionJSONBody
|
||||
|
||||
// PostApiIntegrationsMspTenantsIdUnlinkJSONRequestBody defines body for PostApiIntegrationsMspTenantsIdUnlink for application/json ContentType.
|
||||
type PostApiIntegrationsMspTenantsIdUnlinkJSONRequestBody PostApiIntegrationsMspTenantsIdUnlinkJSONBody
|
||||
|
||||
// CreateSCIMIntegrationJSONRequestBody defines body for CreateSCIMIntegration for application/json ContentType.
|
||||
type CreateSCIMIntegrationJSONRequestBody = CreateScimIntegrationRequest
|
||||
|
||||
// UpdateSCIMIntegrationJSONRequestBody defines body for UpdateSCIMIntegration for application/json ContentType.
|
||||
type UpdateSCIMIntegrationJSONRequestBody = UpdateScimIntegrationRequest
|
||||
|
||||
// PostApiNetworksJSONRequestBody defines body for PostApiNetworks for application/json ContentType.
|
||||
type PostApiNetworksJSONRequestBody = NetworkRequest
|
||||
|
||||
|
||||
Reference in New Issue
Block a user