package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" ) type Account struct { AccountID string `json:"account_id"` AccountName string `json:"account_name"` AlertEmails []string `json:"alert_emails"` BillingAddress BillingAddress `json:"billing_address"` PrimaryContact string `json:"primary_contact"` PrimaryEmail string `json:"primary_email"` PrimaryPhone string `json:"primary_phone"` } type BillingAddress struct { City string `json:"City"` Country string `json:"Country"` Line1 string `json:"Line1"` Line2 string `json:"Line2"` PostalCode string `json:"PostalCode"` State string `json:"State"` } type AccountService struct { baseEndpoint string requestClient *requestClient } // https://docs.slide.tech/api/#tag/accounts/GET/v1/account func (a AccountService) List( ctx context.Context, pageHandler func(response ListResponse[Account]) error, ) error { return a.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/accounts/GET/v1/account func (a AccountService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[Account]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[Account]{} endpoint := a.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := a.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/accounts/GET/v1/account/{account_id} func (a AccountService) Get(ctx context.Context, accountID string) (Account, error) { target := Account{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, a.baseEndpoint+"/"+accountID, http.NoBody, ) if err != nil { return Account{}, err } if err := a.requestClient.SlideRequest(request, &target); err != nil { return Account{}, err } return target, nil } // https://docs.slide.tech/api/#tag/accounts/PATCH/v1/account/{account_id} func (a AccountService) Update( ctx context.Context, accountID string, alertEmails []string, ) (Account, error) { type accountPayload struct { AlertEmails []string `json:"alert_emails"` } payloadBytes, err := json.Marshal(accountPayload{ AlertEmails: alertEmails, }) if err != nil { return Account{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPatch, a.baseEndpoint+"/"+accountID, requestBody, ) if err != nil { return Account{}, err } target := Account{} if err := a.requestClient.SlideRequest(request, &target); err != nil { return Account{}, err } return target, nil }
package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" "time" ) type Agent struct { Addresses []Address `json:"addresses"` AgentID string `json:"agent_id"` AgentVersion string `json:"agent_version"` BootedAt time.Time `json:"booted_at"` ClientID string `json:"client_id"` DeviceID string `json:"device_id"` DisplayName string `json:"display_name"` EncryptionAlgorithm string `json:"encryption_algorithm"` FirmwareType string `json:"firmware_type"` Hostname string `json:"hostname"` LastSeenAt time.Time `json:"last_seen_at"` Manufacturer string `json:"manufacturer"` OS string `json:"os"` OSVersion string `json:"os_version"` Platform string `json:"platform"` PublicIPAddress string `json:"public_ip_address"` } type AgentService struct { baseEndpoint string requestClient *requestClient } type AgentAutoPairPayload struct { DeviceID string `json:"device_id"` DisplayName string `json:"display_name"` } type AgentAutoPairResponse struct { AgentID string `json:"agent_id"` DisplayName string `json:"display_name"` PairCode string `json:"pair_code"` } type AgentPairPayload struct { DeviceID string `json:"device_id"` PairCode string `json:"pair_code"` } // https://docs.slide.tech/api/#tag/agents/GET/v1/agent func (a AgentService) List( ctx context.Context, pageHandler func(response ListResponse[Agent]) error, ) error { return a.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/agents/GET/v1/agent func (c AgentService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[Agent]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[Agent]{} endpoint := c.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := c.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/agents/POST/v1/agent func (c AgentService) AutoPair(ctx context.Context, payload AgentAutoPairPayload) (AgentAutoPairResponse, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return AgentAutoPairResponse{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, c.baseEndpoint, requestBody, ) if err != nil { return AgentAutoPairResponse{}, err } target := AgentAutoPairResponse{} if err := c.requestClient.SlideRequest(request, &target); err != nil { return AgentAutoPairResponse{}, err } return target, nil } // https://docs.slide.tech/api/#tag/agents/POST/v1/agent/pair func (c AgentService) Pair(ctx context.Context, payload AgentPairPayload) (Agent, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return Agent{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, c.baseEndpoint, requestBody, ) if err != nil { return Agent{}, err } target := Agent{} if err := c.requestClient.SlideRequest(request, &target); err != nil { return Agent{}, err } return target, nil } // https://docs.slide.tech/api/#tag/agents/GET/v1/agent/{agent_id} func (c AgentService) Get(ctx context.Context, agentID string) (Agent, error) { target := Agent{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, c.baseEndpoint+"/"+agentID, http.NoBody, ) if err != nil { return Agent{}, err } if err := c.requestClient.SlideRequest(request, &target); err != nil { return Agent{}, err } return target, nil } // https://docs.slide.tech/api/#tag/agents/PATCH/v1/agent/{agent_id} func (c AgentService) Update(ctx context.Context, agentID, displayName string) (Agent, error) { type agentPayload struct { DisplayName string `json:"display_name"` } payload := agentPayload{ DisplayName: displayName, } payloadBytes, err := json.Marshal(payload) if err != nil { return Agent{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPatch, c.baseEndpoint+"/"+agentID, requestBody, ) if err != nil { return Agent{}, err } target := Agent{} if err := c.requestClient.SlideRequest(request, &target); err != nil { return Agent{}, err } return target, nil }
package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" "time" ) type Alert struct { AgentID string `json:"agent_id"` AlertFields string `json:"alert_fields"` AlertID string `json:"alert_id"` AlertType AlertType `json:"alert_type"` CreatedAt time.Time `json:"created_at"` DeviceID string `json:"device_id"` Resolved bool `json:"resolved"` ResolvedAt *time.Time `json:"resolved_at"` ResolvedBy string `json:"resolved_by"` } type AlertService struct { baseEndpoint string requestClient *requestClient } type AlertType string const ( AlertType_DEVICE_NOT_CHECKING_IN AlertType = "device_not_checking_in" AlertType_DEVICE_OUT_OF_DATE AlertType = "device_out_of_date" AlertType_DEVICE_STORAGE_NOT_HEALTHY AlertType = "device_storage_not_healthy" AlertType_DEVICE_STORAGE_SPACE_LOW AlertType = "device_storage_space_low" AlertType_DEVICE_STORAGE_SPACE_CRITICAL AlertType = "device_storage_space_critical" AlertType_AGENT_NOT_CHECKING_IN AlertType = "agent_not_checking_in" AlertType_AGENT_NOT_BACKING_UP AlertType = "agent_not_backing_up" AlertType_AGENT_BACKUP_FAILED AlertType = "agent_backup_failed" ) // https://docs.slide.tech/api/#tag/alerts/GET/v1/alert/{alert_id} func (a AlertService) Get(ctx context.Context, alertID string) (Alert, error) { target := Alert{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, a.baseEndpoint+"/"+alertID, http.NoBody, ) if err != nil { return Alert{}, err } if err := a.requestClient.SlideRequest(request, &target); err != nil { return Alert{}, err } return target, nil } // https://docs.slide.tech/api/#tag/alerts/GET/v1/alert func (a AlertService) List( ctx context.Context, pageHandler func(response ListResponse[Alert]) error, ) error { return a.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/alerts/GET/v1/alert func (a AlertService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[Alert]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[Alert]{} endpoint := a.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := a.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/alerts/PATCH/v1/alert/{alert_id} func (a AlertService) Update( ctx context.Context, alertID string, resolved bool, ) (Alert, error) { type alertPayload struct { Resolved bool `json:"resolved"` } payloadBytes, err := json.Marshal(alertPayload{ Resolved: resolved, }) if err != nil { return Alert{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPatch, a.baseEndpoint+"/"+alertID, requestBody, ) if err != nil { return Alert{}, err } target := Alert{} if err := a.requestClient.SlideRequest(request, &target); err != nil { return Alert{}, err } return target, nil }
package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" "time" ) type BackupStatus string const ( BackupStatus_CREATED BackupStatus = "created" BackupStatus_PENDING BackupStatus = "pending" BackupStatus_STARTED BackupStatus = "started" BackupStatus_PREFLIGHT BackupStatus = "preflight" BackupStatus_CONTACTING BackupStatus = "contacting" BackupStatus_CREATING_VSS BackupStatus = "creating_vss" BackupStatus_PREPARING BackupStatus = "preparing" BackupStatus_TRANSFERRING BackupStatus = "transferring" BackupStatus_SNAPSHOT BackupStatus = "snapshot" BackupStatus_FINALIZING BackupStatus = "finalizing" BackupStatus_CANCELING BackupStatus = "canceling" BackupStatus_FAILING BackupStatus = "failing" BackupStatus_CANCELED BackupStatus = "canceled" BackupStatus_FAILED BackupStatus = "failed" BackupStatus_SUCCEEDED BackupStatus = "succeeded" ) type Backup struct { AgentID string `json:"agent_id"` BackupID string `json:"backup_id"` EndedAt time.Time `json:"ended_at"` ErrorCode uint `json:"error_code"` ErrorMessage string `json:"error_message"` SnapshotID string `json:"snapshot_id"` StartedAt time.Time `json:"started_at"` Status BackupStatus `json:"status"` } type BackupService struct { baseEndpoint string requestClient *requestClient } // https://docs.slide.tech/api/#tag/backups/GET/v1/backup func (b BackupService) List( ctx context.Context, pageHandler func(response ListResponse[Backup]) error, ) error { return b.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/backups/GET/v1/backup func (b BackupService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[Backup]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[Backup]{} endpoint := b.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := b.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/backups/GET/v1/backup/{backup_id} func (b BackupService) Get(ctx context.Context, backupID string) (Backup, error) { target := Backup{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, b.baseEndpoint+"/"+backupID, http.NoBody, ) if err != nil { return Backup{}, err } if err := b.requestClient.SlideRequest(request, &target); err != nil { return Backup{}, err } return target, nil } // https://docs.slide.tech/api/#tag/backups/POST/v1/backup func (b BackupService) StartBackup(ctx context.Context, agentID string) error { type backupPayload struct { AgentID string `json:"agent_id"` } payloadBytes, err := json.Marshal(backupPayload{ AgentID: agentID, }) if err != nil { return err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, b.baseEndpoint, requestBody, ) if err != nil { return err } return b.requestClient.SlideRequest(request, nil) }
package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" ) type Client struct { ClientID string `json:"client_id"` Name string `json:"name"` Comments string `json:"comments"` } type ClientService struct { baseEndpoint string requestClient *requestClient } type ClientPayload struct { Comments string `json:"comments,omitempty"` Name string `json:"name,omitempty"` } // https://docs.slide.tech/api/#tag/clients/GET/v1/client func (c ClientService) List( ctx context.Context, pageHandler func(response ListResponse[Client]) error, ) error { return c.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/clients/GET/v1/client func (c ClientService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[Client]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[Client]{} endpoint := c.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := c.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/clients/POST/v1/client func (c ClientService) Create(ctx context.Context, payload ClientPayload) (Client, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return Client{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, c.baseEndpoint, requestBody, ) if err != nil { return Client{}, err } target := Client{} if err := c.requestClient.SlideRequest(request, &target); err != nil { return Client{}, err } return target, nil } // https://docs.slide.tech/api/#tag/clients/GET/v1/client/{client_id} func (c ClientService) Get(ctx context.Context, clientID string) (Client, error) { target := Client{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, c.baseEndpoint+"/"+clientID, http.NoBody, ) if err != nil { return Client{}, err } if err := c.requestClient.SlideRequest(request, &target); err != nil { return Client{}, err } return target, nil } // https://docs.slide.tech/api/#tag/clients/DELETE/v1/client/{client_id} func (c ClientService) Delete(ctx context.Context, clientID string) error { request, err := http.NewRequestWithContext( ctx, http.MethodDelete, c.baseEndpoint+"/"+clientID, http.NoBody, ) if err != nil { return err } return c.requestClient.SlideRequest(request, nil) } // https://docs.slide.tech/api/#tag/clients/PATCH/v1/client/{client_id} func (c ClientService) Update(ctx context.Context, clientID string, payload ClientPayload) (Client, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return Client{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPatch, c.baseEndpoint+"/"+clientID, requestBody, ) if err != nil { return Client{}, err } target := Client{} if err := c.requestClient.SlideRequest(request, &target); err != nil { return Client{}, err } return target, nil }
package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" "time" ) type Device struct { Addresses []Address `json:"addresses"` BootedAt time.Time `json:"booted_at"` ClientID string `json:"client_id"` DeviceID string `json:"device_id"` DisplayName string `json:"display_name"` HardwareModelName string `json:"hardware_model_name"` Hostname string `json:"hostname"` ImageVersion string `json:"image_version"` PublicIPAddress string `json:"public_ip_address"` LastSeenAt time.Time `json:"last_seen_at"` NFR bool `json:"nfr"` PackageVersion string `json:"package_version"` SerialNumber string `json:"serial_number"` ServiceModelName string `json:"service_model_name"` ServiceModelNameShort string `json:"service_model_name_short"` ServiceStatus string `json:"service_status"` StorageTotalBytes uint64 `json:"storage_total_bytes"` StorageUsedBytes uint64 `json:"storage_used_bytes"` } type Address struct { MAC string `json:"mac"` IPs []string `json:"ips"` } type DeviceService struct { baseEndpoint string requestClient *requestClient } type DevicePayload struct { DisplayName string `json:"display_name,omitempty"` Hostname string `json:"hostname,omitempty"` ClientID string `json:"client_id,omitempty"` } // https://docs.slide.tech/api/#tag/devices func (d DeviceService) List( ctx context.Context, pageHandler func(response ListResponse[Device]) error, ) error { return d.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/devices func (d DeviceService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[Device]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[Device]{} endpoint := d.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := d.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/devices/GET/v1/device/{device_id} func (d DeviceService) Get(ctx context.Context, deviceID string) (Device, error) { target := Device{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, d.baseEndpoint+"/"+deviceID, http.NoBody, ) if err != nil { return Device{}, err } if err := d.requestClient.SlideRequest(request, &target); err != nil { return Device{}, err } return target, nil } // https://docs.slide.tech/api/#tag/devices/PATCH/v1/device/{device_id} func (d DeviceService) Update(ctx context.Context, deviceID string, payload DevicePayload) (Device, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return Device{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPatch, d.baseEndpoint+"/"+deviceID, requestBody, ) if err != nil { return Device{}, err } target := Device{} if err := d.requestClient.SlideRequest(request, &target); err != nil { return Device{}, err } return target, nil }
package goslide import ( "fmt" "strings" ) type APIErrorCode string const ( APIErrorCode_ERR_ENDPOINT_NOT_FOUND APIErrorCode = "err_endpoint_not_found" APIErrorCode_ERR_ENTITY_NOT_FOUND APIErrorCode = "err_entity_not_found" APIErrorCode_ERR_VALIDATION_ERROR APIErrorCode = "err_validation_error" APIErrorCode_ERR_MISSING_AUTHENTICATION APIErrorCode = "err_missing_authentication" APIErrorCode_ERR_UNAUTHORIZED APIErrorCode = "err_unauthorized" APIErrorCode_ERR_INTERNAL_SERVER_ERROR APIErrorCode = "err_internal_server_error" APIErrorCode_ERR_RATE_LIMIT_EXCEEDED APIErrorCode = "err_rate_limit_exceeded" APIErrorCode_ERR_AGENT_NOT_CONNECTED_TO_DEVICE APIErrorCode = "err_agent_not_connected_to_device" APIErrorCode_ERR_DEVICE_NOT_CONNECTED_TO_CLOUD APIErrorCode = "err_device_not_connected_to_cloud" APIErrorCode_ERR_BACKUP_ALREADY_RUNNING APIErrorCode = "err_backup_already_running" APIErrorCode_ERR_CLIENT_NOT_FOUND APIErrorCode = "err_client_not_found" ) type SlideError struct { HTTPStatusCode int HTTPRequestPath string HTTPRequestMethod string Codes []APIErrorCode `json:"codes"` Details []string `json:"details"` Message string `json:"message"` } func (e *SlideError) Error() string { var sb strings.Builder sb.Write([]byte("slide api request error")) if len(e.Codes) > 0 { for _, errcode := range e.Codes { sb.WriteString(fmt.Sprintf(" %s ", errcode)) } } return sb.String() }
package goslide import ( "context" "errors" "net/http" ) // healthCheck is the service that is used to report whether an API Token is valid. // // TODO: This can be deprecated if Slide implements an endpoint to validate tokens. type HealthCheck struct { requestClient *requestClient } // IsAuthenticated makes a simple GET request to the list users endpoint with a limit of 1. // If an error is encountered, the http.Response error code is checked to validate if the error is // authentication related (401) or a generic API error func (h HealthCheck) IsAuthenticated(ctx context.Context) (bool, error) { userListReq, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/user?limit=1", http.NoBody) if err != nil { return false, err } err = h.requestClient.SlideRequest(userListReq, nil) if err != nil { var slideError *SlideError if errors.As(err, &slideError) { for _, errCode := range slideError.Codes { if errCode == APIErrorCode_ERR_MISSING_AUTHENTICATION || errCode == APIErrorCode_ERR_UNAUTHORIZED { return false, slideError } } } else { return true, err } } return true, nil }
package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" ) type NetworkService struct { baseEndpoint string requestClient *requestClient } type Network struct { BridgeDeviceID string `json:"bridge_device_id"` ClientID string `json:"client_id"` Comments string `json:"comments"` ConnectedVirtIDs []string `json:"connected_virt_ids"` DHCP bool `json:"dhcp"` DHCPRangeEnd string `json:"dhcp_range_end"` DHCPRangeStart string `json:"dhcp_range_start"` Internet bool `json:"internet"` Name string `json:"name"` Nameservers string `json:"nameservers"` NetworkID string `json:"network_id"` RouterPrefix string `json:"router_prefix"` Type NetworkTypeDisaster `json:"type"` } type NetworkTypeDisaster string const ( NetworkTypeDisaster_STANDARD NetworkTypeDisaster = "standard" NetworkTypeDisaster_BRIDGE_LAN NetworkTypeDisaster = "bridge-lan" ) // https://docs.slide.tech/api/#tag/networks/GET/v1/network func (n NetworkService) List( ctx context.Context, pageHandler func(response ListResponse[Network]) error, ) error { return n.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/networks/GET/v1/network func (n NetworkService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[Network]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[Network]{} endpoint := n.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := n.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } type NetworkCreatePayload struct { Name string `json:"name"` Type NetworkTypeDisaster `json:"type"` BridgeDeviceID string `json:"bridge_device_id,omitempty"` ClientID string `json:"client_id,omitempty"` Comments string `json:"comments,omitempty"` DHCP bool `json:"dhcp,omitempty"` DHCPRangeEnd string `json:"dhcp_range_end,omitempty"` DHCPRangeStart string `json:"dhcp_range_start,omitempty"` Internet bool `json:"internet,omitempty"` Nameservers string `json:"nameservers,omitempty"` RouterPrefix string `json:"router_prefix,omitempty"` } type NetworkUpdatePayload struct { Name string `json:"name,omitempty"` Type NetworkTypeDisaster `json:"type,omitempty"` Comments string `json:"comments,omitempty"` DHCP bool `json:"dhcp,omitempty"` DHCPRangeEnd string `json:"dhcp_range_end,omitempty"` DHCPRangeStart string `json:"dhcp_range_start,omitempty"` Internet bool `json:"internet,omitempty"` Nameservers string `json:"nameservers,omitempty"` RouterPrefix string `json:"router_prefix,omitempty"` } // https://docs.slide.tech/api/#tag/networks/POST/v1/network func (n NetworkService) Create(ctx context.Context, payload NetworkCreatePayload) (Network, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return Network{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, n.baseEndpoint, requestBody, ) if err != nil { return Network{}, err } target := Network{} if err := n.requestClient.SlideRequest(request, &target); err != nil { return Network{}, err } return target, nil } // https://docs.slide.tech/api/#tag/networks/GET/v1/network/{network_id} func (n NetworkService) Get(ctx context.Context, networkID string) (Network, error) { target := Network{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, n.baseEndpoint+"/"+networkID, http.NoBody, ) if err != nil { return Network{}, err } if err := n.requestClient.SlideRequest(request, &target); err != nil { return Network{}, err } return target, nil } // https://docs.slide.tech/api/#tag/networks/DELETE/v1/network/{network_id} func (n NetworkService) Delete(ctx context.Context, networkID string) error { request, err := http.NewRequestWithContext( ctx, http.MethodDelete, n.baseEndpoint+"/"+networkID, http.NoBody, ) if err != nil { return err } return n.requestClient.SlideRequest(request, nil) } // https://docs.slide.tech/api/#tag/networks/PATCH/v1/network/{network_id} func (n NetworkService) Update(ctx context.Context, networkID string, payload NetworkUpdatePayload) (Network, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return Network{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPatch, n.baseEndpoint+"/"+networkID, requestBody, ) if err != nil { return Network{}, err } target := Network{} if err := n.requestClient.SlideRequest(request, &target); err != nil { return Network{}, err } return target, nil } type NetworkPortForwardPayload struct { Dest string `json:"dest"` NetworkID string `json:"network_id"` Proto NetworkProto `json:"proto"` } type NetworkProto string const ( NetworkProto_UDP NetworkProto = "udp" NetworkProto_TCP NetworkProto = "tcp" ) // https://docs.slide.tech/api/#tag/networks/POST/v1/network/{network_id}/port-forwards func (n NetworkService) CreatePortForward(ctx context.Context, networkID string, payload NetworkPortForwardPayload) (NetworkPortForward, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return NetworkPortForward{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, n.baseEndpoint+"/"+networkID+"/port-forwards", requestBody, ) if err != nil { return NetworkPortForward{}, err } target := NetworkPortForward{} if err := n.requestClient.SlideRequest(request, &target); err != nil { return NetworkPortForward{}, err } return target, nil } // https://docs.slide.tech/api/#tag/networks/DELETE/v1/network/{network_id}/port-forwards func (n NetworkService) DeletePortForward(ctx context.Context, networkID string, payload NetworkPortForwardPayload) error { payloadBytes, err := json.Marshal(payload) if err != nil { return err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, n.baseEndpoint+"/"+networkID+"/port-forwards", requestBody, ) if err != nil { return err } if err := n.requestClient.SlideRequest(request, nil); err != nil { return err } return nil } // https://docs.slide.tech/api/#tag/networks/PATCH/v1/network/{network_id}/port-forwards func (n NetworkService) UpdatePortForward(ctx context.Context, networkID string, payload NetworkPortForwardUpdatePayload) error { payloadBytes, err := json.Marshal(payload) if err != nil { return err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, n.baseEndpoint+"/"+networkID+"/port-forwards", requestBody, ) if err != nil { return err } if err := n.requestClient.SlideRequest(request, nil); err != nil { return err } return nil } type NetworkPortForwardUpdatePayload struct { Dest string `json:"dest"` NetworkID string `json:"network_id"` Port uint `json:"port"` ProtoNew NetworkProto `json:"proto_new"` ProtoOld NetworkProto `json:"proto_old"` } type NetworkPortForward struct { Dest string `json:"dest"` NetworkID string `json:"network_id"` Port uint `json:"port"` Proto NetworkProto `json:"proto"` } type NetworkWGPeer struct { NetworkID string `json:"network_id"` PeerName string `json:"peer_name"` RemoteNetworks []string `json:"remote_networks"` WGAddress string `json:"wg_address"` WGPrivateKey string `json:"wg_private_key"` WGPublicKey string `json:"wg_public_key"` } type NetworkWGPeerCreatePayload struct { NetworkID string `json:"network_id"` PeerName string `json:"peer_name"` RemoteNetworks []string `json:"remote_networks"` } // https://docs.slide.tech/api/#tag/networks/POST/v1/network/{network_id}/wg-peers func (n NetworkService) CreateWGPeer(ctx context.Context, networkID string, payload NetworkWGPeerCreatePayload) (NetworkWGPeer, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return NetworkWGPeer{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, n.baseEndpoint+"/"+networkID+"/wg-peers", requestBody, ) if err != nil { return NetworkWGPeer{}, err } target := NetworkWGPeer{} if err := n.requestClient.SlideRequest(request, &target); err != nil { return NetworkWGPeer{}, err } return target, nil } // https://docs.slide.tech/api/#tag/networks/DELETE/v1/network/{network_id}/wg-peers func (n NetworkService) DeleteWGPeer(ctx context.Context, networkID, wgAddress string) error { type networkWGPeerDeletePayload struct { NetworkID string `json:"network_id"` WGAddress string `json:"wg_address"` } payload := networkWGPeerDeletePayload{ NetworkID: networkID, WGAddress: wgAddress, } payloadBytes, err := json.Marshal(payload) if err != nil { return err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, n.baseEndpoint+"/"+networkID+"/wg-peers", requestBody, ) if err != nil { return err } if err := n.requestClient.SlideRequest(request, nil); err != nil { return err } return nil } // https://docs.slide.tech/api/#tag/networks/PATCH/v1/network/{network_id}/wg-peers func (n NetworkService) UpdateWGPeer(ctx context.Context, networkID string, payload NetworkPortForwardUpdatePayload) (NetworkWGPeer, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return NetworkWGPeer{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, n.baseEndpoint+"/"+networkID+"/wg-peers", requestBody, ) if err != nil { return NetworkWGPeer{}, err } target := NetworkWGPeer{} if err := n.requestClient.SlideRequest(request, &target); err != nil { return NetworkWGPeer{}, err } return target, nil }
package goslide import ( "net/url" "strconv" ) type OffsetPagination struct { Total uint `json:"total"` NextOffset *uint `json:"next_offset"` } type ListResponse[Record any] struct { Pagination OffsetPagination `json:"pagination"` Data []Record `json:"data"` } type paginationQueryParam func(u url.Values) func WithOffset(offset uint) paginationQueryParam { return func(u url.Values) { u.Set("offset", strconv.FormatUint(uint64(offset), 10)) } } func WithLimit(limit uint) paginationQueryParam { return func(u url.Values) { u.Set("limit", strconv.FormatUint(uint64(limit), 10)) } } func WithSortDirection(ascending bool) paginationQueryParam { return func(u url.Values) { u.Set("sort_asc", strconv.FormatBool(ascending)) } } func WithSortBy(field string) paginationQueryParam { return func(u url.Values) { u.Set("sort_by", url.QueryEscape(field)) } } func WithAgentID(agentID string) paginationQueryParam { return func(u url.Values) { u.Set("agent_id", url.QueryEscape(agentID)) } } func WithDeviceID(deviceID string) paginationQueryParam { return func(u url.Values) { u.Set("device_id", url.QueryEscape(deviceID)) } } func WithIncludeResolvedAlerts(b bool) paginationQueryParam { return func(u url.Values) { u.Set("resolved", strconv.FormatBool(b)) } } func WithSnapshotID(snapshotID string) paginationQueryParam { return func(u url.Values) { u.Set("snapshot_id", url.QueryEscape(snapshotID)) } } func WithPath(path string) paginationQueryParam { return func(u url.Values) { u.Set("path", url.QueryEscape(path)) } } func WithSnapshotLocationFilter(snapshotLocation SnapshotLocationFilter) paginationQueryParam { return func(u url.Values) { u.Set("snapshot_location", url.QueryEscape(string(snapshotLocation))) } } type SnapshotLocationFilter string const ( SnapshotLocationFilter_EXISTS_LOCAL SnapshotLocationFilter = "exists_local" SnapshotLocationFilter_EXISTS_CLOUD SnapshotLocationFilter = "exists_cloud" SnapshotLocationFilter_EXISTS_DELETED SnapshotLocationFilter = "exists_deleted" SnapshotLocationFilter_EXISTS_DELETED_RETENTION SnapshotLocationFilter = "exists_deleted_retention" SnapshotLocationFilter_EXISTS_DELETED_MANUAL SnapshotLocationFilter = "exists_deleted_manual" SnapshotLocationFilter_EXISTS_DELETED_OTHER SnapshotLocationFilter = "exists_deleted_other" )
package goslide import ( "encoding/json" "fmt" "io" "net/http" "golang.org/x/oauth2" ) type requestClient struct { token *oauth2.Token apiURL string httpClient *http.Client } func (rc *requestClient) do(request *http.Request, target any) error { if request.URL.Host == "" { request.URL.Host = rc.apiURL } request.URL.Scheme = "https" request.Header.Set("Accept", "application/json") if request.Header.Get("Content-Type") == "" { request.Header.Set("Content-Type", "application/json") } response, err := rc.httpClient.Do(request) if err != nil { return err } defer response.Body.Close() if response.StatusCode >= http.StatusBadRequest { slideAPIError := &SlideError{ HTTPStatusCode: response.StatusCode, HTTPRequestPath: request.URL.Path, HTTPRequestMethod: request.Method, } bodyBytes, err := io.ReadAll(response.Body) if err != nil { return err } if err := json.Unmarshal(bodyBytes, slideAPIError); err != nil { return fmt.Errorf("goslide library error while unmarshalling Slide API response - %w. HTTP Status Code %d", err, response.StatusCode) } return slideAPIError } if target != nil { bodyBytes, err := io.ReadAll(response.Body) if err != nil { return err } if err := json.Unmarshal(bodyBytes, target); err != nil { return err } } return nil } func (rc *requestClient) SlideRequest(request *http.Request, target any) error { if request.Header.Get("Authorization") == "" { if rc.token == nil { return fmt.Errorf("unable to set authorization header - API Token not set") } rc.token.SetAuthHeader(request) } return rc.do(request, target) } func (rc *requestClient) Request(request *http.Request, target any) error { return rc.do(request, target) }
package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" "time" ) type FileRestore struct { AgentID string `json:"agent_id"` CreatedAt time.Time `json:"created_at"` DeviceID string `json:"device_id"` ExpiresAt time.Time `json:"expires_at"` FileRestoreID string `json:"file_restore_id"` SnapshotID string `json:"snapshot_id"` } type FileRestoreService struct { baseEndpoint string requestClient *requestClient } type FileRestorePayload struct { DeviceID string `json:"device_id"` SnapshotID string `json:"snapshot_id"` } // https://docs.slide.tech/api/#tag/restores-file/GET/v1/restore/file func (f FileRestoreService) List( ctx context.Context, pageHandler func(response ListResponse[FileRestore]) error, ) error { return f.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/restores-file/GET/v1/restore/file func (f FileRestoreService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[FileRestore]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[FileRestore]{} endpoint := f.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := f.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/restores-file/POST/v1/restore/file func (f FileRestoreService) Create(ctx context.Context, payload FileRestorePayload) (FileRestore, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return FileRestore{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, f.baseEndpoint, requestBody, ) if err != nil { return FileRestore{}, err } target := FileRestore{} if err := f.requestClient.SlideRequest(request, &target); err != nil { return FileRestore{}, err } return target, nil } // https://docs.slide.tech/api/#tag/restores-file/GET/v1/restore/file/{file_restore_id} func (f FileRestoreService) Get(ctx context.Context, fileRestoreID string) (FileRestore, error) { target := FileRestore{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, f.baseEndpoint+"/"+fileRestoreID, http.NoBody, ) if err != nil { return FileRestore{}, err } if err := f.requestClient.SlideRequest(request, &target); err != nil { return FileRestore{}, err } return target, nil } // https://docs.slide.tech/api/#tag/restores-file/GET/v1/restore/file/{file_restore_id}/browse func (f FileRestoreService) Browse( ctx context.Context, fileRestoreID string, pageHandler func(response ListResponse[FileRestoreData]) error, ) error { return f.BrowseWithQueryParameters(ctx, fileRestoreID, pageHandler) } // https://docs.slide.tech/api/#tag/restores-file/GET/v1/restore/file/{file_restore_id}/browse func (f FileRestoreService) BrowseWithQueryParameters( ctx context.Context, fileRestoreID string, pageHandler func(response ListResponse[FileRestoreData]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[FileRestoreData]{} endpoint := f.baseEndpoint + "/" + fileRestoreID + "/browse" if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := f.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/restores-file/DELETE/v1/restore/file/{file_restore_id} func (f FileRestoreService) Delete(ctx context.Context, fileRestoreID string) error { request, err := http.NewRequestWithContext( ctx, http.MethodDelete, f.baseEndpoint+"/"+fileRestoreID, http.NoBody, ) if err != nil { return err } return f.requestClient.SlideRequest(request, nil) } type FileRestoreData struct { DownloadURIs []FileRestoreDownloadURI `json:"download_uris"` ModifiedAt string `json:"modified_at"` Name string `json:"name"` Path string `json:"path"` Size uint `json:"size"` SymlinkTargetPath string `json:"symlink_target_path"` Type FileRestoreDataType `json:"type"` } type FileRestoreDownloadURI struct { Type FileRestoreDownloadType `json:"type"` URI string `json:"uri"` } type FileRestoreDownloadType string const ( FileRestoreDownloadType_LOCAL FileRestoreDownloadType = "local" FileRestoreDownloadType_CLOUD FileRestoreDownloadType = "cloud" ) type FileRestoreDataType string const ( FileRestoreDataType_FILE FileRestoreDataType = "file" FileRestoreDataType_DIR FileRestoreDataType = "dir" FileRestoreDataType_SYMLINK FileRestoreDataType = "symlink" )
package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" "time" ) type ImageExportRestore struct { AgentID string `json:"agent_id"` CreatedAt time.Time `json:"created_at"` DeviceID string `json:"device_id"` ImageExportID string `json:"image_export_id"` ImageType ImageExportType `json:"image_type"` SnapshotID string `json:"snapshot_id"` } type ImageExportRestoreService struct { baseEndpoint string requestClient *requestClient } type ImageExportType string const ( ImageExportType_VHDX ImageExportType = "vhdx" ImageExportType_VHDX_DYNAMIC ImageExportType = "vhdx-dynamic" ImageExportType_VHD ImageExportType = "vhd" ImageExportType_RAW ImageExportType = "raw" ) type ImageExportRestoreData struct { DiskID string `json:"disk_id"` DownloadURIs []ImageExportRestoreDownloadURI `json:"download_uris"` Name string `json:"name"` Size uint `json:"size"` } type ImageExportRestoreDownloadURI struct { Type ImageExportDownloadType `json:"type"` URI string `json:"uri"` } type ImageExportDownloadType string const ( ImageExportDownloadType_LOCAL ImageExportDownloadType = "local" ImageExportDownloadType_CLOUD ImageExportDownloadType = "cloud" ) type ImageExportRestorePayload struct { DeviceID string `json:"device_id"` SnapshotID string `json:"snapshot_id"` ImageType ImageExportType `json:"image_type"` BootMods []BootMod `json:"boot_mods,omitempty"` } // https://docs.slide.tech/api/#tag/restores-image/GET/v1/restore/image func (i ImageExportRestoreService) List( ctx context.Context, pageHandler func(response ListResponse[ImageExportRestore]) error, ) error { return i.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/restores-image/GET/v1/restore/image func (i ImageExportRestoreService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[ImageExportRestore]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[ImageExportRestore]{} endpoint := i.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := i.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/restores-image/POST/v1/restore/image func (i ImageExportRestoreService) Create(ctx context.Context, payload ImageExportRestorePayload) (ImageExportRestore, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return ImageExportRestore{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, i.baseEndpoint, requestBody, ) if err != nil { return ImageExportRestore{}, err } target := ImageExportRestore{} if err := i.requestClient.SlideRequest(request, &target); err != nil { return ImageExportRestore{}, err } return target, nil } // https://docs.slide.tech/api/#tag/restores-image/GET/v1/restore/image/{image_export_id} func (i ImageExportRestoreService) Get(ctx context.Context, imageExportRestoreID string) (ImageExportRestore, error) { target := ImageExportRestore{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, i.baseEndpoint+"/"+imageExportRestoreID, http.NoBody, ) if err != nil { return ImageExportRestore{}, err } if err := i.requestClient.SlideRequest(request, &target); err != nil { return ImageExportRestore{}, err } return target, nil } // https://docs.slide.tech/api/#tag/restores-image/GET/v1/restore/image/{image_export_id}/browse func (i ImageExportRestoreService) Browse( ctx context.Context, imageExportRestoreID string, pageHandler func(response ListResponse[ImageExportRestoreData]) error, ) error { return i.BrowseWithQueryParameters(ctx, imageExportRestoreID, pageHandler) } // https://docs.slide.tech/api/#tag/restores-image/GET/v1/restore/image/{image_export_id}/browse func (i ImageExportRestoreService) BrowseWithQueryParameters( ctx context.Context, imageExportRestoreID string, pageHandler func(response ListResponse[ImageExportRestoreData]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[ImageExportRestoreData]{} endpoint := i.baseEndpoint + "/" + imageExportRestoreID + "/browse" if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := i.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/restores-image/DELETE/v1/restore/image/{image_export_id} func (i ImageExportRestoreService) Delete(ctx context.Context, imageExportRestoreID string) error { request, err := http.NewRequestWithContext( ctx, http.MethodDelete, i.baseEndpoint+"/"+imageExportRestoreID, http.NoBody, ) if err != nil { return err } return i.requestClient.SlideRequest(request, nil) }
package goslide import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" "strconv" "time" ) type VirtualMachineRestore struct { AgentID string `json:"agent_id"` CPUCount uint `json:"cpu_count"` CreatedAt time.Time `json:"created_at"` DeviceID string `json:"device_id"` DiskBus DiskBus `json:"disk_bus"` ExpiresAt time.Time `json:"expires_at"` MemoryInMB uint `json:"memory_in_mb"` NetworkModel VirtualMachineNetworkModel `json:"network_model"` NetworkType VirtualMachineNetworkType `json:"network_type"` SnapshotID string `json:"snapshot_id"` State VirtualMachineState `json:"state"` VirtID string `json:"virt_id"` VNC []VirtualMachineVNC `json:"vnc"` VNCPassword string `json:"vnc_password"` } type VirtualMachineRestoreService struct { baseEndpoint string requestClient *requestClient } type VirtualMachineVNC struct { Host string `json:"host"` Port uint `json:"port"` Type VirtualMachineVNCType `json:"type"` WebsocketURI string `json:"websocket_uri"` } // https://docs.slide.tech/api/#tag/restores-virtual-machine/GET/v1/restore/virt func (v VirtualMachineRestoreService) List( ctx context.Context, pageHandler func(response ListResponse[VirtualMachineRestore]) error, ) error { return v.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/restores-virtual-machine/GET/v1/restore/virt func (v VirtualMachineRestoreService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[VirtualMachineRestore]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[VirtualMachineRestore]{} endpoint := v.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := v.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/restores-virtual-machine/POST/v1/restore/virt func (v VirtualMachineRestoreService) Create(ctx context.Context, payload VirtualMachineRestoreCreatePayload) (VirtualMachineRestore, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return VirtualMachineRestore{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPost, v.baseEndpoint, requestBody, ) if err != nil { return VirtualMachineRestore{}, err } target := VirtualMachineRestore{} if err := v.requestClient.SlideRequest(request, &target); err != nil { return VirtualMachineRestore{}, err } return target, nil } // https://docs.slide.tech/api/#tag/restores-virtual-machine/GET/v1/restore/virt/{virt_id} func (v VirtualMachineRestoreService) Get(ctx context.Context, virtID string) (VirtualMachineRestore, error) { target := VirtualMachineRestore{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, v.baseEndpoint+"/"+virtID, http.NoBody, ) if err != nil { return VirtualMachineRestore{}, err } if err := v.requestClient.SlideRequest(request, &target); err != nil { return VirtualMachineRestore{}, err } return target, nil } // https://docs.slide.tech/api/#tag/restores-virtual-machine/DELETE/v1/restore/virt/{virt_id} func (v VirtualMachineRestoreService) Delete(ctx context.Context, virtID string) error { request, err := http.NewRequestWithContext( ctx, http.MethodDelete, v.baseEndpoint+"/"+virtID, http.NoBody, ) if err != nil { return err } return v.requestClient.SlideRequest(request, nil) } // https://docs.slide.tech/api/#tag/restores-virtual-machine/PATCH/v1/restore/virt/{virt_id} func (v VirtualMachineRestoreService) Update(ctx context.Context, virtID string, payload VirtualMachineRestoreUpdatePayload) (VirtualMachineRestore, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return VirtualMachineRestore{}, err } requestBody := bytes.NewReader(payloadBytes) request, err := http.NewRequestWithContext( ctx, http.MethodPatch, v.baseEndpoint+"/"+virtID, requestBody, ) if err != nil { return VirtualMachineRestore{}, err } target := VirtualMachineRestore{} if err := v.requestClient.SlideRequest(request, &target); err != nil { return VirtualMachineRestore{}, err } return target, nil } type VirtualMachineRestoreUpdatePayload struct { State VirtualMachineState `json:"state,omitempty"` CPUCount uint `json:"cpu_count,omitempty"` MemoryInMB uint `json:"memory_in_mb,omitempty"` ExpiresAt time.Time `json:"expires_at,omitempty"` } type VirtualMachineRestoreCreatePayload struct { DeviceID string `json:"device_id"` SnapshotID string `json:"snapshot_id"` BootMods []BootMod `json:"boot_mods,omitempty"` CPUCount uint `json:"cpu_count,omitempty"` DiskBus DiskBus `json:"disk_bus,omitempty"` MemoryInMB uint `json:"memory_in_mb,omitempty"` NetworkModel VirtualMachineNetworkModel `json:"network_model,omitempty"` NetworkType VirtualMachineNetworkType `json:"network_type,omitempty"` } type BootMod string const ( BootMod_PASSWORDLESS_ADMIN_USER BootMod = "passwordless_admin_user" ) type DiskBus string const ( DiskBus_SATA DiskBus = "sata" DiskBus_VIRTIO DiskBus = "virtio" ) type VirtualMachineNetworkModel string const ( VirtualMachineNetworkModel_HYPERVISOR_DEFAULT VirtualMachineNetworkModel = "hypervisor_default" VirtualMachineNetworkModel_E1000 VirtualMachineNetworkModel = "e1000" VirtualMachineNetworkModel_RTL8139 VirtualMachineNetworkModel = "rtl8139" ) type VirtualMachineNetworkType string const ( VirtualMachineNetworkType_NETWORK VirtualMachineNetworkType = "network" VirtualMachineNetworkType_NETWORK_ISOLATED VirtualMachineNetworkType = "network-isolated" VirtualMachineNetworkType_BRIDGE VirtualMachineNetworkType = "bridge" ) type VirtualMachineState string const ( VirtualMachineState_RUNNING VirtualMachineState = "running" VirtualMachineState_STOPPED VirtualMachineState = "stopped" VirtualMachineState_PAUSED VirtualMachineState = "paused" ) type VirtualMachineVNCType string const ( VirtualMachineVNCType_LOCAL VirtualMachineVNCType = "local" VirtualMachineVNCType_CLOUD VirtualMachineVNCType = "cloud" )
package goslide import ( "context" "net/http" "golang.org/x/oauth2" ) type serviceConfig struct { roundtripper http.RoundTripper apiURL string } type configOption func(s *serviceConfig) func WithCustomRoundtripper(roundtripper http.RoundTripper) configOption { return func(s *serviceConfig) { s.roundtripper = roundtripper } } func AddRequestPreProcessor(roundtripper http.RoundTripper) configOption { return func(s *serviceConfig) { s.roundtripper = roundtripper } } func WithSlogger(roundtripper http.RoundTripper) configOption { return func(s *serviceConfig) { s.roundtripper = roundtripper } } type Service struct { accounts AccountService agents AgentService alerts AlertService backups BackupService clients ClientService devices DeviceService fileRestores FileRestoreService health HealthCheck imageExportRestores ImageExportRestoreService networks NetworkService snapshots SnapshotService users UserService virtualMachineRestores VirtualMachineRestoreService } func NewService( apiToken string, options ...configOption, ) Service { config := &serviceConfig{ apiURL: "api.slide.tech", } for _, option := range options { option(config) } oauthToken := &oauth2.Token{ AccessToken: apiToken, } requestClient := &requestClient{ token: oauthToken, apiURL: config.apiURL, httpClient: &http.Client{ Transport: config.roundtripper, }, } return Service{ accounts: AccountService{ baseEndpoint: "/v1/account", requestClient: requestClient, }, agents: AgentService{ baseEndpoint: "/v1/agent", requestClient: requestClient, }, alerts: AlertService{ baseEndpoint: "/v1/alert", requestClient: requestClient, }, backups: BackupService{ baseEndpoint: "/v1/backup", requestClient: requestClient, }, clients: ClientService{ baseEndpoint: "/v1/client", requestClient: requestClient, }, devices: DeviceService{ baseEndpoint: "/v1/device", requestClient: requestClient, }, fileRestores: FileRestoreService{ baseEndpoint: "/v1/restore/file", requestClient: requestClient, }, health: HealthCheck{ requestClient: requestClient, }, imageExportRestores: ImageExportRestoreService{ baseEndpoint: "/v1/restore/image", requestClient: requestClient, }, networks: NetworkService{ baseEndpoint: "/v1/network", requestClient: requestClient, }, snapshots: SnapshotService{ baseEndpoint: "/v1/snapshot", requestClient: requestClient, }, users: UserService{ baseEndpoint: "/v1/user", requestClient: requestClient, }, virtualMachineRestores: VirtualMachineRestoreService{ baseEndpoint: "/v1/restore/virt", requestClient: requestClient, }, } } // https://docs.slide.tech/api/#tag/accounts func (s Service) Accounts() AccountService { return s.accounts } // https://docs.slide.tech/api/#tag/agents func (s Service) Agents() AgentService { return s.agents } // https://docs.slide.tech/api/#tag/alerts func (s Service) Alerts() AlertService { return s.alerts } // https://docs.slide.tech/api/#tag/backups func (s Service) Backups() BackupService { return s.backups } // https://docs.slide.tech/api/#tag/clients func (s Service) Clients() ClientService { return s.clients } // https://docs.slide.tech/api/#tag/devices func (s Service) Devices() DeviceService { return s.devices } // https://docs.slide.tech/api/#tag/restores-file func (s Service) FileRestores() FileRestoreService { return s.fileRestores } // https://docs.slide.tech/api/#tag/restores-image func (s Service) ImageExportRestores() ImageExportRestoreService { return s.imageExportRestores } // https://docs.slide.tech/api/#tag/networks func (s Service) Networks() NetworkService { return s.networks } // https://docs.slide.tech/api/#tag/snapshots func (s Service) Snapshots() SnapshotService { return s.snapshots } // https://docs.slide.tech/api/#tag/users func (s Service) Users() UserService { return s.users } // https://docs.slide.tech/api/#tag/restores-virtual-machine func (s Service) VirtualMachineRestores() VirtualMachineRestoreService { return s.virtualMachineRestores } func (s Service) CheckAuthenticationToken(ctx context.Context) (bool, error) { return s.health.IsAuthenticated(ctx) }
package goslide import ( "context" "fmt" "net/http" "net/url" "strconv" "time" ) type Snapshot struct { AgentID string `json:"agent_id"` BackupEndedAt time.Time `json:"backup_ended_at"` BackupStartedAt time.Time `json:"backup_started_at"` Locations []SnapshotLocation `json:"locations"` Deleted *time.Time `json:"deleted"` Deletions []SnapshotDeletion `json:"deletions"` SnapshotID string `json:"snapshot_id"` VerifyBootScreenshotURL string `json:"verify_boot_screenshot_url"` VerifyBootStatus SnapshotBootStatus `json:"verify_boot_status"` VerifyFSStatus SnapshotFSStatus `json:"verify_fs_status"` } type SnapshotService struct { baseEndpoint string requestClient *requestClient } type SnapshotLocation struct { DeviceID string `json:"device_id"` Type SnapshotLocationType `json:"type"` } type SnapshotDeletion struct { Deleted time.Time `json:"deleted"` DeletedBy string `json:"deleted_by"` FirstAndLastName string `json:"first_and_last_name"` Type SnapshotLocationType `json:"type"` } type SnapshotLocationType string const ( SnapshotLocationType_LOCAL SnapshotLocationType = "local" SnapshotLocationType_CLOUD SnapshotLocationType = "cloud" ) type SnapshotFSStatus string const ( SnapshotFSStatus_SUCCESS SnapshotFSStatus = "success" SnapshotFSStatus_WARNING SnapshotFSStatus = "warning" SnapshotFSStatus_ERROR SnapshotFSStatus = "error" SnapshotFSStatus_SKIPPED SnapshotFSStatus = "skipped" ) type SnapshotBootStatus string const ( SnapshotBootStatus_SUCCESS SnapshotBootStatus = "success" SnapshotBootStatus_WARNING SnapshotBootStatus = "warning" SnapshotBootStatus_ERROR SnapshotBootStatus = "error" SnapshotBootStatus_SKIPPED SnapshotBootStatus = "skipped" SnapshotBootStatus_PENDING SnapshotBootStatus = "pending" SnapshotBootStatus_PENDING_DUE_TO_DISASTER_VM SnapshotBootStatus = "pending_due_to_disaster_vm" ) // https://docs.slide.tech/api/#tag/snapshots/GET/v1/snapshot func (s SnapshotService) List( ctx context.Context, pageHandler func(response ListResponse[Snapshot]) error, ) error { return s.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/snapshots/GET/v1/snapshot func (s SnapshotService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[Snapshot]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[Snapshot]{} endpoint := s.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := s.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/snapshots/GET/v1/snapshot/{snapshot_id} func (s SnapshotService) Get(ctx context.Context, snapshotID string) (Snapshot, error) { target := Snapshot{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, s.baseEndpoint+"/"+snapshotID, http.NoBody, ) if err != nil { return Snapshot{}, err } if err := s.requestClient.SlideRequest(request, &target); err != nil { return Snapshot{}, err } return target, nil }
package goslide import ( "context" "fmt" "net/http" "net/url" "strconv" ) type User struct { DisplayName string `json:"display_name"` Email string `json:"email"` FirstName string `json:"first_name"` LastName string `json:"last_name"` RoleID UserRole `json:"role_id"` UserID string `json:"user_id"` } type UserRole string const ( UserRole_AccountOwner UserRole = "r_account_owner" UserRole_AccountAdmin UserRole = "r_account_admin" UserRole_AccountTech UserRole = "r_account_tech" UserRole_AccountReadOnly UserRole = "r_readonly" ) type UserService struct { baseEndpoint string requestClient *requestClient } // https://docs.slide.tech/api/#tag/users/GET/v1/user func (u UserService) List( ctx context.Context, pageHandler func(response ListResponse[User]) error, ) error { return u.ListWithQueryParameters(ctx, pageHandler) } // https://docs.slide.tech/api/#tag/users/GET/v1/user func (u UserService) ListWithQueryParameters( ctx context.Context, pageHandler func(response ListResponse[User]) error, options ...paginationQueryParam, ) error { queryParams := url.Values{} for _, option := range options { option(queryParams) } for { target := ListResponse[User]{} endpoint := u.baseEndpoint if len(queryParams) > 0 { endpoint = endpoint + "?" } request, err := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("%s%s", endpoint, queryParams.Encode()), http.NoBody, ) if err != nil { return err } if err := u.requestClient.SlideRequest(request, &target); err != nil { return err } if err := pageHandler(target); err != nil { return err } // No next offset marks the end of the paginated results if target.Pagination.NextOffset == nil { break } queryParams.Set( "offset", strconv.FormatUint( uint64(*target.Pagination.NextOffset), 10, ), ) } return nil } // https://docs.slide.tech/api/#tag/users/GET/v1/user/{user_id} func (u UserService) Get(ctx context.Context, userID string) (User, error) { target := User{} request, err := http.NewRequestWithContext( ctx, http.MethodGet, "/v1/user/"+userID, http.NoBody, ) if err != nil { return User{}, err } if err := u.requestClient.SlideRequest(request, &target); err != nil { return User{}, err } return target, nil }