From 0d80b85bf5cd2f57d5a1e82d764a830ba6878c2e Mon Sep 17 00:00:00 2001 From: Jeremy Muriel Date: Thu, 29 Aug 2024 16:47:00 +0200 Subject: [PATCH] add no_decode_secrets provider attribute to disable decoding secret hashes by Junos device when reading resource data Fix #688 --- .changes/issue-688.md | 4 ++ .golangci.yml | 6 ++ docs/index.md | 17 +++-- go.mod | 1 + go.sum | 2 + internal/junos/client.go | 8 +++ internal/junos/client_session.go | 4 +- internal/junos/constants.go | 1 + internal/junos/session.go | 16 +++++ internal/providerfwk/provider.go | 35 +++++++++-- internal/providerfwk/resource_bgp_group.go | 2 +- internal/providerfwk/resource_bgp_neighbor.go | 2 +- .../resource_eventoptions_destination.go | 2 +- internal/providerfwk/resource_iccp.go | 2 +- internal/providerfwk/resource_iccp_peer.go | 2 +- .../providerfwk/resource_interface_logical.go | 8 ++- internal/providerfwk/resource_ospf_area.go | 10 +-- internal/providerfwk/resource_rip_neighbor.go | 4 +- ...ource_security_authentication_key_chain.go | 8 ++- .../resource_security_ike_gateway.go | 2 +- .../resource_security_ike_policy.go | 4 +- .../resource_security_ipsec_vpn.go | 12 ++-- .../providerfwk/resource_snmp_v3_community.go | 3 +- .../providerfwk/resource_snmp_v3_usm_user.go | 9 ++- internal/providerfwk/resource_system.go | 40 +++++++----- .../resource_system_radius_server.go | 4 +- .../resource_system_radius_server_test.go | 31 +++++++--- .../resource_system_syslog_file.go | 2 +- .../resource_system_tacplus_server.go | 2 +- internal/providerfwk/resourceattr_bgp.go | 7 ++- .../2/main.tf | 4 ++ .../4/main.tf | 6 ++ .../4/provider.tf | 3 + .../5/main.tf | 6 ++ internal/providersdk/provider.go | 25 ++++++-- internal/ruleguard/rule_junos_decode.go | 12 ++++ internal/tfdata/to_int64.go | 3 +- internal/tfdata/to_string.go | 3 +- internal/utils/bool.go | 15 +++++ internal/utils/bool_test.go | 62 +++++++++++++++++++ 40 files changed, 308 insertions(+), 81 deletions(-) create mode 100644 .changes/issue-688.md create mode 100644 internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/4/main.tf create mode 100644 internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/4/provider.tf create mode 100644 internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/5/main.tf create mode 100644 internal/ruleguard/rule_junos_decode.go create mode 100644 internal/utils/bool.go create mode 100644 internal/utils/bool_test.go diff --git a/.changes/issue-688.md b/.changes/issue-688.md new file mode 100644 index 00000000..fae3b8a1 --- /dev/null +++ b/.changes/issue-688.md @@ -0,0 +1,4 @@ + +FEATURES: + +* add **no_decode_secrets** provider attribute to disable decoding secret hashes by Junos device when reading resource data (Fix [#688](https://github.com/jeremmfr/terraform-provider-junos/issues/688)) diff --git a/.golangci.yml b/.golangci.yml index 15b09790..f457f69c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -44,6 +44,12 @@ linters-settings: min-occurrences: 25 # Ignore test files. ignore-tests: true + gocritic: + enabled-checks: + - ruleguard + settings: + ruleguard: + rules: '${configDir}/internal/ruleguard/*.go' gocyclo: # minimal code complexity to report, 30 by default min-complexity: 100 diff --git a/docs/index.md b/docs/index.md index 45038c1e..10bfb804 100644 --- a/docs/index.md +++ b/docs/index.md @@ -113,6 +113,13 @@ The following arguments are supported in the `provider` block: It can also be sourced from the `JUNOS_GROUP_INTERFACE_DELETE` environment variable. Defaults to empty. +- **no_decode_secrets** (Optional, Boolean) + Disable decoding secret hashes by Junos device when reading resource data. + So **encoded** secrets need to be set in the resources config to + avoid drift between Terraform config and state. + It can also be enabled from the `JUNOS_NO_DECODE_SECRETS` environment variable and + its value is `1`, `t` or `true`. + -> **Note:** Two SSH authentication methods (keys / password) are possible and tried with the `sshkey_pem`, `sshkeyfile` arguments or the keys provided by a SSH agent through the `SSH_AUTH_SOCK` @@ -248,9 +255,8 @@ The following arguments are supported in the `provider` block: line when it should be necessary. - **junos_null_commit_file**, the skip doesn’t of course concern this resource. - It can also be sourced from the `JUNOS_FAKEUPDATE_ALSO` environment variable and - its value is `true`. - Defaults to `false`. + It can also be enabled from the `JUNOS_FAKEUPDATE_ALSO` environment variable and + its value is `1`, `t` or `true`. - **fake_delete_also** (Optional, Boolean, **don't use in normal terraform run**) As with `create` and `fake_create_with_setfile`, when this option is true, the normal @@ -264,9 +270,8 @@ The following arguments are supported in the `provider` block: line when it should be necessary. - **junos_null_commit_file**, the skip doesn’t of course concern this resource. - It can also be sourced from the `JUNOS_FAKEDELETE_ALSO` environment variable and - its value is `true`. - Defaults to `false`. + It can also be enabled from the `JUNOS_FAKEDELETE_ALSO` environment variable and + its value is `1`, `t` or `true`. ## Interface specifications diff --git a/go.mod b/go.mod index 286d4c61..9d44cad9 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/jeremmfr/go-netconf v0.5.0 github.com/jeremmfr/go-utils v0.12.0 github.com/jeremmfr/junosdecode v1.1.1 + github.com/quasilyte/go-ruleguard/dsl v0.3.22 golang.org/x/crypto v0.26.0 ) diff --git a/go.sum b/go.sum index 7ef745ca..da344cf0 100644 --- a/go.sum +++ b/go.sum @@ -136,6 +136,8 @@ github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= +github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= diff --git a/internal/junos/client.go b/internal/junos/client.go index 79e2f683..d2e40ede 100644 --- a/internal/junos/client.go +++ b/internal/junos/client.go @@ -16,6 +16,7 @@ type Client struct { junosSSHKeyFile string junosSSHKeyPass string groupIntDel string + decodeSecrets bool sleepShort int sleepLock int junosCommitConfirmed int @@ -41,6 +42,7 @@ func NewClient(ip string) *Client { junosSSHKeyFile: "", junosSSHKeyPass: "", groupIntDel: "", + decodeSecrets: true, sleepShort: 100, sleepLock: 10, junosCommitConfirmed: 0, @@ -99,6 +101,12 @@ func (clt *Client) WithGroupInterfaceDelete(groupIntDel string) *Client { return clt } +func (clt *Client) WithoutDecodeSecrets() *Client { + clt.decodeSecrets = false + + return clt +} + func (clt *Client) WithSleepShort(sleep int) *Client { clt.sleepShort = sleep diff --git a/internal/junos/client_session.go b/internal/junos/client_session.go index c6cfa18b..e9ee8899 100644 --- a/internal/junos/client_session.go +++ b/internal/junos/client_session.go @@ -54,6 +54,7 @@ func (clt *Client) StartNewSession(ctx context.Context) (*Session, error) { message = "[" + sess.localAddress + "->" + sess.remoteAddress + "]" + message clt.logFile(message) } + sess.decodeSecrets = clt.decodeSecrets sess.sleepLock = clt.sleepLock sess.sleepShort = clt.sleepShort sess.sleepSSHClosed = clt.sleepSSHClosed @@ -72,7 +73,8 @@ func (clt *Client) StartNewSession(ctx context.Context) (*Session, error) { func (clt *Client) NewSessionWithoutNetconf(_ context.Context) *Session { sess := Session{ - logFile: clt.logFile, + logFile: clt.logFile, + decodeSecrets: clt.decodeSecrets, } if clt.fakeCreateSetFile != "" { sess.fakeSetFile = clt.appendFakeCreateSetFile diff --git a/internal/junos/constants.go b/internal/junos/constants.go index 8ac8049a..3876041f 100644 --- a/internal/junos/constants.go +++ b/internal/junos/constants.go @@ -53,6 +53,7 @@ const ( EnvFakecreateSetfile = "JUNOS_FAKECREATE_SETFILE" EnvFakeupdateAlso = "JUNOS_FAKEUPDATE_ALSO" EnvFakedeleteAlso = "JUNOS_FAKEDELETE_ALSO" + EnvNoDecodeSecrets = "JUNOS_NO_DECODE_SECRETS" DefaultInterfaceTestAcc = "ge-0/0/3" DefaultInterfaceTestAcc2 = "ge-0/0/4" diff --git a/internal/junos/session.go b/internal/junos/session.go index 5f4762d3..49efb462 100644 --- a/internal/junos/session.go +++ b/internal/junos/session.go @@ -9,8 +9,11 @@ import ( "os" "time" + "github.com/jeremmfr/terraform-provider-junos/internal/tfdata" "github.com/jeremmfr/terraform-provider-junos/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/jeremmfr/go-netconf/netconf" "golang.org/x/crypto/ssh" ) @@ -22,6 +25,7 @@ type Session struct { localAddress string remoteAddress string logFile func(string) + decodeSecrets bool fakeSetFile func([]string) error sleepShort int sleepLock int @@ -326,3 +330,15 @@ func (sess *Session) Close() { } } } + +func (sess *Session) JunosDecode( + str, errMsg string, +) ( + basetypes.StringValue, error, +) { + if !sess.decodeSecrets { + return types.StringValue(str), nil + } + + return tfdata.JunosDecode(str, errMsg) +} diff --git a/internal/providerfwk/provider.go b/internal/providerfwk/provider.go index e01beb04..e6a4649d 100644 --- a/internal/providerfwk/provider.go +++ b/internal/providerfwk/provider.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "strconv" - "strings" "github.com/jeremmfr/terraform-provider-junos/internal/junos" "github.com/jeremmfr/terraform-provider-junos/internal/tfdiag" @@ -41,6 +40,7 @@ type junosProviderModel struct { SSHKeyFile types.String `tfsdk:"sshkeyfile"` SSHKeyPass types.String `tfsdk:"keypass"` GroupIntDel types.String `tfsdk:"group_interface_delete"` + NoDecodeSecrets types.Bool `tfsdk:"no_decode_secrets"` CmdSleepShort types.Int64 `tfsdk:"cmd_sleep_short"` CmdSleepLock types.Int64 `tfsdk:"cmd_sleep_lock"` CommitConfirmed types.Int64 `tfsdk:"commit_confirmed"` @@ -116,6 +116,13 @@ func (p *junosProvider) Schema( Description: "This is the Junos group used to remove configuration on a physical interface." + " May also be provided via " + junos.EnvGroupInterfaceDelete + " environment variable.", }, + "no_decode_secrets": schema.BoolAttribute{ + Optional: true, + Description: "Disable decoding secret hashes by Junos device when read resource data." + + " So encoded secrets need to be set in resources config to " + + "avoid drift between Terraform config and state." + + " May also be enabled via " + junos.EnvNoDecodeSecrets + " environment variable.", + }, "cmd_sleep_short": schema.Int64Attribute{ Optional: true, Description: "Milliseconds to wait after Terraform provider executes an action on the Junos device." + @@ -197,14 +204,14 @@ func (p *junosProvider) Schema( Description: "The normal process to update resources skipped to generate set/delete lines, " + "append them to the same file as `fake_create_with_setfile`, " + "and respond with a `fake` successful update of resources to Terraform." + - " May also be provided via " + junos.EnvFakeupdateAlso + " environment variable.", + " May also be enabled via " + junos.EnvFakeupdateAlso + " environment variable.", }, "fake_delete_also": schema.BoolAttribute{ Optional: true, Description: "The normal process to delete resources skipped to generate delete lines, " + "append them to the same file as `fake_create_with_setfile`, " + "and respond with a `fake` successful delete of resources to Terraform." + - " May also be provided via " + junos.EnvFakedeleteAlso + " environment variable.", + " May also be enabled via " + junos.EnvFakedeleteAlso + " environment variable.", }, }, } @@ -316,7 +323,7 @@ func (p *junosProvider) Resources(_ context.Context) []func() resource.Resource } } -func (p *junosProvider) Configure( +func (p *junosProvider) Configure( //nolint:gocyclo ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse, ) { var config junosProviderModel @@ -393,6 +400,14 @@ func (p *junosProvider) Configure( fmt.Sprintf(instructionUnknownMessage, junos.EnvGroupInterfaceDelete), ) } + if config.NoDecodeSecrets.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("no_decode_secrets"), + tfdiag.UnknownJunosAttrErrSummary, + unknownValueErrorMessage+"for 'no_decode_secrets' attribute."+ + fmt.Sprintf(instructionUnknownMessage, junos.EnvNoDecodeSecrets), + ) + } if config.CmdSleepShort.IsUnknown() { resp.Diagnostics.AddAttributeError( path.Root("cmd_sleep_short"), @@ -602,6 +617,14 @@ func (p *junosProvider) Configure( client.WithGroupInterfaceDelete(v) } + if !config.NoDecodeSecrets.IsNull() { + if config.NoDecodeSecrets.ValueBool() { + client.WithoutDecodeSecrets() + } + } else if utils.ParseTrue(os.Getenv(junos.EnvNoDecodeSecrets)) { + client.WithoutDecodeSecrets() + } + client.WithSleepShort(100) // default value for cmd_sleep_short if !config.CmdSleepShort.IsNull() { client.WithSleepShort(int(config.CmdSleepShort.ValueInt64())) @@ -864,7 +887,7 @@ func (p *junosProvider) Configure( if config.FakeUpdateAlso.ValueBool() { client.WithFakeUpdateAlso() } - } else if v := os.Getenv(junos.EnvFakeupdateAlso); strings.EqualFold(v, "true") || v == "1" { + } else if utils.ParseTrue(os.Getenv(junos.EnvFakeupdateAlso)) { client.WithFakeUpdateAlso() } @@ -872,7 +895,7 @@ func (p *junosProvider) Configure( if config.FakeDeleteAlso.ValueBool() { client.WithFakeDeleteAlso() } - } else if v := os.Getenv(junos.EnvFakedeleteAlso); strings.EqualFold(v, "true") || v == "1" { + } else if utils.ParseTrue(os.Getenv(junos.EnvFakedeleteAlso)) { client.WithFakeDeleteAlso() } diff --git a/internal/providerfwk/resource_bgp_group.go b/internal/providerfwk/resource_bgp_group.go index 249b7a7b..617e3613 100644 --- a/internal/providerfwk/resource_bgp_group.go +++ b/internal/providerfwk/resource_bgp_group.go @@ -492,7 +492,7 @@ func (rscData *bgpGroupData) read( case balt.CutPrefixInString(&itemTrim, "type "): rscData.Type = types.StringValue(itemTrim) default: - if err := rscData.bgpAttrData.read(itemTrim); err != nil { + if err := rscData.bgpAttrData.read(itemTrim, junSess); err != nil { return err } } diff --git a/internal/providerfwk/resource_bgp_neighbor.go b/internal/providerfwk/resource_bgp_neighbor.go index e4364d5d..c46636f8 100644 --- a/internal/providerfwk/resource_bgp_neighbor.go +++ b/internal/providerfwk/resource_bgp_neighbor.go @@ -535,7 +535,7 @@ func (rscData *bgpNeighborData) read( break } itemTrim := strings.TrimPrefix(item, junos.SetLS) - if err := rscData.bgpAttrData.read(itemTrim); err != nil { + if err := rscData.bgpAttrData.read(itemTrim, junSess); err != nil { return err } } diff --git a/internal/providerfwk/resource_eventoptions_destination.go b/internal/providerfwk/resource_eventoptions_destination.go index 9e667a2a..4486816e 100644 --- a/internal/providerfwk/resource_eventoptions_destination.go +++ b/internal/providerfwk/resource_eventoptions_destination.go @@ -410,7 +410,7 @@ func (rscData *eventoptionsDestinationData) read( case balt.CutPrefixInString(&itemTrim, "archive-sites "): itemTrimFields := strings.Split(itemTrim, " ") if len(itemTrimFields) > 2 { // password - password, err := tfdata.JunosDecode(strings.Trim(itemTrimFields[2], "\""), "password") + password, err := junSess.JunosDecode(strings.Trim(itemTrimFields[2], "\""), "password") if err != nil { return err } diff --git a/internal/providerfwk/resource_iccp.go b/internal/providerfwk/resource_iccp.go index 4f653541..4413120d 100644 --- a/internal/providerfwk/resource_iccp.go +++ b/internal/providerfwk/resource_iccp.go @@ -261,7 +261,7 @@ func (rscData *iccpData) read( case balt.CutPrefixInString(&itemTrim, "local-ip-addr "): rscData.LocalIPAddr = types.StringValue(itemTrim) case balt.CutPrefixInString(&itemTrim, "authentication-key "): - rscData.AuthenticationKey, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") + rscData.AuthenticationKey, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") if err != nil { return err } diff --git a/internal/providerfwk/resource_iccp_peer.go b/internal/providerfwk/resource_iccp_peer.go index dd21069b..b40eb69e 100644 --- a/internal/providerfwk/resource_iccp_peer.go +++ b/internal/providerfwk/resource_iccp_peer.go @@ -543,7 +543,7 @@ func (rscData *iccpPeerData) read( } rscData.RedundancyGroupIDList = append(rscData.RedundancyGroupIDList, value) case balt.CutPrefixInString(&itemTrim, "authentication-key "): - rscData.AuthenticationKey, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") + rscData.AuthenticationKey, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") if err != nil { return err } diff --git a/internal/providerfwk/resource_interface_logical.go b/internal/providerfwk/resource_interface_logical.go index 793f795e..22cd2813 100644 --- a/internal/providerfwk/resource_interface_logical.go +++ b/internal/providerfwk/resource_interface_logical.go @@ -2897,7 +2897,7 @@ func (rscData *interfaceLogicalData) read( if len(itemTrimFields) > 1 { balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" ") - if err := address.read(itemTrim); err != nil { + if err := address.read(itemTrim, junSess); err != nil { return err } } @@ -3028,7 +3028,9 @@ func (rscData *interfaceLogicalData) read( return nil } -func (block *interfaceLogicalBlockFamilyInetBlockAddress) read(itemTrim string) (err error) { +func (block *interfaceLogicalBlockFamilyInetBlockAddress) read( + itemTrim string, junSess *junos.Session, +) (err error) { switch { case itemTrim == "primary": block.Primary = types.BoolValue(true) @@ -3063,7 +3065,7 @@ func (block *interfaceLogicalBlockFamilyInetBlockAddress) read(itemTrim string) return err } case balt.CutPrefixInString(&itemTrim, "authentication-key "): - vrrpGroup.AuthenticationKey, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") + vrrpGroup.AuthenticationKey, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") if err != nil { return err } diff --git a/internal/providerfwk/resource_ospf_area.go b/internal/providerfwk/resource_ospf_area.go index 9c59f664..23ae5903 100644 --- a/internal/providerfwk/resource_ospf_area.go +++ b/internal/providerfwk/resource_ospf_area.go @@ -2315,7 +2315,7 @@ func (rscData *ospfAreaData) read( interFace.Name = types.StringValue(itemTrimFields[0]) balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" ") - if err := interFace.read(itemTrim); err != nil { + if err := interFace.read(itemTrim, junSess); err != nil { return err } rscData.Interface = append(rscData.Interface, interFace) @@ -2402,10 +2402,12 @@ func (rscData *ospfAreaData) read( return nil } -func (block *ospfAreaBlockInterface) read(itemTrim string) (err error) { +func (block *ospfAreaBlockInterface) read( + itemTrim string, junSess *junos.Session, +) (err error) { switch { case balt.CutPrefixInString(&itemTrim, "authentication simple-password "): - block.AuthenticationSimplePassword, err = tfdata.JunosDecode( + block.AuthenticationSimplePassword, err = junSess.JunosDecode( strings.Trim(itemTrim, "\""), "authentication simple-password", ) @@ -2523,7 +2525,7 @@ func (block *ospfAreaBlockInterface) read(itemTrim string) (err error) { switch { case balt.CutPrefixInString(&itemTrim, "key "): - authenticationMD5.Key, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "authentication md5 key") + authenticationMD5.Key, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication md5 key") if err != nil { return err } diff --git a/internal/providerfwk/resource_rip_neighbor.go b/internal/providerfwk/resource_rip_neighbor.go index 27c8f7c4..8ac1022d 100644 --- a/internal/providerfwk/resource_rip_neighbor.go +++ b/internal/providerfwk/resource_rip_neighbor.go @@ -1020,7 +1020,7 @@ func (rscData *ripNeighborData) read( case itemTrim == "any-sender": rscData.AnySender = types.BoolValue(true) case balt.CutPrefixInString(&itemTrim, "authentication-key "): - rscData.AuthenticationKey, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") + rscData.AuthenticationKey, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") if err != nil { return err } @@ -1083,7 +1083,7 @@ func (rscData *ripNeighborData) read( balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" ") switch { case balt.CutPrefixInString(&itemTrim, "key "): - authenticationSelectiveMD5.Key, err = tfdata.JunosDecode( + authenticationSelectiveMD5.Key, err = junSess.JunosDecode( strings.Trim(itemTrim, "\""), "authentication-selective-md5 key", ) diff --git a/internal/providerfwk/resource_security_authentication_key_chain.go b/internal/providerfwk/resource_security_authentication_key_chain.go index 21ba707b..9ccbc93c 100644 --- a/internal/providerfwk/resource_security_authentication_key_chain.go +++ b/internal/providerfwk/resource_security_authentication_key_chain.go @@ -543,7 +543,7 @@ func (rscData *securityAuthenticationKeyChainData) read( key.ID = keyID balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" ") - if err := key.read(itemTrim); err != nil { + if err := key.read(itemTrim, junSess); err != nil { return err } rscData.Key = append(rscData.Key, key) @@ -554,10 +554,12 @@ func (rscData *securityAuthenticationKeyChainData) read( return nil } -func (block *securityAuthenticationKeyChainBlockKey) read(itemTrim string) (err error) { +func (block *securityAuthenticationKeyChainBlockKey) read( + itemTrim string, junSess *junos.Session, +) (err error) { switch { case balt.CutPrefixInString(&itemTrim, "secret "): - block.Secret, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "secret") + block.Secret, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "secret") if err != nil { return err } diff --git a/internal/providerfwk/resource_security_ike_gateway.go b/internal/providerfwk/resource_security_ike_gateway.go index a1e17caf..4b63c8f9 100644 --- a/internal/providerfwk/resource_security_ike_gateway.go +++ b/internal/providerfwk/resource_security_ike_gateway.go @@ -1019,7 +1019,7 @@ func (rscData *securityIkeGatewayData) read( case balt.CutPrefixInString(&itemTrim, "access-profile "): rscData.Aaa.AccessProfile = types.StringValue(strings.Trim(itemTrim, "\"")) case balt.CutPrefixInString(&itemTrim, "client password "): - rscData.Aaa.ClientPassword, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "aaa client password") + rscData.Aaa.ClientPassword, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "aaa client password") if err != nil { return err } diff --git a/internal/providerfwk/resource_security_ike_policy.go b/internal/providerfwk/resource_security_ike_policy.go index 58c25a37..e4b7b333 100644 --- a/internal/providerfwk/resource_security_ike_policy.go +++ b/internal/providerfwk/resource_security_ike_policy.go @@ -451,12 +451,12 @@ func (rscData *securityIkePolicyData) read( case balt.CutPrefixInString(&itemTrim, "proposal-set "): rscData.ProposalSet = types.StringValue(itemTrim) case balt.CutPrefixInString(&itemTrim, "pre-shared-key hexadecimal "): - rscData.PreSharedKeyHexa, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "pre-shared-key hexadecimal") + rscData.PreSharedKeyHexa, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "pre-shared-key hexadecimal") if err != nil { return err } case balt.CutPrefixInString(&itemTrim, "pre-shared-key ascii-text "): - rscData.PreSharedKeyText, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "pre-shared-key ascii-text") + rscData.PreSharedKeyText, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "pre-shared-key ascii-text") if err != nil { return err } diff --git a/internal/providerfwk/resource_security_ipsec_vpn.go b/internal/providerfwk/resource_security_ipsec_vpn.go index bb5846f3..c176cc44 100644 --- a/internal/providerfwk/resource_security_ipsec_vpn.go +++ b/internal/providerfwk/resource_security_ipsec_vpn.go @@ -943,7 +943,7 @@ func (rscData *securityIpsecVpnData) set( configSet = append(configSet, setPrefix+"manual authentication algorithm "+v) } if v := rscData.Manual.AuthenticationKeyHexa.ValueString(); v != "" { - configSet = append(configSet, setPrefix+"manual authentication key hexadecimal "+v) + configSet = append(configSet, setPrefix+"manual authentication key hexadecimal \""+v+"\"") } if v := rscData.Manual.AuthenticationKeyText.ValueString(); v != "" { configSet = append(configSet, setPrefix+"manual authentication key ascii-text \""+v+"\"") @@ -952,7 +952,7 @@ func (rscData *securityIpsecVpnData) set( configSet = append(configSet, setPrefix+"manual encryption algorithm "+v) } if v := rscData.Manual.EncryptionKeyHexa.ValueString(); v != "" { - configSet = append(configSet, setPrefix+"manual encryption key hexadecimal "+v) + configSet = append(configSet, setPrefix+"manual encryption key hexadecimal \""+v+"\"") } if v := rscData.Manual.EncryptionKeyText.ValueString(); v != "" { configSet = append(configSet, setPrefix+"manual encryption key ascii-text \""+v+"\"") @@ -1062,13 +1062,13 @@ func (rscData *securityIpsecVpnData) read( case balt.CutPrefixInString(&itemTrim, "authentication algorithm "): rscData.Manual.AuthenticationAlgorithm = types.StringValue(itemTrim) case balt.CutPrefixInString(&itemTrim, "authentication key hexadecimal "): - rscData.Manual.AuthenticationKeyHexa, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), + rscData.Manual.AuthenticationKeyHexa, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication key hexadecimal") if err != nil { return err } case balt.CutPrefixInString(&itemTrim, "authentication key ascii-text "): - rscData.Manual.AuthenticationKeyText, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), + rscData.Manual.AuthenticationKeyText, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication key ascii-text") if err != nil { return err @@ -1076,13 +1076,13 @@ func (rscData *securityIpsecVpnData) read( case balt.CutPrefixInString(&itemTrim, "encryption algorithm "): rscData.Manual.EncryptionAlgorithm = types.StringValue(itemTrim) case balt.CutPrefixInString(&itemTrim, "encryption key hexadecimal "): - rscData.Manual.EncryptionKeyHexa, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), + rscData.Manual.EncryptionKeyHexa, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "encryption key hexadecimal") if err != nil { return err } case balt.CutPrefixInString(&itemTrim, "encryption key ascii-text "): - rscData.Manual.EncryptionKeyText, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), + rscData.Manual.EncryptionKeyText, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "encryption key ascii-text") if err != nil { return err diff --git a/internal/providerfwk/resource_snmp_v3_community.go b/internal/providerfwk/resource_snmp_v3_community.go index 26a813ae..ce3910a6 100644 --- a/internal/providerfwk/resource_snmp_v3_community.go +++ b/internal/providerfwk/resource_snmp_v3_community.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/jeremmfr/terraform-provider-junos/internal/junos" - "github.com/jeremmfr/terraform-provider-junos/internal/tfdata" "github.com/jeremmfr/terraform-provider-junos/internal/tfdiag" "github.com/jeremmfr/terraform-provider-junos/internal/tfvalidator" @@ -354,7 +353,7 @@ func (rscData *snmpV3CommunityData) read( case balt.CutPrefixInString(&itemTrim, "security-name "): rscData.SecurityName = types.StringValue(strings.Trim(itemTrim, "\"")) case balt.CutPrefixInString(&itemTrim, "community-name "): - rscData.CommunityName, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "community-name") + rscData.CommunityName, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "community-name") if err != nil { return err } diff --git a/internal/providerfwk/resource_snmp_v3_usm_user.go b/internal/providerfwk/resource_snmp_v3_usm_user.go index bf462be5..3821454f 100644 --- a/internal/providerfwk/resource_snmp_v3_usm_user.go +++ b/internal/providerfwk/resource_snmp_v3_usm_user.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/jeremmfr/terraform-provider-junos/internal/junos" - "github.com/jeremmfr/terraform-provider-junos/internal/tfdata" "github.com/jeremmfr/terraform-provider-junos/internal/tfdiag" "github.com/jeremmfr/terraform-provider-junos/internal/tfvalidator" @@ -789,7 +788,7 @@ func (rscData *snmpV3UsmUserData) read( itemTrimFields := strings.Split(itemTrim, " ") rscData.AuthenticationType = types.StringValue(itemTrimFields[0]) if balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" authentication-key ") { - rscData.AuthenticationKey, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") + rscData.AuthenticationKey, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") if err != nil { return err } @@ -798,7 +797,7 @@ func (rscData *snmpV3UsmUserData) read( itemTrimFields := strings.Split(itemTrim, " ") rscData.PrivacyType = types.StringValue(itemTrimFields[0]) if balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" privacy-key ") { - rscData.PrivacyKey, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "privacy-key") + rscData.PrivacyKey, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "privacy-key") if err != nil { return err } @@ -839,7 +838,7 @@ func (rscData *snmpV3UsmUserData) readPrivateToState( case strings.HasPrefix(itemTrim, "authentication-"): itemTrimFields := strings.Split(itemTrim, " ") if balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" authentication-key ") { - authenticationKey, err := tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") + authenticationKey, err := junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") if err != nil { return err } @@ -848,7 +847,7 @@ func (rscData *snmpV3UsmUserData) readPrivateToState( case strings.HasPrefix(itemTrim, "privacy-"): itemTrimFields := strings.Split(itemTrim, " ") if balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" privacy-key ") { - privacyKey, err := tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "privacy-key") + privacyKey, err := junSess.JunosDecode(strings.Trim(itemTrim, "\""), "privacy-key") if err != nil { return err } diff --git a/internal/providerfwk/resource_system.go b/internal/providerfwk/resource_system.go index 8b9988b3..e8f4170b 100644 --- a/internal/providerfwk/resource_system.go +++ b/internal/providerfwk/resource_system.go @@ -4063,14 +4063,14 @@ func (rscData *systemData) read( if rscData.Accounting == nil { rscData.Accounting = &systemBlockAccounting{} } - if err := rscData.Accounting.read(itemTrim); err != nil { + if err := rscData.Accounting.read(itemTrim, junSess); err != nil { return err } case balt.CutPrefixInString(&itemTrim, "archival configuration "): if rscData.ArchivalConfiguration == nil { rscData.ArchivalConfiguration = &systemBlockArchivalConfiguration{} } - if err := rscData.ArchivalConfiguration.read(itemTrim); err != nil { + if err := rscData.ArchivalConfiguration.read(itemTrim, junSess); err != nil { return err } case balt.CutPrefixInString(&itemTrim, "inet6-backup-router "): @@ -4094,7 +4094,7 @@ func (rscData *systemData) read( if rscData.License == nil { rscData.License = &systemBlockLicense{} } - if err := rscData.License.read(itemTrim); err != nil { + if err := rscData.License.read(itemTrim, junSess); err != nil { return err } case bchk.StringHasOneOfPrefixes(itemTrim, systemBlockLogin{}.junosLines()): @@ -4183,7 +4183,9 @@ func (rscData *systemData) read( return nil } -func (block *systemBlockAccounting) read(itemTrim string) (err error) { +func (block *systemBlockAccounting) read( + itemTrim string, junSess *junos.Session, +) (err error) { switch { case balt.CutPrefixInString(&itemTrim, "events "): block.Events = append(block.Events, types.StringValue(itemTrim)) @@ -4202,7 +4204,7 @@ func (block *systemBlockAccounting) read(itemTrim string) (err error) { ) destinationRadiusServer.Address = types.StringValue(itemTrimFields[0]) balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" ") - if err := destinationRadiusServer.read(itemTrim); err != nil { + if err := destinationRadiusServer.read(itemTrim, junSess); err != nil { return err } block.DestinationRadiusServer = append(block.DestinationRadiusServer, destinationRadiusServer) @@ -4217,7 +4219,7 @@ func (block *systemBlockAccounting) read(itemTrim string) (err error) { ) destinationTacplusServer.Address = types.StringValue(itemTrimFields[0]) balt.CutPrefixInString(&itemTrim, itemTrimFields[0]+" ") - if err := destinationTacplusServer.read(itemTrim); err != nil { + if err := destinationTacplusServer.read(itemTrim, junSess); err != nil { return err } block.DestinationTacplusServer = append(block.DestinationTacplusServer, destinationTacplusServer) @@ -4227,10 +4229,12 @@ func (block *systemBlockAccounting) read(itemTrim string) (err error) { return nil } -func (block *systemBlockAccountingBlockDestinationRadiusServer) read(itemTrim string) (err error) { +func (block *systemBlockAccountingBlockDestinationRadiusServer) read( + itemTrim string, junSess *junos.Session, +) (err error) { switch { case balt.CutPrefixInString(&itemTrim, "secret "): - block.Secret, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "secret") + block.Secret, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "secret") if err != nil { return err } @@ -4270,7 +4274,7 @@ func (block *systemBlockAccountingBlockDestinationRadiusServer) read(itemTrim st return err } case balt.CutPrefixInString(&itemTrim, "preauthentication-secret "): - block.PreauthenticationSecret, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "preauthentication-secret") + block.PreauthenticationSecret, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "preauthentication-secret") if err != nil { return err } @@ -4293,7 +4297,9 @@ func (block *systemBlockAccountingBlockDestinationRadiusServer) read(itemTrim st return nil } -func (block *systemBlockAccountingBlockDestinationTacplusServer) read(itemTrim string) (err error) { +func (block *systemBlockAccountingBlockDestinationTacplusServer) read( + itemTrim string, junSess *junos.Session, +) (err error) { switch { case balt.CutPrefixInString(&itemTrim, "port "): block.Port, err = tfdata.ConvAtoi64Value(itemTrim) @@ -4303,7 +4309,7 @@ func (block *systemBlockAccountingBlockDestinationTacplusServer) read(itemTrim s case balt.CutPrefixInString(&itemTrim, "routing-instance "): block.RoutingInstance = types.StringValue(itemTrim) case balt.CutPrefixInString(&itemTrim, "secret "): - block.Secret, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "secret") + block.Secret, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "secret") if err != nil { return err } @@ -4321,12 +4327,14 @@ func (block *systemBlockAccountingBlockDestinationTacplusServer) read(itemTrim s return nil } -func (block *systemBlockArchivalConfiguration) read(itemTrim string) (err error) { +func (block *systemBlockArchivalConfiguration) read( + itemTrim string, junSess *junos.Session, +) (err error) { switch { case balt.CutPrefixInString(&itemTrim, "archive-sites "): itemTrimFields := strings.Split(itemTrim, " ") if len(itemTrimFields) > 2 { // password - password, err := tfdata.JunosDecode(strings.Trim(itemTrimFields[2], "\""), "password") + password, err := junSess.JunosDecode(strings.Trim(itemTrimFields[2], "\""), "password") if err != nil { return err } @@ -4449,7 +4457,9 @@ func (systemBlockLicense) junosLines() []string { } } -func (block *systemBlockLicense) read(itemTrim string) (err error) { +func (block *systemBlockLicense) read( + itemTrim string, junSess *junos.Session, +) (err error) { itemTrim = strings.TrimPrefix(itemTrim, "license ") switch { case itemTrim == "autoupdate": @@ -4460,7 +4470,7 @@ func (block *systemBlockLicense) read(itemTrim string) (err error) { block.AutoupdateURL = types.StringValue(strings.Trim(url, "\"")) if balt.CutPrefixInString(&itemTrim, url+" password ") { - password, err := tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "password") + password, err := junSess.JunosDecode(strings.Trim(itemTrim, "\""), "password") if err != nil { return err } diff --git a/internal/providerfwk/resource_system_radius_server.go b/internal/providerfwk/resource_system_radius_server.go index 6cca0ee9..8fe54785 100644 --- a/internal/providerfwk/resource_system_radius_server.go +++ b/internal/providerfwk/resource_system_radius_server.go @@ -454,7 +454,7 @@ func (rscData *systemRadiusServerData) read( itemTrim := strings.TrimPrefix(item, junos.SetLS) switch { case balt.CutPrefixInString(&itemTrim, "secret "): - rscData.Secret, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "secret") + rscData.Secret, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "secret") if err != nil { return err } @@ -494,7 +494,7 @@ func (rscData *systemRadiusServerData) read( return err } case balt.CutPrefixInString(&itemTrim, "preauthentication-secret "): - rscData.PreauthenticationSecret, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "preauthentication-secret") + rscData.PreauthenticationSecret, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "preauthentication-secret") if err != nil { return err } diff --git a/internal/providerfwk/resource_system_radius_server_test.go b/internal/providerfwk/resource_system_radius_server_test.go index eadb2930..308e575c 100644 --- a/internal/providerfwk/resource_system_radius_server_test.go +++ b/internal/providerfwk/resource_system_radius_server_test.go @@ -5,15 +5,16 @@ import ( "github.com/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" ) func TestAccResourceSystemRadiusServer_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProtoV5ProviderFactories: testAccProtoV5ProviderFactories, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { - ConfigDirectory: config.TestStepDirectory(), + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories, + ConfigDirectory: config.TestStepDirectory(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("junos_system_radius_server.testacc_radiusServer", "address", "192.0.2.1"), @@ -22,7 +23,8 @@ func TestAccResourceSystemRadiusServer_basic(t *testing.T) { ), }, { - ConfigDirectory: config.TestStepDirectory(), + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories, + ConfigDirectory: config.TestStepDirectory(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("junos_system_radius_server.testacc_radiusServer", "preauthentication_secret", "password"), @@ -51,9 +53,24 @@ func TestAccResourceSystemRadiusServer_basic(t *testing.T) { ), }, { - ResourceName: "junos_system_radius_server.testacc_radiusServer", - ImportState: true, - ImportStateVerify: true, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories, + ResourceName: "junos_system_radius_server.testacc_radiusServer", + ImportState: true, + ImportStateVerify: true, + }, + // testing no_decode_secrets provider attribute + { + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories, + ConfigDirectory: config.TestStepDirectory(), + }, + { + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories, + ConfigDirectory: config.TestStepDirectory(), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, }, }, }) diff --git a/internal/providerfwk/resource_system_syslog_file.go b/internal/providerfwk/resource_system_syslog_file.go index ca57fcee..27112d64 100644 --- a/internal/providerfwk/resource_system_syslog_file.go +++ b/internal/providerfwk/resource_system_syslog_file.go @@ -919,7 +919,7 @@ func (rscData *systemSyslogFileData) read( balt.CutPrefixInString(&itemTrim, url+" ") switch { case balt.CutPrefixInString(&itemTrim, "password "): - sites.Password, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "password") + sites.Password, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "password") if err != nil { return err } diff --git a/internal/providerfwk/resource_system_tacplus_server.go b/internal/providerfwk/resource_system_tacplus_server.go index 8ac53f4f..44dbd999 100644 --- a/internal/providerfwk/resource_system_tacplus_server.go +++ b/internal/providerfwk/resource_system_tacplus_server.go @@ -378,7 +378,7 @@ func (rscData *systemTacplusServerData) read( case balt.CutPrefixInString(&itemTrim, "routing-instance "): rscData.RoutingInstance = types.StringValue(itemTrim) case balt.CutPrefixInString(&itemTrim, "secret "): - rscData.Secret, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "secret") + rscData.Secret, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "secret") if err != nil { return err } diff --git a/internal/providerfwk/resourceattr_bgp.go b/internal/providerfwk/resourceattr_bgp.go index 11640bb4..57f8c520 100644 --- a/internal/providerfwk/resourceattr_bgp.go +++ b/internal/providerfwk/resourceattr_bgp.go @@ -7,6 +7,7 @@ import ( "regexp" "strings" + "github.com/jeremmfr/terraform-provider-junos/internal/junos" "github.com/jeremmfr/terraform-provider-junos/internal/tfdata" "github.com/jeremmfr/terraform-provider-junos/internal/tfdiag" "github.com/jeremmfr/terraform-provider-junos/internal/tfvalidator" @@ -616,7 +617,9 @@ func (rscData *bgpAttrData) configSet(setPrefix string) ([]string, path.Path, er return configSet, path.Empty(), nil } -func (rscData *bgpAttrData) read(itemTrim string) (err error) { +func (rscData *bgpAttrData) read( + itemTrim string, junSess *junos.Session, +) (err error) { switch { case itemTrim == "accept-remote-nexthop": rscData.AcceptRemoteNexthop = types.BoolValue(true) @@ -636,7 +639,7 @@ func (rscData *bgpAttrData) read(itemTrim string) (err error) { case balt.CutPrefixInString(&itemTrim, "authentication-algorithm "): rscData.AuthenticationAlgorithm = types.StringValue(itemTrim) case balt.CutPrefixInString(&itemTrim, "authentication-key "): - rscData.AuthenticationKey, err = tfdata.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") + rscData.AuthenticationKey, err = junSess.JunosDecode(strings.Trim(itemTrim, "\""), "authentication-key") if err != nil { return err } diff --git a/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/2/main.tf b/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/2/main.tf index 4079a115..b9eb4a05 100644 --- a/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/2/main.tf +++ b/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/2/main.tf @@ -1,4 +1,8 @@ resource "junos_routing_instance" "testacc_radiusServer" { + lifecycle { + create_before_destroy = true + } + name = "testacc_radiusServer" } resource "junos_system_radius_server" "testacc_radiusServer" { diff --git a/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/4/main.tf b/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/4/main.tf new file mode 100644 index 00000000..5352383e --- /dev/null +++ b/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/4/main.tf @@ -0,0 +1,6 @@ +resource "junos_system_radius_server" "testacc_radiusServer" { + address = "192.0.2.1" + secret = "$9$dZV2aZGi.fzDiORSeXxDikqmT" + preauthentication_secret = "$9$6cgx/pBIRSeMXhS4ZjqQzhSrlK8" + port = 1645 +} diff --git a/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/4/provider.tf b/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/4/provider.tf new file mode 100644 index 00000000..7ddfa34c --- /dev/null +++ b/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/4/provider.tf @@ -0,0 +1,3 @@ +provider "junos" { + no_decode_secrets = true +} diff --git a/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/5/main.tf b/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/5/main.tf new file mode 100644 index 00000000..fec2d352 --- /dev/null +++ b/internal/providerfwk/testdata/TestAccResourceSystemRadiusServer_basic/5/main.tf @@ -0,0 +1,6 @@ +resource "junos_system_radius_server" "testacc_radiusServer" { + address = "192.0.2.1" + secret = "password" + preauthentication_secret = "password" + port = 1645 +} diff --git a/internal/providersdk/provider.go b/internal/providersdk/provider.go index 5a8a3f6b..25a2f614 100644 --- a/internal/providersdk/provider.go +++ b/internal/providersdk/provider.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "strconv" - "strings" "github.com/jeremmfr/terraform-provider-junos/internal/junos" "github.com/jeremmfr/terraform-provider-junos/internal/utils" @@ -68,6 +67,14 @@ func Provider() *schema.Provider { Description: "This is the Junos group used to remove configuration on a physical interface." + " May also be provided via " + junos.EnvGroupInterfaceDelete + " environment variable.", }, + "no_decode_secrets": { + Type: schema.TypeBool, + Optional: true, + Description: "Disable decoding secret hashes by Junos device when read resource data." + + " So encoded secrets need to be set in resources config to " + + "avoid drift between Terraform config and state." + + " May also be enabled via " + junos.EnvNoDecodeSecrets + " environment variable.", + }, "cmd_sleep_short": { Type: schema.TypeInt, Optional: true, @@ -155,7 +162,7 @@ func Provider() *schema.Provider { Description: "The normal process to update resources skipped to generate set/delete lines, " + "append them to the same file as `fake_create_with_setfile`, " + "and respond with a `fake` successful update of resources to Terraform." + - " May also be provided via " + junos.EnvFakeupdateAlso + " environment variable.", + " May also be enabled via " + junos.EnvFakeupdateAlso + " environment variable.", }, "fake_delete_also": { Type: schema.TypeBool, @@ -163,7 +170,7 @@ func Provider() *schema.Provider { Description: "The normal process to delete resources skipped to generate delete lines, " + "append them to the same file as `fake_create_with_setfile`, " + "and respond with a `fake` successful delete of resources to Terraform." + - " May also be provided via " + junos.EnvFakedeleteAlso + " environment variable.", + " May also be enabled via " + junos.EnvFakedeleteAlso + " environment variable.", }, }, ResourcesMap: map[string]*schema.Resource{ @@ -318,6 +325,14 @@ func configureProvider(_ context.Context, d *schema.ResourceData) (interface{}, client.WithGroupInterfaceDelete(ev) } + if v, ok := d.GetOk("no_decode_secrets"); ok { + if v.(bool) { + client.WithoutDecodeSecrets() + } + } else if utils.ParseTrue(os.Getenv(junos.EnvNoDecodeSecrets)) { + client.WithoutDecodeSecrets() + } + client.WithSleepShort(100) // default value for cmd_sleep_short if v, ok := d.GetOk("cmd_sleep_short"); ok { client.WithSleepShort(v.(int)) @@ -580,7 +595,7 @@ func configureProvider(_ context.Context, d *schema.ResourceData) (interface{}, if v.(bool) { client.WithFakeUpdateAlso() } - } else if v := os.Getenv(junos.EnvFakeupdateAlso); strings.EqualFold(v, "true") || v == "1" { + } else if utils.ParseTrue(os.Getenv(junos.EnvFakeupdateAlso)) { client.WithFakeUpdateAlso() } @@ -588,7 +603,7 @@ func configureProvider(_ context.Context, d *schema.ResourceData) (interface{}, if v.(bool) { client.WithFakeDeleteAlso() } - } else if v := os.Getenv(junos.EnvFakedeleteAlso); strings.EqualFold(v, "true") || v == "1" { + } else if utils.ParseTrue(os.Getenv(junos.EnvFakedeleteAlso)) { client.WithFakeDeleteAlso() } diff --git a/internal/ruleguard/rule_junos_decode.go b/internal/ruleguard/rule_junos_decode.go new file mode 100644 index 00000000..d32418ae --- /dev/null +++ b/internal/ruleguard/rule_junos_decode.go @@ -0,0 +1,12 @@ +//go:build ruleguard +// +build ruleguard + +package ruleguard + +import "github.com/quasilyte/go-ruleguard/dsl" + +func junosDecode(m dsl.Matcher) { //nolint + m.Match(`tfdata.JunosDecode($*_)`). + Where(!m.File().PkgPath.Matches("internal/junos") && !m.File().PkgPath.Matches("internal/tfdata")). + Suggest("use JunosDecode function of *junos.Session instead of function from tfdata package") +} diff --git a/internal/tfdata/to_int64.go b/internal/tfdata/to_int64.go index 0c2da04e..3e1ae53d 100644 --- a/internal/tfdata/to_int64.go +++ b/internal/tfdata/to_int64.go @@ -9,7 +9,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) -func ConvAtoi64Value(str string, +func ConvAtoi64Value( + str string, ) ( basetypes.Int64Value, error, ) { diff --git a/internal/tfdata/to_string.go b/internal/tfdata/to_string.go index fcc85651..812c367f 100644 --- a/internal/tfdata/to_string.go +++ b/internal/tfdata/to_string.go @@ -8,7 +8,8 @@ import ( "github.com/jeremmfr/junosdecode" ) -func JunosDecode(str, errMsg string, +func JunosDecode( + str, errMsg string, ) ( basetypes.StringValue, error, ) { diff --git a/internal/utils/bool.go b/internal/utils/bool.go new file mode 100644 index 00000000..be259994 --- /dev/null +++ b/internal/utils/bool.go @@ -0,0 +1,15 @@ +package utils + +import ( + "strconv" + "strings" +) + +func ParseTrue(str string) bool { + switch v, err := strconv.ParseBool(strings.ToLower(str)); { + case err != nil: + return false + default: + return v + } +} diff --git a/internal/utils/bool_test.go b/internal/utils/bool_test.go new file mode 100644 index 00000000..b040ec6e --- /dev/null +++ b/internal/utils/bool_test.go @@ -0,0 +1,62 @@ +package utils_test + +import ( + "testing" + + "github.com/jeremmfr/terraform-provider-junos/internal/utils" +) + +func TestParseTrue(t *testing.T) { + t.Parallel() + + type testCase struct { + val string + expectValue bool + } + tests := map[string]testCase{ + "unknown": { + val: "unknown", + expectValue: false, + }, + "empty": { + val: "", + expectValue: false, + }, + "1": { + val: "1", + expectValue: true, + }, + "T": { + val: "T", + expectValue: true, + }, + "true": { + val: "true", + expectValue: true, + }, + "0": { + val: "0", + expectValue: false, + }, + "F": { + val: "F", + expectValue: false, + }, + "false": { + val: "false", + expectValue: false, + }, + } + + for name, test := range tests { + name, test := name, test + t.Run(name, func(t *testing.T) { + t.Parallel() + r := utils.ParseTrue(test.val) + + if r != test.expectValue { + t.Fatalf("got unexpected value: want %t, got %t", test.expectValue, r) + } + }) + } +}