From 63420430e254da33f57b0d9afe86e28f288366c4 Mon Sep 17 00:00:00 2001 From: chinthalapalli Date: Thu, 4 Jan 2024 16:25:14 +0530 Subject: [PATCH] devel sync --- docs/resources/interface.md | 2 +- docs/resources/lag.md | 6 +- go.mod | 4 +- go.sum | 11 +- .../provider/fixtures/f5os_lacp_config.json | 68 ++++++++++++ internal/provider/interface_resource.go | 6 +- internal/provider/lag_resource.go | 102 +++++++++++++++--- internal/provider/lag_resource_test.go | 18 +++- internal/provider/tenant_image_resource.go | 13 +-- .../terraform-providers/f5osclient/f5os.go | 85 ++++++++++++++- .../f5osclient/structs_partition.go | 66 ++++++++++++ vendor/modules.txt | 4 +- 12 files changed, 343 insertions(+), 42 deletions(-) create mode 100644 internal/provider/fixtures/f5os_lacp_config.json diff --git a/docs/resources/interface.md b/docs/resources/interface.md index 8f91bee..1187a27 100644 --- a/docs/resources/interface.md +++ b/docs/resources/interface.md @@ -35,7 +35,7 @@ resource "f5os_interface" "test_interface" { For VELOS partitions blade/port format is required e.g. `1/1.0` - `native_vlan` (Number) Configures the VLAN ID to associate with the interface. The `native_vlan` parameter is used for untagged traffic. -- `trunk_vlans` (List of Number) Configures multiple VLAN IDs to associate with the interface. +- `trunk_vlans` (Set of Number) Configures multiple VLAN IDs to associate with the interface. The `trunk_vlans` parameter is used for tagged traffic ### Read-Only diff --git a/docs/resources/lag.md b/docs/resources/lag.md index cbfad1a..8422bef 100644 --- a/docs/resources/lag.md +++ b/docs/resources/lag.md @@ -34,10 +34,12 @@ resource "f5os_lag" "test_lag" { ### Optional -- `members` (List of String) List of physical interfaces that are members of the LAG. +- `interval` (String) The LACP interval of the interface to be created. +- `members` (Set of String) List of physical interfaces that are members of the LAG. The members should be present on F5 platform and they shouldn't have any VLANs attached to it +- `mode` (String) The LACP mode of the interface to be created. - `native_vlan` (Number) Configures the VLAN ID to associate with LAG interface. The `native_vlan` parameter is used for untagged traffic. -- `trunk_vlans` (List of Number) Configures multiple VLAN IDs to associate with the LAG interface. +- `trunk_vlans` (Set of Number) Configures multiple VLAN IDs to associate with the LAG interface. The `trunk_vlans` parameter is used for tagged traffic ### Read-Only diff --git a/go.mod b/go.mod index 32c86f8..74a2046 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module gitswarm.f5net.com/terraform-providers/terraform-provider-f5os -go 1.19 +go 1.21.3 require ( github.com/hashicorp/terraform-plugin-docs v0.14.1 @@ -10,7 +10,7 @@ require ( github.com/hashicorp/terraform-plugin-log v0.8.0 github.com/hashicorp/terraform-plugin-testing v1.2.0 github.com/stretchr/testify v1.8.4 - gitswarm.f5net.com/terraform-providers/f5osclient v1.0.2 + gitswarm.f5net.com/terraform-providers/f5osclient v1.0.3 ) require ( diff --git a/go.sum b/go.sum index 6b3338a..e00575b 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,7 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= @@ -47,6 +48,7 @@ github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6 github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -125,17 +127,20 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -175,6 +180,7 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= @@ -182,6 +188,7 @@ github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3V github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -211,8 +218,8 @@ github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6e github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zclconf/go-cty v1.13.1 h1:0a6bRwuiSHtAmqCqNOE+c2oHgepv0ctoxU4FUe43kwc= github.com/zclconf/go-cty v1.13.1/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= -gitswarm.f5net.com/terraform-providers/f5osclient v1.0.2 h1:RXDYEeXCYymbdPnbOt2XVQLVK2tYXWpfrQMZ607jDSQ= -gitswarm.f5net.com/terraform-providers/f5osclient v1.0.2/go.mod h1:XmqFs5vsbNni7scPBmJ0pWDIFa8i1NOnHoLnQPU/c98= +gitswarm.f5net.com/terraform-providers/f5osclient v1.0.3 h1:YbDdA8oViX9PDsHHBL8EcmHVq0f3f8cM2vyJ0/GunHI= +gitswarm.f5net.com/terraform-providers/f5osclient v1.0.3/go.mod h1:k+4tg9l6yO3FlFh3dkXGc+Wl+LOB/AXu302hAX6nhDU= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= diff --git a/internal/provider/fixtures/f5os_lacp_config.json b/internal/provider/fixtures/f5os_lacp_config.json new file mode 100644 index 0000000..c65dcc2 --- /dev/null +++ b/internal/provider/fixtures/f5os_lacp_config.json @@ -0,0 +1,68 @@ +{ + "openconfig-lacp:interface": [ + { + "name": "tf-lag", + "config": { + "name": "tf-lag", + "interval": "FAST", + "lacp-mode": "ACTIVE" + }, + "state": { + "name": "tf-lag", + "interval": "FAST", + "lacp-mode": "ACTIVE", + "system-id-mac": "f4:15:63:fb:a0:18" + }, + "members": { + "member": [ + { + "interface": "1.1", + "state": { + "interface": "1.1", + "activity": "ACTIVE", + "timeout": "SHORT", + "synchronization": "OUT_SYNC", + "aggregatable": true, + "collecting": false, + "distributing": false, + "system-id": "f4:15:63:fb:a0:18", + "oper-key": 15, + "partner-id": "00:00:00:00:00:00", + "partner-key": 0, + "port-num": 8320, + "partner-port-num": 0, + "counters": { + "lacp-in-pkts": "0", + "lacp-out-pkts": "3610", + "lacp-rx-errors": "0" + } + } + }, + { + "interface": "1.2", + "state": { + "interface": "1.2", + "activity": "ACTIVE", + "timeout": "SHORT", + "synchronization": "OUT_SYNC", + "aggregatable": true, + "collecting": false, + "distributing": false, + "system-id": "f4:15:63:fb:a0:18", + "oper-key": 15, + "partner-id": "00:00:00:00:00:00", + "partner-key": 0, + "port-num": 8448, + "partner-port-num": 0, + "counters": { + "lacp-in-pkts": "0", + "lacp-out-pkts": "3610", + "lacp-rx-errors": "0" + } + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/internal/provider/interface_resource.go b/internal/provider/interface_resource.go index c5211b5..af822de 100644 --- a/internal/provider/interface_resource.go +++ b/internal/provider/interface_resource.go @@ -31,7 +31,7 @@ type InterfaceResource struct { type InterfaceResourceModel struct { Name types.String `tfsdk:"name"` NativeVlan types.Int64 `tfsdk:"native_vlan"` - TrunkVlans types.List `tfsdk:"trunk_vlans"` + TrunkVlans types.Set `tfsdk:"trunk_vlans"` Enabled types.Bool `tfsdk:"enabled"` Status types.String `tfsdk:"status"` Id types.String `tfsdk:"id"` @@ -55,7 +55,7 @@ func (r *InterfaceResource) Schema(ctx context.Context, req resource.SchemaReque MarkdownDescription: "Configures the VLAN ID to associate with the interface.\nThe `native_vlan` parameter is used for untagged traffic.", Optional: true, }, - "trunk_vlans": schema.ListAttribute{ + "trunk_vlans": schema.SetAttribute{ MarkdownDescription: "Configures multiple VLAN IDs to associate with the interface.\nThe `trunk_vlans` parameter is used for tagged traffic", Optional: true, ElementType: types.Int64Type, @@ -230,7 +230,7 @@ func (r *InterfaceResource) interfaceResourceModelToState(ctx context.Context, r if int64(respData.OpenconfigInterfacesInterface[0].OpenconfigIfEthernetEthernet.OpenconfigVlanSwitchedVlan.Config.NativeVlan) != 0 { data.NativeVlan = types.Int64Value(int64(respData.OpenconfigInterfacesInterface[0].OpenconfigIfEthernetEthernet.OpenconfigVlanSwitchedVlan.Config.NativeVlan)) } - data.TrunkVlans, _ = types.ListValueFrom(ctx, types.Int64Type, respData.OpenconfigInterfacesInterface[0].OpenconfigIfEthernetEthernet.OpenconfigVlanSwitchedVlan.Config.TrunkVlans) + data.TrunkVlans, _ = types.SetValueFrom(ctx, types.Int64Type, respData.OpenconfigInterfacesInterface[0].OpenconfigIfEthernetEthernet.OpenconfigVlanSwitchedVlan.Config.TrunkVlans) } func getInterfaceConfig(ctx context.Context, data *InterfaceResourceModel) *f5ossdk.F5ReqOpenconfigInterface { diff --git a/internal/provider/lag_resource.go b/internal/provider/lag_resource.go index 2882264..62591ea 100644 --- a/internal/provider/lag_resource.go +++ b/internal/provider/lag_resource.go @@ -3,11 +3,14 @@ package provider import ( "context" "fmt" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" f5ossdk "gitswarm.f5net.com/terraform-providers/f5osclient" @@ -29,10 +32,12 @@ type LagResource struct { type LagResourceModel struct { Name types.String `tfsdk:"name"` NativeVlan types.Int64 `tfsdk:"native_vlan"` - TrunkVlans types.List `tfsdk:"trunk_vlans"` + TrunkVlans types.Set `tfsdk:"trunk_vlans"` Status types.String `tfsdk:"status"` - Members types.List `tfsdk:"members"` + Members types.Set `tfsdk:"members"` Id types.String `tfsdk:"id"` + Mode types.String `tfsdk:"mode"` + Interval types.String `tfsdk:"interval"` } func (r *LagResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -56,13 +61,13 @@ func (r *LagResource) Schema(ctx context.Context, req resource.SchemaRequest, re MarkdownDescription: "Configures the VLAN ID to associate with LAG interface.\nThe `native_vlan` parameter is used for untagged traffic.", Optional: true, }, - "trunk_vlans": schema.ListAttribute{ + "trunk_vlans": schema.SetAttribute{ MarkdownDescription: "Configures multiple VLAN IDs to associate with the LAG interface.\nThe `trunk_vlans` parameter is used for tagged traffic", Optional: true, ElementType: types.Int64Type, }, - "members": schema.ListAttribute{ - MarkdownDescription: "List of physical interfaces that are members of the LAG.", + "members": schema.SetAttribute{ + MarkdownDescription: "List of physical interfaces that are members of the LAG. The members should be present on F5 platform and they shouldn't have any VLANs attached to it", Optional: true, Computed: true, ElementType: types.StringType, @@ -78,6 +83,22 @@ func (r *LagResource) Schema(ctx context.Context, req resource.SchemaRequest, re stringplanmodifier.UseStateForUnknown(), }, }, + "mode": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The LACP mode of the interface to be created.", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"ACTIVE", "PASSIVE"}...), + }, + }, + "interval": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The LACP interval of the interface to be created.", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"SLOW", "FAST"}...), + }, + }, }, } } @@ -106,7 +127,9 @@ func (r *LagResource) Create(ctx context.Context, req resource.CreateRequest, re membersConfig := getLagMembersConfig(ctx, data) - respByte, err := r.client.CreateLagInterface(interfaceReqConfig, membersConfig) + modeIntervalConfig := getLagModeIntervalConfig(ctx, data) + + respByte, err := r.client.CreateLagInterface(interfaceReqConfig, membersConfig, modeIntervalConfig) if err != nil { resp.Diagnostics.AddError("F5OS Client Error:", fmt.Sprintf("Creating LAG interface failed, got error: %s", err)) return @@ -121,7 +144,15 @@ func (r *LagResource) Create(ctx context.Context, req resource.CreateRequest, re return } tflog.Debug(ctx, fmt.Sprintf("LAG interface Resp :%+v", intfData)) - r.lagInterfaceResourceModelToState(ctx, intfData, data) + + lacpData, err := r.client.GetLacpInterface(data.Name.ValueString()) + if err != nil { + resp.Diagnostics.AddError("F5OS Client Error", fmt.Sprintf("Unable to Read/Get LACP Interface, got error: %s", err)) + return + } + tflog.Debug(ctx, fmt.Sprintf("LACP interface Resp :%+v", lacpData)) + + r.lagInterfaceResourceModelToState(ctx, intfData, lacpData, data) // Save data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -145,7 +176,15 @@ func (r *LagResource) Read(ctx context.Context, req resource.ReadRequest, resp * return } tflog.Debug(ctx, fmt.Sprintf("LAG interface Resp :%+v", intfData)) - r.lagInterfaceResourceModelToState(ctx, intfData, data) + + lacpData, err := r.client.GetLacpInterface(data.Id.ValueString()) + if err != nil { + resp.Diagnostics.AddError("F5OS Client Error", fmt.Sprintf("Unable to Read/Get LACP Interface, got error: %s", err)) + return + } + tflog.Debug(ctx, fmt.Sprintf("LACP interface Resp :%+v", lacpData)) + + r.lagInterfaceResourceModelToState(ctx, intfData, lacpData, data) // Save data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -168,6 +207,9 @@ func (r *LagResource) Update(ctx context.Context, req resource.UpdateRequest, re lagInterfaceReqConfig := getLagInterfaceConfig(ctx, data) tflog.Info(ctx, fmt.Sprintf("lagInterfaceReqConfig Data:%+v", lagInterfaceReqConfig)) + modeIntervalConfig := getLagModeIntervalConfig(ctx, data) + tflog.Info(ctx, fmt.Sprintf("modeIntervalConfig Data:%+v", modeIntervalConfig)) + if !data.Members.IsNull() && !data.Members.IsUnknown() { memberData, err := r.client.GetLagInterface(data.Id.ValueString()) if err != nil { @@ -193,7 +235,7 @@ func (r *LagResource) Update(ctx context.Context, req resource.UpdateRequest, re } } - respByte, err := r.client.UpdateLagInterface(data.Id.ValueString(), lagInterfaceReqConfig) + respByte, err := r.client.UpdateLagInterface(data.Id.ValueString(), lagInterfaceReqConfig, modeIntervalConfig) if err != nil { resp.Diagnostics.AddError("F5OS Client Error:", fmt.Sprintf("Update LAG interface failed, got error: %s", err)) return @@ -207,8 +249,15 @@ func (r *LagResource) Update(ctx context.Context, req resource.UpdateRequest, re resp.Diagnostics.AddError("F5OS Client Error", fmt.Sprintf("Unable to Read/Get LAG Interface, got error: %s", err)) return } + + lacpData, err := r.client.GetLacpInterface(data.Name.ValueString()) + if err != nil { + resp.Diagnostics.AddError("F5OS Client Error", fmt.Sprintf("Unable to Read/Get LACP Interface, got error: %s", err)) + return + } + tflog.Debug(ctx, fmt.Sprintf("LAG interface Resp :%+v", intfData)) - r.lagInterfaceResourceModelToState(ctx, intfData, data) + r.lagInterfaceResourceModelToState(ctx, intfData, lacpData, data) // Save data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -242,8 +291,14 @@ func (r *LagResource) Delete(ctx context.Context, req resource.DeleteRequest, re } } - err2 := r.client.RemoveLagInterface(data.Id.ValueString()) + err2 := r.client.RemoveLacpInterface(data.Id.ValueString()) if err2 != nil { + resp.Diagnostics.AddError("F5OS Client Error", fmt.Sprintf("Unable to delete LACP interface, got error: %s", err2)) + return + } + + err3 := r.client.RemoveLagInterface(data.Id.ValueString()) + if err3 != nil { resp.Diagnostics.AddError("F5OS Client Error", fmt.Sprintf("Unable to delete LAG interface, got error: %s", err2)) return } @@ -254,17 +309,21 @@ func (r *LagResource) ImportState(ctx context.Context, req resource.ImportStateR resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } -func (r *LagResource) lagInterfaceResourceModelToState(ctx context.Context, respData *f5ossdk.F5RespLagInterfaces, data *LagResourceModel) { +func (r *LagResource) lagInterfaceResourceModelToState(ctx context.Context, respData *f5ossdk.F5RespLagInterfaces, lacpData *f5ossdk.LacpInterfaceResponses, data *LagResourceModel) { data.Name = types.StringValue(respData.OpenconfigInterfacesInterface[0].Name) - data.NativeVlan = types.Int64Value(int64(respData.OpenconfigInterfacesInterface[0].OpenconfigIfAggregateAggregation.OpenconfigVlanSwitchedVlan.Config.NativeVlan)) - data.TrunkVlans, _ = types.ListValueFrom(ctx, types.Int64Type, respData.OpenconfigInterfacesInterface[0].OpenconfigIfAggregateAggregation.OpenconfigVlanSwitchedVlan.Config.TrunkVlans) + if int64(respData.OpenconfigInterfacesInterface[0].OpenconfigIfAggregateAggregation.OpenconfigVlanSwitchedVlan.Config.NativeVlan) != 0 { + data.NativeVlan = types.Int64Value(int64(respData.OpenconfigInterfacesInterface[0].OpenconfigIfAggregateAggregation.OpenconfigVlanSwitchedVlan.Config.NativeVlan)) + } + data.TrunkVlans, _ = types.SetValueFrom(ctx, types.Int64Type, respData.OpenconfigInterfacesInterface[0].OpenconfigIfAggregateAggregation.OpenconfigVlanSwitchedVlan.Config.TrunkVlans) data.Status = types.StringValue(respData.OpenconfigInterfacesInterface[0].State.OperStatus) + data.Mode = types.StringValue(lacpData.OpenConfigLacpInterface[0].Config.Mode) + data.Interval = types.StringValue(lacpData.OpenConfigLacpInterface[0].Config.Interval) var members []string for _, member := range respData.OpenconfigInterfacesInterface[0].OpenconfigIfAggregateAggregation.State.Members.Member { members = append(members, member.Name) } - data.Members, _ = types.ListValueFrom(ctx, types.StringType, members) + data.Members, _ = types.SetValueFrom(ctx, types.StringType, members) } func getLagInterfaceConfig(ctx context.Context, data *LagResourceModel) *f5ossdk.F5ReqLagInterfaces { @@ -297,3 +356,16 @@ func getLagMembersConfig(ctx context.Context, data *LagResourceModel) *f5ossdk.F } return &memberConfigReq } + +func getLagModeIntervalConfig(ctx context.Context, data *LagResourceModel) *f5ossdk.F5ReqLagInterfacesConfig { + interfaceReq := f5ossdk.F5ReqLagInterfaceConfig{} + interfaceReq.Name = data.Name.ValueString() + interfaceReq.Config.Interval = data.Interval.ValueString() + interfaceReq.Config.Mode = data.Mode.ValueString() + interfaceReq.Config.Name = data.Name.ValueString() + + modeIntervalLagReq := f5ossdk.F5ReqLagInterfacesConfig{} + modeIntervalLagReq.OpenconfigInterfacesInterfaces.OpenConfigLacp.Interfaces.Interface = append(modeIntervalLagReq.OpenconfigInterfacesInterfaces.OpenConfigLacp.Interfaces.Interface, interfaceReq) + + return &modeIntervalLagReq +} diff --git a/internal/provider/lag_resource_test.go b/internal/provider/lag_resource_test.go index d4a6311..8153b24 100644 --- a/internal/provider/lag_resource_test.go +++ b/internal/provider/lag_resource_test.go @@ -2,11 +2,11 @@ package provider import ( "fmt" - "github.com/stretchr/testify/assert" - "log" "net/http" "testing" + "github.com/stretchr/testify/assert" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) @@ -107,6 +107,12 @@ func TestAccLagInterfaceCreateUnitTC3Resource(t *testing.T) { _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/f5os_lag_config.json")) } }) + mux.HandleFunc("/restconf/data/openconfig-lacp:lacp/interfaces/interface=tf-lag", func(w http.ResponseWriter, r *http.Request) { + if r.URL.String() == "/restconf/data/openconfig-lacp:lacp/interfaces/interface=tf-lag" { + w.WriteHeader(http.StatusOK) + _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/f5os_lacp_config.json")) + } + }) defer teardown() resource.Test(t, resource.TestCase{ @@ -184,9 +190,7 @@ func TestAccLagInterfaceCreateUnitTC4Resource(t *testing.T) { w.WriteHeader(http.StatusOK) _, _ = fmt.Fprintf(w, "%s", "") }) - mux.HandleFunc("/restconf/data/openconfig-interfaces:interfaces/interface=tf-lag", func(w http.ResponseWriter, r *http.Request) { - log.Printf("\n\n\n ############### count LAG:%+v ##############\n\n\n", count) if r.Method == "GET" && (count == 0 || count == 1 || count == 2 || count == 3) { w.WriteHeader(http.StatusOK) _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/f5os_lag_config.json")) @@ -197,6 +201,12 @@ func TestAccLagInterfaceCreateUnitTC4Resource(t *testing.T) { } count++ }) + mux.HandleFunc("/restconf/data/openconfig-lacp:lacp/interfaces/interface=tf-lag", func(w http.ResponseWriter, r *http.Request) { + if r.URL.String() == "/restconf/data/openconfig-lacp:lacp/interfaces/interface=tf-lag" { + w.WriteHeader(http.StatusOK) + _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/f5os_lacp_config.json")) + } + }) defer teardown() resource.Test(t, resource.TestCase{ IsUnitTest: true, diff --git a/internal/provider/tenant_image_resource.go b/internal/provider/tenant_image_resource.go index ec41c34..4baf6e0 100644 --- a/internal/provider/tenant_image_resource.go +++ b/internal/provider/tenant_image_resource.go @@ -149,13 +149,14 @@ func (r *TenantImageResource) Create(ctx context.Context, req resource.CreateReq return } - resp1Byte, err := r.client.GetImage(data.ImageName.ValueString()) - if err != nil { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Import Image, got error: %s", err)) - return - } + resp1Byte, _ := r.client.GetImage(data.ImageName.ValueString()) + + // if err != nil { + // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Import Image, got error: %s", err)) + // return + // } - if len(resp1Byte.TenantImages) == 0 { + if resp1Byte == nil || len(resp1Byte.TenantImages) == 0 { if data.UploadFromPath.IsNull() { respByte, err := r.importImage(ctx, data) if err != nil { diff --git a/vendor/gitswarm.f5net.com/terraform-providers/f5osclient/f5os.go b/vendor/gitswarm.f5net.com/terraform-providers/f5osclient/f5os.go index e7ea339..6a0e4e1 100644 --- a/vendor/gitswarm.f5net.com/terraform-providers/f5osclient/f5os.go +++ b/vendor/gitswarm.f5net.com/terraform-providers/f5osclient/f5os.go @@ -36,6 +36,7 @@ const ( uriFileDelete = "/f5-utils-file-transfer:file/delete" uriFileList = "/f5-utils-file-transfer:file/list" uriFileTransferStatus = "/f5-utils-file-transfer:file/transfer-operations/transfer-operation" + uriLacp = "/openconfig-lacp:lacp/interfaces" ) var f5osLogger hclog.Logger @@ -410,7 +411,22 @@ func (p *F5os) GetLagInterface(intf string) (*F5RespLagInterfaces, error) { return intLag, nil } -func (p *F5os) CreateLagInterface(body *F5ReqLagInterfaces, members *F5ReqLagInterfaces) ([]byte, error) { +func (p *F5os) GetLacpInterface(intf string) (*LacpInterfaceResponses, error) { + intfnew := fmt.Sprintf("/interface=%s", encodeUrl(intf)) + url := fmt.Sprintf("%s%s", uriLacp, intfnew) + f5osLogger.Info("[GetLacpInterface]", "Request path", hclog.Fmt("%+v", url)) + + intLag := &LacpInterfaceResponses{} + byteData, err := p.GetRequest(url) + if err != nil { + return nil, err + } + json.Unmarshal(byteData, intLag) + f5osLogger.Debug("[GetLacpInterface]", "intLag", hclog.Fmt("%+v", intLag)) + return intLag, nil +} + +func (p *F5os) CreateLagInterface(body *F5ReqLagInterfaces, members *F5ReqLagInterfaces, lagModeInterval *F5ReqLagInterfacesConfig) ([]byte, error) { f5osLogger.Debug("[CreateLagInterface]", "Request path", hclog.Fmt("%+v", "/")) byteBody, err := json.Marshal(body) if err != nil { @@ -425,12 +441,38 @@ func (p *F5os) CreateLagInterface(body *F5ReqLagInterfaces, members *F5ReqLagInt resp, err = p.addLagMembers(members) if err != nil { + err1 := p.RemoveLagInterface(body.OpenconfigInterfacesInterfaces.Interface[0].Config.Name) + if err1 != nil { + return nil, err + } return resp, err } + + data, err := p.addLagModeInterval(lagModeInterval) + if err != nil { + + var haveMembers []string + for _, member := range members.OpenconfigInterfacesInterfaces.Interface { + haveMembers = append(haveMembers, member.Name) + } + + err1 := p.RemoveLagMembers(haveMembers) + if err1 != nil { + return nil, err + } + + err2 := p.RemoveLagInterface(body.OpenconfigInterfacesInterfaces.Interface[0].Config.Name) + if err2 != nil { + return nil, err + } + + return data, err + } + return resp, nil } -func (p *F5os) UpdateLagInterface(intf string, body *F5ReqLagInterfaces) ([]byte, error) { +func (p *F5os) UpdateLagInterface(intf string, body *F5ReqLagInterfaces, lagModeIntervalData *F5ReqLagInterfacesConfig) ([]byte, error) { f5osLogger.Debug("[UpdateLagInterface]", "Request path", hclog.Fmt("%+v", uriInterface)) vlans, err := p.getLagSwitchedVlans(encodeUrl(intf)) if err != nil { @@ -459,6 +501,12 @@ func (p *F5os) UpdateLagInterface(intf string, body *F5ReqLagInterfaces) ([]byte return resp, err } f5osLogger.Debug("[UpdateLagInterface]", "Resp:", hclog.Fmt("%+v", string(resp))) + + data, err := p.addLagModeInterval(lagModeIntervalData) + if err != nil { + return data, err + } + return resp, nil } @@ -509,6 +557,17 @@ func (p *F5os) RemoveLagInterface(intf string) error { return nil } +func (p *F5os) RemoveLacpInterface(intf string) error { + intfnew := fmt.Sprintf("/interface=%s", intf) + url := fmt.Sprintf("%s%s", uriLacp, intfnew) + f5osLogger.Debug("[RemoveLacpInterface]", "Request path", hclog.Fmt("%+v", url)) + err := p.DeleteRequest(url) + if err != nil { + return err + } + return nil +} + func (p *F5os) UpdateLagMembers(members *F5ReqLagInterfaces) ([]byte, error) { resp, err := p.addLagMembers(members) if err != nil { @@ -518,17 +577,33 @@ func (p *F5os) UpdateLagMembers(members *F5ReqLagInterfaces) ([]byte, error) { } func (p *F5os) addLagMembers(body *F5ReqLagInterfaces) ([]byte, error) { - f5osLogger.Debug("[UpdateLagMember]", "Request path", hclog.Fmt("%+v", "/")) + f5osLogger.Debug("[addLagMembers]", "Request path", hclog.Fmt("%+v", "/")) byteBody, err := json.Marshal(body) if err != nil { return byteBody, err } - f5osLogger.Debug("[UpdateLagMember]", "Request Body", hclog.Fmt("%+v", body)) + f5osLogger.Debug("[addLagMembers]", "Request Body", hclog.Fmt("%+v", body)) + resp, err := p.PatchRequest("/", byteBody) + if err != nil { + return resp, err + } + f5osLogger.Debug("[addLagMembers]", "Resp:", hclog.Fmt("%+v", string(resp))) + return resp, nil +} + +func (p *F5os) addLagModeInterval(body *F5ReqLagInterfacesConfig) ([]byte, error) { + f5osLogger.Debug("[addLagModeInterval]", "Request path", hclog.Fmt("%+v", "/")) + byteBody, err := json.Marshal(body) + if err != nil { + return byteBody, err + } + f5osLogger.Debug("[addLagModeInterval]", "Request Body", hclog.Fmt("%+v", body)) + resp, err := p.PatchRequest("/", byteBody) if err != nil { return resp, err } - f5osLogger.Debug("[UpdateLagMember]", "Resp:", hclog.Fmt("%+v", string(resp))) + f5osLogger.Debug("[addLagModeInterval]", "Resp:", hclog.Fmt("%+v", string(resp))) return resp, nil } diff --git a/vendor/gitswarm.f5net.com/terraform-providers/f5osclient/structs_partition.go b/vendor/gitswarm.f5net.com/terraform-providers/f5osclient/structs_partition.go index d22b1e4..4e068bb 100644 --- a/vendor/gitswarm.f5net.com/terraform-providers/f5osclient/structs_partition.go +++ b/vendor/gitswarm.f5net.com/terraform-providers/f5osclient/structs_partition.go @@ -169,6 +169,72 @@ type F5ReqLagInterfaces struct { } `json:"openconfig-interfaces:interfaces,omitempty"` } +type F5ReqLagInterfacesConfig struct { + OpenconfigInterfacesInterfaces struct { + OpenConfigLacp struct { + Interfaces struct { + Interface []F5ReqLagInterfaceConfig `json:"interface,omitempty"` + } `json:"interfaces,omitempty"` + } `json:"openconfig-lacp:lacp,omitempty"` + } `json:"ietf-restconf:data,omitempty"` +} + +type F5ReqLagInterfaceConfig struct { + Name string `json:"name,omitempty"` + Config LagIntervalConfig `json:"config,omitempty"` +} + +type LagIntervalConfig struct { + Name string `json:"name,omitempty"` + Interval string `json:"interval,omitempty"` + Mode string `json:"lacp-mode,omitempty"` +} + +type LacpInterfaceResponses struct { + OpenConfigLacpInterface []LacpInterfaceResponse `json:"openconfig-lacp:interface,omitempty"` +} +type LacpInterfaceResponse struct { + Name string `json:"name,omitempty"` + Config struct { + Name string `json:"name,omitempty"` + Interval string `json:"interval,omitempty"` + Mode string `json:"lacp-mode,omitempty"` + } `json:"config,omitempty"` + State struct { + Name string `json:"name,omitempty"` + Interval string `json:"interval,omitempty"` + Mode string `json:"lacp-mode,,omitempty"` + SystemIdMac string `json:"system-id-mac,omitempty"` + } + Members struct { + Member []MemberConfig `json:"member,omitempty"` + } `json:"members,omitempty"` +} + +type MemberConfig struct { + Interface string `json:"interface,omitempty"` + State struct { + Interface string `json:"interface,omitempty"` + Activity string `json:"activity,omitempty"` + Timeout string `json:"timeout,omitempty"` + Synchronization string `json:"synchronization,omitempty"` + Aggregatable bool `json:"aggregatable,omitempty"` + Collecting bool `json:"collecting,omitempty"` + Distributing bool `json:"distributing,omitempty"` + SystemId string `json:"system-id,omitempty"` + OperKey int `json:"oper-key,omitempty"` + PartnerId string `json:"partner-id,omitempty"` + PartnerKey int `json:"partner-key,omitempty"` + PortNum int `json:"port-num,omitempty"` + PartnerPortNum int `json:"partner-port-num,omitempty"` + Counters struct { + LacpInPkts int `json:"lacp-in-pkts,omitempty"` + LacpOutPkts int `json:"lacp-out-pkts,omitempty"` + LacpRxErrors int `json:"lacp-rx-errors,omitempty"` + } `json:"counters,omitempty"` + } `json:"state,omitempty"` +} + type F5ReqLagInterface struct { Name string `json:"name,omitempty"` Config struct { diff --git a/vendor/modules.txt b/vendor/modules.txt index ffbb1ac..657ed45 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -307,8 +307,8 @@ github.com/zclconf/go-cty/cty/function/stdlib github.com/zclconf/go-cty/cty/gocty github.com/zclconf/go-cty/cty/json github.com/zclconf/go-cty/cty/set -# gitswarm.f5net.com/terraform-providers/f5osclient v1.0.2 -## explicit; go 1.19 +# gitswarm.f5net.com/terraform-providers/f5osclient v1.0.3 +## explicit; go 1.21.3 gitswarm.f5net.com/terraform-providers/f5osclient # golang.org/x/crypto v0.7.0 ## explicit; go 1.17