mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00: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
|
// Events NetBird Events APIs
|
||||||
// see more: https://docs.netbird.io/api/resources/events
|
// see more: https://docs.netbird.io/api/resources/events
|
||||||
Events *EventsAPI
|
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
|
// New initialize new Client instance using PAT token
|
||||||
@@ -120,6 +152,14 @@ func (c *Client) initialize() {
|
|||||||
c.DNSZones = &DNSZonesAPI{c}
|
c.DNSZones = &DNSZonesAPI{c}
|
||||||
c.GeoLocation = &GeoLocationAPI{c}
|
c.GeoLocation = &GeoLocationAPI{c}
|
||||||
c.Events = &EventsAPI{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
|
// 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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
)
|
)
|
||||||
@@ -11,10 +13,79 @@ type EventsAPI struct {
|
|||||||
c *Client
|
c *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list all events
|
// NetworkTrafficOption options for ListNetworkTrafficEvents API
|
||||||
// See more: https://docs.netbird.io/api/resources/events#list-all-events
|
type NetworkTrafficOption func(query map[string]string)
|
||||||
func (a *EventsAPI) List(ctx context.Context) ([]api.Event, error) {
|
|
||||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/events", nil, nil)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -24,3 +95,21 @@ func (a *EventsAPI) List(ctx context.Context) ([]api.Event, error) {
|
|||||||
ret, err := parseResponse[[]api.Event](resp)
|
ret, err := parseResponse[[]api.Event](resp)
|
||||||
return ret, err
|
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",
|
Activity: "AccountCreate",
|
||||||
ActivityCode: api.EventActivityCodeAccountCreate,
|
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) {
|
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})
|
retBytes, _ := json.Marshal([]api.Event{testEvent})
|
||||||
_, err := w.Write(retBytes)
|
_, err := w.Write(retBytes)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
ret, err := c.Events.List(context.Background())
|
ret, err := c.Events.ListAuditEvents(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, ret, 1)
|
assert.Len(t, ret, 1)
|
||||||
assert.Equal(t, testEvent, ret[0])
|
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) {
|
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})
|
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
_, err := w.Write(retBytes)
|
_, err := w.Write(retBytes)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
ret, err := c.Events.List(context.Background())
|
ret, err := c.Events.ListAuditEvents(context.Background())
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, "No", err.Error())
|
assert.Equal(t, "No", err.Error())
|
||||||
assert.Empty(t, ret)
|
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) {
|
func TestEvents_Integration(t *testing.T) {
|
||||||
withBlackBoxServer(t, func(c *rest.Client) {
|
withBlackBoxServer(t, func(c *rest.Client) {
|
||||||
// Do something that would trigger any event
|
// Do something that would trigger any event
|
||||||
@@ -62,7 +101,7 @@ func TestEvents_Integration(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
events, err := c.Events.List(context.Background())
|
events, err := c.Events.ListAuditEvents(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NotEmpty(t, events)
|
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
|
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
|
// NetworkResourcesAPI APIs for Network Resources, do not use directly
|
||||||
type NetworkResourcesAPI struct {
|
type NetworkResourcesAPI struct {
|
||||||
c *Client
|
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) {
|
func TestNetworkResources_List_200(t *testing.T) {
|
||||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||||
mux.HandleFunc("/api/networks/Meow/resources", func(w http.ResponseWriter, r *http.Request) {
|
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)
|
ret, err := parseResponse[[]api.Peer](resp)
|
||||||
return ret, err
|
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",
|
DnsLabel: "test",
|
||||||
Id: "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) {
|
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) {
|
func TestPeers_Integration(t *testing.T) {
|
||||||
withBlackBoxServer(t, func(c *rest.Client) {
|
withBlackBoxServer(t, func(c *rest.Client) {
|
||||||
peers, err := c.Peers.List(context.Background())
|
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)
|
ret, err := parseResponse[api.User](resp)
|
||||||
return &ret, err
|
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",
|
Role: "user",
|
||||||
Status: api.UserStatusActive,
|
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) {
|
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) {
|
func TestUsers_Integration(t *testing.T) {
|
||||||
withBlackBoxServer(t, func(c *rest.Client) {
|
withBlackBoxServer(t, func(c *rest.Client) {
|
||||||
// rest client PAT is owner's
|
// rest client PAT is owner's
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,14 @@ const (
|
|||||||
TokenAuthScopes = "TokenAuth.Scopes"
|
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.
|
// Defines values for DNSRecordType.
|
||||||
const (
|
const (
|
||||||
DNSRecordTypeA DNSRecordType = "A"
|
DNSRecordTypeA DNSRecordType = "A"
|
||||||
@@ -188,6 +196,20 @@ const (
|
|||||||
IngressPortAllocationRequestPortRangeProtocolUdp IngressPortAllocationRequestPortRangeProtocol = "udp"
|
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.
|
// Defines values for JobResponseStatus.
|
||||||
const (
|
const (
|
||||||
JobResponseStatusFailed JobResponseStatus = "failed"
|
JobResponseStatusFailed JobResponseStatus = "failed"
|
||||||
@@ -266,6 +288,21 @@ const (
|
|||||||
ResourceTypeSubnet ResourceType = "subnet"
|
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.
|
// Defines values for UserStatus.
|
||||||
const (
|
const (
|
||||||
UserStatusActive UserStatus = "active"
|
UserStatusActive UserStatus = "active"
|
||||||
@@ -299,6 +336,12 @@ const (
|
|||||||
GetApiEventsNetworkTrafficParamsDirectionINGRESS GetApiEventsNetworkTrafficParamsDirection = "INGRESS"
|
GetApiEventsNetworkTrafficParamsDirectionINGRESS GetApiEventsNetworkTrafficParamsDirection = "INGRESS"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Defines values for PutApiIntegrationsMspTenantsIdInviteJSONBodyValue.
|
||||||
|
const (
|
||||||
|
PutApiIntegrationsMspTenantsIdInviteJSONBodyValueAccept PutApiIntegrationsMspTenantsIdInviteJSONBodyValue = "accept"
|
||||||
|
PutApiIntegrationsMspTenantsIdInviteJSONBodyValueDecline PutApiIntegrationsMspTenantsIdInviteJSONBodyValue = "decline"
|
||||||
|
)
|
||||||
|
|
||||||
// AccessiblePeer defines model for AccessiblePeer.
|
// AccessiblePeer defines model for AccessiblePeer.
|
||||||
type AccessiblePeer struct {
|
type AccessiblePeer struct {
|
||||||
// CityName Commonly used English name of the city
|
// CityName Commonly used English name of the city
|
||||||
@@ -490,6 +533,21 @@ type BundleWorkloadResponse struct {
|
|||||||
Type WorkloadType `json:"type"`
|
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
|
// Checks List of objects that perform the actual checks
|
||||||
type Checks struct {
|
type Checks struct {
|
||||||
// GeoLocationCheck Posture check for geo location
|
// 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
|
// CountryCode 2-letter ISO 3166-1 alpha-2 code that represents the country
|
||||||
type CountryCode = string
|
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.
|
// CreateSetupKeyRequest defines model for CreateSetupKeyRequest.
|
||||||
type CreateSetupKeyRequest struct {
|
type CreateSetupKeyRequest struct {
|
||||||
// AllowExtraDnsLabels Allow extra DNS labels to be added to the peer
|
// AllowExtraDnsLabels Allow extra DNS labels to be added to the peer
|
||||||
@@ -556,6 +644,24 @@ type CreateSetupKeyRequest struct {
|
|||||||
UsageLimit int `json:"usage_limit"`
|
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.
|
// DNSRecord defines model for DNSRecord.
|
||||||
type DNSRecord struct {
|
type DNSRecord struct {
|
||||||
// Content DNS record content (IP address for A/AAAA, domain for CNAME)
|
// 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"`
|
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.
|
// Event defines model for Event.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
// Activity The activity that occurred during the event
|
// Activity The activity that occurred during the event
|
||||||
@@ -643,6 +977,9 @@ type GeoLocationCheck struct {
|
|||||||
// GeoLocationCheckAction Action to take upon policy match
|
// GeoLocationCheckAction Action to take upon policy match
|
||||||
type GeoLocationCheckAction string
|
type GeoLocationCheckAction string
|
||||||
|
|
||||||
|
// GetTenantsResponse defines model for GetTenantsResponse.
|
||||||
|
type GetTenantsResponse = []TenantResponse
|
||||||
|
|
||||||
// Group defines model for Group.
|
// Group defines model for Group.
|
||||||
type Group struct {
|
type Group struct {
|
||||||
// Id Group ID
|
// Id Group ID
|
||||||
@@ -699,6 +1036,21 @@ type GroupRequest struct {
|
|||||||
Resources *[]Resource `json:"resources,omitempty"`
|
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.
|
// IdentityProvider defines model for IdentityProvider.
|
||||||
type IdentityProvider struct {
|
type IdentityProvider struct {
|
||||||
// ClientId OAuth2 client ID
|
// ClientId OAuth2 client ID
|
||||||
@@ -738,6 +1090,21 @@ type IdentityProviderRequest struct {
|
|||||||
// IdentityProviderType Type of identity provider
|
// IdentityProviderType Type of identity provider
|
||||||
type IdentityProviderType string
|
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.
|
// IngressPeer defines model for IngressPeer.
|
||||||
type IngressPeer struct {
|
type IngressPeer struct {
|
||||||
AvailablePorts AvailablePorts `json:"available_ports"`
|
AvailablePorts AvailablePorts `json:"available_ports"`
|
||||||
@@ -892,6 +1259,57 @@ type InstanceVersionInfo struct {
|
|||||||
ManagementUpdateAvailable bool `json:"management_update_available"`
|
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.
|
// JobRequest defines model for JobRequest.
|
||||||
type JobRequest struct {
|
type JobRequest struct {
|
||||||
Workload WorkloadRequest `json:"workload"`
|
Workload WorkloadRequest `json:"workload"`
|
||||||
@@ -1797,6 +2215,15 @@ type PolicyUpdate struct {
|
|||||||
SourcePostureChecks *[]string `json:"source_posture_checks,omitempty"`
|
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.
|
// PostureCheck defines model for PostureCheck.
|
||||||
type PostureCheck struct {
|
type PostureCheck struct {
|
||||||
// Checks List of objects that perform the actual checks
|
// Checks List of objects that perform the actual checks
|
||||||
@@ -1824,6 +2251,21 @@ type PostureCheckUpdate struct {
|
|||||||
Name string `json:"name"`
|
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.
|
// Process Describes the operational activity within a peer's system.
|
||||||
type Process struct {
|
type Process struct {
|
||||||
// LinuxPath Path to the process executable file in a Linux operating system
|
// LinuxPath Path to the process executable file in a Linux operating system
|
||||||
@@ -1841,6 +2283,24 @@ type ProcessCheck struct {
|
|||||||
Processes []Process `json:"processes"`
|
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.
|
// Resource defines model for Resource.
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
// Id ID of the resource
|
// Id ID of the resource
|
||||||
@@ -1950,6 +2410,66 @@ type RulePortRange struct {
|
|||||||
Start int `json:"start"`
|
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.
|
// SetupKey defines model for SetupKey.
|
||||||
type SetupKey struct {
|
type SetupKey struct {
|
||||||
// AllowExtraDnsLabels Allow extra DNS labels to be added to the peer
|
// AllowExtraDnsLabels Allow extra DNS labels to be added to the peer
|
||||||
@@ -2121,6 +2641,117 @@ type SetupResponse struct {
|
|||||||
UserId string `json:"user_id"`
|
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.
|
// User defines model for User.
|
||||||
type User struct {
|
type User struct {
|
||||||
// AutoGroups Group IDs to auto-assign to peers registered by this user
|
// 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"`
|
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.
|
// GetApiPeersParams defines parameters for GetApiPeers.
|
||||||
type GetApiPeersParams struct {
|
type GetApiPeersParams struct {
|
||||||
// Name Filter peers by name
|
// Name Filter peers by name
|
||||||
@@ -2452,6 +3143,12 @@ type PostApiDnsZonesZoneIdRecordsJSONRequestBody = DNSRecordRequest
|
|||||||
// PutApiDnsZonesZoneIdRecordsRecordIdJSONRequestBody defines body for PutApiDnsZonesZoneIdRecordsRecordId for application/json ContentType.
|
// PutApiDnsZonesZoneIdRecordsRecordIdJSONRequestBody defines body for PutApiDnsZonesZoneIdRecordsRecordId for application/json ContentType.
|
||||||
type PutApiDnsZonesZoneIdRecordsRecordIdJSONRequestBody = DNSRecordRequest
|
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.
|
// PostApiGroupsJSONRequestBody defines body for PostApiGroups for application/json ContentType.
|
||||||
type PostApiGroupsJSONRequestBody = GroupRequest
|
type PostApiGroupsJSONRequestBody = GroupRequest
|
||||||
|
|
||||||
@@ -2470,6 +3167,63 @@ type PostApiIngressPeersJSONRequestBody = IngressPeerCreateRequest
|
|||||||
// PutApiIngressPeersIngressPeerIdJSONRequestBody defines body for PutApiIngressPeersIngressPeerId for application/json ContentType.
|
// PutApiIngressPeersIngressPeerIdJSONRequestBody defines body for PutApiIngressPeersIngressPeerId for application/json ContentType.
|
||||||
type PutApiIngressPeersIngressPeerIdJSONRequestBody = IngressPeerUpdateRequest
|
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.
|
// PostApiNetworksJSONRequestBody defines body for PostApiNetworks for application/json ContentType.
|
||||||
type PostApiNetworksJSONRequestBody = NetworkRequest
|
type PostApiNetworksJSONRequestBody = NetworkRequest
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user