From 9f98ebc9d72f9893acdb1b8e585bcb215c8fe9b2 Mon Sep 17 00:00:00 2001 From: Michael Riley Date: Sun, 30 Jun 2024 16:39:03 -0400 Subject: [PATCH] Add support for CDN --- cdn.go | 376 +++++++++++++++++++++++++++++++++++++++++++++++++++++ govultr.go | 2 + 2 files changed, 378 insertions(+) create mode 100644 cdn.go diff --git a/cdn.go b/cdn.go new file mode 100644 index 0000000..c2b5a09 --- /dev/null +++ b/cdn.go @@ -0,0 +1,376 @@ +package govultr + +import ( + "context" + "fmt" + "net/http" +) + +const cdnPath string = "/v2/cdns" + +var ( + cdnPullPath string = fmt.Sprintf("%s/pull-zones", cdnPath) + cdnPushPath string = fmt.Sprintf("%s/push-zones", cdnPath) +) + +// CDNService is the interface to interact with the CDN endpoints on the Vultr API +// Link : https://www.vultr.com/api/#tag/CDNs +type CDNService interface { + ListPullZones(ctx context.Context) ([]CDNZone, *Meta, *http.Response, error) + GetPullZone(ctx context.Context, zoneID string) (*CDNZone, *http.Response, error) + CreatePullZone(ctx context.Context, zoneReq *CDNZoneReq) (*CDNZone, *http.Response, error) + UpdatePullZone(ctx context.Context, zoneID string, zoneReq *CDNZoneReq) (*CDNZone, *http.Response, error) + DeletePullZone(ctx context.Context, zoneID string) error + PurgePullZone(ctx context.Context, zoneID string) error + + ListPushZones(ctx context.Context) ([]CDNZone, *Meta, *http.Response, error) + GetPushZone(ctx context.Context, zoneID string) (*CDNZone, *http.Response, error) + CreatePushZone(ctx context.Context, zoneReq *CDNZoneReq) (*CDNZone, *http.Response, error) + UpdatePushZone(ctx context.Context, zoneID string, zoneReq *CDNZoneReq) (*CDNZone, *http.Response, error) + DeletePushZone(ctx context.Context, zoneID string) error + + ListPushZoneFiles(ctx context.Context, zoneID string) (*CDNZoneFileData, *http.Response, error) + GetPushZoneFile(ctx context.Context, zoneID, fileName string) (*CDNZoneFile, *http.Response, error) + DeletePushZoneFile(ctx context.Context, zoneID, fileName string) error + CreatePushZoneFileEndpoint(ctx context.Context, zoneID string, endpointReq *CDNZoneEndpointReq) (*CDNZoneEndpoint, *http.Response, error) //nolint:lll +} + +// CDNZone represents the CDN push/pull zone data +type CDNZone struct { + ID string `json:"id"` + DateCreated string `json:"date_created"` + Status string `json:"status"` + Label string `json:"label"` + OriginScheme string `json:"origin_scheme,omitempty"` + OriginDomain string `json:"origin_domain,omitempty"` + CDNURL string `json:"cdn_url"` + CacheSize int `json:"cache_size"` + Requests int `json:"requests"` + BytesIn int `json:"in_bytes"` + BytesOut int `json:"out_bytes"` + PacketsPerSec int `json:"packets_per_sec"` + DatePurged string `json:"last_purge,omitempty"` + CORS bool `json:"cors"` + GZIP bool `json:"gzip"` + BlockAI bool `json:"block_ai"` + BlockBadBots bool `json:"block_bad_bots"` + Regions []string `json:"regions"` +} + +// CDNZoneReq is the data used to create a push/pull zone +type CDNZoneReq struct { + Label string `json:"label"` + OriginScheme string `json:"origin_scheme,omitempty"` + OriginDomain string `json:"origin_domain,omitempty"` + CORS bool `json:"cors"` + GZIP bool `json:"gzip"` + BlockAI bool `json:"block_ai"` + BlockBadBots bool `json:"block_bad_bots"` + Regions []string `json:"regions,omitempty"` +} + +// CDNZoneFileData represents the push zone files and metadata +type CDNZoneFileData struct { + Files []CDNZoneFile `json:"files"` + Count int `json:"count"` + Size int `json:"total_size"` +} + +// CDNZoneFile is the data for a push zone file +type CDNZoneFile struct { + Name string `json:"name"` + Size int `json:"size"` + DateModified string `json:"last_modified"` +} + +// CDNZoneEndpointReq is the data used to create a push zone upload endpoint +type CDNZoneEndpointReq struct { + Name string `json:"name"` + Size int `json:"size"` +} + +// CDNZoneEndpoint is the data for a push zone file endpoint +type CDNZoneEndpoint struct { + URL string `json:"url"` + Inputs CDNZoneEndpointInputs `json:"inputs"` +} + +// CDNZoneEndpointInputs is the data for push zone file endpoint inputs +type CDNZoneEndpointInputs struct { + ACL string `json:"acl"` + Key string `json:"key"` + Policy string `json:"policy"` + Credential string `json:"x-amz-credential"` + Algorithm string `json:"x-amz-algorithm"` + Signature string `json:"x-amz-signature"` +} + +type cdnPullZonesBase struct { + PullZones []CDNZone `json:"pull_zones"` + Meta *Meta `json:"meta"` +} + +type cdnPullZoneBase struct { + PullZone CDNZone `json:"pull_zone"` +} + +type cdnPushZonesBase struct { + PushZones []CDNZone `json:"push_zones"` + Meta *Meta `json:"meta"` +} + +type cdnPushZoneBase struct { + PushZone CDNZone `json:"push_zone"` +} + +type cdnPushZoneEndpointBase struct { + Endpoint CDNZoneEndpoint `json:"upload_endpoint"` +} + +// CDNServiceHandler handles interaction with the CDN methods for the Vultr API +type CDNServiceHandler struct { + client *Client +} + +// ListPullZones will retrieve a CDN pull zone +func (c *CDNServiceHandler) ListPullZones(ctx context.Context) ([]CDNZone, *Meta, *http.Response, error) { + req, err := c.client.NewRequest(ctx, http.MethodGet, cdnPullPath, nil) + if err != nil { + return nil, nil, nil, err + } + + zones := new(cdnPullZonesBase) + resp, err := c.client.DoWithContext(ctx, req, &zones) + if err != nil { + return nil, nil, resp, err + } + + return zones.PullZones, zones.Meta, resp, nil +} + +// GetPullZone will retrieve data for a CDN pull zone +func (c *CDNServiceHandler) GetPullZone(ctx context.Context, zoneID string) (*CDNZone, *http.Response, error) { + cdnPullGetPath := fmt.Sprintf("%s/%s", cdnPullPath, zoneID) + req, err := c.client.NewRequest(ctx, http.MethodGet, cdnPullGetPath, nil) + if err != nil { + return nil, nil, err + } + + zone := new(cdnPullZoneBase) + resp, err := c.client.DoWithContext(ctx, req, &zone) + if err != nil { + return nil, resp, err + } + + return &zone.PullZone, resp, nil +} + +// CreatePullZone will create a new CDN pull zone +func (c *CDNServiceHandler) CreatePullZone(ctx context.Context, zoneReq *CDNZoneReq) (*CDNZone, *http.Response, error) { + req, err := c.client.NewRequest(ctx, http.MethodPost, cdnPullPath, zoneReq) + if err != nil { + return nil, nil, err + } + + zone := new(cdnPullZoneBase) + resp, err := c.client.DoWithContext(ctx, req, &zone) + if err != nil { + return nil, resp, err + } + + return &zone.PullZone, resp, nil +} + +// UpdatePullZone will update an existing CDN pull zone +func (c *CDNServiceHandler) UpdatePullZone(ctx context.Context, zoneID string, zoneReq *CDNZoneReq) (*CDNZone, *http.Response, error) { //nolint:dupl,lll + cndPullUpdatePath := fmt.Sprintf("%s/%s", cdnPullPath, zoneID) + req, err := c.client.NewRequest(ctx, http.MethodPut, cndPullUpdatePath, zoneReq) + if err != nil { + return nil, nil, err + } + + zone := new(cdnPullZoneBase) + resp, err := c.client.DoWithContext(ctx, req, &zone) + if err != nil { + return nil, resp, err + } + + return &zone.PullZone, resp, nil +} + +// DeletePullZone will delete a CDN pull zone +func (c *CDNServiceHandler) DeletePullZone(ctx context.Context, zoneID string) error { + cdnPullDeletePath := fmt.Sprintf("%s/%s", cdnPullPath, zoneID) + req, err := c.client.NewRequest(ctx, http.MethodDelete, cdnPullDeletePath, nil) + if err != nil { + return err + } + + _, err = c.client.DoWithContext(ctx, req, nil) + if err != nil { + return err + } + + return nil +} + +// PurgePullZone will clear the cache on a CDN pull zone +func (c *CDNServiceHandler) PurgePullZone(ctx context.Context, zoneID string) error { + cdnPullPurgePath := fmt.Sprintf("%s/%s", cdnPullPath, zoneID) + req, err := c.client.NewRequest(ctx, http.MethodGet, cdnPullPurgePath, nil) + if err != nil { + return err + } + + _, err = c.client.DoWithContext(ctx, req, nil) + if err != nil { + return err + } + + return nil +} + +// ListPushZones will retrieve a CDN push zone +func (c *CDNServiceHandler) ListPushZones(ctx context.Context) ([]CDNZone, *Meta, *http.Response, error) { + req, err := c.client.NewRequest(ctx, http.MethodGet, cdnPushPath, nil) + if err != nil { + return nil, nil, nil, err + } + + zones := new(cdnPushZonesBase) + resp, err := c.client.DoWithContext(ctx, req, &zones) + if err != nil { + return nil, nil, resp, err + } + + return zones.PushZones, zones.Meta, resp, nil +} + +// GetPushZone will retrieve data for a CDN push zone +func (c *CDNServiceHandler) GetPushZone(ctx context.Context, zoneID string) (*CDNZone, *http.Response, error) { + cdnPushGetPath := fmt.Sprintf("%s/%s", cdnPushPath, zoneID) + req, err := c.client.NewRequest(ctx, http.MethodGet, cdnPushGetPath, nil) + if err != nil { + return nil, nil, err + } + + zone := new(cdnPushZoneBase) + resp, err := c.client.DoWithContext(ctx, req, &zone) + if err != nil { + return nil, resp, err + } + + return &zone.PushZone, resp, nil +} + +// CreatePushZone will create a new CDN push zone +func (c *CDNServiceHandler) CreatePushZone(ctx context.Context, zoneReq *CDNZoneReq) (*CDNZone, *http.Response, error) { + req, err := c.client.NewRequest(ctx, http.MethodPost, cdnPushPath, zoneReq) + if err != nil { + return nil, nil, err + } + + zone := new(cdnPushZoneBase) + resp, err := c.client.DoWithContext(ctx, req, &zone) + if err != nil { + return nil, resp, err + } + + return &zone.PushZone, resp, nil +} + +// UpdatePushZone will update an existing CDN push zone +func (c *CDNServiceHandler) UpdatePushZone(ctx context.Context, zoneID string, zoneReq *CDNZoneReq) (*CDNZone, *http.Response, error) { //nolint:dupl,lll + cndPushUpdatePath := fmt.Sprintf("%s/%s", cdnPushPath, zoneID) + req, err := c.client.NewRequest(ctx, http.MethodPut, cndPushUpdatePath, zoneReq) + if err != nil { + return nil, nil, err + } + + zone := new(cdnPushZoneBase) + resp, err := c.client.DoWithContext(ctx, req, &zone) + if err != nil { + return nil, resp, err + } + + return &zone.PushZone, resp, nil +} + +// DeletePushZone will delete a CDN push zone +func (c *CDNServiceHandler) DeletePushZone(ctx context.Context, zoneID string) error { + cdnPushDeletePath := fmt.Sprintf("%s/%s", cdnPushPath, zoneID) + req, err := c.client.NewRequest(ctx, http.MethodDelete, cdnPushDeletePath, nil) + if err != nil { + return err + } + + _, err = c.client.DoWithContext(ctx, req, nil) + if err != nil { + return err + } + + return nil +} + +// CreatePushZoneFileEndpoint will create a new CDN push zone file upload +// endpoint +func (c *CDNServiceHandler) CreatePushZoneFileEndpoint(ctx context.Context, zoneID string, zoneEndpointReq *CDNZoneEndpointReq) (*CDNZoneEndpoint, *http.Response, error) { //nolint:lll,dupl + cdnPushEnpointPath := fmt.Sprintf("%s/%s/files", cdnPushPath, zoneID) + req, err := c.client.NewRequest(ctx, http.MethodPost, cdnPushEnpointPath, zoneEndpointReq) + if err != nil { + return nil, nil, err + } + + endpoint := new(cdnPushZoneEndpointBase) + resp, err := c.client.DoWithContext(ctx, req, &endpoint) + if err != nil { + return nil, resp, err + } + + return &endpoint.Endpoint, resp, nil +} + +// ListPushZoneFiles will retrieve all CDN push zone file data that have been +// uploaded +func (c *CDNServiceHandler) ListPushZoneFiles(ctx context.Context, zoneID string) (*CDNZoneFileData, *http.Response, error) { + cdnPushFilesPath := fmt.Sprintf("%s/%s", cdnPushPath, zoneID) + req, err := c.client.NewRequest(ctx, http.MethodGet, cdnPushFilesPath, nil) + if err != nil { + return nil, nil, err + } + + fd := new(CDNZoneFileData) + resp, err := c.client.DoWithContext(ctx, req, &fd) + if err != nil { + return nil, resp, err + } + + return fd, resp, nil +} + +// GetPushZoneFile will retrieve data on a file in a CDN push zone +func (c *CDNServiceHandler) GetPushZoneFile(ctx context.Context, zoneID, fileName string) (*CDNZoneFile, *http.Response, error) { + cdnFileGetPath := fmt.Sprintf("%s/%s/files/%s", cdnPushPath, zoneID, fileName) + req, err := c.client.NewRequest(ctx, http.MethodGet, cdnFileGetPath, nil) + if err != nil { + return nil, nil, err + } + + file := new(CDNZoneFile) + resp, err := c.client.DoWithContext(ctx, req, &file) + if err != nil { + return nil, resp, err + } + + return file, resp, nil +} + +// DeletePushZoneFile delete a file in a CDN push zone +func (c *CDNServiceHandler) DeletePushZoneFile(ctx context.Context, zoneID, fileName string) error { + cdnFileGetPath := fmt.Sprintf("%s/%s/files/%s", cdnPushPath, zoneID, fileName) + if _, err := c.client.NewRequest(ctx, http.MethodGet, cdnFileGetPath, nil); err != nil { + return err + } + + return nil +} diff --git a/govultr.go b/govultr.go index e2bc3e6..3195277 100644 --- a/govultr.go +++ b/govultr.go @@ -47,6 +47,7 @@ type Client struct { BareMetalServer BareMetalServerService Billing BillingService BlockStorage BlockStorageService + CDN CDNService ContainerRegistry ContainerRegistryService Database DatabaseService Domain DomainService @@ -122,6 +123,7 @@ func NewClient(httpClient *http.Client) *Client { client.Billing = &BillingServiceHandler{client} client.BlockStorage = &BlockStorageServiceHandler{client} client.ContainerRegistry = &ContainerRegistryServiceHandler{client} + client.CDN = &CDNServiceHandler{client} client.Database = &DatabaseServiceHandler{client} client.Domain = &DomainServiceHandler{client} client.DomainRecord = &DomainRecordsServiceHandler{client}