Skip to content

Commit 5834d1e

Browse files
committed
init/updateFlexVMTerraform: 2.4.5
Signed-off-by: FTNT-HQCM <hq-devops-admin@fortinet.com>
1 parent a743f59 commit 5834d1e

34 files changed

Lines changed: 914 additions & 268 deletions

CHANGELOG.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,26 @@
1-
## 2.4.5 (Unreleased)
1+
## 2.4.6 (Unreleased)
2+
3+
4+
## 2.4.5 (June 4, 2026)
5+
6+
IMPROVEMENTS:
7+
8+
* Supported 3 new configuration: `FEXT_HW`, `FDC_CLOUD`, `FMG_CLOUD`.
9+
* Added `FMG_VM` configuration arguments: `service_pkg`, `addons`, and `fortiai_tokens`.
10+
* Added `SIEM_CLOUD` configuration arguments: `region`.
11+
* Added `FORTISASE` configuration arguments: `data_transfer`, `branch_on_ramp_locations_fortinet_cloud`, `branch_on_ramp_locations_public_cloud`, `global_region`, `additional_compute_region_fortinet_cloud`, and `additional_compute_region_public_cloud`.
12+
* Improved provider documentation with clearer getting-started guidance.
13+
* Added provider-level arguments `account_id` and `program_serial_number`.
14+
15+
BUG FIXES:
16+
17+
* Fixed entitlement resources so `end_date` is sent to the API only when the user explicitly configures it. Also fixed stale `end_date` state after changing entitlement status.
18+
19+
DEPRECATIONS:
20+
21+
* Deprecated provider-level `import_options`. Specify `program_serial_number` directly instead.
22+
* Marked deprecated `FORTISASE` configuration arguments `bandwidth`, `additional_compute_region`, and `locations` as read-only.
23+
224

325
## 2.4.4 (December 15, 2025)
426

@@ -140,4 +162,4 @@ FEATURES:
140162
* **New Resource:** `fortiflexvm_vms_create`
141163
* **New Data Source:** `fortiflexvm_vms_list`
142164
* **New Data Source:** `fortiflexvm_vms_points`
143-
* **New Resource:** `fortiflexvm_vms_update`
165+
* **New Resource:** `fortiflexvm_vms_update`

fortiflexvm/client.go

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ import (
44
"log"
55
"strings"
66

7+
"github.com/hashicorp/go-cty/cty"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
79
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
810
fortisdk "github.com/terraform-providers/terraform-provider-fortiflexvm/sdk/sdkcore"
911
)
1012

1113
// FortiClient contains the basic FortiFlex SDK connection information to FortiFlex
1214
// It can be used to as a client of FortiFlex for the plugin
1315
type FortiClient struct {
14-
Client *fortisdk.FortiSDKClient
15-
ImportOptions *schema.Set // Only used in terraform import
16+
Client *fortisdk.FortiSDKClient
17+
AccountID int
18+
ProgramSerialNumber string
19+
ImportOptions *schema.Set // Only used in terraform import
1620
}
1721

1822
// providerConfigure creates a FortiClient Object with the authentication information.
@@ -26,11 +30,57 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
2630
return nil, err
2731
}
2832
return &FortiClient{
29-
Client: client,
30-
ImportOptions: d.Get("import_options").(*schema.Set),
33+
Client: client,
34+
AccountID: d.Get("account_id").(int),
35+
ProgramSerialNumber: d.Get("program_serial_number").(string),
36+
ImportOptions: d.Get("import_options").(*schema.Set),
3137
}, nil
3238
}
3339

40+
func getAccountID(d *schema.ResourceData, m interface{}) (interface{}, bool) {
41+
if value, ok := d.GetOk("account_id"); ok {
42+
return value, true
43+
}
44+
45+
if client, ok := m.(*FortiClient); ok && client.AccountID != 0 {
46+
return client.AccountID, true
47+
}
48+
49+
return nil, false
50+
}
51+
52+
func getProgramSerialNumber(d *schema.ResourceData, m interface{}) (string, bool) {
53+
if value, ok := d.GetOk("program_serial_number"); ok {
54+
return value.(string), true
55+
}
56+
57+
if client, ok := m.(*FortiClient); ok && client.ProgramSerialNumber != "" {
58+
return client.ProgramSerialNumber, true
59+
}
60+
61+
return "", false
62+
}
63+
64+
type rawConfigGetter interface {
65+
GetRawConfigAt(cty.Path) (cty.Value, diag.Diagnostics)
66+
}
67+
68+
func isConfigured(d rawConfigGetter, name string) bool {
69+
rawValue, rawDiags := d.GetRawConfigAt(cty.GetAttrPath(name))
70+
return !rawDiags.HasError() && !rawValue.IsNull() && rawValue.IsWhollyKnown()
71+
}
72+
73+
func getConfiguredString(d *schema.ResourceData, name string) (string, bool) {
74+
if !isConfigured(d, name) {
75+
return "", false
76+
}
77+
value, ok := d.Get(name).(string)
78+
if !ok || value == "" {
79+
return "", false
80+
}
81+
return value, true
82+
}
83+
3484
func importOptionChecking(ImportOptions *schema.Set, para string) string {
3585
v := ImportOptions.List()
3686
if len(v) == 0 {

fortiflexvm/config.go

Lines changed: 102 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import (
1010
)
1111

1212
var PRODUCT_TYPES = []string{"fgt_vm_bundle", "fmg_vm", "fwb_vm", "fgt_vm_lcs", "fc_ems_op", "faz_vm",
13-
"fpc_vm", "fad_vm", "fortisoar_vm", "fortimail_vm", "fgt_hw", "fap_hw", "fsw_hw",
13+
"fpc_vm", "fad_vm", "fortisoar_vm", "fortimail_vm", "fgt_hw", "fap_hw", "fsw_hw", "fext_hw",
1414
"fwbc_private", "fwbc_public", "fc_ems_cloud", "fortisase", "fortiedr", "fortindr_cloud",
15-
"fortirecon", "siem_cloud", "fortinac_vm", "fortiappsec", "fortidlp"}
15+
"fortirecon", "siem_cloud", "fortinac_vm", "fdc_cloud", "fortiappsec", "fortidlp", "fmg_cloud"}
1616

1717
func fortiAPIPatch(t interface{}) bool {
1818
if t == nil {
@@ -58,6 +58,8 @@ func convProductTypeName2Id(p_type string) int {
5858
return 102
5959
case "FSW_HW":
6060
return 103
61+
case "FEXT_HW":
62+
return 104
6163
case "FWBC_PRIVATE":
6264
return 202
6365
case "FWBC_PUBLIC":
@@ -74,10 +76,14 @@ func convProductTypeName2Id(p_type string) int {
7476
return 208
7577
case "SIEM_CLOUD":
7678
return 209
79+
case "FDC_CLOUD":
80+
return 210
7781
case "FORTIAPPSEC":
7882
return 211
7983
case "FORTIDLP":
8084
return 212
85+
case "FMG_CLOUD":
86+
return 213
8187
default:
8288
return 0
8389
}
@@ -113,6 +119,8 @@ func convProductTypeId2Name(p_id int) string {
113119
return "FAP_HW"
114120
case 103:
115121
return "FSW_HW"
122+
case 104:
123+
return "FEXT_HW"
116124
case 202:
117125
return "FWBC_PRIVATE"
118126
case 203:
@@ -129,10 +137,14 @@ func convProductTypeId2Name(p_id int) string {
129137
return "FORTIRECON"
130138
case 209:
131139
return "SIEM_CLOUD"
140+
case 210:
141+
return "FDC_CLOUD"
132142
case 211:
133143
return "FORTIAPPSEC"
134144
case 212:
135145
return "FORTIDLP"
146+
case 213:
147+
return "FMG_CLOUD"
136148
default:
137149
return ""
138150
}
@@ -228,7 +240,7 @@ func convConfParsId2NameList(p_id int) (string, string, string) {
228240
return "fortisase", "users", "int"
229241
case 49:
230242
return "fortisase", "service_pkg", "string"
231-
case 50:
243+
case 50: // deprecated
232244
return "fortisase", "bandwidth", "int"
233245
case 51:
234246
return "fortisase", "dedicated_ips", "int"
@@ -246,7 +258,7 @@ func convConfParsId2NameList(p_id int) (string, string, string) {
246258
return "fap_hw", "addons", "list"
247259
case 58:
248260
return "faz_vm", "addons", "list"
249-
case 59:
261+
case 59: // deprecated
250262
return "fortisase", "additional_compute_region", "int"
251263
case 60:
252264
return "fortindr_cloud", "metered_usage", "int" // Read only
@@ -272,7 +284,7 @@ func convConfParsId2NameList(p_id int) (string, string, string) {
272284
return "fortisoar_vm", "additional_users_license", "int"
273285
case 71:
274286
return "fortisoar_vm", "addons", "list"
275-
case 72:
287+
case 72: // deprecated
276288
return "fortisase", "locations", "int"
277289
case 73:
278290
return "fortimail_vm", "cpu_size", "string"
@@ -308,6 +320,38 @@ func convConfParsId2NameList(p_id int) (string, string, string) {
308320
return "fortidlp", "endpoints", "int"
309321
case 92:
310322
return "fortidlp", "addons", "list"
323+
case 97:
324+
return "fmg_cloud", "device_num", "int"
325+
case 98:
326+
return "fmg_cloud", "addons", "list"
327+
case 99:
328+
return "siem_cloud", "region", "string"
329+
case 100:
330+
return "fortisase", "data_transfer", "int"
331+
case 101:
332+
return "fortisase", "branch_on_ramp_locations_fortinet_cloud", "int"
333+
case 102:
334+
return "fortisase", "branch_on_ramp_locations_public_cloud", "int"
335+
case 103:
336+
return "fortisase", "global_region", "string"
337+
case 104:
338+
return "fortisase", "additional_compute_region_fortinet_cloud", "int"
339+
case 105:
340+
return "fortisase", "additional_compute_region_public_cloud", "int"
341+
case 106:
342+
return "fdc_cloud", "service_pkg", "string"
343+
case 107:
344+
return "fdc_cloud", "vlan_num", "int"
345+
case 108:
346+
return "fmg_vm", "service_pkg", "string"
347+
case 109:
348+
return "fmg_vm", "addons", "list"
349+
case 110:
350+
return "fmg_vm", "fortiai_tokens", "int"
351+
case 111:
352+
return "fext_hw", "device_model", "string"
353+
case 112:
354+
return "fext_hw", "service_pkg", "string"
311355
default:
312356
return "", "", ""
313357
}
@@ -338,6 +382,12 @@ func convConfParsNameList2Id(p_type, c_name string) int {
338382
return 30
339383
case "adom_num":
340384
return 9
385+
case "service_pkg":
386+
return 108
387+
case "addons":
388+
return 109
389+
case "fortiai_tokens":
390+
return 110
341391
default:
342392
return 0
343393
}
@@ -473,6 +523,15 @@ func convConfParsNameList2Id(p_type, c_name string) int {
473523
default:
474524
return 0
475525
}
526+
case "fext_hw":
527+
switch c_name {
528+
case "device_model":
529+
return 111
530+
case "service_pkg":
531+
return 112
532+
default:
533+
return 0
534+
}
476535
case "fwbc_private":
477536
switch c_name {
478537
case "average_throughput":
@@ -514,14 +573,26 @@ func convConfParsNameList2Id(p_type, c_name string) int {
514573
return 48
515574
case "service_pkg":
516575
return 49
517-
case "bandwidth":
576+
case "bandwidth": // deprecated
518577
return 50
519578
case "dedicated_ips":
520579
return 51
521-
case "additional_compute_region":
580+
case "additional_compute_region": // deprecated
522581
return 59
523-
case "locations":
582+
case "locations": // deprecated
524583
return 72
584+
case "data_transfer":
585+
return 100
586+
case "branch_on_ramp_locations_fortinet_cloud":
587+
return 101
588+
case "branch_on_ramp_locations_public_cloud":
589+
return 102
590+
case "global_region":
591+
return 103
592+
case "additional_compute_region_fortinet_cloud":
593+
return 104
594+
case "additional_compute_region_public_cloud":
595+
return 105
525596
default:
526597
return 0
527598
}
@@ -568,6 +639,17 @@ func convConfParsNameList2Id(p_type, c_name string) int {
568639
return 67
569640
case "archive_storage":
570641
return 68
642+
case "region":
643+
return 99
644+
default:
645+
return 0
646+
}
647+
case "fdc_cloud":
648+
switch c_name {
649+
case "service_pkg":
650+
return 106
651+
case "vlan_num":
652+
return 107
571653
default:
572654
return 0
573655
}
@@ -601,6 +683,15 @@ func convConfParsNameList2Id(p_type, c_name string) int {
601683
default:
602684
return 0
603685
}
686+
case "fmg_cloud":
687+
switch c_name {
688+
case "device_num":
689+
return 97
690+
case "addons":
691+
return 98
692+
default:
693+
return 0
694+
}
604695
default:
605696
return 0
606697
}
@@ -722,6 +813,9 @@ func getEntitlementFromId(resource_id string, m interface{}) (map[string]interfa
722813
obj := make(map[string]interface{})
723814
obj["configId"] = config_id
724815
obj["serialNumber"] = serial_number
816+
if client, ok := m.(*FortiClient); ok && client.AccountID != 0 {
817+
obj["accountId"] = client.AccountID
818+
}
725819
return_data, err := c.ReadEntitlementsList(&obj)
726820
if err != nil {
727821
return nil, diag.FromErr(err)

0 commit comments

Comments
 (0)