forked from digitalocean/terraform-provider-digitalocean
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
145 lines (124 loc) · 3.8 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package digitalocean
import (
"context"
"fmt"
"log"
"net/url"
"strings"
"text/template"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/digitalocean/godo"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"golang.org/x/oauth2"
)
type Config struct {
Token string
APIEndpoint string
SpacesAPIEndpoint string
AccessID string
SecretKey string
TerraformVersion string
}
type CombinedConfig struct {
client *godo.Client
spacesEndpointTemplate *template.Template
accessID string
secretKey string
}
func (c *CombinedConfig) godoClient() *godo.Client { return c.client }
func (c *CombinedConfig) spacesClient(region string) (*session.Session, error) {
if c.accessID == "" || c.secretKey == "" {
err := fmt.Errorf("Spaces credentials not configured")
return &session.Session{}, err
}
endpointWriter := strings.Builder{}
err := c.spacesEndpointTemplate.Execute(&endpointWriter, map[string]string{
"Region": strings.ToLower(region),
})
if err != nil {
return &session.Session{}, err
}
endpoint := endpointWriter.String()
client, err := session.NewSession(&aws.Config{
Region: aws.String("us-east-1"),
Credentials: credentials.NewStaticCredentials(c.accessID, c.secretKey, ""),
Endpoint: aws.String(endpoint)},
)
if err != nil {
return &session.Session{}, err
}
return client, nil
}
// Client() returns a new client for accessing digital ocean.
func (c *Config) Client() (*CombinedConfig, error) {
tokenSrc := oauth2.StaticTokenSource(&oauth2.Token{
AccessToken: c.Token,
})
userAgent := fmt.Sprintf("Terraform/%s", c.TerraformVersion)
client := oauth2.NewClient(oauth2.NoContext, tokenSrc)
client.Transport = logging.NewTransport("DigitalOcean", client.Transport)
godoClient, err := godo.New(client, godo.SetUserAgent(userAgent))
if err != nil {
return nil, err
}
apiURL, err := url.Parse(c.APIEndpoint)
if err != nil {
return nil, err
}
godoClient.BaseURL = apiURL
spacesEndpointTemplate, err := template.New("spaces").Parse(c.SpacesAPIEndpoint)
if err != nil {
return nil, fmt.Errorf("unable to parse spaces_endpoint '%s' as template: %s", c.SpacesAPIEndpoint, err)
}
log.Printf("[INFO] DigitalOcean Client configured for URL: %s", godoClient.BaseURL.String())
return &CombinedConfig{
client: godoClient,
spacesEndpointTemplate: spacesEndpointTemplate,
accessID: c.AccessID,
secretKey: c.SecretKey,
}, nil
}
// waitForAction waits for the action to finish using the resource.StateChangeConf.
func waitForAction(client *godo.Client, action *godo.Action) error {
var (
pending = "in-progress"
target = "completed"
refreshfn = func() (result interface{}, state string, err error) {
a, _, err := client.Actions.Get(context.Background(), action.ID)
if err != nil {
return nil, "", err
}
if a.Status == "errored" {
return a, "errored", nil
}
if a.CompletedAt != nil {
return a, target, nil
}
return a, pending, nil
}
)
_, err := (&resource.StateChangeConf{
Pending: []string{pending},
Refresh: refreshfn,
Target: []string{target},
Delay: 10 * time.Second,
Timeout: 60 * time.Minute,
MinTimeout: 3 * time.Second,
// This is a hack around DO API strangeness.
// https://github.com/hashicorp/terraform/issues/481
//
NotFoundChecks: 60,
}).WaitForState()
return err
}
func isDigitalOceanError(err error, code int, message string) bool {
if err, ok := err.(*godo.ErrorResponse); ok {
return err.Response.StatusCode == code &&
strings.Contains(strings.ToLower(err.Message), strings.ToLower(message))
}
return false
}