Skip to content

Commit fa03778

Browse files
authored
fix: resolve API key generation (#52), stack prune handling (#53), and improve import method (#51)
1 parent 3b080ff commit fa03778

File tree

3 files changed

+72
-16
lines changed

3 files changed

+72
-16
lines changed

docs/resources/stack.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ terraform apply
222222
| `repository_url` | string | ✅ yes | Git repository URL |
223223
| `repository_reference_name` | string | ✅ yes | Git reference (default: `refs/heads/main`) |
224224
| `file_path_in_repository` | string | ✅ yes | Path to Compose file (default: `docker-compose.yml`) |
225-
| `tlsskip_verify` | bool | 🚫 optional | Skip TLS verification (default: `false`) |
225+
| `tlsskip_verify` | bool | 🚫 optional | Skip TLS verification |
226226
| `git_repository_authentication` | bool | 🚫 optional | Enable auth for Git repo (default: `false`) |
227227
| `repository_username` | string | 🚫 optional | Git username (if auth is enabled) |
228228
| `repository_password` | string | 🚫 optional | Git password/token (if auth is enabled) |

internal/resource_stack.go

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,27 @@ func resourcePortainerStack() *schema.Resource {
2323
Importer: &schema.ResourceImporter{
2424
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
2525
// "<endpoint_id>-<stack_id>-<deployment_type>"
26-
var endpointID, stackID int
27-
var deploymentType string
28-
_, err := fmt.Sscanf(d.Id(), "%d-%d-%s", &endpointID, &stackID, &deploymentType)
26+
// "<endpoint_id>-<stack_id>-<deployment_type>-<method>"
27+
28+
parts := strings.Split(d.Id(), "-")
29+
if len(parts) < 3 {
30+
return nil, fmt.Errorf("invalid ID format. Use '<endpoint_id>-<stack_id>-<deployment_type>[-<method>]'")
31+
}
32+
33+
endpointID, err := strconv.Atoi(parts[0])
2934
if err != nil {
30-
return nil, fmt.Errorf("invalid ID format. Use '<endpoint_id>-<stack_id>-<deployment_type>'")
35+
return nil, fmt.Errorf("invalid endpoint_id in import ID: %s", parts[0])
36+
}
37+
38+
stackID, err := strconv.Atoi(parts[1])
39+
if err != nil {
40+
return nil, fmt.Errorf("invalid stack_id in import ID: %s", parts[1])
41+
}
42+
43+
deploymentType := parts[2]
44+
45+
if len(parts) > 3 {
46+
d.Set("method", parts[3])
3147
}
3248
d.Set("endpoint_id", endpointID)
3349
d.Set("deployment_type", deploymentType)
@@ -125,7 +141,7 @@ func resourcePortainerStack() *schema.Resource {
125141
},
126142
},
127143
},
128-
"tlsskip_verify": {Type: schema.TypeBool, Optional: true, Default: false, ForceNew: true},
144+
"tlsskip_verify": {Type: schema.TypeBool, Optional: true, Computed: true, ForceNew: true},
129145
"prune": {
130146
Type: schema.TypeBool,
131147
Optional: true,
@@ -334,12 +350,21 @@ func resourcePortainerStackRead(d *schema.ResourceData, meta interface{}) error
334350
EndpointID int `json:"EndpointId"`
335351
SupportRelativePath bool `json:"supportRelativePath"`
336352
AutoUpdate *struct {
337-
Webhook string `json:"webhook"`
353+
Webhook string `json:"webhook"`
354+
ForcePullImage bool `json:"forcePullImage"`
338355
} `json:"AutoUpdate,omitempty"`
339356
Env []struct {
340357
Name string `json:"name"`
341358
Value string `json:"value"`
342359
} `json:"Env"`
360+
361+
Option struct {
362+
Prune bool `json:"prune"`
363+
} `json:"Option"`
364+
365+
GitConfig *struct {
366+
TLSSkipVerify bool `json:"tlsskipVerify"`
367+
} `json:"gitConfig,omitempty"`
343368
}
344369
if err := json.NewDecoder(resp.Body).Decode(&stack); err != nil {
345370
return fmt.Errorf("failed to decode stack response: %w", err)
@@ -392,12 +417,15 @@ func resourcePortainerStackRead(d *schema.ResourceData, meta interface{}) error
392417
}
393418
d.Set("env", tfEnvs)
394419
_ = d.Set("method", method)
395-
_ = d.Set("endpoint_id", client.Endpoint)
420+
_ = d.Set("endpoint_id", stack.EndpointID)
396421
_ = d.Set("stack_webhook", stack.AutoUpdate != nil && stack.AutoUpdate.Webhook != "")
397422
_ = d.Set("support_relative_path", stack.SupportRelativePath)
398-
_ = d.Set("prune", false)
399-
_ = d.Set("pull_image", false)
400-
_ = d.Set("tlsskip_verify", false)
423+
if method == "repository" && stack.GitConfig != nil {
424+
_ = d.Set("tlsskip_verify", stack.GitConfig.TLSSkipVerify)
425+
}
426+
if stack.AutoUpdate != nil {
427+
_ = d.Set("pull_image", stack.AutoUpdate.ForcePullImage)
428+
}
401429

402430
return nil
403431
}

internal/resource_user.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,8 @@ func resourceUser() *schema.Resource {
5757
Default: "terraform-generated-api-key",
5858
},
5959
"api_key_raw": {
60-
Type: schema.TypeString,
61-
Computed: true,
62-
Sensitive: true,
60+
Type: schema.TypeString,
61+
Computed: true,
6362
},
6463
},
6564
}
@@ -161,12 +160,41 @@ func resourceUserCreate(d *schema.ResourceData, meta interface{}) error {
161160
if password == "" {
162161
return fmt.Errorf("password must be set to generate API key")
163162
}
163+
164+
loginPayload := map[string]interface{}{
165+
"Username": username,
166+
"Password": password,
167+
}
168+
loginResp, err := client.DoRequest("POST", "/auth", nil, loginPayload)
169+
if err != nil {
170+
return fmt.Errorf("failed to authenticate as new user: %w", err)
171+
}
172+
defer loginResp.Body.Close()
173+
174+
if loginResp.StatusCode != 200 {
175+
data, _ := io.ReadAll(loginResp.Body)
176+
return fmt.Errorf("failed to authenticate as new user: %s", string(data))
177+
}
178+
179+
var loginResult struct {
180+
JWT string `json:"jwt"`
181+
}
182+
if err := json.NewDecoder(loginResp.Body).Decode(&loginResult); err != nil {
183+
return fmt.Errorf("failed to decode login response: %w", err)
184+
}
185+
186+
userClient := &APIClient{
187+
Endpoint: client.Endpoint,
188+
APIKey: "",
189+
JWTToken: loginResult.JWT,
190+
HTTPClient: client.HTTPClient,
191+
}
192+
164193
apiPayload := map[string]interface{}{
165194
"description": description,
166195
"password": password,
167196
}
168-
169-
apiResp, err := client.DoRequest("POST", fmt.Sprintf("/users/%d/tokens", result.ID), nil, apiPayload)
197+
apiResp, err := userClient.DoRequest("POST", fmt.Sprintf("/users/%d/tokens", result.ID), nil, apiPayload)
170198
if err != nil {
171199
return fmt.Errorf("failed to generate API key: %w", err)
172200
}

0 commit comments

Comments
 (0)