-
Notifications
You must be signed in to change notification settings - Fork 9
/
dockitems_resource.go
280 lines (244 loc) · 9.51 KB
/
dockitems_resource.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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
// dockitems_resource.go
package dockitems
import (
"context"
"fmt"
"strconv"
"time"
"github.com/deploymenttheory/go-api-sdk-jamfpro/sdk/jamfpro"
"github.com/deploymenttheory/terraform-provider-jamfpro/internal/client"
"github.com/deploymenttheory/terraform-provider-jamfpro/internal/endpoints/common"
"github.com/deploymenttheory/terraform-provider-jamfpro/internal/endpoints/common/state"
"github.com/deploymenttheory/terraform-provider-jamfpro/internal/waitfor"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
// ResourceJamfProDockItems defines the schema and CRUD operations for managing Jamf Pro Dock Items in Terraform.
func ResourceJamfProDockItems() *schema.Resource {
return &schema.Resource{
CreateContext: ResourceJamfProDockItemsCreate,
ReadContext: ResourceJamfProDockItemsRead,
UpdateContext: ResourceJamfProDockItemsUpdate,
DeleteContext: ResourceJamfProDockItemsDelete,
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(70 * time.Second),
Read: schema.DefaultTimeout(30 * time.Second),
Update: schema.DefaultTimeout(30 * time.Second),
Delete: schema.DefaultTimeout(15 * time.Second),
},
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
Description: "The unique identifier of the dock item.",
},
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the dock item.",
},
"type": {
Type: schema.TypeString,
Required: true,
Description: "The type of the dock item (App/File/Folder).",
ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
v, ok := val.(string)
if !ok {
errs = append(errs, fmt.Errorf("expected a string for %q but got a different type", key))
return
}
validTypes := map[string]bool{
"App": true,
"File": true,
"Folder": true,
}
if !validTypes[v] {
errs = append(errs, fmt.Errorf("%q must be one of 'App', 'File', or 'Folder', got: %s", key, v))
}
return
},
},
"path": {
Type: schema.TypeString,
Required: true,
Description: "The path of the dock item.",
},
"contents": {
Type: schema.TypeString,
Computed: true,
Description: "Contents of the dock item.",
},
},
}
}
// ResourceJamfProDockItemsCreate is responsible for creating a new Jamf Pro Dock Item in the remote system.
// The function:
// 1. Constructs the dock item data using the provided Terraform configuration.
// 2. Calls the API to create the dock item in Jamf Pro.
// 3. Updates the Terraform state with the ID of the newly created dock item.
// 4. Initiates a read operation to synchronize the Terraform state with the actual state in Jamf Pro.
func ResourceJamfProDockItemsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// Assert the meta interface to the expected APIClient type
apiclient, ok := meta.(*client.APIClient)
if !ok {
return diag.Errorf("error asserting meta as *client.APIClient")
}
conn := apiclient.Conn
// Initialize variables
var diags diag.Diagnostics
// Construct the resource object
resource, err := constructJamfProDockItem(d)
if err != nil {
return diag.FromErr(fmt.Errorf("failed to construct Jamf Pro Dock Item: %v", err))
}
// Retry the API call to create the resource in Jamf Pro
var creationResponse *jamfpro.ResourceDockItem
err = retry.RetryContext(ctx, d.Timeout(schema.TimeoutCreate), func() *retry.RetryError {
var apiErr error
creationResponse, apiErr = conn.CreateDockItem(resource)
if apiErr != nil {
return retry.RetryableError(apiErr)
}
// No error, exit the retry loop
return nil
})
if err != nil {
return diag.FromErr(fmt.Errorf("failed to create Jamf Pro Dock Item '%s' after retries: %v", resource.Name, err))
}
// Set the resource ID in Terraform state
d.SetId(strconv.Itoa(creationResponse.ID))
// Wait for the resource to be fully available before reading it
checkResourceExists := func(id interface{}) (interface{}, error) {
intID, err := strconv.Atoi(id.(string))
if err != nil {
return nil, fmt.Errorf("error converting ID '%v' to integer: %v", id, err)
}
return apiclient.Conn.GetDockItemByID(intID)
}
_, waitDiags := waitfor.ResourceIsAvailable(ctx, d, "Jamf Pro Dock Item", strconv.Itoa(creationResponse.ID), checkResourceExists, time.Duration(common.DefaultPropagationTime)*time.Second, apiclient.EnableCookieJar)
if waitDiags.HasError() {
return waitDiags
}
// Read the resource to ensure the Terraform state is up to date
readDiags := ResourceJamfProDockItemsRead(ctx, d, meta)
if len(readDiags) > 0 {
diags = append(diags, readDiags...)
}
return diags
}
// ResourceJamfProDockItemsRead is responsible for reading the current state of a Jamf Pro Dock Item Resource from the remote system.
// The function:
// 1. Fetches the dock item's current state using its ID. If it fails then obtain dock item's current state using its Name.
// 2. Updates the Terraform state with the fetched data to ensure it accurately reflects the current state in Jamf Pro.
// 3. Handles any discrepancies, such as the dock item being deleted outside of Terraform, to keep the Terraform state synchronized.
func ResourceJamfProDockItemsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// Initialize API client
apiclient, ok := meta.(*client.APIClient)
if !ok {
return diag.Errorf("error asserting meta as *client.APIClient")
}
// Initialize variables
resourceID := d.Id()
var diags diag.Diagnostics
resourceIDInt, err := strconv.Atoi(resourceID)
if err != nil {
return diag.FromErr(fmt.Errorf("error converting resource ID '%s' to int: %v", resourceID, err))
}
// Attempt to fetch the resource by ID
resource, err := apiclient.Conn.GetDockItemByID(resourceIDInt)
if err != nil {
// Handle not found error or other errors
return state.HandleResourceNotFoundError(err, d)
}
// Update the Terraform state with the fetched data from the resource
diags = updateTerraformState(d, resource)
// Handle any errors and return diagnostics
if len(diags) > 0 {
return diags
}
return nil
}
// ResourceJamfProDockItemsUpdate is responsible for updating a Jamf Pro dock item.
func ResourceJamfProDockItemsUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// Initialize API client
apiclient, ok := meta.(*client.APIClient)
if !ok {
return diag.Errorf("error asserting meta as *client.APIClient")
}
conn := apiclient.Conn
// Initialize variables
var diags diag.Diagnostics
resourceID := d.Id()
// Convert resourceID from string to int
resourceIDInt, err := strconv.Atoi(resourceID)
if err != nil {
return diag.FromErr(fmt.Errorf("error converting resource ID '%s' to int: %v", resourceID, err))
}
// Construct the resource object
resource, err := constructJamfProDockItem(d)
if err != nil {
return diag.FromErr(fmt.Errorf("failed to construct Jamf Pro Dock Item for update: %v", err))
}
// Update operations with retries
err = retry.RetryContext(ctx, d.Timeout(schema.TimeoutUpdate), func() *retry.RetryError {
_, apiErr := conn.UpdateDockItemByID(resourceIDInt, resource)
if apiErr != nil {
// If updating by ID fails, attempt to update by Name
return retry.RetryableError(apiErr)
}
// Successfully updated the resource, exit the retry loop
return nil
})
if err != nil {
return diag.FromErr(fmt.Errorf("failed to update Jamf Pro Dock Item '%s' (ID: %d) after retries: %v", resource.Name, resourceIDInt, err))
}
// Read the resource to ensure the Terraform state is up to date
readDiags := ResourceJamfProDockItemsRead(ctx, d, meta)
if len(readDiags) > 0 {
diags = append(diags, readDiags...)
}
return diags
}
// ResourceJamfProDiskEncryptionConfigurationsDelete is responsible for deleting a Jamf Pro Disk Encryption Configuration.
func ResourceJamfProDockItemsDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// Initialize API client
apiclient, ok := meta.(*client.APIClient)
if !ok {
return diag.Errorf("error asserting meta as *client.APIClient")
}
conn := apiclient.Conn
// Initialize variables
var diags diag.Diagnostics
resourceID := d.Id()
// Convert resourceID from string to int
resourceIDInt, err := strconv.Atoi(resourceID)
if err != nil {
return diag.FromErr(fmt.Errorf("error converting resource ID '%s' to int: %v", resourceID, err))
}
// Use the retry function for the delete operation with appropriate timeout
err = retry.RetryContext(ctx, d.Timeout(schema.TimeoutDelete), func() *retry.RetryError {
// Attempt to delete by ID
apiErr := conn.DeleteDockItemByID(resourceIDInt)
if apiErr != nil {
// If deleting by ID fails, attempt to delete by Name
resourceName := d.Get("name").(string)
apiErrByName := conn.DeleteDockItemByName(resourceName)
if apiErrByName != nil {
// If deletion by name also fails, return a retryable error
return retry.RetryableError(apiErrByName)
}
}
// Successfully deleted the resource, exit the retry loop
return nil
})
if err != nil {
return diag.FromErr(fmt.Errorf("failed to delete Jamf Pro Dock Item '%s' (ID: %d) after retries: %v", d.Get("name").(string), resourceIDInt, err))
}
// Clear the ID from the Terraform state as the resource has been deleted
d.SetId("")
return diags
}