-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
resource_token.go
186 lines (156 loc) · 4.77 KB
/
resource_token.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package main
import (
"fmt"
"log"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/pactflow/terraform/broker"
"github.com/pactflow/terraform/client"
)
const (
readOnlyTokenType = "read-only"
readWriteTokenType = "read-write"
)
var allowedTokenTypes = map[string]string{
readOnlyTokenType: "Read only token (developer)",
readWriteTokenType: "Read/write token (CI)",
}
var tokenType = &schema.Schema{
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Resource{},
}
// Used to convert from TF configuration to a broker.APIToken
type apiTokenDefinition struct {
UUID string
Name string
Type string
Description string
Value string
}
func token() *schema.Resource {
return &schema.Resource{
DeprecationMessage: "This resource is deprecated and will soon be removed",
Create: tokenCreate,
Update: tokenUpdate,
Read: tokenRead,
Delete: tokenDelete,
Importer: &schema.ResourceImporter{State: schema.ImportStatePassthrough},
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "A short name for the token. Changing the name will generate a _new_ token each time, removing the existing token",
},
"type": {
Type: schema.TypeString,
Required: true,
Description: "The type of token to generate (valid values are 'read-only' and 'read-write'",
ValidateFunc: validateTokenType,
},
"description": {
Type: schema.TypeString,
Computed: true,
Description: "The description of the token as defined by the broker",
},
"value": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
Description: "The actual API token",
},
"uuid": {
Type: schema.TypeString,
Computed: true,
Description: "The UUID of API token",
},
},
}
}
func validateTokenType(val interface{}, key string) (warns []string, errs []error) {
v := val.(string)
if _, ok := allowedTokenTypes[v]; !ok {
errs = append(errs, fmt.Errorf("%q must be one of the allowed types %v, got %v", key, allowedTokenTypes, v))
}
return
}
func parseToken(d *schema.ResourceData, meta interface{}) (apiTokenDefinition, error) {
log.Printf("[DEBUG] create or update token with data %+v \n", d)
name := d.Get("name").(string)
tokenType := d.Get("type").(string)
description := d.Get("description").(string)
value := d.Get("value").(string)
token := apiTokenDefinition{
UUID: d.Id(),
Name: name,
Type: tokenType,
Description: description,
Value: value,
}
log.Printf("[DEBUG] Have a parsed token %+v \n", token)
return token, nil
}
// Basically just does a regenerate
func tokenCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*client.Client)
token, _ := parseToken(d, meta)
// If token UUID is empty, read from remote
if token.UUID == "" {
log.Println("[DEBUG] importing resource as no existing UUID was found")
t, err := client.FindTokenByType(token.Type)
if err != nil {
return err
}
token.UUID = t.UUID
// TF definition specific fields
d.SetId(t.UUID)
d.Set("type", token.Type)
d.Set("name", token.Name)
// Set the (remote state) resource specific fields
return setTokenState(d, *t)
}
return nil
}
// Regenerate
func tokenUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*client.Client)
token, _ := parseToken(d, meta)
log.Println("[DEBUG] updating (regenearting) token", token)
updatedToken, err := client.RegenerateToken(broker.APIToken{UUID: token.UUID})
// At the moment, if you regenerate the access token - you need to use it for new requests!
if token.Type == readWriteTokenType {
if client.Config.AccessToken != "" {
log.Println("[INFO] updating access token as read-write token was re-generated")
client.Config.AccessToken = updatedToken.Value
}
}
if err != nil {
return err
}
// TF definition specific fields
d.Set("type", token.Type)
d.Set("name", token.Name)
return setTokenState(d, updatedToken.APIToken)
}
func tokenRead(d *schema.ResourceData, meta interface{}) error {
httpClient := meta.(*client.Client)
uuid := d.Id()
token, err := httpClient.ReadToken(uuid)
if err != nil {
return err
}
return setTokenState(d, *token)
}
// Uncouples from broker
func tokenDelete(d *schema.ResourceData, meta interface{}) error {
log.Println("[INFO] Deleting API token is currently a no-op, setting id to ''")
d.SetId("")
return nil
}
func setTokenState(d *schema.ResourceData, token broker.APIToken) error {
log.Printf("[DEBUG] setting token state: %+v \n", token)
d.SetId(token.UUID)
d.Set("description", token.Description)
d.Set("uuid", token.UUID)
d.Set("value", token.Value)
return nil
}