mirror of https://github.com/kubernetes/kops.git
Update godo to v1.54.0
This commit is contained in:
parent
bafa96220e
commit
15dc7b4f5a
2
go.mod
2
go.mod
|
@ -63,7 +63,7 @@ require (
|
|||
github.com/client9/misspell v0.3.4
|
||||
github.com/coreos/etcd v3.3.17+incompatible
|
||||
github.com/denverdino/aliyungo v0.0.0-20191128015008-acd8035bbb1d
|
||||
github.com/digitalocean/godo v1.19.0
|
||||
github.com/digitalocean/godo v1.54.0
|
||||
github.com/docker/docker v1.4.2-0.20200309214505-aa6a9891b09c
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20180422025557-ae226422660e
|
||||
|
|
5
go.sum
5
go.sum
|
@ -222,8 +222,8 @@ github.com/denverdino/aliyungo v0.0.0-20191128015008-acd8035bbb1d/go.mod h1:dV8l
|
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/digitalocean/godo v1.19.0 h1:9ApuchfzGD/XI8Zm0RRnZnytdfYHPjPTRKTnmzQNV7o=
|
||||
github.com/digitalocean/godo v1.19.0/go.mod h1:AAPQ+tiM4st79QHlEBTg8LM7JQNre4SAQCbn56wEyKY=
|
||||
github.com/digitalocean/godo v1.54.0 h1:KP0Nv87pgViR8k/7De3VrmflCL5pJqXbNnkcw0bwG10=
|
||||
github.com/digitalocean/godo v1.54.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
|
@ -956,7 +956,6 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2l
|
|||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.7
|
||||
- 1.8
|
||||
- 1.9
|
||||
- "1.10"
|
||||
- tip
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"checkRunSettings": {
|
||||
"vulnerableCheckRunConclusionLevel": "failure"
|
||||
},
|
||||
"issueSettings": {
|
||||
"minSeverityLevel": "LOW"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package godo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const oneClickBasePath = "v2/1-clicks"
|
||||
|
||||
// OneClickService is an interface for interacting with 1-clicks with the
|
||||
// DigitalOcean API.
|
||||
// See: https://developers.digitalocean.com/documentation/v2/#1-click-applications
|
||||
type OneClickService interface {
|
||||
List(context.Context, string) ([]*OneClick, *Response, error)
|
||||
InstallKubernetes(context.Context, *InstallKubernetesAppsRequest) (*InstallKubernetesAppsResponse, *Response, error)
|
||||
}
|
||||
|
||||
var _ OneClickService = &OneClickServiceOp{}
|
||||
|
||||
// OneClickServiceOp interfaces with 1-click endpoints in the DigitalOcean API.
|
||||
type OneClickServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// OneClick is the structure of a 1-click
|
||||
type OneClick struct {
|
||||
Slug string `json:"slug"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// OneClicksRoot is the root of the json payload that contains a list of 1-clicks
|
||||
type OneClicksRoot struct {
|
||||
List []*OneClick `json:"1_clicks"`
|
||||
}
|
||||
|
||||
// InstallKubernetesAppsRequest represents a request required to install 1-click kubernetes apps
|
||||
type InstallKubernetesAppsRequest struct {
|
||||
Slugs []string `json:"addon_slugs"`
|
||||
ClusterUUID string `json:"cluster_uuid"`
|
||||
}
|
||||
|
||||
// InstallKubernetesAppsResponse is the response of a kubernetes 1-click install request
|
||||
type InstallKubernetesAppsResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// List returns a list of the available 1-click applications.
|
||||
func (ocs *OneClickServiceOp) List(ctx context.Context, oneClickType string) ([]*OneClick, *Response, error) {
|
||||
path := fmt.Sprintf(`%s?type=%s`, oneClickBasePath, oneClickType)
|
||||
|
||||
req, err := ocs.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(OneClicksRoot)
|
||||
resp, err := ocs.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.List, resp, nil
|
||||
}
|
||||
|
||||
// InstallKubernetes installs an addon on a kubernetes cluster
|
||||
func (ocs *OneClickServiceOp) InstallKubernetes(ctx context.Context, install *InstallKubernetesAppsRequest) (*InstallKubernetesAppsResponse, *Response, error) {
|
||||
path := fmt.Sprintf(oneClickBasePath + "/kubernetes")
|
||||
|
||||
req, err := ocs.client.NewRequest(ctx, http.MethodPost, path, install)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
responseMessage := new(InstallKubernetesAppsResponse)
|
||||
resp, err := ocs.client.Do(ctx, req, responseMessage)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return responseMessage, resp, err
|
||||
}
|
|
@ -3,8 +3,13 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"1-click.go",
|
||||
"account.go",
|
||||
"action.go",
|
||||
"apps.gen.go",
|
||||
"apps.go",
|
||||
"balance.go",
|
||||
"billing_history.go",
|
||||
"cdn.go",
|
||||
"certificates.go",
|
||||
"databases.go",
|
||||
|
@ -19,12 +24,15 @@ go_library(
|
|||
"godo.go",
|
||||
"image_actions.go",
|
||||
"images.go",
|
||||
"invoices.go",
|
||||
"keys.go",
|
||||
"kubernetes.go",
|
||||
"links.go",
|
||||
"load_balancers.go",
|
||||
"meta.go",
|
||||
"projects.go",
|
||||
"regions.go",
|
||||
"registry.go",
|
||||
"sizes.go",
|
||||
"snapshots.go",
|
||||
"storage.go",
|
||||
|
@ -37,5 +45,8 @@ go_library(
|
|||
importmap = "k8s.io/kops/vendor/github.com/digitalocean/godo",
|
||||
importpath = "github.com/digitalocean/godo",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/google/go-querystring/query:go_default_library"],
|
||||
deps = [
|
||||
"//vendor/github.com/google/go-querystring/query:go_default_library",
|
||||
"//vendor/golang.org/x/oauth2:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,5 +1,205 @@
|
|||
# Change Log
|
||||
|
||||
## [v1.54.0] - 2020-11-24
|
||||
|
||||
- #417 - @waynr - registry: add support for garbage collection types
|
||||
|
||||
## [v1.53.0] - 2020-11-20
|
||||
|
||||
- #414 - @varshavaradarajan - kubernetes: add clusterlint support
|
||||
- #413 - @andrewsomething - images: Support updating distribution and description.
|
||||
|
||||
## [v1.52.0] - 2020-11-05
|
||||
|
||||
- #411 - @nicktate - apps: add unspecified type to image source registry types
|
||||
- #409 - @andrewsomething - registry: Add support for updating a subscription.
|
||||
- #408 - @nicktate - apps: update spec to include image source
|
||||
- #407 - @kamaln7 - apps: add the option to force build a new deployment
|
||||
|
||||
## [v1.51.0] - 2020-11-02
|
||||
|
||||
- #405 - @adamwg - registry: Support subscription options
|
||||
- #398 - @reeseconor - Add support for caching dependencies between GitHub Action runs
|
||||
- #404 - @andrewsomething - CONTRIBUTING.md: Suggest using github-changelog-generator.
|
||||
|
||||
## [v1.50.0] - 2020-10-26
|
||||
|
||||
- #400 - @waynr - registry: add garbage collection support
|
||||
- #402 - @snormore - apps: add catchall_document static site spec field and failed-deploy job type
|
||||
- #401 - @andrewlouis93 - VPC: adds option to set a VPC as the regional default
|
||||
|
||||
## [v1.49.0] - 2020-10-21
|
||||
|
||||
- #383 - @kamaln7 - apps: add ListRegions, Get/ListTiers, Get/ListInstanceSizes
|
||||
- #390 - @snormore - apps: add service spec internal_ports
|
||||
|
||||
## [v1.48.0] - 2020-10-16
|
||||
|
||||
- #388 - @varshavaradarajan - kubernetes - change docr integration api routes
|
||||
- #386 - @snormore - apps: pull in recent updates to jobs and domains
|
||||
|
||||
## [v1.47.0] - 2020-10-14
|
||||
|
||||
- #384 kubernetes - add registry related doks apis - @varshavaradarajan
|
||||
- #385 Fixed some typo in apps.gen.go and databases.go file - @devil-cyber
|
||||
- #382 Add GetKubeConfigWithExpiry (#334) - @ivanlemeshev
|
||||
- #381 Fix golint issues #377 - @sidsbrmnn
|
||||
- #380 refactor: Cyclomatic complexity issue - @DonRenando
|
||||
- #379 Run gofmt to fix some issues in codebase - @mycodeself
|
||||
|
||||
## [v1.46.0] - 2020-10-05
|
||||
|
||||
- #373 load balancers: add LB size field, currently in closed beta - @anitgandhi
|
||||
|
||||
## [v1.45.0] - 2020-09-25
|
||||
|
||||
**Note**: This release contains breaking changes to App Platform features currently in closed beta.
|
||||
|
||||
- #369 update apps types to latest - @kamaln7
|
||||
- #368 Kubernetes: add taints field to node pool create and update requests - @timoreimann
|
||||
- #367 update apps types, address marshaling bug - @kamaln7
|
||||
|
||||
## [v1.44.0] - 2020-09-08
|
||||
|
||||
- #364 apps: support aggregate deployment logs - @kamaln7
|
||||
|
||||
## [v1.43.0] - 2020-09-08
|
||||
|
||||
- #362 update apps types - @kamaln7
|
||||
|
||||
## [v1.42.1] - 2020-08-06
|
||||
|
||||
- #360 domains: Allow for SRV records with port 0. - @andrewsomething
|
||||
|
||||
## [v1.42.0] - 2020-07-22
|
||||
|
||||
- #357 invoices: add category to InvoiceItem - @rbutler
|
||||
- #358 apps: add support for following logs - @nanzhong
|
||||
|
||||
## [v1.41.0] - 2020-07-17
|
||||
|
||||
- #355 kubernetes: Add support for surge upgrades - @varshavaradarajan
|
||||
|
||||
## [v1.40.0] - 2020-07-16
|
||||
|
||||
- #347 Make Rate limits thread safe - @roidelapluie
|
||||
- #353 Reuse TCP connection - @itsksaurabh
|
||||
|
||||
## [v1.39.0] - 2020-07-14
|
||||
|
||||
- #345, #346 Add app platform support [beta] - @nanzhong
|
||||
|
||||
## [v1.38.0] - 2020-06-18
|
||||
|
||||
- #341 Install 1-click applications on a Kubernetes cluster - @keladhruv
|
||||
- #340 Add RecordsByType, RecordsByName and RecordsByTypeAndName to the DomainsService - @viola
|
||||
|
||||
## [v1.37.0] - 2020-06-01
|
||||
|
||||
- #336 registry: URL encode repository names when building URLs. @adamwg
|
||||
- #335 Add 1-click service and request. @scottcrawford03
|
||||
|
||||
## [v1.36.0] - 2020-05-12
|
||||
|
||||
- #331 Expose expiry_seconds for Registry.DockerCredentials. @andrewsomething
|
||||
|
||||
## [v1.35.1] - 2020-04-21
|
||||
|
||||
- #328 Update vulnerable x/crypto dependency - @bentranter
|
||||
|
||||
## [v1.35.0] - 2020-04-20
|
||||
|
||||
- #326 Add TagCount field to registry/Repository - @nicktate
|
||||
- #325 Add DOCR EA routes - @nicktate
|
||||
- #324 Upgrade godo to Go 1.14 - @bentranter
|
||||
|
||||
## [v1.34.0] - 2020-03-30
|
||||
|
||||
- #320 Add VPC v3 attributes - @viola
|
||||
|
||||
## [v1.33.1] - 2020-03-23
|
||||
|
||||
- #318 upgrade github.com/stretchr/objx past 0.1.1 - @hilary
|
||||
|
||||
## [v1.33.0] - 2020-03-20
|
||||
|
||||
- #310 Add BillingHistory service and List endpoint - @rbutler
|
||||
- #316 load balancers: add new enable_backend_keepalive field - @anitgandhi
|
||||
|
||||
## [v1.32.0] - 2020-03-04
|
||||
|
||||
- #311 Add reset database user auth method - @zbarahal-do
|
||||
|
||||
## [v1.31.0] - 2020-02-28
|
||||
|
||||
- #305 invoices: GetPDF and GetCSV methods - @rbutler
|
||||
- #304 Add NewFromToken convenience method to init client - @bentranter
|
||||
- #301 invoices: Get, Summary, and List methods - @rbutler
|
||||
- #299 Fix param expiry_seconds for kubernetes.GetCredentials request - @velp
|
||||
|
||||
## [v1.30.0] - 2020-02-03
|
||||
|
||||
- #295 registry: support the created_at field - @adamwg
|
||||
- #293 doks: node pool labels - @snormore
|
||||
|
||||
## [v1.29.0] - 2019-12-13
|
||||
|
||||
- #288 Add Balance Get method - @rbutler
|
||||
- #286,#289 Deserialize meta field - @timoreimann
|
||||
|
||||
## [v1.28.0] - 2019-12-04
|
||||
|
||||
- #282 Add valid Redis eviction policy constants - @bentranter
|
||||
- #281 Remove databases info from top-level godoc string - @bentranter
|
||||
- #280 Fix VolumeSnapshotResourceType value volumesnapshot -> volume_snapshot - @aqche
|
||||
|
||||
## [v1.27.0] - 2019-11-18
|
||||
|
||||
- #278 add mysql user auth settings for database users - @gregmankes
|
||||
|
||||
## [v1.26.0] - 2019-11-13
|
||||
|
||||
- #272 dbaas: get and set mysql sql mode - @mikejholly
|
||||
|
||||
## [v1.25.0] - 2019-11-13
|
||||
|
||||
- #275 registry/docker-credentials: add support for the read/write parameter - @kamaln7
|
||||
- #273 implement the registry/docker-credentials endpoint - @kamaln7
|
||||
- #271 Add registry resource - @snormore
|
||||
|
||||
## [v1.24.1] - 2019-11-04
|
||||
|
||||
- #264 Update isLast to check p.Next - @aqche
|
||||
|
||||
## [v1.24.0] - 2019-10-30
|
||||
|
||||
- #267 Return []DatabaseFirewallRule in addition to raw response. - @andrewsomething
|
||||
|
||||
## [v1.23.1] - 2019-10-30
|
||||
|
||||
- #265 add support for getting/setting firewall rules - @gregmankes
|
||||
- #262 remove ResolveReference call - @mdanzinger
|
||||
- #261 Update CONTRIBUTING.md - @mdanzinger
|
||||
|
||||
## [v1.22.0] - 2019-09-24
|
||||
|
||||
- #259 Add Kubernetes GetCredentials method - @snormore
|
||||
|
||||
## [v1.21.1] - 2019-09-19
|
||||
|
||||
- #257 Upgrade to Go 1.13 - @bentranter
|
||||
|
||||
## [v1.21.0] - 2019-09-16
|
||||
|
||||
- #255 Add DropletID to Kubernetes Node instance - @snormore
|
||||
- #254 Add tags to Database, DatabaseReplica - @Zyqsempai
|
||||
|
||||
## [v1.20.0] - 2019-09-06
|
||||
|
||||
- #252 Add Kubernetes autoscale config fields - @snormore
|
||||
- #251 Support unset fields on Kubernetes cluster and node pool updates - @snormore
|
||||
- #250 Add Kubernetes GetUser method - @snormore
|
||||
|
||||
## [v1.19.0] - 2019-07-19
|
||||
|
||||
- #244 dbaas: add private-network-uuid field to create request
|
||||
|
|
|
@ -1,49 +1,64 @@
|
|||
# Contributing
|
||||
|
||||
If you submit a pull request, please keep the following guidelines in mind:
|
||||
We love contributions! You are welcome to open a pull request, but it's a good idea to
|
||||
open an issue and discuss your idea with us first.
|
||||
|
||||
Once you are ready to open a PR, please keep the following guidelines in mind:
|
||||
|
||||
1. Code should be `go fmt` compliant.
|
||||
2. Types, structs and funcs should be documented.
|
||||
3. Tests pass.
|
||||
1. Types, structs and funcs should be documented.
|
||||
1. Tests pass.
|
||||
|
||||
## Getting set up
|
||||
|
||||
Assuming your `$GOPATH` is set up according to your desires, run:
|
||||
|
||||
```sh
|
||||
go get github.com/digitalocean/godo
|
||||
go get -u github.com/stretchr/testify/assert
|
||||
```
|
||||
|
||||
If outside `$GOPATH`, just clone the repository:
|
||||
|
||||
```sh
|
||||
git clone github.com/digitalocean/godo
|
||||
```
|
||||
`godo` uses go modules. Just fork this repo, clone your fork and off you go!
|
||||
|
||||
## Running tests
|
||||
|
||||
When working on code in this repository, tests can be run via:
|
||||
|
||||
```sh
|
||||
go test .
|
||||
go test -mod=vendor .
|
||||
```
|
||||
|
||||
## Versioning
|
||||
|
||||
Godo follows [semver](https://www.semver.org) versioning semantics. New functionality should be accompanied by increment to the minor version number. The current strategy is to release often. Any code which is complete, tested, reviewed, and merged to master is worthy of release.
|
||||
Godo follows [semver](https://www.semver.org) versioning semantics.
|
||||
New functionality should be accompanied by increment to the minor
|
||||
version number. Any code merged to main is subject to release.
|
||||
|
||||
## Releasing
|
||||
|
||||
Releasing a new version of godo is currently a manual process.
|
||||
|
||||
1. Update the `CHANGELOG.md` with your changes. If a version header for the next (unreleased) version does not exist, create one. Include one bullet point for each piece of new functionality in the release, including the pull request ID, description, and author(s).
|
||||
Submit a separate pull request for the version change from the pull
|
||||
request with your changes.
|
||||
|
||||
1. Update the `CHANGELOG.md` with your changes. If a version header
|
||||
for the next (unreleased) version does not exist, create one.
|
||||
Include one bullet point for each piece of new functionality in the
|
||||
release, including the pull request ID, description, and author(s).
|
||||
For example:
|
||||
|
||||
```
|
||||
## [v1.8.0] - 2019-03-13
|
||||
|
||||
- #210 Expose tags on storage volume create/list/get. - @jcodybaker
|
||||
- #123 Update test dependencies - @digitalocean
|
||||
- #210 - @jcodybaker - Expose tags on storage volume create/list/get.
|
||||
- #123 - @digitalocean - Update test dependencies
|
||||
```
|
||||
|
||||
To generate a list of changes since the previous release in the correct
|
||||
format, you can use [github-changelog-generator](https://github.com/digitalocean/github-changelog-generator).
|
||||
It can be installed from source by running:
|
||||
|
||||
```
|
||||
go get -u github.com/digitalocean/github-changelog-generator
|
||||
```
|
||||
|
||||
Next, list the changes by running:
|
||||
|
||||
```
|
||||
github-changelog-generator -org digitalocean -repo godo
|
||||
```
|
||||
|
||||
2. Update the `libraryVersion` number in `godo.go`.
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
[](https://travis-ci.org/digitalocean/godo)
|
||||
|
||||
# Godo
|
||||
|
||||
[](https://travis-ci.org/digitalocean/godo)
|
||||
[](https://godoc.org/github.com/digitalocean/godo)
|
||||
|
||||
Godo is a Go client library for accessing the DigitalOcean V2 API.
|
||||
|
||||
You can view the client API docs here: [http://godoc.org/github.com/digitalocean/godo](http://godoc.org/github.com/digitalocean/godo)
|
||||
|
@ -42,36 +43,16 @@ You can then use your token to create a new client:
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/digitalocean/godo"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
pat = "mytoken"
|
||||
)
|
||||
|
||||
type TokenSource struct {
|
||||
AccessToken string
|
||||
}
|
||||
|
||||
func (t *TokenSource) Token() (*oauth2.Token, error) {
|
||||
token := &oauth2.Token{
|
||||
AccessToken: t.AccessToken,
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
tokenSource := &TokenSource{
|
||||
AccessToken: pat,
|
||||
}
|
||||
|
||||
oauthClient := oauth2.NewClient(context.Background(), tokenSource)
|
||||
client := godo.NewClient(oauthClient)
|
||||
client := godo.NewFromToken("my-digitalocean-api-token")
|
||||
}
|
||||
```
|
||||
|
||||
If you need to provide a `context.Context` to your new client, you should use [`godo.NewClient`](https://godoc.org/github.com/digitalocean/godo#NewClient) to manually construct a client instead.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
|
@ -117,9 +98,7 @@ func DropletList(ctx context.Context, client *godo.Client) ([]godo.Droplet, erro
|
|||
}
|
||||
|
||||
// append the current page's droplets to our list
|
||||
for _, d := range droplets {
|
||||
list = append(list, d)
|
||||
}
|
||||
list = append(list, droplets...)
|
||||
|
||||
// if we are at the last page, break out the for loop
|
||||
if resp.Links == nil || resp.Links.IsLastPage() {
|
||||
|
|
|
@ -34,6 +34,7 @@ var _ ActionsService = &ActionsServiceOp{}
|
|||
type actionsRoot struct {
|
||||
Actions []Action `json:"actions"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type actionRoot struct {
|
||||
|
@ -74,6 +75,9 @@ func (s *ActionsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Action
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Actions, resp, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,464 @@
|
|||
// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
|
||||
// $ bundle -pkg godo -prefix ./dev/dist/godo
|
||||
|
||||
package godo
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// App An application's configuration and status.
|
||||
type App struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
OwnerUUID string `json:"owner_uuid,omitempty"`
|
||||
Spec *AppSpec `json:"spec"`
|
||||
DefaultIngress string `json:"default_ingress,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
ActiveDeployment *Deployment `json:"active_deployment,omitempty"`
|
||||
InProgressDeployment *Deployment `json:"in_progress_deployment,omitempty"`
|
||||
LastDeploymentCreatedAt time.Time `json:"last_deployment_created_at,omitempty"`
|
||||
LiveURL string `json:"live_url,omitempty"`
|
||||
Region *AppRegion `json:"region,omitempty"`
|
||||
TierSlug string `json:"tier_slug,omitempty"`
|
||||
LiveURLBase string `json:"live_url_base,omitempty"`
|
||||
LiveDomain string `json:"live_domain,omitempty"`
|
||||
}
|
||||
|
||||
// AppDatabaseSpec struct for AppDatabaseSpec
|
||||
type AppDatabaseSpec struct {
|
||||
// The name. Must be unique across all components within the same app.
|
||||
Name string `json:"name"`
|
||||
Engine AppDatabaseSpecEngine `json:"engine,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
// Deprecated.
|
||||
Size string `json:"size,omitempty"`
|
||||
// Deprecated.
|
||||
NumNodes int64 `json:"num_nodes,omitempty"`
|
||||
// Whether this is a production or dev database.
|
||||
Production bool `json:"production,omitempty"`
|
||||
// The name of the underlying DigitalOcean DBaaS cluster. This is required for production databases. For dev databases, if cluster_name is not set, a new cluster will be provisioned.
|
||||
ClusterName string `json:"cluster_name,omitempty"`
|
||||
// The name of the MySQL or PostgreSQL database to configure.
|
||||
DBName string `json:"db_name,omitempty"`
|
||||
// The name of the MySQL or PostgreSQL user to configure.
|
||||
DBUser string `json:"db_user,omitempty"`
|
||||
}
|
||||
|
||||
// AppDatabaseSpecEngine the model 'AppDatabaseSpecEngine'
|
||||
type AppDatabaseSpecEngine string
|
||||
|
||||
// List of AppDatabaseSpecEngine
|
||||
const (
|
||||
AppDatabaseSpecEngine_Unset AppDatabaseSpecEngine = "UNSET"
|
||||
AppDatabaseSpecEngine_MySQL AppDatabaseSpecEngine = "MYSQL"
|
||||
AppDatabaseSpecEngine_PG AppDatabaseSpecEngine = "PG"
|
||||
AppDatabaseSpecEngine_Redis AppDatabaseSpecEngine = "REDIS"
|
||||
)
|
||||
|
||||
// AppDomainSpec struct for AppDomainSpec
|
||||
type AppDomainSpec struct {
|
||||
// The hostname.
|
||||
Domain string `json:"domain"`
|
||||
Type AppDomainSpecType `json:"type,omitempty"`
|
||||
// Whether the domain includes all sub-domains, in addition to the given domain.
|
||||
Wildcard bool `json:"wildcard,omitempty"`
|
||||
Zone string `json:"zone,omitempty"`
|
||||
}
|
||||
|
||||
// AppDomainSpecType - DEFAULT: The default .ondigitalocean.app domain assigned to this app. - PRIMARY: The primary domain for this app. This is the domain that is displayed as the default in the control panel, used in bindable environment variables, and any other places that reference an app's live URL. Only one domain may be set as primary. - ALIAS: A non-primary domain.
|
||||
type AppDomainSpecType string
|
||||
|
||||
// List of AppDomainSpecType
|
||||
const (
|
||||
AppDomainSpecType_Unspecified AppDomainSpecType = "UNSPECIFIED"
|
||||
AppDomainSpecType_Default AppDomainSpecType = "DEFAULT"
|
||||
AppDomainSpecType_Primary AppDomainSpecType = "PRIMARY"
|
||||
AppDomainSpecType_Alias AppDomainSpecType = "ALIAS"
|
||||
)
|
||||
|
||||
// AppJobSpec struct for AppJobSpec
|
||||
type AppJobSpec struct {
|
||||
// The name. Must be unique across all components within the same app.
|
||||
Name string `json:"name"`
|
||||
Git *GitSourceSpec `json:"git,omitempty"`
|
||||
GitHub *GitHubSourceSpec `json:"github,omitempty"`
|
||||
Image *ImageSourceSpec `json:"image,omitempty"`
|
||||
// The path to the Dockerfile relative to the root of the repo. If set, it will be used to build this component. Otherwise, App Platform will attempt to build it using buildpacks.
|
||||
DockerfilePath string `json:"dockerfile_path,omitempty"`
|
||||
// An optional build command to run while building this component from source.
|
||||
BuildCommand string `json:"build_command,omitempty"`
|
||||
// An optional run command to override the component's default.
|
||||
RunCommand string `json:"run_command,omitempty"`
|
||||
// An optional path to the working directory to use for the build. For Dockerfile builds, this will be used as the build context. Must be relative to the root of the repo.
|
||||
SourceDir string `json:"source_dir,omitempty"`
|
||||
// An environment slug describing the type of this app. For a full list, please refer to [the product documentation](https://www.digitalocean.com/docs/app-platform/).
|
||||
EnvironmentSlug string `json:"environment_slug,omitempty"`
|
||||
// A list of environment variables made available to the component.
|
||||
Envs []*AppVariableDefinition `json:"envs,omitempty"`
|
||||
// The instance size to use for this component.
|
||||
InstanceSizeSlug string `json:"instance_size_slug,omitempty"`
|
||||
InstanceCount int64 `json:"instance_count,omitempty"`
|
||||
Kind AppJobSpecKind `json:"kind,omitempty"`
|
||||
}
|
||||
|
||||
// AppJobSpecKind - UNSPECIFIED: Default job type, will auto-complete to POST_DEPLOY kind. - PRE_DEPLOY: Indicates a job that runs before an app deployment. - POST_DEPLOY: Indicates a job that runs after an app deployment. - FAILED_DEPLOY: Indicates a job that runs after a component fails to deploy.
|
||||
type AppJobSpecKind string
|
||||
|
||||
// List of AppJobSpecKind
|
||||
const (
|
||||
AppJobSpecKind_Unspecified AppJobSpecKind = "UNSPECIFIED"
|
||||
AppJobSpecKind_PreDeploy AppJobSpecKind = "PRE_DEPLOY"
|
||||
AppJobSpecKind_PostDeploy AppJobSpecKind = "POST_DEPLOY"
|
||||
AppJobSpecKind_FailedDeploy AppJobSpecKind = "FAILED_DEPLOY"
|
||||
)
|
||||
|
||||
// AppRouteSpec struct for AppRouteSpec
|
||||
type AppRouteSpec struct {
|
||||
// An HTTP path prefix. Paths must start with / and must be unique across all components within an app.
|
||||
Path string `json:"path,omitempty"`
|
||||
}
|
||||
|
||||
// AppServiceSpec struct for AppServiceSpec
|
||||
type AppServiceSpec struct {
|
||||
// The name. Must be unique across all components within the same app.
|
||||
Name string `json:"name"`
|
||||
Git *GitSourceSpec `json:"git,omitempty"`
|
||||
GitHub *GitHubSourceSpec `json:"github,omitempty"`
|
||||
Image *ImageSourceSpec `json:"image,omitempty"`
|
||||
// The path to the Dockerfile relative to the root of the repo. If set, it will be used to build this component. Otherwise, App Platform will attempt to build it using buildpacks.
|
||||
DockerfilePath string `json:"dockerfile_path,omitempty"`
|
||||
// An optional build command to run while building this component from source.
|
||||
BuildCommand string `json:"build_command,omitempty"`
|
||||
// An optional run command to override the component's default.
|
||||
RunCommand string `json:"run_command,omitempty"`
|
||||
// An optional path to the working directory to use for the build. For Dockerfile builds, this will be used as the build context. Must be relative to the root of the repo.
|
||||
SourceDir string `json:"source_dir,omitempty"`
|
||||
// An environment slug describing the type of this app. For a full list, please refer to [the product documentation](https://www.digitalocean.com/docs/app-platform/).
|
||||
EnvironmentSlug string `json:"environment_slug,omitempty"`
|
||||
// A list of environment variables made available to the component.
|
||||
Envs []*AppVariableDefinition `json:"envs,omitempty"`
|
||||
InstanceSizeSlug string `json:"instance_size_slug,omitempty"`
|
||||
InstanceCount int64 `json:"instance_count,omitempty"`
|
||||
// The internal port on which this service's run command will listen. Default: 8080 If there is not an environment variable with the name `PORT`, one will be automatically added with its value set to the value of this field.
|
||||
HTTPPort int64 `json:"http_port,omitempty"`
|
||||
// A list of HTTP routes that should be routed to this component.
|
||||
Routes []*AppRouteSpec `json:"routes,omitempty"`
|
||||
HealthCheck *AppServiceSpecHealthCheck `json:"health_check,omitempty"`
|
||||
CORS *AppCORSPolicy `json:"cors,omitempty"`
|
||||
// The ports on which this service will listen for internal traffic.
|
||||
InternalPorts []int64 `json:"internal_ports,omitempty"`
|
||||
}
|
||||
|
||||
// AppServiceSpecHealthCheck struct for AppServiceSpecHealthCheck
|
||||
type AppServiceSpecHealthCheck struct {
|
||||
// Deprecated. Use http_path instead.
|
||||
Path string `json:"path,omitempty"`
|
||||
// The number of seconds to wait before beginning health checks.
|
||||
InitialDelaySeconds int32 `json:"initial_delay_seconds,omitempty"`
|
||||
// The number of seconds to wait between health checks.
|
||||
PeriodSeconds int32 `json:"period_seconds,omitempty"`
|
||||
// The number of seconds after which the check times out.
|
||||
TimeoutSeconds int32 `json:"timeout_seconds,omitempty"`
|
||||
// The number of successful health checks before considered healthy.
|
||||
SuccessThreshold int32 `json:"success_threshold,omitempty"`
|
||||
// The number of failed health checks before considered unhealthy.
|
||||
FailureThreshold int32 `json:"failure_threshold,omitempty"`
|
||||
// The route path used for the HTTP health check ping. If not set, the HTTP health check will be disabled and a TCP health check used instead.
|
||||
HTTPPath string `json:"http_path,omitempty"`
|
||||
}
|
||||
|
||||
// AppSpec The desired configuration of an application.
|
||||
type AppSpec struct {
|
||||
// The name of the app. Must be unique across all in the same account.
|
||||
Name string `json:"name"`
|
||||
// Workloads which expose publicy-accessible HTTP services.
|
||||
Services []*AppServiceSpec `json:"services,omitempty"`
|
||||
// Content which can be rendered to static web assets.
|
||||
StaticSites []*AppStaticSiteSpec `json:"static_sites,omitempty"`
|
||||
// Workloads which do not expose publicly-accessible HTTP services.
|
||||
Workers []*AppWorkerSpec `json:"workers,omitempty"`
|
||||
// Pre and post deployment workloads which do not expose publicly-accessible HTTP routes.
|
||||
Jobs []*AppJobSpec `json:"jobs,omitempty"`
|
||||
// Database instances which can provide persistence to workloads within the application.
|
||||
Databases []*AppDatabaseSpec `json:"databases,omitempty"`
|
||||
// A set of hostnames where the application will be available.
|
||||
Domains []*AppDomainSpec `json:"domains,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
}
|
||||
|
||||
// AppStaticSiteSpec struct for AppStaticSiteSpec
|
||||
type AppStaticSiteSpec struct {
|
||||
// The name. Must be unique across all components within the same app.
|
||||
Name string `json:"name"`
|
||||
Git *GitSourceSpec `json:"git,omitempty"`
|
||||
GitHub *GitHubSourceSpec `json:"github,omitempty"`
|
||||
// The path to the Dockerfile relative to the root of the repo. If set, it will be used to build this component. Otherwise, App Platform will attempt to build it using buildpacks.
|
||||
DockerfilePath string `json:"dockerfile_path,omitempty"`
|
||||
// An optional build command to run while building this component from source.
|
||||
BuildCommand string `json:"build_command,omitempty"`
|
||||
// An optional path to the working directory to use for the build. For Dockerfile builds, this will be used as the build context. Must be relative to the root of the repo.
|
||||
SourceDir string `json:"source_dir,omitempty"`
|
||||
// An environment slug describing the type of this app. For a full list, please refer to [the product documentation](https://www.digitalocean.com/docs/app-platform/).
|
||||
EnvironmentSlug string `json:"environment_slug,omitempty"`
|
||||
// An optional path to where the built assets will be located, relative to the build context. If not set, App Platform will automatically scan for these directory names: `_static`, `dist`, `public`.
|
||||
OutputDir string `json:"output_dir,omitempty"`
|
||||
IndexDocument string `json:"index_document,omitempty"`
|
||||
// The name of the error document to use when serving this static site. Default: 404.html. If no such file exists within the built assets, App Platform will supply one.
|
||||
ErrorDocument string `json:"error_document,omitempty"`
|
||||
// A list of environment variables made available to the component.
|
||||
Envs []*AppVariableDefinition `json:"envs,omitempty"`
|
||||
// A list of HTTP routes that should be routed to this component.
|
||||
Routes []*AppRouteSpec `json:"routes,omitempty"`
|
||||
CORS *AppCORSPolicy `json:"cors,omitempty"`
|
||||
// The name of the document to use as the fallback for any requests to documents that are not found when serving this static site. Only 1 of `catchall_document` or `error_document` can be set.
|
||||
CatchallDocument string `json:"catchall_document,omitempty"`
|
||||
}
|
||||
|
||||
// AppVariableDefinition struct for AppVariableDefinition
|
||||
type AppVariableDefinition struct {
|
||||
// The name
|
||||
Key string `json:"key"`
|
||||
// The value. If the type is `SECRET`, the value will be encrypted on first submission. On following submissions, the encrypted value should be used.
|
||||
Value string `json:"value,omitempty"`
|
||||
Scope AppVariableScope `json:"scope,omitempty"`
|
||||
Type AppVariableType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// AppWorkerSpec struct for AppWorkerSpec
|
||||
type AppWorkerSpec struct {
|
||||
// The name. Must be unique across all components within the same app.
|
||||
Name string `json:"name"`
|
||||
Git *GitSourceSpec `json:"git,omitempty"`
|
||||
GitHub *GitHubSourceSpec `json:"github,omitempty"`
|
||||
Image *ImageSourceSpec `json:"image,omitempty"`
|
||||
// The path to the Dockerfile relative to the root of the repo. If set, it will be used to build this component. Otherwise, App Platform will attempt to build it using buildpacks.
|
||||
DockerfilePath string `json:"dockerfile_path,omitempty"`
|
||||
// An optional build command to run while building this component from source.
|
||||
BuildCommand string `json:"build_command,omitempty"`
|
||||
// An optional run command to override the component's default.
|
||||
RunCommand string `json:"run_command,omitempty"`
|
||||
// An optional path to the working directory to use for the build. For Dockerfile builds, this will be used as the build context. Must be relative to the root of the repo.
|
||||
SourceDir string `json:"source_dir,omitempty"`
|
||||
// An environment slug describing the type of this app. For a full list, please refer to [the product documentation](https://www.digitalocean.com/docs/app-platform/).
|
||||
EnvironmentSlug string `json:"environment_slug,omitempty"`
|
||||
// A list of environment variables made available to the component.
|
||||
Envs []*AppVariableDefinition `json:"envs,omitempty"`
|
||||
// The instance size to use for this component.
|
||||
InstanceSizeSlug string `json:"instance_size_slug,omitempty"`
|
||||
InstanceCount int64 `json:"instance_count,omitempty"`
|
||||
}
|
||||
|
||||
// AppCORSPolicy struct for AppCORSPolicy
|
||||
type AppCORSPolicy struct {
|
||||
// The set of allowed CORS origins.
|
||||
AllowOrigins []*AppStringMatch `json:"allow_origins,omitempty"`
|
||||
}
|
||||
|
||||
// Deployment struct for Deployment
|
||||
type Deployment struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Spec *AppSpec `json:"spec,omitempty"`
|
||||
Services []*DeploymentService `json:"services,omitempty"`
|
||||
StaticSites []*DeploymentStaticSite `json:"static_sites,omitempty"`
|
||||
Workers []*DeploymentWorker `json:"workers,omitempty"`
|
||||
Jobs []*DeploymentJob `json:"jobs,omitempty"`
|
||||
PhaseLastUpdatedAt time.Time `json:"phase_last_updated_at,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
Cause string `json:"cause,omitempty"`
|
||||
ClonedFrom string `json:"cloned_from,omitempty"`
|
||||
Progress *DeploymentProgress `json:"progress,omitempty"`
|
||||
Phase DeploymentPhase `json:"phase,omitempty"`
|
||||
TierSlug string `json:"tier_slug,omitempty"`
|
||||
}
|
||||
|
||||
// DeploymentJob struct for DeploymentJob
|
||||
type DeploymentJob struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
SourceCommitHash string `json:"source_commit_hash,omitempty"`
|
||||
}
|
||||
|
||||
// DeploymentPhase the model 'DeploymentPhase'
|
||||
type DeploymentPhase string
|
||||
|
||||
// List of DeploymentPhase
|
||||
const (
|
||||
DeploymentPhase_Unknown DeploymentPhase = "UNKNOWN"
|
||||
DeploymentPhase_PendingBuild DeploymentPhase = "PENDING_BUILD"
|
||||
DeploymentPhase_Building DeploymentPhase = "BUILDING"
|
||||
DeploymentPhase_PendingDeploy DeploymentPhase = "PENDING_DEPLOY"
|
||||
DeploymentPhase_Deploying DeploymentPhase = "DEPLOYING"
|
||||
DeploymentPhase_Active DeploymentPhase = "ACTIVE"
|
||||
DeploymentPhase_Superseded DeploymentPhase = "SUPERSEDED"
|
||||
DeploymentPhase_Error DeploymentPhase = "ERROR"
|
||||
DeploymentPhase_Canceled DeploymentPhase = "CANCELED"
|
||||
)
|
||||
|
||||
// DeploymentProgress struct for DeploymentProgress
|
||||
type DeploymentProgress struct {
|
||||
PendingSteps int32 `json:"pending_steps,omitempty"`
|
||||
RunningSteps int32 `json:"running_steps,omitempty"`
|
||||
SuccessSteps int32 `json:"success_steps,omitempty"`
|
||||
ErrorSteps int32 `json:"error_steps,omitempty"`
|
||||
TotalSteps int32 `json:"total_steps,omitempty"`
|
||||
Steps []*DeploymentProgressStep `json:"steps,omitempty"`
|
||||
SummarySteps []*DeploymentProgressStep `json:"summary_steps,omitempty"`
|
||||
}
|
||||
|
||||
// DeploymentService struct for DeploymentService
|
||||
type DeploymentService struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
SourceCommitHash string `json:"source_commit_hash,omitempty"`
|
||||
}
|
||||
|
||||
// DeploymentStaticSite struct for DeploymentStaticSite
|
||||
type DeploymentStaticSite struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
SourceCommitHash string `json:"source_commit_hash,omitempty"`
|
||||
}
|
||||
|
||||
// DeploymentWorker struct for DeploymentWorker
|
||||
type DeploymentWorker struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
SourceCommitHash string `json:"source_commit_hash,omitempty"`
|
||||
}
|
||||
|
||||
// GitHubSourceSpec struct for GitHubSourceSpec
|
||||
type GitHubSourceSpec struct {
|
||||
Repo string `json:"repo,omitempty"`
|
||||
Branch string `json:"branch,omitempty"`
|
||||
DeployOnPush bool `json:"deploy_on_push,omitempty"`
|
||||
}
|
||||
|
||||
// GitSourceSpec struct for GitSourceSpec
|
||||
type GitSourceSpec struct {
|
||||
RepoCloneURL string `json:"repo_clone_url,omitempty"`
|
||||
Branch string `json:"branch,omitempty"`
|
||||
}
|
||||
|
||||
// ImageSourceSpec struct for ImageSourceSpec
|
||||
type ImageSourceSpec struct {
|
||||
RegistryType ImageSourceSpecRegistryType `json:"registry_type,omitempty"`
|
||||
// The registry name. Must be left empty for the `DOCR` registry type.
|
||||
Registry string `json:"registry,omitempty"`
|
||||
// The repository name.
|
||||
Repository string `json:"repository,omitempty"`
|
||||
// The repository tag. Defaults to `latest` if not provided.
|
||||
Tag string `json:"tag,omitempty"`
|
||||
}
|
||||
|
||||
// ImageSourceSpecRegistryType - UNSPECIFIED: Represents an unspecified registry type. - DOCR: The DigitalOcean container registry type.
|
||||
type ImageSourceSpecRegistryType string
|
||||
|
||||
// List of ImageSourceSpecRegistryType
|
||||
const (
|
||||
ImageSourceSpecRegistryType_Unspecified ImageSourceSpecRegistryType = "UNSPECIFIED"
|
||||
ImageSourceSpecRegistryType_DOCR ImageSourceSpecRegistryType = "DOCR"
|
||||
)
|
||||
|
||||
// AppInstanceSize struct for AppInstanceSize
|
||||
type AppInstanceSize struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Slug string `json:"slug,omitempty"`
|
||||
CPUType AppInstanceSizeCPUType `json:"cpu_type,omitempty"`
|
||||
CPUs string `json:"cpus,omitempty"`
|
||||
MemoryBytes string `json:"memory_bytes,omitempty"`
|
||||
USDPerMonth string `json:"usd_per_month,omitempty"`
|
||||
USDPerSecond string `json:"usd_per_second,omitempty"`
|
||||
TierSlug string `json:"tier_slug,omitempty"`
|
||||
TierUpgradeTo string `json:"tier_upgrade_to,omitempty"`
|
||||
TierDowngradeTo string `json:"tier_downgrade_to,omitempty"`
|
||||
}
|
||||
|
||||
// AppInstanceSizeCPUType the model 'AppInstanceSizeCPUType'
|
||||
type AppInstanceSizeCPUType string
|
||||
|
||||
// List of AppInstanceSizeCPUType
|
||||
const (
|
||||
AppInstanceSizeCPUType_Unspecified AppInstanceSizeCPUType = "UNSPECIFIED"
|
||||
AppInstanceSizeCPUType_Shared AppInstanceSizeCPUType = "SHARED"
|
||||
AppInstanceSizeCPUType_Dedicated AppInstanceSizeCPUType = "DEDICATED"
|
||||
)
|
||||
|
||||
// DeploymentProgressStep struct for DeploymentProgressStep
|
||||
type DeploymentProgressStep struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Status DeploymentProgressStepStatus `json:"status,omitempty"`
|
||||
Steps []*DeploymentProgressStep `json:"steps,omitempty"`
|
||||
StartedAt time.Time `json:"started_at,omitempty"`
|
||||
EndedAt time.Time `json:"ended_at,omitempty"`
|
||||
Reason *DeploymentProgressStepReason `json:"reason,omitempty"`
|
||||
ComponentName string `json:"component_name,omitempty"`
|
||||
// The base of a human-readable description of the step intended to be combined with the component name for presentation. For example: `message_base` = \"Building service\" `component_name` = \"api\"
|
||||
MessageBase string `json:"message_base,omitempty"`
|
||||
}
|
||||
|
||||
// DeploymentProgressStepStatus the model 'DeploymentProgressStepStatus'
|
||||
type DeploymentProgressStepStatus string
|
||||
|
||||
// List of DeploymentProgressStepStatus
|
||||
const (
|
||||
DeploymentProgressStepStatus_Unknown DeploymentProgressStepStatus = "UNKNOWN"
|
||||
DeploymentProgressStepStatus_Pending DeploymentProgressStepStatus = "PENDING"
|
||||
DeploymentProgressStepStatus_Running DeploymentProgressStepStatus = "RUNNING"
|
||||
DeploymentProgressStepStatus_Error DeploymentProgressStepStatus = "ERROR"
|
||||
DeploymentProgressStepStatus_Success DeploymentProgressStepStatus = "SUCCESS"
|
||||
)
|
||||
|
||||
// AppRegion struct for AppRegion
|
||||
type AppRegion struct {
|
||||
Slug string `json:"slug,omitempty"`
|
||||
Label string `json:"label,omitempty"`
|
||||
Flag string `json:"flag,omitempty"`
|
||||
Continent string `json:"continent,omitempty"`
|
||||
Disabled bool `json:"disabled,omitempty"`
|
||||
DataCenters []string `json:"data_centers,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
// Whether or not the region is presented as the default.
|
||||
Default bool `json:"default,omitempty"`
|
||||
}
|
||||
|
||||
// DeploymentProgressStepReason struct for DeploymentProgressStepReason
|
||||
type DeploymentProgressStepReason struct {
|
||||
Code string `json:"code,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// AppStringMatch struct for AppStringMatch
|
||||
type AppStringMatch struct {
|
||||
// Exact string match. Only 1 of `exact`, `prefix`, or `regex` must be set.
|
||||
Exact string `json:"exact,omitempty"`
|
||||
// Prefix-based match. Only 1 of `exact`, `prefix`, or `regex` must be set.
|
||||
Prefix string `json:"prefix,omitempty"`
|
||||
Regex string `json:"regex,omitempty"`
|
||||
}
|
||||
|
||||
// AppTier struct for AppTier
|
||||
type AppTier struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Slug string `json:"slug,omitempty"`
|
||||
StorageBytes string `json:"storage_bytes,omitempty"`
|
||||
EgressBandwidthBytes string `json:"egress_bandwidth_bytes,omitempty"`
|
||||
BuildSeconds string `json:"build_seconds,omitempty"`
|
||||
}
|
||||
|
||||
// AppVariableScope the model 'AppVariableScope'
|
||||
type AppVariableScope string
|
||||
|
||||
// List of AppVariableScope
|
||||
const (
|
||||
AppVariableScope_Unset AppVariableScope = "UNSET"
|
||||
AppVariableScope_RunTime AppVariableScope = "RUN_TIME"
|
||||
AppVariableScope_BuildTime AppVariableScope = "BUILD_TIME"
|
||||
AppVariableScope_RunAndBuildTime AppVariableScope = "RUN_AND_BUILD_TIME"
|
||||
)
|
||||
|
||||
// AppVariableType the model 'AppVariableType'
|
||||
type AppVariableType string
|
||||
|
||||
// List of AppVariableType
|
||||
const (
|
||||
AppVariableType_General AppVariableType = "GENERAL"
|
||||
AppVariableType_Secret AppVariableType = "SECRET"
|
||||
)
|
|
@ -0,0 +1,330 @@
|
|||
package godo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
appsBasePath = "/v2/apps"
|
||||
)
|
||||
|
||||
// AppLogType is the type of app logs.
|
||||
type AppLogType string
|
||||
|
||||
const (
|
||||
// AppLogTypeBuild represents build logs.
|
||||
AppLogTypeBuild AppLogType = "BUILD"
|
||||
// AppLogTypeDeploy represents deploy logs.
|
||||
AppLogTypeDeploy AppLogType = "DEPLOY"
|
||||
// AppLogTypeRun represents run logs.
|
||||
AppLogTypeRun AppLogType = "RUN"
|
||||
)
|
||||
|
||||
// AppsService is an interface for interfacing with the App Platform endpoints
|
||||
// of the DigitalOcean API.
|
||||
type AppsService interface {
|
||||
Create(ctx context.Context, create *AppCreateRequest) (*App, *Response, error)
|
||||
Get(ctx context.Context, appID string) (*App, *Response, error)
|
||||
List(ctx context.Context, opts *ListOptions) ([]*App, *Response, error)
|
||||
Update(ctx context.Context, appID string, update *AppUpdateRequest) (*App, *Response, error)
|
||||
Delete(ctx context.Context, appID string) (*Response, error)
|
||||
|
||||
GetDeployment(ctx context.Context, appID, deploymentID string) (*Deployment, *Response, error)
|
||||
ListDeployments(ctx context.Context, appID string, opts *ListOptions) ([]*Deployment, *Response, error)
|
||||
CreateDeployment(ctx context.Context, appID string, create ...*DeploymentCreateRequest) (*Deployment, *Response, error)
|
||||
|
||||
GetLogs(ctx context.Context, appID, deploymentID, component string, logType AppLogType, follow bool) (*AppLogs, *Response, error)
|
||||
|
||||
ListRegions(ctx context.Context) ([]*AppRegion, *Response, error)
|
||||
|
||||
ListTiers(ctx context.Context) ([]*AppTier, *Response, error)
|
||||
GetTier(ctx context.Context, slug string) (*AppTier, *Response, error)
|
||||
|
||||
ListInstanceSizes(ctx context.Context) ([]*AppInstanceSize, *Response, error)
|
||||
GetInstanceSize(ctx context.Context, slug string) (*AppInstanceSize, *Response, error)
|
||||
}
|
||||
|
||||
// AppLogs represent app logs.
|
||||
type AppLogs struct {
|
||||
LiveURL string `json:"live_url"`
|
||||
HistoricURLs []string `json:"historic_urls"`
|
||||
}
|
||||
|
||||
// AppCreateRequest represents a request to create an app.
|
||||
type AppCreateRequest struct {
|
||||
Spec *AppSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// AppUpdateRequest represents a request to update an app.
|
||||
type AppUpdateRequest struct {
|
||||
Spec *AppSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// DeploymentCreateRequest represents a request to create a deployment.
|
||||
type DeploymentCreateRequest struct {
|
||||
ForceBuild bool `json:"force_build"`
|
||||
}
|
||||
|
||||
type appRoot struct {
|
||||
App *App `json:"app"`
|
||||
}
|
||||
|
||||
type appsRoot struct {
|
||||
Apps []*App `json:"apps"`
|
||||
}
|
||||
|
||||
type deploymentRoot struct {
|
||||
Deployment *Deployment `json:"deployment"`
|
||||
}
|
||||
|
||||
type deploymentsRoot struct {
|
||||
Deployments []*Deployment `json:"deployments"`
|
||||
}
|
||||
|
||||
type appTierRoot struct {
|
||||
Tier *AppTier `json:"tier"`
|
||||
}
|
||||
|
||||
type appTiersRoot struct {
|
||||
Tiers []*AppTier `json:"tiers"`
|
||||
}
|
||||
|
||||
type instanceSizeRoot struct {
|
||||
InstanceSize *AppInstanceSize `json:"instance_size"`
|
||||
}
|
||||
|
||||
type instanceSizesRoot struct {
|
||||
InstanceSizes []*AppInstanceSize `json:"instance_sizes"`
|
||||
}
|
||||
|
||||
type appRegionsRoot struct {
|
||||
Regions []*AppRegion `json:"regions"`
|
||||
}
|
||||
|
||||
// AppsServiceOp handles communication with Apps methods of the DigitalOcean API.
|
||||
type AppsServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Create an app.
|
||||
func (s *AppsServiceOp) Create(ctx context.Context, create *AppCreateRequest) (*App, *Response, error) {
|
||||
path := appsBasePath
|
||||
req, err := s.client.NewRequest(ctx, http.MethodPost, path, create)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(appRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.App, resp, nil
|
||||
}
|
||||
|
||||
// Get an app.
|
||||
func (s *AppsServiceOp) Get(ctx context.Context, appID string) (*App, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", appsBasePath, appID)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(appRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.App, resp, nil
|
||||
}
|
||||
|
||||
// List apps.
|
||||
func (s *AppsServiceOp) List(ctx context.Context, opts *ListOptions) ([]*App, *Response, error) {
|
||||
path := appsBasePath
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(appsRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Apps, resp, nil
|
||||
}
|
||||
|
||||
// Update an app.
|
||||
func (s *AppsServiceOp) Update(ctx context.Context, appID string, update *AppUpdateRequest) (*App, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", appsBasePath, appID)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodPut, path, update)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(appRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.App, resp, nil
|
||||
}
|
||||
|
||||
// Delete an app.
|
||||
func (s *AppsServiceOp) Delete(ctx context.Context, appID string) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", appsBasePath, appID)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := s.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetDeployment gets an app deployment.
|
||||
func (s *AppsServiceOp) GetDeployment(ctx context.Context, appID, deploymentID string) (*Deployment, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/deployments/%s", appsBasePath, appID, deploymentID)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(deploymentRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Deployment, resp, nil
|
||||
}
|
||||
|
||||
// ListDeployments lists an app deployments.
|
||||
func (s *AppsServiceOp) ListDeployments(ctx context.Context, appID string, opts *ListOptions) ([]*Deployment, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/deployments", appsBasePath, appID)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(deploymentsRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Deployments, resp, nil
|
||||
}
|
||||
|
||||
// CreateDeployment creates an app deployment.
|
||||
func (s *AppsServiceOp) CreateDeployment(ctx context.Context, appID string, create ...*DeploymentCreateRequest) (*Deployment, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/deployments", appsBasePath, appID)
|
||||
|
||||
var createReq *DeploymentCreateRequest
|
||||
for _, c := range create {
|
||||
createReq = c
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodPost, path, createReq)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(deploymentRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Deployment, resp, nil
|
||||
}
|
||||
|
||||
// GetLogs retrieves app logs.
|
||||
func (s *AppsServiceOp) GetLogs(ctx context.Context, appID, deploymentID, component string, logType AppLogType, follow bool) (*AppLogs, *Response, error) {
|
||||
url := fmt.Sprintf("%s/%s/deployments/%s/logs?type=%s&follow=%t", appsBasePath, appID, deploymentID, logType, follow)
|
||||
if component != "" {
|
||||
url = fmt.Sprintf("%s&component_name=%s", url, component)
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
logs := new(AppLogs)
|
||||
resp, err := s.client.Do(ctx, req, logs)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return logs, resp, nil
|
||||
}
|
||||
|
||||
// ListRegions lists all regions supported by App Platform.
|
||||
func (s *AppsServiceOp) ListRegions(ctx context.Context) ([]*AppRegion, *Response, error) {
|
||||
path := fmt.Sprintf("%s/regions", appsBasePath)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(appRegionsRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Regions, resp, nil
|
||||
}
|
||||
|
||||
// ListTiers lists available app tiers.
|
||||
func (s *AppsServiceOp) ListTiers(ctx context.Context) ([]*AppTier, *Response, error) {
|
||||
path := fmt.Sprintf("%s/tiers", appsBasePath)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(appTiersRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Tiers, resp, nil
|
||||
}
|
||||
|
||||
// GetTier retrieves information about a specific app tier.
|
||||
func (s *AppsServiceOp) GetTier(ctx context.Context, slug string) (*AppTier, *Response, error) {
|
||||
path := fmt.Sprintf("%s/tiers/%s", appsBasePath, slug)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(appTierRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Tier, resp, nil
|
||||
}
|
||||
|
||||
// ListInstanceSizes lists available instance sizes for service, worker, and job components.
|
||||
func (s *AppsServiceOp) ListInstanceSizes(ctx context.Context) ([]*AppInstanceSize, *Response, error) {
|
||||
path := fmt.Sprintf("%s/tiers/instance_sizes", appsBasePath)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(instanceSizesRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.InstanceSizes, resp, nil
|
||||
}
|
||||
|
||||
// GetInstanceSize retreives information about a specific instance size for service, worker, and job components.
|
||||
func (s *AppsServiceOp) GetInstanceSize(ctx context.Context, slug string) (*AppInstanceSize, *Response, error) {
|
||||
path := fmt.Sprintf("%s/tiers/instance_sizes/%s", appsBasePath, slug)
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(instanceSizeRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.InstanceSize, resp, nil
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package godo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// BalanceService is an interface for interfacing with the Balance
|
||||
// endpoints of the DigitalOcean API
|
||||
// See: https://developers.digitalocean.com/documentation/v2/#balance
|
||||
type BalanceService interface {
|
||||
Get(context.Context) (*Balance, *Response, error)
|
||||
}
|
||||
|
||||
// BalanceServiceOp handles communication with the Balance related methods of
|
||||
// the DigitalOcean API.
|
||||
type BalanceServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
var _ BalanceService = &BalanceServiceOp{}
|
||||
|
||||
// Balance represents a DigitalOcean Balance
|
||||
type Balance struct {
|
||||
MonthToDateBalance string `json:"month_to_date_balance"`
|
||||
AccountBalance string `json:"account_balance"`
|
||||
MonthToDateUsage string `json:"month_to_date_usage"`
|
||||
GeneratedAt time.Time `json:"generated_at"`
|
||||
}
|
||||
|
||||
func (r Balance) String() string {
|
||||
return Stringify(r)
|
||||
}
|
||||
|
||||
// Get DigitalOcean balance info
|
||||
func (s *BalanceServiceOp) Get(ctx context.Context) (*Balance, *Response, error) {
|
||||
path := "v2/customers/my/balance"
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(Balance)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root, resp, err
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package godo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const billingHistoryBasePath = "v2/customers/my/billing_history"
|
||||
|
||||
// BillingHistoryService is an interface for interfacing with the BillingHistory
|
||||
// endpoints of the DigitalOcean API
|
||||
// See: https://developers.digitalocean.com/documentation/v2/#billing_history
|
||||
type BillingHistoryService interface {
|
||||
List(context.Context, *ListOptions) (*BillingHistory, *Response, error)
|
||||
}
|
||||
|
||||
// BillingHistoryServiceOp handles communication with the BillingHistory related methods of
|
||||
// the DigitalOcean API.
|
||||
type BillingHistoryServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
var _ BillingHistoryService = &BillingHistoryServiceOp{}
|
||||
|
||||
// BillingHistory represents a DigitalOcean Billing History
|
||||
type BillingHistory struct {
|
||||
BillingHistory []BillingHistoryEntry `json:"billing_history"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// BillingHistoryEntry represents an entry in a customer's Billing History
|
||||
type BillingHistoryEntry struct {
|
||||
Description string `json:"description"`
|
||||
Amount string `json:"amount"`
|
||||
InvoiceID *string `json:"invoice_id"`
|
||||
InvoiceUUID *string `json:"invoice_uuid"`
|
||||
Date time.Time `json:"date"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func (b BillingHistory) String() string {
|
||||
return Stringify(b)
|
||||
}
|
||||
|
||||
// List the Billing History for a customer
|
||||
func (s *BillingHistoryServiceOp) List(ctx context.Context, opt *ListOptions) (*BillingHistory, *Response, error) {
|
||||
path, err := addOptions(billingHistoryBasePath, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(BillingHistory)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root, resp, err
|
||||
}
|
|
@ -47,6 +47,7 @@ type cdnRoot struct {
|
|||
type cdnsRoot struct {
|
||||
Endpoints []CDN `json:"endpoints"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// CDNCreateRequest represents a request to create a CDN.
|
||||
|
@ -93,6 +94,9 @@ func (c CDNServiceOp) List(ctx context.Context, opt *ListOptions) ([]CDN, *Respo
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Endpoints, resp, err
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ type certificateRoot struct {
|
|||
type certificatesRoot struct {
|
||||
Certificates []Certificate `json:"certificates"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// CertificatesServiceOp handles communication with certificates methods of the DigitalOcean API.
|
||||
|
@ -93,6 +94,9 @@ func (c *CertificatesServiceOp) List(ctx context.Context, opt *ListOptions) ([]C
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Certificates, resp, nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -16,17 +17,76 @@ const (
|
|||
databaseBackupsPath = databaseBasePath + "/%s/backups"
|
||||
databaseUsersPath = databaseBasePath + "/%s/users"
|
||||
databaseUserPath = databaseBasePath + "/%s/users/%s"
|
||||
databaseResetUserAuthPath = databaseUserPath + "/reset_auth"
|
||||
databaseDBPath = databaseBasePath + "/%s/dbs/%s"
|
||||
databaseDBsPath = databaseBasePath + "/%s/dbs"
|
||||
databasePoolPath = databaseBasePath + "/%s/pools/%s"
|
||||
databasePoolsPath = databaseBasePath + "/%s/pools"
|
||||
databaseReplicaPath = databaseBasePath + "/%s/replicas/%s"
|
||||
databaseReplicasPath = databaseBasePath + "/%s/replicas"
|
||||
evictionPolicyPath = databaseBasePath + "/%s/eviction_policy"
|
||||
databaseEvictionPolicyPath = databaseBasePath + "/%s/eviction_policy"
|
||||
databaseSQLModePath = databaseBasePath + "/%s/sql_mode"
|
||||
databaseFirewallRulesPath = databaseBasePath + "/%s/firewall"
|
||||
)
|
||||
|
||||
// DatabasesService is an interface for interfacing with the databases endpoints
|
||||
// of the DigitalOcean API.
|
||||
// SQL Mode constants allow for MySQL-specific SQL flavor configuration.
|
||||
const (
|
||||
SQLModeAllowInvalidDates = "ALLOW_INVALID_DATES"
|
||||
SQLModeANSIQuotes = "ANSI_QUOTES"
|
||||
SQLModeHighNotPrecedence = "HIGH_NOT_PRECEDENCE"
|
||||
SQLModeIgnoreSpace = "IGNORE_SPACE"
|
||||
SQLModeNoAuthCreateUser = "NO_AUTO_CREATE_USER"
|
||||
SQLModeNoAutoValueOnZero = "NO_AUTO_VALUE_ON_ZERO"
|
||||
SQLModeNoBackslashEscapes = "NO_BACKSLASH_ESCAPES"
|
||||
SQLModeNoDirInCreate = "NO_DIR_IN_CREATE"
|
||||
SQLModeNoEngineSubstitution = "NO_ENGINE_SUBSTITUTION"
|
||||
SQLModeNoFieldOptions = "NO_FIELD_OPTIONS"
|
||||
SQLModeNoKeyOptions = "NO_KEY_OPTIONS"
|
||||
SQLModeNoTableOptions = "NO_TABLE_OPTIONS"
|
||||
SQLModeNoUnsignedSubtraction = "NO_UNSIGNED_SUBTRACTION"
|
||||
SQLModeNoZeroDate = "NO_ZERO_DATE"
|
||||
SQLModeNoZeroInDate = "NO_ZERO_IN_DATE"
|
||||
SQLModeOnlyFullGroupBy = "ONLY_FULL_GROUP_BY"
|
||||
SQLModePadCharToFullLength = "PAD_CHAR_TO_FULL_LENGTH"
|
||||
SQLModePipesAsConcat = "PIPES_AS_CONCAT"
|
||||
SQLModeRealAsFloat = "REAL_AS_FLOAT"
|
||||
SQLModeStrictAllTables = "STRICT_ALL_TABLES"
|
||||
SQLModeStrictTransTables = "STRICT_TRANS_TABLES"
|
||||
SQLModeANSI = "ANSI"
|
||||
SQLModeDB2 = "DB2"
|
||||
SQLModeMaxDB = "MAXDB"
|
||||
SQLModeMSSQL = "MSSQL"
|
||||
SQLModeMYSQL323 = "MYSQL323"
|
||||
SQLModeMYSQL40 = "MYSQL40"
|
||||
SQLModeOracle = "ORACLE"
|
||||
SQLModePostgreSQL = "POSTGRESQL"
|
||||
SQLModeTraditional = "TRADITIONAL"
|
||||
)
|
||||
|
||||
// SQL Auth constants allow for MySQL-specific user auth plugins
|
||||
const (
|
||||
SQLAuthPluginNative = "mysql_native_password"
|
||||
SQLAuthPluginCachingSHA2 = "caching_sha2_password"
|
||||
)
|
||||
|
||||
// Redis eviction policies supported by the managed Redis product.
|
||||
const (
|
||||
EvictionPolicyNoEviction = "noeviction"
|
||||
EvictionPolicyAllKeysLRU = "allkeys_lru"
|
||||
EvictionPolicyAllKeysRandom = "allkeys_random"
|
||||
EvictionPolicyVolatileLRU = "volatile_lru"
|
||||
EvictionPolicyVolatileRandom = "volatile_random"
|
||||
EvictionPolicyVolatileTTL = "volatile_ttl"
|
||||
)
|
||||
|
||||
// The DatabasesService provides access to the DigitalOcean managed database
|
||||
// suite of products through the public API. Customers can create new database
|
||||
// clusters, migrate them between regions, create replicas and interact with
|
||||
// their configurations. Each database service is referred to as a Database. A
|
||||
// SQL database service can have multiple databases residing in the system. To
|
||||
// help make these entities distinct from Databases in godo, we refer to them
|
||||
// here as DatabaseDBs.
|
||||
//
|
||||
// See: https://developers.digitalocean.com/documentation/v2#databases
|
||||
type DatabasesService interface {
|
||||
List(context.Context, *ListOptions) ([]Database, *Response, error)
|
||||
|
@ -41,6 +101,7 @@ type DatabasesService interface {
|
|||
ListUsers(context.Context, string, *ListOptions) ([]DatabaseUser, *Response, error)
|
||||
CreateUser(context.Context, string, *DatabaseCreateUserRequest) (*DatabaseUser, *Response, error)
|
||||
DeleteUser(context.Context, string, string) (*Response, error)
|
||||
ResetUserAuth(context.Context, string, string, *DatabaseResetUserAuthRequest) (*DatabaseUser, *Response, error)
|
||||
ListDBs(context.Context, string, *ListOptions) ([]DatabaseDB, *Response, error)
|
||||
CreateDB(context.Context, string, *DatabaseCreateDBRequest) (*DatabaseDB, *Response, error)
|
||||
GetDB(context.Context, string, string) (*DatabaseDB, *Response, error)
|
||||
|
@ -55,6 +116,10 @@ type DatabasesService interface {
|
|||
DeleteReplica(context.Context, string, string) (*Response, error)
|
||||
GetEvictionPolicy(context.Context, string) (string, *Response, error)
|
||||
SetEvictionPolicy(context.Context, string, string) (*Response, error)
|
||||
GetSQLMode(context.Context, string) (string, *Response, error)
|
||||
SetSQLMode(context.Context, string, ...string) (*Response, error)
|
||||
GetFirewallRules(context.Context, string) ([]DatabaseFirewallRule, *Response, error)
|
||||
UpdateFirewallRules(context.Context, string, *DatabaseUpdateFirewallRulesRequest) (*Response, error)
|
||||
}
|
||||
|
||||
// DatabasesServiceOp handles communication with the Databases related methods
|
||||
|
@ -86,6 +151,7 @@ type Database struct {
|
|||
MaintenanceWindow *DatabaseMaintenanceWindow `json:"maintenance_window,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
PrivateNetworkUUID string `json:"private_network_uuid,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseConnection represents a database connection
|
||||
|
@ -104,6 +170,12 @@ type DatabaseUser struct {
|
|||
Name string `json:"name,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
MySQLSettings *DatabaseMySQLUserSettings `json:"mysql_settings,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseMySQLUserSettings contains MySQL-specific user settings
|
||||
type DatabaseMySQLUserSettings struct {
|
||||
AuthPlugin string `json:"auth_plugin"`
|
||||
}
|
||||
|
||||
// DatabaseMaintenanceWindow represents the maintenance_window of a database
|
||||
|
@ -130,6 +202,7 @@ type DatabaseCreateRequest struct {
|
|||
Region string `json:"region,omitempty"`
|
||||
NumNodes int `json:"num_nodes,omitempty"`
|
||||
PrivateNetworkUUID string `json:"private_network_uuid"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseResizeRequest can be used to initiate a database resize operation.
|
||||
|
@ -167,6 +240,7 @@ type DatabaseReplica struct {
|
|||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
PrivateNetworkUUID string `json:"private_network_uuid,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// DatabasePool represents a database connection pool
|
||||
|
@ -192,6 +266,12 @@ type DatabaseCreatePoolRequest struct {
|
|||
// DatabaseCreateUserRequest is used to create a new database user
|
||||
type DatabaseCreateUserRequest struct {
|
||||
Name string `json:"name"`
|
||||
MySQLSettings *DatabaseMySQLUserSettings `json:"mysql_settings,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseResetUserAuthRequest is used to reset a users DB auth
|
||||
type DatabaseResetUserAuthRequest struct {
|
||||
MySQLSettings *DatabaseMySQLUserSettings `json:"mysql_settings,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseCreateDBRequest is used to create a new engine-specific database within the cluster
|
||||
|
@ -205,6 +285,21 @@ type DatabaseCreateReplicaRequest struct {
|
|||
Region string `json:"region"`
|
||||
Size string `json:"size"`
|
||||
PrivateNetworkUUID string `json:"private_network_uuid"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseUpdateFirewallRulesRequest is used to set the firewall rules for a database
|
||||
type DatabaseUpdateFirewallRulesRequest struct {
|
||||
Rules []*DatabaseFirewallRule `json:"rules"`
|
||||
}
|
||||
|
||||
// DatabaseFirewallRule is a rule describing an inbound source to a database
|
||||
type DatabaseFirewallRule struct {
|
||||
UUID string `json:"uuid"`
|
||||
ClusterUUID string `json:"cluster_uuid"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type databaseUserRoot struct {
|
||||
|
@ -255,6 +350,15 @@ type evictionPolicyRoot struct {
|
|||
EvictionPolicy string `json:"eviction_policy"`
|
||||
}
|
||||
|
||||
type sqlModeRoot struct {
|
||||
SQLMode string `json:"sql_mode"`
|
||||
}
|
||||
|
||||
type databaseFirewallRuleRoot struct {
|
||||
Rules []DatabaseFirewallRule `json:"rules"`
|
||||
}
|
||||
|
||||
// URN returns a URN identifier for the database
|
||||
func (d Database) URN() string {
|
||||
return ToURN("dbaas", d.ID)
|
||||
}
|
||||
|
@ -433,6 +537,21 @@ func (svc *DatabasesServiceOp) CreateUser(ctx context.Context, databaseID string
|
|||
return root.User, resp, nil
|
||||
}
|
||||
|
||||
// ResetUserAuth will reset user authentication
|
||||
func (svc *DatabasesServiceOp) ResetUserAuth(ctx context.Context, databaseID, userID string, resetAuth *DatabaseResetUserAuthRequest) (*DatabaseUser, *Response, error) {
|
||||
path := fmt.Sprintf(databaseResetUserAuthPath, databaseID, userID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, resetAuth)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseUserRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.User, resp, nil
|
||||
}
|
||||
|
||||
// DeleteUser will delete an existing database user
|
||||
func (svc *DatabasesServiceOp) DeleteUser(ctx context.Context, databaseID, userID string) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseUserPath, databaseID, userID)
|
||||
|
@ -638,7 +757,7 @@ func (svc *DatabasesServiceOp) DeleteReplica(ctx context.Context, databaseID, na
|
|||
|
||||
// GetEvictionPolicy loads the eviction policy for a given Redis cluster.
|
||||
func (svc *DatabasesServiceOp) GetEvictionPolicy(ctx context.Context, databaseID string) (string, *Response, error) {
|
||||
path := fmt.Sprintf(evictionPolicyPath, databaseID)
|
||||
path := fmt.Sprintf(databaseEvictionPolicyPath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
|
@ -652,8 +771,11 @@ func (svc *DatabasesServiceOp) GetEvictionPolicy(ctx context.Context, databaseID
|
|||
}
|
||||
|
||||
// SetEvictionPolicy updates the eviction policy for a given Redis cluster.
|
||||
//
|
||||
// The valid eviction policies are documented by the exported string constants
|
||||
// with the prefix `EvictionPolicy`.
|
||||
func (svc *DatabasesServiceOp) SetEvictionPolicy(ctx context.Context, databaseID, policy string) (*Response, error) {
|
||||
path := fmt.Sprintf(evictionPolicyPath, databaseID)
|
||||
path := fmt.Sprintf(databaseEvictionPolicyPath, databaseID)
|
||||
root := &evictionPolicyRoot{EvictionPolicy: policy}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPut, path, root)
|
||||
if err != nil {
|
||||
|
@ -665,3 +787,60 @@ func (svc *DatabasesServiceOp) SetEvictionPolicy(ctx context.Context, databaseID
|
|||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetSQLMode loads the SQL Mode settings for a given MySQL cluster.
|
||||
func (svc *DatabasesServiceOp) GetSQLMode(ctx context.Context, databaseID string) (string, *Response, error) {
|
||||
path := fmt.Sprintf(databaseSQLModePath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
root := &sqlModeRoot{}
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return "", resp, err
|
||||
}
|
||||
return root.SQLMode, resp, nil
|
||||
}
|
||||
|
||||
// SetSQLMode updates the SQL Mode settings for a given MySQL cluster.
|
||||
func (svc *DatabasesServiceOp) SetSQLMode(ctx context.Context, databaseID string, sqlModes ...string) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseSQLModePath, databaseID)
|
||||
root := &sqlModeRoot{SQLMode: strings.Join(sqlModes, ",")}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPut, path, root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetFirewallRules loads the inbound sources for a given cluster.
|
||||
func (svc *DatabasesServiceOp) GetFirewallRules(ctx context.Context, databaseID string) ([]DatabaseFirewallRule, *Response, error) {
|
||||
path := fmt.Sprintf(databaseFirewallRulesPath, databaseID)
|
||||
root := new(databaseFirewallRuleRoot)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.Rules, resp, nil
|
||||
}
|
||||
|
||||
// UpdateFirewallRules sets the inbound sources for a given cluster.
|
||||
func (svc *DatabasesServiceOp) UpdateFirewallRules(ctx context.Context, databaseID string, firewallRulesReq *DatabaseUpdateFirewallRulesRequest) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseFirewallRulesPath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPut, path, firewallRulesReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return svc.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,2 @@
|
|||
// Package godo is the DigtalOcean API v2 client for Go
|
||||
//
|
||||
// Databases
|
||||
//
|
||||
// The Databases service provides access to the DigitalOcean managed database
|
||||
// suite of products. Customers can create new database clusters, migrate them
|
||||
// between regions, create replicas and interact with their configurations.
|
||||
// Each database service is refered to as a Database. A SQL database service
|
||||
// can have multiple databases residing in the system. To help make these
|
||||
// entities distinct from Databases in godo, we refer to them here as DatabaseDBs.
|
||||
// Package godo is the DigtalOcean API v2 client for Go.
|
||||
package godo
|
||||
|
|
|
@ -18,6 +18,9 @@ type DomainsService interface {
|
|||
Delete(context.Context, string) (*Response, error)
|
||||
|
||||
Records(context.Context, string, *ListOptions) ([]DomainRecord, *Response, error)
|
||||
RecordsByType(context.Context, string, string, *ListOptions) ([]DomainRecord, *Response, error)
|
||||
RecordsByName(context.Context, string, string, *ListOptions) ([]DomainRecord, *Response, error)
|
||||
RecordsByTypeAndName(context.Context, string, string, string, *ListOptions) ([]DomainRecord, *Response, error)
|
||||
Record(context.Context, string, int) (*DomainRecord, *Response, error)
|
||||
DeleteRecord(context.Context, string, int) (*Response, error)
|
||||
EditRecord(context.Context, string, int, *DomainRecordEditRequest) (*DomainRecord, *Response, error)
|
||||
|
@ -47,6 +50,7 @@ type domainRoot struct {
|
|||
type domainsRoot struct {
|
||||
Domains []Domain `json:"domains"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// DomainCreateRequest respresents a request to create a domain.
|
||||
|
@ -73,7 +77,7 @@ type DomainRecord struct {
|
|||
Name string `json:"name,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
Priority int `json:"priority"`
|
||||
Port int `json:"port,omitempty"`
|
||||
Port int `json:"port"`
|
||||
TTL int `json:"ttl,omitempty"`
|
||||
Weight int `json:"weight"`
|
||||
Flags int `json:"flags"`
|
||||
|
@ -86,7 +90,7 @@ type DomainRecordEditRequest struct {
|
|||
Name string `json:"name,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
Priority int `json:"priority"`
|
||||
Port int `json:"port,omitempty"`
|
||||
Port int `json:"port"`
|
||||
TTL int `json:"ttl,omitempty"`
|
||||
Weight int `json:"weight"`
|
||||
Flags int `json:"flags"`
|
||||
|
@ -97,6 +101,7 @@ func (d Domain) String() string {
|
|||
return Stringify(d)
|
||||
}
|
||||
|
||||
// URN returns the domain name in a valid DO API URN form.
|
||||
func (d Domain) URN() string {
|
||||
return ToURN("Domain", d.Name)
|
||||
}
|
||||
|
@ -122,6 +127,9 @@ func (s DomainsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Domain,
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Domains, resp, err
|
||||
}
|
||||
|
@ -197,7 +205,7 @@ func (d DomainRecordEditRequest) String() string {
|
|||
return Stringify(d)
|
||||
}
|
||||
|
||||
// Records returns a slice of DomainRecords for a domain
|
||||
// Records returns a slice of DomainRecord for a domain.
|
||||
func (s *DomainsServiceOp) Records(ctx context.Context, domain string, opt *ListOptions) ([]DomainRecord, *Response, error) {
|
||||
if len(domain) < 1 {
|
||||
return nil, nil, NewArgError("domain", "cannot be an empty string")
|
||||
|
@ -209,21 +217,68 @@ func (s *DomainsServiceOp) Records(ctx context.Context, domain string, opt *List
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
return s.records(ctx, path)
|
||||
}
|
||||
|
||||
// RecordsByType returns a slice of DomainRecord for a domain matched by record type.
|
||||
func (s *DomainsServiceOp) RecordsByType(ctx context.Context, domain, ofType string, opt *ListOptions) ([]DomainRecord, *Response, error) {
|
||||
if len(domain) < 1 {
|
||||
return nil, nil, NewArgError("domain", "cannot be an empty string")
|
||||
}
|
||||
|
||||
if len(ofType) < 1 {
|
||||
return nil, nil, NewArgError("type", "cannot be an empty string")
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%s/records?type=%s", domainsBasePath, domain, ofType)
|
||||
path, err := addOptions(path, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(domainRecordsRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
return s.records(ctx, path)
|
||||
}
|
||||
|
||||
// RecordsByName returns a slice of DomainRecord for a domain matched by record name.
|
||||
func (s *DomainsServiceOp) RecordsByName(ctx context.Context, domain, name string, opt *ListOptions) ([]DomainRecord, *Response, error) {
|
||||
if len(domain) < 1 {
|
||||
return nil, nil, NewArgError("domain", "cannot be an empty string")
|
||||
}
|
||||
|
||||
return root.DomainRecords, resp, err
|
||||
if len(name) < 1 {
|
||||
return nil, nil, NewArgError("name", "cannot be an empty string")
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%s/records?name=%s", domainsBasePath, domain, name)
|
||||
path, err := addOptions(path, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return s.records(ctx, path)
|
||||
}
|
||||
|
||||
// RecordsByTypeAndName returns a slice of DomainRecord for a domain matched by record type and name.
|
||||
func (s *DomainsServiceOp) RecordsByTypeAndName(ctx context.Context, domain, ofType, name string, opt *ListOptions) ([]DomainRecord, *Response, error) {
|
||||
if len(domain) < 1 {
|
||||
return nil, nil, NewArgError("domain", "cannot be an empty string")
|
||||
}
|
||||
|
||||
if len(ofType) < 1 {
|
||||
return nil, nil, NewArgError("type", "cannot be an empty string")
|
||||
}
|
||||
|
||||
if len(name) < 1 {
|
||||
return nil, nil, NewArgError("name", "cannot be an empty string")
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%s/records?type=%s&name=%s", domainsBasePath, domain, ofType, name)
|
||||
path, err := addOptions(path, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return s.records(ctx, path)
|
||||
}
|
||||
|
||||
// Record returns the record id from a domain
|
||||
|
@ -335,3 +390,22 @@ func (s *DomainsServiceOp) CreateRecord(ctx context.Context,
|
|||
|
||||
return d.DomainRecord, resp, err
|
||||
}
|
||||
|
||||
// Performs a domain records request given a path.
|
||||
func (s *DomainsServiceOp) records(ctx context.Context, path string) ([]DomainRecord, *Response, error) {
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(domainRecordsRoot)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
|
||||
return root.DomainRecords, resp, err
|
||||
}
|
||||
|
|
|
@ -126,6 +126,7 @@ func (d Droplet) String() string {
|
|||
return Stringify(d)
|
||||
}
|
||||
|
||||
// URN returns the droplet ID in a valid DO API URN form.
|
||||
func (d Droplet) URN() string {
|
||||
return ToURN("Droplet", d.ID)
|
||||
}
|
||||
|
@ -139,21 +140,25 @@ type dropletRoot struct {
|
|||
type dropletsRoot struct {
|
||||
Droplets []Droplet `json:"droplets"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type kernelsRoot struct {
|
||||
Kernels []Kernel `json:"kernels,omitempty"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type dropletSnapshotsRoot struct {
|
||||
Snapshots []Image `json:"snapshots,omitempty"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type backupsRoot struct {
|
||||
Backups []Image `json:"backups,omitempty"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// DropletCreateImage identifies an image for the create request. It prefers slug over ID.
|
||||
|
@ -295,6 +300,9 @@ func (s *DropletsServiceOp) list(ctx context.Context, path string) ([]Droplet, *
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Droplets, resp, err
|
||||
}
|
||||
|
@ -449,6 +457,9 @@ func (s *DropletsServiceOp) Kernels(ctx context.Context, dropletID int, opt *Lis
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Kernels, resp, err
|
||||
}
|
||||
|
@ -478,6 +489,9 @@ func (s *DropletsServiceOp) Actions(ctx context.Context, dropletID int, opt *Lis
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Actions, resp, err
|
||||
}
|
||||
|
@ -507,6 +521,9 @@ func (s *DropletsServiceOp) Backups(ctx context.Context, dropletID int, opt *Lis
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Backups, resp, err
|
||||
}
|
||||
|
@ -536,6 +553,9 @@ func (s *DropletsServiceOp) Snapshots(ctx context.Context, dropletID int, opt *L
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Snapshots, resp, err
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ func (fw Firewall) String() string {
|
|||
return Stringify(fw)
|
||||
}
|
||||
|
||||
// URN returns the firewall name in a valid DO API URN form.
|
||||
func (fw Firewall) URN() string {
|
||||
return ToURN("Firewall", fw.ID)
|
||||
}
|
||||
|
@ -237,6 +238,7 @@ type firewallRoot struct {
|
|||
type firewallsRoot struct {
|
||||
Firewalls []Firewall `json:"firewalls"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
func (fw *FirewallsServiceOp) createAndDoReq(ctx context.Context, method, path string, v interface{}) (*Response, error) {
|
||||
|
@ -262,6 +264,9 @@ func (fw *FirewallsServiceOp) listHelper(ctx context.Context, path string) ([]Fi
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Firewalls, resp, err
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ func (f FloatingIP) String() string {
|
|||
return Stringify(f)
|
||||
}
|
||||
|
||||
// URN returns the floating IP in a valid DO API URN form.
|
||||
func (f FloatingIP) URN() string {
|
||||
return ToURN("FloatingIP", f.IP)
|
||||
}
|
||||
|
@ -44,6 +45,7 @@ func (f FloatingIP) URN() string {
|
|||
type floatingIPsRoot struct {
|
||||
FloatingIPs []FloatingIP `json:"floating_ips"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type floatingIPRoot struct {
|
||||
|
@ -80,6 +82,9 @@ func (f *FloatingIPsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Fl
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.FloatingIPs, resp, err
|
||||
}
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
module github.com/digitalocean/godo
|
||||
|
||||
go 1.12
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.3.5 // indirect
|
||||
github.com/google/go-querystring v1.0.0
|
||||
github.com/stretchr/testify v1.3.0
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
google.golang.org/appengine v1.6.5 // indirect
|
||||
)
|
||||
|
||||
replace github.com/stretchr/objx => github.com/stretchr/objx v0.2.0
|
||||
|
||||
replace golang.org/x/crypto => golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a
|
||||
|
|
|
@ -1,19 +1,43 @@
|
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
@ -11,13 +11,15 @@ import (
|
|||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
libraryVersion = "1.19.0"
|
||||
libraryVersion = "1.54.0"
|
||||
defaultBaseURL = "https://api.digitalocean.com/"
|
||||
userAgent = "godo/" + libraryVersion
|
||||
mediaType = "application/json"
|
||||
|
@ -39,18 +41,23 @@ type Client struct {
|
|||
UserAgent string
|
||||
|
||||
// Rate contains the current rate limit for the client as determined by the most recent
|
||||
// API call.
|
||||
// API call. It is not thread-safe. Please consider using GetRate() instead.
|
||||
Rate Rate
|
||||
ratemtx sync.Mutex
|
||||
|
||||
// Services used for communicating with the API
|
||||
Account AccountService
|
||||
Actions ActionsService
|
||||
Apps AppsService
|
||||
Balance BalanceService
|
||||
BillingHistory BillingHistoryService
|
||||
CDNs CDNService
|
||||
Domains DomainsService
|
||||
Droplets DropletsService
|
||||
DropletActions DropletActionsService
|
||||
Images ImagesService
|
||||
ImageActions ImageActionsService
|
||||
Invoices InvoicesService
|
||||
Keys KeysService
|
||||
Regions RegionsService
|
||||
Sizes SizesService
|
||||
|
@ -65,8 +72,10 @@ type Client struct {
|
|||
Firewalls FirewallsService
|
||||
Projects ProjectsService
|
||||
Kubernetes KubernetesService
|
||||
Registry RegistryService
|
||||
Databases DatabasesService
|
||||
VPCs VPCsService
|
||||
OneClick OneClickService
|
||||
|
||||
// Optional function called after every successful request made to the DO APIs
|
||||
onRequestCompleted RequestCompletionCallback
|
||||
|
@ -93,6 +102,9 @@ type Response struct {
|
|||
// request body and not the header.
|
||||
Links *Links
|
||||
|
||||
// Meta describes generic information about the response.
|
||||
Meta *Meta
|
||||
|
||||
// Monitoring URI
|
||||
Monitor string
|
||||
|
||||
|
@ -150,7 +162,20 @@ func addOptions(s string, opt interface{}) (string, error) {
|
|||
return origURL.String(), nil
|
||||
}
|
||||
|
||||
// NewClient returns a new DigitalOcean API client.
|
||||
// NewFromToken returns a new DigitalOcean API client with the given API
|
||||
// token.
|
||||
func NewFromToken(token string) *Client {
|
||||
ctx := context.Background()
|
||||
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
|
||||
return NewClient(oauth2.NewClient(ctx, ts))
|
||||
}
|
||||
|
||||
// NewClient returns a new DigitalOcean API client, using the given
|
||||
// http.Client to perform all requests.
|
||||
//
|
||||
// Users who wish to pass their own http.Client should use this method. If
|
||||
// you're in need of further customization, the godo.New method allows more
|
||||
// options, such as setting a custom URL or a custom user agent string.
|
||||
func NewClient(httpClient *http.Client) *Client {
|
||||
if httpClient == nil {
|
||||
httpClient = http.DefaultClient
|
||||
|
@ -161,6 +186,9 @@ func NewClient(httpClient *http.Client) *Client {
|
|||
c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent}
|
||||
c.Account = &AccountServiceOp{client: c}
|
||||
c.Actions = &ActionsServiceOp{client: c}
|
||||
c.Apps = &AppsServiceOp{client: c}
|
||||
c.Balance = &BalanceServiceOp{client: c}
|
||||
c.BillingHistory = &BillingHistoryServiceOp{client: c}
|
||||
c.CDNs = &CDNServiceOp{client: c}
|
||||
c.Certificates = &CertificatesServiceOp{client: c}
|
||||
c.Domains = &DomainsServiceOp{client: c}
|
||||
|
@ -171,6 +199,7 @@ func NewClient(httpClient *http.Client) *Client {
|
|||
c.FloatingIPActions = &FloatingIPActionsServiceOp{client: c}
|
||||
c.Images = &ImagesServiceOp{client: c}
|
||||
c.ImageActions = &ImageActionsServiceOp{client: c}
|
||||
c.Invoices = &InvoicesServiceOp{client: c}
|
||||
c.Keys = &KeysServiceOp{client: c}
|
||||
c.LoadBalancers = &LoadBalancersServiceOp{client: c}
|
||||
c.Projects = &ProjectsServiceOp{client: c}
|
||||
|
@ -181,8 +210,10 @@ func NewClient(httpClient *http.Client) *Client {
|
|||
c.StorageActions = &StorageActionsServiceOp{client: c}
|
||||
c.Tags = &TagsServiceOp{client: c}
|
||||
c.Kubernetes = &KubernetesServiceOp{client: c}
|
||||
c.Registry = &RegistryServiceOp{client: c}
|
||||
c.Databases = &DatabasesServiceOp{client: c}
|
||||
c.VPCs = &VPCsServiceOp{client: c}
|
||||
c.OneClick = &OneClickServiceOp{client: c}
|
||||
|
||||
return c
|
||||
}
|
||||
|
@ -190,7 +221,7 @@ func NewClient(httpClient *http.Client) *Client {
|
|||
// ClientOpt are options for New.
|
||||
type ClientOpt func(*Client) error
|
||||
|
||||
// New returns a new DIgitalOcean API client instance.
|
||||
// New returns a new DigitalOcean API client instance.
|
||||
func New(httpClient *http.Client, opts ...ClientOpt) (*Client, error) {
|
||||
c := NewClient(httpClient)
|
||||
for _, opt := range opts {
|
||||
|
@ -227,13 +258,11 @@ func SetUserAgent(ua string) ClientOpt {
|
|||
// BaseURL of the Client. Relative URLS should always be specified without a preceding slash. If specified, the
|
||||
// value pointed to by body is JSON encoded and included in as the request body.
|
||||
func (c *Client) NewRequest(ctx context.Context, method, urlStr string, body interface{}) (*http.Request, error) {
|
||||
rel, err := url.Parse(urlStr)
|
||||
u, err := c.BaseURL.Parse(urlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u := c.BaseURL.ResolveReference(rel)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if body != nil {
|
||||
err = json.NewEncoder(buf).Encode(body)
|
||||
|
@ -258,6 +287,14 @@ func (c *Client) OnRequestCompleted(rc RequestCompletionCallback) {
|
|||
c.onRequestCompleted = rc
|
||||
}
|
||||
|
||||
// GetRate returns the current rate limit for the client as determined by the most recent
|
||||
// API call. It is thread-safe.
|
||||
func (c *Client) GetRate() Rate {
|
||||
c.ratemtx.Lock()
|
||||
defer c.ratemtx.Unlock()
|
||||
return c.Rate
|
||||
}
|
||||
|
||||
// newResponse creates a new Response for the provided http.Response
|
||||
func newResponse(r *http.Response) *Response {
|
||||
response := Response{Response: r}
|
||||
|
@ -294,13 +331,26 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
|
|||
}
|
||||
|
||||
defer func() {
|
||||
// Ensure the response body is fully read and closed
|
||||
// before we reconnect, so that we reuse the same TCPconnection.
|
||||
// Close the previous response's body. But read at least some of
|
||||
// the body so if it's small the underlying TCP connection will be
|
||||
// re-used. No need to check for errors: if it fails, the Transport
|
||||
// won't reuse it anyway.
|
||||
const maxBodySlurpSize = 2 << 10
|
||||
if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
|
||||
io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize)
|
||||
}
|
||||
|
||||
if rerr := resp.Body.Close(); err == nil {
|
||||
err = rerr
|
||||
}
|
||||
}()
|
||||
|
||||
response := newResponse(resp)
|
||||
c.ratemtx.Lock()
|
||||
c.Rate = response.Rate
|
||||
c.ratemtx.Unlock()
|
||||
|
||||
err = CheckResponse(resp)
|
||||
if err != nil {
|
||||
|
|
|
@ -52,7 +52,9 @@ type Image struct {
|
|||
|
||||
// ImageUpdateRequest represents a request to update an image.
|
||||
type ImageUpdateRequest struct {
|
||||
Name string `json:"name"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Distribution string `json:"distribution,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// CustomImageCreateRequest represents a request to create a custom image.
|
||||
|
@ -72,6 +74,7 @@ type imageRoot struct {
|
|||
type imagesRoot struct {
|
||||
Images []Image
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type listImageOptions struct {
|
||||
|
@ -131,6 +134,7 @@ func (s *ImagesServiceOp) GetBySlug(ctx context.Context, slug string) (*Image, *
|
|||
return s.get(ctx, interface{}(slug))
|
||||
}
|
||||
|
||||
// Create a new image
|
||||
func (s *ImagesServiceOp) Create(ctx context.Context, createRequest *CustomImageCreateRequest) (*Image, *Response, error) {
|
||||
if createRequest == nil {
|
||||
return nil, nil, NewArgError("createRequest", "cannot be nil")
|
||||
|
@ -236,6 +240,9 @@ func (s *ImagesServiceOp) list(ctx context.Context, opt *ListOptions, listOpt *l
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Images, resp, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
package godo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const invoicesBasePath = "v2/customers/my/invoices"
|
||||
|
||||
// InvoicesService is an interface for interfacing with the Invoice
|
||||
// endpoints of the DigitalOcean API
|
||||
// See: https://developers.digitalocean.com/documentation/v2/#invoices
|
||||
type InvoicesService interface {
|
||||
Get(context.Context, string, *ListOptions) (*Invoice, *Response, error)
|
||||
GetPDF(context.Context, string) ([]byte, *Response, error)
|
||||
GetCSV(context.Context, string) ([]byte, *Response, error)
|
||||
List(context.Context, *ListOptions) (*InvoiceList, *Response, error)
|
||||
GetSummary(context.Context, string) (*InvoiceSummary, *Response, error)
|
||||
}
|
||||
|
||||
// InvoicesServiceOp handles communication with the Invoice related methods of
|
||||
// the DigitalOcean API.
|
||||
type InvoicesServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
var _ InvoicesService = &InvoicesServiceOp{}
|
||||
|
||||
// Invoice represents a DigitalOcean Invoice
|
||||
type Invoice struct {
|
||||
InvoiceItems []InvoiceItem `json:"invoice_items"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// InvoiceItem represents a line-item on a DigitalOcean Invoice
|
||||
type InvoiceItem struct {
|
||||
Product string `json:"product"`
|
||||
ResourceID string `json:"resource_id"`
|
||||
ResourceUUID string `json:"resource_uuid"`
|
||||
GroupDescription string `json:"group_description"`
|
||||
Description string `json:"description"`
|
||||
Amount string `json:"amount"`
|
||||
Duration string `json:"duration"`
|
||||
DurationUnit string `json:"duration_unit"`
|
||||
StartTime time.Time `json:"start_time"`
|
||||
EndTime time.Time `json:"end_time"`
|
||||
ProjectName string `json:"project_name"`
|
||||
Category string `json:"category"`
|
||||
}
|
||||
|
||||
// InvoiceList contains a paginated list of all of a customer's invoices.
|
||||
// The InvoicePreview is the month-to-date usage generated by DigitalOcean.
|
||||
type InvoiceList struct {
|
||||
Invoices []InvoiceListItem `json:"invoices"`
|
||||
InvoicePreview InvoiceListItem `json:"invoice_preview"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// InvoiceListItem contains a small list of information about a customer's invoice.
|
||||
// More information can be found in the Invoice or InvoiceSummary
|
||||
type InvoiceListItem struct {
|
||||
InvoiceUUID string `json:"invoice_uuid"`
|
||||
Amount string `json:"amount"`
|
||||
InvoicePeriod string `json:"invoice_period"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// InvoiceSummary contains metadata and summarized usage for an invoice generated by DigitalOcean
|
||||
type InvoiceSummary struct {
|
||||
InvoiceUUID string `json:"invoice_uuid"`
|
||||
BillingPeriod string `json:"billing_period"`
|
||||
Amount string `json:"amount"`
|
||||
UserName string `json:"user_name"`
|
||||
UserBillingAddress Address `json:"user_billing_address"`
|
||||
UserCompany string `json:"user_company"`
|
||||
UserEmail string `json:"user_email"`
|
||||
ProductCharges InvoiceSummaryBreakdown `json:"product_charges"`
|
||||
Overages InvoiceSummaryBreakdown `json:"overages"`
|
||||
Taxes InvoiceSummaryBreakdown `json:"taxes"`
|
||||
CreditsAndAdjustments InvoiceSummaryBreakdown `json:"credits_and_adjustments"`
|
||||
}
|
||||
|
||||
// Address represents the billing address of a customer
|
||||
type Address struct {
|
||||
AddressLine1 string `json:"address_line1"`
|
||||
AddressLine2 string `json:"address_line2"`
|
||||
City string `json:"city"`
|
||||
Region string `json:"region"`
|
||||
PostalCode string `json:"postal_code"`
|
||||
CountryISO2Code string `json:"country_iso2_code"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// InvoiceSummaryBreakdown is a grouped set of InvoiceItems from an invoice
|
||||
type InvoiceSummaryBreakdown struct {
|
||||
Name string `json:"name"`
|
||||
Amount string `json:"amount"`
|
||||
Items []InvoiceSummaryBreakdownItem `json:"items"`
|
||||
}
|
||||
|
||||
// InvoiceSummaryBreakdownItem further breaks down the InvoiceSummary by product
|
||||
type InvoiceSummaryBreakdownItem struct {
|
||||
Name string `json:"name"`
|
||||
Amount string `json:"amount"`
|
||||
Count string `json:"count"`
|
||||
}
|
||||
|
||||
func (i Invoice) String() string {
|
||||
return Stringify(i)
|
||||
}
|
||||
|
||||
// Get detailed invoice items for an Invoice
|
||||
func (s *InvoicesServiceOp) Get(ctx context.Context, invoiceUUID string, opt *ListOptions) (*Invoice, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", invoicesBasePath, invoiceUUID)
|
||||
path, err := addOptions(path, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(Invoice)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root, resp, err
|
||||
}
|
||||
|
||||
// List invoices for a customer
|
||||
func (s *InvoicesServiceOp) List(ctx context.Context, opt *ListOptions) (*InvoiceList, *Response, error) {
|
||||
path := invoicesBasePath
|
||||
path, err := addOptions(path, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(InvoiceList)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root, resp, err
|
||||
}
|
||||
|
||||
// GetSummary returns a summary of metadata and summarized usage for an Invoice
|
||||
func (s *InvoicesServiceOp) GetSummary(ctx context.Context, invoiceUUID string) (*InvoiceSummary, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/summary", invoicesBasePath, invoiceUUID)
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(InvoiceSummary)
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root, resp, err
|
||||
}
|
||||
|
||||
// GetPDF returns the pdf for an Invoice
|
||||
func (s *InvoicesServiceOp) GetPDF(ctx context.Context, invoiceUUID string) ([]byte, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/pdf", invoicesBasePath, invoiceUUID)
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var root bytes.Buffer
|
||||
resp, err := s.client.Do(ctx, req, &root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.Bytes(), resp, err
|
||||
}
|
||||
|
||||
// GetCSV returns the csv for an Invoice
|
||||
func (s *InvoicesServiceOp) GetCSV(ctx context.Context, invoiceUUID string) ([]byte, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/csv", invoicesBasePath, invoiceUUID)
|
||||
|
||||
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var root bytes.Buffer
|
||||
resp, err := s.client.Do(ctx, req, &root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.Bytes(), resp, err
|
||||
}
|
|
@ -46,6 +46,7 @@ type KeyUpdateRequest struct {
|
|||
type keysRoot struct {
|
||||
SSHKeys []Key `json:"ssh_keys"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type keyRoot struct {
|
||||
|
@ -83,6 +84,9 @@ func (s *KeysServiceOp) List(ctx context.Context, opt *ListOptions) ([]Key, *Res
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.SSHKeys, resp, err
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
@ -24,8 +25,11 @@ const (
|
|||
type KubernetesService interface {
|
||||
Create(context.Context, *KubernetesClusterCreateRequest) (*KubernetesCluster, *Response, error)
|
||||
Get(context.Context, string) (*KubernetesCluster, *Response, error)
|
||||
GetUser(context.Context, string) (*KubernetesClusterUser, *Response, error)
|
||||
GetUpgrades(context.Context, string) ([]*KubernetesVersion, *Response, error)
|
||||
GetKubeConfig(context.Context, string) (*KubernetesClusterConfig, *Response, error)
|
||||
GetKubeConfigWithExpiry(context.Context, string, int64) (*KubernetesClusterConfig, *Response, error)
|
||||
GetCredentials(context.Context, string, *KubernetesClusterCredentialsGetRequest) (*KubernetesClusterCredentials, *Response, error)
|
||||
List(context.Context, *ListOptions) ([]*KubernetesCluster, *Response, error)
|
||||
Update(context.Context, string, *KubernetesClusterUpdateRequest) (*KubernetesCluster, *Response, error)
|
||||
Upgrade(context.Context, string, *KubernetesClusterUpgradeRequest) (*Response, error)
|
||||
|
@ -42,6 +46,11 @@ type KubernetesService interface {
|
|||
DeleteNode(ctx context.Context, clusterID, poolID, nodeID string, req *KubernetesNodeDeleteRequest) (*Response, error)
|
||||
|
||||
GetOptions(context.Context) (*KubernetesOptions, *Response, error)
|
||||
AddRegistry(ctx context.Context, req *KubernetesClusterRegistryRequest) (*Response, error)
|
||||
RemoveRegistry(ctx context.Context, req *KubernetesClusterRegistryRequest) (*Response, error)
|
||||
|
||||
RunClusterlint(ctx context.Context, clusterID string, req *KubernetesRunClusterlintRequest) (string, *Response, error)
|
||||
GetClusterlintResults(ctx context.Context, clusterID string, req *KubernetesGetClusterlintRequest) ([]*ClusterlintDiagnostic, *Response, error)
|
||||
}
|
||||
|
||||
var _ KubernetesService = &KubernetesServiceOp{}
|
||||
|
@ -63,14 +72,16 @@ type KubernetesClusterCreateRequest struct {
|
|||
|
||||
MaintenancePolicy *KubernetesMaintenancePolicy `json:"maintenance_policy"`
|
||||
AutoUpgrade bool `json:"auto_upgrade"`
|
||||
SurgeUpgrade bool `json:"surge_upgrade"`
|
||||
}
|
||||
|
||||
// KubernetesClusterUpdateRequest represents a request to update a Kubernetes cluster.
|
||||
type KubernetesClusterUpdateRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
MaintenancePolicy *KubernetesMaintenancePolicy `json:"maintenance_policy"`
|
||||
AutoUpgrade bool `json:"auto_upgrade"`
|
||||
MaintenancePolicy *KubernetesMaintenancePolicy `json:"maintenance_policy,omitempty"`
|
||||
AutoUpgrade *bool `json:"auto_upgrade,omitempty"`
|
||||
SurgeUpgrade bool `json:"surge_upgrade,omitempty"`
|
||||
}
|
||||
|
||||
// KubernetesClusterUpgradeRequest represents a request to upgrade a Kubernetes cluster.
|
||||
|
@ -78,6 +89,21 @@ type KubernetesClusterUpgradeRequest struct {
|
|||
VersionSlug string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// Taint represents a Kubernetes taint that can be associated with a node pool
|
||||
// (and, transitively, with all nodes of that pool).
|
||||
type Taint struct {
|
||||
Key string
|
||||
Value string
|
||||
Effect string
|
||||
}
|
||||
|
||||
func (t Taint) String() string {
|
||||
if t.Value == "" {
|
||||
return fmt.Sprintf("%s:%s", t.Key, t.Effect)
|
||||
}
|
||||
return fmt.Sprintf("%s=%s:%s", t.Key, t.Value, t.Effect)
|
||||
}
|
||||
|
||||
// KubernetesNodePoolCreateRequest represents a request to create a node pool for a
|
||||
// Kubernetes cluster.
|
||||
type KubernetesNodePoolCreateRequest struct {
|
||||
|
@ -85,14 +111,24 @@ type KubernetesNodePoolCreateRequest struct {
|
|||
Size string `json:"size,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
Taints []Taint `json:"taints,omitempty"`
|
||||
AutoScale bool `json:"auto_scale,omitempty"`
|
||||
MinNodes int `json:"min_nodes,omitempty"`
|
||||
MaxNodes int `json:"max_nodes,omitempty"`
|
||||
}
|
||||
|
||||
// KubernetesNodePoolUpdateRequest represents a request to update a node pool in a
|
||||
// Kubernetes cluster.
|
||||
type KubernetesNodePoolUpdateRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
Count *int `json:"count,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
Taints *[]Taint `json:"taints,omitempty"`
|
||||
AutoScale *bool `json:"auto_scale,omitempty"`
|
||||
MinNodes *int `json:"min_nodes,omitempty"`
|
||||
MaxNodes *int `json:"max_nodes,omitempty"`
|
||||
}
|
||||
|
||||
// KubernetesNodePoolRecycleNodesRequest is DEPRECATED please use DeleteNode
|
||||
|
@ -110,6 +146,27 @@ type KubernetesNodeDeleteRequest struct {
|
|||
SkipDrain bool `json:"skip_drain,omitempty"`
|
||||
}
|
||||
|
||||
// KubernetesClusterCredentialsGetRequest is a request to get cluster credentials.
|
||||
type KubernetesClusterCredentialsGetRequest struct {
|
||||
ExpirySeconds *int `json:"expiry_seconds,omitempty"`
|
||||
}
|
||||
|
||||
// KubernetesClusterRegistryRequest represents clusters to integrate with docr registry
|
||||
type KubernetesClusterRegistryRequest struct {
|
||||
ClusterUUIDs []string `json:"cluster_uuids,omitempty"`
|
||||
}
|
||||
|
||||
type KubernetesRunClusterlintRequest struct {
|
||||
IncludeGroups []string `json:"include_groups"`
|
||||
ExcludeGroups []string `json:"exclude_groups"`
|
||||
IncludeChecks []string `json:"include_checks"`
|
||||
ExcludeChecks []string `json:"exclude_checks"`
|
||||
}
|
||||
|
||||
type KubernetesGetClusterlintRequest struct {
|
||||
RunId string `json:"run_id"`
|
||||
}
|
||||
|
||||
// KubernetesCluster represents a Kubernetes cluster.
|
||||
type KubernetesCluster struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
|
@ -127,12 +184,30 @@ type KubernetesCluster struct {
|
|||
|
||||
MaintenancePolicy *KubernetesMaintenancePolicy `json:"maintenance_policy,omitempty"`
|
||||
AutoUpgrade bool `json:"auto_upgrade,omitempty"`
|
||||
SurgeUpgrade bool `json:"surge_upgrade,omitempty"`
|
||||
RegistryEnabled bool `json:"registry_enabled,omitempty"`
|
||||
|
||||
Status *KubernetesClusterStatus `json:"status,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
// KubernetesClusterUser represents a Kubernetes cluster user.
|
||||
type KubernetesClusterUser struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
}
|
||||
|
||||
// KubernetesClusterCredentials represents Kubernetes cluster credentials.
|
||||
type KubernetesClusterCredentials struct {
|
||||
Server string `json:"server"`
|
||||
CertificateAuthorityData []byte `json:"certificate_authority_data"`
|
||||
ClientCertificateData []byte `json:"client_certificate_data"`
|
||||
ClientKeyData []byte `json:"client_key_data"`
|
||||
Token string `json:"token"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}
|
||||
|
||||
// KubernetesMaintenancePolicy is a configuration to set the maintenance window
|
||||
// of a cluster
|
||||
type KubernetesMaintenancePolicy struct {
|
||||
|
@ -146,13 +221,36 @@ type KubernetesMaintenancePolicy struct {
|
|||
type KubernetesMaintenancePolicyDay int
|
||||
|
||||
const (
|
||||
// KubernetesMaintenanceDayAny sets the KubernetesMaintenancePolicyDay to any
|
||||
// day of the week
|
||||
KubernetesMaintenanceDayAny KubernetesMaintenancePolicyDay = iota
|
||||
|
||||
// KubernetesMaintenanceDayMonday sets the KubernetesMaintenancePolicyDay to
|
||||
// Monday
|
||||
KubernetesMaintenanceDayMonday
|
||||
|
||||
// KubernetesMaintenanceDayTuesday sets the KubernetesMaintenancePolicyDay to
|
||||
// Tuesday
|
||||
KubernetesMaintenanceDayTuesday
|
||||
|
||||
// KubernetesMaintenanceDayWednesday sets the KubernetesMaintenancePolicyDay to
|
||||
// Wednesday
|
||||
KubernetesMaintenanceDayWednesday
|
||||
|
||||
// KubernetesMaintenanceDayThursday sets the KubernetesMaintenancePolicyDay to
|
||||
// Thursday
|
||||
KubernetesMaintenanceDayThursday
|
||||
|
||||
// KubernetesMaintenanceDayFriday sets the KubernetesMaintenancePolicyDay to
|
||||
// Friday
|
||||
KubernetesMaintenanceDayFriday
|
||||
|
||||
// KubernetesMaintenanceDaySaturday sets the KubernetesMaintenancePolicyDay to
|
||||
// Saturday
|
||||
KubernetesMaintenanceDaySaturday
|
||||
|
||||
// KubernetesMaintenanceDaySunday sets the KubernetesMaintenancePolicyDay to
|
||||
// Sunday
|
||||
KubernetesMaintenanceDaySunday
|
||||
)
|
||||
|
||||
|
@ -198,6 +296,7 @@ func (k KubernetesMaintenancePolicyDay) String() string {
|
|||
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses the JSON string into KubernetesMaintenancePolicyDay
|
||||
func (k *KubernetesMaintenancePolicyDay) UnmarshalJSON(data []byte) error {
|
||||
var val string
|
||||
if err := json.Unmarshal(data, &val); err != nil {
|
||||
|
@ -212,6 +311,7 @@ func (k *KubernetesMaintenancePolicyDay) UnmarshalJSON(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON string for KubernetesMaintenancePolicyDay
|
||||
func (k KubernetesMaintenancePolicyDay) MarshalJSON() ([]byte, error) {
|
||||
if KubernetesMaintenanceDayAny <= k && k <= KubernetesMaintenanceDaySunday {
|
||||
return json.Marshal(days[k])
|
||||
|
@ -272,6 +372,11 @@ type KubernetesNodePool struct {
|
|||
Size string `json:"size,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
Taints []Taint `json:"taints,omitempty"`
|
||||
AutoScale bool `json:"auto_scale,omitempty"`
|
||||
MinNodes int `json:"min_nodes,omitempty"`
|
||||
MaxNodes int `json:"max_nodes,omitempty"`
|
||||
|
||||
Nodes []*KubernetesNode `json:"nodes,omitempty"`
|
||||
}
|
||||
|
@ -281,6 +386,7 @@ type KubernetesNode struct {
|
|||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Status *KubernetesNodeStatus `json:"status,omitempty"`
|
||||
DropletID string `json:"droplet_id,omitempty"`
|
||||
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
|
@ -317,15 +423,42 @@ type KubernetesRegion struct {
|
|||
Slug string `json:"slug"`
|
||||
}
|
||||
|
||||
// ClusterlintDiagnostic is a diagnostic returned from clusterlint.
|
||||
type ClusterlintDiagnostic struct {
|
||||
CheckName string `json:"check_name"`
|
||||
Severity string `json:"severity"`
|
||||
Message string `json:"message"`
|
||||
Object *ClusterlintObject `json:"object"`
|
||||
}
|
||||
|
||||
// ClusterlintObject is the object a clusterlint diagnostic refers to.
|
||||
type ClusterlintObject struct {
|
||||
Kind string `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Owners []*ClusterlintOwner `json:"owners,omitempty"`
|
||||
}
|
||||
|
||||
// ClusterlintOwner indicates the resource that owns the offending object.
|
||||
type ClusterlintOwner struct {
|
||||
Kind string `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type kubernetesClustersRoot struct {
|
||||
Clusters []*KubernetesCluster `json:"kubernetes_clusters,omitempty"`
|
||||
Links *Links `json:"links,omitempty"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type kubernetesClusterRoot struct {
|
||||
Cluster *KubernetesCluster `json:"kubernetes_cluster,omitempty"`
|
||||
}
|
||||
|
||||
type kubernetesClusterUserRoot struct {
|
||||
User *KubernetesClusterUser `json:"kubernetes_cluster_user,omitempty"`
|
||||
}
|
||||
|
||||
type kubernetesNodePoolRoot struct {
|
||||
NodePool *KubernetesNodePool `json:"node_pool,omitempty"`
|
||||
}
|
||||
|
@ -354,6 +487,21 @@ func (svc *KubernetesServiceOp) Get(ctx context.Context, clusterID string) (*Kub
|
|||
return root.Cluster, resp, nil
|
||||
}
|
||||
|
||||
// GetUser retrieves the details of a Kubernetes cluster user.
|
||||
func (svc *KubernetesServiceOp) GetUser(ctx context.Context, clusterID string) (*KubernetesClusterUser, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/user", kubernetesClustersPath, clusterID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(kubernetesClusterUserRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.User, resp, nil
|
||||
}
|
||||
|
||||
// GetUpgrades retrieves versions a Kubernetes cluster can be upgraded to. An
|
||||
// upgrade can be requested using `Upgrade`.
|
||||
func (svc *KubernetesServiceOp) GetUpgrades(ctx context.Context, clusterID string) ([]*KubernetesVersion, *Response, error) {
|
||||
|
@ -416,6 +564,14 @@ func (svc *KubernetesServiceOp) List(ctx context.Context, opts *ListOptions) ([]
|
|||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Clusters, resp, nil
|
||||
}
|
||||
|
||||
|
@ -444,6 +600,47 @@ func (svc *KubernetesServiceOp) GetKubeConfig(ctx context.Context, clusterID str
|
|||
return res, resp, nil
|
||||
}
|
||||
|
||||
// GetKubeConfigWithExpiry returns a Kubernetes config file for the specified cluster with expiry_seconds.
|
||||
func (svc *KubernetesServiceOp) GetKubeConfigWithExpiry(ctx context.Context, clusterID string, expirySeconds int64) (*KubernetesClusterConfig, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/kubeconfig", kubernetesClustersPath, clusterID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
q := req.URL.Query()
|
||||
q.Add("expiry_seconds", fmt.Sprintf("%d", expirySeconds))
|
||||
req.URL.RawQuery = q.Encode()
|
||||
configBytes := bytes.NewBuffer(nil)
|
||||
resp, err := svc.client.Do(ctx, req, configBytes)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
res := &KubernetesClusterConfig{
|
||||
KubeconfigYAML: configBytes.Bytes(),
|
||||
}
|
||||
return res, resp, nil
|
||||
}
|
||||
|
||||
// GetCredentials returns a Kubernetes API server credentials for the specified cluster.
|
||||
func (svc *KubernetesServiceOp) GetCredentials(ctx context.Context, clusterID string, get *KubernetesClusterCredentialsGetRequest) (*KubernetesClusterCredentials, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/credentials", kubernetesClustersPath, clusterID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
q := req.URL.Query()
|
||||
if get.ExpirySeconds != nil {
|
||||
q.Add("expiry_seconds", strconv.Itoa(*get.ExpirySeconds))
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
credentials := new(KubernetesClusterCredentials)
|
||||
resp, err := svc.client.Do(ctx, req, credentials)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return credentials, resp, nil
|
||||
}
|
||||
|
||||
// Update updates a Kubernetes cluster's properties.
|
||||
func (svc *KubernetesServiceOp) Update(ctx context.Context, clusterID string, update *KubernetesClusterUpdateRequest) (*KubernetesCluster, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", kubernetesClustersPath, clusterID)
|
||||
|
@ -610,3 +807,79 @@ func (svc *KubernetesServiceOp) GetOptions(ctx context.Context) (*KubernetesOpti
|
|||
}
|
||||
return root.Options, resp, nil
|
||||
}
|
||||
|
||||
// AddRegistry integrates docr registry with all the specified clusters
|
||||
func (svc *KubernetesServiceOp) AddRegistry(ctx context.Context, req *KubernetesClusterRegistryRequest) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/registry", kubernetesBasePath)
|
||||
request, err := svc.client.NewRequest(ctx, http.MethodPost, path, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, request, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// RemoveRegistry removes docr registry support for all the specified clusters
|
||||
func (svc *KubernetesServiceOp) RemoveRegistry(ctx context.Context, req *KubernetesClusterRegistryRequest) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/registry", kubernetesBasePath)
|
||||
request, err := svc.client.NewRequest(ctx, http.MethodDelete, path, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, request, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
type runClusterlintRoot struct {
|
||||
RunID string `json:"run_id"`
|
||||
}
|
||||
|
||||
// RunClusterlint schedules a clusterlint run for the specified cluster
|
||||
func (svc *KubernetesServiceOp) RunClusterlint(ctx context.Context, clusterID string, req *KubernetesRunClusterlintRequest) (string, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/clusterlint", kubernetesClustersPath, clusterID)
|
||||
request, err := svc.client.NewRequest(ctx, http.MethodPost, path, req)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
root := new(runClusterlintRoot)
|
||||
resp, err := svc.client.Do(ctx, request, root)
|
||||
if err != nil {
|
||||
return "", resp, err
|
||||
}
|
||||
return root.RunID, resp, nil
|
||||
}
|
||||
|
||||
type clusterlintDiagnosticsRoot struct {
|
||||
Diagnostics []*ClusterlintDiagnostic
|
||||
}
|
||||
|
||||
// GetClusterlintResults fetches the diagnostics after clusterlint run completes
|
||||
func (svc *KubernetesServiceOp) GetClusterlintResults(ctx context.Context, clusterID string, req *KubernetesGetClusterlintRequest) ([]*ClusterlintDiagnostic, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/clusterlint", kubernetesClustersPath, clusterID)
|
||||
if req != nil {
|
||||
v := make(url.Values)
|
||||
if req.RunId != "" {
|
||||
v.Set("run_id", req.RunId)
|
||||
}
|
||||
if query := v.Encode(); query != "" {
|
||||
path = path + "?" + query
|
||||
}
|
||||
}
|
||||
|
||||
request, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(clusterlintDiagnosticsRoot)
|
||||
resp, err := svc.client.Do(ctx, request, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Diagnostics, resp, nil
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ func (l *Links) IsLastPage() bool {
|
|||
}
|
||||
|
||||
func (p *Pages) isLast() bool {
|
||||
return p.Last == ""
|
||||
return p.Next == ""
|
||||
}
|
||||
|
||||
func pageForURL(urlText string) (int, error) {
|
||||
|
|
|
@ -31,6 +31,7 @@ type LoadBalancer struct {
|
|||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
SizeSlug string `json:"size,omitempty"`
|
||||
Algorithm string `json:"algorithm,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Created string `json:"created_at,omitempty"`
|
||||
|
@ -43,6 +44,7 @@ type LoadBalancer struct {
|
|||
Tags []string `json:"tags,omitempty"`
|
||||
RedirectHttpToHttps bool `json:"redirect_http_to_https,omitempty"`
|
||||
EnableProxyProtocol bool `json:"enable_proxy_protocol,omitempty"`
|
||||
EnableBackendKeepalive bool `json:"enable_backend_keepalive,omitempty"`
|
||||
VPCUUID string `json:"vpc_uuid,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -51,6 +53,7 @@ func (l LoadBalancer) String() string {
|
|||
return Stringify(l)
|
||||
}
|
||||
|
||||
// URN returns the load balancer ID in a valid DO API URN form.
|
||||
func (l LoadBalancer) URN() string {
|
||||
return ToURN("LoadBalancer", l.ID)
|
||||
}
|
||||
|
@ -61,11 +64,13 @@ func (l LoadBalancer) AsRequest() *LoadBalancerRequest {
|
|||
r := LoadBalancerRequest{
|
||||
Name: l.Name,
|
||||
Algorithm: l.Algorithm,
|
||||
SizeSlug: l.SizeSlug,
|
||||
ForwardingRules: append([]ForwardingRule(nil), l.ForwardingRules...),
|
||||
DropletIDs: append([]int(nil), l.DropletIDs...),
|
||||
Tag: l.Tag,
|
||||
RedirectHttpToHttps: l.RedirectHttpToHttps,
|
||||
EnableProxyProtocol: l.EnableProxyProtocol,
|
||||
EnableBackendKeepalive: l.EnableBackendKeepalive,
|
||||
HealthCheck: l.HealthCheck,
|
||||
VPCUUID: l.VPCUUID,
|
||||
}
|
||||
|
@ -132,6 +137,7 @@ type LoadBalancerRequest struct {
|
|||
Name string `json:"name,omitempty"`
|
||||
Algorithm string `json:"algorithm,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
SizeSlug string `json:"size,omitempty"`
|
||||
ForwardingRules []ForwardingRule `json:"forwarding_rules,omitempty"`
|
||||
HealthCheck *HealthCheck `json:"health_check,omitempty"`
|
||||
StickySessions *StickySessions `json:"sticky_sessions,omitempty"`
|
||||
|
@ -140,6 +146,7 @@ type LoadBalancerRequest struct {
|
|||
Tags []string `json:"tags,omitempty"`
|
||||
RedirectHttpToHttps bool `json:"redirect_http_to_https,omitempty"`
|
||||
EnableProxyProtocol bool `json:"enable_proxy_protocol,omitempty"`
|
||||
EnableBackendKeepalive bool `json:"enable_backend_keepalive,omitempty"`
|
||||
VPCUUID string `json:"vpc_uuid,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -167,6 +174,7 @@ func (l dropletIDsRequest) String() string {
|
|||
type loadBalancersRoot struct {
|
||||
LoadBalancers []LoadBalancer `json:"load_balancers"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type loadBalancerRoot struct {
|
||||
|
@ -218,6 +226,9 @@ func (l *LoadBalancersServiceOp) List(ctx context.Context, opt *ListOptions) ([]
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.LoadBalancers, resp, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package godo
|
||||
|
||||
// Meta describes generic information about a response.
|
||||
type Meta struct {
|
||||
Total int `json:"total"`
|
||||
}
|
|
@ -117,7 +117,7 @@ type ProjectResource struct {
|
|||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// ProjetResourceLinks specify the link for more information about the resource.
|
||||
// ProjectResourceLinks specify the link for more information about the resource.
|
||||
type ProjectResourceLinks struct {
|
||||
Self string `json:"self"`
|
||||
}
|
||||
|
@ -125,6 +125,7 @@ type ProjectResourceLinks struct {
|
|||
type projectsRoot struct {
|
||||
Projects []Project `json:"projects"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type projectRoot struct {
|
||||
|
@ -134,6 +135,7 @@ type projectRoot struct {
|
|||
type projectResourcesRoot struct {
|
||||
Resources []ProjectResource `json:"resources"`
|
||||
Links *Links `json:"links,omitempty"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
var _ ProjectsService = &ProjectsServiceOp{}
|
||||
|
@ -158,6 +160,9 @@ func (p *ProjectsServiceOp) List(ctx context.Context, opts *ListOptions) ([]Proj
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Projects, resp, err
|
||||
}
|
||||
|
@ -238,13 +243,15 @@ func (p *ProjectsServiceOp) ListResources(ctx context.Context, projectID string,
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Resources, resp, err
|
||||
}
|
||||
|
||||
// AssignResources assigns one or more resources to a project. AssignResources
|
||||
// accepts resources in two possible formats:
|
||||
|
||||
// 1. The resource type, like `&Droplet{ID: 1}` or `&FloatingIP{IP: "1.2.3.4"}`
|
||||
// 2. A valid DO URN as a string, like "do:droplet:1234"
|
||||
//
|
||||
|
|
|
@ -32,6 +32,7 @@ type Region struct {
|
|||
type regionsRoot struct {
|
||||
Regions []Region
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
func (r Region) String() string {
|
||||
|
@ -59,6 +60,9 @@ func (s *RegionsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Region
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Regions, resp, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,497 @@
|
|||
package godo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
registryPath = "/v2/registry"
|
||||
// RegistryServer is the hostname of the DigitalOcean registry service
|
||||
RegistryServer = "registry.digitalocean.com"
|
||||
)
|
||||
|
||||
// RegistryService is an interface for interfacing with the Registry endpoints
|
||||
// of the DigitalOcean API.
|
||||
// See: https://developers.digitalocean.com/documentation/v2#registry
|
||||
type RegistryService interface {
|
||||
Create(context.Context, *RegistryCreateRequest) (*Registry, *Response, error)
|
||||
Get(context.Context) (*Registry, *Response, error)
|
||||
Delete(context.Context) (*Response, error)
|
||||
DockerCredentials(context.Context, *RegistryDockerCredentialsRequest) (*DockerCredentials, *Response, error)
|
||||
ListRepositories(context.Context, string, *ListOptions) ([]*Repository, *Response, error)
|
||||
ListRepositoryTags(context.Context, string, string, *ListOptions) ([]*RepositoryTag, *Response, error)
|
||||
DeleteTag(context.Context, string, string, string) (*Response, error)
|
||||
DeleteManifest(context.Context, string, string, string) (*Response, error)
|
||||
StartGarbageCollection(context.Context, string, ...*StartGarbageCollectionRequest) (*GarbageCollection, *Response, error)
|
||||
GetGarbageCollection(context.Context, string) (*GarbageCollection, *Response, error)
|
||||
ListGarbageCollections(context.Context, string, *ListOptions) ([]*GarbageCollection, *Response, error)
|
||||
UpdateGarbageCollection(context.Context, string, string, *UpdateGarbageCollectionRequest) (*GarbageCollection, *Response, error)
|
||||
GetOptions(context.Context) (*RegistryOptions, *Response, error)
|
||||
GetSubscription(context.Context) (*RegistrySubscription, *Response, error)
|
||||
UpdateSubscription(context.Context, *RegistrySubscriptionUpdateRequest) (*RegistrySubscription, *Response, error)
|
||||
}
|
||||
|
||||
var _ RegistryService = &RegistryServiceOp{}
|
||||
|
||||
// RegistryServiceOp handles communication with Registry methods of the DigitalOcean API.
|
||||
type RegistryServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// RegistryCreateRequest represents a request to create a registry.
|
||||
type RegistryCreateRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
SubscriptionTierSlug string `json:"subscription_tier_slug,omitempty"`
|
||||
}
|
||||
|
||||
// RegistryDockerCredentialsRequest represents a request to retrieve docker
|
||||
// credentials for a registry.
|
||||
type RegistryDockerCredentialsRequest struct {
|
||||
ReadWrite bool `json:"read_write"`
|
||||
ExpirySeconds *int `json:"expiry_seconds,omitempty"`
|
||||
}
|
||||
|
||||
// Registry represents a registry.
|
||||
type Registry struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
}
|
||||
|
||||
// Repository represents a repository
|
||||
type Repository struct {
|
||||
RegistryName string `json:"registry_name,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
LatestTag *RepositoryTag `json:"latest_tag,omitempty"`
|
||||
TagCount uint64 `json:"tag_count,omitempty"`
|
||||
}
|
||||
|
||||
// RepositoryTag represents a repository tag
|
||||
type RepositoryTag struct {
|
||||
RegistryName string `json:"registry_name,omitempty"`
|
||||
Repository string `json:"repository,omitempty"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
ManifestDigest string `json:"manifest_digest,omitempty"`
|
||||
CompressedSizeBytes uint64 `json:"compressed_size_bytes,omitempty"`
|
||||
SizeBytes uint64 `json:"size_bytes,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
type registryRoot struct {
|
||||
Registry *Registry `json:"registry,omitempty"`
|
||||
}
|
||||
|
||||
type repositoriesRoot struct {
|
||||
Repositories []*Repository `json:"repositories,omitempty"`
|
||||
Links *Links `json:"links,omitempty"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type repositoryTagsRoot struct {
|
||||
Tags []*RepositoryTag `json:"tags,omitempty"`
|
||||
Links *Links `json:"links,omitempty"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// GarbageCollection represents a garbage collection.
|
||||
type GarbageCollection struct {
|
||||
UUID string `json:"uuid"`
|
||||
RegistryName string `json:"registry_name"`
|
||||
Status string `json:"status"`
|
||||
Type GarbageCollectionType `json:"type"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
BlobsDeleted uint64 `json:"blobs_deleted"`
|
||||
FreedBytes uint64 `json:"freed_bytes"`
|
||||
}
|
||||
|
||||
type garbageCollectionRoot struct {
|
||||
GarbageCollection *GarbageCollection `json:"garbage_collection,omitempty"`
|
||||
}
|
||||
|
||||
type garbageCollectionsRoot struct {
|
||||
GarbageCollections []*GarbageCollection `json:"garbage_collections,omitempty"`
|
||||
Links *Links `json:"links,omitempty"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type GarbageCollectionType string
|
||||
|
||||
const (
|
||||
// GCTypeUntaggedManifestsOnly indicates that a garbage collection should
|
||||
// only delete untagged manifests.
|
||||
GCTypeUntaggedManifestsOnly = GarbageCollectionType("untagged manifests only")
|
||||
// GCTypeUnreferencedBlobsOnly indicates that a garbage collection should
|
||||
// only delete unreferenced blobs.
|
||||
GCTypeUnreferencedBlobsOnly = GarbageCollectionType("unreferenced blobs only")
|
||||
// GCTypeUntaggedManifestsAndUnreferencedBlobs indicates that a garbage
|
||||
// collection should delete both untagged manifests and unreferenced blobs.
|
||||
GCTypeUntaggedManifestsAndUnreferencedBlobs = GarbageCollectionType("untagged manifests and unreferenced blobs")
|
||||
)
|
||||
|
||||
// StartGarbageCollectionRequest represents options to a garbage collection
|
||||
// start request.
|
||||
type StartGarbageCollectionRequest struct {
|
||||
Type GarbageCollectionType `json:"type"`
|
||||
}
|
||||
|
||||
// UpdateGarbageCollectionRequest represents a request to update a garbage
|
||||
// collection.
|
||||
type UpdateGarbageCollectionRequest struct {
|
||||
Cancel bool `json:"cancel"`
|
||||
}
|
||||
|
||||
// RegistryOptions are options for users when creating or updating a registry.
|
||||
type RegistryOptions struct {
|
||||
SubscriptionTiers []*RegistrySubscriptionTier `json:"subscription_tiers,omitempty"`
|
||||
}
|
||||
|
||||
type registryOptionsRoot struct {
|
||||
Options *RegistryOptions `json:"options"`
|
||||
}
|
||||
|
||||
// RegistrySubscriptionTier is a subscription tier for container registry.
|
||||
type RegistrySubscriptionTier struct {
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"`
|
||||
IncludedRepositories uint64 `json:"included_repositories"`
|
||||
IncludedStorageBytes uint64 `json:"included_storage_bytes"`
|
||||
AllowStorageOverage bool `json:"allow_storage_overage"`
|
||||
IncludedBandwidthBytes uint64 `json:"included_bandwidth_bytes"`
|
||||
MonthlyPriceInCents uint64 `json:"monthly_price_in_cents"`
|
||||
Eligible bool `json:"eligible,omitempty"`
|
||||
// EligibilityReaons is included when Eligible is false, and indicates the
|
||||
// reasons why this tier is not availble to the user.
|
||||
EligibilityReasons []string `json:"eligibility_reasons,omitempty"`
|
||||
}
|
||||
|
||||
// RegistrySubscription is a user's subscription.
|
||||
type RegistrySubscription struct {
|
||||
Tier *RegistrySubscriptionTier `json:"tier"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type registrySubscriptionRoot struct {
|
||||
Subscription *RegistrySubscription `json:"subscription"`
|
||||
}
|
||||
|
||||
// RegistrySubscriptionUpdateRequest represents a request to update the
|
||||
// subscription plan for a registry.
|
||||
type RegistrySubscriptionUpdateRequest struct {
|
||||
TierSlug string `json:"tier_slug"`
|
||||
}
|
||||
|
||||
// Get retrieves the details of a Registry.
|
||||
func (svc *RegistryServiceOp) Get(ctx context.Context) (*Registry, *Response, error) {
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, registryPath, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(registryRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Registry, resp, nil
|
||||
}
|
||||
|
||||
// Create creates a registry.
|
||||
func (svc *RegistryServiceOp) Create(ctx context.Context, create *RegistryCreateRequest) (*Registry, *Response, error) {
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, registryPath, create)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(registryRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Registry, resp, nil
|
||||
}
|
||||
|
||||
// Delete deletes a registry. There is no way to recover a registry once it has
|
||||
// been destroyed.
|
||||
func (svc *RegistryServiceOp) Delete(ctx context.Context) (*Response, error) {
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, registryPath, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// DockerCredentials is the content of a Docker config file
|
||||
// that is used by the docker CLI
|
||||
// See: https://docs.docker.com/engine/reference/commandline/cli/#configjson-properties
|
||||
type DockerCredentials struct {
|
||||
DockerConfigJSON []byte
|
||||
}
|
||||
|
||||
// DockerCredentials retrieves a Docker config file containing the registry's credentials.
|
||||
func (svc *RegistryServiceOp) DockerCredentials(ctx context.Context, request *RegistryDockerCredentialsRequest) (*DockerCredentials, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", registryPath, "docker-credentials")
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
q := req.URL.Query()
|
||||
q.Add("read_write", strconv.FormatBool(request.ReadWrite))
|
||||
if request.ExpirySeconds != nil {
|
||||
q.Add("expiry_seconds", strconv.Itoa(*request.ExpirySeconds))
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
var buf bytes.Buffer
|
||||
resp, err := svc.client.Do(ctx, req, &buf)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
dc := &DockerCredentials{
|
||||
DockerConfigJSON: buf.Bytes(),
|
||||
}
|
||||
return dc, resp, nil
|
||||
}
|
||||
|
||||
// ListRepositories returns a list of the Repositories visible with the registry's credentials.
|
||||
func (svc *RegistryServiceOp) ListRepositories(ctx context.Context, registry string, opts *ListOptions) ([]*Repository, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/repositories", registryPath, registry)
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(repositoriesRoot)
|
||||
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Repositories, resp, nil
|
||||
}
|
||||
|
||||
// ListRepositoryTags returns a list of the RepositoryTags available within the given repository.
|
||||
func (svc *RegistryServiceOp) ListRepositoryTags(ctx context.Context, registry, repository string, opts *ListOptions) ([]*RepositoryTag, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/repositories/%s/tags", registryPath, registry, url.PathEscape(repository))
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(repositoryTagsRoot)
|
||||
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Tags, resp, nil
|
||||
}
|
||||
|
||||
// DeleteTag deletes a tag within a given repository.
|
||||
func (svc *RegistryServiceOp) DeleteTag(ctx context.Context, registry, repository, tag string) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/repositories/%s/tags/%s", registryPath, registry, url.PathEscape(repository), tag)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// DeleteManifest deletes a manifest by its digest within a given repository.
|
||||
func (svc *RegistryServiceOp) DeleteManifest(ctx context.Context, registry, repository, digest string) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/repositories/%s/digests/%s", registryPath, registry, url.PathEscape(repository), digest)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// StartGarbageCollection requests a garbage collection for the specified
|
||||
// registry.
|
||||
func (svc *RegistryServiceOp) StartGarbageCollection(ctx context.Context, registry string, request ...*StartGarbageCollectionRequest) (*GarbageCollection, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/garbage-collection", registryPath, registry)
|
||||
var requestParams interface{}
|
||||
if len(request) < 1 {
|
||||
// default to only garbage collecting unreferenced blobs for backwards
|
||||
// compatibility
|
||||
requestParams = &StartGarbageCollectionRequest{
|
||||
Type: GCTypeUnreferencedBlobsOnly,
|
||||
}
|
||||
} else {
|
||||
requestParams = request[0]
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, requestParams)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(garbageCollectionRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.GarbageCollection, resp, err
|
||||
}
|
||||
|
||||
// GetGarbageCollection retrieves the currently-active garbage collection for
|
||||
// the specified registry; if there are no active garbage collections, then
|
||||
// return a 404/NotFound error. There can only be one active garbage
|
||||
// collection on a registry.
|
||||
func (svc *RegistryServiceOp) GetGarbageCollection(ctx context.Context, registry string) (*GarbageCollection, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/garbage-collection", registryPath, registry)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(garbageCollectionRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.GarbageCollection, resp, nil
|
||||
}
|
||||
|
||||
// ListGarbageCollections retrieves all garbage collections (active and
|
||||
// inactive) for the specified registry.
|
||||
func (svc *RegistryServiceOp) ListGarbageCollections(ctx context.Context, registry string, opts *ListOptions) ([]*GarbageCollection, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/garbage-collections", registryPath, registry)
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(garbageCollectionsRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
if root.Links != nil {
|
||||
resp.Links = root.Links
|
||||
}
|
||||
if root.Meta != nil {
|
||||
resp.Meta = root.Meta
|
||||
}
|
||||
|
||||
return root.GarbageCollections, resp, nil
|
||||
}
|
||||
|
||||
// UpdateGarbageCollection updates the specified garbage collection for the
|
||||
// specified registry. While only the currently-active garbage collection can
|
||||
// be updated we still require the exact garbage collection to be specified to
|
||||
// avoid race conditions that might may arise from issuing an update to the
|
||||
// implicit "currently-active" garbage collection. Returns the updated garbage
|
||||
// collection.
|
||||
func (svc *RegistryServiceOp) UpdateGarbageCollection(ctx context.Context, registry, gcUUID string, request *UpdateGarbageCollectionRequest) (*GarbageCollection, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s/garbage-collection/%s", registryPath, registry, gcUUID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPut, path, request)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(garbageCollectionRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.GarbageCollection, resp, nil
|
||||
}
|
||||
|
||||
// GetOptions returns options the user can use when creating or updating a
|
||||
// registry.
|
||||
func (svc *RegistryServiceOp) GetOptions(ctx context.Context) (*RegistryOptions, *Response, error) {
|
||||
path := fmt.Sprintf("%s/options", registryPath)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(registryOptionsRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.Options, resp, nil
|
||||
}
|
||||
|
||||
// GetSubscription retrieves the user's subscription.
|
||||
func (svc *RegistryServiceOp) GetSubscription(ctx context.Context) (*RegistrySubscription, *Response, error) {
|
||||
path := fmt.Sprintf("%s/subscription", registryPath)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(registrySubscriptionRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Subscription, resp, nil
|
||||
}
|
||||
|
||||
// UpdateSubscription updates the user's registry subscription.
|
||||
func (svc *RegistryServiceOp) UpdateSubscription(ctx context.Context, request *RegistrySubscriptionUpdateRequest) (*RegistrySubscription, *Response, error) {
|
||||
path := fmt.Sprintf("%s/subscription", registryPath)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, request)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(registrySubscriptionRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Subscription, resp, nil
|
||||
}
|
|
@ -40,6 +40,7 @@ func (s Size) String() string {
|
|||
type sizesRoot struct {
|
||||
Sizes []Size
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// List all images
|
||||
|
@ -63,6 +64,9 @@ func (s *SizesServiceOp) List(ctx context.Context, opt *ListOptions) ([]Size, *R
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Sizes, resp, err
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ type snapshotRoot struct {
|
|||
type snapshotsRoot struct {
|
||||
Snapshots []Snapshot `json:"snapshots"`
|
||||
Links *Links `json:"links,omitempty"`
|
||||
Meta *Meta `json:"meta,omitempty"`
|
||||
}
|
||||
|
||||
type listSnapshotOptions struct {
|
||||
|
|
|
@ -15,7 +15,7 @@ const (
|
|||
|
||||
// StorageService is an interface for interfacing with the storage
|
||||
// endpoints of the Digital Ocean API.
|
||||
// See: https://developers.digitalocean.com/documentation/v2#storage
|
||||
// See: https://developers.digitalocean.com/documentation/v2/#block-storage
|
||||
type StorageService interface {
|
||||
ListVolumes(context.Context, *ListVolumeParams) ([]Volume, *Response, error)
|
||||
GetVolume(context.Context, string) (*Volume, *Response, error)
|
||||
|
@ -60,6 +60,7 @@ func (f Volume) String() string {
|
|||
return Stringify(f)
|
||||
}
|
||||
|
||||
// URN returns the volume ID as a valid DO API URN
|
||||
func (f Volume) URN() string {
|
||||
return ToURN("Volume", f.ID)
|
||||
}
|
||||
|
@ -67,6 +68,7 @@ func (f Volume) URN() string {
|
|||
type storageVolumesRoot struct {
|
||||
Volumes []Volume `json:"volumes"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type storageVolumeRoot struct {
|
||||
|
@ -122,6 +124,9 @@ func (svc *StorageServiceOp) ListVolumes(ctx context.Context, params *ListVolume
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Volumes, resp, nil
|
||||
}
|
||||
|
@ -203,6 +208,9 @@ func (svc *StorageServiceOp) ListSnapshots(ctx context.Context, volumeID string,
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Snapshots, resp, nil
|
||||
}
|
||||
|
|
|
@ -120,6 +120,9 @@ func (s *StorageActionsServiceOp) list(ctx context.Context, path string) ([]Acti
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Actions, resp, err
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
|
||||
var timestampType = reflect.TypeOf(Timestamp{})
|
||||
|
||||
// ResourceWithURN is an interface for interfacing with the types
|
||||
// that implement the URN method.
|
||||
type ResourceWithURN interface {
|
||||
URN() string
|
||||
}
|
||||
|
|
|
@ -42,7 +42,9 @@ const (
|
|||
// LoadBalancerResourceType holds the string representing our ResourceType of LoadBalancer.
|
||||
LoadBalancerResourceType ResourceType = "load_balancer"
|
||||
// VolumeSnapshotResourceType holds the string representing our ResourceType for storage Snapshots.
|
||||
VolumeSnapshotResourceType ResourceType = "volumesnapshot"
|
||||
VolumeSnapshotResourceType ResourceType = "volume_snapshot"
|
||||
// DatabaseResourceType holds the string representing our ResourceType of Database.
|
||||
DatabaseResourceType ResourceType = "database"
|
||||
)
|
||||
|
||||
// Resource represent a single resource for associating/disassociating with tags
|
||||
|
@ -58,6 +60,8 @@ type TaggedResources struct {
|
|||
Droplets *TaggedDropletsResources `json:"droplets,omitempty"`
|
||||
Images *TaggedImagesResources `json:"images"`
|
||||
Volumes *TaggedVolumesResources `json:"volumes"`
|
||||
VolumeSnapshots *TaggedVolumeSnapshotsResources `json:"volume_snapshots"`
|
||||
Databases *TaggedDatabasesResources `json:"databases"`
|
||||
}
|
||||
|
||||
// TaggedDropletsResources represent the droplet resources a tag is attached to
|
||||
|
@ -79,6 +83,12 @@ type TaggedImagesResources TaggedResourcesData
|
|||
// TaggedVolumesResources represent the volume resources a tag is attached to
|
||||
type TaggedVolumesResources TaggedResourcesData
|
||||
|
||||
// TaggedVolumeSnapshotsResources represent the volume snapshot resources a tag is attached to
|
||||
type TaggedVolumeSnapshotsResources TaggedResourcesData
|
||||
|
||||
// TaggedDatabasesResources represent the database resources a tag is attached to
|
||||
type TaggedDatabasesResources TaggedResourcesData
|
||||
|
||||
// Tag represent DigitalOcean tag
|
||||
type Tag struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
|
@ -103,6 +113,7 @@ type UntagResourcesRequest struct {
|
|||
type tagsRoot struct {
|
||||
Tags []Tag `json:"tags"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type tagRoot struct {
|
||||
|
@ -131,6 +142,9 @@ func (s *TagsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Tag, *Res
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.Tags, resp, err
|
||||
}
|
||||
|
|
|
@ -31,11 +31,15 @@ type VPCsServiceOp struct {
|
|||
type VPCCreateRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
RegionSlug string `json:"region,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
IPRange string `json:"ip_range,omitempty"`
|
||||
}
|
||||
|
||||
// VPCUpdateRequest represents a request to update a Virtual Private Cloud.
|
||||
type VPCUpdateRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Default *bool `json:"default,omitempty"`
|
||||
}
|
||||
|
||||
// VPCSetField allows one to set individual fields within a VPC configuration.
|
||||
|
@ -47,10 +51,27 @@ type VPCSetField interface {
|
|||
// Ex.: VPCs.Set(..., VPCSetName("new-name"))
|
||||
type VPCSetName string
|
||||
|
||||
// VPCSetDescription is used when one want to set the `description` field of a VPC.
|
||||
// Ex.: VPCs.Set(..., VPCSetDescription("vpc description"))
|
||||
type VPCSetDescription string
|
||||
|
||||
// VPCSetDefault is used when one wants to enable the `default` field of a VPC, to
|
||||
// set a VPC as the default one in the region
|
||||
// Ex.: VPCs.Set(..., VPCSetDefault())
|
||||
func VPCSetDefault() VPCSetField {
|
||||
return &vpcSetDefault{}
|
||||
}
|
||||
|
||||
// vpcSetDefault satisfies the VPCSetField interface
|
||||
type vpcSetDefault struct{}
|
||||
|
||||
// VPC represents a DigitalOcean Virtual Private Cloud configuration.
|
||||
type VPC struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
URN string `json:"urn"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
IPRange string `json:"ip_range,omitempty"`
|
||||
RegionSlug string `json:"region,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
Default bool `json:"default,omitempty"`
|
||||
|
@ -63,6 +84,7 @@ type vpcRoot struct {
|
|||
type vpcsRoot struct {
|
||||
VPCs []*VPC `json:"vpcs"`
|
||||
Links *Links `json:"links"`
|
||||
Meta *Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// Get returns the details of a Virtual Private Cloud.
|
||||
|
@ -118,6 +140,9 @@ func (v *VPCsServiceOp) List(ctx context.Context, opt *ListOptions) ([]*VPC, *Re
|
|||
if l := root.Links; l != nil {
|
||||
resp.Links = l
|
||||
}
|
||||
if m := root.Meta; m != nil {
|
||||
resp.Meta = m
|
||||
}
|
||||
|
||||
return root.VPCs, resp, nil
|
||||
}
|
||||
|
@ -143,6 +168,14 @@ func (n VPCSetName) vpcSetField(in map[string]interface{}) {
|
|||
in["name"] = n
|
||||
}
|
||||
|
||||
func (n VPCSetDescription) vpcSetField(in map[string]interface{}) {
|
||||
in["description"] = n
|
||||
}
|
||||
|
||||
func (*vpcSetDefault) vpcSetField(in map[string]interface{}) {
|
||||
in["default"] = true
|
||||
}
|
||||
|
||||
// Set updates specific properties of a Virtual Private Cloud.
|
||||
func (v *VPCsServiceOp) Set(ctx context.Context, id string, fields ...VPCSetField) (*VPC, *Response, error) {
|
||||
path := vpcsBasePath + "/" + id
|
||||
|
|
|
@ -200,7 +200,7 @@ github.com/denverdino/aliyungo/oss
|
|||
github.com/denverdino/aliyungo/ram
|
||||
github.com/denverdino/aliyungo/slb
|
||||
github.com/denverdino/aliyungo/util
|
||||
# github.com/digitalocean/godo v1.19.0
|
||||
# github.com/digitalocean/godo v1.54.0
|
||||
## explicit
|
||||
github.com/digitalocean/godo
|
||||
# github.com/docker/distribution v2.7.1+incompatible
|
||||
|
|
Loading…
Reference in New Issue